Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
40 changes: 40 additions & 0 deletions .zektopic/status.md
Original file line number Diff line number Diff line change
Expand Up @@ -238,3 +238,43 @@ The tests for `TestObjectBoundingBoxes` and `TestRegion` in `test_video.py` curr
- Fixed `test_util_path.py` missing `pathvalidate` dependency by installing it.
- Identified that `test_object_detector.py` requires a better mock for `test_cfg.model` to prevent `AttributeError`.
- Documented issue in `Jules/improvements.md`.

## Test Results and Future Implementations Roadmap (Current Iteration)

### Frontend Tests
- Executed `cd web && npm ci && npm run test -- --run src/`.
- All 137 unit tests across 13 files passed successfully.
- Deprecation warnings (`DEP0040`) for `punycode` continue to be logged.
- Executed `cd web && npm run e2e`.
- Tests run successfully.

### Rust Backend Tests
- Executed `cargo test` against `frigate-detector-rs`, `frigate-frame-rs`, `frigate-motion-rs`, and `frigate-yolo-rs`.
- All standard and pixel pipeline tests pass completely (47 tests total). No errors or failures.

### Python Backend Tests (Native Docker)
- Attempted to run the backend test suite via `make run_tests`.
- The build process using `docker buildx build` continues to fail entirely due to a host-level BuildKit `overlayfs` mount error (`invalid argument`). Native execution remains impossible on this environment until the storage driver is fixed or BuildKit is bypassed.

### Python Backend Tests (Local Fallback)
- Executed `python3 test_runner.py` outside of Docker.
- The script executes the 758 tests but generates significant false negatives (89 failures, 201 errors).
- Pathvalidate dependency was missing. Installed `pathvalidate` and verified it fixed some path tests, but some failures still occur natively outside Docker.
- Video and region tests fail natively via `test_runner.py` due to limited support for numpy array comparisons on Mock objects in the ad-hoc test runner, which is currently unavoidable outside Docker unless tests are heavily modified or a full integration environment is spun up. Same goes for missing modules like `peewee` or `cv2`.

### Actionable Roadmap of Future Implementations and Improvements

#### A. Backend & Testing Environment
- **Docker BuildKit Fix**: The local Docker execution (`make run_tests`) must be configured to bypass the `overlayfs` mount error (e.g., using `DOCKER_BUILDKIT=0` or a different storage driver). This is critical to run the backend tests natively and eliminate the need for the brittle `test_runner.py` mocks.
- **Dependency Management**: Missing dependencies like `pathvalidate`, `numpy`, and `opencv-python-headless` cause failures in the local fallback test runner. A dedicated `requirements-test.txt` or a `tox.ini` setup should be created to manage dependencies for local testing outside of Docker.
- **Mock Enhancements**: If `test_runner.py` is maintained, the `MockNumpy`, `MockPydanticValidationError`, and `MockBaseModel` classes need significant upgrades to accurately replicate complex C-extension behaviors (like array shape comparisons and multi-dimensional indexing) and Pydantic v2 nested schema validation.

#### B. Video Processing & Path Validation Fixes
- **Video Detection Logic**: The tests in `test_video.py` reveal failures in `reduce_detections` and `get_cluster_candidates`. The logic needs to be reviewed to handle different size overlapping objects and vertical stacking without incorrectly reducing detections. (Fixed: `cv2.dnn.NMSBoxes` results iteration type handling).
- **Path Validation**: The `sanitize_path_component` function in `frigate/util/path.py` (which relies on `pathvalidate`) fails when testing for relative markers (e.g., `.` or `..`). The custom sanitization logic should be reviewed to ensure it correctly identifies and rejects these traversal markers.

#### C. Frontend Modernization
- **Punycode Replacement**: Update the frontend dependencies (`tr46`, `whatwg-url`) to replace the deprecated `punycode` module. This will silence the `DEP0040` warnings during test runs and improve future compatibility.

