fix: correct invalid segment topic matching in CameraWatchdog

`topic.endswith("valid")` also matched `"recordings/invalid"`, routing
invalid segment messages to the valid branch. This kept
`latest_invalid_segment_time` permanently at 0, preventing the stale
recording restart logic from ever triggering on a stream of corrupt
segments.

Fix by anchoring the suffix with a leading slash so each enum value
matches exactly one topic type.

Co-authored-by: Claude <claude@anthropic.com>
This commit is contained in:
Luis Miranda 2026-04-28 13:09:57 +01:00
parent 99606e82c1
commit bd772ae4b2
No known key found for this signature in database
2 changed files with 18 additions and 4 deletions

View File

@ -89,16 +89,30 @@ class TestProcessSegmentUpdates(unittest.TestCase):
self.assertEqual(watchdog.latest_invalid_segment_time, 0.0)
self.assertEqual(watchdog.latest_cache_segment_time, 0.0)
def test_out_of_order_invalid_segments(self):
"""Out-of-order invalid segments still result in the maximum timestamp."""
watchdog = _make_watchdog()
watchdog.segment_subscriber.check_for_update.side_effect = [
_msg(RecordingsDataTypeEnum.invalid, "front_door", 5.0),
_msg(RecordingsDataTypeEnum.invalid, "front_door", 15.0),
_msg(RecordingsDataTypeEnum.invalid, "front_door", 8.0),
(None, None),
]
watchdog._drain_segment_updates()
self.assertEqual(watchdog.latest_invalid_segment_time, 15.0)
def test_mixed_types_tracked_independently(self):
"""Valid and cache segment times are each tracked independently."""
"""Valid, invalid, and cache segment times are each tracked independently."""
watchdog = _make_watchdog()
watchdog.segment_subscriber.check_for_update.side_effect = [
_msg(RecordingsDataTypeEnum.valid, "front_door", 10.0),
_msg(RecordingsDataTypeEnum.invalid, "front_door", 20.0),
_msg(RecordingsDataTypeEnum.latest, "front_door", 30.0),
(None, None),
]
watchdog._drain_segment_updates()
self.assertEqual(watchdog.latest_valid_segment_time, 10.0)
self.assertEqual(watchdog.latest_invalid_segment_time, 20.0)
self.assertEqual(watchdog.latest_cache_segment_time, 30.0)

View File

@ -218,21 +218,21 @@ class CameraWatchdog(threading.Thread):
if camera != self.config.name:
continue
if topic.endswith(RecordingsDataTypeEnum.valid.value):
if topic.endswith(f"/{RecordingsDataTypeEnum.valid.value}"):
self.logger.debug(
f"Latest valid recording segment time on {camera}: {segment_time}"
)
self.latest_valid_segment_time = max(
self.latest_valid_segment_time, segment_time
)
elif topic.endswith(RecordingsDataTypeEnum.invalid.value):
elif topic.endswith(f"/{RecordingsDataTypeEnum.invalid.value}"):
self.logger.warning(
f"Invalid recording segment detected for {camera} at {segment_time}"
)
self.latest_invalid_segment_time = max(
self.latest_invalid_segment_time, segment_time
)
elif topic.endswith(RecordingsDataTypeEnum.latest.value):
elif topic.endswith(f"/{RecordingsDataTypeEnum.latest.value}"):
if segment_time is not None:
self.latest_cache_segment_time = max(
self.latest_cache_segment_time, segment_time