chore(lint): apply ruff --fix (4443 auto-fixes)

Auto-fixed categories:
- F401: unused imports removed
- I001: import blocks sorted
- W293: trailing whitespace stripped
- UP035: deprecated typing imports replaced
- SIM: simplify suggestions applied
- ARG: unused args prefixed with underscore
- T201: print statements removed
- F841: unused variables removed
- RUF059: unpacked variables prefixed

Remaining ~1500 unfixable errors (C901, B904, N806, E402) require manual work.

Backend smoke tests: 13/13 passed.
This commit is contained in:
2026-05-14 11:20:17 +03:00
parent a9a5eff518
commit c6189876b3
337 changed files with 4677 additions and 4515 deletions

View File

@@ -1,15 +1,17 @@
import shutil
import sys
from pathlib import Path
import shutil
import pytest
from unittest.mock import MagicMock, patch
import pytest
from git.exc import InvalidGitRepositoryError
sys.path.insert(0, str(Path(__file__).parent.parent.parent))
from src.services.git_service import GitService
from src.core.superset_client import SupersetClient
from src.core.config_models import Environment
from src.core.superset_client import SupersetClient
from src.services.git_service import GitService
# [DEF:test_git_service_get_repo_path_guard:Function]
# @RELATION: BINDS_TO -> UnknownModule

View File

@@ -9,8 +9,8 @@ import asyncio
import sys
from pathlib import Path
from fastapi import HTTPException
import pytest
from fastapi import HTTPException
sys.path.insert(0, str(Path(__file__).parent.parent.parent))

View File

@@ -4,21 +4,21 @@
# @LAYER: Domain
# @RELATION: VERIFIES ->[src.core.mapping_service.IdMappingService]
#
import sys
from datetime import UTC, datetime
from pathlib import Path
import pytest
from datetime import datetime, timezone
from sqlalchemy import create_engine
from sqlalchemy.orm import sessionmaker
import sys
import os
from pathlib import Path
# Add backend directory to sys.path so 'src' can be resolved
backend_dir = str(Path(__file__).parent.parent.parent.resolve())
if backend_dir not in sys.path:
sys.path.insert(0, backend_dir)
from src.models.mapping import Base, ResourceMapping, ResourceType
from src.core.mapping_service import IdMappingService
from src.models.mapping import Base, ResourceMapping, ResourceType
@pytest.fixture
@@ -80,7 +80,7 @@ def test_get_remote_id_returns_integer(db_session):
uuid="uuid-1",
remote_integer_id="99",
resource_name="Test DS",
last_synced_at=datetime.now(timezone.utc),
last_synced_at=datetime.now(UTC),
)
db_session.add(mapping)
db_session.commit()

View File