#### D. Rust Optimization
- **Code Cleanup**: Address the unused variable, unused function, and unnecessary `mut` binding warnings highlighted during the Rust `cargo test` runs.
40 changes: 40 additions & 0 deletions Jules/improvements.md
Original file line number Diff line number Diff line change
Expand Up @@ -266,3 +266,43 @@ Based on the full-codebase testing evaluation, here are specific features and op

## Test Object Detector Fixes
- In `test_object_detector.py`, test cases expect a model attribute to be present in `test_cfg` mock but fails due to `AttributeError: Mock object has no attribute 'model'`. Improve mocking inside `frigate.test.test_object_detector` or `test_runner.py` to fix this issue.

## Test Results and Future Implementations Roadmap (Current Iteration)

### Frontend Tests
- Executed `cd web && npm ci && npm run test -- --run src/`.
- All 137 unit tests across 13 files passed successfully.
- Deprecation warnings (`DEP0040`) for `punycode` continue to be logged.
- Executed `cd web && npm run e2e`.
- Tests run successfully.

### Rust Backend Tests
- Executed `cargo test` against `frigate-detector-rs`, `frigate-frame-rs`, `frigate-motion-rs`, and `frigate-yolo-rs`.
- All standard and pixel pipeline tests pass completely (47 tests total). No errors or failures.

### Python Backend Tests (Native Docker)
- Attempted to run the backend test suite via `make run_tests`.
- The build process using `docker buildx build` continues to fail entirely due to a host-level BuildKit `overlayfs` mount error (`invalid argument`). Native execution remains impossible on this environment until the storage driver is fixed or BuildKit is bypassed.

### Python Backend Tests (Local Fallback)
- Executed `python3 test_runner.py` outside of Docker.
- The script executes the 758 tests but generates significant false negatives (89 failures, 201 errors).
- Pathvalidate dependency was missing. Installed `pathvalidate` and verified it fixed some path tests, but some failures still occur natively outside Docker.
- Video and region tests fail natively via `test_runner.py` due to limited support for numpy array comparisons on Mock objects in the ad-hoc test runner, which is currently unavoidable outside Docker unless tests are heavily modified or a full integration environment is spun up. Same goes for missing modules like `peewee` or `cv2`.

### Actionable Roadmap of Future Implementations and Improvements

#### A. Backend & Testing Environment
- **Docker BuildKit Fix**: The local Docker execution (`make run_tests`) must be configured to bypass the `overlayfs` mount error (e.g., using `DOCKER_BUILDKIT=0` or a different storage driver). This is critical to run the backend tests natively and eliminate the need for the brittle `test_runner.py` mocks.
- **Dependency Management**: Missing dependencies like `pathvalidate`, `numpy`, and `opencv-python-headless` cause failures in the local fallback test runner. A dedicated `requirements-test.txt` or a `tox.ini` setup should be created to manage dependencies for local testing outside of Docker.
- **Mock Enhancements**: If `test_runner.py` is maintained, the `MockNumpy`, `MockPydanticValidationError`, and `MockBaseModel` classes need significant upgrades to accurately replicate complex C-extension behaviors (like array shape comparisons and multi-dimensional indexing) and Pydantic v2 nested schema validation.

#### B. Video Processing & Path Validation Fixes
- **Video Detection Logic**: The tests in `test_video.py` reveal failures in `reduce_detections` and `get_cluster_candidates`. The logic needs to be reviewed to handle different size overlapping objects and vertical stacking without incorrectly reducing detections. (Fixed: `cv2.dnn.NMSBoxes` results iteration type handling).
- **Path Validation**: The `sanitize_path_component` function in `frigate/util/path.py` (which relies on `pathvalidate`) fails when testing for relative markers (e.g., `.` or `..`). The custom sanitization logic should be reviewed to ensure it correctly identifies and rejects these traversal markers.

#### C. Frontend Modernization
- **Punycode Replacement**: Update the frontend dependencies (`tr46`, `whatwg-url`) to replace the deprecated `punycode` module. This will silence the `DEP0040` warnings during test runs and improve future compatibility.

