| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154 |
- from __future__ import annotations
- from datetime import UTC, datetime
- from uuid import uuid4
- import pytest
- def _source(**overrides):
- from app.core.data_research.sources import IngestionSourceRecord
- values = {
- "uid": str(uuid4()),
- "source_type": "database",
- "name": "设备源",
- "config": {"database_type": "postgresql"},
- "permission_scope": {"departments": ["equipment"]},
- "status": "active",
- "created_by": "admin-1",
- "created_at": datetime(2026, 7, 29, tzinfo=UTC),
- "updated_at": datetime(2026, 7, 29, tzinfo=UTC),
- }
- values.update(overrides)
- return IngestionSourceRecord(**values)
- class Repository:
- def __init__(self, records=()):
- self.records = {record.uid: record for record in records}
- self.saved = []
- def get(self, uid):
- return self.records.get(uid)
- def save(self, record):
- self.records[record.uid] = record
- self.saved.append(record)
- return record
- def list_device_sources(self):
- return tuple(self.records.values())
- def test_device_source_scope_is_sorted_unique_and_preserves_other_keys():
- from app.core.knowledge.device_scope import DeviceSourceScopeService
- source = _source()
- repository = Repository((source,))
- service = DeviceSourceScopeService(
- repository,
- clock=lambda: datetime(2026, 7, 30, tzinfo=UTC),
- )
- domain_a = str(uuid4())
- domain_b = str(uuid4())
- updated = service.update(
- source.uid,
- {"business_domains": [domain_b, domain_a, domain_b]},
- actor_is_admin=True,
- )
- assert updated.permission_scope == {
- "departments": ["equipment"],
- "business_domains": sorted([domain_a, domain_b]),
- }
- assert repository.saved == [updated]
- assert updated.updated_at == datetime(2026, 7, 30, tzinfo=UTC)
- def test_device_source_scope_rejects_invalid_uuid_and_more_than_100_domains():
- from app.core.knowledge.device_scope import (
- DeviceSourceScopeInvalid,
- DeviceSourceScopeService,
- )
- source = _source()
- service = DeviceSourceScopeService(Repository((source,)))
- with pytest.raises(DeviceSourceScopeInvalid, match="UUID"):
- service.update(
- source.uid,
- {"business_domains": ["not-a-uuid"]},
- actor_is_admin=True,
- )
- with pytest.raises(DeviceSourceScopeInvalid, match="100"):
- service.update(
- source.uid,
- {"business_domains": [str(uuid4()) for _ in range(101)]},
- actor_is_admin=True,
- )
- def test_device_source_scope_missing_source_and_payload_are_rejected():
- from app.core.knowledge.device_scope import (
- DeviceSourceScopeInvalid,
- DeviceSourceScopeNotFound,
- DeviceSourceScopeService,
- )
- service = DeviceSourceScopeService(Repository())
- with pytest.raises(DeviceSourceScopeNotFound):
- service.update(
- str(uuid4()),
- {"business_domains": []},
- actor_is_admin=True,
- )
- with pytest.raises(DeviceSourceScopeInvalid, match="business_domains"):
- service.update(
- str(uuid4()),
- {},
- actor_is_admin=True,
- )
- def test_empty_scope_is_explicitly_admin_only_and_updates_require_admin():
- from app.core.knowledge.device_scope import (
- DeviceSourceScopeForbidden,
- DeviceSourceScopeService,
- source_scope_access,
- )
- source = _source(permission_scope={"business_domains": []})
- service = DeviceSourceScopeService(Repository((source,)))
- assert source_scope_access(source.permission_scope) == {
- "business_domains": (),
- "admin_only": True,
- }
- with pytest.raises(DeviceSourceScopeForbidden):
- service.update(
- source.uid,
- {"business_domains": [str(uuid4())]},
- actor_is_admin=False,
- )
- def test_list_exposes_scope_metadata_but_never_source_configuration():
- from app.core.knowledge.device_scope import DeviceSourceScopeService
- source = _source(
- config={"password": "must-not-leak"},
- permission_scope={"business_domains": [str(uuid4())]},
- )
- service = DeviceSourceScopeService(Repository((source,)))
- records = service.list()
- assert records[0]["uid"] == source.uid
- assert records[0]["business_domains"] == tuple(
- source.permission_scope["business_domains"]
- )
- assert "config" not in records[0]
- assert "permission_scope" not in records[0]
|