fix: pytest -m live works without extra flags
Root cause: test_schemathesis.py mutates decnet.web.auth.SECRET_KEY at module-level import time, poisoning JWT verification for all other tests in the same process — even when fuzz tests are deselected. - Add pytest_ignore_collect hook in tests/api/conftest.py to skip collecting test_schemathesis.py unless -m fuzz is selected - Add --dist loadscope to addopts so xdist groups by module (protects module-scoped fixtures in live tests) - Remove now-unnecessary xdist_group markers from live test classes
This commit is contained in:
@@ -22,6 +22,7 @@ dependencies = [
|
|||||||
"psutil>=5.9.0",
|
"psutil>=5.9.0",
|
||||||
"python-dotenv>=1.0.0",
|
"python-dotenv>=1.0.0",
|
||||||
"sqlmodel>=0.0.16",
|
"sqlmodel>=0.0.16",
|
||||||
|
"scapy>=2.6.1",
|
||||||
]
|
]
|
||||||
|
|
||||||
[project.optional-dependencies]
|
[project.optional-dependencies]
|
||||||
@@ -53,7 +54,6 @@ dev = [
|
|||||||
"psycopg2-binary>=2.9.11",
|
"psycopg2-binary>=2.9.11",
|
||||||
"paho-mqtt>=2.1.0",
|
"paho-mqtt>=2.1.0",
|
||||||
"pymongo>=4.16.0",
|
"pymongo>=4.16.0",
|
||||||
"scapy>=2.6.1",
|
|
||||||
]
|
]
|
||||||
|
|
||||||
[project.scripts]
|
[project.scripts]
|
||||||
@@ -62,7 +62,7 @@ decnet = "decnet.cli:app"
|
|||||||
[tool.pytest.ini_options]
|
[tool.pytest.ini_options]
|
||||||
asyncio_mode = "auto"
|
asyncio_mode = "auto"
|
||||||
asyncio_debug = "true"
|
asyncio_debug = "true"
|
||||||
addopts = "-m 'not fuzz and not live' -v -q -x -n logical"
|
addopts = "-m 'not fuzz and not live' -v -q -x -n logical --dist loadscope"
|
||||||
markers = [
|
markers = [
|
||||||
"fuzz: hypothesis-based fuzz tests (slow, run with -m fuzz or -m '' for all)",
|
"fuzz: hypothesis-based fuzz tests (slow, run with -m fuzz or -m '' for all)",
|
||||||
"live: live subprocess service tests (run with -m live)",
|
"live: live subprocess service tests (run with -m live)",
|
||||||
|
|||||||
@@ -12,6 +12,18 @@ from sqlalchemy.ext.asyncio import AsyncSession, async_sessionmaker, create_asyn
|
|||||||
from sqlalchemy.pool import StaticPool
|
from sqlalchemy.pool import StaticPool
|
||||||
import os as _os
|
import os as _os
|
||||||
|
|
||||||
|
|
||||||
|
def pytest_ignore_collect(collection_path, config):
|
||||||
|
"""Skip test_schemathesis.py unless fuzz marker is selected.
|
||||||
|
|
||||||
|
Its module-level code starts a subprocess server and mutates
|
||||||
|
decnet.web.auth.SECRET_KEY, which poisons other test suites.
|
||||||
|
"""
|
||||||
|
if collection_path.name == "test_schemathesis.py":
|
||||||
|
markexpr = config.getoption("markexpr", default="")
|
||||||
|
if "fuzz" not in markexpr:
|
||||||
|
return True
|
||||||
|
|
||||||
# Must be set before any decnet import touches decnet.env
|
# Must be set before any decnet import touches decnet.env
|
||||||
os.environ["DECNET_JWT_SECRET"] = "test-secret-key-at-least-32-chars-long!!"
|
os.environ["DECNET_JWT_SECRET"] = "test-secret-key-at-least-32-chars-long!!"
|
||||||
os.environ["DECNET_ADMIN_PASSWORD"] = "test-password-123"
|
os.environ["DECNET_ADMIN_PASSWORD"] = "test-password-123"
|
||||||
|
|||||||
@@ -97,7 +97,6 @@ async def token(live_client):
|
|||||||
|
|
||||||
|
|
||||||
@pytest.mark.live
|
@pytest.mark.live
|
||||||
@pytest.mark.xdist_group("health_live")
|
|
||||||
class TestHealthLive:
|
class TestHealthLive:
|
||||||
"""Live integration tests — real DB, real Docker check, real task state."""
|
"""Live integration tests — real DB, real Docker check, real task state."""
|
||||||
|
|
||||||
|
|||||||
@@ -128,7 +128,6 @@ async def token(live_client):
|
|||||||
|
|
||||||
|
|
||||||
@pytest.mark.live
|
@pytest.mark.live
|
||||||
@pytest.mark.xdist_group("service_isolation_live")
|
|
||||||
class TestCollectorLiveIsolation:
|
class TestCollectorLiveIsolation:
|
||||||
"""Real collector behaviour against the actual Docker daemon."""
|
"""Real collector behaviour against the actual Docker daemon."""
|
||||||
|
|
||||||
@@ -204,7 +203,6 @@ class TestCollectorLiveIsolation:
|
|||||||
|
|
||||||
|
|
||||||
@pytest.mark.live
|
@pytest.mark.live
|
||||||
@pytest.mark.xdist_group("service_isolation_live")
|
|
||||||
class TestIngesterLiveIsolation:
|
class TestIngesterLiveIsolation:
|
||||||
"""Real ingester against real DB and real filesystem."""
|
"""Real ingester against real DB and real filesystem."""
|
||||||
|
|
||||||
@@ -314,7 +312,6 @@ class TestIngesterLiveIsolation:
|
|||||||
|
|
||||||
|
|
||||||
@pytest.mark.live
|
@pytest.mark.live
|
||||||
@pytest.mark.xdist_group("service_isolation_live")
|
|
||||||
class TestAttackerWorkerLiveIsolation:
|
class TestAttackerWorkerLiveIsolation:
|
||||||
"""Real attacker worker against real DB."""
|
"""Real attacker worker against real DB."""
|
||||||
|
|
||||||
@@ -363,7 +360,6 @@ class TestAttackerWorkerLiveIsolation:
|
|||||||
|
|
||||||
|
|
||||||
@pytest.mark.live
|
@pytest.mark.live
|
||||||
@pytest.mark.xdist_group("service_isolation_live")
|
|
||||||
class TestSnifferLiveIsolation:
|
class TestSnifferLiveIsolation:
|
||||||
"""Real sniffer against the actual host network stack."""
|
"""Real sniffer against the actual host network stack."""
|
||||||
|
|
||||||
@@ -400,7 +396,6 @@ class TestSnifferLiveIsolation:
|
|||||||
|
|
||||||
|
|
||||||
@pytest.mark.live
|
@pytest.mark.live
|
||||||
@pytest.mark.xdist_group("service_isolation_live")
|
|
||||||
class TestApiLifespanLiveIsolation:
|
class TestApiLifespanLiveIsolation:
|
||||||
"""Real API lifespan against real DB and real host state."""
|
"""Real API lifespan against real DB and real host state."""
|
||||||
|
|
||||||
@@ -447,7 +442,6 @@ class TestApiLifespanLiveIsolation:
|
|||||||
|
|
||||||
|
|
||||||
@pytest.mark.live
|
@pytest.mark.live
|
||||||
@pytest.mark.xdist_group("service_isolation_live")
|
|
||||||
class TestCascadeLiveIsolation:
|
class TestCascadeLiveIsolation:
|
||||||
"""Verify that real component failures do not cascade."""
|
"""Verify that real component failures do not cascade."""
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user