Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[6.15.z] Capsule N-Minus testing #14344

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions conf/capsule.yaml.template
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
CAPSULE:
# Capsule hostname for N-minus testing
HOSTNAME:
VERSION:
# The full release version (6.9.2)
RELEASE: # populate with capsule version
Expand Down
6 changes: 3 additions & 3 deletions conf/dynaconf_hooks.py
Original file line number Diff line number Diff line change
Expand Up @@ -85,9 +85,9 @@ def get_ohsnap_repos(settings):
settings,
repo='capsule',
product='capsule',
release=settings.server.version.release,
os_release=settings.server.version.rhel_version,
snap=settings.server.version.snap,
release=settings.capsule.version.release,
os_release=settings.capsule.version.rhel_version,
snap=settings.capsule.version.snap,
)

data['SATELLITE_REPO'] = get_ohsnap_repo_url(
Expand Down
1 change: 1 addition & 0 deletions conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
'pytest_plugins.requirements.update_requirements',
'pytest_plugins.sanity_plugin',
'pytest_plugins.video_cleanup',
'pytest_plugins.capsule_n-minus',
# Fixtures
'pytest_fixtures.core.broker',
'pytest_fixtures.core.sat_cap_factory',
Expand Down
40 changes: 31 additions & 9 deletions pytest_fixtures/core/sat_cap_factory.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
from contextlib import contextmanager
from functools import lru_cache

from broker import Broker
from packaging.version import Version
Expand Down Expand Up @@ -37,13 +38,29 @@ def _target_satellite_host(request, satellite_factory):
yield


@lru_cache
def cached_capsule_cdn_register(hostname=None):
cap = Capsule.get_host_by_hostname(hostname=hostname)
cap.enable_capsule_downstream_repos()


@contextmanager
def _target_capsule_host(request, capsule_factory):
if 'sanity' not in request.config.option.markexpr:
if 'sanity' not in request.config.option.markexpr and not request.config.option.n_minus:
new_cap = capsule_factory()
yield new_cap
new_cap.teardown()
Broker(hosts=[new_cap]).checkin()
elif request.config.option.n_minus:
if not settings.capsule.hostname:
hosts = Capsule.get_hosts_from_inventory(filter="'cap' in @inv.name")
settings.capsule.hostname = hosts[0].hostname
cap = hosts[0]
else:
cap = Capsule.get_host_by_hostname(settings.capsule.hostname)
# Capsule needs RHEL contents for some tests
cached_capsule_cdn_register(hostname=settings.capsule.hostname)
yield cap
else:
yield

Expand Down Expand Up @@ -162,9 +179,10 @@ def session_capsule_host(request, capsule_factory):


@pytest.fixture
def capsule_configured(capsule_host, target_sat):
def capsule_configured(request, capsule_host, target_sat):
"""Configure the capsule instance with the satellite from settings.server.hostname"""
capsule_host.capsule_setup(sat_host=target_sat)
if not request.config.option.n_minus:
capsule_host.capsule_setup(sat_host=target_sat)
return capsule_host


Expand All @@ -176,21 +194,23 @@ def large_capsule_configured(large_capsule_host, target_sat):


@pytest.fixture(scope='module')
def module_capsule_configured(module_capsule_host, module_target_sat):
def module_capsule_configured(request, module_capsule_host, module_target_sat):
"""Configure the capsule instance with the satellite from settings.server.hostname"""
module_capsule_host.capsule_setup(sat_host=module_target_sat)
if not request.config.option.n_minus:
module_capsule_host.capsule_setup(sat_host=module_target_sat)
return module_capsule_host


@pytest.fixture(scope='session')
def session_capsule_configured(session_capsule_host, session_target_sat):
def session_capsule_configured(request, session_capsule_host, session_target_sat):
"""Configure the capsule instance with the satellite from settings.server.hostname"""
session_capsule_host.capsule_setup(sat_host=session_target_sat)
if not request.config.option.n_minus:
session_capsule_host.capsule_setup(sat_host=session_target_sat)
return session_capsule_host


@pytest.fixture(scope='module')
def module_capsule_configured_mqtt(module_capsule_configured):
def module_capsule_configured_mqtt(request, module_capsule_configured):
"""Configure the capsule instance with the satellite from settings.server.hostname,
enable MQTT broker"""
module_capsule_configured.set_rex_script_mode_provider('pull-mqtt')
Expand All @@ -201,7 +221,9 @@ def module_capsule_configured_mqtt(module_capsule_configured):
result = module_capsule_configured.execute('firewall-cmd --permanent --add-port="1883/tcp"')
assert result.status == 0, 'Failed to open mqtt port on capsule'
module_capsule_configured.execute('firewall-cmd --reload')
return module_capsule_configured
yield module_capsule_configured
if request.config.option.n_minus:
raise TypeError('The teardown is missed for MQTT configuration undo for nminus testing')


@pytest.fixture(scope='module')
Expand Down
55 changes: 55 additions & 0 deletions pytest_plugins/capsule_n-minus.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
# Collection of Capsule Factory fixture tests
# No destructive tests
# Adjust capsule host and capsule_configured host behavior for n_minus testing
# Calculate capsule hostname from inventory just as we do in xDist.py
from robottelo.config import settings
from robottelo.hosts import Capsule


def pytest_addoption(parser):
"""Add options for pytest to collect tests based on fixtures its using"""
help_text = '''
Collects tests based on capsule fixtures used by tests and uncollect destructive tests

Usage: --n-minus

example: pytest --n-minus tests/foreman
'''
parser.addoption("--n-minus", action='store_true', default=False, help=help_text)


def pytest_collection_modifyitems(items, config):

if not config.getoption('n_minus', False):
return

selected = []
deselected = []

for item in items:
is_destructive = item.get_closest_marker('destructive')
# Deselect Destructive tests and tests without capsule_factory fixture
if 'capsule_factory' not in item.fixturenames or is_destructive:
deselected.append(item)
continue
# Ignoring all puppet tests as they are destructive in nature
# and needs its own satellite for verification
if 'session_puppet_enabled_sat' in item.fixturenames:
deselected.append(item)
continue
# Ignoring all satellite maintain tests as they are destructive in nature
# Also dont need them in nminus testing as its not integration testing
if 'sat_maintain' in item.fixturenames and 'satellite' in item.callspec.params.values():
deselected.append(item)
continue
selected.append(item)

config.hook.pytest_deselected(items=deselected)
items[:] = selected


def pytest_sessionfinish(session, exitstatus):
# Unregister the capsule from CDN after all tests
if session.config.option.n_minus and not session.config.option.collectonly:
caps = Capsule.get_host_by_hostname(hostname=settings.capsule.hostname)
caps.unregister()
6 changes: 6 additions & 0 deletions robottelo/exceptions.py
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,12 @@ class CLIError(Exception):
"""Indicates that a CLI command could not be run."""


class CapsuleHostError(Exception):
"""Indicates error in capsule configuration etc"""

pass


class CLIBaseError(Exception):
"""Indicates that a CLI command has finished with return code different
from zero.
Expand Down
20 changes: 19 additions & 1 deletion robottelo/hosts.py
Original file line number Diff line number Diff line change
Expand Up @@ -1599,6 +1599,21 @@ def get_features(self):
"""Get capsule features"""
return requests.get(f'https://{self.hostname}:9090/features', verify=False).text

def enable_capsule_downstream_repos(self):
"""Enable CDN repos and capsule downstream repos on Capsule Host"""
# CDN Repos
self.register_to_cdn()
for repo in getattr(constants, f"OHSNAP_RHEL{self.os_version.major}_REPOS"):
result = self.enable_repo(repo, force=True)
if result.status:
raise CapsuleHostError(f'Repo enable at capsule host failed\n{result.stdout}')
# Downstream Capsule specific Repos
self.download_repofile(
product='capsule',
release=settings.capsule.version.release,
snap=settings.capsule.version.snap,
)

def capsule_setup(self, sat_host=None, capsule_cert_opts=None, **installer_kwargs):
"""Prepare the host and run the capsule installer"""
self._satellite = sat_host or Satellite()
Expand Down Expand Up @@ -1686,7 +1701,10 @@ def run_installer_arg(self, *args, timeout='20m'):
timeout=timeout,
)
if result.status != 0:
raise SatelliteHostError(f'Failed to execute with argument: {result.stderr}')
raise SatelliteHostError(
f'Failed to execute with arguments: {installer_args} and,'
f' the stderr is {result.stderr}'
)

def set_mqtt_resend_interval(self, value):
"""Set the time interval in seconds at which the notification should be
Expand Down
15 changes: 13 additions & 2 deletions tests/foreman/api/test_capsule.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@
@pytest.mark.e2e
@pytest.mark.upgrade
@pytest.mark.tier1
def test_positive_update_capsule(target_sat, module_capsule_configured):
def test_positive_update_capsule(request, pytestconfig, target_sat, module_capsule_configured):
"""Update various capsule properties

:id: a3d3eaa9-ed8d-42e6-9c83-20251e5ca9af
Expand All @@ -39,7 +39,7 @@ def test_positive_update_capsule(target_sat, module_capsule_configured):

:customerscenario: true
"""
new_name = f'{gen_string("alpha")}-{module_capsule_configured.name}'
new_name = f'{gen_string("alpha")}-{module_capsule_configured.hostname}'
capsule = target_sat.api.SmartProxy().search(
query={'search': f'name = {module_capsule_configured.hostname}'}
)[0]
Expand Down Expand Up @@ -68,6 +68,17 @@ def test_positive_update_capsule(target_sat, module_capsule_configured):
capsule = capsule.update(['name'])
assert capsule.name == new_name

@request.addfinalizer
def _finalize():
# Updating the hostname back
if (
cap := target_sat.api.SmartProxy().search(query={'search': f'name = {new_name}'})
and pytestconfig.option.n_minus
):
cap = cap[0]
cap.name = module_capsule_configured.hostname
cap.update(['name'])

# serching for non-default capsule BZ#2077824
capsules = target_sat.api.SmartProxy().search(query={'search': 'id != 1'})
assert len(capsules) > 0
Expand Down
3 changes: 3 additions & 0 deletions tests/foreman/api/test_capsulecontent.py
Original file line number Diff line number Diff line change
Expand Up @@ -1263,6 +1263,7 @@ def test_positive_capsule_sync_status_persists(
def test_positive_remove_capsule_orphans(
self,
target_sat,
pytestconfig,
capsule_configured,
function_entitlement_manifest_org,
function_lce_library,
Expand Down Expand Up @@ -1292,6 +1293,8 @@ def test_positive_remove_capsule_orphans(
:BZ: 22043089, 2211962

"""
if not pytestconfig.option.n_minus:
pytest.skip('Test cannot be run on n-minus setups session-scoped capsule')
# Enable RHST repo and sync it to the Library LCE.
repo_id = target_sat.api_factory.enable_rhrepo_and_fetchid(
basearch='x86_64',
Expand Down
2 changes: 2 additions & 0 deletions tests/foreman/destructive/test_registration.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@

from robottelo.config import settings

pytestmark = pytest.mark.destructive


@pytest.mark.tier3
@pytest.mark.no_containers
Expand Down
Loading