Skip to content

Commit b57c313

Browse files
committed
chore(test): split container-backed unit tests into their own runner
Running `tox` over the full unit test suite was hanging on the first container-backed plugin: py39 timed out after 20min on keycloak-version, py310 got OOM-killed on cpu-usage, and py311 failed even earlier on netifaces source-builds. The container tests are valuable but they are integration tests, not multi-Python unit tests - they each build a podman image per target OS, inject the plugin plus lib/, and exercise the check against a live service. - tools/run-unit-tests: add `--no-container` and `--only-container` mutually-exclusive flags. A plugin counts as container-based when its `unit-test/` dir has a `containerfiles/` subdirectory. Without a flag, behavior is unchanged (runs everything). - tools/run-container-tests: new thin wrapper that calls `run-unit-tests --only-container` for the full podman-driven sweep. - tox.ini: call `tools/run-unit-tests --no-container` so the multi-Python matrix only runs the 103 fast tests and skips the 7 container-backed ones. Split is 103 fast / 7 container (+ 1 skipped `example` template).
1 parent 9420ddc commit b57c313

File tree

4 files changed

+106
-10
lines changed

4 files changed

+106
-10
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
3333
* rocketchat-stats: add missing `lib.txt` import so the user-count pluralization no longer crashes with `AttributeError` at runtime
3434
* sap-open-concur-com: `choices=services.append('All')` was effectively `choices=None` because `list.append()` returns `None`. The `--service` argument therefore accepted any value without validation. Use `choices=services + ['All']` to build a proper choices list ([#1070](https://github.com/Linuxfabrik/monitoring-plugins/issues/1070))
3535
* starface-java-memory-usage: the heap and non-heap state checks used `state += lib.base.get_worst(used_state, state)` which adds state integers together and corrupts the accumulated state (e.g. WARN+WARN=2 reads as CRIT, WARN+CRIT=3 is outside the valid range). Replaced with `state = lib.base.get_worst(state, used_state)` so the accumulated state remains a valid STATE_OK / STATE_WARN / STATE_CRIT value ([#1070](https://github.com/Linuxfabrik/monitoring-plugins/issues/1070))
36+
* tools/run-unit-tests: add `--no-container` and `--only-container` flags so container-backed unit tests (podman-driven integration suites that take minutes per plugin) can be filtered out of the fast default run. `tools/run-container-tests` is a thin wrapper around `--only-container` for the full integration sweep. `tox` now invokes `tools/run-unit-tests --no-container` so the multi-Python matrix actually completes instead of hanging / OOM-killing on the first container stage
3637
* tools/run-unit-tests: skip the `example` plugin in default runs. Its unit test is a template meant to be copy-pasted into new plugins and does not correspond to a real check. Explicit `python tools/run-unit-tests example` still runs it
3738
* tox.ini: disable the sdist build (`no_package = true`) so `tox` no longer trips over the flat top-level layout with "Multiple top-level packages discovered". The repo is a collection of plugin scripts, not a Python package
3839
* tuned-profile, crypto-policy: make the "expected vs actual" branches structurally exclusive via an explicit `else:`. The old code relied on `lib.base.oao()` exiting to skip the follow-up WARN call, which works but is fragile to read ([#1070](https://github.com/Linuxfabrik/monitoring-plugins/issues/1070))

tools/run-container-tests

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
#!/usr/bin/env python3
2+
# -*- coding: utf-8; py-indent-offset: 4 -*-
3+
#
4+
# Author: Linuxfabrik GmbH, Zurich, Switzerland
5+
# Contact: info (at) linuxfabrik (dot) ch
6+
# https://www.linuxfabrik.ch/
7+
# License: The Unlicense, see LICENSE file.
8+
9+
"""Discover and run all container-based plugin unit tests.
10+
11+
A plugin's unit test counts as container-based when its `unit-test/`
12+
directory has a `containerfiles/` subdirectory. These tests build a
13+
podman image per target OS, inject the plugin plus `lib/`, and exercise
14+
the check against a live service. They take minutes per plugin and
15+
need podman on the host.
16+
17+
This runner is a thin wrapper around `tools/run-unit-tests
18+
--only-container` so the two entry points (fast tests and container
19+
tests) are clearly separated. `tox` runs `tools/run-unit-tests
20+
--no-container` for multi-Python-version coverage; use this runner for
21+
a full integration sweep before a release.
22+
23+
Usage:
24+
python tools/run-container-tests # run all container tests
25+
python tools/run-container-tests keycloak-version # run one
26+
"""
27+
28+
import os
29+
import subprocess
30+
import sys
31+
32+
33+
def main():
34+
here = os.path.dirname(os.path.abspath(__file__))
35+
runner = os.path.join(here, 'run-unit-tests')
36+
argv = [sys.executable, runner, '--only-container', *sys.argv[1:]]
37+
result = subprocess.run(argv, check=False)
38+
sys.exit(result.returncode)
39+
40+
41+
if __name__ == '__main__':
42+
main()

tools/run-unit-tests

Lines changed: 59 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -11,12 +11,32 @@
1111
Each unit test is executed from its own directory (check-plugins/<name>/unit-test/)
1212
because the test files use relative paths for test data and plugin references.
1313
14+
Unit tests come in two shapes:
15+
16+
- **fast tests**: pure-Python tests that use `--test` fixtures and run in
17+
well under a second. These are safe to run in the multi-Python-version
18+
tox matrix.
19+
- **container tests**: tests that build a podman container per target OS,
20+
inject the plugin plus `lib/`, and exercise the check against a live
21+
service. They take minutes per plugin and need podman. They are not
22+
safe for the tox matrix, and get their own runner
23+
(`tools/run-container-tests`). A unit test counts as a container test
24+
if the plugin's `unit-test/` directory has a `containerfiles/`
25+
subdirectory.
26+
1427
Usage:
15-
python tools/run-unit-tests # run all
28+
python tools/run-unit-tests # run everything
29+
python tools/run-unit-tests --no-container # skip container tests
30+
python tools/run-unit-tests --only-container # run only container tests
1631
python tools/run-unit-tests disk-smart # run one plugin
1732
python tools/run-unit-tests disk-smart xml # run specific plugins
33+
python tools/run-unit-tests --no-container procs # flags + plugins mix
34+
35+
When specific plugins are requested on the command line, filters like
36+
`--no-container` still apply.
1837
"""
1938

39+
import argparse
2040
import os
2141
import subprocess
2242
import sys
@@ -27,27 +47,57 @@ import sys
2747
SKIP_PLUGINS = {'example'}
2848

2949

50+
def is_container_test(check_plugins, plugin):
51+
"""Return True if the plugin's unit test builds/runs containers."""
52+
return os.path.isdir(
53+
os.path.join(check_plugins, plugin, 'unit-test', 'containerfiles')
54+
)
55+
56+
3057
def main():
3158
"""Find and run unit tests, report results."""
59+
parser = argparse.ArgumentParser(description=__doc__.strip().split('\n\n')[0])
60+
group = parser.add_mutually_exclusive_group()
61+
group.add_argument(
62+
'--no-container',
63+
action='store_true',
64+
help='Skip container-based unit tests (anything with a containerfiles/ dir).',
65+
)
66+
group.add_argument(
67+
'--only-container',
68+
action='store_true',
69+
help='Run only container-based unit tests. Useful for tools/run-container-tests.',
70+
)
71+
parser.add_argument(
72+
'plugins',
73+
nargs='*',
74+
help='Optional list of plugin names to restrict the run to.',
75+
)
76+
args = parser.parse_args()
77+
3278
root = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
3379
check_plugins = os.path.join(root, 'check-plugins')
3480

35-
# filter to specific plugins if given as arguments
36-
requested = sys.argv[1:] if len(sys.argv) > 1 else None
81+
requested = set(args.plugins) if args.plugins else None
3782

3883
# discover tests
3984
plugins = []
4085
for plugin in sorted(os.listdir(check_plugins)):
41-
if requested and plugin not in requested:
86+
if requested is not None and plugin not in requested:
4287
continue
4388
# when a plugin is explicitly requested on the command line, run it
4489
# even if it is normally skipped; otherwise honor the skip set
45-
if plugin in SKIP_PLUGINS and not requested:
90+
if plugin in SKIP_PLUGINS and requested is None:
4691
continue
47-
unit_test_dir = os.path.join(check_plugins, plugin, 'unit-test')
48-
run_file = os.path.join(unit_test_dir, 'run')
49-
if os.path.isfile(run_file):
50-
plugins.append(plugin)
92+
run_file = os.path.join(check_plugins, plugin, 'unit-test', 'run')
93+
if not os.path.isfile(run_file):
94+
continue
95+
container = is_container_test(check_plugins, plugin)
96+
if args.no_container and container:
97+
continue
98+
if args.only_container and not container:
99+
continue
100+
plugins.append(plugin)
51101

52102
if not plugins:
53103
print('No unit tests found.')

tox.ini

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,4 +20,7 @@ deps =
2020
vici
2121
xmltodict
2222
commands =
23-
python tools/run-unit-tests {posargs}
23+
# `--no-container` keeps tox focused on fast pure-Python unit tests so
24+
# the multi-Python matrix actually completes. Run `tools/run-container-tests`
25+
# separately for the container-backed integration suite (podman required).
26+
python tools/run-unit-tests --no-container {posargs}

0 commit comments

Comments
 (0)