Skip to content
Open
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
18 changes: 18 additions & 0 deletions .zektopic/optimization_and_issues_report.md
Original file line number Diff line number Diff line change
Expand Up @@ -240,3 +240,21 @@ The backend test runner (`test_runner.py`) uses a large number of mocked imports
**Frontend Testing Optimizations:**
- Executing frontend tests in the root `web/` folder with standard `npm run test` causes assertion and describe-block collisions. This occurs because Vitest encounters Playwright integration tests inside the `e2e/` folder, causing conflicts where Playwright explicitly rejects `test.describe()` from foreign executors.
- *Optimization Suggestion*: Always explicitly scope unit tests to the source code folder using `cd web && npm run test -- --run src/`. Doing so results in all 138 test items resolving successfully within an isolated boundary, improving both the test reliability and preventing tool-chain cross-pollution.



### Test Results Overview (Local Run)

- **Backend (Python)**: Failed. (`FAILED (failures=89, errors=201, skipped=12)`) Many `ImportError` on missing test dependencies (e.g., `http_api.test_debug_replay_api`).
- **Frontend (Web)**: Passed. 137 tests passed in 5.31s. Emitted `[DEP0040] DeprecationWarning: The punycode module is deprecated.`
- **Rust**: Passed. 0 failures across `frigate-detector-rs`, `frigate-frame-rs`, `frigate-motion-rs`, `frigate-yolo-rs`.
- **Linting/Static Analysis**:
- `ruff`: 11 errors (10 fixable via `--fix`).
- `npm run lint`: 8 warnings (prettier formatting).
- `mypy`: 139 errors in 33 files.

### Actionable Roadmap
1. **Fix Python Backend Test Imports**: Modify `test_runner.py` to properly mock or install missing nested dependencies for tests failing with `ImportError`.
2. **Fix `ruff` and `npm run lint` errors**: Run `ruff check --fix frigate/` and `npm run lint:fix` to clean up easily automatable formatting issues.
3. **Address `mypy` typing issues**: Iteratively go through the `139` typing errors in `frigate/` (e.g., in `license_plate/mixin.py`, unused ignore comments).
4. **Update Frontend Dependencies**: Look into userland alternatives for the `punycode` module dependency to resolve Node deprecation warnings.
18 changes: 18 additions & 0 deletions .zektopic/status.md
Original file line number Diff line number Diff line change
Expand Up @@ -205,3 +205,21 @@ Based on the full-codebase testing evaluation, here are specific features and op
- `AttributeError: type object 'Recordings' has no attribute 'insert'`: Mocked Peewee models lack functional parity for storage manipulation.
- Pydantic v2 nested object and regex attribute mapping (`MockPydanticValidationError`) limits fail configuration validation tests natively.
- Complex multi-dimensional array comparisons (e.g. `numpy.ndarray.shape` and `cv2` properties) fail assert-equals clauses heavily in video and motion tests.



### Test Results Overview (Local Run)

- **Backend (Python)**: Failed. (`FAILED (failures=89, errors=201, skipped=12)`) Many `ImportError` on missing test dependencies (e.g., `http_api.test_debug_replay_api`).
- **Frontend (Web)**: Passed. 137 tests passed in 5.31s. Emitted `[DEP0040] DeprecationWarning: The punycode module is deprecated.`
- **Rust**: Passed. 0 failures across `frigate-detector-rs`, `frigate-frame-rs`, `frigate-motion-rs`, `frigate-yolo-rs`.
- **Linting/Static Analysis**:
- `ruff`: 11 errors (10 fixable via `--fix`).
- `npm run lint`: 8 warnings (prettier formatting).
- `mypy`: 139 errors in 33 files.

