forked from BasedHardware/omi
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathtest_task_integrations.py
More file actions
200 lines (149 loc) · 6.91 KB
/
Copy pathtest_task_integrations.py
File metadata and controls
200 lines (149 loc) · 6.91 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
"""Task integration route and external-call seam coverage."""
import asyncio
import json
import httpx
def _todoist_task_payload(title="E2E task"):
return {
"title": title,
"description": "from hermetic test",
"due_date": "2026-01-02T00:00:00Z",
}
def _save_todoist_integration(client, auth_headers, **overrides):
payload = {"connected": True, "access_token": "todoist-token"}
payload.update(overrides)
response = client.put("/v1/task-integrations/todoist", json=payload, headers=auth_headers)
assert response.status_code == 200, response.text
assert response.json() == {"status": "ok", "app_key": "todoist"}
return payload
def _get_todoist_integration(client, auth_headers):
response = client.get("/v1/task-integrations", headers=auth_headers)
assert response.status_code == 200, response.text
return response.json()["integrations"].get("todoist")
def _patch_todoist_transport(monkeypatch, handler):
import utils.task_integrations_ops as task_integrations_ops
fake_client = httpx.AsyncClient(transport=httpx.MockTransport(handler))
monkeypatch.setattr(task_integrations_ops, "http_client", fake_client)
return fake_client
def _close_async_client(fake_client):
asyncio.run(fake_client.aclose())
def test_task_integration_crud_default_and_todoist_task_creation(client, auth_headers, monkeypatch):
_save_todoist_integration(client, auth_headers)
listed = client.get("/v1/task-integrations", headers=auth_headers)
assert listed.status_code == 200, listed.text
body = listed.json()
assert body["integrations"]["todoist"]["connected"] is True
assert body["default_app"] is None
default = client.put("/v1/task-integrations/default", json={"app_key": "todoist"}, headers=auth_headers)
assert default.status_code == 200, default.text
assert default.json() == {"default_app": "todoist"}
requests = []
def handler(request):
requests.append(request)
return httpx.Response(201, json={"id": "todo-123"})
fake_client = _patch_todoist_transport(monkeypatch, handler)
try:
created = client.post(
"/v1/task-integrations/todoist/tasks",
json=_todoist_task_payload(),
headers=auth_headers,
)
finally:
_close_async_client(fake_client)
assert created.status_code == 200, created.text
assert created.json() == {"success": True, "external_task_id": "todo-123", "error": None}
assert len(requests) == 1
request = requests[0]
assert str(request.url) == "https://api.todoist.com/rest/v2/tasks"
assert request.headers["authorization"] == "Bearer todoist-token"
payload = json.loads(request.content)
assert payload["content"] == "E2E task"
assert payload["description"] == "from hermetic test"
assert payload["due_string"] == "2026-01-02"
delete = client.delete("/v1/task-integrations/todoist", headers=auth_headers)
assert delete.status_code == 204, delete.text
after_delete = client.get("/v1/task-integrations", headers=auth_headers)
assert after_delete.status_code == 200, after_delete.text
assert "todoist" not in after_delete.json()["integrations"]
assert after_delete.json()["default_app"] is None
delete_missing = client.delete("/v1/task-integrations/todoist", headers=auth_headers)
assert delete_missing.status_code == 404, delete_missing.text
assert delete_missing.json()["detail"] == "Task integration not found"
def test_task_creation_returns_not_connected_for_disconnected_integration(client, auth_headers):
_save_todoist_integration(client, auth_headers, connected=False)
response = client.post(
"/v1/task-integrations/todoist/tasks",
json=_todoist_task_payload("Disconnected task"),
headers=auth_headers,
)
assert response.status_code == 404, response.text
assert response.json()["detail"] == "Not connected to todoist"
def test_task_creation_returns_no_access_token_for_connected_integration_without_token(client, auth_headers):
_save_todoist_integration(client, auth_headers, access_token=None)
response = client.post(
"/v1/task-integrations/todoist/tasks",
json=_todoist_task_payload("Tokenless task"),
headers=auth_headers,
)
assert response.status_code == 401, response.text
assert response.json()["detail"] == "No access token for todoist"
def test_todoist_provider_500_returns_failure_without_disconnect(client, auth_headers, monkeypatch):
requests = []
_save_todoist_integration(client, auth_headers)
def handler(request):
requests.append(request)
return httpx.Response(500, json={"error": "upstream unavailable"})
fake_client = _patch_todoist_transport(monkeypatch, handler)
try:
response = client.post(
"/v1/task-integrations/todoist/tasks",
json=_todoist_task_payload("Provider 500 task"),
headers=auth_headers,
)
finally:
_close_async_client(fake_client)
assert response.status_code == 200, response.text
assert response.json() == {
"success": False,
"external_task_id": None,
"error": "Todoist API error: 500",
}
assert len(requests) == 1
assert _get_todoist_integration(client, auth_headers)["connected"] is True
def test_todoist_provider_401_marks_integration_disconnected(client, auth_headers, monkeypatch):
_save_todoist_integration(client, auth_headers, access_token="expired-todoist-token")
def handler(request):
return httpx.Response(401, json={"error": "unauthorized"})
fake_client = _patch_todoist_transport(monkeypatch, handler)
try:
response = client.post(
"/v1/task-integrations/todoist/tasks",
json=_todoist_task_payload("Expired token task"),
headers=auth_headers,
)
finally:
_close_async_client(fake_client)
assert response.status_code == 200, response.text
assert response.json()["success"] is False
assert response.json()["error"] == "Todoist API error: 401"
stored = _get_todoist_integration(client, auth_headers)
assert stored["connected"] is False
assert stored["access_token"] == "expired-todoist-token"
def test_todoist_timeout_returns_failure_without_real_network(client, auth_headers, monkeypatch):
_save_todoist_integration(client, auth_headers)
def handler(request):
raise httpx.ConnectTimeout("deterministic Todoist timeout")
fake_client = _patch_todoist_transport(monkeypatch, handler)
try:
response = client.post(
"/v1/task-integrations/todoist/tasks",
json=_todoist_task_payload("Timeout task"),
headers=auth_headers,
)
finally:
_close_async_client(fake_client)
assert response.status_code == 200, response.text
assert response.json() == {
"success": False,
"external_task_id": None,
"error": "deterministic Todoist timeout",
}