from __future__ import annotations from datetime import UTC, datetime, timedelta 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_core.core.provider_governance import ExternalProviderStateContext from govoplan_core.db.base import Base from govoplan_mail.backend.db.models import ( MailBounceSource, MailDeliveryCommand, MailMailboxFolderIndex, MailMailboxMessageIndex, MailPop3Import, MailServerEndpoint, MailServerProfile, ) from govoplan_mail.backend.manifest import manifest from govoplan_mail.backend.provider_state import ( IMAP_PROVIDER_ID, POP3_PROVIDER_ID, SMTP_PROVIDER_ID, imap_provider_states, pop3_provider_states, smtp_provider_states, ) class MailProviderStateTests(unittest.TestCase): def setUp(self) -> None: self.engine = create_engine("sqlite+pysqlite:///:memory:", future=True) Base.metadata.create_all( self.engine, tables=( MailServerProfile.__table__, MailServerEndpoint.__table__, MailDeliveryCommand.__table__, MailMailboxFolderIndex.__table__, MailMailboxMessageIndex.__table__, MailBounceSource.__table__, MailPop3Import.__table__, ), ) self.session = sessionmaker(bind=self.engine, expire_on_commit=False)() self.profile = MailServerProfile( id="profile-1", tenant_id="tenant-1", scope_type="tenant", scope_id="tenant-1", name="Mail", slug="mail", is_active=True, smtp_config={"host": "smtp.example.test", "port": 587}, imap_config={"host": "imap.example.test", "port": 993}, ) self.session.add( self.profile ) self.session.add( MailMailboxFolderIndex( id="folder-1", tenant_id="tenant-1", profile_id=self.profile.id, folder="INBOX", indexed_at=datetime.now(UTC), ) ) self.session.commit() def tearDown(self) -> None: self.session.close() self.engine.dispose() def test_smtp_state_exposes_reconciliation_without_server_or_secrets(self) -> None: self.session.add( MailDeliveryCommand( id="command-1", tenant_id="tenant-1", command_type="message", source_module="notifications", source_resource_type="notification", idempotency_key="notification-1", canonical_request_hash="a" * 64, profile_id=self.profile.id, expected_smtp_transport_revision="revision-1", message_sha256="b" * 64, message_size_bytes=10, recipient_count=1, status="outcome_unknown", expires_at=datetime.now(UTC) + timedelta(days=1), ) ) self.session.flush() state = smtp_provider_states( ExternalProviderStateContext(session=self.session, tenant_id="tenant-1") )[0] self.assertEqual("warning", state.health) self.assertEqual("pending", state.conflict) self.assertEqual("attention", state.recovery) self.assertEqual(1, state.metrics["outcome_unknown_commands"]) self.assertNotIn("smtp.example.test", str(state.to_dict())) def test_imap_state_is_fresh_tenant_bounded_and_registered(self) -> None: state = imap_provider_states( ExternalProviderStateContext(session=self.session, tenant_id="tenant-1") )[0] self.assertEqual("healthy", state.health) self.assertEqual("current", state.freshness) self.assertEqual("external_mirror", state.authority_mode) self.assertNotIn("imap.example.test", str(state.to_dict())) self.assertEqual( (), imap_provider_states( ExternalProviderStateContext( session=self.session, tenant_id="tenant-2", ) ), ) self.assertEqual( {SMTP_PROVIDER_ID, IMAP_PROVIDER_ID, POP3_PROVIDER_ID}, {item.id for item in manifest.external_providers}, ) self.assertEqual( {SMTP_PROVIDER_ID, IMAP_PROVIDER_ID, POP3_PROVIDER_ID}, { item.provider_id for item in manifest.external_provider_state_providers }, ) def test_pop3_state_is_disabled_by_default_and_projects_deletion_evidence(self) -> None: endpoint = MailServerEndpoint( id="pop3-server-1", profile_id=self.profile.id, tenant_id="tenant-1", protocol="pop3", name="Legacy POP3", config={"host": "pop3.example.test", "legacy_import_enabled": False}, scope_type="tenant", scope_id="tenant-1", is_active=True, ) self.session.add(endpoint) self.session.flush() disabled = pop3_provider_states( ExternalProviderStateContext(session=self.session, tenant_id="tenant-1") )[0] self.assertFalse(disabled.active) self.assertEqual("inactive", disabled.health) endpoint.config = { "host": "pop3.example.test", "legacy_import_enabled": True, } self.session.add( MailPop3Import( id="pop3-import-1", tenant_id="tenant-1", profile_id=self.profile.id, pop3_server_id=endpoint.id, transport_revision=endpoint.transport_revision, provider_uidl="uid-1", fingerprint="a" * 64, raw_sha256="b" * 64, raw_message_encrypted="ciphertext-do-not-project", size_bytes=42, imported_at=datetime.now(UTC), deletion_requested=True, deletion_status="outcome_unknown", ) ) self.session.add( MailPop3Import( id="pop3-import-tenant-2", tenant_id="tenant-2", profile_id=self.profile.id, pop3_server_id=endpoint.id, transport_revision=endpoint.transport_revision, provider_uidl="uid-tenant-2", fingerprint="c" * 64, raw_sha256="d" * 64, raw_message_encrypted="other-tenant-ciphertext", size_bytes=42, imported_at=datetime.now(UTC), deletion_requested=True, deletion_status="failed", ) ) self.session.flush() state = pop3_provider_states( ExternalProviderStateContext(session=self.session, tenant_id="tenant-1") )[0] self.assertTrue(state.active) self.assertEqual("warning", state.health) self.assertEqual("pending", state.conflict) self.assertEqual(1, state.metrics["outcome_unknown_deletions"]) self.assertEqual(0, state.metrics["failed_deletions"]) self.assertNotIn("pop3.example.test", str(state.to_dict())) self.assertNotIn("ciphertext-do-not-project", str(state.to_dict())) if __name__ == "__main__": unittest.main()