|
1 | 1 | import os |
2 | 2 | import uuid |
| 3 | +import subprocess |
| 4 | +from functools import cached_property |
| 5 | +from pathlib import Path |
3 | 6 |
|
4 | 7 | import apypie |
5 | 8 | import paramiko |
|
16 | 19 | SSH_CONFIG = './.tmp/ssh-config' |
17 | 20 |
|
18 | 21 |
|
| 22 | +class UserParameters: |
| 23 | + def __init__(self, config): |
| 24 | + self._config = config |
| 25 | + |
| 26 | + @cached_property |
| 27 | + def features(self): |
| 28 | + # foremanctl outputs |
| 29 | + # FEATURE STATE DESCRIPTION |
| 30 | + # $feature enabled/available $description |
| 31 | + output = subprocess.check_output(['./foremanctl', 'features'], cwd=self._config.rootdir, |
| 32 | + universal_newlines=True) |
| 33 | + lines = output.splitlines(keepends=False) |
| 34 | + # feature, status, description |
| 35 | + return [line.split(None, 2) for line in lines[1:]] |
| 36 | + |
| 37 | + @cached_property |
| 38 | + def available_features(self): |
| 39 | + return set(feature for feature, _status, _desc in self.features) |
| 40 | + |
| 41 | + @cached_property |
| 42 | + def enabled_features(self): |
| 43 | + return set(feature for feature, status, _desc in self.features if status == 'enabled') |
| 44 | + |
| 45 | + |
19 | 46 | def pytest_addoption(parser): |
20 | 47 | parser.addoption("--certificate-source", action="store", default="default", choices=('default', 'installer', 'custom_server'), help="Certificate source used during deployment") |
21 | 48 | parser.addoption("--database-mode", action="store", default="internal", choices=('internal', 'external'), help="Whether the database is internal or external") |
22 | 49 |
|
23 | 50 |
|
| 51 | +@pytest.fixture(scope="module") |
| 52 | +def enabled_features(pytestconfig): |
| 53 | + return pytestconfig.user_parameters.features |
| 54 | + |
| 55 | + |
24 | 56 | @pytest.fixture(scope="module") |
25 | 57 | def fixture_dir(): |
26 | 58 | return py.path.local(__file__).realpath() / '..' / 'fixtures' |
@@ -206,35 +238,21 @@ def wait_for_metadata_generate(foremanapi): |
206 | 238 | wait_for_tasks(foremanapi, 'label = Actions::Katello::Repository::MetadataGenerate') |
207 | 239 |
|
208 | 240 |
|
209 | | -def enabled_features(): |
210 | | - test_dir = os.path.dirname(os.path.abspath(__file__)) |
211 | | - foremanctl_dir = os.path.dirname(test_dir) |
212 | | - params_file = os.path.join(foremanctl_dir, '.var', 'lib', 'foremanctl', 'parameters.yaml') |
213 | | - if os.path.exists(params_file): |
214 | | - with open(params_file, 'r') as f: |
215 | | - features = yaml.safe_load(f).get('features', []) |
216 | | - if isinstance(features, str): |
217 | | - features = features.split() |
218 | | - return features |
219 | | - return [] |
220 | | - |
221 | | - |
222 | | -def is_iop_enabled(): |
223 | | - return 'iop' in enabled_features() |
224 | | - |
225 | | - |
226 | 241 | def pytest_configure(config): |
227 | | - config.addinivalue_line("markers", "iop: tests requiring IOP to be enabled") |
| 242 | + config.addinivalue_line("markers", "feature(name): mark a test as requiring a feature") |
228 | 243 |
|
| 244 | + config.user_parameters = UserParameters(config) |
229 | 245 |
|
230 | | -def pytest_collection_modifyitems(config, items): |
231 | | - if is_iop_enabled(): |
232 | | - return |
233 | 246 |
|
234 | | - skip_iop = pytest.mark.skip(reason="IOP not enabled - skipping IOP tests ('iop' not in enabled_features)") |
235 | | - for item in items: |
236 | | - if "iop" in item.keywords: |
237 | | - item.add_marker(skip_iop) |
| 247 | +def pytest_runtest_setup(item): |
| 248 | + feature_markers = set(mark.args[0] for mark in item.iter_markers(name="feature")) |
| 249 | + if feature_markers: |
| 250 | + invalid_features = feature_markers - item.config.user_parameters.available_features |
| 251 | + if invalid_features: |
| 252 | + raise pytest.PytestConfigWarning(f"Invalid feature(s) {invalid_features!r} on {item}") |
| 253 | + missing = feature_markers - item.config.user_parameters.enabled_features |
| 254 | + if missing: |
| 255 | + pytest.skip(f"test requires feature(s) {missing!r}") |
238 | 256 |
|
239 | 257 |
|
240 | 258 | class ResolveAdapter(HTTPAdapter): |
|
0 commit comments