| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215 |
- from __future__ import annotations
- import os
- import uuid
- import pytest
- from sqlalchemy import create_engine, text
- pytestmark = pytest.mark.integration
- def test_device_quality_responsibility_type_is_allowed_by_postgres():
- platform_url = os.environ.get("TEST_DATABASE_URL")
- if not platform_url:
- pytest.skip("TEST_DATABASE_URL is required")
- engine = create_engine(platform_url)
- try:
- with engine.connect() as connection:
- definition = connection.execute(
- text(
- """
- SELECT pg_get_constraintdef(oid)
- FROM pg_constraint
- WHERE conname =
- 'governance_responsibility_scopes_resource_type_check'
- """
- )
- ).scalar_one()
- assert "device_quality" in definition
- finally:
- engine.dispose()
- def test_device_quality_postgres_keeps_version_run_and_source_evidence(
- monkeypatch,
- ):
- platform_url = os.environ.get("TEST_DATABASE_URL")
- if not platform_url:
- pytest.skip("TEST_DATABASE_URL is required")
- monkeypatch.setenv("DATABASE_URL", platform_url)
- from app import create_app, db
- from app.core.data_research.device_quality import DeviceQualityService
- from app.core.data_research.device_quality_repository import (
- SqlAlchemyDeviceQualityRepository,
- )
- from app.models.data_research import (
- DeviceAsset,
- DeviceAssetSourceMapping,
- DeviceQualityAssetScore,
- DeviceQualityProfile,
- DeviceQualityProfileVersion,
- DeviceQualityRuleResult,
- DeviceQualityRun,
- DeviceQualityViolationSample,
- IngestionSource,
- )
- app = create_app()
- app.config.update(TESTING=True)
- source_uid = str(uuid.uuid4())
- asset_uid = str(uuid.uuid4())
- mapping_uid = str(uuid.uuid4())
- profile_uids = []
- run_uids = []
- try:
- with app.app_context():
- db.session.add(
- IngestionSource(
- uid=source_uid,
- source_type="database",
- name="WP07 PostgreSQL 质量验收源",
- config={
- "database_type": "postgresql",
- "database": "acceptance",
- "schema": "asset",
- },
- permission_scope={},
- status="active",
- created_by="integration-test",
- )
- )
- db.session.add(
- DeviceAsset(
- uid=asset_uid,
- asset_type="device",
- name="WP07 验收设备",
- status="active",
- current_version=1,
- content_hash="a" * 64,
- location="动力车间",
- organization="设备动力部",
- responsible_person="张工",
- attributes={"model": "P-100"},
- created_by="integration-test",
- updated_by="integration-test",
- )
- )
- db.session.flush()
- db.session.add(
- DeviceAssetSourceMapping(
- uid=mapping_uid,
- asset_uid=asset_uid,
- source_uid=source_uid,
- source_entity="asset.equipment",
- asset_type="device",
- source_code="EQ-WP07-001",
- )
- )
- db.session.commit()
- repository = SqlAlchemyDeviceQualityRepository(db.session)
- quality = DeviceQualityService(
- repository,
- publish_authorizer=lambda _actor: None,
- commit=db.session.commit,
- rollback=db.session.rollback,
- )
- had_profile = repository.latest_version() is not None
- draft = quality.bootstrap(actor_uid="integration-test")
- if not had_profile:
- profile_uids.append(draft.profile_uid)
- published = (
- quality.publish(
- draft.uid,
- actor_uid="integration-test",
- )
- if draft.status == "draft"
- else draft
- )
- run = quality.run(
- actor_uid="integration-test",
- source_uid=source_uid,
- )
- run_uids.append(run.uid)
- second_run = quality.run(
- actor_uid="integration-test",
- source_uid=source_uid,
- )
- run_uids.append(second_run.uid)
- loaded, results = quality.get_run(run.uid)
- violations, violation_total = quality.violations(
- run.uid,
- rule_code=None,
- page=1,
- page_size=100,
- )
- scores, score_total = quality.asset_scores(
- run.uid,
- page=1,
- page_size=100,
- )
- recent_runs, run_total = quality.runs(
- page=1,
- page_size=100,
- )
- assert published.status == "published"
- assert loaded.policy_version_uid == published.uid
- assert loaded.policy_hash == published.content_hash
- assert loaded.total_assets == 1
- assert loaded.score == 100
- assert len(results) == 7
- assert violation_total == 0
- assert violations == []
- assert score_total == 1
- assert scores[0].asset_uid == asset_uid
- assert scores[0].score == 100
- assert run_total >= 2
- assert {run.uid, second_run.uid} <= {
- item.uid for item in recent_runs
- }
- snapshots, total = repository.load_assets(
- source_uid=source_uid,
- limit=5_001,
- )
- assert total == 1
- assert snapshots[0].uid == asset_uid
- assert snapshots[0].current_version == 1
- assert snapshots[0].mappings[0].uid == mapping_uid
- finally:
- with app.app_context():
- if run_uids:
- db.session.query(DeviceQualityViolationSample).filter(
- DeviceQualityViolationSample.run_uid.in_(run_uids)
- ).delete(synchronize_session=False)
- db.session.query(DeviceQualityAssetScore).filter(
- DeviceQualityAssetScore.run_uid.in_(run_uids)
- ).delete(synchronize_session=False)
- db.session.query(DeviceQualityRuleResult).filter(
- DeviceQualityRuleResult.run_uid.in_(run_uids)
- ).delete(synchronize_session=False)
- db.session.query(DeviceQualityRun).filter(
- DeviceQualityRun.uid.in_(run_uids)
- ).delete(synchronize_session=False)
- if profile_uids:
- db.session.query(DeviceQualityProfileVersion).filter(
- DeviceQualityProfileVersion.profile_uid.in_(profile_uids)
- ).delete(synchronize_session=False)
- db.session.query(DeviceQualityProfile).filter(
- DeviceQualityProfile.uid.in_(profile_uids)
- ).delete(synchronize_session=False)
- db.session.query(DeviceAssetSourceMapping).filter_by(
- uid=mapping_uid
- ).delete(synchronize_session=False)
- db.session.query(DeviceAsset).filter_by(
- uid=asset_uid
- ).delete(synchronize_session=False)
- db.session.query(IngestionSource).filter_by(
- uid=source_uid
- ).delete(synchronize_session=False)
- db.session.commit()
|