### Actionable Roadmap
1. **Fix Python Backend Test Imports**: Modify `test_runner.py` to properly mock or install missing nested dependencies for tests failing with `ImportError`.
2. **Fix `ruff` and `npm run lint` errors**: Run `ruff check --fix frigate/` and `npm run lint:fix` to clean up easily automatable formatting issues.
3. **Address `mypy` typing issues**: Iteratively go through the `139` typing errors in `frigate/` (e.g., in `license_plate/mixin.py`, unused ignore comments).
4. **Update Frontend Dependencies**: Look into userland alternatives for the `punycode` module dependency to resolve Node deprecation warnings.
18 changes: 18 additions & 0 deletions Jules/improvements.md
Original file line number Diff line number Diff line change
Expand Up @@ -239,3 +239,21 @@ Based on the full-codebase testing evaluation, here are specific features and op
#### D. Database & Video Pipeline
- **Utilize Bulk Operations**: Given the high throughput demonstrated in SQLite batch benchmarks, refactor logic that loops over singular `select` or `insert` statements (e.g., in `frigate.record.export`) to utilize Peewee batch chunking for significant IO gains.
- **Quantized Model Loading**: For CPU-constrained or APU setups, implement dynamic loading for INT8/quantized models to reduce overhead in ONNX/YOLO pipelines (e.g., minimizing `np.transpose` contiguous copy bottlenecks).



### Test Results Overview (Local Run)

- **Backend (Python)**: Failed. (`FAILED (failures=89, errors=201, skipped=12)`) Many `ImportError` on missing test dependencies (e.g., `http_api.test_debug_replay_api`).
- **Frontend (Web)**: Passed. 137 tests passed in 5.31s. Emitted `[DEP0040] DeprecationWarning: The punycode module is deprecated.`
- **Rust**: Passed. 0 failures across `frigate-detector-rs`, `frigate-frame-rs`, `frigate-motion-rs`, `frigate-yolo-rs`.
- **Linting/Static Analysis**:
- `ruff`: 11 errors (10 fixable via `--fix`).
- `npm run lint`: 8 warnings (prettier formatting).
- `mypy`: 139 errors in 33 files.

### Actionable Roadmap
1. **Fix Python Backend Test Imports**: Modify `test_runner.py` to properly mock or install missing nested dependencies for tests failing with `ImportError`.
2. **Fix `ruff` and `npm run lint` errors**: Run `ruff check --fix frigate/` and `npm run lint:fix` to clean up easily automatable formatting issues.
3. **Address `mypy` typing issues**: Iteratively go through the `139` typing errors in `frigate/` (e.g., in `license_plate/mixin.py`, unused ignore comments).
4. **Update Frontend Dependencies**: Look into userland alternatives for the `punycode` module dependency to resolve Node deprecation warnings.
18 changes: 18 additions & 0 deletions Jules/optimization_and_issues_report.md
Original file line number Diff line number Diff line change
Expand Up @@ -67,3 +67,21 @@ The mocks for `BaseModel` and `unidecode` were incomplete.
**Frontend Testing Optimizations:**
- Executing frontend tests in the root `web/` folder with standard `npm run test` causes assertion and describe-block collisions. This occurs because Vitest encounters Playwright integration tests inside the `e2e/` folder, causing conflicts where Playwright explicitly rejects `test.describe()` from foreign executors.
- *Optimization Suggestion*: Always explicitly scope unit tests to the source code folder using `cd web && npm run test -- --run src/`. Doing so results in all 138 test items resolving successfully within an isolated boundary, improving both the test reliability and preventing tool-chain cross-pollution.



### Test Results Overview (Local Run)

- **Backend (Python)**: Failed. (`FAILED (failures=89, errors=201, skipped=12)`) Many `ImportError` on missing test dependencies (e.g., `http_api.test_debug_replay_api`).
- **Frontend (Web)**: Passed. 137 tests passed in 5.31s. Emitted `[DEP0040] DeprecationWarning: The punycode module is deprecated.`
- **Rust**: Passed. 0 failures across `frigate-detector-rs`, `frigate-frame-rs`, `frigate-motion-rs`, `frigate-yolo-rs`.
- **Linting/Static Analysis**:
- `ruff`: 11 errors (10 fixable via `--fix`).
- `npm run lint`: 8 warnings (prettier formatting).
- `mypy`: 139 errors in 33 files.