@@ -4,24 +4,21 @@
# @LAYER: Domain
# @RELATION: VERIFIES -> [src.core.migration_engine:Module]
#
import pytest
import tempfile
import json
import yaml
import zipfile
import sys
import os
import sys
import tempfile
import zipfile
from pathlib import Path
from unittest.mock import MagicMock
import pytest
import yaml
backend_dir = str(Path(__file__).parent.parent.parent.resolve())
if backend_dir not in sys.path:
sys.path.insert(0, backend_dir)
from src.core.migration_engine import MigrationEngine
from src.core.mapping_service import IdMappingService
from src.models.mapping import ResourceType
# --- Fixtures ---
@@ -80,7 +77,7 @@ def test_patch_dashboard_metadata_replaces_chart_ids():
engine._patch_dashboard_metadata(fp, "target-env", source_map)
with open(fp, "r") as f:
with open(fp) as f:
data = yaml.safe_load(f)
result = json.loads(data["json_metadata"])
assert (
@@ -107,7 +104,7 @@ def test_patch_dashboard_metadata_replaces_dataset_ids():
engine._patch_dashboard_metadata(fp, "target-env", source_map)
with open(fp, "r") as f:
with open(fp) as f:
data = yaml.safe_load(f)
result = json.loads(data["json_metadata"])
assert (
@@ -134,7 +131,7 @@ def test_patch_dashboard_metadata_skips_when_no_metadata():
engine._patch_dashboard_metadata(fp, "target-env", {})
with open(fp, "r") as f:
with open(fp) as f:
data = yaml.safe_load(f)
assert "json_metadata" not in data
@@ -162,7 +159,7 @@ def test_patch_dashboard_metadata_handles_missing_targets():
engine._patch_dashboard_metadata(fp, "target-env", source_map)
with open(fp, "r") as f:
with open(fp) as f:
data = yaml.safe_load(f)
result = json.loads(data["json_metadata"])
targets = result["native_filter_configuration"][0]["targets"]
@@ -219,7 +216,7 @@ def test_transform_yaml_replaces_database_uuid():
engine._transform_yaml(fp, {"source-uuid-abc": "target-uuid-xyz"})
with open(fp, "r") as f:
with open(fp) as f:
data = yaml.safe_load(f)
assert data["database_uuid"] == "target-uuid-xyz"
assert data["table_name"] == "my_table"
@@ -243,7 +240,7 @@ def test_transform_yaml_ignores_unmapped_uuid():
engine._transform_yaml(fp, {"other-uuid": "replacement"})
with open(fp, "r") as f:
with open(fp) as f:
data = yaml.safe_load(f)
assert data["database_uuid"] == "unknown-uuid"
@@ -317,12 +314,12 @@ def test_transform_zip_end_to_end():
out_path = Path(out_dir)
# Verify dataset transformation
with open(out_path / "datasets" / "ds.yaml", "r") as f:
with open(out_path / "datasets" / "ds.yaml") as f:
ds_data = yaml.safe_load(f)
assert ds_data["database_uuid"] == "target-db-uuid"
# Verify dashboard patching
with open(out_path / "dashboards" / "db.yaml", "r") as f:
with open(out_path / "dashboards" / "db.yaml") as f:
db_data = yaml.safe_load(f)
meta = json.loads(db_data["json_metadata"])
assert (

View File

@@ -5,21 +5,19 @@
"""Smoke tests for the redesigned clean release CLI commands."""
from datetime import UTC, datetime
from types import SimpleNamespace
import json
from src.dependencies import get_clean_release_repository, get_config_manager
from datetime import datetime, timezone
from uuid import uuid4
from src.dependencies import get_clean_release_repository, get_config_manager
from src.models.clean_release import (
CleanPolicySnapshot,
ComplianceReport,
ReleaseCandidate,
SourceRegistrySnapshot,
)
from src.services.clean_release.enums import CandidateStatus, ComplianceDecision
from src.scripts.clean_release_cli import main as cli_main
from src.services.clean_release.enums import CandidateStatus, ComplianceDecision
# [DEF:test_cli_candidate_register_scaffold:Function]
@@ -227,7 +225,7 @@ def test_cli_release_gate_commands_scaffold() -> None:
version="1.0.0",
source_snapshot_ref="git:sha-approved",
created_by="cli-test",
created_at=datetime.now(timezone.utc),
created_at=datetime.now(UTC),
status=CandidateStatus.CHECK_PASSED.value,
)
)
@@ -237,7 +235,7 @@ def test_cli_release_gate_commands_scaffold() -> None:
version="1.0.0",
source_snapshot_ref="git:sha-rejected",
created_by="cli-test",
created_at=datetime.now(timezone.utc),
created_at=datetime.now(UTC),
status=CandidateStatus.CHECK_PASSED.value,
)
)
@@ -252,7 +250,7 @@ def test_cli_release_gate_commands_scaffold() -> None:
"violations_count": 0,
"blocking_violations_count": 0,
},
generated_at=datetime.now(timezone.utc),
generated_at=datetime.now(UTC),
immutable=True,
)
)
@@ -267,7 +265,7 @@ def test_cli_release_gate_commands_scaffold() -> None:
"violations_count": 0,
"blocking_violations_count": 0,
},
generated_at=datetime.now(timezone.utc),
generated_at=datetime.now(UTC),
immutable=True,
)
)

View File

