v4: 7643 tests passing, 83% raw / 96.9% real coverage (excl __tests__).
12 known failures — all from Agent 3 new unverified tests (mock setup issues): - 3 dataset_review_routes_extended (DTO field mismatches) - 1 settings_consolidated (dict key access) - 1 llm_analysis_service_coverage (rate_limit mock) - 1 migration_plugin (SessionLocal side_effect exhaustion) - 1 preview (DB query vs dict key) - 5 scheduler (datetime timezone + async mock mismatches) NEW TEST FILES THIS SESSION: - test_batch_insert_coverage.py — 3 tests - test_storage_plugin.py — +3 tests - test_search.py — +2 tests - test_mapper.py — already 100% - test_llm_analysis_migration_v1_to_v2.py — 14 tests - test_llm_async_http.py — +1 test - test_prompt_builder.py — +1 test - test_service_datasource.py — +1 test - test_lang_detect.py — +1 test - test_scheduler.py — +6 tests - test_llm_analysis_service_coverage.py — +15 tests - test_dataset_review_routes_extended.py — +14 tests - test_settings_consolidated.py — +13 tests Modules pushed to 100%: _batch_insert, dictionary_entries, service_datasource, _llm_async_http, prompt_builder, dictionary_crud, _batch_sizer, storage/plugin, mapper.py Session: 7194→7643 tests (+449), 80%→83% raw (+3pp), 93.4%→96.9% real (+3.5pp). Remaining: 12 failures to fix + ~300 statements to reach 98% real coverage.
This commit is contained in:
498
backend/tests/scripts/test_facade_adapter.py
Normal file
498
backend/tests/scripts/test_facade_adapter.py
Normal file
@@ -0,0 +1,498 @@
|
||||
# #region TestFacadeAdapter [C:3] [TYPE Module] [SEMANTICS test,clean-release,facade,tui,adapter]
|
||||
# @BRIEF Tests for TuiFacadeAdapter and CleanReleaseTUI logic methods (non-rendering).
|
||||
# @RELATION BINDS_TO -> [CleanReleaseTuiScript]
|
||||
# @TEST_EDGE: facade_build_config_no_policy -> Raises ValueError
|
||||
# @TEST_EDGE: facade_run_compliance_no_manifests -> Raises ValueError
|
||||
# @TEST_EDGE: facade_approve_latest_no_reports -> Raises ValueError
|
||||
# @TEST_EDGE: facade_publish_latest_no_reports -> Raises ValueError
|
||||
# @TEST_EDGE: resolve_candidate_id_by_env -> Uses CLEAN_TUI_CANDIDATE_ID
|
||||
# @TEST_EDGE: resolve_candidate_id_fallback -> Uses first candidate
|
||||
# @TEST_EDGE: resolve_candidate_id_empty -> Returns ""
|
||||
# @TEST_EDGE: tui_run_checks_error -> FAILED status on exception
|
||||
# @TEST_EDGE: tui_approve_no_report -> Disabled message when no report_id
|
||||
# @TEST_EDGE: tui_publish_no_report -> Disabled message when no report_id
|
||||
# @TEST_EDGE: tui_approve_error -> Error stored on facade failure
|
||||
# @TEST_EDGE: tui_publish_error -> Error stored on facade failure
|
||||
# @TEST_EDGE: tui_build_manifest_error -> Error stored on facade failure
|
||||
# @TEST_EDGE: bootstrap_real_no_path -> Returns early
|
||||
import os
|
||||
import pytest
|
||||
from unittest.mock import MagicMock, patch, PropertyMock
|
||||
from types import SimpleNamespace
|
||||
|
||||
from src.models.clean_release import (
|
||||
CheckFinalStatus, CheckStageStatus, ComplianceViolation,
|
||||
ReleaseCandidate, CleanProfilePolicy, ProfileType,
|
||||
ResourceSourceRegistry, ResourceSourceEntry, RegistryStatus,
|
||||
ReleaseCandidateStatus, CandidateArtifact,
|
||||
)
|
||||
from src.services.clean_release.enums import CandidateStatus
|
||||
from src.scripts.clean_release_tui import TuiFacadeAdapter, CleanReleaseTUI
|
||||
|
||||
|
||||
# =============================================================================
|
||||
# TuiFacadeAdapter tests (no curses required)
|
||||
# =============================================================================
|
||||
|
||||
class TestTuiFacadeAdapterBuildConfig:
|
||||
"""Verify _build_config_manager."""
|
||||
|
||||
def test_build_config_with_policy(self):
|
||||
"""Happy: policy found returns config with active_policy_id."""
|
||||
repo = MagicMock()
|
||||
policy = MagicMock()
|
||||
policy.id = "POL-1"
|
||||
policy.registry_snapshot_id = "REG-1"
|
||||
repo.get_active_policy.return_value = policy
|
||||
|
||||
adapter = TuiFacadeAdapter(repo)
|
||||
cm = adapter._build_config_manager()
|
||||
config = cm.get_config()
|
||||
assert config.settings.clean_release.active_policy_id == "POL-1"
|
||||
assert config.settings.clean_release.active_registry_id == "REG-1"
|
||||
|
||||
def test_build_config_no_policy_raises(self):
|
||||
"""Edge: no active policy raises ValueError."""
|
||||
repo = MagicMock()
|
||||
repo.get_active_policy.return_value = None
|
||||
|
||||
adapter = TuiFacadeAdapter(repo)
|
||||
with pytest.raises(ValueError, match="Active policy not found"):
|
||||
adapter._build_config_manager()
|
||||
|
||||
|
||||
class TestTuiFacadeAdapterRunCompliance:
|
||||
"""Verify run_compliance."""
|
||||
|
||||
def test_run_compliance_with_manifests(self):
|
||||
"""Happy: manifests found, executes compliance."""
|
||||
repo = MagicMock()
|
||||
policy = MagicMock()
|
||||
policy.id = "POL-1"
|
||||
policy.registry_snapshot_id = "REG-1"
|
||||
repo.get_active_policy.return_value = policy
|
||||
|
||||
manifest_old = MagicMock()
|
||||
manifest_old.manifest_version = 1
|
||||
manifest_new = MagicMock()
|
||||
manifest_new.manifest_version = 2
|
||||
repo.get_manifests_by_candidate.return_value = [manifest_old, manifest_new]
|
||||
|
||||
adapter = TuiFacadeAdapter(repo)
|
||||
with patch('src.scripts.clean_release_tui.ComplianceExecutionService') as MockService:
|
||||
mock_instance = MockService.return_value
|
||||
mock_instance.execute_run.return_value = "compliance_result"
|
||||
result = adapter.run_compliance(candidate_id="cand-1", actor="test")
|
||||
|
||||
repo.get_manifests_by_candidate.assert_called_once_with("cand-1")
|
||||
assert result == "compliance_result"
|
||||
|
||||
def test_run_compliance_no_manifests_raises(self):
|
||||
"""Edge: no manifests raises ValueError."""
|
||||
repo = MagicMock()
|
||||
repo.get_manifests_by_candidate.return_value = []
|
||||
|
||||
adapter = TuiFacadeAdapter(repo)
|
||||
with pytest.raises(ValueError, match="Manifest required before compliance run"):
|
||||
adapter.run_compliance(candidate_id="cand-1", actor="test")
|
||||
|
||||
|
||||
class TestTuiFacadeAdapterApproveLatest:
|
||||
"""Verify approve_latest."""
|
||||
|
||||
def test_approve_with_reports(self):
|
||||
"""Happy: reports found, approves."""
|
||||
repo = MagicMock()
|
||||
r1 = MagicMock()
|
||||
r1.candidate_id = "cand-1"
|
||||
r1.generated_at = "2024-01-01T00:00:00"
|
||||
r2 = MagicMock()
|
||||
r2.candidate_id = "cand-1"
|
||||
r2.generated_at = "2024-06-01T00:00:00"
|
||||
repo.reports = {"r1": r1, "r2": r2}
|
||||
|
||||
adapter = TuiFacadeAdapter(repo)
|
||||
with patch('src.scripts.clean_release_tui.approve_candidate') as mock_approve:
|
||||
adapter.approve_latest(candidate_id="cand-1", actor="test")
|
||||
mock_approve.assert_called_once()
|
||||
|
||||
def test_approve_no_reports_raises(self):
|
||||
"""Edge: no reports raises ValueError."""
|
||||
repo = MagicMock()
|
||||
repo.reports = {}
|
||||
|
||||
adapter = TuiFacadeAdapter(repo)
|
||||
with pytest.raises(ValueError, match="No compliance report available for approval"):
|
||||
adapter.approve_latest(candidate_id="cand-1", actor="test")
|
||||
|
||||
|
||||
class TestTuiFacadeAdapterPublishLatest:
|
||||
"""Verify publish_latest."""
|
||||
|
||||
def test_publish_with_reports(self):
|
||||
"""Happy: reports found, publishes."""
|
||||
repo = MagicMock()
|
||||
r1 = MagicMock()
|
||||
r1.candidate_id = "cand-1"
|
||||
r1.generated_at = "2024-01-01T00:00:00"
|
||||
repo.reports = {"r1": r1}
|
||||
|
||||
adapter = TuiFacadeAdapter(repo)
|
||||
with patch('src.scripts.clean_release_tui.publish_candidate') as mock_publish:
|
||||
adapter.publish_latest(candidate_id="cand-1", actor="test")
|
||||
mock_publish.assert_called_once()
|
||||
|
||||
def test_publish_no_reports_raises(self):
|
||||
"""Edge: no reports raises ValueError."""
|
||||
repo = MagicMock()
|
||||
repo.reports = {}
|
||||
|
||||
adapter = TuiFacadeAdapter(repo)
|
||||
with pytest.raises(ValueError, match="No compliance report available for publication"):
|
||||
adapter.publish_latest(candidate_id="cand-1", actor="test")
|
||||
|
||||
|
||||
class TestTuiFacadeAdapterBuildManifest:
|
||||
"""Verify build_manifest."""
|
||||
|
||||
def test_build_manifest_delegates(self):
|
||||
"""Happy: delegates to build_manifest_snapshot."""
|
||||
repo = MagicMock()
|
||||
adapter = TuiFacadeAdapter(repo)
|
||||
with patch('src.scripts.clean_release_tui.build_manifest_snapshot') as mock_build:
|
||||
adapter.build_manifest(candidate_id="cand-1", actor="test")
|
||||
mock_build.assert_called_once_with(
|
||||
repository=repo, candidate_id="cand-1", created_by="test",
|
||||
)
|
||||
|
||||
|
||||
class TestTuiFacadeAdapterGetOverview:
|
||||
"""Verify get_overview."""
|
||||
|
||||
def test_get_overview_full(self):
|
||||
"""Happy: all data present."""
|
||||
repo = MagicMock()
|
||||
candidate = MagicMock()
|
||||
candidate.id = "cand-1"
|
||||
repo.get_candidate.return_value = candidate
|
||||
|
||||
manifest = MagicMock()
|
||||
manifest.manifest_version = 2
|
||||
repo.get_manifests_by_candidate.return_value = [manifest]
|
||||
|
||||
run = MagicMock()
|
||||
run.candidate_id = "cand-1"
|
||||
run.requested_at = "2024-06-01T00:00:00"
|
||||
repo.check_runs = {"r1": run}
|
||||
|
||||
report = MagicMock()
|
||||
report.run_id = run.id
|
||||
repo.reports = {"rep1": report}
|
||||
|
||||
approval = MagicMock()
|
||||
approval.candidate_id = "cand-1"
|
||||
approval.decided_at = "2024-06-02T00:00:00"
|
||||
repo.approval_decisions = [approval]
|
||||
|
||||
publication = MagicMock()
|
||||
publication.candidate_id = "cand-1"
|
||||
publication.published_at = "2024-06-03T00:00:00"
|
||||
repo.publication_records = [publication]
|
||||
|
||||
policy = MagicMock()
|
||||
policy.internal_source_registry_ref = "REG-1"
|
||||
repo.get_active_policy.return_value = policy
|
||||
|
||||
registry = MagicMock()
|
||||
repo.get_registry.return_value = registry
|
||||
|
||||
adapter = TuiFacadeAdapter(repo)
|
||||
overview = adapter.get_overview(candidate_id="cand-1")
|
||||
|
||||
assert overview["candidate"] is candidate
|
||||
assert overview["manifest"] is manifest
|
||||
assert overview["run"] is run
|
||||
assert overview["report"] is report
|
||||
assert overview["approval"] is approval
|
||||
assert overview["publication"] is publication
|
||||
assert overview["policy"] is policy
|
||||
assert overview["registry"] is registry
|
||||
|
||||
def test_get_overview_empty(self):
|
||||
"""Edge: no data at all, returns safe defaults."""
|
||||
repo = MagicMock()
|
||||
repo.get_candidate.return_value = None
|
||||
repo.get_manifests_by_candidate.return_value = []
|
||||
repo.check_runs = {}
|
||||
repo.reports = {}
|
||||
repo.get_active_policy.return_value = None
|
||||
|
||||
adapter = TuiFacadeAdapter(repo)
|
||||
overview = adapter.get_overview(candidate_id="nonexistent")
|
||||
|
||||
assert overview["candidate"] is None
|
||||
assert overview["manifest"] is None
|
||||
assert overview["run"] is None
|
||||
assert overview["report"] is None
|
||||
assert overview["approval"] is None
|
||||
assert overview["publication"] is None
|
||||
assert overview["policy"] is None
|
||||
assert overview["registry"] is None
|
||||
|
||||
|
||||
# =============================================================================
|
||||
# CleanReleaseTUI logic tests (curses mocked at module level)
|
||||
# =============================================================================
|
||||
|
||||
@pytest.fixture
|
||||
def mock_stdscr():
|
||||
stdscr = MagicMock()
|
||||
stdscr.getmaxyx.return_value = (40, 100)
|
||||
stdscr.getch.return_value = -1
|
||||
return stdscr
|
||||
|
||||
|
||||
class TestResolveCandidateId:
|
||||
"""Verify _resolve_candidate_id."""
|
||||
|
||||
@patch("src.scripts.clean_release_tui.curses")
|
||||
def test_returns_env_var(self, mock_curses, mock_stdscr):
|
||||
"""Edge: CLEAN_TUI_CANDIDATE_ID set returns env value."""
|
||||
with patch.dict(os.environ, {"CLEAN_TUI_CANDIDATE_ID": "env-cand"}, clear=False):
|
||||
app = CleanReleaseTUI(mock_stdscr)
|
||||
# After init the candidate_id is already resolved, verify it
|
||||
assert app.candidate_id == "env-cand"
|
||||
|
||||
@patch("src.scripts.clean_release_tui.curses")
|
||||
def test_falls_back_to_first_candidate(self, mock_curses, mock_stdscr):
|
||||
"""Edge: no env var, uses first candidate key."""
|
||||
app = CleanReleaseTUI(mock_stdscr)
|
||||
# Demo mode creates a candidate "2026.03.03-rc1"
|
||||
assert app.candidate_id == "2026.03.03-rc1"
|
||||
|
||||
@patch("src.scripts.clean_release_tui.curses")
|
||||
def test_returns_empty_when_no_candidates(self, mock_curses):
|
||||
"""Edge: no env var and no candidates returns empty string."""
|
||||
stdscr = MagicMock()
|
||||
stdscr.getmaxyx.return_value = (40, 100)
|
||||
# Inject a repo with no candidates
|
||||
from src.services.clean_release.repository import CleanReleaseRepository
|
||||
from src.scripts.clean_release_tui import TuiFacadeAdapter
|
||||
|
||||
with patch.dict(os.environ, {"CLEAN_TUI_MODE": "real"}, clear=False):
|
||||
with patch("src.scripts.clean_release_tui.CleanReleaseTUI._bootstrap_real_repository"):
|
||||
app = CleanReleaseTUI(stdscr)
|
||||
# In real mode with no bootstrap, no candidates exist
|
||||
resolved = app._resolve_candidate_id()
|
||||
# _resolve_candidate_id is called during __init__, so the result is already in app.candidate_id
|
||||
assert app.candidate_id == ""
|
||||
|
||||
|
||||
class TestTuiBuildManifestError:
|
||||
"""Verify build_manifest error handling."""
|
||||
|
||||
@patch("src.scripts.clean_release_tui.curses")
|
||||
def test_build_manifest_captures_error(self, mock_curses, mock_stdscr):
|
||||
"""Edge: facade raises, error stored."""
|
||||
app = CleanReleaseTUI(mock_stdscr)
|
||||
# Replace facade with one that raises
|
||||
app.facade = MagicMock()
|
||||
app.facade.build_manifest.side_effect = ValueError("Build failed")
|
||||
|
||||
app.build_manifest()
|
||||
assert "Build failed" in app.last_error
|
||||
|
||||
|
||||
class TestTuiApproveError:
|
||||
"""Verify approve_latest error handling."""
|
||||
|
||||
@patch("src.scripts.clean_release_tui.curses")
|
||||
def test_approve_no_report_id(self, mock_curses, mock_stdscr):
|
||||
"""Edge: no report_id sets disabled message."""
|
||||
app = CleanReleaseTUI(mock_stdscr)
|
||||
app.report_id = None
|
||||
app.approve_latest()
|
||||
assert "F8 disabled" in app.last_error
|
||||
|
||||
@patch("src.scripts.clean_release_tui.curses")
|
||||
def test_approve_facade_error(self, mock_curses, mock_stdscr):
|
||||
"""Edge: facade raises, error stored."""
|
||||
app = CleanReleaseTUI(mock_stdscr)
|
||||
app.report_id = "rep-1"
|
||||
app.facade = MagicMock()
|
||||
app.facade.approve_latest.side_effect = ValueError("Approve failed")
|
||||
|
||||
app.approve_latest()
|
||||
assert "Approve failed" in app.last_error
|
||||
|
||||
|
||||
class TestTuiPublishError:
|
||||
"""Verify publish_latest error handling."""
|
||||
|
||||
@patch("src.scripts.clean_release_tui.curses")
|
||||
def test_publish_no_report_id(self, mock_curses, mock_stdscr):
|
||||
"""Edge: no report_id sets disabled message."""
|
||||
app = CleanReleaseTUI(mock_stdscr)
|
||||
app.report_id = None
|
||||
app.publish_latest()
|
||||
assert "F9 disabled" in app.last_error
|
||||
|
||||
@patch("src.scripts.clean_release_tui.curses")
|
||||
def test_publish_facade_error(self, mock_curses, mock_stdscr):
|
||||
"""Edge: facade raises, error stored."""
|
||||
app = CleanReleaseTUI(mock_stdscr)
|
||||
app.report_id = "rep-1"
|
||||
app.facade = MagicMock()
|
||||
app.facade.publish_latest.side_effect = ValueError("Publish failed")
|
||||
|
||||
app.publish_latest()
|
||||
assert "Publish failed" in app.last_error
|
||||
|
||||
|
||||
class TestTuiRunChecksError:
|
||||
"""Verify run_checks error handling."""
|
||||
|
||||
@patch("src.scripts.clean_release_tui.curses")
|
||||
def test_run_checks_facade_error(self, mock_curses, mock_stdscr):
|
||||
"""Edge: facade raises during run_checks -> FAILED status."""
|
||||
app = CleanReleaseTUI(mock_stdscr)
|
||||
app.facade = MagicMock()
|
||||
app.facade.run_compliance.side_effect = RuntimeError("Compliance crashed")
|
||||
|
||||
app.run_checks()
|
||||
assert app.status == CheckFinalStatus.FAILED
|
||||
assert "Compliance crashed" in app.last_error
|
||||
|
||||
|
||||
class TestTuiClearHistory:
|
||||
"""Verify clear_history resets state."""
|
||||
|
||||
@patch("src.scripts.clean_release_tui.curses")
|
||||
def test_clear_history_resets_state(self, mock_curses, mock_stdscr):
|
||||
"""Edge: after running checks, clear_history resets."""
|
||||
app = CleanReleaseTUI(mock_stdscr)
|
||||
app.status = CheckFinalStatus.BLOCKED
|
||||
app.report_id = "rep-1"
|
||||
app.violations_list = [MagicMock()]
|
||||
app.checks_progress = [{"stage": "test", "status": "FAIL"}]
|
||||
app.last_error = "some error"
|
||||
|
||||
app.clear_history()
|
||||
assert app.status == "READY"
|
||||
assert app.report_id is None
|
||||
assert app.violations_list == []
|
||||
assert app.checks_progress == []
|
||||
assert app.last_error is None
|
||||
|
||||
|
||||
# =============================================================================
|
||||
# _bootstrap_real_repository tests
|
||||
# =============================================================================
|
||||
|
||||
class TestBootstrapRealRepository:
|
||||
"""Verify _bootstrap_real_repository."""
|
||||
|
||||
@patch("src.scripts.clean_release_tui.curses")
|
||||
def test_no_bootstrap_path_returns_early(self, mock_curses, mock_stdscr):
|
||||
"""Edge: CLEAN_TUI_BOOTSTRAP_JSON not set returns early."""
|
||||
from src.services.clean_release.repository import CleanReleaseRepository
|
||||
app = CleanReleaseTUI(mock_stdscr)
|
||||
repo = CleanReleaseRepository()
|
||||
|
||||
app._bootstrap_real_repository(repo)
|
||||
# No bootstrap loaded -> no candidates
|
||||
assert len(repo.candidates) == 0
|
||||
|
||||
@patch("src.scripts.clean_release_tui.curses")
|
||||
def test_bootstrap_with_valid_json(self, mock_curses, mock_stdscr, tmp_path):
|
||||
"""Happy: valid bootstrap.json loads candidate, registry and policy."""
|
||||
import json
|
||||
bootstrap = tmp_path / "bootstrap.json"
|
||||
bootstrap.write_text(json.dumps({
|
||||
"candidate_id": "test-cand",
|
||||
"version": "1.0.0",
|
||||
"source_snapshot_ref": "git-ref",
|
||||
"created_by": "test",
|
||||
"allowed_hosts": ["repo.example.com"],
|
||||
}), encoding="utf-8")
|
||||
|
||||
from src.services.clean_release.repository import CleanReleaseRepository
|
||||
app = CleanReleaseTUI(mock_stdscr)
|
||||
repo = CleanReleaseRepository()
|
||||
|
||||
with patch.dict(os.environ, {
|
||||
"CLEAN_TUI_BOOTSTRAP_JSON": str(bootstrap),
|
||||
}, clear=False):
|
||||
app._bootstrap_real_repository(repo)
|
||||
|
||||
assert repo.get_candidate("test-cand") is not None
|
||||
assert len(repo.registries) > 0
|
||||
assert len(repo.policies) > 0
|
||||
assert repo.get_candidate("test-cand").status == "DRAFT"
|
||||
|
||||
@patch("src.scripts.clean_release_tui.curses")
|
||||
def test_bootstrap_with_artifacts_transitions_to_prepared(self, mock_curses, mock_stdscr, tmp_path):
|
||||
"""Happy: artifacts imported transitions candidate to PREPARED."""
|
||||
import json
|
||||
bootstrap = tmp_path / "bootstrap.json"
|
||||
bootstrap.write_text(json.dumps({
|
||||
"candidate_id": "test-cand-2",
|
||||
"version": "2.0.0",
|
||||
"source_snapshot_ref": "git-ref-2",
|
||||
"created_by": "test",
|
||||
"allowed_hosts": [],
|
||||
}), encoding="utf-8")
|
||||
|
||||
artifacts = tmp_path / "artifacts.json"
|
||||
artifacts.write_text(json.dumps({
|
||||
"artifacts": [{
|
||||
"id": "art-1", "path": "dist/file.tar.gz",
|
||||
"sha256": "abc123", "size": 512, "category": "core",
|
||||
"source_uri": "https://repo.example.com/file.tar.gz",
|
||||
"source_host": "repo.example.com",
|
||||
}]
|
||||
}), encoding="utf-8")
|
||||
|
||||
from src.services.clean_release.repository import CleanReleaseRepository
|
||||
app = CleanReleaseTUI(mock_stdscr)
|
||||
repo = CleanReleaseRepository()
|
||||
|
||||
with patch.dict(os.environ, {
|
||||
"CLEAN_TUI_BOOTSTRAP_JSON": str(bootstrap),
|
||||
"CLEAN_TUI_ARTIFACTS_JSON": str(artifacts),
|
||||
}, clear=False):
|
||||
app._bootstrap_real_repository(repo)
|
||||
|
||||
assert repo.get_candidate("test-cand-2").status == "PREPARED"
|
||||
artifacts_list = repo.get_artifacts_by_candidate("test-cand-2")
|
||||
assert len(artifacts_list) == 1
|
||||
assert artifacts_list[0].detected_category == "core"
|
||||
|
||||
@patch("src.scripts.clean_release_tui.curses")
|
||||
def test_bootstrap_with_entries_saves_policy(self, mock_curses, mock_stdscr, tmp_path):
|
||||
"""Edge: entries present saves registry and policy."""
|
||||
import json
|
||||
bootstrap = tmp_path / "bootstrap.json"
|
||||
bootstrap.write_text(json.dumps({
|
||||
"candidate_id": "test-cand-3",
|
||||
"version": "3.0.0",
|
||||
"source_snapshot_ref": "git-ref-3",
|
||||
"created_by": "test",
|
||||
"allowed_hosts": ["repo.example.com"],
|
||||
"registry_id": "REG-TEST",
|
||||
"policy_id": "POL-TEST",
|
||||
}), encoding="utf-8")
|
||||
|
||||
from src.services.clean_release.repository import CleanReleaseRepository
|
||||
app = CleanReleaseTUI(mock_stdscr)
|
||||
repo = CleanReleaseRepository()
|
||||
|
||||
with patch.dict(os.environ, {
|
||||
"CLEAN_TUI_BOOTSTRAP_JSON": str(bootstrap),
|
||||
}, clear=False):
|
||||
app._bootstrap_real_repository(repo)
|
||||
|
||||
assert repo.get_registry("REG-TEST") is not None
|
||||
policy = repo.get_policy("POL-TEST")
|
||||
assert policy is not None
|
||||
# #endregion TestFacadeAdapter
|
||||
Reference in New Issue
Block a user