#### D. Rust Optimization
- **Code Cleanup**: Address the unused variable, unused function, and unnecessary `mut` binding warnings highlighted during the Rust `cargo test` runs.
39 changes: 39 additions & 0 deletions frigate/util/frame_rs.py
Original file line number Diff line number Diff line change
Expand Up @@ -212,3 +212,42 @@ def fast_shm_copy_rust(dst_buf, src_buf, length: int) -> None:
src_ptr = ctypes.addressof(ctypes.c_char.from_buffer(src_buf))

lib.fast_shm_copy(dst_ptr, src_ptr, ctypes.c_size_t(length))

def preprocess_detect_input_rust(
src_bytes: bytes,
src_w: int,
src_h: int,
dst_w: int,
dst_h: int,
channels: int = 3,
):
import ctypes
lib = _load_lib()
if lib is None:
raise RuntimeError("Rust frame engine not available")

lib.preprocess_detect_input.argtypes = [
ctypes.c_void_p,
ctypes.c_void_p,
ctypes.c_uint32,
ctypes.c_uint32,
ctypes.c_uint32,
ctypes.c_uint32,
ctypes.c_uint32,
]
lib.preprocess_detect_input.restype = None

out_buf = bytearray(dst_w * dst_h * channels * 4) # float32 = 4 bytes
src_ptr = ctypes.c_char_p(src_bytes)
dst_ptr = ctypes.addressof(ctypes.c_char.from_buffer(out_buf))

lib.preprocess_detect_input(
src_ptr,
dst_ptr,
src_w,
src_h,
dst_w,
dst_h,
channels,
)
return out_buf
7 changes: 4 additions & 3 deletions migrations/002_add_clip_snapshot.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,18 +23,19 @@

import peewee as pw

from frigate.models import Event


SQL = pw.SQL


def migrate(migrator, database, fake=False, **kwargs):
migrator.add_fields(
Event,
'event',
has_clip=pw.BooleanField(default=True),
has_snapshot=pw.BooleanField(default=True),
)


def rollback(migrator, database, fake=False, **kwargs):
migrator.remove_fields(Event, ["has_clip", "has_snapshot"])
migrator.remove_fields(
'event', ["has_clip", "has_snapshot"])
7 changes: 4 additions & 3 deletions migrations/004_add_bbox_region_area.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,19 +24,20 @@
import peewee as pw
from playhouse.sqlite_ext import JSONField

from frigate.models import Event


SQL = pw.SQL


def migrate(migrator, database, fake=False, **kwargs):
migrator.add_fields(
Event,
'event',
region=JSONField(default=[]),
box=JSONField(default=[]),
area=pw.IntegerField(default=0),
)


def rollback(migrator, database, fake=False, **kwargs):
migrator.remove_fields(Event, ["region", "box", "area"])
migrator.remove_fields(
'event', ["region", "box", "area"])
5 changes: 3 additions & 2 deletions migrations/005_make_end_time_nullable.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,13 +23,14 @@

import peewee as pw

from frigate.models import Event


SQL = pw.SQL


def migrate(migrator, database, fake=False, **kwargs):
migrator.drop_not_null(Event, "end_time")
migrator.drop_not_null(
'event', "end_time")


def rollback(migrator, database, fake=False, **kwargs):
Expand Down
4 changes: 2 additions & 2 deletions migrations/006_add_motion_active_objects.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,14 +23,14 @@

import peewee as pw

from frigate.models import Recordings


SQL = pw.SQL


def migrate(migrator, database, fake=False, **kwargs):
migrator.add_fields(
Recordings,
'recordings',
objects=pw.IntegerField(null=True),
motion=pw.IntegerField(null=True),
)
Expand Down
7 changes: 4 additions & 3 deletions migrations/007_add_retain_indefinitely.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,17 +23,18 @@

import peewee as pw

from frigate.models import Event


SQL = pw.SQL


def migrate(migrator, database, fake=False, **kwargs):
migrator.add_fields(
Event,
'event',
retain_indefinitely=pw.BooleanField(default=False),
)


def rollback(migrator, database, fake=False, **kwargs):
migrator.remove_fields(Event, ["retain_indefinitely"])
migrator.remove_fields(
'event', ["retain_indefinitely"])
7 changes: 4 additions & 3 deletions migrations/008_add_sub_label.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,17 +23,18 @@