### Actionable Roadmap
1. **Fix Python Backend Test Imports**: Modify `test_runner.py` to properly mock or install missing nested dependencies for tests failing with `ImportError`.
2. **Fix `ruff` and `npm run lint` errors**: Run `ruff check --fix frigate/` and `npm run lint:fix` to clean up easily automatable formatting issues.
3. **Address `mypy` typing issues**: Iteratively go through the `139` typing errors in `frigate/` (e.g., in `license_plate/mixin.py`, unused ignore comments).
4. **Update Frontend Dependencies**: Look into userland alternatives for the `punycode` module dependency to resolve Node deprecation warnings.
5 changes: 4 additions & 1 deletion frigate/api/notification.py
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,10 @@ def register_notifications(request: Request, body: dict = None):

if not username or username == "anonymous":
return JSONResponse(
content={"success": False, "message": "Cannot register notifications for an anonymous user."},
content={
"success": False,
"message": "Cannot register notifications for an anonymous user.",
},
status_code=400,
)

Expand Down
4 changes: 3 additions & 1 deletion frigate/db/sqlitevecq.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,9 @@ def _connect(self, *args: Any, **kwargs: Any) -> sqlite3.Connection:
conn: sqlite3.Connection = super()._connect(*args, **kwargs) # type: ignore[misc]
conn.execute("PRAGMA journal_mode=WAL;")
conn.execute("PRAGMA synchronous=NORMAL;")
conn.execute("PRAGMA busy_timeout=30000;") # 30-sec busy timeout prevents "database is locked" errors
conn.execute(
"PRAGMA busy_timeout=30000;"
) # 30-sec busy timeout prevents "database is locked" errors
conn.execute("PRAGMA temp_store=MEMORY;")
conn.execute("PRAGMA mmap_size=268435456;") # 256 MB — reduces read() syscalls
conn.execute("PRAGMA wal_autocheckpoint=1000;")
Expand Down
8 changes: 5 additions & 3 deletions frigate/test/test_frame_shm_rust.py
Original file line number Diff line number Diff line change
@@ -1,18 +1,21 @@
import unittest

import numpy as np

from frigate.util.frame_rs import (
frame_rs_available,
intersection_over_union_rust,
track_distance_rust,
preprocess_detect_input_rust,
track_distance_rust,
)


class TestFrameShmRust(unittest.TestCase):
def test_frame_rs_available(self):
"""Ensure Rust frame engine library loads correctly."""
self.assertTrue(frame_rs_available(), "libfrigate_frame_rs.so should be available")
self.assertTrue(
frame_rs_available(), "libfrigate_frame_rs.so should be available"
)

def test_iou_rust(self):
"""Test bounding box IoU calculation in Rust."""
Expand Down Expand Up @@ -59,6 +62,5 @@ def test_preprocess_detect_input_rust(self):
self.assertTrue(np.all(out_np >= 0.0) and np.all(out_np <= 1.0))



if __name__ == "__main__":
unittest.main()
54 changes: 39 additions & 15 deletions frigate/test/test_fuzzing.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,19 +8,19 @@
import math
import random
import unittest

import numpy as np

from frigate.detectors.rust_yolo import (
yolo26_post_process,
yolo_available,
)
from frigate.util.frame_rs import (
fast_shm_copy_rust,
frame_rs_available,
point_in_polygon_rust,
polygon_box_overlap_rust,
intersection_over_union_rust,
track_distance_rust,
fast_shm_copy_rust,
)
from frigate.detectors.rust_yolo import (
yolo_available,
yolo26_post_process,
)


Expand All @@ -31,7 +31,24 @@ def test_fuzz_fast_shm_copy_random_lengths(self):
self.skipTest("Rust frame engine not available")

# Test various aligned and unaligned lengths
test_lengths = [0, 1, 7, 15, 16, 31, 32, 33, 63, 64, 65, 127, 128, 513, 1024, 65537]
test_lengths = [
0,
1,
7,
15,
16,
31,
32,
33,
63,
64,
65,
127,
128,
513,
1024,
65537,
]
for length in test_lengths:
if length == 0:
continue
Expand All @@ -58,14 +75,16 @@ def test_fuzz_track_distance_nan_inf_degenerate(self):
[float("inf"), 10.0, 100.0, 100.0],
[10.0, float("-inf"), 100.0, 100.0],
[100.0, 100.0, 10.0, 10.0], # Inverted box (x2 < x1, y2 < y1)
[50.0, 50.0, 50.0, 50.0], # Zero-width / zero-height box
[-1e9, -1e9, 1e9, 1e9], # Extreme coordinates
[50.0, 50.0, 50.0, 50.0], # Zero-width / zero-height box
[-1e9, -1e9, 1e9, 1e9], # Extreme coordinates
]

