semantic
This commit is contained in:
@@ -331,6 +331,7 @@ def test_parse_superset_link_dashboard_partial_recovery():
|
||||
)
|
||||
fake_client = MagicMock()
|
||||
fake_client.get_dashboard_detail.return_value = {
|
||||
"id": 10,
|
||||
"datasets": [{"id": 42}, {"id": 77}],
|
||||
}
|
||||
fake_client.get_dataset_detail.return_value = {
|
||||
@@ -352,6 +353,123 @@ def test_parse_superset_link_dashboard_partial_recovery():
|
||||
# [/DEF:test_parse_superset_link_dashboard_partial_recovery:Function]
|
||||
|
||||
|
||||
# [DEF:test_parse_superset_link_dashboard_slug_recovery:Function]
|
||||
# @PURPOSE: Verify dashboard slug links resolve through dashboard detail endpoints and recover dataset context.
|
||||
def test_parse_superset_link_dashboard_slug_recovery():
|
||||
env = Environment(
|
||||
id="env-1",
|
||||
name="DEV",
|
||||
url="http://superset.local",
|
||||
username="demo",
|
||||
password="secret",
|
||||
)
|
||||
fake_client = MagicMock()
|
||||
fake_client.get_dashboard_detail.return_value = {
|
||||
"id": 15,
|
||||
"datasets": [{"id": 42}],
|
||||
}
|
||||
fake_client.get_dataset_detail.return_value = {
|
||||
"table_name": "sales",
|
||||
"schema": "public",
|
||||
}
|
||||
|
||||
extractor = SupersetContextExtractor(environment=env, client=fake_client)
|
||||
result = extractor.parse_superset_link(
|
||||
"https://ss-dev.bebesh.ru/superset/dashboard/slack/?native_filters_key=8ZLV4M-UXOM"
|
||||
)
|
||||
|
||||
assert result.dataset_id == 42
|
||||
assert result.dashboard_id == 15
|
||||
assert result.dataset_ref == "public.sales"
|
||||
assert result.partial_recovery is False
|
||||
assert result.query_state["native_filters_key"] == "8ZLV4M-UXOM"
|
||||
fake_client.get_dashboard_detail.assert_called_once_with("slack")
|
||||
# [/DEF:test_parse_superset_link_dashboard_slug_recovery:Function]
|
||||
|
||||
|
||||
# [DEF:test_parse_superset_link_dashboard_permalink_partial_recovery:Function]
|
||||
# @PURPOSE: Verify dashboard permalink links no longer fail parsing and preserve permalink filter state for partial recovery.
|
||||
def test_parse_superset_link_dashboard_permalink_partial_recovery():
|
||||
env = Environment(
|
||||
id="env-1",
|
||||
name="DEV",
|
||||
url="http://superset.local",
|
||||
username="demo",
|
||||
password="secret",
|
||||
)
|
||||
fake_client = MagicMock()
|
||||
fake_client.get_dashboard_permalink_state.return_value = {
|
||||
"state": {
|
||||
"dataMask": {
|
||||
"NATIVE_FILTER-1": {
|
||||
"id": "country",
|
||||
"filterState": {
|
||||
"label": "Country",
|
||||
"value": ["DE"],
|
||||
},
|
||||
"extraFormData": {
|
||||
"filters": [{"col": "country", "op": "IN", "val": ["DE"]}],
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
extractor = SupersetContextExtractor(environment=env, client=fake_client)
|
||||
result = extractor.parse_superset_link(
|
||||
"http://ss-dev.bebesh.ru/superset/dashboard/p/QabXy6wG30Z/"
|
||||
)
|
||||
|
||||
assert result.resource_type == "dashboard"
|
||||
assert result.dataset_id is None
|
||||
assert result.dashboard_id is None
|
||||
assert result.dataset_ref == "dashboard_permalink:QabXy6wG30Z"
|
||||
assert result.partial_recovery is True
|
||||
assert "dashboard_permalink_dataset_binding_unresolved" in result.unresolved_references
|
||||
assert result.imported_filters[0]["filter_name"] == "country"
|
||||
assert result.imported_filters[0]["raw_value"] == ["DE"]
|
||||
fake_client.get_dashboard_permalink_state.assert_called_once_with("QabXy6wG30Z")
|
||||
|
||||
|
||||
# [DEF:test_parse_superset_link_dashboard_permalink_recovers_dataset_from_nested_dashboard_state:Function]
|
||||
# @PURPOSE: Verify permalink state with nested dashboard id recovers dataset binding and keeps imported filters.
|
||||
def test_parse_superset_link_dashboard_permalink_recovers_dataset_from_nested_dashboard_state():
|
||||
env = Environment(
|
||||
id="env-1",
|
||||
name="DEV",
|
||||
url="http://superset.local",
|
||||
username="demo",
|
||||
password="secret",
|
||||
)
|
||||
fake_client = MagicMock()
|
||||
fake_client.get_dashboard_permalink_state.return_value = {
|
||||
"state": {
|
||||
"form_data": {"dashboardId": 22},
|
||||
"dataMask": {
|
||||
"NATIVE_FILTER-1": {
|
||||
"id": "country",
|
||||
"filterState": {"label": "Country", "value": ["DE"]},
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
fake_client.get_dashboard_detail.return_value = {"id": 22, "datasets": [{"id": 42}]}
|
||||
fake_client.get_dataset_detail.return_value = {"table_name": "sales", "schema": "public"}
|
||||
|
||||
extractor = SupersetContextExtractor(environment=env, client=fake_client)
|
||||
result = extractor.parse_superset_link(
|
||||
"http://ss-dev.bebesh.ru/superset/dashboard/p/QabXy6wG30Z/"
|
||||
)
|
||||
|
||||
assert result.dashboard_id == 22
|
||||
assert result.dataset_id == 42
|
||||
assert result.dataset_ref == "public.sales"
|
||||
assert "dashboard_permalink_dataset_binding_unresolved" not in result.unresolved_references
|
||||
assert result.imported_filters[0]["filter_name"] == "country"
|
||||
# [/DEF:test_parse_superset_link_dashboard_permalink_recovers_dataset_from_nested_dashboard_state:Function]
|
||||
# [/DEF:test_parse_superset_link_dashboard_permalink_partial_recovery:Function]
|
||||
|
||||
|
||||
# [DEF:test_resolve_from_dictionary_prefers_exact_match:Function]
|
||||
# @PURPOSE: Verify trusted dictionary exact matches outrank fuzzy candidates and unresolved fields stay explicit.
|
||||
def test_resolve_from_dictionary_prefers_exact_match():
|
||||
@@ -400,6 +518,7 @@ def test_orchestrator_start_session_preserves_partial_recovery(dataset_review_ap
|
||||
|
||||
repository.create_session.return_value = created_session
|
||||
repository.save_profile_and_findings.return_value = created_session
|
||||
repository.save_recovery_state.return_value = created_session
|
||||
repository.db = MagicMock()
|
||||
|
||||
orchestrator = DatasetReviewOrchestrator(
|
||||
@@ -415,11 +534,23 @@ def test_orchestrator_start_session_preserves_partial_recovery(dataset_review_ap
|
||||
chart_id=None,
|
||||
partial_recovery=True,
|
||||
unresolved_references=["dashboard_dataset_binding_missing"],
|
||||
imported_filters=[],
|
||||
)
|
||||
|
||||
fake_extractor = MagicMock()
|
||||
fake_extractor.parse_superset_link.return_value = parsed_context
|
||||
fake_extractor.recover_imported_filters.return_value = []
|
||||
fake_extractor.client.get_dataset_detail.return_value = {
|
||||
"id": 42,
|
||||
"sql": "",
|
||||
"columns": [],
|
||||
"metrics": [],
|
||||
}
|
||||
fake_extractor.discover_template_variables.return_value = []
|
||||
|
||||
with patch(
|
||||
"src.services.dataset_review.orchestrator.SupersetContextExtractor.parse_superset_link",
|
||||
return_value=parsed_context,
|
||||
"src.services.dataset_review.orchestrator.SupersetContextExtractor",
|
||||
side_effect=[fake_extractor, fake_extractor],
|
||||
):
|
||||
result = orchestrator.start_session(
|
||||
StartSessionCommand(
|
||||
@@ -438,6 +569,94 @@ def test_orchestrator_start_session_preserves_partial_recovery(dataset_review_ap
|
||||
# [/DEF:test_orchestrator_start_session_preserves_partial_recovery:Function]
|
||||
|
||||
|
||||
# [DEF:test_orchestrator_start_session_bootstraps_recovery_state:Function]
|
||||
# @PURPOSE: Verify session start persists recovered filters, template variables, and initial execution mappings for review workspace bootstrap.
|
||||
def test_orchestrator_start_session_bootstraps_recovery_state(dataset_review_api_dependencies):
|
||||
repository = MagicMock()
|
||||
created_session = _make_session()
|
||||
created_session.readiness_state = ReadinessState.RECOVERY_REQUIRED
|
||||
created_session.current_phase = SessionPhase.RECOVERY
|
||||
|
||||
repository.create_session.return_value = created_session
|
||||
repository.save_profile_and_findings.return_value = created_session
|
||||
repository.save_recovery_state.return_value = created_session
|
||||
repository.db = MagicMock()
|
||||
|
||||
orchestrator = DatasetReviewOrchestrator(
|
||||
repository=repository,
|
||||
config_manager=dataset_review_api_dependencies["config_manager"],
|
||||
task_manager=None,
|
||||
)
|
||||
|
||||
parsed_context = SimpleNamespace(
|
||||
dataset_ref="public.sales",
|
||||
dataset_id=42,
|
||||
dashboard_id=10,
|
||||
chart_id=None,
|
||||
partial_recovery=True,
|
||||
unresolved_references=["dashboard_dataset_binding_missing"],
|
||||
imported_filters=[{"filter_name": "country", "raw_value": ["DE"]}],
|
||||
)
|
||||
|
||||
fake_extractor = MagicMock()
|
||||
fake_extractor.parse_superset_link.return_value = parsed_context
|
||||
fake_extractor.recover_imported_filters.return_value = [
|
||||
{
|
||||
"filter_name": "country",
|
||||
"display_name": "Country",
|
||||
"raw_value": ["DE"],
|
||||
"normalized_value": ["DE"],
|
||||
"source": "superset_url",
|
||||
"confidence_state": "imported",
|
||||
"requires_confirmation": False,
|
||||
"recovery_status": "recovered",
|
||||
"notes": "Recovered from permalink state",
|
||||
}
|
||||
]
|
||||
fake_extractor.client.get_dataset_detail.return_value = {
|
||||
"id": 42,
|
||||
"sql": "select * from sales where country in {{ filter_values('country') }}",
|
||||
"columns": [],
|
||||
"metrics": [],
|
||||
}
|
||||
fake_extractor.discover_template_variables.return_value = [
|
||||
{
|
||||
"variable_name": "country",
|
||||
"expression_source": "{{ filter_values('country') }}",
|
||||
"variable_kind": "native_filter",
|
||||
"is_required": True,
|
||||
"default_value": None,
|
||||
"mapping_status": "unmapped",
|
||||
}
|
||||
]
|
||||
|
||||
with patch(
|
||||
"src.services.dataset_review.orchestrator.SupersetContextExtractor",
|
||||
side_effect=[fake_extractor, fake_extractor],
|
||||
):
|
||||
result = orchestrator.start_session(
|
||||
StartSessionCommand(
|
||||
user=dataset_review_api_dependencies["user"],
|
||||
environment_id="env-1",
|
||||
source_kind="superset_link",
|
||||
source_input="http://superset.local/dashboard/10",
|
||||
)
|
||||
)
|
||||
|
||||
assert result.session.readiness_state == ReadinessState.RECOVERY_REQUIRED
|
||||
repository.save_recovery_state.assert_called_once()
|
||||
saved_filters = repository.save_recovery_state.call_args.args[2]
|
||||
saved_variables = repository.save_recovery_state.call_args.args[3]
|
||||
saved_mappings = repository.save_recovery_state.call_args.args[4]
|
||||
assert len(saved_filters) == 1
|
||||
assert saved_filters[0].filter_name == "country"
|
||||
assert len(saved_variables) == 1
|
||||
assert saved_variables[0].variable_name == "country"
|
||||
assert len(saved_mappings) == 1
|
||||
assert saved_mappings[0].raw_input_value == ["DE"]
|
||||
# [/DEF:test_orchestrator_start_session_bootstraps_recovery_state:Function]
|
||||
|
||||
|
||||
# [DEF:test_start_session_endpoint_returns_created_summary:Function]
|
||||
# @PURPOSE: Verify POST session lifecycle endpoint returns a persisted ownership-scoped summary.
|
||||
def test_start_session_endpoint_returns_created_summary(dataset_review_api_dependencies):
|
||||
@@ -828,6 +1047,54 @@ def test_us3_mapping_patch_approval_preview_and_launch_endpoints(dataset_review_
|
||||
# [/DEF:test_us3_mapping_patch_approval_preview_and_launch_endpoints:Function]
|
||||
|
||||
|
||||
# [DEF:test_us3_preview_endpoint_returns_failed_preview_without_false_dashboard_not_found_contract_drift:Function]
|
||||
# @PURPOSE: Preview endpoint should preserve API contract and surface generic upstream preview failures without fabricating dashboard-not-found semantics for non-dashboard 404s.
|
||||
def test_us3_preview_endpoint_returns_failed_preview_without_false_dashboard_not_found_contract_drift(
|
||||
dataset_review_api_dependencies,
|
||||
):
|
||||
session = _make_us3_session()
|
||||
repository = MagicMock()
|
||||
repository.load_session_detail.return_value = session
|
||||
repository.db = MagicMock()
|
||||
repository.event_logger = MagicMock(spec=SessionEventLogger)
|
||||
|
||||
failed_preview = SimpleNamespace(
|
||||
preview_id="preview-failed",
|
||||
session_id="sess-1",
|
||||
preview_status=PreviewStatus.FAILED,
|
||||
compiled_sql=None,
|
||||
preview_fingerprint="fingerprint-failed",
|
||||
compiled_by="superset",
|
||||
error_code="superset_preview_failed",
|
||||
error_details="RuntimeError: [API_FAILURE] API resource not found at endpoint '/chart/data' | Context: {'status_code': 404, 'endpoint': '/chart/data', 'subtype': 'not_found'}",
|
||||
compiled_at=None,
|
||||
created_at=datetime.now(timezone.utc),
|
||||
)
|
||||
orchestrator = MagicMock()
|
||||
orchestrator.prepare_launch_preview.return_value = PreparePreviewResult(
|
||||
session=session,
|
||||
preview=failed_preview,
|
||||
blocked_reasons=[],
|
||||
)
|
||||
|
||||
app.dependency_overrides[_get_repository] = lambda: repository
|
||||
app.dependency_overrides[_get_orchestrator] = lambda: orchestrator
|
||||
|
||||
response = client.post("/api/dataset-orchestration/sessions/sess-1/preview")
|
||||
|
||||
assert response.status_code == 200
|
||||
payload = response.json()
|
||||
assert payload["preview_id"] == "preview-failed"
|
||||
assert payload["preview_status"] == "failed"
|
||||
assert payload["compiled_sql"] is None
|
||||
assert payload["compiled_by"] == "superset"
|
||||
assert payload["error_code"] == "superset_preview_failed"
|
||||
assert "/chart/data" in payload["error_details"]
|
||||
assert "API resource not found" in payload["error_details"]
|
||||
assert "Dashboard not found" not in payload["error_details"]
|
||||
# [/DEF:test_us3_preview_endpoint_returns_failed_preview_without_false_dashboard_not_found_contract_drift:Function]
|
||||
|
||||
|
||||
# [DEF:test_us3_launch_endpoint_requires_launch_permission:Function]
|
||||
# @PURPOSE: Launch endpoint should enforce the contract RBAC permission instead of the generic session-manage permission.
|
||||
def test_us3_launch_endpoint_requires_launch_permission(dataset_review_api_dependencies):
|
||||
|
||||
Reference in New Issue
Block a user