mirror of
https://github.com/got-feedBack/feedBack.git
synced 2026-08-13 04:09:26 +00:00
fix(tests): isolate plugin routes modules + redact .feedpak filenames (#736)
Two pre-existing failures the segfault had been masking (the run aborted at ~25%, so they never ran until #735 let the suite complete): 1) Tuner group (~24): plugins ship a bare-named routes.py, so sys.modules['routes'] leaked between plugin test dirs (achievements ran first, tuner got its module). Each plugin conftest now pops the stale 'routes' and an autouse fixture binds sys.modules['routes'] to that plugin's module for the duration of its tests (covers runtime 'import routes' in test bodies). 2) Diagnostics group (5): _SONG_FILENAME_RE never matched the tests' .feedpak/.archive filenames — it also lacked 'feedpak' (the current primary format), a real redaction gap. Added feedpak to the regex and switched the tests off the fake .archive to the real .feedpak. Verified: full suite 2183 passed, 0 failed. Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 4.8
parent
97a941c45d
commit
286c59707b
@@ -34,7 +34,7 @@ _QSTRING_SECRET_RE = re.compile(
|
|||||||
r"(?i)\b(api[_-]?key|key|token|secret|password|pwd|auth)=([^\s&\"']+)"
|
r"(?i)\b(api[_-]?key|key|token|secret|password|pwd|auth)=([^\s&\"']+)"
|
||||||
)
|
)
|
||||||
_SONG_FILENAME_RE = re.compile(
|
_SONG_FILENAME_RE = re.compile(
|
||||||
r"\b[\w()'\-+&,.!?\[\]]+\.(?:psarc|sloppak|wem|ogg|mp3|wav)\b",
|
r"\b[\w()'\-+&,.!?\[\]]+\.(?:psarc|sloppak|feedpak|wem|ogg|mp3|wav)\b",
|
||||||
re.IGNORECASE,
|
re.IGNORECASE,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|||||||
@@ -7,6 +7,8 @@ import pytest
|
|||||||
from fastapi import FastAPI
|
from fastapi import FastAPI
|
||||||
from fastapi.testclient import TestClient
|
from fastapi.testclient import TestClient
|
||||||
|
|
||||||
|
# Drop a sibling 'routes' cached by another plugin's tests (bare-name collision).
|
||||||
|
sys.modules.pop('routes', None)
|
||||||
import routes as ach_routes
|
import routes as ach_routes
|
||||||
|
|
||||||
|
|
||||||
@@ -26,3 +28,17 @@ def client(tmp_path):
|
|||||||
app = FastAPI()
|
app = FastAPI()
|
||||||
ach_routes.setup(app, {"config_dir": str(tmp_path)})
|
ach_routes.setup(app, {"config_dir": str(tmp_path)})
|
||||||
return TestClient(app)
|
return TestClient(app)
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.fixture(autouse=True)
|
||||||
|
def _bind_ach_routes():
|
||||||
|
"""Keep sys.modules['routes'] pointing at THIS plugin's routes for these tests."""
|
||||||
|
prev = sys.modules.get('routes')
|
||||||
|
sys.modules['routes'] = ach_routes
|
||||||
|
try:
|
||||||
|
yield
|
||||||
|
finally:
|
||||||
|
if prev is not None:
|
||||||
|
sys.modules['routes'] = prev
|
||||||
|
else:
|
||||||
|
sys.modules.pop('routes', None)
|
||||||
|
|||||||
@@ -5,6 +5,8 @@ sys.path.insert(0, str(Path(__file__).parent.parent.parent.parent / 'plugins' /
|
|||||||
import pytest
|
import pytest
|
||||||
from fastapi import FastAPI
|
from fastapi import FastAPI
|
||||||
from fastapi.testclient import TestClient
|
from fastapi.testclient import TestClient
|
||||||
|
# Drop a sibling 'routes' cached by another plugin's tests (bare-name collision).
|
||||||
|
sys.modules.pop('routes', None)
|
||||||
import routes as tuner_routes
|
import routes as tuner_routes
|
||||||
|
|
||||||
|
|
||||||
@@ -22,3 +24,19 @@ def client(config_dir):
|
|||||||
"unregister_tuning_provider": lambda pid: None,
|
"unregister_tuning_provider": lambda pid: None,
|
||||||
})
|
})
|
||||||
return TestClient(app)
|
return TestClient(app)
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.fixture(autouse=True)
|
||||||
|
def _bind_tuner_routes():
|
||||||
|
"""Keep sys.modules['routes'] pointing at THIS plugin's routes for these
|
||||||
|
tests, so a runtime `import routes` in a test body resolves correctly
|
||||||
|
regardless of which other plugin's bare-named routes ran first."""
|
||||||
|
prev = sys.modules.get('routes')
|
||||||
|
sys.modules['routes'] = tuner_routes
|
||||||
|
try:
|
||||||
|
yield
|
||||||
|
finally:
|
||||||
|
if prev is not None:
|
||||||
|
sys.modules['routes'] = prev
|
||||||
|
else:
|
||||||
|
sys.modules.pop('routes', None)
|
||||||
|
|||||||
@@ -204,7 +204,7 @@ def test_client_audio_session_contribution_redacts_paths(tmp_path):
|
|||||||
kw["client_contributions"] = {
|
kw["client_contributions"] = {
|
||||||
"note_detect": {
|
"note_detect": {
|
||||||
"schema": "feedBack.audio_session.diagnostics.v1",
|
"schema": "feedBack.audio_session.diagnostics.v1",
|
||||||
"session": {"sessionId": str(home_path / "DLC" / "private-song.archive")},
|
"session": {"sessionId": str(home_path / "DLC" / "private-song.feedpak")},
|
||||||
"domains": {"audio-input": {"sources": [{"label": str(home_path / "devices" / "raw-id")}]}},
|
"domains": {"audio-input": {"sources": [{"label": str(home_path / "devices" / "raw-id")}]}},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1541,7 +1541,7 @@ def test_console_error_object_args_are_redacted(tmp_path):
|
|||||||
kw = _basic_kwargs(tmp_path)
|
kw = _basic_kwargs(tmp_path)
|
||||||
kw["include"]["console"] = True
|
kw["include"]["console"] = True
|
||||||
kw["redact"] = True
|
kw["redact"] = True
|
||||||
secret_path = "/home/alice/Music/DLC/my_song.archive"
|
secret_path = "/home/alice/Music/DLC/my_song.feedpak"
|
||||||
kw["client_console"] = [
|
kw["client_console"] = [
|
||||||
{
|
{
|
||||||
"level": "error",
|
"level": "error",
|
||||||
@@ -1567,13 +1567,13 @@ def test_console_string_args_still_redacted(tmp_path):
|
|||||||
kw["include"]["console"] = True
|
kw["include"]["console"] = True
|
||||||
kw["redact"] = True
|
kw["redact"] = True
|
||||||
kw["client_console"] = [
|
kw["client_console"] = [
|
||||||
{"level": "log", "msg": "ok", "args": ["loaded /home/alice/Music/DLC/my_song.archive ok"]},
|
{"level": "log", "msg": "ok", "args": ["loaded /home/alice/Music/DLC/my_song.feedpak ok"]},
|
||||||
]
|
]
|
||||||
zip_bytes, _name, _m = db.build_bundle(**kw)
|
zip_bytes, _name, _m = db.build_bundle(**kw)
|
||||||
with _open_zip(zip_bytes) as zf:
|
with _open_zip(zip_bytes) as zf:
|
||||||
console = json.loads(zf.read("client/console.json"))
|
console = json.loads(zf.read("client/console.json"))
|
||||||
# The song filename should be replaced with a hash token, not appear verbatim.
|
# The song filename should be replaced with a hash token, not appear verbatim.
|
||||||
assert "my_song.archive" not in console["entries"][0]["args"][0]
|
assert "my_song.feedpak" not in console["entries"][0]["args"][0]
|
||||||
|
|
||||||
|
|
||||||
def test_console_non_string_non_dict_args_pass_through(tmp_path):
|
def test_console_non_string_non_dict_args_pass_through(tmp_path):
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ from diagnostics_redact import Redactor
|
|||||||
|
|
||||||
def test_dlc_path_replaced():
|
def test_dlc_path_replaced():
|
||||||
r = Redactor(dlc_dir=Path("/dlc/songs"))
|
r = Redactor(dlc_dir=Path("/dlc/songs"))
|
||||||
out = r.redact_text("loaded from /dlc/songs/foo.archive")
|
out = r.redact_text("loaded from /dlc/songs/foo.feedpak")
|
||||||
assert "<DLC_DIR>" in out
|
assert "<DLC_DIR>" in out
|
||||||
assert "/dlc/songs" not in out
|
assert "/dlc/songs" not in out
|
||||||
assert r.counts["paths_replaced"] == 1
|
assert r.counts["paths_replaced"] == 1
|
||||||
@@ -13,8 +13,8 @@ def test_dlc_path_replaced():
|
|||||||
|
|
||||||
def test_song_filename_redacted_consistently():
|
def test_song_filename_redacted_consistently():
|
||||||
r = Redactor()
|
r = Redactor()
|
||||||
a = r.redact_text("Loading Test-Artist_Test-Song.archive")
|
a = r.redact_text("Loading Test-Artist_Test-Song.feedpak")
|
||||||
b = r.redact_text("Replaying Test-Artist_Test-Song.archive again")
|
b = r.redact_text("Replaying Test-Artist_Test-Song.feedpak again")
|
||||||
token_a = a.split("Loading ")[1].strip()
|
token_a = a.split("Loading ")[1].strip()
|
||||||
token_b = b.split("Replaying ")[1].split(" ")[0]
|
token_b = b.split("Replaying ")[1].split(" ")[0]
|
||||||
assert token_a == token_b
|
assert token_a == token_b
|
||||||
@@ -63,8 +63,8 @@ def test_home_dir_replaced():
|
|||||||
def test_different_redactors_produce_different_tokens():
|
def test_different_redactors_produce_different_tokens():
|
||||||
a = Redactor()
|
a = Redactor()
|
||||||
b = Redactor()
|
b = Redactor()
|
||||||
out_a = a.redact_text("Foo.archive")
|
out_a = a.redact_text("Foo.feedpak")
|
||||||
out_b = b.redact_text("Foo.archive")
|
out_b = b.redact_text("Foo.feedpak")
|
||||||
assert out_a != out_b
|
assert out_a != out_b
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user