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:
@@ -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
|
||||
|
||||
@@ -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))
|
||||
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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 (
|
||||
|
||||
@@ -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,
|
||||
)
|
||||
)
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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]
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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,
|
||||
)
|
||||
)
|
||||
|
||||
@@ -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"],
|
||||
|
||||
@@ -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",
|
||||
)
|
||||
)
|
||||
|
||||
@@ -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]
|
||||
|
||||
@@ -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,
|
||||
)
|
||||
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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:"
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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]
|
||||
|
||||
@@ -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()
|
||||
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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,
|
||||
)
|
||||
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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]
|
||||
|
||||
|
||||
|
||||
@@ -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:"
|
||||
|
||||
@@ -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
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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 = []
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
|
||||
@@ -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)
|
||||
|
||||
|
||||
Reference in New Issue
Block a user