Phase 6 — Events + Rule Engine: - EventProcessor subprocess: subscribes to all MQTT events, logs to DB, evaluates rules, fires alert actions - ArmStateFSM: DISARMED/ARMED_HOME/ARMED_AWAY with PIN verification (HMAC-safe), DB persistence, MQTT state publishing - RuleEngine: AND/OR logic, 4 condition types (arm_state, sensor_event, camera_motion, time_window), per-rule cooldown tracking - SSE event stream with subscriber queue pattern and keepalive - Event acknowledge endpoint Phase 7 — Sensor Bridge: - SensorBridge subprocess: subscribes to Zigbee2MQTT, normalizes payloads (contact, occupancy, temperature, humidity, battery, linkquality) - GPIOHandler: conditional gpiozero import, callbacks for reed switches and PIR sensors - SensorRegistry: maps Zigbee addresses and names to config sensor IDs - SensorEvent/SensorState dataclasses - Web UI now shows real sensor states from DB Phase 8 — UPS Monitor: - UPSMonitor subprocess: polls NUT via pynut2 with reconnect backoff - State transition detection: OL→OB (power_loss), charge/runtime thresholds (low_battery, critical), OB→OL (restored) - ShutdownSequence: ordered shutdown with configurable delay and command - All conditionally imported (pynut2, gpiozero) for non-target platforms Fixed test_db fixture to use isolated engines (no global singleton leak). 96 tests passing. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
45 lines
1.1 KiB
Python
45 lines
1.1 KiB
Python
"""Pytest fixtures for Vigilar tests."""
|
|
|
|
import os
|
|
import tempfile
|
|
from pathlib import Path
|
|
|
|
import pytest
|
|
from sqlalchemy import create_engine, event
|
|
|
|
from vigilar.config import VigilarConfig, load_config
|
|
from vigilar.storage.schema import metadata
|
|
|
|
|
|
def _create_test_engine(db_path: Path):
|
|
"""Create a fresh engine for testing (bypasses the global singleton)."""
|
|
db_path.parent.mkdir(parents=True, exist_ok=True)
|
|
engine = create_engine(f"sqlite:///{db_path}", echo=False)
|
|
metadata.create_all(engine)
|
|
return engine
|
|
|
|
|
|
@pytest.fixture
|
|
def tmp_data_dir(tmp_path):
|
|
"""Temporary data directory for tests."""
|
|
data_dir = tmp_path / "data"
|
|
data_dir.mkdir()
|
|
return data_dir
|
|
|
|
|
|
@pytest.fixture
|
|
def test_db(tmp_path):
|
|
"""Create an isolated test database (no shared state between tests)."""
|
|
db_path = tmp_path / "data" / "test.db"
|
|
return _create_test_engine(db_path)
|
|
|
|
|
|
@pytest.fixture
|
|
def sample_config():
|
|
"""Return a minimal VigilarConfig for testing."""
|
|
return VigilarConfig(
|
|
cameras=[],
|
|
sensors=[],
|
|
rules=[],
|
|
)
|