Files
liqiang b119135836
Build latest book artifacts / build (push) Canceled after 0s
dependency resolution / resolve (3.11) (push) Canceled after 0s
dependency resolution / resolve (3.13) (push) Canceled after 0s
deploy-pages / build (push) Canceled after 0s
deploy-pages / deploy (push) Canceled after 0s
i18n consistency check / check (push) Canceled after 0s
provider adoption tests / test (chapter2/context-compression) (push) Canceled after 0s
provider adoption tests / test (chapter2/prompt-injection) (push) Canceled after 0s
provider adoption tests / test (chapter2/system-hint) (push) Canceled after 0s
provider adoption tests / test (chapter3/log-sanitization) (push) Canceled after 0s
web-search-agent tests / test (push) Canceled after 0s
web-search-agent tests / agentbook (push) Canceled after 0s
ai-agent-book 精选快照(<2MB 代码与文档,来自 github.com/bojieli/ai-agent-book)
2026-08-20 13:12:50 +00:00

139 lines
6.4 KiB
Python

"""Offline contract tests; these are not substitutes for the live campaign receipt."""
from __future__ import annotations
import importlib.util
import json
import sys
from datetime import datetime, timezone
from pathlib import Path
import httpx
import pytest
HERE = Path(__file__).resolve().parent
MODULE_PATH = HERE / "unipile_mailbox_experiment.py"
SPEC = importlib.util.spec_from_file_location("experiment_6_1_unipile", MODULE_PATH)
experiment = importlib.util.module_from_spec(SPEC)
assert SPEC.loader is not None
sys.modules[SPEC.name] = experiment
SPEC.loader.exec_module(experiment)
def _email(kind: str, date: str, suffix: str) -> dict:
base = {"id": f"email-{suffix}", "account_id": "account-real",
"date": date, "role": "inbox", "folders": ["Inbox"]}
if kind == "meeting_invitation":
return {**base, "subject": "Meeting invitation: design review",
"body_plain": "START_UTC: 2026-08-03T10:00:00.000Z\n"
"END_UTC: 2026-08-03T11:00:00.000Z"}
if kind == "customer_complaint":
return {**base, "subject": "Customer complaint: delayed order",
"body_plain": "Customer complaint for order #E44-TEST. Please escalate."}
return {**base, "subject": "Marketing newsletter",
"body_plain": "Marketing newsletter promotion. Click to unsubscribe."}
def _provider(request: httpx.Request) -> httpx.Response:
assert request.headers.get("X-API-KEY") == "unit-secret"
if request.method == "GET" and request.url.path == "/api/v1/calendars":
return httpx.Response(200, json={"data": [{"id": "calendar-real",
"is_primary": True}]})
if request.method == "GET" and request.url.path.endswith("/events"):
return httpx.Response(200, json={"data": []})
if request.method == "GET" and request.url.path == "/api/v1/folders":
return httpx.Response(200, json={"items": [{"id": "folder-archive",
"name": "Archive",
"role": "archive"}]})
if request.method == "PUT" and request.url.path == "/api/v1/emails/email-marketing":
assert json.loads(request.content) == {"folders": ["archive"]}
return httpx.Response(200, json={"object": "EmailUpdated"})
if request.method == "GET" and request.url.path == "/api/v1/emails/email-marketing":
return httpx.Response(200, json={"id": "email-marketing",
"role": "archive", "folders": ["Archive"]})
return httpx.Response(404, json={"type": "unexpected_test_request"})
def test_classification_is_unique_and_meeting_interval_is_exact():
email = _email("meeting_invitation", "2026-08-01T00:00:01.000Z", "meeting")
assert experiment.classify_email(email) == "meeting_invitation"
start, end = experiment.meeting_interval(email)
assert start.isoformat() == "2026-08-03T10:00:00+00:00"
assert (end - start).total_seconds() == 3600
ambiguous = {**email, "subject": "Meeting invitation and marketing newsletter",
"body_plain": email["body_plain"] + "\nMarketing unsubscribe"}
with pytest.raises(ValueError, match="not unique"):
experiment.classify_email(ambiguous)
def test_real_api_error_is_receipted_and_raises():
def unauthorized(_: httpx.Request) -> httpx.Response:
return httpx.Response(401, json={"status": 401,
"type": "errors/missing_credentials",
"title": "Missing credentials"})
client = experiment.UnipileClient(
"api.example.invalid:12345", "unit-secret",
transport=httpx.MockTransport(unauthorized),
)
with pytest.raises(experiment.UnipileAPIError):
client.list_accounts()
assert client.calls == [{
**client.calls[0], "status": 401, "success": False,
"credential_scheme": "X-API-KEY",
"error_type": "errors/missing_credentials",
}]
assert "unit-secret" not in experiment.canonical_json(client.calls)
client.close()
def test_three_email_workflow_and_acceptance(tmp_path):
client = experiment.UnipileClient(
"api.example.invalid:12345", "unit-secret",
transport=httpx.MockTransport(_provider),
)
runner = experiment.MailboxExperiment(
client, tmp_path, "account-real", "account-real"
)
# Deliberately unordered input proves that the FIFO queue uses provider time.
emails = [
_email("marketing", "2026-08-01T00:00:03.000Z", "marketing"),
_email("meeting_invitation", "2026-08-01T00:00:01.000Z", "meeting"),
_email("customer_complaint", "2026-08-01T00:00:02.000Z", "complaint"),
]
runner.process_queue(emails)
assert [row["classification"] for row in runner.workflows] == [
"meeting_invitation", "customer_complaint", "marketing"
]
result = experiment.derive_acceptance(
runner.events, runner.workflows, client.calls,
[{"object": "EmailSent"}] * 3,
credential_secret="unit-secret", dsn_secret="api.example.invalid:12345",
)
assert result["status"] == "passed"
assert all(result["gates"].values())
assert (tmp_path / "artifacts" / "meeting_reply_draft.txt").stat().st_size > 100
assert (tmp_path / "artifacts" / "high_priority_notifications.jsonl").is_file()
assert "unit-secret" not in experiment.canonical_json(client.calls)
client.close()
def test_acceptance_fails_when_provider_archive_verification_is_missing(tmp_path):
client = experiment.UnipileClient(
"api.example.invalid:12345", "unit-secret",
transport=httpx.MockTransport(_provider),
)
runner = experiment.MailboxExperiment(client, tmp_path, "account-real", "account-real")
runner.process_queue([
_email("meeting_invitation", "2026-08-01T00:00:01.000Z", "meeting"),
_email("customer_complaint", "2026-08-01T00:00:02.000Z", "complaint"),
_email("marketing", "2026-08-01T00:00:03.000Z", "marketing"),
])
runner.workflows[-1]["archive"]["verified"] = False
result = experiment.derive_acceptance(
runner.events, runner.workflows, client.calls, [{}, {}, {}],
credential_secret="unit-secret", dsn_secret="api.example.invalid:12345",
)
assert result["status"] == "failed"
assert not result["gates"]["marketing_archived_and_verified_through_provider"]
client.close()