mirror of
https://github.com/blakeblackshear/frigate.git
synced 2026-05-10 07:25:27 +03:00
Compare commits
5 Commits
cbfefd6df5
...
f7271e0a5b
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
f7271e0a5b | ||
|
|
67604eb61d | ||
|
|
0835aa7ea5 | ||
|
|
3c3cf11da4 | ||
|
|
b657f04d0e |
@ -119,6 +119,7 @@ class FrigateApp:
|
||||
self.ptz_metrics: dict[str, PTZMetrics] = {}
|
||||
self.processes: dict[str, int] = {}
|
||||
self.embeddings: Optional[EmbeddingsContext] = None
|
||||
self.profile_manager: Optional[ProfileManager] = None
|
||||
self.config = config
|
||||
|
||||
def ensure_dirs(self) -> None:
|
||||
@ -351,9 +352,7 @@ class FrigateApp:
|
||||
)
|
||||
|
||||
def init_profile_manager(self) -> None:
|
||||
self.profile_manager = ProfileManager(
|
||||
self.config, self.inter_config_updater
|
||||
)
|
||||
self.profile_manager = ProfileManager(self.config, self.inter_config_updater)
|
||||
self.dispatcher.profile_manager = self.profile_manager
|
||||
|
||||
persisted = ProfileManager.load_persisted_profile()
|
||||
|
||||
@ -16,6 +16,7 @@ from frigate.config.camera.updater import (
|
||||
CameraConfigUpdateTopic,
|
||||
)
|
||||
from frigate.config.config import RuntimeFilterConfig, RuntimeMotionConfig
|
||||
from frigate.config.profile_manager import ProfileManager
|
||||
from frigate.const import (
|
||||
CLEAR_ONGOING_REVIEW_SEGMENTS,
|
||||
EXPIRE_AUDIO_ACTIVITY,
|
||||
@ -93,7 +94,7 @@ class Dispatcher:
|
||||
"notifications": self._on_global_notification_command,
|
||||
"profile": self._on_profile_command,
|
||||
}
|
||||
self.profile_manager = None
|
||||
self.profile_manager: Optional[ProfileManager] = None
|
||||
|
||||
for comm in self.comms:
|
||||
comm.subscribe(self._receive)
|
||||
@ -569,7 +570,9 @@ class Dispatcher:
|
||||
logger.error("Profile manager not initialized")
|
||||
return
|
||||
|
||||
profile_name = payload.strip() if payload.strip() not in ("", "none", "None") else None
|
||||
profile_name = (
|
||||
payload.strip() if payload.strip() not in ("", "none", "None") else None
|
||||
)
|
||||
err = self.profile_manager.activate_profile(profile_name)
|
||||
if err:
|
||||
logger.error("Failed to activate profile: %s", err)
|
||||
|
||||
@ -2,16 +2,29 @@ import sys
|
||||
import unittest
|
||||
from unittest.mock import MagicMock, patch
|
||||
|
||||
# Mock complex imports before importing maintainer
|
||||
sys.modules["frigate.comms.inter_process"] = MagicMock()
|
||||
sys.modules["frigate.comms.detections_updater"] = MagicMock()
|
||||
sys.modules["frigate.comms.recordings_updater"] = MagicMock()
|
||||
sys.modules["frigate.config.camera.updater"] = MagicMock()
|
||||
# Mock complex imports before importing maintainer, saving originals so we can
|
||||
# restore them after import and avoid polluting sys.modules for other tests.
|
||||
_MOCKED_MODULES = [
|
||||
"frigate.comms.inter_process",
|
||||
"frigate.comms.detections_updater",
|
||||
"frigate.comms.recordings_updater",
|
||||
"frigate.config.camera.updater",
|
||||
]
|
||||
_originals = {name: sys.modules.get(name) for name in _MOCKED_MODULES}
|
||||
for name in _MOCKED_MODULES:
|
||||
sys.modules[name] = MagicMock()
|
||||
|
||||
# Now import the class under test
|
||||
from frigate.config import FrigateConfig # noqa: E402
|
||||
from frigate.record.maintainer import RecordingMaintainer # noqa: E402
|
||||
|
||||
# Restore original modules (or remove mock if there was no original)
|
||||
for name, orig in _originals.items():
|
||||
if orig is None:
|
||||
sys.modules.pop(name, None)
|
||||
else:
|
||||
sys.modules[name] = orig
|
||||
|
||||
|
||||
class TestMaintainer(unittest.IsolatedAsyncioTestCase):
|
||||
async def test_move_files_survives_bad_filename(self):
|
||||
|
||||
@ -48,9 +48,7 @@ class TestCameraProfileConfig(unittest.TestCase):
|
||||
|
||||
def test_partial_review(self):
|
||||
"""Profile with nested review.alerts.labels."""
|
||||
profile = CameraProfileConfig(
|
||||
review={"alerts": {"labels": ["person", "car"]}}
|
||||
)
|
||||
profile = CameraProfileConfig(review={"alerts": {"labels": ["person", "car"]}})
|
||||
assert profile.review is not None
|
||||
assert profile.review.alerts.labels == ["person", "car"]
|
||||
|
||||
@ -116,9 +114,7 @@ class TestCameraProfileConfig(unittest.TestCase):
|
||||
from pydantic import ValidationError
|
||||
|
||||
with self.assertRaises(ValidationError):
|
||||
CameraProfileConfig(
|
||||
review={"alerts": {"labels": "not_a_list"}}
|
||||
)
|
||||
CameraProfileConfig(review={"alerts": {"labels": "not_a_list"}})
|
||||
|
||||
def test_invalid_profile_in_camera_config(self):
|
||||
"""Invalid profile section in full config is caught at parse time."""
|
||||
@ -410,14 +406,14 @@ class TestProfileManager(unittest.TestCase):
|
||||
self.manager.activate_profile("disarmed")
|
||||
|
||||
# Back camera has no "disarmed" profile, should be unchanged
|
||||
assert self.config.cameras["back"].notifications.enabled == back_base_notifications
|
||||
assert (
|
||||
self.config.cameras["back"].notifications.enabled == back_base_notifications
|
||||
)
|
||||
|
||||
@patch.object(ProfileManager, "_persist_active_profile")
|
||||
def test_activate_profile_disables_camera(self, mock_persist):
|
||||
"""Profile with enabled=false disables the camera."""
|
||||
self.config.profiles["away"] = ProfileDefinitionConfig(
|
||||
friendly_name="Away"
|
||||
)
|
||||
self.config.profiles["away"] = ProfileDefinitionConfig(friendly_name="Away")
|
||||
self.config.cameras["front"].profiles["away"] = CameraProfileConfig(
|
||||
enabled=False
|
||||
)
|
||||
@ -431,9 +427,7 @@ class TestProfileManager(unittest.TestCase):
|
||||
@patch.object(ProfileManager, "_persist_active_profile")
|
||||
def test_deactivate_restores_enabled(self, mock_persist):
|
||||
"""Deactivating a profile restores the camera's base enabled state."""
|
||||
self.config.profiles["away"] = ProfileDefinitionConfig(
|
||||
friendly_name="Away"
|
||||
)
|
||||
self.config.profiles["away"] = ProfileDefinitionConfig(friendly_name="Away")
|
||||
self.config.cameras["front"].profiles["away"] = CameraProfileConfig(
|
||||
enabled=False
|
||||
)
|
||||
@ -450,9 +444,7 @@ class TestProfileManager(unittest.TestCase):
|
||||
"""Profile with zones adds/overrides zones on camera."""
|
||||
from frigate.config.camera.zone import ZoneConfig
|
||||
|
||||
self.config.profiles["away"] = ProfileDefinitionConfig(
|
||||
friendly_name="Away"
|
||||
)
|
||||
self.config.profiles["away"] = ProfileDefinitionConfig(friendly_name="Away")
|
||||
self.config.cameras["front"].profiles["away"] = CameraProfileConfig(
|
||||
zones={
|
||||
"driveway": ZoneConfig(
|
||||
@ -474,9 +466,7 @@ class TestProfileManager(unittest.TestCase):
|
||||
"""Deactivating a profile restores base zones."""
|
||||
from frigate.config.camera.zone import ZoneConfig
|
||||
|
||||
self.config.profiles["away"] = ProfileDefinitionConfig(
|
||||
friendly_name="Away"
|
||||
)
|
||||
self.config.profiles["away"] = ProfileDefinitionConfig(friendly_name="Away")
|
||||
self.config.cameras["front"].profiles["away"] = CameraProfileConfig(
|
||||
zones={
|
||||
"driveway": ZoneConfig(
|
||||
@ -502,9 +492,7 @@ class TestProfileManager(unittest.TestCase):
|
||||
)
|
||||
from frigate.config.camera.zone import ZoneConfig
|
||||
|
||||
self.config.profiles["away"] = ProfileDefinitionConfig(
|
||||
friendly_name="Away"
|
||||
)
|
||||
self.config.profiles["away"] = ProfileDefinitionConfig(friendly_name="Away")
|
||||
self.config.cameras["front"].profiles["away"] = CameraProfileConfig(
|
||||
zones={
|
||||
"driveway": ZoneConfig(
|
||||
@ -534,9 +522,7 @@ class TestProfileManager(unittest.TestCase):
|
||||
CameraConfigUpdateTopic,
|
||||
)
|
||||
|
||||
self.config.profiles["away"] = ProfileDefinitionConfig(
|
||||
friendly_name="Away"
|
||||
)
|
||||
self.config.profiles["away"] = ProfileDefinitionConfig(friendly_name="Away")
|
||||
self.config.cameras["front"].profiles["away"] = CameraProfileConfig(
|
||||
enabled=False
|
||||
)
|
||||
@ -598,9 +584,7 @@ class TestProfilePersistence(unittest.TestCase):
|
||||
|
||||
try:
|
||||
with patch.object(type(PERSISTENCE_FILE), "exists", return_value=True):
|
||||
with patch.object(
|
||||
type(PERSISTENCE_FILE), "read_text", return_value=""
|
||||
):
|
||||
with patch.object(type(PERSISTENCE_FILE), "read_text", return_value=""):
|
||||
result = ProfileManager.load_persisted_profile()
|
||||
assert result is None
|
||||
finally:
|
||||
|
||||
Loading…
Reference in New Issue
Block a user