forked from BasedHardware/omi
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathtest_screen_frames.py
More file actions
334 lines (256 loc) · 15.5 KB
/
Copy pathtest_screen_frames.py
File metadata and controls
334 lines (256 loc) · 15.5 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
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
"""Router-level tests for routers/screen_frames.py.
Follows the direct-call pattern from tests/routers/test_imports.py: call the
endpoint function directly with uid=UID and patch.object the db modules the
router imports, rather than spinning up a full FastAPI TestClient.
Covers: a digest mismatch fails the whole adjudication request with 400,
admission is refused (409) when the account's
meeting_note_screenshots_enabled setting is off, and the public shared route
returns an empty set whenever sharing isn't currently on — never a 404 (that
would leak whether a conversation_id exists).
"""
import base64
import hashlib
from datetime import datetime, timedelta, timezone
from unittest.mock import MagicMock
from uuid import uuid4
import pytest
from fastapi import HTTPException
from models.conversation_enums import ConversationStatus, ConversationVisibility
from models.screen_frame import ScreenFrameAdjudicationRequest, ScreenFrameCandidateIn, ScreenFrameSubjectIn
from routers import screen_frames as screen_frames_mod
UID = "user-1"
CONVERSATION_ID = "conv-1"
def _conversation(**overrides):
started_at = datetime(2026, 1, 1, tzinfo=timezone.utc)
base = {
"id": CONVERSATION_ID,
"status": ConversationStatus.completed.value,
"started_at": started_at,
"finished_at": started_at + timedelta(minutes=30),
"deleted": False,
"visibility": ConversationVisibility.private.value,
}
base.update(overrides)
return base
def _candidate(**overrides) -> ScreenFrameCandidateIn:
raw = b"some fake candidate bytes"
base = dict(
client_frame_id="c1",
captured_at=datetime(2026, 1, 1, 0, 5, tzinfo=timezone.utc),
mime_type="image/jpeg",
declared_width=800,
declared_height=600,
sha256_base64=base64.b64encode(hashlib.sha256(raw).digest()).decode(),
bytes_base64=base64.b64encode(raw).decode(),
)
base.update(overrides)
return ScreenFrameCandidateIn(**base)
def _request(**overrides) -> ScreenFrameAdjudicationRequest:
base = dict(
schema_version=1,
attempt_id=uuid4(),
purpose="meeting_note_v1",
subject=ScreenFrameSubjectIn(kind="conversation", id=CONVERSATION_ID),
candidates=[_candidate()],
)
base.update(overrides)
return ScreenFrameAdjudicationRequest(**base)
@pytest.fixture(autouse=True)
def _stub_admission_dependencies(monkeypatch):
# Egress is default-off in production and the gate sits above everything else in
# the handler, so without this every test here would assert against a 409 from
# the gate rather than the behaviour it means to pin. TestEgressDisabled below
# is where the off state is covered.
monkeypatch.setenv("SCREEN_FRAME_EGRESS_ENABLED", "true")
monkeypatch.setenv("BUCKET_SCREEN_FRAMES", "test-screen-frames")
monkeypatch.setenv("SCREEN_FRAME_SIGNING_SECRET", "test-secret")
fake_conversations_db = MagicMock()
fake_conversations_db.get_conversation.return_value = _conversation()
fake_conversations_db.is_soft_deleted.return_value = False
monkeypatch.setattr(screen_frames_mod, "conversations_db", fake_conversations_db)
monkeypatch.setattr(screen_frames_mod, "screen_frames_db", fake_conversations_db)
fake_users_db = MagicMock()
fake_users_db.get_meeting_note_screenshots_enabled.return_value = True
monkeypatch.setattr(screen_frames_mod, "users_db", fake_users_db)
fake_redis_db = MagicMock()
fake_redis_db.reserve_screen_frame_adjudication_attempt.return_value = None
monkeypatch.setattr(screen_frames_mod, "redis_db", fake_redis_db)
return fake_conversations_db, fake_users_db, fake_redis_db
class TestEgressDisabled:
"""The gate that makes merging this safe before the bucket exists.
The judge is the first step that sends screen bytes to Gemini and it runs two
stages before any bucket or signer check, so these assert on what did NOT
happen: no judging, and no adjudication stamp.
"""
def test_returns_409_when_flag_not_set(self, _stub_admission_dependencies, monkeypatch):
monkeypatch.delenv("SCREEN_FRAME_EGRESS_ENABLED", raising=False)
with pytest.raises(HTTPException) as exc_info:
screen_frames_mod.adjudicate_screen_frames(_request(), uid=UID)
assert exc_info.value.status_code == 409
assert exc_info.value.detail["code"] == "screen_frame_egress_unavailable"
def test_returns_409_when_flag_set_but_bucket_missing(self, _stub_admission_dependencies, monkeypatch):
monkeypatch.delenv("BUCKET_SCREEN_FRAMES", raising=False)
with pytest.raises(HTTPException) as exc_info:
screen_frames_mod.adjudicate_screen_frames(_request(), uid=UID)
assert exc_info.value.status_code == 409
def test_returns_409_when_no_signer_is_configured(self, _stub_admission_dependencies, monkeypatch):
monkeypatch.delenv("SCREEN_FRAME_SIGNING_SECRET", raising=False)
monkeypatch.delenv("SCREEN_FRAME_KMS_KEY", raising=False)
with pytest.raises(HTTPException) as exc_info:
screen_frames_mod.adjudicate_screen_frames(_request(), uid=UID)
assert exc_info.value.status_code == 409
def test_nothing_is_judged_and_nothing_is_stamped_when_disabled(self, _stub_admission_dependencies, monkeypatch):
fake_conversations_db, _fake_users_db, _fake_redis_db = _stub_admission_dependencies
monkeypatch.delenv("SCREEN_FRAME_EGRESS_ENABLED", raising=False)
judged = MagicMock()
monkeypatch.setattr(screen_frames_mod, "adjudicate_candidate", judged)
with pytest.raises(HTTPException):
screen_frames_mod.adjudicate_screen_frames(_request(), uid=UID)
judged.assert_not_called()
# A stamp here would tell the client this conversation was already decided,
# and it would never retry once the feature is switched on.
fake_conversations_db.mark_conversation_screen_frames_adjudicated.assert_not_called()
class TestDigestMismatch:
def test_digest_mismatch_returns_400_for_the_whole_request(self):
bad_candidate = _candidate(sha256_base64=base64.b64encode(hashlib.sha256(b"different bytes").digest()).decode())
request = _request(candidates=[bad_candidate])
with pytest.raises(HTTPException) as exc_info:
screen_frames_mod.adjudicate_screen_frames(request, uid=UID)
assert exc_info.value.status_code == 400
class TestAdmissionRefusedWhenSettingDisabled:
def test_returns_409_when_meeting_note_screenshots_disabled(self, _stub_admission_dependencies):
_fake_conversations_db, fake_users_db, _fake_redis_db = _stub_admission_dependencies
fake_users_db.get_meeting_note_screenshots_enabled.return_value = False
request = _request()
with pytest.raises(HTTPException) as exc_info:
screen_frames_mod.adjudicate_screen_frames(request, uid=UID)
assert exc_info.value.status_code == 409
assert exc_info.value.detail["code"] == "meeting_note_screenshots_disabled"
class TestAdmissionRefusedWhenNotCompleted:
def test_returns_409_when_conversation_not_completed(self, _stub_admission_dependencies):
fake_conversations_db, _fake_users_db, _fake_redis_db = _stub_admission_dependencies
fake_conversations_db.get_conversation.return_value = _conversation(status=ConversationStatus.in_progress.value)
request = _request()
with pytest.raises(HTTPException) as exc_info:
screen_frames_mod.adjudicate_screen_frames(request, uid=UID)
assert exc_info.value.status_code == 409
class TestUnknownConversationIs404:
def test_returns_404_when_conversation_missing(self, _stub_admission_dependencies):
fake_conversations_db, _fake_users_db, _fake_redis_db = _stub_admission_dependencies
fake_conversations_db.get_conversation.return_value = None
request = _request()
with pytest.raises(HTTPException) as exc_info:
screen_frames_mod.adjudicate_screen_frames(request, uid=UID)
assert exc_info.value.status_code == 404
class TestSettingsRoutes:
def test_get_reads_from_users_db(self, _stub_admission_dependencies):
_fake_conversations_db, fake_users_db, _fake_redis_db = _stub_admission_dependencies
fake_users_db.get_meeting_note_screenshots_enabled.return_value = False
result = screen_frames_mod.get_screen_frame_settings(uid=UID)
assert result.meeting_note_screenshots_enabled is False
def test_patch_writes_and_echoes(self, _stub_admission_dependencies):
_fake_conversations_db, fake_users_db, _fake_redis_db = _stub_admission_dependencies
from models.screen_frame import ScreenFrameSettingsUpdateRequest
result = screen_frames_mod.update_screen_frame_settings(
ScreenFrameSettingsUpdateRequest(meeting_note_screenshots_enabled=False), uid=UID
)
fake_users_db.set_meeting_note_screenshots_enabled.assert_called_once_with(UID, False)
assert result.meeting_note_screenshots_enabled is False
class TestAuthenticatedScreenshotsRoute:
def test_empty_set_when_account_setting_off(self, _stub_admission_dependencies, monkeypatch):
"""Contract §9: the account gate hides existing frames on every surface, not just
the ones that remember to check it client-side — the web GET goes through this
route and has no local gate."""
_fake_conversations_db, fake_users_db, _fake_redis_db = _stub_admission_dependencies
fake_users_db.get_meeting_note_screenshots_enabled.return_value = False
fake_enforcement = MagicMock()
monkeypatch.setattr(screen_frames_mod, "enforcement", fake_enforcement)
result = screen_frames_mod.get_conversation_screenshots(CONVERSATION_ID, uid=UID)
assert result == screen_frames_mod.EMPTY_FRAME_SET
fake_enforcement.build_frame_set_response.assert_not_called()
def test_builds_frame_set_when_account_setting_on(self, _stub_admission_dependencies, monkeypatch):
fake_enforcement = MagicMock()
sentinel = object()
fake_enforcement.build_frame_set_response.return_value = sentinel
monkeypatch.setattr(screen_frames_mod, "enforcement", fake_enforcement)
result = screen_frames_mod.get_conversation_screenshots(CONVERSATION_ID, uid=UID)
assert result is sentinel
fake_enforcement.build_frame_set_response.assert_called_once_with(UID, CONVERSATION_ID)
class TestSharedScreenshotsRoute:
def test_empty_when_conversation_id_unknown(self, monkeypatch):
fake_redis_db = MagicMock()
fake_redis_db.get_conversation_uid.return_value = ""
monkeypatch.setattr(screen_frames_mod, "redis_db", fake_redis_db)
result = screen_frames_mod.get_shared_conversation_screenshots(CONVERSATION_ID)
assert result == screen_frames_mod.EMPTY_FRAME_SET
def test_empty_when_visibility_is_private(self, monkeypatch):
fake_redis_db = MagicMock()
fake_redis_db.get_conversation_uid.return_value = UID
monkeypatch.setattr(screen_frames_mod, "redis_db", fake_redis_db)
fake_conversations_db = MagicMock()
fake_conversations_db.get_conversation.return_value = _conversation(
visibility=ConversationVisibility.private.value
)
fake_conversations_db.is_soft_deleted.return_value = False
monkeypatch.setattr(screen_frames_mod, "conversations_db", fake_conversations_db)
monkeypatch.setattr(screen_frames_mod, "screen_frames_db", fake_conversations_db)
result = screen_frames_mod.get_shared_conversation_screenshots(CONVERSATION_ID)
assert result == screen_frames_mod.EMPTY_FRAME_SET
def test_empty_when_screenshot_sharing_disabled_even_if_publicly_shared(self, monkeypatch):
fake_redis_db = MagicMock()
fake_redis_db.get_conversation_uid.return_value = UID
monkeypatch.setattr(screen_frames_mod, "redis_db", fake_redis_db)
fake_conversations_db = MagicMock()
fake_conversations_db.get_conversation.return_value = _conversation(
visibility=ConversationVisibility.public.value, screenshot_sharing_enabled=False
)
fake_conversations_db.is_soft_deleted.return_value = False
fake_conversations_db.get_conversation_screenshot_sharing_enabled.return_value = False
monkeypatch.setattr(screen_frames_mod, "conversations_db", fake_conversations_db)
monkeypatch.setattr(screen_frames_mod, "screen_frames_db", fake_conversations_db)
result = screen_frames_mod.get_shared_conversation_screenshots(CONVERSATION_ID)
assert result == screen_frames_mod.EMPTY_FRAME_SET
def test_builds_frame_set_when_public_and_sharing_enabled(self, monkeypatch):
fake_redis_db = MagicMock()
fake_redis_db.get_conversation_uid.return_value = UID
monkeypatch.setattr(screen_frames_mod, "redis_db", fake_redis_db)
fake_conversations_db = MagicMock()
fake_conversations_db.get_conversation.return_value = _conversation(
visibility=ConversationVisibility.public.value, screenshot_sharing_enabled=True
)
fake_conversations_db.is_soft_deleted.return_value = False
fake_conversations_db.get_conversation_screenshot_sharing_enabled.return_value = True
monkeypatch.setattr(screen_frames_mod, "conversations_db", fake_conversations_db)
monkeypatch.setattr(screen_frames_mod, "screen_frames_db", fake_conversations_db)
fake_users_db = MagicMock()
fake_users_db.get_meeting_note_screenshots_enabled.return_value = True
monkeypatch.setattr(screen_frames_mod, "users_db", fake_users_db)
fake_enforcement = MagicMock()
sentinel = object()
fake_enforcement.build_frame_set_response.return_value = sentinel
monkeypatch.setattr(screen_frames_mod, "enforcement", fake_enforcement)
result = screen_frames_mod.get_shared_conversation_screenshots(CONVERSATION_ID)
assert result is sentinel
# Pinned deliberately: this public route resolves the OWNER's uid from the share index,
# and serving any other uid's frames from an unauthenticated endpoint is the worst thing
# it could do. Asserting the return value alone would not catch that.
fake_enforcement.build_frame_set_response.assert_called_once_with(UID, CONVERSATION_ID)
def test_empty_when_account_setting_off_even_if_publicly_shared(self, monkeypatch):
"""Contract §9 on the public route too: the owner turning the account gate off
must hide the shared note's screenshots, not just the owner's own clients."""
fake_redis_db = MagicMock()
fake_redis_db.get_conversation_uid.return_value = UID
monkeypatch.setattr(screen_frames_mod, "redis_db", fake_redis_db)
fake_conversations_db = MagicMock()
fake_conversations_db.get_conversation.return_value = _conversation(
visibility=ConversationVisibility.public.value, screenshot_sharing_enabled=True
)
fake_conversations_db.is_soft_deleted.return_value = False
fake_conversations_db.get_conversation_screenshot_sharing_enabled.return_value = True
monkeypatch.setattr(screen_frames_mod, "conversations_db", fake_conversations_db)
monkeypatch.setattr(screen_frames_mod, "screen_frames_db", fake_conversations_db)
fake_users_db = MagicMock()
fake_users_db.get_meeting_note_screenshots_enabled.return_value = False
monkeypatch.setattr(screen_frames_mod, "users_db", fake_users_db)
result = screen_frames_mod.get_shared_conversation_screenshots(CONVERSATION_ID)
assert result == screen_frames_mod.EMPTY_FRAME_SET