| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123 |
- """End-to-end tests for the M3-M0 governance vertical slice."""
- from __future__ import annotations
- import os
- os.environ.setdefault("AGENTPAAS_DATABASE_URL", "sqlite:///:memory:")
- os.environ.setdefault("AGENTPAAS_TESTING", "1")
- import pytest
- from agentpaas.db.models import Database, now_utc
- from agentpaas.governance import service
- from agentpaas.governance.agents import execute_governance_agent
- @pytest.fixture
- def db():
- value = Database("sqlite:///:memory:")
- value.execute(
- "INSERT INTO tenants (id,name,plan,status,created_at) VALUES (?,?,?,?,?)",
- ("tenant-a", "Tenant A", "free", "active", now_utc()),
- )
- value.execute(
- "INSERT INTO tenants (id,name,plan,status,created_at) VALUES (?,?,?,?,?)",
- ("tenant-b", "Tenant B", "free", "active", now_utc()),
- )
- value.commit()
- return value
- def test_reference_slice_is_complete_valid_and_idempotent(db):
- first = service.seed_tenant_isolation(db, "tenant-a")
- second = service.seed_tenant_isolation(db, "tenant-a")
- assert first["project"]["id"] == second["project"]["id"]
- assert second["validation"]["valid"] is True
- assert second["validation"]["findings"] == []
- assert second["overview"]["layers"]["M3"] == 8
- assert second["overview"]["layers"]["M0"] == 3
- assert second["overview"]["totals"]["pending_reviews"] == 0
- def test_impact_crosses_business_software_and_governance_profiles(db):
- seeded = service.seed_tenant_isolation(db, "tenant-a")
- project_id = seeded["project"]["id"]
- elements = service.list_elements(db, "tenant-a", project_id, query="TenantIdColumn")["items"]
- column = next(item for item in elements if item["name"] == "TenantIdColumn")
- result = service.impact(db, "tenant-a", column["id"], max_depth=5)
- names = {item["name"] for item in result["nodes"]}
- assert {"Tenant", "IAMDataOwner", "TenantIsolationPolicy", "TenantIdCompleteness"} <= names
- assert any(edge["predicate"] == "REPRESENTS" for edge in result["edges"])
- def test_tenant_scope_blocks_cross_tenant_reads(db):
- seeded = service.seed_tenant_isolation(db, "tenant-a")
- project_id = seeded["project"]["id"]
- with pytest.raises(service.GovernanceError) as exc:
- service.overview(db, "tenant-b", project_id)
- assert exc.value.status == 404
- def test_ddl_agent_persists_facts_candidates_evidence_and_trace(db):
- project = service.create_project(db, "tenant-a", {
- "name": "DDL ingest", "namespace": "https://example.test/ddl",
- })
- ddl = """
- CREATE TABLE dcp_customer (
- id BIGINT PRIMARY KEY,
- mobile VARCHAR(32) NOT NULL,
- created_at TIMESTAMP
- );
- """
- response = execute_governance_agent(db, "tenant-a", project["id"], {
- "source_type": "ddl",
- "source_name": "customer.sql",
- "environment": "production",
- "content": ddl,
- })
- assert response["status"] == "completed"
- assert response["persisted"]["elements"] == 9
- assert response["persisted"]["assertions"] == 11
- assert response["persisted"]["issues"] == 2
- assert {entry["term_name"] for entry in response["trace"]} >= {
- "governance-source-normalizer", "asset-discovery-agent",
- "business-semantics-agent", "governance-controls-agent",
- "governance-synthesis-agent",
- }
- pending = service.list_assertions(
- db, "tenant-a", project["id"], review_status="pending"
- )
- assert len(pending) == 1
- assert pending[0]["predicate"] == "REPRESENTS"
- assert pending[0]["assertion_type"] == "inferred"
- assert pending[0]["evidence_ids"]
- reviewed = service.review_assertion(
- db, "tenant-a", pending[0]["id"], "accepted", "data-steward", "术语已确认"
- )
- assert reviewed["review_status"] == "accepted"
- assert reviewed["reviewer"] == "data-steward"
- runs = db.fetchall(
- "SELECT status,trace_json FROM governance_agent_runs WHERE tenant_id=?",
- ("tenant-a",),
- )
- assert len(runs) == 1 and runs[0]["status"] == "completed"
- def test_validation_detects_untyped_published_m0_fact(db):
- project = service.create_project(db, "tenant-a", {
- "name": "Validation", "namespace": "https://example.test/validation",
- })
- fact = service.upsert_element(db, "tenant-a", project["id"], {
- "layer": "M0", "profile": "software", "kind": "PhysicalTable",
- "name": "prod.orphan", "status": "published",
- })
- result = service.validate_project(db, "tenant-a", project["id"], persist=True)
- assert result["valid"] is False
- assert any(item["code"] == "M0_UNKNOWN_TYPE" and item["target_id"] == fact["id"]
- for item in result["findings"])
|