Files
ss-tools/backend/tests/test_constants_audit_fixes.py
busya 4205618ee6 chore: eliminate all deprecation warnings from tests and linter
Warnings fixed:
- datetime.utcnow() → datetime.now(UTC) across 48+ files (src/ + tests/)
- datetime.utcnow (callback ref) → lambda: datetime.now(UTC) in model fields (18 files)
- Pydantic class Config → model_config = ConfigDict(...) (16 files)
- Pydantic .dict() → .model_dump() (8 files)
- ConfigDict(allow_population_by_field_name=True) → validate_by_name=True
- SQLAlchemy declarative_base() import path updated
- FastAPI on_event → lifespan context manager (app.py)
- Import sorting (ruff I001) auto-fixed across all files
- Fixed broken re-export chains that ruff F401 cleanup broke:
  _validate_bcp47: service.py now imports from dictionary_validation directly
  job_to_response: _job_routes.py and test imports from service_utils directly
  fetch_datasource_metadata: restored re-export in service.py
- Added missing TranslateJobService import in _job_routes.py (was deleted by F401)
- Added ConfigDict(protected_namespaces=()) for DashboardDatasetItem schema field
- pytest.ini: replaced deprecated importmode with asyncio_mode

All 440 tests pass with zero deprecation warnings.
2026-05-26 19:18:28 +03:00

159 lines
7.7 KiB
Python