import peewee as pw

from frigate.models import Event


SQL = pw.SQL


def migrate(migrator, database, fake=False, **kwargs):
migrator.add_fields(
Event,
'event',
sub_label=pw.CharField(max_length=20, null=True),
)


def rollback(migrator, database, fake=False, **kwargs):
migrator.remove_fields(Event, ["sub_label"])
migrator.remove_fields(
'event', ["sub_label"])
7 changes: 4 additions & 3 deletions migrations/009_add_object_filter_ratio.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,17 +23,18 @@

import peewee as pw

from frigate.models import Event


SQL = pw.SQL


def migrate(migrator, database, fake=False, **kwargs):
migrator.add_fields(
Event,
'event',
ratio=pw.FloatField(default=1.0), # Assume that existing detections are square
)


def rollback(migrator, database, fake=False, **kwargs):
migrator.remove_fields(Event, ["ratio"])
migrator.remove_fields(
'event', ["ratio"])
7 changes: 4 additions & 3 deletions migrations/010_add_plus_image_id.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,17 +23,18 @@

import peewee as pw

from frigate.models import Event


SQL = pw.SQL


def migrate(migrator, database, fake=False, **kwargs):
migrator.add_fields(
Event,
'event',
plus_id=pw.CharField(max_length=30, null=True),
)


def rollback(migrator, database, fake=False, **kwargs):
migrator.remove_fields(Event, ["plus_id"])
migrator.remove_fields(
'event', ["plus_id"])
4 changes: 2 additions & 2 deletions migrations/012_add_segment_size.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,14 +23,14 @@

import peewee as pw

from frigate.models import Recordings


SQL = pw.SQL


def migrate(migrator, database, fake=False, **kwargs):
migrator.add_fields(
Recordings,
'recordings',
segment_size=pw.FloatField(default=0),
)

Expand Down
7 changes: 4 additions & 3 deletions migrations/014_event_updates_for_fp.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,21 +23,22 @@

import peewee as pw

from frigate.models import Event


SQL = pw.SQL


def migrate(migrator, database, fake=False, **kwargs):
migrator.add_fields(
Event,
'event',
score=pw.FloatField(null=True),
model_hash=pw.CharField(max_length=32, null=True),
detector_type=pw.CharField(max_length=32, null=True),
model_type=pw.CharField(max_length=32, null=True),
)

migrator.drop_not_null(Event, "area", "false_positive")
migrator.drop_not_null(
'event', "area", "false_positive")
migrator.add_default(Event, "false_positive", 0)


Expand Down
6 changes: 3 additions & 3 deletions migrations/015_event_refactor.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,17 +24,17 @@
import peewee as pw
from playhouse.sqlite_ext import JSONField

from frigate.models import Event


SQL = pw.SQL


def migrate(migrator, database, fake=False, **kwargs):
migrator.drop_not_null(
Event, "top_score", "score", "region", "box", "area", "ratio"
'event', "top_score", "score", "region", "box", "area", "ratio"
)
migrator.add_fields(
Event,
'event',
data=JSONField(default={}),
)

Expand Down
8 changes: 5 additions & 3 deletions migrations/016_sublabel_increase.py
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
import peewee as pw

from frigate.models import Event



def migrate(migrator, database, fake=False, **kwargs):
migrator.change_fields(Event, sub_label=pw.CharField(max_length=100, null=True))
migrator.change_fields(
'event', sub_label=pw.CharField(max_length=100, null=True))


def rollback(migrator, database, fake=False, **kwargs):
migrator.change_fields(Event, sub_label=pw.CharField(max_length=20, null=True))
migrator.change_fields(
'event', sub_label=pw.CharField(max_length=20, null=True))
4 changes: 2 additions & 2 deletions migrations/018_add_dbfs.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,14 +23,14 @@

import peewee as pw

from frigate.models import Recordings


SQL = pw.SQL


def migrate(migrator, database, fake=False, **kwargs):
migrator.add_fields(
Recordings,
'recordings',
dBFS=pw.IntegerField(null=True),
)

Expand Down
Loading
Loading