from pathlib import Path from app.core.common.identifiers import new_governance_uid from app.core.data_rules.contracts import validate_dataflow_spec API = Path("frontend/src/api/dataRules.js") AUTHORING = Path("frontend/src/components/DataRules/RuleAuthoringPanel.vue") CATALOG = Path("frontend/src/components/DataRules/RuleCatalogPicker.vue") EVIDENCE = Path("frontend/src/components/DataRules/CompilationEvidence.vue") ASSEMBLER = Path( "frontend/src/components/DataRules/ProductionLineAssembler.vue" ) STANDARD = Path( "frontend/src/views/dataGovernance/dataStandard/components/edit.vue" ) DATAFLOW = Path( "frontend/src/views/dataGovernance/dataProcess/components/edit.vue" ) FACTORY = Path( "frontend/src/views/dataFactory/workflow/ProductionLineDeployment.vue" ) FACTORY_INDEX = Path("frontend/src/views/dataFactory/workflow/index.vue") def test_rule_api_client_exposes_versions_publish_and_server_side_release(): source = API.read_text(encoding="utf-8") assert "http.get('/rules/capabilities')" in source assert "http.post('/rules/interpret'" in source assert "http.post('/rules/validate'" in source assert "http.post('/rules/production-lines/resolve'" in source assert "http.post('/rules/rule-versions'" in source assert "http.post(`/rules/rule-versions/${versionId}/publish`)" in source assert "http.post(`/rules/rule-versions/${versionId}/validate`" in source assert "http.post(`/rules/rule-versions/${versionId}/test`" in source assert "http.get('/rules/catalog'" in source assert "/rules/catalog/assets/${assetType}/${versionId}/evidence" in source assert "http.post('/rules/standard-versions'" in source assert "http.post(`/rules/standard-versions/${versionId}/publish`)" in source assert "http.post(`/rules/production-lines/${dataflowUid}/release`" in source assert "/activate" not in source def test_reusable_authoring_panel_preserves_human_review_gate(): source = AUTHORING.read_text(encoding="utf-8") assert "authoringSurface" in source assert "interpretRule" in source assert "clarification_required" in source assert "$emit('candidate'" in source assert "createRuleVersion" in source assert "publishRuleVersion" in source assert "先生成并发布 RuleVersion" in source assert "rules:publish" in source assert "$emit('version'" in source assert "自动执行" not in source def test_authoring_panel_exposes_governed_ai_lifecycle_without_code_editor(): source = AUTHORING.read_text(encoding="utf-8") for token in [ "schemaContextReady", "generation_receipt", "assumptions", "ambiguities", "modelProvenance", "validateRuleVersion", "testRuleVersion", "CompilationEvidence", ]: assert token in source assert "candidatePreview" not in source assert "
{{ candidate" not in source
def test_catalog_picker_selects_fixed_published_asset_versions():
source = CATALOG.read_text(encoding="utf-8")
for token in [
"searchPublishedCatalog",
"assetType",
"published",
"schema_compatibility",
"latest_evidence",
"v-skeleton-loader",
"aria-label",
"keydown",
]:
assert token in source
assert "$emit('input', item.id)" in source
assert "item.name" in source
assert "rule_uid" in source
assert "standard_uid" in source
def test_compilation_evidence_shows_trusted_chain_without_sensitive_payloads():
source = EVIDENCE.read_text(encoding="utf-8")
for token in [
"generation",
"logical_compile",
"dry_run",
"publication",
"physical",
"getRuleVersionEvidence",
]:
assert token in source
for forbidden in ["raw_sample", "secret", "password", "token"]:
assert forbidden not in source.lower()
assert "'ready'" in source
def test_standard_links_published_rules_and_keeps_legacy_code_read_only():
standard = STANDARD.read_text(encoding="utf-8")
assert 'authoring-surface="data_standard"' in standard
assert '@version="handleRuleVersion"' in standard
assert "RuleCatalogPicker" in standard
assert "rule_version_id" in standard
assert "legacyMigration" in standard
assert "readonly" in standard
assert "迁移" in standard
assert "dataStandardCodeGenerate" not in standard
assert "handleCodeGenerate" not in standard
assert "rule_version_status" not in standard
def test_dataflow_assembler_uses_published_catalog_ids_without_inline_rules():
source = ASSEMBLER.read_text(encoding="utf-8")
dataflow = DATAFLOW.read_text(encoding="utf-8")
assert "RuleCatalogPicker" in source
assert "standard_version_id" in source
assert "rule_version_id" in source
assert "schema_compatibility" in source
assert "releaseReadiness" in source
assert "component_kind" in source
assert "rule_spec" not in source
assert "operation_code" not in source
assert "ProductionLineAssembler" in dataflow
assert "dataflow_spec" in dataflow
assert "migration_metadata" in dataflow
assert "rule_spec" not in dataflow
assert "v-model=\"changeObj.rule\"" not in dataflow
assert "handleRuleCandidate" not in dataflow
def test_assembler_emits_a_real_closed_dataflow_spec_for_every_station_kind():
standard_version_id = new_governance_uid()
apply_rule_version_id = new_governance_uid()
quality_rule_version_id = new_governance_uid()
normalized = validate_dataflow_spec(
{
"schema_version": "1.0",
"dataflow_uid": new_governance_uid(),
"name": "客户数据生产线",
"description": "固定受治理资产版本",
"input_schema_refs": ["bd:customer_raw:v1"],
"output_schema_ref": "bd:customer_clean:v1",
"components": [
{
"id": "station_1",
"type": "standard.enforce",
"standard_version_id": standard_version_id,
"stage": "quality_gate",
"order": 1,
},
{
"id": "station_2",
"type": "rule.apply",
"rule_version_id": apply_rule_version_id,
"stage": "transform",
"order": 2,
"idempotency": {
"strategy": "partition_replace",
"key": "run_partition",
},
},
{
"id": "station_3",
"type": "quality.check",
"rule_version_id": quality_rule_version_id,
"stage": "quality_gate",
"order": 3,
},
],
"parameters": {},
}
)
assert "idempotency" not in normalized["components"][0]
assert "idempotency" in normalized["components"][1]
assert "idempotency" not in normalized["components"][2]
source = ASSEMBLER.read_text(encoding="utf-8")
assert "station.component_kind === 'rule.apply'" in source
assert "component.idempotency" in source
assert "idempotency: {" not in source
def test_catalog_never_guesses_schema_compatibility_from_arbitrary_objects():
source = CATALOG.read_text(encoding="utf-8")
assembler = ASSEMBLER.read_text(encoding="utf-8")
assert "normalizeCompatibility" in source
assert "Object.keys(item.schema_compatibility).length" not in source
assert "unknown" in source
assert "schema_compatibility !== 'compatible'" in assembler
assert "服务端发布预检" in assembler
def test_new_dataflow_gets_server_governed_uid_before_assembly():
api = API.read_text(encoding="utf-8")
dataflow = DATAFLOW.read_text(encoding="utf-8")
assert "createProductionLineDraftIdentity" in api
assert "/rules/production-lines/draft-identity" in api
assert "ensureDataflowUid" in dataflow
assert "if (!this.dataflowUid) await this.ensureDataflowUid()" in dataflow
assert "persistedUid" in dataflow
assert "dataflow_uid: null" not in dataflow
def test_standard_authoring_does_not_forge_validated_state_client_side():
source = AUTHORING.read_text(encoding="utf-8")
assert "candidate.candidate_type === 'standard'" not in source or (
"status: 'validated'" not in source
)
assert "先发布规则,再在标准条款中绑定" in source
def test_data_factory_exposes_release_ready_but_no_fake_activation():
page = FACTORY.read_text(encoding="utf-8")
index = FACTORY_INDEX.read_text(encoding="utf-8")
assert "数据生产线投产" in page
assert "getRuleCapabilities" in page
assert "production_line_release" in page
assert "data_factory_activation" in page
assert "发布版本" in page
assert "执行计划" in page
assert "发布与执行计划已经可用" in page
assert "投产激活仍保持关闭" in page
assert "ProductionLineDeployment" in index