You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
test: iterate platform lists via lib.lftest.attach_each for accurate test counts
Convert the last 7 run files that still used a plain for/subTest loop
(apache-httpd-status, cpu-usage, keycloak-memory-usage, keycloak-stats,
keycloak-version, logfile, mysql-connections) to lib.lftest.attach_each
so each platform, image or scenario shows up as its own unittest test
method. Plain subTest loops collapse into a single method and make
./run report "Ran 1 test" regardless of actual coverage.
Document both the TESTS-list pattern (attach_tests) and the
platform-list pattern (attach_each) in CONTRIBUTING.md, and update the
container-based test example to match.
Unit tests are implemented using the `unittest` framework (<https://docs.python.org/3/library/unittest.html>) with a declarative, data-driven approach. Test definitions are a list of dicts, executed via `lib.lftest.run()`and `unittest.subTest()`. See the [example](check-plugins/example/unit-test/run) plugin for the reference implementation.
696
+
Unit tests are implemented using the `unittest` framework (<https://docs.python.org/3/library/unittest.html>) with a declarative, data-driven approach. Test definitions are a list of dicts (or a list of platform/image items for container tests), materialised into one real `unittest` test method per item via `lib.lftest.attach_tests()`or `lib.lftest.attach_each()`. See the [example](check-plugins/example/unit-test/run) plugin for the reference implementation.
697
697
698
698
699
699
#### Test directory structure
@@ -802,6 +802,20 @@ Available assertion keys in each testcase dict:
Two iteration shapes show up in the test files, and each has its own helper. Both materialise one real `unittest` test method per item so `./run` reports an accurate count and `./run -v` names every case.
808
+
809
+
***TESTS list** (the default): a list of testcase dicts executed by `lib.lftest.run()`. Use `lib.lftest.attach_tests(TestCheck, TESTS)`. This is the right shape for everything that injects fixture data via `--test=stdout/...`.
810
+
***Platform list** (container-based tests): a list of images, Containerfiles, or scenario dicts where each item needs its own setup (spin up a container, build an image, reset a cache DB). Use `lib.lftest.attach_each(TestCheck, ITEMS, action, id_func=...)` with an `action(test, item)` callable that does the per-item work. The `id_func` turns one item into the test method name. Examples in-tree:
811
+
812
+
*`check-plugins/mysql-connections/unit-test/run` iterates over an `IMAGES` list of `(image, label)` tuples, with `id_func=lambda it: it[1]`.
813
+
*`check-plugins/cpu-usage/unit-test/run` iterates over a `CONTAINERFILES` list of strings, with the default `id_func=str`.
814
+
*`check-plugins/apache-httpd-status/unit-test/run` iterates over a `SCENARIOS` list of dicts where the action resets a cache DB and then replays a multi-step sequence.
815
+
816
+
Do not fall back to a plain `for ... subTest()` loop. It still executes every case and failures still surface, but unittest collapses the whole loop into a single method and reports `Ran 1 test`, which hides the real coverage count from `./run` and from the `tox` summary.
***Pull upstream images whenever possible.** You do not need a custom `Containerfile` that injects Python into the service image, because the plugin runs from the host and connects to the container via the exposed port. That is the common case for API-driven checks.
912
931
***Wait on a log marker, not a sleep.** The `wait_log` argument takes a substring that the service writes to stdout/stderr when it is ready (e.g. `Listening on:` for Keycloak, `ready for connections.` for MariaDB). Use `wait_log_timeout` for services that take longer than 2 minutes to start.
913
932
***Do not hardcode state-shifting assertions.** If the plugin reports something that depends on today's date (EOL windows, "last seen N days ago", "expires in X days"), assert only that the plugin returned a valid state (any of `STATE_OK`, `STATE_WARN`, `STATE_CRIT`) and that the output contains the expected version / service identifier. Locking in a specific state will break the test every time the calendar moves past a boundary.
914
-
***Multi-version matrix** goes in an `IMAGES` list at the top of the test file, iterated via `self.subTest(image=...)`. Add a new major release at the bottom of the list when it becomes available upstream.
915
-
***Rootless podman**: testcontainers-python works, but the Ryuk cleanup container needs to be disabled. Set `TESTCONTAINERS_RYUK_DISABLED=true` and `DOCKER_HOST=unix:///run/user/$UID/podman/podman.sock` before running the tests. A lightweight wrapper can live in `tools/run-container-tests`to set these for you.
933
+
***Multi-version matrix** goes in an `IMAGES` list (or `CONTAINERFILES`, `SCENARIOS`, ...) at the top of the test file, materialised into one real test method per item via `lib.lftest.attach_each()`. Add a new major release at the bottom of the list when it becomes available upstream. See the "Iterating over TESTS vs. platforms" subsection below for the rationale.
934
+
***Rootless podman**: testcontainers-python works, but the Ryuk cleanup container needs to be disabled. Set `TESTCONTAINERS_RYUK_DISABLED=true` and `CONTAINER_HOST=unix:///run/user/$UID/podman/podman.sock` before running the tests. `tools/run-unit-tests`sets both automatically when it detects a container-based test.
916
935
***Do not run container tests via `tox`.** They are integration tests and belong in `tools/run-container-tests`, not in the multi-Python matrix. `tools/run-unit-tests` detects them automatically by inspecting the `run` file for `podman` or `testcontainers` references.
917
936
***Keep hand-rolled podman orchestration out of new tests.** If you find a plugin that still builds containers via `subprocess.run(['podman', 'build', ...])`, migrate it to `lib.lftest.run_container()`; the old pattern is being retired.
0 commit comments