Skip to content

Commit

Permalink
Capsule N-Minus testing
Browse files Browse the repository at this point in the history
  • Loading branch information
jyejare committed Feb 1, 2024
1 parent 734f57a commit 103a30a
Show file tree
Hide file tree
Showing 10 changed files with 127 additions and 13 deletions.
1 change: 1 addition & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ PYTEST_XDIST_OPTS=$(PYTEST_OPTS) -n $(PYTEST_XDIST_NUMPROCESSES)
ROBOTTELO_TESTS_PATH=tests/robottelo/
TESTIMONY_OPTIONS=--config testimony.yaml


# Commands --------------------------------------------------------------------

help:
Expand Down
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
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
37 changes: 29 additions & 8 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,16 +194,18 @@ 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


Expand All @@ -201,7 +221,8 @@ 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
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(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
16 changes: 15 additions & 1 deletion robottelo/hosts.py
Original file line number Diff line number Diff line change
Expand Up @@ -1597,6 +1597,17 @@ 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):
"""Enabling 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.server.version.release)

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 @@ -1684,7 +1695,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
14 changes: 12 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 @@ -74,6 +74,16 @@ def test_positive_update_capsule(target_sat, module_capsule_configured):
assert capsule.url in [cps.url for cps in capsules]
assert capsule.name in [cps.name for cps in capsules]

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


@pytest.mark.skip_if_not_set('fake_capsules')
@pytest.mark.tier1
Expand Down
6 changes: 4 additions & 2 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 @@ -1312,8 +1313,9 @@ def test_positive_remove_capsule_orphans(
data={'environment_id': function_lce_library.id}
)
result = capsule_configured.nailgun_capsule.content_lifecycle_environments()
assert len(result['results']) == 1
assert result['results'][0]['id'] == function_lce_library.id
if not pytestconfig.option.n_minus:
assert len(result['results']) == 1
assert result['results'][0]['id'] == function_lce_library.id

sync_status = capsule_configured.nailgun_capsule.content_sync()
assert sync_status['result'] == 'success', 'Capsule sync task failed.'
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

0 comments on commit 103a30a

Please sign in to comment.