for bad_box in extreme_cases:
dist = track_distance_rust(bad_box, valid_box)
# Must return finite float or +inf without panic or segfault
self.assertTrue(math.isnan(dist) or math.isinf(dist) or isinstance(dist, float))
self.assertTrue(
math.isnan(dist) or math.isinf(dist) or isinstance(dist, float)
)

def test_fuzz_polygon_geometry_extreme_points(self):
"""Fuzz point-in-polygon and polygon-box overlap with complex / self-intersecting polygons."""
Expand All @@ -78,7 +97,9 @@ def test_fuzz_polygon_geometry_extreme_points(self):

# 2. Single point / 2-point line segment
self.assertFalse(point_in_polygon_rust(50.0, 50.0, [(10.0, 10.0)]))
self.assertFalse(point_in_polygon_rust(50.0, 50.0, [(10.0, 10.0), (20.0, 20.0)]))
self.assertFalse(
point_in_polygon_rust(50.0, 50.0, [(10.0, 10.0), (20.0, 20.0)])
)

# 3. Huge self-intersecting bowtie polygon
bowtie = [(0.0, 0.0), (100.0, 100.0), (0.0, 100.0), (100.0, 0.0)]
Expand All @@ -87,8 +108,7 @@ def test_fuzz_polygon_geometry_extreme_points(self):

# 4. Fuzz with 1000 random points against a complex 20-vertex polygon
polygon = [
(random.uniform(0, 1000), random.uniform(0, 1000))
for _ in range(20)
(random.uniform(0, 1000), random.uniform(0, 1000)) for _ in range(20)
]
for _ in range(100):
px = random.uniform(-100, 1100)
Expand All @@ -103,15 +123,19 @@ def test_fuzz_yolo26_post_process_corrupted_tensors(self):

# Random tensor of shape (84, 8400)
raw_noise = np.random.uniform(-10.0, 10.0, (84, 8400)).astype(np.float32)
dets = yolo26_post_process(raw_noise, model_size=640, frame_w=1.0, frame_h=1.0, score_thresh=0.5)
dets = yolo26_post_process(
raw_noise, model_size=640, frame_w=1.0, frame_h=1.0, score_thresh=0.5
)
self.assertEqual(dets.shape, (20, 6))

# Tensor containing NaNs and Infs
raw_corrupt = np.zeros((84, 100), dtype=np.float32)
raw_corrupt[0, :] = np.nan
raw_corrupt[1, :] = np.inf
raw_corrupt[4, :] = 0.9 # high class score
dets_corrupt = yolo26_post_process(raw_corrupt, model_size=640, frame_w=1.0, frame_h=1.0)
dets_corrupt = yolo26_post_process(
raw_corrupt, model_size=640, frame_w=1.0, frame_h=1.0
)
self.assertEqual(dets_corrupt.shape, (20, 6))


Expand Down
8 changes: 6 additions & 2 deletions frigate/test/test_smoke_physical.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@

import os
import unittest

import numpy as np


Expand All @@ -22,7 +23,7 @@ def test_physical_vulkan_gpu_compute(self):

# Test Net initialization with Vulkan options
net = ncnn.Net()
net.opt.use_vulkan_compute = (gpu_count > 0)
net.opt.use_vulkan_compute = gpu_count > 0
net.opt.use_fp16_arithmetic = True
net.opt.use_fp16_packed = True
net.opt.use_fp16_storage = True
Expand All @@ -31,7 +32,9 @@ def test_physical_vulkan_gpu_compute(self):
bin_path = "/config/model_cache/yolo26n.bin"

if not os.path.exists(param_path) or not os.path.exists(bin_path):
self.skipTest(f"Model files {param_path} / {bin_path} not found in test environment")
self.skipTest(
f"Model files {param_path} / {bin_path} not found in test environment"
)

