fix: commit semantic repair changes
This commit is contained in:
@@ -1,4 +1,4 @@
|
||||
# [DEF:backend.tests.core.migration.test_archive_parser:Module]
|
||||
# [DEF:TestArchiveParser:Module]
|
||||
#
|
||||
# @COMPLEXITY: 3
|
||||
# @PURPOSE: Unit tests for MigrationArchiveParser ZIP extraction contract.
|
||||
@@ -20,6 +20,8 @@ if backend_dir not in sys.path:
|
||||
from src.core.migration.archive_parser import MigrationArchiveParser
|
||||
|
||||
|
||||
# [DEF:test_extract_objects_from_zip_collects_all_types:Function]
|
||||
# @RELATION: BINDS_TO -> TestArchiveParser
|
||||
def test_extract_objects_from_zip_collects_all_types():
|
||||
parser = MigrationArchiveParser()
|
||||
with tempfile.TemporaryDirectory() as td:
|
||||
@@ -59,4 +61,5 @@ def test_extract_objects_from_zip_collects_all_types():
|
||||
raise AssertionError("dataset uuid mismatch")
|
||||
|
||||
|
||||
# [/DEF:backend.tests.core.migration.test_archive_parser:Module]
|
||||
# [/DEF:TestArchiveParser:Module]
|
||||
# [/DEF:test_extract_objects_from_zip_collects_all_types:Function]
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
# [DEF:backend.tests.core.migration.test_dry_run_orchestrator:Module]
|
||||
# [DEF:TestDryRunOrchestrator:Module]
|
||||
#
|
||||
# @COMPLEXITY: 3
|
||||
# @PURPOSE: Unit tests for MigrationDryRunService diff and risk computation contracts.
|
||||
@@ -23,11 +23,17 @@ from src.models.dashboard import DashboardSelection
|
||||
from src.models.mapping import Base
|
||||
|
||||
|
||||
# [DEF:_load_fixture:Function]
|
||||
# @RELATION: BINDS_TO -> TestDryRunOrchestrator
|
||||
def _load_fixture() -> dict:
|
||||
fixture_path = Path(__file__).parents[2] / "fixtures" / "migration_dry_run_fixture.json"
|
||||
return json.loads(fixture_path.read_text())
|
||||
|
||||
|
||||
# [/DEF:_load_fixture:Function]
|
||||
|
||||
# [DEF:_make_session:Function]
|
||||
# @RELATION: BINDS_TO -> TestDryRunOrchestrator
|
||||
def _make_session():
|
||||
engine = create_engine(
|
||||
"sqlite:///:memory:",
|
||||
@@ -39,6 +45,10 @@ def _make_session():
|
||||
return Session()
|
||||
|
||||
|
||||
# [/DEF:_make_session:Function]
|
||||
|
||||
# [DEF:test_migration_dry_run_service_builds_diff_and_risk:Function]
|
||||
# @RELATION: BINDS_TO -> TestDryRunOrchestrator
|
||||
def test_migration_dry_run_service_builds_diff_and_risk():
|
||||
# @TEST_CONTRACT: dry_run_result_contract -> {
|
||||
# required_fields: {diff: object, summary: object, risk: object},
|
||||
@@ -107,4 +117,5 @@ def test_migration_dry_run_service_builds_diff_and_risk():
|
||||
raise AssertionError("breaking_reference risk is not detected")
|
||||
|
||||
|
||||
# [/DEF:backend.tests.core.migration.test_dry_run_orchestrator:Module]
|
||||
# [/DEF:TestDryRunOrchestrator:Module]
|
||||
# [/DEF:test_migration_dry_run_service_builds_diff_and_risk:Function]
|
||||
|
||||
@@ -11,6 +11,8 @@ from src.services.git_service import GitService
|
||||
from src.core.superset_client import SupersetClient
|
||||
from src.core.config_models import Environment
|
||||
|
||||
# [DEF:test_git_service_get_repo_path_guard:Function]
|
||||
# @RELATION: BINDS_TO -> UnknownModule
|
||||
def test_git_service_get_repo_path_guard():
|
||||
"""Verify that _get_repo_path raises ValueError if dashboard_id is None."""
|
||||
service = GitService(base_path="test_repos")
|
||||
@@ -18,6 +20,10 @@ def test_git_service_get_repo_path_guard():
|
||||
service._get_repo_path(None)
|
||||
|
||||
|
||||
# [/DEF:test_git_service_get_repo_path_guard:Function]
|
||||
|
||||
# [DEF:test_git_service_get_repo_path_recreates_base_dir:Function]
|
||||
# @RELATION: BINDS_TO -> UnknownModule
|
||||
def test_git_service_get_repo_path_recreates_base_dir():
|
||||
"""Verify _get_repo_path recreates missing base directory before returning repo path."""
|
||||
service = GitService(base_path="test_repos_runtime_recreate")
|
||||
@@ -28,6 +34,10 @@ def test_git_service_get_repo_path_recreates_base_dir():
|
||||
assert Path(service.base_path).is_dir()
|
||||
assert repo_path == str(Path(service.base_path) / "42")
|
||||
|
||||
# [/DEF:test_git_service_get_repo_path_recreates_base_dir:Function]
|
||||
|
||||
# [DEF:test_superset_client_import_dashboard_guard:Function]
|
||||
# @RELATION: BINDS_TO -> UnknownModule
|
||||
def test_superset_client_import_dashboard_guard():
|
||||
"""Verify that import_dashboard raises ValueError if file_name is None."""
|
||||
mock_env = Environment(
|
||||
@@ -42,6 +52,10 @@ def test_superset_client_import_dashboard_guard():
|
||||
client.import_dashboard(None)
|
||||
|
||||
|
||||
# [/DEF:test_superset_client_import_dashboard_guard:Function]
|
||||
|
||||
# [DEF:test_git_service_init_repo_reclones_when_path_is_not_a_git_repo:Function]
|
||||
# @RELATION: BINDS_TO -> UnknownModule
|
||||
def test_git_service_init_repo_reclones_when_path_is_not_a_git_repo():
|
||||
"""Verify init_repo reclones when target path exists but is not a valid Git repository."""
|
||||
service = GitService(base_path="test_repos_invalid_repo")
|
||||
@@ -61,6 +75,10 @@ def test_git_service_init_repo_reclones_when_path_is_not_a_git_repo():
|
||||
assert not target_path.exists()
|
||||
|
||||
|
||||
# [/DEF:test_git_service_init_repo_reclones_when_path_is_not_a_git_repo:Function]
|
||||
|
||||
# [DEF:test_git_service_ensure_gitflow_branches_creates_and_pushes_missing_defaults:Function]
|
||||
# @RELATION: BINDS_TO -> UnknownModule
|
||||
def test_git_service_ensure_gitflow_branches_creates_and_pushes_missing_defaults():
|
||||
"""Verify _ensure_gitflow_branches creates dev/preprod locally and pushes them to origin."""
|
||||
service = GitService(base_path="test_repos_gitflow_defaults")
|
||||
@@ -115,6 +133,10 @@ def test_git_service_ensure_gitflow_branches_creates_and_pushes_missing_defaults
|
||||
assert "preprod:preprod" in repo.origin.pushed
|
||||
|
||||
|
||||
# [/DEF:test_git_service_ensure_gitflow_branches_creates_and_pushes_missing_defaults:Function]
|
||||
|
||||
# [DEF:test_git_service_configure_identity_updates_repo_local_config:Function]
|
||||
# @RELATION: BINDS_TO -> UnknownModule
|
||||
def test_git_service_configure_identity_updates_repo_local_config():
|
||||
"""Verify configure_identity writes repository-local user.name/user.email."""
|
||||
service = GitService(base_path="test_repos_identity")
|
||||
@@ -130,3 +152,4 @@ def test_git_service_configure_identity_updates_repo_local_config():
|
||||
fake_repo.config_writer.assert_called_once_with(config_level="repository")
|
||||
config_writer.set_value.assert_any_call("user", "name", "user_1")
|
||||
config_writer.set_value.assert_any_call("user", "email", "user1@mail.ru")
|
||||
# [/DEF:test_git_service_configure_identity_updates_repo_local_config:Function]
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
# [DEF:backend.tests.core.test_git_service_gitea_pr:Module]
|
||||
# [DEF:TestGitServiceGiteaPr:Module]
|
||||
# @RELATION: BELONGS_TO -> SrcRoot
|
||||
# @COMPLEXITY: 3
|
||||
# @SEMANTICS: tests, git, gitea, pull_request, fallback
|
||||
# @PURPOSE: Validate Gitea PR creation fallback behavior when configured server URL is stale.
|
||||
# @LAYER: Domain
|
||||
# @RELATION: TESTS -> backend.src.services.git_service.create_gitea_pull_request
|
||||
# @INVARIANT: A 404 from primary Gitea URL retries once against remote-url host when different.
|
||||
|
||||
import asyncio
|
||||
@@ -19,6 +19,7 @@ from src.services.git_service import GitService
|
||||
|
||||
|
||||
# [DEF:test_derive_server_url_from_remote_strips_credentials:Function]
|
||||
# @RELATION: BINDS_TO -> TestGitServiceGiteaPr
|
||||
# @PURPOSE: Ensure helper returns host base URL and removes embedded credentials.
|
||||
# @PRE: remote_url is an https URL with username/token.
|
||||
# @POST: Result is scheme+host only.
|
||||
@@ -32,6 +33,7 @@ def test_derive_server_url_from_remote_strips_credentials():
|
||||
|
||||
|
||||
# [DEF:test_create_gitea_pull_request_retries_with_remote_host_on_404:Function]
|
||||
# @RELATION: BINDS_TO -> TestGitServiceGiteaPr
|
||||
# @PURPOSE: Verify create_gitea_pull_request retries with remote URL host after primary 404.
|
||||
# @PRE: primary server_url differs from remote_url host.
|
||||
# @POST: Method returns success payload from fallback request.
|
||||
@@ -67,6 +69,7 @@ def test_create_gitea_pull_request_retries_with_remote_host_on_404(monkeypatch):
|
||||
|
||||
|
||||
# [DEF:test_create_gitea_pull_request_returns_branch_error_when_target_missing:Function]
|
||||
# @RELATION: BINDS_TO -> TestGitServiceGiteaPr
|
||||
# @PURPOSE: Ensure Gitea 404 on PR creation is mapped to actionable target-branch validation error.
|
||||
# @PRE: PR create call returns 404 and target branch is absent.
|
||||
# @POST: Service raises HTTPException 400 with explicit missing target branch message.
|
||||
@@ -101,4 +104,4 @@ def test_create_gitea_pull_request_returns_branch_error_when_target_missing(monk
|
||||
assert "target branch 'preprod'" in str(exc_info.value.detail)
|
||||
# [/DEF:test_create_gitea_pull_request_returns_branch_error_when_target_missing:Function]
|
||||
|
||||
# [/DEF:backend.tests.core.test_git_service_gitea_pr:Module]
|
||||
# [/DEF:TestGitServiceGiteaPr:Module]
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
# [DEF:backend.tests.core.test_migration_engine:Module]
|
||||
# [DEF:TestMigrationEngine:Module]
|
||||
#
|
||||
# @COMPLEXITY: 3
|
||||
# @PURPOSE: Unit tests for MigrationEngine's cross-filter patching algorithms.
|
||||
@@ -26,8 +26,15 @@ from src.models.mapping import ResourceType
|
||||
|
||||
# --- Fixtures ---
|
||||
|
||||
|
||||
# [DEF:MockMappingService:Class]
|
||||
# @RELATION: BINDS_TO ->[TestMigrationEngine]
|
||||
# @COMPLEXITY: 2
|
||||
# @PURPOSE: Deterministic mapping service double for native filter ID remapping scenarios.
|
||||
# @INVARIANT: Returns mappings only for requested UUID keys present in seeded map.
|
||||
class MockMappingService:
|
||||
"""Mock that simulates IdMappingService.get_remote_ids_batch."""
|
||||
|
||||
def __init__(self, mappings: dict):
|
||||
self.mappings = mappings
|
||||
|
||||
@@ -39,26 +46,32 @@ class MockMappingService:
|
||||
return result
|
||||
|
||||
|
||||
# [/DEF:MockMappingService:Class]
|
||||
|
||||
|
||||
# [DEF:_write_dashboard_yaml:Function]
|
||||
# @RELATION: BINDS_TO -> TestMigrationEngine
|
||||
def _write_dashboard_yaml(dir_path: Path, metadata: dict) -> Path:
|
||||
"""Helper: writes a dashboard YAML file with json_metadata."""
|
||||
file_path = dir_path / "dash.yaml"
|
||||
with open(file_path, 'w') as f:
|
||||
with open(file_path, "w") as f:
|
||||
yaml.dump({"json_metadata": json.dumps(metadata)}, f)
|
||||
return file_path
|
||||
|
||||
|
||||
# --- _patch_dashboard_metadata tests ---
|
||||
|
||||
# [/DEF:_write_dashboard_yaml:Function]
|
||||
|
||||
|
||||
# [DEF:test_patch_dashboard_metadata_replaces_chart_ids:Function]
|
||||
# @RELATION: BINDS_TO -> TestMigrationEngine
|
||||
def test_patch_dashboard_metadata_replaces_chart_ids():
|
||||
"""Verifies that chartId values are replaced using the mapping service."""
|
||||
mock_service = MockMappingService({"uuid-chart-A": 999})
|
||||
engine = MigrationEngine(mock_service)
|
||||
|
||||
metadata = {
|
||||
"native_filter_configuration": [
|
||||
{"targets": [{"chartId": 42}]}
|
||||
]
|
||||
}
|
||||
metadata = {"native_filter_configuration": [{"targets": [{"chartId": 42}]}]}
|
||||
|
||||
with tempfile.TemporaryDirectory() as td:
|
||||
fp = _write_dashboard_yaml(Path(td), metadata)
|
||||
@@ -66,22 +79,25 @@ 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, "r") as f:
|
||||
data = yaml.safe_load(f)
|
||||
result = json.loads(data["json_metadata"])
|
||||
assert result["native_filter_configuration"][0]["targets"][0]["chartId"] == 999
|
||||
assert (
|
||||
result["native_filter_configuration"][0]["targets"][0]["chartId"] == 999
|
||||
)
|
||||
|
||||
|
||||
# [/DEF:test_patch_dashboard_metadata_replaces_chart_ids:Function]
|
||||
|
||||
|
||||
# [DEF:test_patch_dashboard_metadata_replaces_dataset_ids:Function]
|
||||
# @RELATION: BINDS_TO -> TestMigrationEngine
|
||||
def test_patch_dashboard_metadata_replaces_dataset_ids():
|
||||
"""Verifies that datasetId values are replaced using the mapping service."""
|
||||
mock_service = MockMappingService({"uuid-ds-B": 500})
|
||||
engine = MigrationEngine(mock_service)
|
||||
|
||||
metadata = {
|
||||
"native_filter_configuration": [
|
||||
{"targets": [{"datasetId": 10}]}
|
||||
]
|
||||
}
|
||||
metadata = {"native_filter_configuration": [{"targets": [{"datasetId": 10}]}]}
|
||||
|
||||
with tempfile.TemporaryDirectory() as td:
|
||||
fp = _write_dashboard_yaml(Path(td), metadata)
|
||||
@@ -89,12 +105,20 @@ 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, "r") as f:
|
||||
data = yaml.safe_load(f)
|
||||
result = json.loads(data["json_metadata"])
|
||||
assert result["native_filter_configuration"][0]["targets"][0]["datasetId"] == 500
|
||||
assert (
|
||||
result["native_filter_configuration"][0]["targets"][0]["datasetId"]
|
||||
== 500
|
||||
)
|
||||
|
||||
|
||||
# [/DEF:test_patch_dashboard_metadata_replaces_dataset_ids:Function]
|
||||
|
||||
|
||||
# [DEF:test_patch_dashboard_metadata_skips_when_no_metadata:Function]
|
||||
# @RELATION: BINDS_TO -> TestMigrationEngine
|
||||
def test_patch_dashboard_metadata_skips_when_no_metadata():
|
||||
"""Verifies early return when json_metadata key is absent."""
|
||||
mock_service = MockMappingService({})
|
||||
@@ -102,16 +126,21 @@ def test_patch_dashboard_metadata_skips_when_no_metadata():
|
||||
|
||||
with tempfile.TemporaryDirectory() as td:
|
||||
fp = Path(td) / "dash.yaml"
|
||||
with open(fp, 'w') as f:
|
||||
with open(fp, "w") as f:
|
||||
yaml.dump({"title": "No metadata here"}, f)
|
||||
|
||||
engine._patch_dashboard_metadata(fp, "target-env", {})
|
||||
|
||||
with open(fp, 'r') as f:
|
||||
with open(fp, "r") as f:
|
||||
data = yaml.safe_load(f)
|
||||
assert "json_metadata" not in data
|
||||
|
||||
|
||||
# [/DEF:test_patch_dashboard_metadata_skips_when_no_metadata:Function]
|
||||
|
||||
|
||||
# [DEF:test_patch_dashboard_metadata_handles_missing_targets:Function]
|
||||
# @RELATION: BINDS_TO -> TestMigrationEngine
|
||||
def test_patch_dashboard_metadata_handles_missing_targets():
|
||||
"""When some source IDs have no target mapping, patches what it can and leaves the rest."""
|
||||
mock_service = MockMappingService({"uuid-A": 100}) # Only uuid-A maps
|
||||
@@ -129,7 +158,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, "r") as f:
|
||||
data = yaml.safe_load(f)
|
||||
result = json.loads(data["json_metadata"])
|
||||
targets = result["native_filter_configuration"][0]["targets"]
|
||||
@@ -140,6 +169,11 @@ def test_patch_dashboard_metadata_handles_missing_targets():
|
||||
|
||||
# --- _extract_chart_uuids_from_archive tests ---
|
||||
|
||||
# [/DEF:test_patch_dashboard_metadata_handles_missing_targets:Function]
|
||||
|
||||
|
||||
# [DEF:test_extract_chart_uuids_from_archive:Function]
|
||||
# @RELATION: BINDS_TO -> TestMigrationEngine
|
||||
def test_extract_chart_uuids_from_archive():
|
||||
"""Verifies that chart YAML files are parsed for id->uuid mappings."""
|
||||
engine = MigrationEngine()
|
||||
@@ -151,9 +185,9 @@ def test_extract_chart_uuids_from_archive():
|
||||
chart1 = {"id": 42, "uuid": "uuid-42", "slice_name": "Chart One"}
|
||||
chart2 = {"id": 99, "uuid": "uuid-99", "slice_name": "Chart Two"}
|
||||
|
||||
with open(charts_dir / "chart1.yaml", 'w') as f:
|
||||
with open(charts_dir / "chart1.yaml", "w") as f:
|
||||
yaml.dump(chart1, f)
|
||||
with open(charts_dir / "chart2.yaml", 'w') as f:
|
||||
with open(charts_dir / "chart2.yaml", "w") as f:
|
||||
yaml.dump(chart2, f)
|
||||
|
||||
result = engine._extract_chart_uuids_from_archive(Path(td))
|
||||
@@ -163,23 +197,33 @@ def test_extract_chart_uuids_from_archive():
|
||||
|
||||
# --- _transform_yaml tests ---
|
||||
|
||||
# [/DEF:test_extract_chart_uuids_from_archive:Function]
|
||||
|
||||
|
||||
# [DEF:test_transform_yaml_replaces_database_uuid:Function]
|
||||
# @RELATION: BINDS_TO -> TestMigrationEngine
|
||||
def test_transform_yaml_replaces_database_uuid():
|
||||
"""Verifies that database_uuid in a dataset YAML is replaced."""
|
||||
engine = MigrationEngine()
|
||||
|
||||
with tempfile.TemporaryDirectory() as td:
|
||||
fp = Path(td) / "dataset.yaml"
|
||||
with open(fp, 'w') as f:
|
||||
with open(fp, "w") as f:
|
||||
yaml.dump({"database_uuid": "source-uuid-abc", "table_name": "my_table"}, f)
|
||||
|
||||
engine._transform_yaml(fp, {"source-uuid-abc": "target-uuid-xyz"})
|
||||
|
||||
with open(fp, 'r') as f:
|
||||
with open(fp, "r") as f:
|
||||
data = yaml.safe_load(f)
|
||||
assert data["database_uuid"] == "target-uuid-xyz"
|
||||
assert data["table_name"] == "my_table"
|
||||
|
||||
|
||||
# [/DEF:test_transform_yaml_replaces_database_uuid:Function]
|
||||
|
||||
|
||||
# [DEF:test_transform_yaml_ignores_unmapped_uuid:Function]
|
||||
# @RELATION: BINDS_TO -> TestMigrationEngine
|
||||
def test_transform_yaml_ignores_unmapped_uuid():
|
||||
"""Verifies no changes when UUID is not in the mapping."""
|
||||
engine = MigrationEngine()
|
||||
@@ -187,18 +231,23 @@ def test_transform_yaml_ignores_unmapped_uuid():
|
||||
with tempfile.TemporaryDirectory() as td:
|
||||
fp = Path(td) / "dataset.yaml"
|
||||
original = {"database_uuid": "unknown-uuid", "table_name": "test"}
|
||||
with open(fp, 'w') as f:
|
||||
with open(fp, "w") as f:
|
||||
yaml.dump(original, f)
|
||||
|
||||
engine._transform_yaml(fp, {"other-uuid": "replacement"})
|
||||
|
||||
with open(fp, 'r') as f:
|
||||
with open(fp, "r") as f:
|
||||
data = yaml.safe_load(f)
|
||||
assert data["database_uuid"] == "unknown-uuid"
|
||||
|
||||
|
||||
# --- [NEW] transform_zip E2E tests ---
|
||||
|
||||
# [/DEF:test_transform_yaml_ignores_unmapped_uuid:Function]
|
||||
|
||||
|
||||
# [DEF:test_transform_zip_end_to_end:Function]
|
||||
# @RELATION: BINDS_TO -> TestMigrationEngine
|
||||
def test_transform_zip_end_to_end():
|
||||
"""Verifies full orchestration: extraction, transformation, patching, and re-packaging."""
|
||||
mock_service = MockMappingService({"char-uuid": 101, "ds-uuid": 202})
|
||||
@@ -212,41 +261,41 @@ def test_transform_zip_end_to_end():
|
||||
# Create source ZIP structure
|
||||
with tempfile.TemporaryDirectory() as src_dir:
|
||||
src_path = Path(src_dir)
|
||||
|
||||
|
||||
# 1. Dataset
|
||||
ds_dir = src_path / "datasets"
|
||||
ds_dir.mkdir()
|
||||
with open(ds_dir / "ds.yaml", 'w') as f:
|
||||
with open(ds_dir / "ds.yaml", "w") as f:
|
||||
yaml.dump({"database_uuid": "source-db-uuid", "table_name": "users"}, f)
|
||||
|
||||
|
||||
# 2. Chart
|
||||
ch_dir = src_path / "charts"
|
||||
ch_dir.mkdir()
|
||||
with open(ch_dir / "ch.yaml", 'w') as f:
|
||||
with open(ch_dir / "ch.yaml", "w") as f:
|
||||
yaml.dump({"id": 10, "uuid": "char-uuid"}, f)
|
||||
|
||||
|
||||
# 3. Dashboard
|
||||
db_dir = src_path / "dashboards"
|
||||
db_dir.mkdir()
|
||||
metadata = {"native_filter_configuration": [{"targets": [{"chartId": 10}]}]}
|
||||
with open(db_dir / "db.yaml", 'w') as f:
|
||||
with open(db_dir / "db.yaml", "w") as f:
|
||||
yaml.dump({"json_metadata": json.dumps(metadata)}, f)
|
||||
|
||||
with zipfile.ZipFile(zip_path, 'w') as zf:
|
||||
with zipfile.ZipFile(zip_path, "w") as zf:
|
||||
for root, _, files in os.walk(src_path):
|
||||
for file in files:
|
||||
p = Path(root) / file
|
||||
zf.write(p, p.relative_to(src_path))
|
||||
|
||||
db_mapping = {"source-db-uuid": "target-db-uuid"}
|
||||
|
||||
|
||||
# Execute transform
|
||||
success = engine.transform_zip(
|
||||
str(zip_path),
|
||||
str(output_path),
|
||||
db_mapping,
|
||||
target_env_id="test-target",
|
||||
fix_cross_filters=True
|
||||
str(zip_path),
|
||||
str(output_path),
|
||||
db_mapping,
|
||||
target_env_id="test-target",
|
||||
fix_cross_filters=True,
|
||||
)
|
||||
|
||||
assert success is True
|
||||
@@ -254,23 +303,31 @@ def test_transform_zip_end_to_end():
|
||||
|
||||
# Verify contents
|
||||
with tempfile.TemporaryDirectory() as out_dir:
|
||||
with zipfile.ZipFile(output_path, 'r') as zf:
|
||||
with zipfile.ZipFile(output_path, "r") as zf:
|
||||
zf.extractall(out_dir)
|
||||
|
||||
|
||||
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", "r") 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", "r") as f:
|
||||
db_data = yaml.safe_load(f)
|
||||
meta = json.loads(db_data["json_metadata"])
|
||||
assert meta["native_filter_configuration"][0]["targets"][0]["chartId"] == 101
|
||||
assert (
|
||||
meta["native_filter_configuration"][0]["targets"][0]["chartId"]
|
||||
== 101
|
||||
)
|
||||
|
||||
|
||||
# [/DEF:test_transform_zip_end_to_end:Function]
|
||||
|
||||
|
||||
# [DEF:test_transform_zip_invalid_path:Function]
|
||||
# @RELATION: BINDS_TO -> TestMigrationEngine
|
||||
def test_transform_zip_invalid_path():
|
||||
"""@PRE: Verify behavior (False) on invalid ZIP path."""
|
||||
engine = MigrationEngine()
|
||||
@@ -278,13 +335,19 @@ def test_transform_zip_invalid_path():
|
||||
assert success is False
|
||||
|
||||
|
||||
# [/DEF:test_transform_zip_invalid_path:Function]
|
||||
|
||||
|
||||
# [DEF:test_transform_yaml_nonexistent_file:Function]
|
||||
# @RELATION: BINDS_TO -> TestMigrationEngine
|
||||
def test_transform_yaml_nonexistent_file():
|
||||
"""@PRE: Verify behavior on non-existent YAML file."""
|
||||
engine = MigrationEngine()
|
||||
# Should log error and not crash (implemented via try-except if wrapped,
|
||||
# Should log error and not crash (implemented via try-except if wrapped,
|
||||
# but _transform_yaml itself might raise FileNotFoundError if not guarded)
|
||||
with pytest.raises(FileNotFoundError):
|
||||
engine._transform_yaml(Path("non_existent.yaml"), {})
|
||||
|
||||
|
||||
# [/DEF:backend.tests.core.test_migration_engine:Module]
|
||||
# [/DEF:TestMigrationEngine:Module]
|
||||
# [/DEF:test_transform_yaml_nonexistent_file:Function]
|
||||
|
||||
Reference in New Issue
Block a user