@@ -78,22 +78,44 @@ ci-build-sbom: ## Generate SBOM files (matches publish.yml workflow)
7878 @echo " This matches the GitHub Actions publish.yml workflow exactly"
7979 $(MAKE ) sbom-generate
8080
81+ # pytest-xdist parallelisation.
82+ #
83+ # Two variants are provided:
84+ #
85+ # PYTEST_PARALLEL_LOCAL — used by the local ``make test`` targets.
86+ # ``-n auto`` spawns one worker per CPU core, which is ideal on developer
87+ # machines that typically have 8-16 cores.
88+ #
89+ # PYTEST_PARALLEL_CI — used by CI targets (ci-tests-*).
90+ # GitHub-hosted runners expose exactly 2 vCPUs. ``-n auto`` therefore
91+ # spawns 2 workers, but the xdist scheduler introduces coordination
92+ # overhead that can make single-worker runs *slower* on 2-core hosts.
93+ # Using ``-n 2`` is explicit and avoids surprises if the runner class
94+ # changes. ``--dist=loadscope`` keeps tests in the same class/module on
95+ # one worker so class-scoped setUp / fixtures don't re-run per worker.
96+ #
97+ # PYTEST_PARALLEL (kept for backward compat) — points at the CI variant so
98+ # any external callers that reference the old variable name still work.
99+ #
100+ # Tests that share global state (live AWS, docker daemon, e2e tempdirs) are
101+ # tagged ``serial`` and run sequentially via a second pytest pass (PYTEST_SERIAL).
102+ PYTEST_PARALLEL_LOCAL := -n auto --dist=loadscope -m "not serial"
103+ PYTEST_PARALLEL_CI := -n 2 --dist=loadscope -m "not serial"
104+ PYTEST_PARALLEL := $(PYTEST_PARALLEL_CI )
105+ PYTEST_SERIAL := -m serial
106+
81107ci-tests-unit : # # Run unit tests only (matches ci.yml unit-tests job)
82- @echo " Running unit tests..."
83- $(call run-tool,pytest,$(TESTS_UNIT ) $(PYTEST_ARGS ) $(PYTEST_COV_ARGS ) --cov-report=xml:coverage-unit.xml --junitxml=junit-unit.xml)
108+ @echo " Running unit tests (parallel) ..."
109+ $(call run-tool,pytest,$(TESTS_UNIT ) $(PYTEST_PARALLEL ) $( PYTEST_ARGS ) $(PYTEST_COV_ARGS ) --cov-report=xml:coverage-unit.xml --junitxml=junit-unit.xml)
84110
85111ci-tests-integration : # # Run integration tests only (matches ci.yml integration-tests job)
86- @echo " Running integration tests..."
87- $(call run-tool,pytest,$(TESTS_INTEGRATION ) $(PYTEST_ARGS ) $(PYTEST_COV_ARGS ) --cov-report=xml:coverage-integration.xml --junitxml=junit-integration.xml)
112+ @echo " Running integration tests (parallel) ..."
113+ $(call run-tool,pytest,$(TESTS_INTEGRATION ) $(PYTEST_PARALLEL ) $( PYTEST_ARGS ) $(PYTEST_COV_ARGS ) --cov-report=xml:coverage-integration.xml --junitxml=junit-integration.xml)
88114
89115ci-tests-e2e : # # Run end-to-end tests only (matches ci.yml e2e-tests job)
90116 @echo " Running end-to-end tests..."
91117 $(call run-tool,pytest,$(TESTS_E2E ) $(PYTEST_ARGS ) $(PYTEST_COV_ARGS ) --cov-report=xml:coverage-e2e.xml --junitxml=junit-e2e.xml)
92118
93- ci-tests-onmoto : # # Run onmoto (mocked AWS) tests only (matches ci.yml onmoto-tests job)
94- @echo " Running onmoto tests..."
95- $(call run-tool,pytest,$(TESTS_ONMOTO ) $(PYTEST_ARGS ) $(PYTEST_COV_ARGS ) --cov-report=xml:coverage-onmoto.xml --junitxml=junit-onmoto.xml)
96-
97119ci-tests-matrix : # # Run comprehensive test matrix (matches test-matrix.yml workflow)
98120 @echo " Running comprehensive test matrix..."
99121 $(call run-tool,pytest,$(TESTS ) $(PYTEST_ARGS ) $(PYTEST_COV_ARGS ) --cov-report=xml:coverage-matrix.xml --junitxml=junit-matrix.xml)
@@ -102,13 +124,33 @@ ci-tests-performance: ## Run performance tests only (matches ci.yml performance
102124 @echo " Running performance tests..."
103125 $(call run-tool,pytest,$(TESTS_PERFORMANCE ) $(PYTEST_ARGS ) $(PYTEST_COV_ARGS ) --cov-report=xml:coverage-performance.xml --junitxml=junit-performance.xml)
104126
105- ci-tests-providers : # # Run providers tests only (matches ci.yml providers-tests job)
106- @echo " Running providers tests..."
107- $(call run-tool,pytest,$(TESTS_PROVIDERS ) $(PYTEST_ARGS ) $(PYTEST_COV_ARGS ) --cov-report=xml:coverage-providers.xml --junitxml=junit-providers.xml)
127+ # Per-provider matrix target. Pass PROVIDER=<name> to scope the run to a
128+ # single provider's test subtree (e.g. PROVIDER=aws → tests/providers/aws).
129+ # CI's per-provider matrix invokes this with PROVIDER set for each entry;
130+ # local dev can omit it to run the full tests/providers tree.
131+ PROVIDER ?=
132+ PROVIDER_SUFFIX := $(if $(PROVIDER ) ,-$(PROVIDER ) ,)
133+ PROVIDER_PATH := $(if $(PROVIDER ) ,$(TESTS_PROVIDERS ) /$(PROVIDER ) ,$(TESTS_PROVIDERS ) )
134+ # Serial-marked provider tests live under each provider's ``live/`` subtree.
135+ # That directory is listed in pyproject's ``norecursedirs`` so the parallel
136+ # ``ci-tests-providers`` target never descends into it; the serial target
137+ # below has to point pytest at the path explicitly so collection succeeds.
138+ # Without --live the root conftest adds ``skip_live`` to every collected
139+ # test, so the job exits 0 with a clear "163 skipped" line. CI with live
140+ # AWS credentials can opt in by setting PYTEST_LIVE=--live.
141+ PROVIDER_SERIAL_PATH := $(if $(PROVIDER ) ,$(TESTS_PROVIDERS ) /$(PROVIDER ) /live,$(TESTS_PROVIDERS ) )
142+ PYTEST_LIVE ?=
143+ ci-tests-providers : # # Run providers tests (PROVIDER=<name> scopes to one provider)
144+ @echo " Running provider tests (parallel): $( if $( PROVIDER) ,$( PROVIDER) ,all) ..."
145+ $(call run-tool,pytest,$(PROVIDER_PATH ) $(PYTEST_PARALLEL ) $(PYTEST_ARGS ) $(PYTEST_COV_ARGS ) --cov-report=xml:coverage-providers$(PROVIDER_SUFFIX ) .xml --junitxml=junit-providers$(PROVIDER_SUFFIX ) .xml)
146+
147+ ci-tests-providers-serial : # # Run the serial-marked subset of provider tests (live AWS, etc.)
148+ @echo " Running serial provider tests: $( if $( PROVIDER) ,$( PROVIDER) ,all) ..."
149+ $(call run-tool,pytest,$(PROVIDER_SERIAL_PATH ) $(PYTEST_SERIAL ) $(PYTEST_LIVE ) $(PYTEST_ARGS ) $(PYTEST_COV_ARGS ) --cov-report=xml:coverage-providers$(PROVIDER_SUFFIX ) -serial.xml --junitxml=junit-providers$(PROVIDER_SUFFIX ) -serial.xml)
108150
109151ci-tests-infrastructure : # # Run infrastructure tests only (matches ci.yml infrastructure-tests job)
110- @echo " Running infrastructure tests..."
111- $(call run-tool,pytest,$(TESTS_INFRASTRUCTURE ) $(PYTEST_ARGS ) $(PYTEST_COV_ARGS ) --cov-report=xml:coverage-infrastructure.xml --junitxml=junit-infrastructure.xml)
152+ @echo " Running infrastructure tests (parallel) ..."
153+ $(call run-tool,pytest,$(TESTS_INFRASTRUCTURE ) $(PYTEST_PARALLEL ) $( PYTEST_ARGS ) $(PYTEST_COV_ARGS ) --cov-report=xml:coverage-infrastructure.xml --junitxml=junit-infrastructure.xml)
112154
113155ci-check : # # Run comprehensive CI checks (matches GitHub Actions exactly)
114156 @echo " Running comprehensive CI checks that match GitHub Actions pipeline..."
0 commit comments