Skip to content

Commit b9d2991

Browse files
committed
test improvement and fix
1 parent af024e6 commit b9d2991

10 files changed

Lines changed: 112 additions & 14 deletions

File tree

.github/workflows/lint-flake8.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,4 +28,4 @@ jobs:
2828
2929
- name: Run flake8 static analysis
3030
run: |
31-
flake8 . --count --select=E9,F63,F7,F82 --show-source --statistics
31+
flake8 . --count --select=E9,F63,F7,F82,F401,F811 --show-source --statistics

app.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -173,7 +173,8 @@ def teardown_db(e=None):
173173
else:
174174
app.logger.info("RQ worker mode: skipping startup database schema bootstrap.")
175175

176-
import app_setup
176+
import importlib
177+
importlib.import_module('app_setup')
177178

178179
# --- API Endpoints ---
179180

app_helper.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@
2121
import numpy as np
2222

2323
import database
24-
from database import (
24+
from database import ( # noqa: F401
2525
get_db, close_db, save_task_status, record_task_history, _build_task_note,
2626
get_score_data_by_ids, load_map_projection, get_task_info_from_db, get_tracks_by_ids,
2727
save_track_analysis_and_embedding, save_clap_embedding, get_clap_embedding, save_lyrics_embedding,
@@ -37,7 +37,7 @@
3737
send_stop_job_command,
3838
)
3939

40-
from config import (
40+
from config import ( # noqa: F401
4141
STRATIFIED_GENRES,
4242
TASK_STATUS_PENDING, TASK_STATUS_STARTED, TASK_STATUS_PROGRESS,
4343
TASK_STATUS_SUCCESS, TASK_STATUS_FAILURE, TASK_STATUS_REVOKED,

tasks/analysis.py

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11,12 +11,11 @@
1111
import time
1212
import logging
1313
import uuid
14-
import traceback
1514
import gc
1615
import platform
1716

1817
import librosa
19-
import onnxruntime as ort # re-exported: tests patch `tasks.analysis.ort.InferenceSession`
18+
import onnxruntime as ort # noqa: F401 re-exported: tests patch `tasks.analysis.ort.InferenceSession`
2019

2120
# RQ import
2221
from rq import get_current_job, Retry
@@ -70,7 +69,7 @@
7069
# tests depend on (``run_inference``, ``_find_onnx_name``, ``sigmoid``).
7170
# Helpers consumed only inside this file go through ``_ah.<name>`` instead.
7271
from . import analysis_helper as _ah
73-
from .analysis_helper import (
72+
from .analysis_helper import ( # noqa: F401
7473
DEFINED_TENSOR_NAMES,
7574
_find_onnx_name, # re-export: tests do `from tasks.analysis import _find_onnx_name`
7675
run_inference, # re-export: tests do `from tasks.analysis import run_inference`

tasks/analysis_helper.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -566,7 +566,7 @@ def run_lyrics_for_track(item, path, track_audio, track_sr, track_name_full,
566566
if track_audio is None or track_audio.size == 0 or track_sr is None:
567567
raise RuntimeError("Failed to load audio for lyrics analysis")
568568
else:
569-
def audio_loader():
569+
def audio_loader(): # noqa: F811
570570
p = download_fn() if download_fn is not None else None
571571
if not p:
572572
raise RuntimeError("Failed to download audio for lyrics ASR")

tasks/clustering_gpu.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,7 @@ def check_gpu_available():
6464

6565
try:
6666
import cupy as cp
67-
import cuml
67+
import cuml # noqa: F401
6868
# Try to create a small array on GPU to verify it works
6969
test_array = cp.array([1, 2, 3])
7070
_ = test_array.sum()

tasks/sem_grove_manager.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -338,7 +338,7 @@ def _merge_batches():
338338
def _load_sem_grove_index_from_db() -> bool:
339339
"""Load the SemGrove merged Voyager index from the DB into the global cache."""
340340
try:
341-
import voyager # type: ignore
341+
import voyager # type: ignore # noqa: F401
342342
except ImportError:
343343
logger.warning("Voyager unavailable; cannot load SemGrove index.")
344344
return False

test/integration/test_gpu_status.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -115,22 +115,22 @@ def test_cuml_clustering():
115115
# Test cuML KMeans
116116
cuml_ok = False
117117
try:
118-
from cuml.cluster import KMeans as cuKMeans
118+
from cuml.cluster import KMeans as cuKMeans # noqa: F401
119119
print_result("cuML KMeans", True, "Import successful")
120120
cuml_ok = True
121121
except Exception as e:
122122
print_result("cuML KMeans", False, str(e))
123123

124124
# Test cuML DBSCAN
125125
try:
126-
from cuml.cluster import DBSCAN as cuDBSCAN
126+
from cuml.cluster import DBSCAN as cuDBSCAN # noqa: F401
127127
print_result("cuML DBSCAN", True, "Import successful")
128128
except Exception as e:
129129
print_result("cuML DBSCAN", False, str(e))
130130

131131
# Test cuML PCA
132132
try:
133-
from cuml.decomposition import PCA as cuPCA
133+
from cuml.decomposition import PCA as cuPCA # noqa: F401
134134
print_result("cuML PCA", True, "Import successful")
135135
except Exception as e:
136136
print_result("cuML PCA", False, str(e))

test/unit/test_app_logging.py

Lines changed: 98 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,98 @@
1+
"""Unit tests for app_logging's record sanitization.
2+
3+
Covers the two jobs of ``_sanitize_log_text`` / ``LogSanitizingFilter``:
4+
console-safety (emoji and non-Latin-1 symbol stripping for Windows code-pages)
5+
and log-injection safety (CR/LF and other control characters are neutralised so
6+
an attacker-controlled value cannot forge or split log lines -- CWE-117).
7+
8+
Emoji and accented characters are built with ``chr()`` so this source file
9+
stays pure ASCII.
10+
"""
11+
import logging
12+
13+
from app_logging import _sanitize_log_text, LogSanitizingFilter, configure_logging
14+
15+
_CHECK_MARK = chr(0x2705)
16+
_MUSIC_NOTE = chr(0x1F3B5)
17+
_ACCENTED = "caf" + chr(0xE9) + " se" + chr(0xF1) + "or " + chr(0xFC) + "ber"
18+
19+
20+
class TestSanitizeLogText:
21+
def test_removes_emoji_and_symbols(self):
22+
assert _sanitize_log_text("done " + _CHECK_MARK) == "done"
23+
assert _sanitize_log_text("track " + _MUSIC_NOTE + " ready") == "track ready"
24+
25+
def test_newline_becomes_space(self):
26+
assert _sanitize_log_text("hello\nworld") == "hello world"
27+
28+
def test_crlf_collapses_to_single_space(self):
29+
assert _sanitize_log_text("hello\r\nworld") == "hello world"
30+
31+
def test_control_chars_become_space(self):
32+
assert _sanitize_log_text("a\x00b\x07c\x7f") == "a b c"
33+
34+
def test_tab_is_preserved(self):
35+
assert _sanitize_log_text("col1\tcol2") == "col1\tcol2"
36+
37+
def test_latin1_accents_pass_through(self):
38+
assert _sanitize_log_text(_ACCENTED) == _ACCENTED
39+
40+
def test_log_injection_cannot_forge_a_line(self):
41+
forged = "user42\n[INFO]-[fake]-dropped all tables"
42+
result = _sanitize_log_text(forged)
43+
assert "\n" not in result
44+
assert "\r" not in result
45+
assert result == "user42 [INFO]-[fake]-dropped all tables"
46+
47+
def test_non_string_returned_unchanged(self):
48+
assert _sanitize_log_text(123) == 123
49+
assert _sanitize_log_text(None) is None
50+
51+
52+
class TestLogSanitizingFilter:
53+
def _record(self, msg, args=None):
54+
return logging.LogRecord(
55+
name="test", level=logging.INFO, pathname=__file__, lineno=1,
56+
msg=msg, args=args, exc_info=None,
57+
)
58+
59+
def test_sanitizes_msg(self):
60+
record = self._record("oops\ninjected " + _CHECK_MARK)
61+
LogSanitizingFilter().filter(record)
62+
assert record.msg == "oops injected"
63+
64+
def test_sanitizes_tuple_args_leaving_non_strings(self):
65+
record = self._record("%s %s", args=("a\nb", 7))
66+
LogSanitizingFilter().filter(record)
67+
assert record.args == ("a b", 7)
68+
69+
def test_sanitizes_dict_args(self):
70+
record = self._record("%(x)s")
71+
record.args = {"x": "p\nq", "n": 3}
72+
LogSanitizingFilter().filter(record)
73+
assert record.args == {"x": "p q", "n": 3}
74+
75+
def test_filter_always_returns_true(self):
76+
assert LogSanitizingFilter().filter(self._record("hi")) is True
77+
78+
79+
class TestConfigureLogging:
80+
def test_attaches_sanitizing_filter_once(self):
81+
root = logging.getLogger()
82+
saved = {handler: list(handler.filters) for handler in root.handlers}
83+
try:
84+
configure_logging()
85+
configure_logging()
86+
assert root.handlers
87+
for handler in root.handlers:
88+
count = sum(isinstance(f, LogSanitizingFilter) for f in handler.filters)
89+
assert count == 1
90+
finally:
91+
for handler in root.handlers:
92+
if handler in saved:
93+
handler.filters = saved[handler]
94+
else:
95+
handler.filters = [
96+
f for f in handler.filters
97+
if not isinstance(f, LogSanitizingFilter)
98+
]

test/unit/test_index_build_helpers.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -759,7 +759,7 @@ def test_rejects_batch_with_mismatched_ids_length(self):
759759

760760
def test_skips_empty_batches_silently(self):
761761
try:
762-
import voyager
762+
import voyager # noqa: F401
763763
except ImportError:
764764
pytest.skip("voyager not installed")
765765
rng = np.random.default_rng(5)

0 commit comments

Comments
 (0)