From b535fb0b275fa38d086c93fb38ef1b2b3b24b870 Mon Sep 17 00:00:00 2001 From: Gdub <290704+gwmullin@users.noreply.github.com> Date: Fri, 26 Jun 2026 14:02:51 -0700 Subject: [PATCH] Add a testcase for validating that on_conflict_ignore bypasses what was formerly an IntegrityError --- frigate/test/http_api/test_http_review.py | 37 +++++++++++++++++++++++ 1 file changed, 37 insertions(+) diff --git a/frigate/test/http_api/test_http_review.py b/frigate/test/http_api/test_http_review.py index ca73c87064..f6d5f2c661 100644 --- a/frigate/test/http_api/test_http_review.py +++ b/frigate/test/http_api/test_http_review.py @@ -497,6 +497,43 @@ class TestHttpReview(BaseTestHttp): ) assert user_review.has_been_reviewed == True + def test_post_reviews_viewed_concurrent_duplicate_does_not_raise(self): + """Regression: concurrent requests marking the same review must not 500. + + Two requests can both SELECT and find no existing status, then both try + to INSERT, hitting the unique (user_id, review_segment) constraint. + on_conflict_ignore() must silently skip the duplicate instead of raising + an IntegrityError (which was previously caught with try/except). + """ + id = "123456.random" + with AuthTestClient(self.app): + super().insert_mock_review_segment(id) + + # Simulate the first request having already committed its insert. + self._insert_user_review_status(id, reviewed=True) + + # Simulate the second concurrent request attempting the same insert. + UserReviewStatus.insert_many( + [ + { + "user_id": self.user_id, + "review_segment_id": id, + "has_been_reviewed": True, + } + ] + ).on_conflict_ignore().execute() + + # Exactly one row should exist; no exception should have been raised. + count = ( + UserReviewStatus.select() + .where( + (UserReviewStatus.user_id == self.user_id) + & (UserReviewStatus.review_segment == id) + ) + .count() + ) + assert count == 1 + #################################################################################################################### ################################### POST reviews/delete Endpoint ################################################ ####################################################################################################################