net.load_param(param_path)
net.load_model(bin_path)
Expand All @@ -54,6 +57,7 @@ def test_isolated_api_smoke_harness(self):
"""Smoke test API route handlers in isolation without binding production port 5000."""
from fastapi import FastAPI
from fastapi.testclient import TestClient

from frigate.version import VERSION

test_app = FastAPI()
Expand Down
1 change: 1 addition & 0 deletions frigate/test/test_sqlite_wal_queue.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import os
import tempfile
import unittest

from frigate.db.sqlitevecq import SqliteVecQueueDatabase


Expand Down
27 changes: 15 additions & 12 deletions frigate/test/test_stress_concurrency.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,13 +9,11 @@
import threading
import time
import unittest
import numpy as np

from frigate.db.sqlitevecq import SqliteVecQueueDatabase
from frigate.util.frame_rs import (
frame_rs_available,
batch_track_distance_matrix_rust,
fast_shm_copy_rust,
frame_rs_available,
)


Expand All @@ -30,6 +28,7 @@ def tearDown(self):

def _init_schema(self):
import sqlite3

conn = sqlite3.connect(self.db_path, timeout=30.0)
conn.execute("PRAGMA journal_mode=WAL;")
conn.execute("PRAGMA synchronous=NORMAL;")
Expand All @@ -51,6 +50,7 @@ def _init_schema(self):
def test_sqlite_concurrent_writers_stress(self):
"""Stress test SQLite database with 30 concurrent threads performing rapid inserts."""
import sqlite3

num_threads = 30
inserts_per_thread = 50
errors = []
Expand All @@ -73,8 +73,7 @@ def worker(thread_idx: int):
errors.append((thread_idx, e))

threads = [
threading.Thread(target=worker, args=(t,))
for t in range(num_threads)
threading.Thread(target=worker, args=(t,)) for t in range(num_threads)
]
for t in threads:
t.start()
Expand All @@ -98,10 +97,7 @@ def test_tracker_distance_matrix_high_density_stress(self):
n_dets = 100
n_ests = 100

dets = [
(i * 5.0, i * 5.0, (i + 2) * 5.0, (i + 2) * 5.0)
for i in range(n_dets)
]
dets = [(i * 5.0, i * 5.0, (i + 2) * 5.0, (i + 2) * 5.0) for i in range(n_dets)]
ests = [
(j * 5.0 + 1.0, j * 5.0 + 1.0, (j + 2) * 5.0 + 1.0, (j + 2) * 5.0 + 1.0)
for j in range(n_ests)
Expand All @@ -115,14 +111,17 @@ def test_tracker_distance_matrix_high_density_stress(self):
elapsed = time.perf_counter() - t0

# 50 runs of 10,000 comparisons (500,000 total) should execute in < 150ms in Rust
self.assertLess(elapsed, 0.5, f"Vectorized tracker distance exceeded budget: {elapsed:.3f}s")
self.assertLess(
elapsed, 0.5, f"Vectorized tracker distance exceeded budget: {elapsed:.3f}s"
)

def test_sustained_zero_copy_simd_throughput(self):
"""Benchmark and stress test fast_shm_copy with 1,000 1080p frame copies."""
if not frame_rs_available():
self.skipTest("Rust frame engine not available")

import ctypes

# 1080p RGB frame size = 1920 * 1080 * 3 = 6,220,800 bytes (~6.2 MB)
frame_size = 1920 * 1080 * 3
src_data = bytearray(frame_size)
Expand All @@ -137,10 +136,14 @@ def test_sustained_zero_copy_simd_throughput(self):
fast_shm_copy_rust(dst_buf, src_buf, frame_size)
elapsed = time.perf_counter() - t0

total_gb = (frame_size * iterations) / (1024 ** 3)
total_gb = (frame_size * iterations) / (1024**3)
throughput_gbps = total_gb / elapsed
# Assert throughput is high-performance (> 5 GB/s)
self.assertGreater(throughput_gbps, 1.0, f"SIMD throughput too slow: {throughput_gbps:.2f} GB/s")
self.assertGreater(
throughput_gbps,
1.0,
f"SIMD throughput too slow: {throughput_gbps:.2f} GB/s",
)


if __name__ == "__main__":
Expand Down
Loading
Loading