Fix Zotero table models for Zotero 9:
- Remove stale Annotations/Highlights/Transaction* models
- Add ItemAnnotations, RetractedItems, DeletedCollections,
DeletedSearches, DbDebug1
- Fix ItemAttachments, Libraries, Users column mismatches
New test files covering all major modules:
- cli/{bib,prisma,rec,zot,mail,run} deep exercising tests
- mail/{droplet,postmark,resend,cloudflare} lifecycle tests
- bib/{iom,oig,pincite,sync,regulations_gov,email_ingest,format,store}
- prisma/{vpn,fetch,export,llm,screen,eligibility,extract,project,ingest,flow}
- aco/lake/{unity,quality,deploy} + api/aco coverage gaps
- zot/{ops,db,extract,duck} + rec/{report,engine,base,pricers}
- pfs/{pipe,rules,eq,files}
Add pytest-xdist for parallel test execution.
Tracks #353
186 lines
6.1 KiB
Python
186 lines
6.1 KiB
Python
"""Exercise mail.postmark — server, domain, DNS, verify."""
|
|
|
|
from __future__ import annotations
|
|
|
|
from unittest.mock import MagicMock, patch
|
|
|
|
import pytest
|
|
|
|
from mail.postmark import (
|
|
_account_headers,
|
|
_load_state,
|
|
_save_state,
|
|
ensure_postmark_domain,
|
|
ensure_postmark_server,
|
|
publish_postmark_dns,
|
|
verify_postmark_domain,
|
|
)
|
|
|
|
|
|
class TestAccountHeaders:
|
|
@patch(
|
|
"mail.postmark.env",
|
|
side_effect=lambda k: "test-token" if k == "POSTMARK_ACCOUNT_TOKEN" else "",
|
|
)
|
|
def test_with_token(self, mc):
|
|
h = _account_headers()
|
|
assert h["X-Postmark-Account-Token"] == "test-token"
|
|
|
|
@patch("mail.postmark.env", return_value="")
|
|
def test_no_token(self, mc):
|
|
with pytest.raises(RuntimeError, match="POSTMARK_API_KEY"):
|
|
_account_headers()
|
|
|
|
|
|
class TestSaveLoadState:
|
|
def test_round_trip(self, tmp_path):
|
|
state_file = tmp_path / "postmark.json"
|
|
with (
|
|
patch("mail.postmark.STATE_DIR", tmp_path),
|
|
patch("mail.postmark._STATE_FILE", state_file),
|
|
):
|
|
_save_state({"server_id": 123})
|
|
result = _load_state()
|
|
assert result["server_id"] == 123
|
|
|
|
|
|
class TestEnsurePostmarkServer:
|
|
@patch("mail.postmark.env", return_value="test-token")
|
|
@patch("mail.postmark._load_state", return_value={})
|
|
@patch("mail.postmark._save_state")
|
|
@patch("httpx.Client")
|
|
def test_creates_new(self, mc_client_cls, mc_save, mc_load, mc_env):
|
|
client = MagicMock()
|
|
client.__enter__ = MagicMock(return_value=client)
|
|
client.__exit__ = MagicMock(return_value=False)
|
|
mc_client_cls.return_value = client
|
|
|
|
# First GET: no matching servers
|
|
list_resp = MagicMock()
|
|
list_resp.json.return_value = {"Servers": []}
|
|
list_resp.raise_for_status = MagicMock()
|
|
|
|
# POST: create server
|
|
create_resp = MagicMock()
|
|
create_resp.json.return_value = {"ID": 42, "ApiTokens": ["srv-token"]}
|
|
create_resp.raise_for_status = MagicMock()
|
|
|
|
# PUT: enable SMTP
|
|
put_resp = MagicMock()
|
|
put_resp.json.return_value = {"SmtpApiActivated": True}
|
|
put_resp.raise_for_status = MagicMock()
|
|
|
|
client.get.return_value = list_resp
|
|
client.post.return_value = create_resp
|
|
client.put.return_value = put_resp
|
|
|
|
token = ensure_postmark_server("fhirworx")
|
|
assert token == "srv-token"
|
|
|
|
@patch("mail.postmark.env", return_value="test-token")
|
|
@patch(
|
|
"mail.postmark._load_state",
|
|
return_value={"server_id": 42, "server_token": "cached"},
|
|
)
|
|
@patch("mail.postmark._save_state")
|
|
@patch("httpx.Client")
|
|
def test_adopts_existing(self, mc_client_cls, mc_save, mc_load, mc_env):
|
|
client = MagicMock()
|
|
client.__enter__ = MagicMock(return_value=client)
|
|
client.__exit__ = MagicMock(return_value=False)
|
|
mc_client_cls.return_value = client
|
|
|
|
put_resp = MagicMock()
|
|
put_resp.json.return_value = {"SmtpApiActivated": True}
|
|
put_resp.raise_for_status = MagicMock()
|
|
client.put.return_value = put_resp
|
|
|
|
token = ensure_postmark_server("fhirworx")
|
|
assert token == "cached"
|
|
|
|
|
|
class TestEnsurePostmarkDomain:
|
|
@patch("mail.postmark.env", return_value="test-token")
|
|
@patch("httpx.Client")
|
|
def test_adopts_existing(self, mc_client_cls, mc_env):
|
|
client = MagicMock()
|
|
client.__enter__ = MagicMock(return_value=client)
|
|
client.__exit__ = MagicMock(return_value=False)
|
|
mc_client_cls.return_value = client
|
|
|
|
list_resp = MagicMock()
|
|
list_resp.json.return_value = {"Domains": [{"ID": 1, "Name": "fhirworx.io"}]}
|
|
list_resp.raise_for_status = MagicMock()
|
|
|
|
full_resp = MagicMock()
|
|
full_resp.json.return_value = {
|
|
"ID": 1,
|
|
"Name": "fhirworx.io",
|
|
"DKIMHost": "dk._domainkey.fhirworx.io",
|
|
}
|
|
full_resp.raise_for_status = MagicMock()
|
|
|
|
client.get.side_effect = [list_resp, full_resp]
|
|
|
|
result = ensure_postmark_domain("fhirworx.io")
|
|
assert result["Name"] == "fhirworx.io"
|
|
|
|
@patch("mail.postmark.env", return_value="test-token")
|
|
@patch("httpx.Client")
|
|
def test_creates_new(self, mc_client_cls, mc_env):
|
|
client = MagicMock()
|
|
client.__enter__ = MagicMock(return_value=client)
|
|
client.__exit__ = MagicMock(return_value=False)
|
|
mc_client_cls.return_value = client
|
|
|
|
list_resp = MagicMock()
|
|
list_resp.json.return_value = {"Domains": []}
|
|
list_resp.raise_for_status = MagicMock()
|
|
|
|
create_resp = MagicMock()
|
|
create_resp.json.return_value = {"ID": 2, "Name": "fhirworx.io"}
|
|
create_resp.raise_for_status = MagicMock()
|
|
|
|
client.get.return_value = list_resp
|
|
client.post.return_value = create_resp
|
|
|
|
result = ensure_postmark_domain("fhirworx.io")
|
|
assert result["Name"] == "fhirworx.io"
|
|
|
|
|
|
class TestPublishPostmarkDns:
|
|
@patch("mail.cloudflare._upsert_record")
|
|
@patch("mail.cloudflare._zone_id", return_value="zone123")
|
|
def test_publishes(self, mc_zone, mc_upsert):
|
|
domain_info = {
|
|
"Name": "fhirworx.io",
|
|
"DKIMHost": "dk._domainkey.fhirworx.io",
|
|
"DKIMTextValue": "v=DKIM1; p=abc",
|
|
"ReturnPathDomain": "pm-bounces.fhirworx.io",
|
|
}
|
|
cf_client = MagicMock()
|
|
publish_postmark_dns(domain_info, cf_client)
|
|
assert mc_upsert.call_count == 2
|
|
|
|
|
|
class TestVerifyPostmarkDomain:
|
|
@patch("mail.postmark.env", return_value="test-token")
|
|
@patch("httpx.Client")
|
|
def test_verifies(self, mc_client_cls, mc_env):
|
|
client = MagicMock()
|
|
client.__enter__ = MagicMock(return_value=client)
|
|
client.__exit__ = MagicMock(return_value=False)
|
|
mc_client_cls.return_value = client
|
|
|
|
put_resp = MagicMock()
|
|
put_resp.status_code = 200
|
|
client.put.return_value = put_resp
|
|
|
|
full_resp = MagicMock()
|
|
full_resp.json.return_value = {"ID": 1, "DKIMVerified": True}
|
|
full_resp.raise_for_status = MagicMock()
|
|
client.get.return_value = full_resp
|
|
|
|
result = verify_postmark_domain(1)
|
|
assert result["DKIMVerified"] is True
|