Files
ss-tools/backend/tests/services/test_structure_diff_service.py
busya a32ca0631b feat(037): capture, verification lifecycle, inheritance + close 036 stabilization
- Authoritative candidate capture with server-issued artifacts and raw-byte
  immutability hashing (source_response_hash server-owned)
- Closed-period lifecycle: request-hash bound approvals, persisted closure
  immutability violations, byte-for-byte catalog stability on reclosure
- Verification runs: persisted VerificationRun model + FK migration,
  publish gate (block_publish), scheduled observability runs (02:00 UTC)
- FR-013 baseline inheritance: prior_release_id migration, plan_inheritance/
  execute_inheritance classification and re-extraction, API endpoints
- Visual executor bound to release-deployment environment; caller mismatch
  rejected; visual SSIM/reconciliation modules
- Query execution decomposed: envelope/model/executor split, no direct SQL
- AgentRun approvals extracted to submodule; evidence adapter; _utils
- Dashboard testing service decomposed into 30+ modules (all <400 LOC)
- Five Feature-037 agent tools with permission guards (tools_037.py)
- API readiness endpoint; Alembic env/migrations; test fixture repos
- Specs 036/037 contracts, openapi.yaml, schema.json, tasks/traceability
  updated; semantic index rebuilt with 0 parse warnings
- Fix ADR-0003 parser ambiguity: remove [DEF🆔ADR] prose example
- Add axiom-mcp-agent-feedback.md: agent findings for MCP rework plan
- Tests: 298 service + 1464 API + 45 agent passing; ruff clean
2026-07-31 11:28:50 +03:00

595 lines
25 KiB
Python