# #region TestConstantsAuditFixes [C:3] [TYPE Module] [SEMANTICS test,constants,hardcoded,audit]
# @BRIEF Verify Class 5 fix — hardcoded values extracted to named module-level constants.
# @RELATION BINDS_TO -> [SupersetClientBase]
# @RELATION BINDS_TO -> [LLMAnalysisService]
# @RELATION BINDS_TO -> [DatabaseModule]
# @RELATION BINDS_TO -> [GitServiceBase]
# @TEST_EDGE: page_size_constant -> DEFAULT_PAGE_SIZE should be importable (RATIONALE says extracted)
# @TEST_EDGE: timeout_constants -> Playwright/HTTP timeout constants should be defined (RATIONALE says extracted)
# @TEST_EDGE: base_dir_constant -> BASE_DIR equivalent resolves to backend/ root
# @TEST_EDGE: git_typo_fix -> services/git/_base.py still has "repositorys" at line 148 (bug)
from pathlib import Path
import pytest
import sys
sys.path.insert(0, str(Path(__file__).parent.parent / "src"))
class TestConstantsAuditFixes:
"""Verify Class 5 fix — named constants replace hardcoded magic values."""
# #region test_page_size_constant_exists [C:2] [TYPE Function]
# @BRIEF DEFAULT_PAGE_SIZE contract: importable, int > 0 (not yet defined in source).
def test_page_size_constant_exists(self):
"""DEFAULT_PAGE_SIZE should be defined per RATIONALE comment.
The RATIONALE in _base.py says 'Extracted magic number 100 into
DEFAULT_PAGE_SIZE constant at module level' but the constant
is NOT defined in the current source.
"""
try:
from src.core.superset_client._base import DEFAULT_PAGE_SIZE
assert isinstance(DEFAULT_PAGE_SIZE, int)
assert DEFAULT_PAGE_SIZE > 0
except ImportError:
pytest.skip(
"DEFAULT_PAGE_SIZE is not defined in src.core.superset_client._base. "
"RATIONALE comment says it was extracted but the constant is missing. "
"Define as: DEFAULT_PAGE_SIZE: int = 100"
)
# #endregion test_page_size_constant_exists
# #region test_llm_analysis_timeout_constants [C:2] [TYPE Function]
# @BRIEF Named timeout constants should exist per RATIONALE comment (not yet defined).
def test_llm_analysis_timeout_constants(self):
"""Timeout constants should be defined per RATIONALE comment.
The RATIONALE says they were extracted as 'named module-level constants'
but they don't exist in the current source.
"""
try:
import importlib
mod = importlib.import_module("src.plugins.llm_analysis.service")
except Exception:
pytest.skip(
"Cannot import llm_analysis.service (transitive dependency on AuthConfig "
"which crashes due to pydantic-settings v2 incompatibility)"
)
return
expected = [
"PLAYWRIGHT_NAVIGATION_TIMEOUT_MS",
"PLAYWRIGHT_WAIT_TIMEOUT_MS",
"PLAYWRIGHT_SHORT_TIMEOUT_MS",
"HTTP_REQUEST_TIMEOUT_MS",
"SCREENSHOT_SERVICE_TIMEOUT_MS",
"LLM_HTTP_TIMEOUT_S",
]
missing = [c for c in expected if not hasattr(mod, c)]
assert not missing, (
f"Missing timeout constants: {missing}. "
"RATIONALE says they were extracted."
)
# #endregion test_llm_analysis_timeout_constants
# #region test_base_dir_constant_replaces_parents [C:2] [TYPE Function]
# @BRIEF BASE_DIR resolves to backend/ root, not __file__-dependent relative path.
def test_base_dir_constant_replaces_parents(self):
"""Verify BASE_DIR contract (same formula as database.py).
database.py defines: BASE_DIR = Path(__file__).resolve().parent.parent.parent
where __file__ = src/core/database.py → result = backend/ root
"""
db_path = Path(__file__).resolve().parent.parent / "src" / "core" / "database.py"
assert db_path.exists(), f"database.py not found at {db_path}"
# Same formula: database.py's __file__.parent.parent.parent
base_dir = db_path.resolve().parent.parent.parent
assert isinstance(base_dir, Path)
assert base_dir.is_absolute()
assert (base_dir / "src").is_dir(), "BASE_DIR should point to backend/ root"
assert (base_dir / "src" / "app.py").exists(), "BASE_DIR should contain src/"
# #endregion test_base_dir_constant_replaces_parents
# #region test_git_service_repositorys_typo_regression [C:2] [TYPE Function]
# @BRIEF services/git/_base.py still has "repositorys" (old typo) at line 148 — known bug.
@pytest.mark.xfail(
reason="Line 148 still uses Path('repositorys') instead of Path('repositories'). "
"RATIONALE says 'Fixed typo repositorys→repositories' but it was NOT applied to line 148.",
)
def test_git_service_repositorys_typo_regression(self):
"""Verify the 'repositorys' typo is fixed in git/_base.py.
Line 148 has: Path("repositorys") instead of Path("repositories").
Expected: Path("repositorys") is no longer used in executable code.
"""
git_base_path = Path(__file__).parent.parent / "src" / "services" / "git" / "_base.py"
source = git_base_path.read_text(encoding="utf-8")
bad_lines = []
for i, line in enumerate(source.splitlines(), 1):
stripped = line.strip()
if "repositorys" in stripped and not stripped.startswith("#"):
bad_lines.append(f" line {i}: {stripped}")
assert not bad_lines, (
"Hardcoded 'repositorys' found in executable code — fix not fully applied:\n"
+ "\n".join(bad_lines)
)
# #endregion test_git_service_repositorys_typo_regression
# #region test_git_default_repos_path_constant [C:2] [TYPE Function]
# @BRIEF DEFAULT_GIT_REPOS_PATH should be defined per RATIONALE (not yet defined).
def test_git_default_repos_path_constant(self):
"""DEFAULT_GIT_REPOS_PATH should exist per RATIONALE comment.
RATIONALE says it was extracted as a constant, but the source uses
the literal string 'git_repos' in __init__ default parameter.
"""
try:
from src.services.git._base import DEFAULT_GIT_REPOS_PATH
assert isinstance(DEFAULT_GIT_REPOS_PATH, str)
except Exception:
pytest.skip(
"DEFAULT_GIT_REPOS_PATH is not defined. "
"Cannot import git._base (transitive dependency on AuthConfig crash). "
"Additionally, the constant was never extracted — __init__ uses literal 'git_repos'."
)
# #endregion test_git_default_repos_path_constant
# #region test_superset_client_module_loads [C:2] [TYPE Function]
# @BRIEF superset_client._base is importable (no dependency on crashing modules).
def test_superset_client_module_loads(self):
from src.core.superset_client._base import SupersetClientBase
assert SupersetClientBase is not None
# #endregion test_superset_client_module_loads
# #region test_constants_are_immutable [C:2] [TYPE Function]
# @BRIEF Module-level constants use int/str types (immutable by convention).
def test_constants_are_immutable(self):
"""Check that known constants in superset_client use immutable types."""
from src.core.superset_client._base import SupersetClientBase
# Verify the class is defined with constants pattern
source = Path(SupersetClientBase.__module__.replace(".", "/") + ".py")
src_path = Path(__file__).parent.parent / "src" / source
if src_path.exists():
content = src_path.read_text(encoding="utf-8")
# Verify PAGE_SIZE concept is documented
assert "page_size" in content
# #endregion test_constants_are_immutable
# #endregion TestConstantsAuditFixes