fix tests to use mock auth

This commit is contained in:
Josh Hawkins 2025-11-26 10:13:38 -06:00
parent 1819044553
commit 07d158aac2
7 changed files with 233 additions and 134 deletions

View File

@ -62,12 +62,15 @@ def create_fastapi_app(
stats_emitter: StatsEmitter, stats_emitter: StatsEmitter,
event_metadata_updater: EventMetadataPublisher, event_metadata_updater: EventMetadataPublisher,
config_publisher: CameraConfigUpdatePublisher, config_publisher: CameraConfigUpdatePublisher,
enforce_default_admin: bool = True,
): ):
logger.info("Starting FastAPI app") logger.info("Starting FastAPI app")
app = FastAPI( app = FastAPI(
debug=False, debug=False,
swagger_ui_parameters={"apisSorter": "alpha", "operationsSorter": "alpha"}, swagger_ui_parameters={"apisSorter": "alpha", "operationsSorter": "alpha"},
dependencies=[Depends(require_admin_by_default())], dependencies=[Depends(require_admin_by_default())]
if enforce_default_admin
else [],
) )
# update the request_address with the x-forwarded-for header from nginx # update the request_address with the x-forwarded-for header from nginx

View File

@ -3,6 +3,8 @@ import logging
import os import os
import unittest import unittest
from fastapi import Request
from fastapi.testclient import TestClient
from peewee_migrate import Router from peewee_migrate import Router
from playhouse.sqlite_ext import SqliteExtDatabase from playhouse.sqlite_ext import SqliteExtDatabase
from playhouse.sqliteq import SqliteQueueDatabase from playhouse.sqliteq import SqliteQueueDatabase
@ -16,6 +18,20 @@ from frigate.review.types import SeverityEnum
from frigate.test.const import TEST_DB, TEST_DB_CLEANUPS from frigate.test.const import TEST_DB, TEST_DB_CLEANUPS
class AuthTestClient(TestClient):
"""TestClient that automatically adds auth headers to all requests."""
def request(self, *args, **kwargs):
# Add default auth headers if not already present
headers = kwargs.get("headers") or {}
if "remote-user" not in headers:
headers["remote-user"] = "admin"
if "remote-role" not in headers:
headers["remote-role"] = "admin"
kwargs["headers"] = headers
return super().request(*args, **kwargs)
class BaseTestHttp(unittest.TestCase): class BaseTestHttp(unittest.TestCase):
def setUp(self, models): def setUp(self, models):
# setup clean database for each test run # setup clean database for each test run
@ -113,7 +129,9 @@ class BaseTestHttp(unittest.TestCase):
pass pass
def create_app(self, stats=None, event_metadata_publisher=None): def create_app(self, stats=None, event_metadata_publisher=None):
return create_fastapi_app( from frigate.api.auth import get_allowed_cameras_for_filter, get_current_user
app = create_fastapi_app(
FrigateConfig(**self.minimal_config), FrigateConfig(**self.minimal_config),
self.db, self.db,
None, None,
@ -123,8 +141,33 @@ class BaseTestHttp(unittest.TestCase):
stats, stats,
event_metadata_publisher, event_metadata_publisher,
None, None,
enforce_default_admin=False,
) )
# Default test mocks for authentication
# Tests can override these in their setUp if needed
# This mock uses headers set by AuthTestClient
async def mock_get_current_user(request: Request):
username = request.headers.get("remote-user")
role = request.headers.get("remote-role")
if not username or not role:
from fastapi.responses import JSONResponse
return JSONResponse(
content={"message": "No authorization headers."}, status_code=401
)
return {"username": username, "role": role}
async def mock_get_allowed_cameras_for_filter(request: Request):
return list(self.minimal_config.get("cameras", {}).keys())
app.dependency_overrides[get_current_user] = mock_get_current_user
app.dependency_overrides[get_allowed_cameras_for_filter] = (
mock_get_allowed_cameras_for_filter
)
return app
def insert_mock_event( def insert_mock_event(
self, self,
id: str, id: str,

View File

@ -1,10 +1,8 @@
from unittest.mock import Mock from unittest.mock import Mock
from fastapi.testclient import TestClient
from frigate.models import Event, Recordings, ReviewSegment from frigate.models import Event, Recordings, ReviewSegment
from frigate.stats.emitter import StatsEmitter from frigate.stats.emitter import StatsEmitter
from frigate.test.http_api.base_http_test import BaseTestHttp from frigate.test.http_api.base_http_test import AuthTestClient, BaseTestHttp
class TestHttpApp(BaseTestHttp): class TestHttpApp(BaseTestHttp):
@ -20,7 +18,7 @@ class TestHttpApp(BaseTestHttp):
stats.get_latest_stats.return_value = self.test_stats stats.get_latest_stats.return_value = self.test_stats
app = super().create_app(stats) app = super().create_app(stats)
with TestClient(app) as client: with AuthTestClient(app) as client:
response = client.get("/stats") response = client.get("/stats")
response_json = response.json() response_json = response.json()
assert response_json == self.test_stats assert response_json == self.test_stats

View File

@ -1,14 +1,13 @@
from unittest.mock import patch from unittest.mock import patch
from fastapi import HTTPException, Request from fastapi import HTTPException, Request
from fastapi.testclient import TestClient
from frigate.api.auth import ( from frigate.api.auth import (
get_allowed_cameras_for_filter, get_allowed_cameras_for_filter,
get_current_user, get_current_user,
) )
from frigate.models import Event, Recordings, ReviewSegment from frigate.models import Event, Recordings, ReviewSegment
from frigate.test.http_api.base_http_test import BaseTestHttp from frigate.test.http_api.base_http_test import AuthTestClient, BaseTestHttp
class TestCameraAccessEventReview(BaseTestHttp): class TestCameraAccessEventReview(BaseTestHttp):
@ -16,9 +15,17 @@ class TestCameraAccessEventReview(BaseTestHttp):
super().setUp([Event, ReviewSegment, Recordings]) super().setUp([Event, ReviewSegment, Recordings])
self.app = super().create_app() self.app = super().create_app()
# Mock get_current_user to return valid user for all tests # Mock get_current_user for all tests
async def mock_get_current_user(): async def mock_get_current_user(request: Request):
return {"username": "test_user", "role": "user"} username = request.headers.get("remote-user")
role = request.headers.get("remote-role")
if not username or not role:
from fastapi.responses import JSONResponse
return JSONResponse(
content={"message": "No authorization headers."}, status_code=401
)
return {"username": username, "role": role}
self.app.dependency_overrides[get_current_user] = mock_get_current_user self.app.dependency_overrides[get_current_user] = mock_get_current_user
@ -30,21 +37,25 @@ class TestCameraAccessEventReview(BaseTestHttp):
super().insert_mock_event("event1", camera="front_door") super().insert_mock_event("event1", camera="front_door")
super().insert_mock_event("event2", camera="back_door") super().insert_mock_event("event2", camera="back_door")
self.app.dependency_overrides[get_allowed_cameras_for_filter] = lambda: [ async def mock_cameras(request: Request):
"front_door" return ["front_door"]
]
with TestClient(self.app) as client: self.app.dependency_overrides[get_allowed_cameras_for_filter] = mock_cameras
with AuthTestClient(self.app) as client:
resp = client.get("/events") resp = client.get("/events")
assert resp.status_code == 200 assert resp.status_code == 200
ids = [e["id"] for e in resp.json()] ids = [e["id"] for e in resp.json()]
assert "event1" in ids assert "event1" in ids
assert "event2" not in ids assert "event2" not in ids
self.app.dependency_overrides[get_allowed_cameras_for_filter] = lambda: [ async def mock_cameras(request: Request):
"front_door", return [
"back_door", "front_door",
] "back_door",
with TestClient(self.app) as client: ]
self.app.dependency_overrides[get_allowed_cameras_for_filter] = mock_cameras
with AuthTestClient(self.app) as client:
resp = client.get("/events") resp = client.get("/events")
assert resp.status_code == 200 assert resp.status_code == 200
ids = [e["id"] for e in resp.json()] ids = [e["id"] for e in resp.json()]
@ -54,21 +65,25 @@ class TestCameraAccessEventReview(BaseTestHttp):
super().insert_mock_review_segment("rev1", camera="front_door") super().insert_mock_review_segment("rev1", camera="front_door")
super().insert_mock_review_segment("rev2", camera="back_door") super().insert_mock_review_segment("rev2", camera="back_door")
self.app.dependency_overrides[get_allowed_cameras_for_filter] = lambda: [ async def mock_cameras(request: Request):
"front_door" return ["front_door"]
]
with TestClient(self.app) as client: self.app.dependency_overrides[get_allowed_cameras_for_filter] = mock_cameras
with AuthTestClient(self.app) as client:
resp = client.get("/review") resp = client.get("/review")
assert resp.status_code == 200 assert resp.status_code == 200
ids = [r["id"] for r in resp.json()] ids = [r["id"] for r in resp.json()]
assert "rev1" in ids assert "rev1" in ids
assert "rev2" not in ids assert "rev2" not in ids
self.app.dependency_overrides[get_allowed_cameras_for_filter] = lambda: [ async def mock_cameras(request: Request):
"front_door", return [
"back_door", "front_door",
] "back_door",
with TestClient(self.app) as client: ]
self.app.dependency_overrides[get_allowed_cameras_for_filter] = mock_cameras
with AuthTestClient(self.app) as client:
resp = client.get("/review") resp = client.get("/review")
assert resp.status_code == 200 assert resp.status_code == 200
ids = [r["id"] for r in resp.json()] ids = [r["id"] for r in resp.json()]
@ -84,7 +99,7 @@ class TestCameraAccessEventReview(BaseTestHttp):
raise HTTPException(status_code=403, detail="Access denied") raise HTTPException(status_code=403, detail="Access denied")
with patch("frigate.api.event.require_camera_access", mock_require_allowed): with patch("frigate.api.event.require_camera_access", mock_require_allowed):
with TestClient(self.app) as client: with AuthTestClient(self.app) as client:
resp = client.get("/events/event1") resp = client.get("/events/event1")
assert resp.status_code == 200 assert resp.status_code == 200
assert resp.json()["id"] == "event1" assert resp.json()["id"] == "event1"
@ -94,7 +109,7 @@ class TestCameraAccessEventReview(BaseTestHttp):
raise HTTPException(status_code=403, detail="Access denied") raise HTTPException(status_code=403, detail="Access denied")
with patch("frigate.api.event.require_camera_access", mock_require_disallowed): with patch("frigate.api.event.require_camera_access", mock_require_disallowed):
with TestClient(self.app) as client: with AuthTestClient(self.app) as client:
resp = client.get("/events/event1") resp = client.get("/events/event1")
assert resp.status_code == 403 assert resp.status_code == 403
@ -108,7 +123,7 @@ class TestCameraAccessEventReview(BaseTestHttp):
raise HTTPException(status_code=403, detail="Access denied") raise HTTPException(status_code=403, detail="Access denied")
with patch("frigate.api.review.require_camera_access", mock_require_allowed): with patch("frigate.api.review.require_camera_access", mock_require_allowed):
with TestClient(self.app) as client: with AuthTestClient(self.app) as client:
resp = client.get("/review/rev1") resp = client.get("/review/rev1")
assert resp.status_code == 200 assert resp.status_code == 200
assert resp.json()["id"] == "rev1" assert resp.json()["id"] == "rev1"
@ -118,7 +133,7 @@ class TestCameraAccessEventReview(BaseTestHttp):
raise HTTPException(status_code=403, detail="Access denied") raise HTTPException(status_code=403, detail="Access denied")
with patch("frigate.api.review.require_camera_access", mock_require_disallowed): with patch("frigate.api.review.require_camera_access", mock_require_disallowed):
with TestClient(self.app) as client: with AuthTestClient(self.app) as client:
resp = client.get("/review/rev1") resp = client.get("/review/rev1")
assert resp.status_code == 403 assert resp.status_code == 403
@ -126,21 +141,25 @@ class TestCameraAccessEventReview(BaseTestHttp):
super().insert_mock_event("event1", camera="front_door") super().insert_mock_event("event1", camera="front_door")
super().insert_mock_event("event2", camera="back_door") super().insert_mock_event("event2", camera="back_door")
self.app.dependency_overrides[get_allowed_cameras_for_filter] = lambda: [ async def mock_cameras(request: Request):
"front_door" return ["front_door"]
]
with TestClient(self.app) as client: self.app.dependency_overrides[get_allowed_cameras_for_filter] = mock_cameras
with AuthTestClient(self.app) as client:
resp = client.get("/events", params={"cameras": "all"}) resp = client.get("/events", params={"cameras": "all"})
assert resp.status_code == 200 assert resp.status_code == 200
ids = [e["id"] for e in resp.json()] ids = [e["id"] for e in resp.json()]
assert "event1" in ids assert "event1" in ids
assert "event2" not in ids assert "event2" not in ids
self.app.dependency_overrides[get_allowed_cameras_for_filter] = lambda: [ async def mock_cameras(request: Request):
"front_door", return [
"back_door", "front_door",
] "back_door",
with TestClient(self.app) as client: ]
self.app.dependency_overrides[get_allowed_cameras_for_filter] = mock_cameras
with AuthTestClient(self.app) as client:
resp = client.get("/events", params={"cameras": "all"}) resp = client.get("/events", params={"cameras": "all"})
assert resp.status_code == 200 assert resp.status_code == 200
ids = [e["id"] for e in resp.json()] ids = [e["id"] for e in resp.json()]
@ -150,20 +169,24 @@ class TestCameraAccessEventReview(BaseTestHttp):
super().insert_mock_event("event1", camera="front_door") super().insert_mock_event("event1", camera="front_door")
super().insert_mock_event("event2", camera="back_door") super().insert_mock_event("event2", camera="back_door")
self.app.dependency_overrides[get_allowed_cameras_for_filter] = lambda: [ async def mock_cameras(request: Request):
"front_door" return ["front_door"]
]
with TestClient(self.app) as client: self.app.dependency_overrides[get_allowed_cameras_for_filter] = mock_cameras
with AuthTestClient(self.app) as client:
resp = client.get("/events/summary") resp = client.get("/events/summary")
assert resp.status_code == 200 assert resp.status_code == 200
summary_list = resp.json() summary_list = resp.json()
assert len(summary_list) == 1 assert len(summary_list) == 1
self.app.dependency_overrides[get_allowed_cameras_for_filter] = lambda: [ async def mock_cameras(request: Request):
"front_door", return [
"back_door", "front_door",
] "back_door",
with TestClient(self.app) as client: ]
self.app.dependency_overrides[get_allowed_cameras_for_filter] = mock_cameras
with AuthTestClient(self.app) as client:
resp = client.get("/events/summary") resp = client.get("/events/summary")
summary_list = resp.json() summary_list = resp.json()
assert len(summary_list) == 2 assert len(summary_list) == 2

View File

@ -2,14 +2,13 @@ from datetime import datetime
from typing import Any from typing import Any
from unittest.mock import Mock from unittest.mock import Mock
from fastapi.testclient import TestClient
from playhouse.shortcuts import model_to_dict from playhouse.shortcuts import model_to_dict
from frigate.api.auth import get_allowed_cameras_for_filter, get_current_user from frigate.api.auth import get_allowed_cameras_for_filter, get_current_user
from frigate.comms.event_metadata_updater import EventMetadataPublisher from frigate.comms.event_metadata_updater import EventMetadataPublisher
from frigate.models import Event, Recordings, ReviewSegment, Timeline from frigate.models import Event, Recordings, ReviewSegment, Timeline
from frigate.stats.emitter import StatsEmitter from frigate.stats.emitter import StatsEmitter
from frigate.test.http_api.base_http_test import BaseTestHttp from frigate.test.http_api.base_http_test import AuthTestClient, BaseTestHttp, Request
from frigate.test.test_storage import _insert_mock_event from frigate.test.test_storage import _insert_mock_event
@ -18,14 +17,26 @@ class TestHttpApp(BaseTestHttp):
super().setUp([Event, Recordings, ReviewSegment, Timeline]) super().setUp([Event, Recordings, ReviewSegment, Timeline])
self.app = super().create_app() self.app = super().create_app()
# Mock auth to bypass camera access for tests # Mock get_current_user for all tests
async def mock_get_current_user(request: Any): async def mock_get_current_user(request: Request):
return {"username": "test_user", "role": "admin"} username = request.headers.get("remote-user")
role = request.headers.get("remote-role")
if not username or not role:
from fastapi.responses import JSONResponse
return JSONResponse(
content={"message": "No authorization headers."}, status_code=401
)
return {"username": username, "role": role}
self.app.dependency_overrides[get_current_user] = mock_get_current_user self.app.dependency_overrides[get_current_user] = mock_get_current_user
self.app.dependency_overrides[get_allowed_cameras_for_filter] = lambda: [
"front_door" async def mock_get_allowed_cameras_for_filter(request: Request):
] return ["front_door"]
self.app.dependency_overrides[get_allowed_cameras_for_filter] = (
mock_get_allowed_cameras_for_filter
)
def tearDown(self): def tearDown(self):
self.app.dependency_overrides.clear() self.app.dependency_overrides.clear()
@ -35,20 +46,20 @@ class TestHttpApp(BaseTestHttp):
################################### GET /events Endpoint ######################################################### ################################### GET /events Endpoint #########################################################
#################################################################################################################### ####################################################################################################################
def test_get_event_list_no_events(self): def test_get_event_list_no_events(self):
with TestClient(self.app) as client: with AuthTestClient(self.app) as client:
events = client.get("/events").json() events = client.get("/events").json()
assert len(events) == 0 assert len(events) == 0
def test_get_event_list_no_match_event_id(self): def test_get_event_list_no_match_event_id(self):
id = "123456.random" id = "123456.random"
with TestClient(self.app) as client: with AuthTestClient(self.app) as client:
super().insert_mock_event(id) super().insert_mock_event(id)
events = client.get("/events", params={"event_id": "abc"}).json() events = client.get("/events", params={"event_id": "abc"}).json()
assert len(events) == 0 assert len(events) == 0
def test_get_event_list_match_event_id(self): def test_get_event_list_match_event_id(self):
id = "123456.random" id = "123456.random"
with TestClient(self.app) as client: with AuthTestClient(self.app) as client:
super().insert_mock_event(id) super().insert_mock_event(id)
events = client.get("/events", params={"event_id": id}).json() events = client.get("/events", params={"event_id": id}).json()
assert len(events) == 1 assert len(events) == 1
@ -58,7 +69,7 @@ class TestHttpApp(BaseTestHttp):
now = int(datetime.now().timestamp()) now = int(datetime.now().timestamp())
id = "123456.random" id = "123456.random"
with TestClient(self.app) as client: with AuthTestClient(self.app) as client:
super().insert_mock_event(id, now, now + 1) super().insert_mock_event(id, now, now + 1)
events = client.get( events = client.get(
"/events", params={"max_length": 1, "min_length": 1} "/events", params={"max_length": 1, "min_length": 1}
@ -69,7 +80,7 @@ class TestHttpApp(BaseTestHttp):
def test_get_event_list_no_match_max_length(self): def test_get_event_list_no_match_max_length(self):
now = int(datetime.now().timestamp()) now = int(datetime.now().timestamp())
with TestClient(self.app) as client: with AuthTestClient(self.app) as client:
id = "123456.random" id = "123456.random"
super().insert_mock_event(id, now, now + 2) super().insert_mock_event(id, now, now + 2)
events = client.get("/events", params={"max_length": 1}).json() events = client.get("/events", params={"max_length": 1}).json()
@ -78,7 +89,7 @@ class TestHttpApp(BaseTestHttp):
def test_get_event_list_no_match_min_length(self): def test_get_event_list_no_match_min_length(self):
now = int(datetime.now().timestamp()) now = int(datetime.now().timestamp())
with TestClient(self.app) as client: with AuthTestClient(self.app) as client:
id = "123456.random" id = "123456.random"
super().insert_mock_event(id, now, now + 2) super().insert_mock_event(id, now, now + 2)
events = client.get("/events", params={"min_length": 3}).json() events = client.get("/events", params={"min_length": 3}).json()
@ -88,7 +99,7 @@ class TestHttpApp(BaseTestHttp):
id = "123456.random" id = "123456.random"
id2 = "54321.random" id2 = "54321.random"
with TestClient(self.app) as client: with AuthTestClient(self.app) as client:
super().insert_mock_event(id) super().insert_mock_event(id)
events = client.get("/events").json() events = client.get("/events").json()
assert len(events) == 1 assert len(events) == 1
@ -108,14 +119,14 @@ class TestHttpApp(BaseTestHttp):
def test_get_event_list_no_match_has_clip(self): def test_get_event_list_no_match_has_clip(self):
now = int(datetime.now().timestamp()) now = int(datetime.now().timestamp())
with TestClient(self.app) as client: with AuthTestClient(self.app) as client:
id = "123456.random" id = "123456.random"
super().insert_mock_event(id, now, now + 2) super().insert_mock_event(id, now, now + 2)
events = client.get("/events", params={"has_clip": 0}).json() events = client.get("/events", params={"has_clip": 0}).json()
assert len(events) == 0 assert len(events) == 0
def test_get_event_list_has_clip(self): def test_get_event_list_has_clip(self):
with TestClient(self.app) as client: with AuthTestClient(self.app) as client:
id = "123456.random" id = "123456.random"
super().insert_mock_event(id, has_clip=True) super().insert_mock_event(id, has_clip=True)
events = client.get("/events", params={"has_clip": 1}).json() events = client.get("/events", params={"has_clip": 1}).json()
@ -123,7 +134,7 @@ class TestHttpApp(BaseTestHttp):
assert events[0]["id"] == id assert events[0]["id"] == id
def test_get_event_list_sort_score(self): def test_get_event_list_sort_score(self):
with TestClient(self.app) as client: with AuthTestClient(self.app) as client:
id = "123456.random" id = "123456.random"
id2 = "54321.random" id2 = "54321.random"
super().insert_mock_event(id, top_score=37, score=37, data={"score": 50}) super().insert_mock_event(id, top_score=37, score=37, data={"score": 50})
@ -141,7 +152,7 @@ class TestHttpApp(BaseTestHttp):
def test_get_event_list_sort_start_time(self): def test_get_event_list_sort_start_time(self):
now = int(datetime.now().timestamp()) now = int(datetime.now().timestamp())
with TestClient(self.app) as client: with AuthTestClient(self.app) as client:
id = "123456.random" id = "123456.random"
id2 = "54321.random" id2 = "54321.random"
super().insert_mock_event(id, start_time=now + 3) super().insert_mock_event(id, start_time=now + 3)
@ -159,7 +170,7 @@ class TestHttpApp(BaseTestHttp):
def test_get_good_event(self): def test_get_good_event(self):
id = "123456.random" id = "123456.random"
with TestClient(self.app) as client: with AuthTestClient(self.app) as client:
super().insert_mock_event(id) super().insert_mock_event(id)
event = client.get(f"/events/{id}").json() event = client.get(f"/events/{id}").json()
@ -171,7 +182,7 @@ class TestHttpApp(BaseTestHttp):
id = "123456.random" id = "123456.random"
bad_id = "654321.other" bad_id = "654321.other"
with TestClient(self.app) as client: with AuthTestClient(self.app) as client:
super().insert_mock_event(id) super().insert_mock_event(id)
event_response = client.get(f"/events/{bad_id}") event_response = client.get(f"/events/{bad_id}")
assert event_response.status_code == 404 assert event_response.status_code == 404
@ -180,7 +191,7 @@ class TestHttpApp(BaseTestHttp):
def test_delete_event(self): def test_delete_event(self):
id = "123456.random" id = "123456.random"
with TestClient(self.app) as client: with AuthTestClient(self.app) as client:
super().insert_mock_event(id) super().insert_mock_event(id)
event = client.get(f"/events/{id}").json() event = client.get(f"/events/{id}").json()
assert event assert event
@ -193,7 +204,7 @@ class TestHttpApp(BaseTestHttp):
def test_event_retention(self): def test_event_retention(self):
id = "123456.random" id = "123456.random"
with TestClient(self.app) as client: with AuthTestClient(self.app) as client:
super().insert_mock_event(id) super().insert_mock_event(id)
client.post(f"/events/{id}/retain", headers={"remote-role": "admin"}) client.post(f"/events/{id}/retain", headers={"remote-role": "admin"})
event = client.get(f"/events/{id}").json() event = client.get(f"/events/{id}").json()
@ -212,12 +223,11 @@ class TestHttpApp(BaseTestHttp):
morning = 1656590400 # 06/30/2022 6 am (GMT) morning = 1656590400 # 06/30/2022 6 am (GMT)
evening = 1656633600 # 06/30/2022 6 pm (GMT) evening = 1656633600 # 06/30/2022 6 pm (GMT)
with TestClient(self.app) as client: with AuthTestClient(self.app) as client:
super().insert_mock_event(morning_id, morning) super().insert_mock_event(morning_id, morning)
super().insert_mock_event(evening_id, evening) super().insert_mock_event(evening_id, evening)
# both events come back # both events come back
events = client.get("/events").json() events = client.get("/events").json()
print("events!!!", events)
assert events assert events
assert len(events) == 2 assert len(events) == 2
# morning event is excluded # morning event is excluded
@ -248,7 +258,7 @@ class TestHttpApp(BaseTestHttp):
mock_event_updater.publish.side_effect = update_event mock_event_updater.publish.side_effect = update_event
with TestClient(app) as client: with AuthTestClient(app) as client:
super().insert_mock_event(id) super().insert_mock_event(id)
new_sub_label_response = client.post( new_sub_label_response = client.post(
f"/events/{id}/sub_label", f"/events/{id}/sub_label",
@ -285,7 +295,7 @@ class TestHttpApp(BaseTestHttp):
mock_event_updater.publish.side_effect = update_event mock_event_updater.publish.side_effect = update_event
with TestClient(app) as client: with AuthTestClient(app) as client:
super().insert_mock_event(id) super().insert_mock_event(id)
client.post( client.post(
f"/events/{id}/sub_label", f"/events/{id}/sub_label",
@ -301,7 +311,7 @@ class TestHttpApp(BaseTestHttp):
#################################################################################################################### ####################################################################################################################
def test_get_metrics(self): def test_get_metrics(self):
"""ensure correct prometheus metrics api response""" """ensure correct prometheus metrics api response"""
with TestClient(self.app) as client: with AuthTestClient(self.app) as client:
ts_start = datetime.now().timestamp() ts_start = datetime.now().timestamp()
ts_end = ts_start + 30 ts_end = ts_start + 30
_insert_mock_event( _insert_mock_event(

View File

@ -1,14 +1,13 @@
"""Unit tests for recordings/media API endpoints.""" """Unit tests for recordings/media API endpoints."""
from datetime import datetime, timezone from datetime import datetime, timezone
from typing import Any
import pytz import pytz
from fastapi.testclient import TestClient from fastapi import Request
from frigate.api.auth import get_allowed_cameras_for_filter, get_current_user from frigate.api.auth import get_allowed_cameras_for_filter, get_current_user
from frigate.models import Recordings from frigate.models import Recordings
from frigate.test.http_api.base_http_test import BaseTestHttp from frigate.test.http_api.base_http_test import AuthTestClient, BaseTestHttp
class TestHttpMedia(BaseTestHttp): class TestHttpMedia(BaseTestHttp):
@ -19,15 +18,26 @@ class TestHttpMedia(BaseTestHttp):
super().setUp([Recordings]) super().setUp([Recordings])
self.app = super().create_app() self.app = super().create_app()
# Mock auth to bypass camera access for tests # Mock get_current_user for all tests
async def mock_get_current_user(request: Any): async def mock_get_current_user(request: Request):
return {"username": "test_user", "role": "admin"} username = request.headers.get("remote-user")
role = request.headers.get("remote-role")
if not username or not role:
from fastapi.responses import JSONResponse
return JSONResponse(
content={"message": "No authorization headers."}, status_code=401
)
return {"username": username, "role": role}
self.app.dependency_overrides[get_current_user] = mock_get_current_user self.app.dependency_overrides[get_current_user] = mock_get_current_user
self.app.dependency_overrides[get_allowed_cameras_for_filter] = lambda: [
"front_door", async def mock_get_allowed_cameras_for_filter(request: Request):
"back_door", return ["front_door"]
]
self.app.dependency_overrides[get_allowed_cameras_for_filter] = (
mock_get_allowed_cameras_for_filter
)
def tearDown(self): def tearDown(self):
"""Clean up after tests.""" """Clean up after tests."""
@ -52,7 +62,7 @@ class TestHttpMedia(BaseTestHttp):
# March 11, 2024 at 12:00 PM EDT (after DST) # March 11, 2024 at 12:00 PM EDT (after DST)
march_11_noon = tz.localize(datetime(2024, 3, 11, 12, 0, 0)).timestamp() march_11_noon = tz.localize(datetime(2024, 3, 11, 12, 0, 0)).timestamp()
with TestClient(self.app) as client: with AuthTestClient(self.app) as client:
# Insert recordings for each day # Insert recordings for each day
Recordings.insert( Recordings.insert(
id="recording_march_9", id="recording_march_9",
@ -128,7 +138,7 @@ class TestHttpMedia(BaseTestHttp):
# November 4, 2024 at 12:00 PM EST (after DST) # November 4, 2024 at 12:00 PM EST (after DST)
nov_4_noon = tz.localize(datetime(2024, 11, 4, 12, 0, 0)).timestamp() nov_4_noon = tz.localize(datetime(2024, 11, 4, 12, 0, 0)).timestamp()
with TestClient(self.app) as client: with AuthTestClient(self.app) as client:
# Insert recordings for each day # Insert recordings for each day
Recordings.insert( Recordings.insert(
id="recording_nov_2", id="recording_nov_2",
@ -195,7 +205,7 @@ class TestHttpMedia(BaseTestHttp):
# March 10, 2024 at 3:00 PM EDT (after DST transition) # March 10, 2024 at 3:00 PM EDT (after DST transition)
march_10_afternoon = tz.localize(datetime(2024, 3, 10, 15, 0, 0)).timestamp() march_10_afternoon = tz.localize(datetime(2024, 3, 10, 15, 0, 0)).timestamp()
with TestClient(self.app) as client: with AuthTestClient(self.app) as client:
# Insert recordings for front_door on March 9 # Insert recordings for front_door on March 9
Recordings.insert( Recordings.insert(
id="front_march_9", id="front_march_9",
@ -250,7 +260,7 @@ class TestHttpMedia(BaseTestHttp):
# This is 1.5 hours of actual time but spans the "missing" hour # This is 1.5 hours of actual time but spans the "missing" hour
after_transition = tz.localize(datetime(2024, 3, 10, 3, 30, 0)).timestamp() after_transition = tz.localize(datetime(2024, 3, 10, 3, 30, 0)).timestamp()
with TestClient(self.app) as client: with AuthTestClient(self.app) as client:
Recordings.insert( Recordings.insert(
id="recording_during_transition", id="recording_during_transition",
path="/media/recordings/transition.mp4", path="/media/recordings/transition.mp4",
@ -283,7 +293,7 @@ class TestHttpMedia(BaseTestHttp):
march_9_utc = datetime(2024, 3, 9, 17, 0, 0, tzinfo=timezone.utc).timestamp() march_9_utc = datetime(2024, 3, 9, 17, 0, 0, tzinfo=timezone.utc).timestamp()
march_10_utc = datetime(2024, 3, 10, 17, 0, 0, tzinfo=timezone.utc).timestamp() march_10_utc = datetime(2024, 3, 10, 17, 0, 0, tzinfo=timezone.utc).timestamp()
with TestClient(self.app) as client: with AuthTestClient(self.app) as client:
Recordings.insert( Recordings.insert(
id="recording_march_9_utc", id="recording_march_9_utc",
path="/media/recordings/march_9_utc.mp4", path="/media/recordings/march_9_utc.mp4",
@ -325,7 +335,7 @@ class TestHttpMedia(BaseTestHttp):
""" """
Test recordings summary when no recordings exist. Test recordings summary when no recordings exist.
""" """
with TestClient(self.app) as client: with AuthTestClient(self.app) as client:
response = client.get( response = client.get(
"/recordings/summary", "/recordings/summary",
params={"timezone": "America/New_York", "cameras": "all"}, params={"timezone": "America/New_York", "cameras": "all"},
@ -342,7 +352,7 @@ class TestHttpMedia(BaseTestHttp):
tz = pytz.timezone("America/New_York") tz = pytz.timezone("America/New_York")
march_10_noon = tz.localize(datetime(2024, 3, 10, 12, 0, 0)).timestamp() march_10_noon = tz.localize(datetime(2024, 3, 10, 12, 0, 0)).timestamp()
with TestClient(self.app) as client: with AuthTestClient(self.app) as client:
# Insert recordings for both cameras # Insert recordings for both cameras
Recordings.insert( Recordings.insert(
id="front_recording", id="front_recording",

View File

@ -1,12 +1,12 @@
from datetime import datetime, timedelta from datetime import datetime, timedelta
from fastapi.testclient import TestClient from fastapi import Request
from peewee import DoesNotExist from peewee import DoesNotExist
from frigate.api.auth import get_allowed_cameras_for_filter, get_current_user from frigate.api.auth import get_allowed_cameras_for_filter, get_current_user
from frigate.models import Event, Recordings, ReviewSegment, UserReviewStatus from frigate.models import Event, Recordings, ReviewSegment, UserReviewStatus
from frigate.review.types import SeverityEnum from frigate.review.types import SeverityEnum
from frigate.test.http_api.base_http_test import BaseTestHttp from frigate.test.http_api.base_http_test import AuthTestClient, BaseTestHttp
class TestHttpReview(BaseTestHttp): class TestHttpReview(BaseTestHttp):
@ -16,14 +16,26 @@ class TestHttpReview(BaseTestHttp):
self.user_id = "admin" self.user_id = "admin"
# Mock get_current_user for all tests # Mock get_current_user for all tests
async def mock_get_current_user(): # This mock uses headers set by AuthTestClient
return {"username": self.user_id, "role": "admin"} async def mock_get_current_user(request: Request):
username = request.headers.get("remote-user")
role = request.headers.get("remote-role")
if not username or not role:
from fastapi.responses import JSONResponse
return JSONResponse(
content={"message": "No authorization headers."}, status_code=401
)
return {"username": username, "role": role}
self.app.dependency_overrides[get_current_user] = mock_get_current_user self.app.dependency_overrides[get_current_user] = mock_get_current_user
self.app.dependency_overrides[get_allowed_cameras_for_filter] = lambda: [ async def mock_get_allowed_cameras_for_filter(request: Request):
"front_door" return ["front_door"]
]
self.app.dependency_overrides[get_allowed_cameras_for_filter] = (
mock_get_allowed_cameras_for_filter
)
def tearDown(self): def tearDown(self):
self.app.dependency_overrides.clear() self.app.dependency_overrides.clear()
@ -57,7 +69,7 @@ class TestHttpReview(BaseTestHttp):
but ends after is included in the results.""" but ends after is included in the results."""
now = datetime.now().timestamp() now = datetime.now().timestamp()
with TestClient(self.app) as client: with AuthTestClient(self.app) as client:
super().insert_mock_review_segment("123456.random", now, now + 2) super().insert_mock_review_segment("123456.random", now, now + 2)
response = client.get("/review") response = client.get("/review")
assert response.status_code == 200 assert response.status_code == 200
@ -67,7 +79,7 @@ class TestHttpReview(BaseTestHttp):
def test_get_review_no_filters(self): def test_get_review_no_filters(self):
now = datetime.now().timestamp() now = datetime.now().timestamp()
with TestClient(self.app) as client: with AuthTestClient(self.app) as client:
id = "123456.random" id = "123456.random"
super().insert_mock_review_segment(id, now - 2, now - 1) super().insert_mock_review_segment(id, now - 2, now - 1)
response = client.get("/review") response = client.get("/review")
@ -81,7 +93,7 @@ class TestHttpReview(BaseTestHttp):
"""Test that review items outside the range are not returned.""" """Test that review items outside the range are not returned."""
now = datetime.now().timestamp() now = datetime.now().timestamp()
with TestClient(self.app) as client: with AuthTestClient(self.app) as client:
id = "123456.random" id = "123456.random"
super().insert_mock_review_segment(id, now - 2, now - 1) super().insert_mock_review_segment(id, now - 2, now - 1)
super().insert_mock_review_segment(f"{id}2", now + 4, now + 5) super().insert_mock_review_segment(f"{id}2", now + 4, now + 5)
@ -97,7 +109,7 @@ class TestHttpReview(BaseTestHttp):
def test_get_review_with_time_filter(self): def test_get_review_with_time_filter(self):
now = datetime.now().timestamp() now = datetime.now().timestamp()
with TestClient(self.app) as client: with AuthTestClient(self.app) as client:
id = "123456.random" id = "123456.random"
super().insert_mock_review_segment(id, now, now + 2) super().insert_mock_review_segment(id, now, now + 2)
params = { params = {
@ -113,7 +125,7 @@ class TestHttpReview(BaseTestHttp):
def test_get_review_with_limit_filter(self): def test_get_review_with_limit_filter(self):
now = datetime.now().timestamp() now = datetime.now().timestamp()
with TestClient(self.app) as client: with AuthTestClient(self.app) as client:
id = "123456.random" id = "123456.random"
id2 = "654321.random" id2 = "654321.random"
super().insert_mock_review_segment(id, now, now + 2) super().insert_mock_review_segment(id, now, now + 2)
@ -132,7 +144,7 @@ class TestHttpReview(BaseTestHttp):
def test_get_review_with_severity_filters_no_matches(self): def test_get_review_with_severity_filters_no_matches(self):
now = datetime.now().timestamp() now = datetime.now().timestamp()
with TestClient(self.app) as client: with AuthTestClient(self.app) as client:
id = "123456.random" id = "123456.random"
super().insert_mock_review_segment(id, now, now + 2, SeverityEnum.detection) super().insert_mock_review_segment(id, now, now + 2, SeverityEnum.detection)
params = { params = {
@ -149,7 +161,7 @@ class TestHttpReview(BaseTestHttp):
def test_get_review_with_severity_filters(self): def test_get_review_with_severity_filters(self):
now = datetime.now().timestamp() now = datetime.now().timestamp()
with TestClient(self.app) as client: with AuthTestClient(self.app) as client:
id = "123456.random" id = "123456.random"
super().insert_mock_review_segment(id, now, now + 2, SeverityEnum.detection) super().insert_mock_review_segment(id, now, now + 2, SeverityEnum.detection)
params = { params = {
@ -165,7 +177,7 @@ class TestHttpReview(BaseTestHttp):
def test_get_review_with_all_filters(self): def test_get_review_with_all_filters(self):
now = datetime.now().timestamp() now = datetime.now().timestamp()
with TestClient(self.app) as client: with AuthTestClient(self.app) as client:
id = "123456.random" id = "123456.random"
super().insert_mock_review_segment(id, now, now + 2) super().insert_mock_review_segment(id, now, now + 2)
params = { params = {
@ -188,7 +200,7 @@ class TestHttpReview(BaseTestHttp):
################################### GET /review/summary Endpoint ################################################# ################################### GET /review/summary Endpoint #################################################
#################################################################################################################### ####################################################################################################################
def test_get_review_summary_all_filters(self): def test_get_review_summary_all_filters(self):
with TestClient(self.app) as client: with AuthTestClient(self.app) as client:
super().insert_mock_review_segment("123456.random") super().insert_mock_review_segment("123456.random")
params = { params = {
"cameras": "front_door", "cameras": "front_door",
@ -219,7 +231,7 @@ class TestHttpReview(BaseTestHttp):
self.assertEqual(response_json, expected_response) self.assertEqual(response_json, expected_response)
def test_get_review_summary_no_filters(self): def test_get_review_summary_no_filters(self):
with TestClient(self.app) as client: with AuthTestClient(self.app) as client:
super().insert_mock_review_segment("123456.random") super().insert_mock_review_segment("123456.random")
response = client.get("/review/summary") response = client.get("/review/summary")
assert response.status_code == 200 assert response.status_code == 200
@ -247,7 +259,7 @@ class TestHttpReview(BaseTestHttp):
now = datetime.now() now = datetime.now()
five_days_ago = datetime.today() - timedelta(days=5) five_days_ago = datetime.today() - timedelta(days=5)
with TestClient(self.app) as client: with AuthTestClient(self.app) as client:
super().insert_mock_review_segment( super().insert_mock_review_segment(
"123456.random", now.timestamp() - 2, now.timestamp() - 1 "123456.random", now.timestamp() - 2, now.timestamp() - 1
) )
@ -291,7 +303,7 @@ class TestHttpReview(BaseTestHttp):
now = datetime.now() now = datetime.now()
five_days_ago = datetime.today() - timedelta(days=5) five_days_ago = datetime.today() - timedelta(days=5)
with TestClient(self.app) as client: with AuthTestClient(self.app) as client:
super().insert_mock_review_segment("123456.random", now.timestamp()) super().insert_mock_review_segment("123456.random", now.timestamp())
five_days_ago_ts = five_days_ago.timestamp() five_days_ago_ts = five_days_ago.timestamp()
for i in range(20): for i in range(20):
@ -342,7 +354,7 @@ class TestHttpReview(BaseTestHttp):
def test_get_review_summary_multiple_in_same_day_with_reviewed(self): def test_get_review_summary_multiple_in_same_day_with_reviewed(self):
five_days_ago = datetime.today() - timedelta(days=5) five_days_ago = datetime.today() - timedelta(days=5)
with TestClient(self.app) as client: with AuthTestClient(self.app) as client:
five_days_ago_ts = five_days_ago.timestamp() five_days_ago_ts = five_days_ago.timestamp()
for i in range(10): for i in range(10):
id = f"123456_{i}.random_alert_not_reviewed" id = f"123456_{i}.random_alert_not_reviewed"
@ -393,14 +405,14 @@ class TestHttpReview(BaseTestHttp):
#################################################################################################################### ####################################################################################################################
def test_post_reviews_viewed_no_body(self): def test_post_reviews_viewed_no_body(self):
with TestClient(self.app) as client: with AuthTestClient(self.app) as client:
super().insert_mock_review_segment("123456.random") super().insert_mock_review_segment("123456.random")
response = client.post("/reviews/viewed") response = client.post("/reviews/viewed")
# Missing ids # Missing ids
assert response.status_code == 422 assert response.status_code == 422
def test_post_reviews_viewed_no_body_ids(self): def test_post_reviews_viewed_no_body_ids(self):
with TestClient(self.app) as client: with AuthTestClient(self.app) as client:
super().insert_mock_review_segment("123456.random") super().insert_mock_review_segment("123456.random")
body = {"ids": [""]} body = {"ids": [""]}
response = client.post("/reviews/viewed", json=body) response = client.post("/reviews/viewed", json=body)
@ -408,7 +420,7 @@ class TestHttpReview(BaseTestHttp):
assert response.status_code == 422 assert response.status_code == 422
def test_post_reviews_viewed_non_existent_id(self): def test_post_reviews_viewed_non_existent_id(self):
with TestClient(self.app) as client: with AuthTestClient(self.app) as client:
id = "123456.random" id = "123456.random"
super().insert_mock_review_segment(id) super().insert_mock_review_segment(id)
body = {"ids": ["1"]} body = {"ids": ["1"]}
@ -425,7 +437,7 @@ class TestHttpReview(BaseTestHttp):
) )
def test_post_reviews_viewed(self): def test_post_reviews_viewed(self):
with TestClient(self.app) as client: with AuthTestClient(self.app) as client:
id = "123456.random" id = "123456.random"
super().insert_mock_review_segment(id) super().insert_mock_review_segment(id)
body = {"ids": [id]} body = {"ids": [id]}
@ -445,14 +457,14 @@ class TestHttpReview(BaseTestHttp):
################################### POST reviews/delete Endpoint ################################################ ################################### POST reviews/delete Endpoint ################################################
#################################################################################################################### ####################################################################################################################
def test_post_reviews_delete_no_body(self): def test_post_reviews_delete_no_body(self):
with TestClient(self.app) as client: with AuthTestClient(self.app) as client:
super().insert_mock_review_segment("123456.random") super().insert_mock_review_segment("123456.random")
response = client.post("/reviews/delete", headers={"remote-role": "admin"}) response = client.post("/reviews/delete", headers={"remote-role": "admin"})
# Missing ids # Missing ids
assert response.status_code == 422 assert response.status_code == 422
def test_post_reviews_delete_no_body_ids(self): def test_post_reviews_delete_no_body_ids(self):
with TestClient(self.app) as client: with AuthTestClient(self.app) as client:
super().insert_mock_review_segment("123456.random") super().insert_mock_review_segment("123456.random")
body = {"ids": [""]} body = {"ids": [""]}
response = client.post( response = client.post(
@ -462,7 +474,7 @@ class TestHttpReview(BaseTestHttp):
assert response.status_code == 422 assert response.status_code == 422
def test_post_reviews_delete_non_existent_id(self): def test_post_reviews_delete_non_existent_id(self):
with TestClient(self.app) as client: with AuthTestClient(self.app) as client:
id = "123456.random" id = "123456.random"
super().insert_mock_review_segment(id) super().insert_mock_review_segment(id)
body = {"ids": ["1"]} body = {"ids": ["1"]}
@ -479,7 +491,7 @@ class TestHttpReview(BaseTestHttp):
assert review_ids_in_db_after[0].id == id assert review_ids_in_db_after[0].id == id
def test_post_reviews_delete(self): def test_post_reviews_delete(self):
with TestClient(self.app) as client: with AuthTestClient(self.app) as client:
id = "123456.random" id = "123456.random"
super().insert_mock_review_segment(id) super().insert_mock_review_segment(id)
body = {"ids": [id]} body = {"ids": [id]}
@ -495,7 +507,7 @@ class TestHttpReview(BaseTestHttp):
assert len(review_ids_in_db_after) == 0 assert len(review_ids_in_db_after) == 0
def test_post_reviews_delete_many(self): def test_post_reviews_delete_many(self):
with TestClient(self.app) as client: with AuthTestClient(self.app) as client:
ids = ["123456.random", "654321.random"] ids = ["123456.random", "654321.random"]
for id in ids: for id in ids:
super().insert_mock_review_segment(id) super().insert_mock_review_segment(id)
@ -527,7 +539,7 @@ class TestHttpReview(BaseTestHttp):
def test_review_activity_motion_no_data_for_time_range(self): def test_review_activity_motion_no_data_for_time_range(self):
now = datetime.now().timestamp() now = datetime.now().timestamp()
with TestClient(self.app) as client: with AuthTestClient(self.app) as client:
params = { params = {
"after": now, "after": now,
"before": now + 3, "before": now + 3,
@ -540,7 +552,7 @@ class TestHttpReview(BaseTestHttp):
def test_review_activity_motion(self): def test_review_activity_motion(self):
now = int(datetime.now().timestamp()) now = int(datetime.now().timestamp())
with TestClient(self.app) as client: with AuthTestClient(self.app) as client:
one_m = int((datetime.now() + timedelta(minutes=1)).timestamp()) one_m = int((datetime.now() + timedelta(minutes=1)).timestamp())
id = "123456.random" id = "123456.random"
id2 = "123451.random" id2 = "123451.random"
@ -573,7 +585,7 @@ class TestHttpReview(BaseTestHttp):
################################### GET /review/event/{event_id} Endpoint ####################################### ################################### GET /review/event/{event_id} Endpoint #######################################
#################################################################################################################### ####################################################################################################################
def test_review_event_not_found(self): def test_review_event_not_found(self):
with TestClient(self.app) as client: with AuthTestClient(self.app) as client:
response = client.get("/review/event/123456.random") response = client.get("/review/event/123456.random")
assert response.status_code == 404 assert response.status_code == 404
response_json = response.json() response_json = response.json()
@ -585,7 +597,7 @@ class TestHttpReview(BaseTestHttp):
def test_review_event_not_found_in_data(self): def test_review_event_not_found_in_data(self):
now = datetime.now().timestamp() now = datetime.now().timestamp()
with TestClient(self.app) as client: with AuthTestClient(self.app) as client:
id = "123456.random" id = "123456.random"
super().insert_mock_review_segment(id, now + 1, now + 2) super().insert_mock_review_segment(id, now + 1, now + 2)
response = client.get(f"/review/event/{id}") response = client.get(f"/review/event/{id}")
@ -599,7 +611,7 @@ class TestHttpReview(BaseTestHttp):
def test_review_get_specific_event(self): def test_review_get_specific_event(self):
now = datetime.now().timestamp() now = datetime.now().timestamp()
with TestClient(self.app) as client: with AuthTestClient(self.app) as client:
event_id = "123456.event.random" event_id = "123456.event.random"
super().insert_mock_event(event_id) super().insert_mock_event(event_id)
review_id = "123456.review.random" review_id = "123456.review.random"
@ -626,7 +638,7 @@ class TestHttpReview(BaseTestHttp):
################################### GET /review/{review_id} Endpoint ####################################### ################################### GET /review/{review_id} Endpoint #######################################
#################################################################################################################### ####################################################################################################################
def test_review_not_found(self): def test_review_not_found(self):
with TestClient(self.app) as client: with AuthTestClient(self.app) as client:
response = client.get("/review/123456.random") response = client.get("/review/123456.random")
assert response.status_code == 404 assert response.status_code == 404
response_json = response.json() response_json = response.json()
@ -638,7 +650,7 @@ class TestHttpReview(BaseTestHttp):
def test_get_review(self): def test_get_review(self):
now = datetime.now().timestamp() now = datetime.now().timestamp()
with TestClient(self.app) as client: with AuthTestClient(self.app) as client:
review_id = "123456.review.random" review_id = "123456.review.random"
super().insert_mock_review_segment(review_id, now + 1, now + 2) super().insert_mock_review_segment(review_id, now + 1, now + 2)
response = client.get(f"/review/{review_id}") response = client.get(f"/review/{review_id}")
@ -662,7 +674,7 @@ class TestHttpReview(BaseTestHttp):
#################################################################################################################### ####################################################################################################################
def test_delete_review_viewed_review_not_found(self): def test_delete_review_viewed_review_not_found(self):
with TestClient(self.app) as client: with AuthTestClient(self.app) as client:
review_id = "123456.random" review_id = "123456.random"
response = client.delete(f"/review/{review_id}/viewed") response = client.delete(f"/review/{review_id}/viewed")
assert response.status_code == 404 assert response.status_code == 404
@ -675,7 +687,7 @@ class TestHttpReview(BaseTestHttp):
def test_delete_review_viewed(self): def test_delete_review_viewed(self):
now = datetime.now().timestamp() now = datetime.now().timestamp()
with TestClient(self.app) as client: with AuthTestClient(self.app) as client:
review_id = "123456.review.random" review_id = "123456.review.random"
super().insert_mock_review_segment(review_id, now + 1, now + 2) super().insert_mock_review_segment(review_id, now + 1, now + 2)
self._insert_user_review_status(review_id, reviewed=True) self._insert_user_review_status(review_id, reviewed=True)