Spaces:
Paused
Paused
| """SimpleLogin provider 单元测试 — 全 mock requests,无真实 HTTP。""" | |
| from __future__ import annotations | |
| from unittest.mock import MagicMock | |
| import pytest | |
| from autoteam.mail import simplelogin as mod | |
| from autoteam.mail.fallback import MailProviderUnavailable | |
| def _make_response(status: int, body: dict | None = None, text: str = "") -> MagicMock: | |
| r = MagicMock() | |
| r.status_code = status | |
| r.text = text or ("" if body is None else "{}") | |
| r.json = MagicMock(return_value=body if body is not None else {}) | |
| return r | |
| def _make_client(monkeypatch) -> mod.SimpleLoginClient: | |
| monkeypatch.setenv("SIMPLELOGIN_API_KEY", "key-abc") | |
| monkeypatch.setenv("SIMPLELOGIN_BASE_URL", "https://sl.example.com") | |
| monkeypatch.setenv("SIMPLELOGIN_HOSTNAME", "openai.com") | |
| client = mod.SimpleLoginClient() | |
| client.session = MagicMock() | |
| return client | |
| def test_init_missing_api_key_raises_unavailable(monkeypatch): | |
| monkeypatch.delenv("SIMPLELOGIN_API_KEY", raising=False) | |
| with pytest.raises(MailProviderUnavailable) as exc: | |
| mod.SimpleLoginClient() | |
| assert "SIMPLELOGIN_API_KEY" in str(exc.value) | |
| def test_init_uses_default_base_url_when_unset(monkeypatch): | |
| monkeypatch.setenv("SIMPLELOGIN_API_KEY", "key-abc") | |
| monkeypatch.delenv("SIMPLELOGIN_BASE_URL", raising=False) | |
| client = mod.SimpleLoginClient() | |
| assert client.base_url == mod.DEFAULT_BASE_URL | |
| def test_headers_use_simplelogin_authentication_header(monkeypatch): | |
| client = _make_client(monkeypatch) | |
| h = client._headers() | |
| assert h["Authentication"] == "key-abc" | |
| assert "Authorization" not in h | |
| assert h["Accept"] == "application/json" | |
| def test_login_calls_user_info(monkeypatch): | |
| client = _make_client(monkeypatch) | |
| client.session.request.return_value = _make_response(200, {"email": "me@example.com"}) | |
| out = client.login() | |
| assert out == "key-abc" | |
| args, _ = client.session.request.call_args | |
| assert args[0] == "GET" | |
| assert "/api/user_info" in args[1] | |
| def test_login_auth_failure_raises(monkeypatch): | |
| client = _make_client(monkeypatch) | |
| client.session.request.return_value = _make_response(401, text="bad key") | |
| with pytest.raises(Exception, match="401"): | |
| client.login() | |
| def test_create_temp_email_random_alias(monkeypatch): | |
| client = _make_client(monkeypatch) | |
| client.session.request.return_value = _make_response( | |
| 201, {"id": 42, "alias": "auto.xyz@aleeas.com"} | |
| ) | |
| aid, email = client.create_temp_email(prefix="autoteam") | |
| assert aid == 42 | |
| assert email == "auto.xyz@aleeas.com" | |
| args, kw = client.session.request.call_args | |
| assert args[0] == "POST" | |
| assert "/api/alias/random/new" in args[1] | |
| assert kw["params"] == {"hostname": "openai.com"} | |
| assert "note" in kw["json"] | |
| def test_create_temp_email_response_missing_fields_raises(monkeypatch): | |
| client = _make_client(monkeypatch) | |
| client.session.request.return_value = _make_response(201, {"id": 99}) | |
| with pytest.raises(Exception, match="缺"): | |
| client.create_temp_email() | |
| def test_list_accounts_paginates_and_stops_when_empty(monkeypatch): | |
| client = _make_client(monkeypatch) | |
| page0 = _make_response( | |
| 200, | |
| {"aliases": [ | |
| {"id": 1, "email": "a@x.com"}, | |
| {"id": 2, "email": "b@x.com"}, | |
| ]}, | |
| ) | |
| page1 = _make_response(200, {"aliases": []}) | |
| client.session.request.side_effect = [page0, page1] | |
| rows = client.list_accounts(size=100) | |
| assert len(rows) == 2 | |
| assert rows[0]["accountId"] == 1 | |
| assert rows[0]["email"] == "a@x.com" | |
| # 翻了 2 页 | |
| assert client.session.request.call_count == 2 | |
| def test_list_accounts_stops_at_target_size(monkeypatch): | |
| client = _make_client(monkeypatch) | |
| page0 = _make_response( | |
| 200, | |
| {"aliases": [ | |
| {"id": i, "email": f"x{i}@x.com"} for i in range(20) | |
| ]}, | |
| ) | |
| client.session.request.return_value = page0 | |
| rows = client.list_accounts(size=5) | |
| # 单页就够,目标 5 条命中后立即停 | |
| assert len(rows) == 5 | |
| def test_delete_account_by_id(monkeypatch): | |
| client = _make_client(monkeypatch) | |
| client.session.request.return_value = _make_response(204) | |
| res = client.delete_account(42) | |
| assert res["code"] == 200 | |
| args, _ = client.session.request.call_args | |
| assert args[0] == "DELETE" | |
| assert "/api/aliases/42" in args[1] | |
| def test_delete_account_by_email_resolves_id(monkeypatch): | |
| client = _make_client(monkeypatch) | |
| list_resp = _make_response( | |
| 200, | |
| {"aliases": [{"id": 7, "email": "match@x.com"}]}, | |
| ) | |
| page2 = _make_response(200, {"aliases": []}) | |
| del_resp = _make_response(204) | |
| client.session.request.side_effect = [list_resp, page2, del_resp] | |
| res = client.delete_account("match@x.com") | |
| assert res["code"] == 200 | |
| last_args = client.session.request.call_args_list[-1] | |
| assert "/api/aliases/7" in last_args.args[1] | |
| def test_inbox_methods_return_empty_with_warning(monkeypatch, caplog): | |
| client = _make_client(monkeypatch) | |
| with caplog.at_level("WARNING", logger="autoteam.mail.simplelogin"): | |
| assert client.search_emails_by_recipient("foo@x.com") == [] | |
| assert client.list_emails(7) == [] | |
| assert client.delete_emails_for("foo@x.com") == 0 | |
| msgs = " ".join(r.message for r in caplog.records) | |
| assert "inbox" in msgs.lower() or "alias forwarding" in msgs.lower() | |
| def test_implements_full_mail_provider_abc(monkeypatch): | |
| from autoteam.mail.base import MailProvider | |
| client = _make_client(monkeypatch) | |
| assert isinstance(client, MailProvider) | |
| for name in ( | |
| "login", | |
| "create_temp_email", | |
| "list_accounts", | |
| "delete_account", | |
| "search_emails_by_recipient", | |
| "list_emails", | |
| "delete_emails_for", | |
| ): | |
| assert callable(getattr(client, name)) | |