# #region Test.BaselineEngine.StructureDiff.Service [C:4] [TYPE Module] [SEMANTICS test,structure-diff,service,deterministic,snapshot]
# @defgroup Test.BaselineEngine.StructureDiff Service-level tests for snapshot-loaded structure diff.
# @LAYER Test
# @RELATION BINDS_TO -> [BaselineEngine.StructureDiff.Service]
# @RELATION VERIFIES -> [BaselineEngine.StructureDiff.ComputeDiff]
# @TEST_EDGE same_snapshot -> zero changes, pass=1, blocked=False
# @TEST_EDGE chart_removed -> critical chart_removed change, blocked=True
# @TEST_EDGE filter_scope_lost -> critical filter_scope_narrowed change
# @TEST_EDGE column_reorder -> warning column_order_changed, xlsx_export affected
# @TEST_EDGE missing_snapshot -> blocked diff with critical missing-snapshot change, NOT synthetic empty diff
# @TEST_EDGE malformed_snapshot -> ValueError raised
# @TEST_EDGE identical_snapshots -> deterministic hash matches
# @TEST_EDGE affected_artifacts -> correct artifacts per change kind
# @INVARIANT The diff is computed from persisted DashboardQueryModel snapshots,
# never from version strings or release metadata.
# @INVARIANT Missing snapshots produce blocked=True with critical severity,
# never a synthetic empty diff.
from __future__ import annotations
from pathlib import Path
import pytest
from src.schemas.dashboard_testing import DiffKind, DiffSeverity, StructureDiffRequest
from src.services.dashboard_testing.structure_diff_service import compute_structure_diff, set_snapshot_base_path
# ── Fixture path ────────────────────────────────────────────────
FIXTURE_DIR = Path(__file__).parents[1] / "fixtures" / "structure_diff"
@pytest.fixture(autouse=True)
def _use_fixture_base():
"""Point the snapshot loader at our test fixture directory."""
set_snapshot_base_path(FIXTURE_DIR)
yield
# Reset to None after each test to avoid cross-test contamination
set_snapshot_base_path(Path.cwd())
# ── Helper ──────────────────────────────────────────────────────
def _make_request(
release_from: str,
release_to: str,
environment_id: str = "ss-preprod",
dashboard_id: int = 42,
repository_key: str | None = None,
dashboard_key: str | None = None,
) -> StructureDiffRequest:
"""Build a StructureDiffRequest pointing at fixture snapshots."""
return StructureDiffRequest(
environment_id=environment_id,
dashboard_id=dashboard_id,
release_version_from=release_from,
release_version_to=release_to,
repository_key=repository_key,
dashboard_key=dashboard_key,
)
def _count_by_severity(changes: list) -> dict[str, int]:
"""Quick severity tally from a change list."""
counts: dict[str, int] = {"critical": 0, "warning": 0, "info": 0}
for c in changes:
counts[c.severity] += 1
return counts
# #region Test.BaselineEngine.StructureDiff.IdenticalSnapshots [C:2] [TYPE Class]
class TestIdenticalSnapshots:
"""Both release versions point to the same snapshot → zero changes."""
# #region Test.BaselineEngine.StructureDiff.IdenticalSnapshots.TestSameSnapshot
def test_same_snapshot_yields_empty_diff(self):
"""T037: same snapshot from/to → no changes, pass=1, blocked=False."""
request = _make_request("v1.0.0", "v1.0.0")
diff = compute_structure_diff(request)
assert diff.release_from == "v1.0.0"
assert diff.release_to == "v1.0.0"
assert diff.query_model_hash_from == diff.query_model_hash_to
assert diff.changes == []
assert diff.summary["pass"] == 1
assert diff.summary["critical"] == 0
assert diff.summary["warning"] == 0
assert diff.summary["info"] == 0
assert diff.blocked is False
# #endregion
# #region Test.BaselineEngine.StructureDiff.IdenticalSnapshots.TestDeterministicHash
def test_deterministic_hash_across_calls(self):
"""T037: same snapshot file produces same hash every time."""
request = _make_request("v1.0.0", "v1.0.0")
diff1 = compute_structure_diff(request)
diff2 = compute_structure_diff(request)
assert diff1.query_model_hash_from == diff2.query_model_hash_from
assert diff1.query_model_hash_to == diff2.query_model_hash_to
# #endregion
# #region Test.BaselineEngine.StructureDiff.IdenticalSnapshots.TestHashFormat
def test_hash_format(self):
"""T037: hash starts with 'sha256:' and is 71 chars (prefix + 64 hex)."""
request = _make_request("v1.0.0", "v1.0.0")
diff = compute_structure_diff(request)
h = diff.query_model_hash_from
assert h is not None
assert h.startswith("sha256:")
assert len(h) == 71 # "sha256:" (7) + 64 hex chars
# #endregion
# #endregion
# #region Test.BaselineEngine.StructureDiff.ChartRemoved [C:2] [TYPE Class]
class TestChartRemoved:
"""Target snapshot has chart 129 removed → critical change."""
# #region Test.BaselineEngine.StructureDiff.ChartRemoved.TestChartRemovedCritical
def test_chart_removed_is_critical(self):
"""T037: chart removed → critical severity, blocked=True."""
request = _make_request("v1.0.0", "v1.1.0-chart-removed")
diff = compute_structure_diff(request)
assert diff.summary["critical"] >= 1
assert diff.blocked is True
# Find the CHART_REMOVED change
chart_changes = [c for c in diff.changes if c.kind == DiffKind.CHART_REMOVED]
assert len(chart_changes) == 1
cc = chart_changes[0]
assert cc.severity == DiffSeverity.CRITICAL
assert "129" in cc.target or "Total Revenue KPI" in cc.detail
assert cc.before is not None
assert cc.before["chart_id"] == 129
assert cc.after is None
assert "screenshot_evidence" in cc.affected_artifacts
assert "metric_assertion" in cc.affected_artifacts
# #endregion
# #region Test.BaselineEngine.StructureDiff.ChartRemoved.TestHashesDiffer
def test_hashes_differ_when_chart_removed(self):
"""T037: different snapshots produce different hashes."""
request = _make_request("v1.0.0", "v1.1.0-chart-removed")
diff = compute_structure_diff(request)
assert diff.query_model_hash_from != diff.query_model_hash_to
# #endregion
# #endregion
# #region Test.BaselineEngine.StructureDiff.FilterScopeLost [C:2] [TYPE Class]
class TestFilterScopeLost:
"""Target snapshot has chart 128 losing its filter scope → critical."""
# #region Test.BaselineEngine.StructureDiff.FilterScopeLost.TestFilterScopeNarrowed
def test_filter_scope_narrowed_is_critical(self):
"""T037: filter scope narrowed on chart 128 → critical."""
request = _make_request("v1.0.0", "v1.1.0-filter-scope-lost")
diff = compute_structure_diff(request)
# Should have at least one FILTER_SCOPE_NARROWED
narrow_changes = [
c for c in diff.changes
if c.kind == DiffKind.FILTER_SCOPE_NARROWED
]
assert len(narrow_changes) >= 1
nc = narrow_changes[0]
assert nc.severity == DiffSeverity.CRITICAL
assert "NATIVE_FILTER-date" in nc.detail or "NATIVE_FILTER-region" in nc.detail
assert "metric_assertion" in nc.affected_artifacts
assert diff.blocked is True
# #endregion
# #endregion
# #region Test.BaselineEngine.StructureDiff.ColumnReorder [C:2] [TYPE Class]
class TestColumnReorder:
"""Target snapshot has reordered dataset columns → warning."""
# #region Test.BaselineEngine.StructureDiff.ColumnReorder.TestColumnOrderChanged
def test_column_order_changed_is_warning(self):
"""T037: column order changed → warning severity, xlsx_export affected."""
request = _make_request("v1.0.0", "v1.1.0-column-reorder")
diff = compute_structure_diff(request)
order_changes = [
c for c in diff.changes
if c.kind == DiffKind.COLUMN_ORDER_CHANGED
]
assert len(order_changes) >= 1
oc = order_changes[0]
assert oc.severity == DiffSeverity.WARNING
assert oc.before is not None
assert oc.after is not None
assert "xlsx_export" in oc.affected_artifacts
assert "screenshot_evidence" in oc.affected_artifacts
assert diff.blocked is False # column reorder is warning, not critical
# #endregion
# #endregion
# #region Test.BaselineEngine.StructureDiff.MissingSnapshot [C:2] [TYPE Class]
class TestMissingSnapshot:
"""One or both snapshots do not exist → blocked error, NOT synthetic success."""
# #region Test.BaselineEngine.StructureDiff.MissingSnapshot.TestBaseMissing
def test_missing_base_snapshot_blocks(self):
"""T037: missing base snapshot → blocked=True with critical explanation."""
request = _make_request("v999.0.0-nonexistent", "v1.0.0")
diff = compute_structure_diff(request)
assert diff.blocked is True
assert diff.summary["critical"] >= 1
assert diff.summary["pass"] == 0
# Verify it's NOT an empty diff
assert len(diff.changes) >= 1
# The change should explain the missing snapshot
assert "not found" in diff.changes[0].detail.lower()
# #endregion
# #region Test.BaselineEngine.StructureDiff.MissingSnapshot.TestTargetMissing
def test_missing_target_snapshot_blocks(self):
"""T037: missing target snapshot → blocked=True."""
request = _make_request("v1.0.0", "v999.0.0-nonexistent")
diff = compute_structure_diff(request)
assert diff.blocked is True
assert diff.summary["critical"] >= 1
assert diff.summary["pass"] == 0
assert "not found" in diff.changes[0].detail.lower()
# #endregion
# #region Test.BaselineEngine.StructureDiff.MissingSnapshot.TestNoSyntheticSuccess
def test_missing_snapshot_not_synthetic_success(self):
"""T037: CRITICAL: never return pass=1 when snapshots are missing."""
request = _make_request("v999.0.0-nonexistent", "v1.0.0")
diff = compute_structure_diff(request)
# This asserts the forbidden behavior: no synthetic empty diff
assert not (diff.summary["pass"] == 1 and diff.changes == [])
# #endregion
# #endregion
# #region Test.BaselineEngine.StructureDiff.MalformedSnapshot [C:2] [TYPE Class]
class TestMalformedSnapshot:
"""Snapshot file exists but contains invalid JSON → ValueError."""
# #region Test.BaselineEngine.StructureDiff.MalformedSnapshot.TestMalformedFile
def test_malformed_snapshot_raises(self):
"""T037: malformed JSON snapshot raises ValueError."""
request = _make_request("v1.0.0", "v1.1.0-malformed")
with pytest.raises(ValueError, match="Malformed snapshot"):
compute_structure_diff(request)
# #endregion
# #endregion
# #region Test.BaselineEngine.StructureDiff.FullDiffScenarios [C:3] [TYPE Class]
class TestFullDiffScenarios:
"""End-to-end diff scenarios with all classification dimensions."""
# #region Test.BaselineEngine.StructureDiff.FullDiffScenarios.TestSummaryCounts
def test_chart_removed_summary_counts(self):
"""T037: chart removed diff has correct severity breakdown."""
request = _make_request("v1.0.0", "v1.1.0-chart-removed")
diff = compute_structure_diff(request)
assert diff.summary["critical"] >= 1 # chart_removed + filter scope changes
assert diff.summary["pass"] == 0
# Verify total changes equals sum of severity counts
total = diff.summary["critical"] + diff.summary["warning"] + diff.summary["info"]
assert total == len(diff.changes)
# #endregion
# #region Test.BaselineEngine.StructureDiff.FullDiffScenarios.TestAffectedArtifactsMapping
def test_affected_artifacts_mapped_correctly(self):
"""T037: every change has appropriate affected_artifacts."""
request = _make_request("v1.0.0", "v1.1.0-chart-removed")
diff = compute_structure_diff(request)
for change in diff.changes:
# Every change must have at least one affected artifact
assert len(change.affected_artifacts) >= 1, (
f"Change {change.kind} on {change.target} has no affected_artifacts"
)
# All values must be valid
for artifact in change.affected_artifacts:
assert artifact in ("xlsx_export", "screenshot_evidence", "metric_assertion")
# #endregion
# #region Test.BaselineEngine.StructureDiff.FullDiffScenarios.TestAllChangesHaveRationale
def test_all_changes_have_rationale(self):
"""T037: every change must have a rationale string."""
request = _make_request("v1.0.0", "v1.1.0-chart-removed")
diff = compute_structure_diff(request)
for change in diff.changes:
assert change.rationale is not None and len(change.rationale) > 0, (
f"Change {change.kind} on {change.target} missing rationale"
)
# #endregion
# #endregion
# #region Test.BaselineEngine.StructureDiff.Deterministic [C:2] [TYPE Class]
class TestDeterministicBehavior:
"""Repeated calls with same inputs produce identical results."""
# #region Test.BaselineEngine.StructureDiff.Deterministic.TestRepeatedIdentical
def test_identical_snapshot_always_empty(self):
"""T037: repeated calls with same snapshot always return empty diff."""
req = _make_request("v1.0.0", "v1.0.0")
for _ in range(3):
diff = compute_structure_diff(req)
assert diff.changes == []
assert diff.summary["pass"] == 1
# #endregion
# #region Test.BaselineEngine.StructureDiff.Deterministic.TestRepeatedWithChanges
def test_repeated_diff_produces_identical_changes(self):
"""T037: repeated calls with different snapshots produce identical change lists."""
req = _make_request("v1.0.0", "v1.1.0-chart-removed")
ref = compute_structure_diff(req)
for _ in range(3):
diff = compute_structure_diff(req)
assert len(diff.changes) == len(ref.changes)
assert [c.kind for c in diff.changes] == [c.kind for c in ref.changes]
assert [c.severity for c in diff.changes] == [c.severity for c in ref.changes]
assert diff.summary == ref.summary
assert diff.blocked == ref.blocked
# #endregion
# #endregion
# #region Test.BaselineEngine.StructureDiff.APIBehavior [C:2] [TYPE Class]
class TestAPIBehavior:
"""Ensure the API-facing contract works correctly with the new implementation."""
# #region Test.BaselineEngine.StructureDiff.APIBehavior.TestRepositoryKeyInference
def test_repository_key_fallback(self):
"""T037: when no repository_key given, uses env+id based fallback."""
request = _make_request(
"v1.0.0", "v1.0.0",
environment_id="ss-preprod", dashboard_id=42,
)
# Should not raise — builds default key from env+dashboard
diff = compute_structure_diff(request)
assert diff.changes == []
# #endregion
# #region Test.BaselineEngine.StructureDiff.APIBehavior.TestRequestExtraFields
def test_request_accepts_repository_and_dashboard_keys(self):
"""T037: optional repository_key/dashboard_key accepted (via schema)."""
from src.schemas.dashboard_testing import StructureDiffRequest
# Schema accepts the keys — this is the contract test
req = StructureDiffRequest(
environment_id="dev",
dashboard_id=1,
release_version_from="v1.0.0",
release_version_to="v2.0.0",
repository_key="my_repo",
dashboard_key="my_dashboard",
)
assert req.repository_key == "my_repo"
assert req.dashboard_key == "my_dashboard"
# Service uses them for path resolution; fixture doesn't exist
# but that's OK — this test only validates schema acceptance
# #endregion
# #endregion
# #region Test.BaselineEngine.StructureDiff.SchemaValidation [C:2] [TYPE Class]
class TestSchemaValidation:
"""New schema fields are populated correctly."""
# #region Test.BaselineEngine.StructureDiff.SchemaValidation.TestAffectedArtifactsOnStructureChange
def test_structure_change_has_affected_artifacts(self):
"""T037: StructureChange has affected_artifacts field."""
from src.schemas.dashboard_testing import StructureChange
sc = StructureChange(
target="charts[128]",
kind=DiffKind.CHART_REMOVED,
severity=DiffSeverity.CRITICAL,
detail="Test change",
affected_artifacts=["screenshot_evidence"],
)
assert sc.affected_artifacts == ["screenshot_evidence"]
# #endregion
# #region Test.BaselineEngine.StructureDiff.SchemaValidation.TestStructureDiffRequestHasKeys
def test_structure_diff_request_has_optional_keys(self):
"""T037: StructureDiffRequest has optional repository_key/dashboard_key."""
from src.schemas.dashboard_testing import StructureDiffRequest
req = StructureDiffRequest(
environment_id="dev",
dashboard_id=1,
release_version_from="v1.0.0",
release_version_to="v2.0.0",
repository_key="my_repo",
dashboard_key="my_dashboard",
)
assert req.repository_key == "my_repo"
assert req.dashboard_key == "my_dashboard"
# #endregion
# #endregion
# #region Test.BaselineEngine.StructureDiff.Classifier [C:2] [TYPE Class]
class TestClassifier:
"""Unit tests for severity classification and artifact mapping."""
# #region Test.BaselineEngine.StructureDiff.Classifier.TestSeverityCritical
def test_classify_critical(self):
from src.schemas.dashboard_testing import DiffKind, DiffSeverity
from src.services.dashboard_testing.structure_diff_classifier import classify_severity
critical_kinds = [DiffKind.FILTER_SCOPE_NARROWED, DiffKind.FILTER_OPERATOR_CHANGED,
DiffKind.CHART_REMOVED, DiffKind.FILTER_REMOVED]
for k in critical_kinds:
assert classify_severity(k) == DiffSeverity.CRITICAL
# #endregion
# #region Test.BaselineEngine.StructureDiff.Classifier.TestSeverityWarning
def test_classify_warning(self):
from src.schemas.dashboard_testing import DiffKind, DiffSeverity
from src.services.dashboard_testing.structure_diff_classifier import classify_severity
warning_kinds = [DiffKind.COLUMN_REORDER, DiffKind.COLUMN_ORDER_CHANGED,
DiffKind.COLUMN_REMOVED, DiffKind.GROUP_BY_CHANGE,
DiffKind.VIZ_TYPE_CHANGE]
for k in warning_kinds:
assert classify_severity(k) == DiffSeverity.WARNING
# #endregion
# #region Test.BaselineEngine.StructureDiff.Classifier.TestSeverityInfo
def test_classify_info(self):
from src.schemas.dashboard_testing import DiffKind, DiffSeverity
from src.services.dashboard_testing.structure_diff_classifier import classify_severity
info_kinds = [DiffKind.CHART_ADDED, DiffKind.COLUMN_ADDED,
DiffKind.FILTER_ADDED, DiffKind.METRIC_ADDED,
DiffKind.METRIC_REMOVED, DiffKind.DATASET_CHANGED]
for k in info_kinds:
assert classify_severity(k) == DiffSeverity.INFO
# #endregion
# #region Test.BaselineEngine.StructureDiff.Classifier.TestAffectedArtifacts
def test_affected_artifacts(self):
from src.schemas.dashboard_testing import DiffKind
from src.services.dashboard_testing.structure_diff_classifier import affected_artifacts_for
# CHART_REMOVED affects screenshot (not metric_assertion by classifier contract)
arts = affected_artifacts_for(DiffKind.CHART_REMOVED)
assert "screenshot_evidence" in arts
# COLUMN_REMOVED affects xlsx
arts = affected_artifacts_for(DiffKind.COLUMN_REMOVED)
assert "xlsx_export" in arts
assert "screenshot_evidence" not in arts
# FILTER_REMOVED affects metric_assertion
arts = affected_artifacts_for(DiffKind.FILTER_REMOVED)
assert "metric_assertion" in arts
# #endregion
# #region Test.BaselineEngine.StructureDiff.Classifier.TestBuildMissingSnapshot
def test_build_missing_snapshot_diff(self):
from src.services.dashboard_testing.structure_diff_classifier import build_missing_snapshot_diff
diff = build_missing_snapshot_diff("v1.0.0", "v2.0.0", "v1.0.0", "/tmp/notfound.json")
assert diff.blocked is True
assert diff.summary["critical"] == 1
assert diff.summary["pass"] == 0
assert "not found" in diff.changes[0].detail.lower()
assert diff.query_model_hash_from is None
assert diff.query_model_hash_to is None
# #endregion
# #endregion
# #region Test.BaselineEngine.StructureDiff.PersistSnapshot [C:2] [TYPE Class]
class TestPersistSnapshot:
"""Tests for atomic snapshot persistence."""
# #region Test.BaselineEngine.StructureDiff.PersistSnapshot.TestPersistAndLoad
def test_persist_and_load_snapshot(self, tmp_path):
from src.schemas.dashboard_testing import DashboardQueryModel
from src.services.dashboard_testing.snapshot_loader import load_snapshot, persist_snapshot
model = DashboardQueryModel(
environment_id="test-env",
dashboard_id=1,
title="Test Dashboard",
charts=[],
datasets=[],
native_filters=[],
query_model_fingerprint="sha256:test123",
)
path = persist_snapshot(
model, "test-repo", "test-dash", "v1.0.0", base_path=str(tmp_path),
)
assert path.exists()
assert path.name == "v1.0.0.json"
assert "test-repo" in str(path)
assert "test-dash" in str(path)
loaded = load_snapshot(path, "v1.0.0")
assert loaded.environment_id == "test-env"
assert loaded.dashboard_id == 1
assert loaded.title == "Test Dashboard"
assert loaded.query_model_fingerprint == "sha256:test123"
# #endregion
# #region Test.BaselineEngine.StructureDiff.PersistSnapshot.TestPersistPathContainment
def test_persist_invalid_path_raises(self, tmp_path):
from src.schemas.dashboard_testing import DashboardQueryModel
from src.services.dashboard_testing.snapshot_loader import persist_snapshot
model = DashboardQueryModel(
environment_id="e", dashboard_id=1, title="T",
query_model_fingerprint="sha256:x",
)
with pytest.raises(ValueError, match="must not contain"):
persist_snapshot(
model, "../escape", "dash", "v1.0.0", base_path=str(tmp_path),
)
# #endregion
# #region Test.BaselineEngine.StructureDiff.PersistSnapshot.TestPersistAtomicity
def test_persist_snapshot_file_content(self, tmp_path):
import json
from src.schemas.dashboard_testing import DashboardQueryModel
from src.services.dashboard_testing.snapshot_loader import persist_snapshot
model = DashboardQueryModel(
environment_id="e2", dashboard_id=2, title="Atomic Test",
slug="atomic-test",
query_model_fingerprint="sha256:atomic_fp",
)
path = persist_snapshot(
model, "atomic-repo", "atomic-dash", "v2.0.0", base_path=str(tmp_path),
)
raw = json.loads(path.read_text())
assert raw["environment_id"] == "e2"
assert raw["dashboard_id"] == 2
assert raw["title"] == "Atomic Test"
assert raw["query_model_fingerprint"] == "sha256:atomic_fp"
assert raw["schema_version"] == 1
# #endregion
# #endregion
# #region Test.BaselineEngine.StructureDiff.CaptureResponse [C:2] [TYPE Class]
class TestCaptureResponseSchema:
"""Schema validation for SnapshotCaptureResponse."""
# #region Test.BaselineEngine.StructureDiff.CaptureResponse.TestCaptureResponse
def test_capture_response_schema(self):
from src.schemas.dashboard_testing import SnapshotCaptureResponse
resp = SnapshotCaptureResponse(
snapshot_path="/tmp/snap.json",
environment_id="prod",
dashboard_id=42,
release_version="v1.0.0",
repository_key="my-repo",
dashboard_key="my-dash",
charts_count=3,
filters_count=2,
datasets_count=1,
query_model_fingerprint="sha256:abc123",
warnings=0,
)
assert resp.snapshot_path == "/tmp/snap.json"
assert resp.charts_count == 3
assert resp.filters_count == 2
assert resp.datasets_count == 1
assert resp.query_model_fingerprint == "sha256:abc123"
# #endregion
# #region Test.BaselineEngine.StructureDiff.CaptureResponse.TestCaptureResponseDefaults
def test_capture_response_defaults(self):
from src.schemas.dashboard_testing import SnapshotCaptureResponse
resp = SnapshotCaptureResponse(
snapshot_path="/tmp/s.json",
environment_id="e",
dashboard_id=1,
release_version="v1",
repository_key="r",
dashboard_key="d",
)
assert resp.charts_count == 0
assert resp.filters_count == 0
assert resp.datasets_count == 0
assert resp.query_model_fingerprint == ""
assert resp.warnings == 0
# #endregion
# #endregion
# #endregion Test.BaselineEngine.StructureDiff.Service