Files
govoplan-calendar/tests/test_provider_state.py
T

201 lines
7.2 KiB
Python

from __future__ import annotations
from datetime import UTC, datetime
import unittest
from sqlalchemy import create_engine
from sqlalchemy.orm import sessionmaker
from govoplan_access.backend.db import models as access_models # noqa: F401
from govoplan_calendar.backend.db.models import CalendarOutboxOperation, CalendarSyncSource
from govoplan_calendar.backend.manifest import (
CALDAV_PROVIDER_ID,
EWS_PROVIDER_ID,
GRAPH_PROVIDER_ID,
ICS_PROVIDER_ID,
OPEN_XCHANGE_PROVIDER_ID,
manifest,
)
from govoplan_calendar.backend.provider_state import (
caldav_provider_states,
ews_provider_states,
graph_provider_states,
ics_provider_states,
open_xchange_provider_states,
)
from govoplan_calendar.backend.schemas import (
CalendarCalDavSourceCreateRequest,
CalendarCollectionCreateRequest,
)
from govoplan_calendar.backend.service import create_caldav_source, create_calendar
from govoplan_core.core.provider_governance import ExternalProviderStateContext
from govoplan_core.db.base import Base
from govoplan_core.tenancy.scope import create_scope_tables
from govoplan_tenancy.backend.db.models import Tenant
class CalendarProviderStateTests(unittest.TestCase):
def setUp(self) -> None:
self.engine = create_engine("sqlite+pysqlite:///:memory:", future=True)
create_scope_tables(self.engine)
Base.metadata.create_all(self.engine)
self.Session = sessionmaker(bind=self.engine, expire_on_commit=False)
self.session = self.Session()
self.session.add(Tenant(id="tenant-1", slug="tenant-1", name="Tenant"))
self.calendar = create_calendar(
self.session,
tenant_id="tenant-1",
user_id=None,
payload=CalendarCollectionCreateRequest(name="Remote"),
)
self.source = create_caldav_source(
self.session,
tenant_id="tenant-1",
user_id=None,
payload=CalendarCalDavSourceCreateRequest(
calendar_id=self.calendar.id,
collection_url="https://dav.example.test/cal",
),
)
self.session.commit()
def tearDown(self) -> None:
self.session.close()
self.engine.dispose()
def test_state_projects_health_freshness_and_unresolved_outcomes(self) -> None:
self.source.last_status = "ok"
self.source.last_synced_at = datetime.now(UTC)
self.session.flush()
healthy = caldav_provider_states(
ExternalProviderStateContext(
session=self.session,
tenant_id="tenant-1",
)
)[0]
self.assertEqual("healthy", healthy.health)
self.assertEqual("current", healthy.freshness)
self.assertEqual("clear", healthy.conflict)
self.assertEqual("ready", healthy.recovery)
self.assertEqual(
f"calendar:sync-source:{self.source.id}",
healthy.binding_ref,
)
self.assertNotIn("dav.example.test", str(healthy.to_dict()))
self.session.add(
CalendarOutboxOperation(
tenant_id="tenant-1",
source_id=self.source.id,
operation_kind="put",
resource_href="event.ics",
idempotency_key="a" * 64,
status="conflict",
)
)
self.session.flush()
conflicted = caldav_provider_states(
ExternalProviderStateContext(
session=self.session,
tenant_id="tenant-1",
)
)[0]
self.assertEqual("warning", conflicted.health)
self.assertEqual("pending", conflicted.conflict)
self.assertEqual("attention", conflicted.recovery)
def test_state_is_tenant_bounded_and_manifest_registered(self) -> None:
self.assertEqual(
(),
caldav_provider_states(
ExternalProviderStateContext(
session=self.session,
tenant_id="tenant-2",
)
),
)
self.assertEqual(
{CALDAV_PROVIDER_ID, ICS_PROVIDER_ID, GRAPH_PROVIDER_ID, EWS_PROVIDER_ID, OPEN_XCHANGE_PROVIDER_ID},
{item.id for item in manifest.external_providers},
)
self.assertEqual(
{CALDAV_PROVIDER_ID, ICS_PROVIDER_ID, GRAPH_PROVIDER_ID, EWS_PROVIDER_ID, OPEN_XCHANGE_PROVIDER_ID},
{
item.provider_id
for item in manifest.external_provider_state_providers
},
)
def test_read_only_sources_have_distinct_secret_free_provider_state(self) -> None:
now = datetime.now(UTC)
sources = (
("ics", "https://feeds.example.test/team.ics", "none"),
("graph", "https://graph.microsoft.com/v1.0/me/calendar/events", "bearer"),
("ews", "https://exchange.example.test/EWS/Exchange.asmx", "basic"),
)
for source_kind, collection_url, auth_type in sources:
self.session.add(
CalendarSyncSource(
tenant_id="tenant-1",
calendar_id=self.calendar.id,
source_kind=source_kind,
collection_url=collection_url,
auth_type=auth_type,
sync_enabled=True,
sync_direction="read_only",
last_status="ok",
last_synced_at=now,
)
)
self.session.flush()
states = (
ics_provider_states(
ExternalProviderStateContext(session=self.session, tenant_id="tenant-1")
)[0],
graph_provider_states(
ExternalProviderStateContext(session=self.session, tenant_id="tenant-1")
)[0],
ews_provider_states(
ExternalProviderStateContext(session=self.session, tenant_id="tenant-1")
)[0],
)
self.assertTrue(all(item.authority_mode == "external_mirror" for item in states))
self.assertTrue(all(item.health == "healthy" for item in states))
rendered = str([item.to_dict() for item in states])
self.assertNotIn("feeds.example.test", rendered)
self.assertNotIn("exchange.example.test", rendered)
def test_open_xchange_profile_has_distinct_provider_state(self) -> None:
self.source.metadata_ = {
"integration_profile": "open_xchange",
"connector_profile_ref": "connector:secret-detail",
"identity_mapping_ref": "idm:secret-detail",
}
self.source.last_status = "ok"
self.source.last_synced_at = datetime.now(UTC)
self.session.flush()
self.assertEqual(
(),
caldav_provider_states(
ExternalProviderStateContext(session=self.session, tenant_id="tenant-1")
),
)
state = open_xchange_provider_states(
ExternalProviderStateContext(session=self.session, tenant_id="tenant-1")
)[0]
self.assertEqual(OPEN_XCHANGE_PROVIDER_ID, state.provider_id)
self.assertEqual("healthy", state.health)
self.assertNotIn("secret-detail", str(state.to_dict()))
if __name__ == "__main__":
unittest.main()