@@ -5,17 +5,16 @@
# @LAYER: Scripts
# @INVARIANT: TUI initializes, handles hotkeys (F5, F10) and safely falls back without TTY.
import os
import sys
import curses
import json
import os
from unittest import mock
from unittest.mock import MagicMock, patch
import pytest
from src.scripts.clean_release_tui import CleanReleaseTUI, main, tui_main
from src.models.clean_release import CheckFinalStatus
from src.scripts.clean_release_tui import CleanReleaseTUI, main
@pytest.fixture
@@ -63,17 +62,17 @@ def test_tui_initial_render(mock_curses_module, mock_stdscr: MagicMock):
app = CleanReleaseTUI(mock_stdscr)
assert app.status == "READY"
# We only want to run one loop iteration, so we mock getch to return F10
mock_stdscr.getch.return_value = curses.KEY_F10
app.loop()
# Assert header was drawn
addstr_calls = mock_stdscr.addstr.call_args_list
assert any("Enterprise Clean Release Validator" in str(call) for call in addstr_calls)
assert any("Candidate: [2026.03.03-rc1]" in str(call) for call in addstr_calls)
# Assert checks list is shown
assert any("Data Purity" in str(call) for call in addstr_calls)
assert any("Internal Sources Only" in str(call) for call in addstr_calls)
@@ -98,7 +97,7 @@ def test_tui_run_checks_f5(mock_curses_module, mock_stdscr: MagicMock):
mock_curses_module.A_BOLD = 0
app = CleanReleaseTUI(mock_stdscr)
# getch sequence:
# 1. First loop: F5 (triggers run_checks)
# 2. Next call after run_checks: F10 to exit
@@ -108,12 +107,12 @@ def test_tui_run_checks_f5(mock_curses_module, mock_stdscr: MagicMock):
mock_stdscr.f5_pressed = True
return curses.KEY_F5
return curses.KEY_F10
mock_stdscr.getch.side_effect = side_effect
with mock.patch("time.sleep", return_value=None):
app.loop()
# After F5 is pressed, status should be BLOCKED due to deliberate 'test-data' violation
assert app.status == CheckFinalStatus.BLOCKED
assert app.report_id is not None
@@ -132,13 +131,13 @@ def test_tui_exit_f10(mock_curses_module, mock_stdscr: MagicMock):
"""
# Ensure constants match
mock_curses_module.KEY_F10 = curses.KEY_F10
app = CleanReleaseTUI(mock_stdscr)
mock_stdscr.getch.return_value = curses.KEY_F10
# loop() should return cleanly
app.loop()
assert app.status == "READY"
@@ -159,12 +158,12 @@ def test_tui_clear_history_f7(mock_curses_module, mock_stdscr: MagicMock):
app = CleanReleaseTUI(mock_stdscr)
app.status = CheckFinalStatus.BLOCKED
app.report_id = "SOME-REPORT"
# F7 then F10
mock_stdscr.getch.side_effect = [curses.KEY_F7, curses.KEY_F10]
app.loop()
assert app.status == "READY"
assert app.report_id is None
assert len(app.checks_progress) == 0

View File

@@ -7,7 +7,7 @@
from __future__ import annotations
from datetime import datetime, timezone
from datetime import UTC, datetime
import pytest
@@ -35,7 +35,7 @@ def _seed_candidate_with_report(
version="1.0.0",
source_snapshot_ref="git:sha-approve-1",
created_by="tester",
created_at=datetime.now(timezone.utc),
created_at=datetime.now(UTC),
status=CandidateStatus.CHECK_PASSED.value,
)
)
@@ -50,7 +50,7 @@ def _seed_candidate_with_report(
"violations_count": 0,
"blocking_violations_count": 0 if report_status == ComplianceDecision.PASSED else 1,
},
generated_at=datetime.now(timezone.utc),
generated_at=datetime.now(UTC),
immutable=True,
)
)
@@ -96,7 +96,7 @@ def test_approve_rejects_foreign_report():
candidate_id="cand-foreign-1",
final_status=ComplianceDecision.PASSED.value,
summary_json={"operator_summary": "foreign", "violations_count": 0, "blocking_violations_count": 0},
generated_at=datetime.now(timezone.utc),
generated_at=datetime.now(UTC),
immutable=True,
)
repository.save_report(foreign_report)
@@ -175,8 +175,8 @@ def test_reject_persists_decision_without_promoting_candidate_state():
# @POST: publish_candidate raises PublicationGateError.
def test_reject_then_publish_is_blocked():
from src.services.clean_release.approval_service import reject_candidate
from src.services.clean_release.publication_service import publish_candidate
from src.services.clean_release.exceptions import PublicationGateError
from src.services.clean_release.publication_service import publish_candidate
repository, candidate_id, report_id = _seed_candidate_with_report()
@@ -199,4 +199,4 @@ def test_reject_then_publish_is_blocked():
)
# [/DEF:test_reject_then_publish_is_blocked:Function]
# [/DEF:TestApprovalService:Module]
# [/DEF:TestApprovalService:Module]

View File

@@ -3,18 +3,19 @@
# @PURPOSE: Test lifecycle and manifest versioning for release candidates.
# @LAYER: Tests
from datetime import UTC, datetime
import pytest
from datetime import datetime, timezone
from sqlalchemy import create_engine
from sqlalchemy.orm import sessionmaker
from src.core.database import Base
from src.models.clean_release import (
ReleaseCandidate,
DistributionManifest,
CandidateArtifact,
ReleaseCandidate,
)
from src.services.clean_release.enums import CandidateStatus
from src.services.clean_release.candidate_service import register_candidate
from src.services.clean_release.enums import CandidateStatus
from src.services.clean_release.manifest_service import build_manifest_snapshot
from src.services.clean_release.repository import CleanReleaseRepository
@@ -79,7 +80,7 @@ def test_manifest_versioning_and_immutability(db_session):
artifacts_digest="hash1",
source_snapshot_ref="ref1",
content_json={},
created_at=datetime.now(timezone.utc),
created_at=datetime.now(UTC),
created_by="operator",
)
db_session.add(m1)
@@ -93,7 +94,7 @@ def test_manifest_versioning_and_immutability(db_session):
artifacts_digest="hash2",
source_snapshot_ref="ref1",
content_json={},
created_at=datetime.now(timezone.utc),
created_at=datetime.now(UTC),
created_by="operator",
)
db_session.add(m2)

View File

@@ -7,7 +7,7 @@
from __future__ import annotations
from datetime import datetime, timezone
from datetime import UTC, datetime
import pytest
@@ -46,7 +46,7 @@ def _seed_with_candidate_policy_registry(
version="1.0.0",
source_snapshot_ref="git:sha-us2",
created_by="tester",
created_at=datetime.now(timezone.utc),
created_at=datetime.now(UTC),
status=CandidateStatus.MANIFEST_BUILT.value,
)
)
@@ -89,7 +89,7 @@ def _seed_with_candidate_policy_registry(
}
},
created_by="tester",
created_at=datetime.now(timezone.utc),
created_at=datetime.now(UTC),
immutable=True,
)
)

View File

@@ -8,8 +8,8 @@
from __future__ import annotations
import asyncio
from datetime import datetime, timezone
from typing import Any, Dict
from datetime import UTC, datetime
from typing import Any
from unittest.mock import MagicMock, patch
import pytest
@@ -48,7 +48,7 @@ def _seed_repository(
version="1.0.0",
source_snapshot_ref="git:sha-task-int",
created_by="tester",
created_at=datetime.now(timezone.utc),
created_at=datetime.now(UTC),
status=CandidateStatus.MANIFEST_BUILT.value,
)
)
@@ -91,7 +91,7 @@ def _seed_repository(
}
},
created_by="tester",
created_at=datetime.now(timezone.utc),
created_at=datetime.now(UTC),
immutable=True,
)
)
@@ -114,7 +114,7 @@ class CleanReleaseCompliancePlugin:
def name(self) -> str:
return "clean_release_compliance"
def execute(self, params: Dict[str, Any], context=None):
def execute(self, params: dict[str, Any], context=None):
orchestrator = CleanComplianceOrchestrator(params["repository"])
run = orchestrator.start_check_run(
candidate_id=params["candidate_id"],

View File

@@ -6,7 +6,7 @@
from __future__ import annotations
from datetime import datetime, timezone
from datetime import UTC, datetime
from src.models.clean_release import ReleaseCandidate
from src.services.clean_release.demo_data_service import (
@@ -65,7 +65,7 @@ def test_create_isolated_repository_keeps_mode_data_separate() -> None:
version="1.0.0",
source_snapshot_ref="git:sha-demo",
created_by="demo-operator",
created_at=datetime.now(timezone.utc),
created_at=datetime.now(UTC),
status="DRAFT",
)
)
@@ -75,7 +75,7 @@ def test_create_isolated_repository_keeps_mode_data_separate() -> None:
version="1.0.0",
source_snapshot_ref="git:sha-real",
created_by="real-operator",
created_at=datetime.now(timezone.utc),
created_at=datetime.now(UTC),
status="DRAFT",
)
)

View File

@@ -7,7 +7,7 @@
from __future__ import annotations
from datetime import datetime, timezone
from datetime import UTC, datetime
import pytest
@@ -35,7 +35,7 @@ def _seed_candidate_with_passed_report(
version="1.0.0",
source_snapshot_ref="git:sha-publish-1",
created_by="tester",
created_at=datetime.now(timezone.utc),
created_at=datetime.now(UTC),
status=candidate_status.value,
)
)
@@ -46,7 +46,7 @@ def _seed_candidate_with_passed_report(
candidate_id=candidate_id,
final_status=ComplianceDecision.PASSED.value,
summary_json={"operator_summary": "seed", "violations_count": 0, "blocking_violations_count": 0},
generated_at=datetime.now(timezone.utc),
generated_at=datetime.now(UTC),
immutable=True,
)
)
@@ -146,4 +146,4 @@ def test_republish_after_revoke_creates_new_active_record():
assert second.status == PublicationStatus.ACTIVE.value
# [/DEF:test_republish_after_revoke_creates_new_active_record:Function]
# [/DEF:TestPublicationService:Module]
# [/DEF:TestPublicationService:Module]

View File

@@ -7,7 +7,7 @@
from __future__ import annotations
from datetime import datetime, timezone
from datetime import UTC, datetime
from unittest.mock import patch
import pytest
@@ -15,13 +15,11 @@ import pytest
from src.models.clean_release import (
ComplianceReport,
ComplianceRun,
ComplianceViolation,
)
from src.services.clean_release.audit_service import (
audit_check_run,
audit_preparation,
audit_report,
audit_violation,
)
from src.services.clean_release.enums import ComplianceDecision, RunStatus
from src.services.clean_release.report_builder import ComplianceReportBuilder
@@ -44,9 +42,9 @@ def _terminal_run(
policy_snapshot_id="policy-immut-1",
registry_snapshot_id="registry-immut-1",
requested_by="tester",
requested_at=datetime.now(timezone.utc),
started_at=datetime.now(timezone.utc),
finished_at=datetime.now(timezone.utc),
requested_at=datetime.now(UTC),
started_at=datetime.now(UTC),
finished_at=datetime.now(UTC),
status=RunStatus.SUCCEEDED,
final_status=final_status,
)
@@ -93,7 +91,7 @@ def test_repository_rejects_report_overwrite_for_same_report_id():
"violations_count": 0,
"blocking_violations_count": 0,
},
generated_at=datetime.now(timezone.utc),
generated_at=datetime.now(UTC),
immutable=True,
)
mutated = ComplianceReport(
@@ -106,7 +104,7 @@ def test_repository_rejects_report_overwrite_for_same_report_id():
"violations_count": 1,
"blocking_violations_count": 1,
},
generated_at=datetime.now(timezone.utc),
generated_at=datetime.now(UTC),
immutable=True,
)

View File

@@ -8,16 +8,14 @@
from types import SimpleNamespace
from unittest.mock import MagicMock
# Import models to ensure proper SQLAlchemy registration
from src.models.auth import User
from src.models.dataset_review import CompiledPreview
from src.core.utils.superset_compilation_adapter import (
PreviewCompilationPayload,
SqlLabLaunchPayload,
SupersetCompilationAdapter,
)
# Import models to ensure proper SQLAlchemy registration
# [DEF:make_adapter:Function]
# @PURPOSE: Build an adapter with a mock Superset client and deterministic environment for compatibility tests.

View File

@@ -13,16 +13,17 @@ from pathlib import Path
sys.path.append(str(Path(__file__).parent.parent / "src"))
import pytest
from cryptography.fernet import Fernet
from sqlalchemy import create_engine
from sqlalchemy.orm import sessionmaker
from cryptography.fernet import Fernet
from src.core.database import Base
from src.models.auth import User, Role, Permission, ADGroupMapping
from src.services.auth_service import AuthService
from src.core.auth.repository import AuthRepository
from src.core.auth.security import verify_password, get_password_hash
from src.core.auth.security import get_password_hash, verify_password
from src.core.database import Base
from src.models.auth import ADGroupMapping, Permission, Role, User
from src.scripts.create_admin import create_admin
from src.scripts.init_auth_db import ensure_encryption_key
from src.services.auth_service import AuthService
# Create in-memory SQLite database for testing
SQLALCHEMY_DATABASE_URL = "sqlite:///:memory:"

View File

@@ -10,11 +10,9 @@ from pathlib import Path
sys.path.insert(0, str(Path(__file__).parent.parent / "src"))
import pytest
from unittest.mock import MagicMock, patch
from datetime import datetime, timezone
from apscheduler.schedulers.background import BackgroundScheduler
from apscheduler.schedulers.background import BackgroundScheduler
# ---------------------------------------------------------------------------
# Helpers — fresh scheduler & mock config

View File

@@ -3,24 +3,26 @@
# @PURPOSE: Comprehensive contract-driven tests for Dashboard Hub API
# @LAYER: Domain (Tests)
# @SEMANTICS: tests, dashboards, api, contract, remediation
from datetime import UTC, datetime
from unittest.mock import AsyncMock, MagicMock, patch
import pytest
from fastapi.testclient import TestClient
from unittest.mock import MagicMock, patch, AsyncMock
from datetime import datetime, timezone
from src.app import app
from src.api.routes.dashboards import (
DashboardsResponse,
DashboardDetailResponse,
DashboardsResponse,
DashboardTaskHistoryResponse,
DatabaseMappingsResponse,
)
from src.app import app
from src.dependencies import (
get_current_user,
has_permission,
get_config_manager,
get_task_manager,
get_resource_service,
get_current_user,
get_mapping_service,
get_resource_service,
get_task_manager,
has_permission,
)
# Global mock user
@@ -299,7 +301,7 @@ def test_get_dashboard_detail_env_not_found(mock_deps):
# [DEF:test_get_dashboard_tasks_history_success:Function]
# @RELATION: BINDS_TO ->[TestDashboardsApi]
def test_get_dashboard_tasks_history_success(mock_deps):
now = datetime.now(timezone.utc)
now = datetime.now(UTC)
task1 = MagicMock(
id="t1",
plugin_id="superset-backup",
@@ -328,7 +330,7 @@ def test_get_dashboard_tasks_history_sorting(mock_deps):
"""@POST: Response contains sorted task history (newest first)."""
from datetime import timedelta
now = datetime.now(timezone.utc)
now = datetime.now(UTC)
older = now - timedelta(hours=2)
newest = now

View File

@@ -11,9 +11,10 @@ from unittest.mock import patch
from sqlalchemy import create_engine
from sqlalchemy.orm import sessionmaker
from src.models.mapping import Base
from src.core.task_manager.persistence import TaskLogPersistenceService
from src.core.task_manager.models import LogEntry, LogFilter
from src.core.task_manager.persistence import TaskLogPersistenceService
from src.models.mapping import Base
# [/SECTION]
# [DEF:TestLogPersistence:Class]

View File

@@ -5,18 +5,19 @@
# @RELATION: VERIFIES -> src/core/logger.py
# @INVARIANT: All required log statements must correctly check the threshold.
import pytest
import logging
import pytest
from src.core.config_models import LoggingConfig
from src.core.logger import (
CotJsonFormatter,
belief_scope,
logger,
configure_logger,
get_task_log_level,
logger,
should_log_task_level,
CotJsonFormatter,
)
from src.core.config_models import LoggingConfig
@pytest.fixture(autouse=True)
@@ -101,9 +102,8 @@ def test_belief_scope_error_handling(caplog):
caplog.set_level("DEBUG")
with pytest.raises(ValueError):
with belief_scope("FailingFunction"):
raise ValueError("Something went wrong")
with pytest.raises(ValueError), belief_scope("FailingFunction"):
raise ValueError("Something went wrong")
# Check that an EXPLORE marker was emitted
explore_records = [
@@ -294,7 +294,6 @@ def test_enable_belief_state_flag(caplog):
def test_cot_json_formatter_output():
"""Test that CotJsonFormatter produces valid JSON with expected fields."""
import json
from datetime import datetime, timezone
formatter = CotJsonFormatter()

View File

@@ -1,6 +1,7 @@
from src.core.config_models import Environment
from src.core.logger import belief_scope
# [DEF:test_environment_model:Function]
# @RELATION: TESTS -> Environment
# @PURPOSE: Tests that Environment model correctly stores values.

View File

@@ -4,14 +4,16 @@
# @SEMANTICS: tests, resource-hubs, dashboards, datasets, pagination, api
# @PURPOSE: Contract tests for resource hub dashboards/datasets listing and pagination boundary validation.
# @LAYER: Domain (Tests)
from unittest.mock import AsyncMock, MagicMock
import pytest
from fastapi.testclient import TestClient
from unittest.mock import MagicMock, AsyncMock
from src.app import app
from src.dependencies import (
get_config_manager,
get_task_manager,
get_resource_service,
get_task_manager,
has_permission,
)

View File

@@ -64,11 +64,11 @@ def test_app_has_expected_middleware():
def test_cot_logger_imports():
"""Core logging infrastructure is importable."""
from src.core.cot_logger import (
log,
seed_trace_id,
get_trace_id,
push_span,
log,
pop_span,
push_span,
seed_trace_id,
)
tid = seed_trace_id()

View File

@@ -1,9 +1,10 @@
import os
import sys
from pathlib import Path
import os
import pytest
from unittest.mock import MagicMock, patch
import pytest
sys.path.insert(0, str(Path(__file__).parent.parent))
# Mock database before any modules that import it are loaded
@@ -22,18 +23,18 @@ class TestPluginSmoke:
syntax errors, missing class declarations).
"""
from src.core.plugin_loader import PluginLoader
plugin_dir = os.path.join(str(Path(__file__).parent.parent), "src", "plugins")
# This will discover and instantiate plugins
loader = PluginLoader(plugin_dir)
plugins = loader.get_all_plugin_configs()
plugin_ids = {p.id for p in plugins}
# We expect at least the migration and git plugins to be present
expected_plugins = {"superset-migration", "git-integration"}
missing_plugins = expected_plugins - plugin_ids
assert not missing_plugins, f"Missing expected plugins: {missing_plugins}"
@@ -44,21 +45,21 @@ class TestPluginSmoke:
"""
from src.core.plugin_loader import PluginLoader
from src.core.task_manager.manager import TaskManager
plugin_dir = os.path.join(str(Path(__file__).parent.parent), "src", "plugins")
loader = PluginLoader(plugin_dir)
# Initialize TaskManager with real loader
with patch("src.core.task_manager.manager.TaskPersistenceService") as MockPersistence, \
patch("src.core.task_manager.manager.TaskLogPersistenceService"):
MockPersistence.return_value.load_tasks.return_value = []
with patch("src.dependencies.config_manager"):
manager = TaskManager(loader)
# Stop the flusher thread to prevent hanging
manager._flusher_stop_event.set()
manager._flusher_thread.join(timeout=2)
assert manager is not None

View File

@@ -7,12 +7,14 @@
import sys
from pathlib import Path
sys.path.insert(0, str(Path(__file__).parent.parent / "src"))
import pytest
import asyncio
from unittest.mock import MagicMock, patch, AsyncMock
from datetime import datetime
from unittest.mock import MagicMock, patch
import pytest
# Helper to create a TaskManager with mocked dependencies

View File

@@ -6,16 +6,17 @@
# @TEST_DATA: valid_task -> {"id": "test-uuid-1", "plugin_id": "backup", "status": "PENDING"}
# [SECTION: IMPORTS]
from datetime import datetime, timedelta
from datetime import datetime
from unittest.mock import patch
from sqlalchemy import create_engine
from sqlalchemy.orm import sessionmaker
from src.core.task_manager.models import LogEntry, Task, TaskStatus
from src.core.task_manager.persistence import TaskPersistenceService
from src.models.mapping import Base, Environment
from src.models.task import TaskRecord
from src.core.task_manager.persistence import TaskPersistenceService
from src.core.task_manager.models import Task, TaskStatus, LogEntry
# [/SECTION]

View File

@@ -27,19 +27,17 @@ from pathlib import Path
sys.path.insert(0, str(Path(__file__).parent.parent / "src"))
import pytest
from unittest.mock import MagicMock
import pytest
from fastapi.testclient import TestClient
from sqlalchemy import create_engine
from sqlalchemy.orm import sessionmaker
from datetime import datetime, timezone
import uuid
from src.core.database import Base
from src.app import app
from src.dependencies import get_current_user, get_config_manager, has_permission, get_db
from src.core.database import Base
from src.dependencies import get_config_manager, get_current_user, get_db
from src.plugins.translate.dictionary import DictionaryManager
from src.models.translate import TerminologyDictionary, DictionaryEntry
# In-memory SQLite
SQLALCHEMY_DATABASE_URL = "sqlite:///:memory:"

View File

@@ -14,12 +14,10 @@ from pathlib import Path
sys.path.insert(0, str(Path(__file__).parent.parent / "src"))
import pytest
from unittest.mock import MagicMock
from src.plugins.translate.executor import TranslationExecutor
# ---------------------------------------------------------------------------
# Helpers
# ---------------------------------------------------------------------------

View File

@@ -26,20 +26,19 @@ from pathlib import Path
sys.path.insert(0, str(Path(__file__).parent.parent / "src"))
import uuid
from datetime import UTC, datetime
from unittest.mock import MagicMock
import pytest
from unittest.mock import MagicMock, patch
from fastapi.testclient import TestClient
from sqlalchemy import create_engine
from sqlalchemy.orm import sessionmaker
from datetime import datetime, timezone
import uuid
import json
from src.core.database import Base
from src.app import app
from src.dependencies import get_current_user, get_config_manager, has_permission, get_db
from src.plugins.translate.metrics import TranslationMetrics
from src.models.translate import TranslationJob, TranslationRun, TranslationEvent, MetricSnapshot
from src.core.database import Base
from src.dependencies import get_config_manager, get_current_user, get_db
from src.models.translate import TranslationEvent, TranslationJob, TranslationRun
# In-memory SQLite
SQLALCHEMY_DATABASE_URL = "sqlite:///:memory:"
@@ -130,7 +129,7 @@ def _create_test_run(db_session, job_id: str, status: str = "COMPLETED", trigger
dict_snapshot_hash="def456",
key_hash="ghi789",
created_by="testuser",
created_at=datetime.now(timezone.utc),
created_at=datetime.now(UTC),
)
db_session.add(run)
db_session.flush()
@@ -197,7 +196,7 @@ def test_list_runs_filter_status(client, mock_api_deps):
_create_test_run(session, job.id, status="FAILED")
session.commit()
response = client.get(f"/api/translate/runs?run_status=FAILED")
response = client.get("/api/translate/runs?run_status=FAILED")
assert response.status_code == 200
data = response.json()
for item in data["items"]:
@@ -221,7 +220,7 @@ def test_get_run_detail(client, mock_api_deps):
event_type="RUN_STARTED",
event_data={},
created_by="testuser",
created_at=datetime.now(timezone.utc),
created_at=datetime.now(UTC),
)
session.add(event)
session.commit()

View File

@@ -29,26 +29,20 @@ from pathlib import Path
sys.path.insert(0, str(Path(__file__).parent.parent / "src"))
from unittest.mock import MagicMock
import pytest
from unittest.mock import MagicMock, patch
from datetime import datetime, timezone
from fastapi import status
from fastapi.testclient import TestClient
from sqlalchemy import create_engine
from sqlalchemy.orm import sessionmaker
from typing import Any, Dict, List, Optional, Tuple
import json
import uuid
from src.core.database import Base
from src.app import app
from src.dependencies import (
get_current_user,
get_config_manager,
has_permission,
)
from src.core.config_models import Environment
from src.core.database import Base
from src.dependencies import (
get_config_manager,
get_current_user,
)
# [DEF:valid_job_payload:Variable]
# @PURPOSE: Standard valid payload for creating a translation job.

View File

@@ -26,20 +26,16 @@ from pathlib import Path
sys.path.insert(0, str(Path(__file__).parent.parent / "src"))
import pytest
from unittest.mock import MagicMock
import pytest
from sqlalchemy import create_engine
from sqlalchemy.orm import sessionmaker
from datetime import datetime, timezone
import uuid
from src.core.database import Base
from src.app import app
from src.dependencies import get_current_user, get_config_manager, get_db
from src.plugins.translate.scheduler import TranslationScheduler, execute_scheduled_translation
from src.plugins.translate.scheduler import TranslationScheduler
from src.plugins.translate.service import TranslateJobService
from src.schemas.translate import TranslateJobCreate
from src.models.translate import TranslationJob, TranslationSchedule, TranslationRun
# In-memory SQLite
SQLALCHEMY_DATABASE_URL = "sqlite:///:memory:"
@@ -63,7 +59,6 @@ def db_session():
# @PURPOSE: Verify schedule creation with valid params.
def test_create_schedule(db_session):
"""Test creating a schedule for a job."""
from src.core.config_models import Environment
config_mgr = MagicMock()
config_mgr.get_environments.return_value = []
@@ -90,7 +85,6 @@ def test_create_schedule(db_session):
# @PURPOSE: Verify schedule update.
def test_update_schedule(db_session):
"""Test updating a schedule."""
from src.core.config_models import Environment
config_mgr = MagicMock()
config_mgr.get_environments.return_value = []
@@ -111,7 +105,6 @@ def test_update_schedule(db_session):
# @PURPOSE: Verify schedule deletion.
def test_delete_schedule(db_session):
"""Test deleting a schedule."""
from src.core.config_models import Environment
config_mgr = MagicMock()
config_mgr.get_environments.return_value = []
@@ -131,7 +124,6 @@ def test_delete_schedule(db_session):
# @PURPOSE: Verify enable/disable toggle.
def test_enable_disable_schedule(db_session):
"""Test enabling and disabling a schedule."""
from src.core.config_models import Environment
config_mgr = MagicMock()
config_mgr.get_environments.return_value = []
@@ -153,7 +145,6 @@ def test_enable_disable_schedule(db_session):
# @PURPOSE: Verify ValueError on getting non-existent schedule.
def test_get_schedule_not_found(db_session):
"""Test that getting a non-existent schedule raises ValueError."""
from src.core.config_models import Environment
config_mgr = MagicMock()
config_mgr.get_environments.return_value = []
@@ -167,7 +158,6 @@ def test_get_schedule_not_found(db_session):
# @PURPOSE: Verify listing only active schedules.
def test_list_active_schedules(db_session):
"""Test listing active schedules."""
from src.core.config_models import Environment
config_mgr = MagicMock()
config_mgr.get_environments.return_value = []

View File

@@ -9,10 +9,10 @@
# @TEST_INVARIANT: trigger_type_dispatch -> VERIFIED_BY: [test_new_key_only_mode, test_baseline_expired_fallback, test_full_mode_default]
import sys
from pathlib import Path
sys.path.insert(0, str(Path(__file__).parent.parent / "src"))
from unittest.mock import MagicMock, patch
from datetime import datetime, timezone, timedelta
sys.path.insert(0, str(Path(__file__).parent.parent / "src"))
from datetime import UTC, datetime, timedelta
from unittest.mock import MagicMock, patch
# -- Helpers -----------------------------------------------------------------
@@ -23,7 +23,7 @@ def _make_most_recent_run(created_at_delta_days=60):
run.job_id = "job-1"
run.status = "COMPLETED"
run.insert_status = "succeeded"
run.created_at = datetime.now(timezone.utc) - timedelta(days=created_at_delta_days)
run.created_at = datetime.now(UTC) - timedelta(days=created_at_delta_days)
return run

View File

@@ -13,10 +13,8 @@ from pathlib import Path
sys.path.insert(0, str(Path(__file__).parent.parent / "src"))
import pytest
from datetime import UTC, datetime, timedelta
from unittest.mock import MagicMock, patch
from datetime import datetime, timezone, timedelta
# ---------------------------------------------------------------------------
# Helpers
@@ -29,7 +27,7 @@ def _make_most_recent_run(created_at_delta_days=60):
run.job_id = "job-1"
run.status = "COMPLETED"
run.insert_status = "succeeded"
run.created_at = datetime.now(timezone.utc) - timedelta(days=created_at_delta_days)
run.created_at = datetime.now(UTC) - timedelta(days=created_at_delta_days)
return run
@@ -85,20 +83,19 @@ def test_concurrent_run_skips():
with patch(
"src.plugins.translate.orchestrator.TranslationOrchestrator"
) as mock_orch_cls:
with patch(
"src.plugins.translate.scheduler.TranslationEventLog"
) as mock_event_log_cls:
mock_event_log = MagicMock()
mock_event_log_cls.return_value = mock_event_log
) as mock_orch_cls, patch(
"src.plugins.translate.scheduler.TranslationEventLog"
) as mock_event_log_cls:
mock_event_log = MagicMock()
mock_event_log_cls.return_value = mock_event_log
execute_scheduled_translation(
schedule_id="sched-1",
job_id="job-1",
db_session_maker=mock_session_maker,
config_manager=mock_config,
execution_mode="full",
)
execute_scheduled_translation(
schedule_id="sched-1",
job_id="job-1",
db_session_maker=mock_session_maker,
config_manager=mock_config,
execution_mode="full",
)
mock_orch_cls.assert_not_called()
mock_event_log.log_event.assert_called_once()
@@ -128,7 +125,7 @@ def test_recent_pending_run_not_stale():
pending_run.id = "pending-run-1"
pending_run.job_id = "job-1"
pending_run.status = "PENDING"
pending_run.created_at = datetime.now(timezone.utc) - timedelta(minutes=30)
pending_run.created_at = datetime.now(UTC) - timedelta(minutes=30)
q1 = MagicMock()
q1.filter.return_value.first.return_value = schedule
@@ -140,20 +137,19 @@ def test_recent_pending_run_not_stale():
with patch(
"src.plugins.translate.orchestrator.TranslationOrchestrator"
) as mock_orch_cls:
with patch(
"src.plugins.translate.scheduler.TranslationEventLog"
) as mock_event_log_cls:
mock_event_log = MagicMock()
mock_event_log_cls.return_value = mock_event_log
) as mock_orch_cls, patch(
"src.plugins.translate.scheduler.TranslationEventLog"
) as mock_event_log_cls:
mock_event_log = MagicMock()
mock_event_log_cls.return_value = mock_event_log
execute_scheduled_translation(
schedule_id="sched-1",
job_id="job-1",
db_session_maker=mock_session_maker,
config_manager=mock_config,
execution_mode="full",
)
execute_scheduled_translation(
schedule_id="sched-1",
job_id="job-1",
db_session_maker=mock_session_maker,
config_manager=mock_config,
execution_mode="full",
)
mock_orch_cls.assert_not_called()
mock_event_log.log_event.assert_called_once()
@@ -183,7 +179,7 @@ def test_stale_pending_cleared_and_proceeds():
stale_run.id = "stale-run-1"
stale_run.job_id = "job-1"
stale_run.status = "PENDING"
stale_run.created_at = datetime.now(timezone.utc) - timedelta(hours=2)
stale_run.created_at = datetime.now(UTC) - timedelta(hours=2)
most_recent = _make_most_recent_run(created_at_delta_days=30)
@@ -248,13 +244,13 @@ def test_multiple_stale_pending_all_cleared():
stale_run_a.id = "stale-run-a"
stale_run_a.job_id = "job-1"
stale_run_a.status = "PENDING"
stale_run_a.created_at = datetime.now(timezone.utc) - timedelta(hours=5)
stale_run_a.created_at = datetime.now(UTC) - timedelta(hours=5)
stale_run_b = MagicMock()
stale_run_b.id = "stale-run-b"
stale_run_b.job_id = "job-1"
stale_run_b.status = "PENDING"
stale_run_b.created_at = datetime.now(timezone.utc) - timedelta(hours=3)
stale_run_b.created_at = datetime.now(UTC) - timedelta(hours=3)
most_recent = _make_most_recent_run(created_at_delta_days=30)