SYMBOL INDEX (587 symbols across 56 files) FILE: app.py function after_request (line 110) | def after_request(response): function handle_connect (line 139) | def handle_connect(): function handle_disconnect (line 146) | def handle_disconnect(): function on_connect (line 152) | def on_connect(client, userdata, flags, rc, properties=None): function on_disconnect (line 178) | def on_disconnect(client, userdata, rc): function on_message (line 191) | def on_message(client, userdata, msg): function get_message_history (line 234) | def get_message_history(): function get_topic_list (line 301) | def get_topic_list(): function get_database_stats (line 317) | def get_database_stats(): function cleanup_database (line 337) | def cleanup_database(): function get_filter_presets (line 358) | def get_filter_presets(): function save_filter_preset (line 372) | def save_filter_preset(): function delete_filter_preset (line 398) | def delete_filter_preset(name): function use_filter_preset (line 416) | def use_filter_preset(name): function index (line 434) | def index(): function publish_message (line 438) | def publish_message(): function get_stats (line 446) | def get_stats(): function send_static (line 455) | def send_static(path): function get_debug_bar_data (line 459) | def get_debug_bar_data(): function toggle_debug_bar (line 468) | def toggle_debug_bar(): function record_client_performance (line 476) | def record_client_performance(): function get_version (line 483) | def get_version(): function connect_mqtt (line 490) | def connect_mqtt(): FILE: database.py class MessageDatabase (line 13) | class MessageDatabase: method __init__ (line 14) | def __init__(self, db_path: str = "mqtt_messages.db", max_messages: in... method get_connection (line 20) | def get_connection(self): method _regexp (line 35) | def _regexp(self, pattern, value): method init_database (line 42) | def init_database(self): method store_message (line 108) | def store_message(self, topic: str, payload: str, timestamp: datetime ... method get_messages (line 144) | def get_messages(self, limit: int = 100, offset: int = 0, method _apply_python_filters (line 203) | def _apply_python_filters(self, messages: List[Dict], regex_topic: str... method _get_json_path_value (line 228) | def _get_json_path_value(self, json_obj: dict, path: str): method get_topics (line 242) | def get_topics(self) -> List[Dict]: method get_message_count (line 259) | def get_message_count(self, topic_filter: str = None, since: datetime ... method _cleanup_old_messages (line 286) | def _cleanup_old_messages(self): method cleanup_old_data (line 322) | def cleanup_old_data(self, days: int = 30): method get_database_size (line 347) | def get_database_size(self) -> Dict: method save_filter_preset (line 371) | def save_filter_preset(self, name: str, filters: Dict, description: st... method get_filter_presets (line 390) | def get_filter_presets(self) -> List[Dict]: method delete_filter_preset (line 414) | def delete_filter_preset(self, name: str) -> bool: method use_filter_preset (line 432) | def use_filter_preset(self, name: str) -> Optional[Dict]: method close (line 459) | def close(self): FILE: debug_bar.py class DebugBarPanel (line 7) | class DebugBarPanel: method __init__ (line 8) | def __init__(self, name): method record (line 12) | def record(self, key, value): method get_data (line 15) | def get_data(self): class DebugBar (line 18) | class DebugBar: method __init__ (line 19) | def __init__(self): method add_panel (line 30) | def add_panel(self, name): method record (line 35) | def record(self, panel, key, value): method start_request (line 40) | def start_request(self): method end_request (line 43) | def end_request(self): method get_data (line 49) | def get_data(self): method enable (line 54) | def enable(self): method disable (line 57) | def disable(self): method remove (line 60) | def remove(self, panel_name, key): function debug_bar_middleware (line 74) | def debug_bar_middleware(): FILE: mqttui/analytics.py class TopicAnalytics (line 20) | class TopicAnalytics: method __init__ (line 29) | def __init__(self): method record (line 33) | def record(self, topic: str, payload: str, timestamp: float): method _update_histogram (line 59) | def _update_histogram(self, topic: str, field_name: str, value: float): method get_rate (line 78) | def get_rate(self, topic: str, window: int = 60) -> float: method get_topic_stats (line 95) | def get_topic_stats(self, topic: str) -> dict: method get_all_stats (line 110) | def get_all_stats(self, limit: int = 20) -> list: function get_analytics (line 132) | def get_analytics() -> TopicAnalytics: function _on_mqtt_message (line 144) | def _on_mqtt_message(sender, **kwargs): FILE: mqttui/app.py function _on_mqtt_message (line 11) | def _on_mqtt_message(sender, **kwargs): function create_app (line 47) | def create_app(config=None): FILE: mqttui/auth.py function load_user_from_api_key (line 16) | def load_user_from_api_key(): function load_user (line 26) | def load_user(user_id): function seed_admin_user (line 30) | def seed_admin_user(app): function login (line 50) | def login(): function login_post (line 57) | def login_post(): function logout (line 72) | def logout(): FILE: mqttui/broker_manager.py function get_broker_manager (line 36) | def get_broker_manager(): class ManagedConnection (line 40) | class ManagedConnection: method __init__ (line 43) | def __init__(self, broker_id, name, host, port, username=None, passwor... method _on_connect (line 78) | def _on_connect(self, client, userdata, connect_flags, reason_code, pr... method _on_disconnect (line 93) | def _on_disconnect(self, client, userdata, disconnect_flags, reason_co... method _on_message (line 101) | def _on_message(self, client, userdata, msg): method start (line 144) | def start(self): method stop (line 154) | def stop(self): method publish (line 162) | def publish(self, topic, payload, qos=0, retain=False): method status_dict (line 166) | def status_dict(self): class BrokerManager (line 177) | class BrokerManager: method __init__ (line 180) | def __init__(self, app=None): method add_connection (line 184) | def add_connection(self, broker): method remove_connection (line 225) | def remove_connection(self, broker_id): method get_connection (line 230) | def get_connection(self, broker_id): method get_default_connection (line 233) | def get_default_connection(self): method publish (line 243) | def publish(self, topic, payload, qos=0, retain=False, broker_id=None): method all_statuses (line 252) | def all_statuses(self): method start_all (line 255) | def start_all(self, app): method stop_all (line 264) | def stop_all(self): method load_env_broker (line 269) | def load_env_broker(self, app): function init_broker_manager (line 297) | def init_broker_manager(app): FILE: mqttui/database.py class MessageDatabase (line 14) | class MessageDatabase: method __init__ (line 15) | def __init__(self, db_path: str = "mqtt_messages.db", max_messages: in... method get_connection (line 21) | def get_connection(self): method _regexp (line 38) | def _regexp(self, pattern, value): method init_database (line 45) | def init_database(self): method store_message (line 111) | def store_message(self, topic: str, payload: str, timestamp: datetime ... method get_messages (line 147) | def get_messages(self, limit: int = 100, offset: int = 0, method _apply_python_filters (line 206) | def _apply_python_filters(self, messages: List[Dict], regex_topic: str... method _get_json_path_value (line 230) | def _get_json_path_value(self, json_obj: dict, path: str): method get_topics (line 244) | def get_topics(self) -> List[Dict]: method get_message_count (line 261) | def get_message_count(self, topic_filter: str = None, since: datetime ... method _cleanup_old_messages (line 288) | def _cleanup_old_messages(self): method cleanup_old_data (line 321) | def cleanup_old_data(self, days: int = 30): method get_database_size (line 345) | def get_database_size(self) -> Dict: method save_filter_preset (line 369) | def save_filter_preset(self, name: str, filters: Dict, description: st... method get_filter_presets (line 388) | def get_filter_presets(self) -> List[Dict]: method delete_filter_preset (line 412) | def delete_filter_preset(self, name: str) -> bool: method use_filter_preset (line 430) | def use_filter_preset(self, name: str) -> Optional[Dict]: method close (line 455) | def close(self): FILE: mqttui/helpers.py function api_success (line 6) | def api_success(data=None, status_code=200): function api_error (line 11) | def api_error(message, code="UNKNOWN_ERROR", status_code=400): FILE: mqttui/logging_config.py function configure_logging (line 10) | def configure_logging(debug=False, log_level='INFO'): FILE: mqttui/models.py class User (line 7) | class User(UserMixin, sa.Model): method set_password (line 17) | def set_password(self, password): method check_password (line 20) | def check_password(self, password): method generate_api_token (line 23) | def generate_api_token(self): method is_active (line 28) | def is_active(self): class TopicFavorite (line 32) | class TopicFavorite(sa.Model): method to_dict (line 42) | def to_dict(self): class Broker (line 51) | class Broker(sa.Model): method to_dict (line 69) | def to_dict(self): FILE: mqttui/mqtt_client.py function init_mqtt (line 11) | def init_mqtt(app): function get_client (line 18) | def get_client(): function publish (line 29) | def publish(topic, payload, qos=0, retain=False, broker_id=None): FILE: mqttui/plugins/examples/json_formatter.py function main (line 15) | def main(): FILE: mqttui/plugins/examples/topic_logger.py function main (line 15) | def main(): FILE: mqttui/plugins/hookspec.py class MQTTUIPlugin (line 12) | class MQTTUIPlugin: method on_message (line 19) | def on_message(self, topic: str, payload: str) -> dict | None: method on_connect (line 31) | def on_connect(self) -> None: method on_rule_trigger (line 35) | def on_rule_trigger(self, rule_name: str, topic: str, payload: str) ->... FILE: mqttui/plugins/models.py class PluginConfig (line 5) | class PluginConfig(sa.Model): method to_dict (line 17) | def to_dict(self): FILE: mqttui/plugins/registry.py class PluginRegistry (line 17) | class PluginRegistry: method __init__ (line 20) | def __init__(self, app=None): method discover (line 25) | def discover(self) -> list[dict]: method list_plugins (line 73) | def list_plugins(self) -> list[dict]: method get_enabled_plugins (line 77) | def get_enabled_plugins(self) -> list[PluginConfig]: method enable (line 81) | def enable(self, name: str) -> bool: method disable (line 91) | def disable(self, name: str) -> bool: function get_plugin_registry (line 106) | def get_plugin_registry() -> PluginRegistry: function init_plugin_registry (line 111) | def init_plugin_registry(app) -> PluginRegistry: FILE: mqttui/plugins/runner.py class PluginRunner (line 22) | class PluginRunner: method __init__ (line 25) | def __init__(self, app=None): method call_plugin (line 29) | def call_plugin(self, plugin_config, event_type: str, data: dict) -> l... method dispatch_message (line 89) | def dispatch_message(self, topic: str, payload: str) -> list[dict]: method dispatch_actions (line 115) | def dispatch_actions(self, actions: list[dict]): method on_mqtt_message (line 141) | def on_mqtt_message(self, sender, **kwargs): method on_rule_trigger (line 151) | def on_rule_trigger(self, sender, **kwargs): function get_plugin_runner (line 179) | def get_plugin_runner() -> PluginRunner | None: function init_plugin_runner (line 184) | def init_plugin_runner(app) -> PluginRunner: FILE: mqttui/routes/alerts.py function list_alerts (line 18) | def list_alerts(): FILE: mqttui/routes/analytics.py function get_topics (line 20) | def get_topics(): function get_topic (line 44) | def get_topic(topic): FILE: mqttui/routes/api.py function get_message_history (line 14) | def get_message_history(): function get_topic_list (line 76) | def get_topic_list(): function get_database_stats (line 92) | def get_database_stats(): function cleanup_database (line 113) | def cleanup_database(): function get_filter_presets (line 135) | def get_filter_presets(): function save_filter_preset (line 150) | def save_filter_preset(): function delete_filter_preset (line 177) | def delete_filter_preset(name): function use_filter_preset (line 196) | def use_filter_preset(name): FILE: mqttui/routes/api_v1.py function get_messages (line 28) | def get_messages(): function get_topics (line 129) | def get_topics(): function get_favorites (line 160) | def get_favorites(): function toggle_bookmark (line 179) | def toggle_bookmark(topic): function get_database_stats (line 220) | def get_database_stats(): function cleanup_database (line 247) | def cleanup_database(): function get_filter_presets (line 284) | def get_filter_presets(): function save_filter_preset (line 306) | def save_filter_preset(): function delete_filter_preset (line 352) | def delete_filter_preset(name): function use_filter_preset (line 385) | def use_filter_preset(name): function publish_message (line 423) | def publish_message(): function get_stats (line 469) | def get_stats(): function get_version (line 491) | def get_version(): function api_docs (line 508) | def api_docs(): function openapi_spec (line 522) | def openapi_spec(): function get_token (line 550) | def get_token(): function regenerate_token (line 564) | def regenerate_token(): function revoke_token (line 579) | def revoke_token(): function handle_429 (line 597) | def handle_429(e): function handle_404 (line 606) | def handle_404(e): function handle_500 (line 611) | def handle_500(e): FILE: mqttui/routes/brokers.py function list_brokers (line 15) | def list_brokers(): function create_broker (line 37) | def create_broker(): function get_broker (line 70) | def get_broker(broker_id): function update_broker (line 88) | def update_broker(broker_id): function delete_broker (line 118) | def delete_broker(broker_id): function connect_broker (line 136) | def connect_broker(broker_id): function disconnect_broker (line 154) | def disconnect_broker(broker_id): function broker_status (line 172) | def broker_status(): FILE: mqttui/routes/debug.py function debug_bar_middleware (line 10) | def debug_bar_middleware(): function after_request (line 18) | def after_request(response): function get_debug_bar_data (line 27) | def get_debug_bar_data(): function toggle_debug_bar (line 38) | def toggle_debug_bar(): function record_client_performance (line 48) | def record_client_performance(): FILE: mqttui/routes/main.py function index (line 14) | def index(): function publish_message (line 20) | def publish_message(): function get_stats (line 30) | def get_stats(): function get_version (line 41) | def get_version(): function send_static (line 46) | def send_static(path): function alerts_list_partial (line 56) | def alerts_list_partial(): function rules_list_partial (line 92) | def rules_list_partial(): function rule_row_partial (line 101) | def rule_row_partial(rule_id): function rule_form_partial (line 113) | def rule_form_partial(): function rule_edit_form_partial (line 120) | def rule_edit_form_partial(rule_id): function dry_run_form_partial (line 132) | def dry_run_form_partial(rule_id): function rule_toggle_partial (line 139) | def rule_toggle_partial(rule_id): function analytics_partial (line 155) | def analytics_partial(): function rule_delete_partial (line 162) | def rule_delete_partial(rule_id): FILE: mqttui/routes/metrics.py function prometheus_metrics (line 31) | def prometheus_metrics(): function _on_message_for_metrics (line 47) | def _on_message_for_metrics(sender, **kwargs): function _on_rule_fired_for_metrics (line 52) | def _on_rule_fired_for_metrics(sender, **kwargs): function _on_alert_for_metrics (line 57) | def _on_alert_for_metrics(sender, **kwargs): FILE: mqttui/routes/plugins.py function list_plugins (line 17) | def list_plugins(): function enable_plugin (line 30) | def enable_plugin(name): function disable_plugin (line 44) | def disable_plugin(name): function plugins_partial (line 58) | def plugins_partial(): FILE: mqttui/routes/rules.py function list_rules (line 29) | def list_rules(): function create_rule (line 37) | def create_rule(): function _get_rule_or_404 (line 92) | def _get_rule_or_404(rule_id): function get_rule (line 102) | def get_rule(rule_id): function update_rule (line 112) | def update_rule(rule_id): function delete_rule (line 157) | def delete_rule(rule_id): function enable_rule (line 178) | def enable_rule(rule_id): function disable_rule (line 193) | def disable_rule(rule_id): function test_rule (line 212) | def test_rule(rule_id): function _topic_matches (line 280) | def _topic_matches(pattern, topic): function _build_action_preview (line 301) | def _build_action_preview(action, context): FILE: mqttui/rules/actions.py function execute_action (line 20) | def execute_action(action_dict, context): function _execute_publish (line 49) | def _execute_publish(action_dict, context): function _execute_log (line 79) | def _execute_log(action_dict, context): function _execute_webhook (line 102) | def _execute_webhook(action_dict, context): function _build_default_payload (line 163) | def _build_default_payload(context): function _build_webhook_payload (line 174) | def _build_webhook_payload(template, context): function _deliver_webhook (line 203) | def _deliver_webhook(url, payload_json, rule_id, rule_name, topic, function _execute_telegram (line 312) | def _execute_telegram(action_dict, context): function _execute_slack (line 336) | def _execute_slack(action_dict, context): function _substitute_template (line 355) | def _substitute_template(template, context): function _log_suppressed_alert (line 368) | def _log_suppressed_alert(rule_id, rule_name, topic, url, function _log_webhook_history (line 396) | def _log_webhook_history(sa, rule_id, rule_name, topic, url, FILE: mqttui/rules/cooldown.py class CooldownTracker (line 11) | class CooldownTracker: method __init__ (line 19) | def __init__(self, default_seconds=300): method check (line 29) | def check(self, rule_id, cooldown_seconds=None): method get_suppressed_count (line 53) | def get_suppressed_count(self, rule_id): method get_cooldown_until (line 64) | def get_cooldown_until(self, rule_id, cooldown_seconds=None): FILE: mqttui/rules/engine.py function _fire_scheduled_rule (line 28) | def _fire_scheduled_rule(app, rule_id): function get_engine (line 39) | def get_engine(): class RuleEngine (line 44) | class RuleEngine: method __init__ (line 57) | def __init__(self, app=None): method init_scheduler (line 71) | def init_scheduler(self): method fire_scheduled_rule (line 88) | def fire_scheduled_rule(self, rule_id): method sync_scheduled_jobs (line 140) | def sync_scheduled_jobs(self): method reload_cache (line 182) | def reload_cache(self): method _check_rate_limit (line 222) | def _check_rate_limit(self, rule): method on_mqtt_message (line 257) | def on_mqtt_message(self, sender, **kwargs): method _on_rule_changed (line 367) | def _on_rule_changed(self, sender, **kwargs): method connect (line 376) | def connect(self): method disconnect (line 390) | def disconnect(self): class _nullcontext (line 402) | class _nullcontext: method __enter__ (line 405) | def __enter__(self): method __exit__ (line 408) | def __exit__(self, *args): FILE: mqttui/rules/evaluator.py class ConditionError (line 9) | class ConditionError(Exception): function _get_path (line 14) | def _get_path(data, path): function _coerce_numeric (line 35) | def _coerce_numeric(actual, expected): function evaluate (line 48) | def evaluate(condition, payload): FILE: mqttui/rules/models.py class Rule (line 6) | class Rule(sa.Model): method action (line 24) | def action(self): method condition (line 31) | def condition(self): method to_dict (line 37) | def to_dict(self): class AlertHistory (line 55) | class AlertHistory(sa.Model): method to_dict (line 73) | def to_dict(self): FILE: mqttui/rules/ssrf.py function is_ssrf_safe (line 15) | def is_ssrf_safe(url: str) -> tuple: function _check_ip (line 63) | def _check_ip(addr) -> tuple: FILE: mqttui/socketio_batch.py class BatchEmitter (line 5) | class BatchEmitter: method __init__ (line 12) | def __init__(self, socketio: SocketIO, interval_ms: int = 100): method start (line 20) | def start(self): method stop (line 25) | def stop(self): method enqueue (line 31) | def enqueue(self, message: dict): method _schedule_flush (line 36) | def _schedule_flush(self): method _flush (line 44) | def _flush(self): function init_batch_emitter (line 57) | def init_batch_emitter(socketio: SocketIO, interval_ms: int = 100): function get_batch_emitter (line 68) | def get_batch_emitter(): FILE: static/script.js function mqttuiApp (line 24) | function mqttuiApp() { function messageListComponent (line 85) | function messageListComponent() { function statsComponent (line 171) | function statsComponent() { function publishComponent (line 197) | function publishComponent() { function initChart (line 216) | function initChart() { function updateChart (line 288) | function updateChart() { function initNetwork (line 312) | function initNetwork() { function updateNetwork (line 422) | function updateNetwork(message) { function getRandomColor (line 482) | function getRandomColor() { function updateMessageList (line 492) | function updateMessageList(message) { function updateStats (line 497) | function updateStats() { function updateTopicFilter (line 501) | function updateTopicFilter(newTopic) { function loadTopicsFromAPI (line 511) | function loadTopicsFromAPI() { function loadFilteredMessages (line 550) | function loadFilteredMessages(customFilters = {}) { function setupAdvancedSearchHandlers (line 579) | function setupAdvancedSearchHandlers() { function loadFilterPresets (line 791) | function loadFilterPresets() { function initDebugBar (line 817) | function initDebugBar() { function toggleDebugBar (line 840) | function toggleDebugBar() { function closeDebugBar (line 849) | function closeDebugBar() { function trackClientPerformance (line 855) | function trackClientPerformance() { function updateDebugBar (line 884) | function updateDebugBar() { function ruleFormComponent (line 909) | function ruleFormComponent(existing = {}) { function dryRunComponent (line 1008) | function dryRunComponent(ruleId) { function brokersComponent (line 1042) | function brokersComponent() { FILE: tests/conftest.py function app (line 8) | def app(tmp_path): function client (line 35) | def client(app): function test_db (line 41) | def test_db(tmp_path): function auth_client (line 51) | def auth_client(app): function api_token (line 70) | def api_token(app): function mock_mqtt (line 79) | def mock_mqtt(): FILE: tests/test_alerts_api.py function _seed_alerts (line 15) | def _seed_alerts(app, count=25, rule_id=1, severity='info'): function _seed_rule (line 31) | def _seed_rule(app, rule_id=None, action_type='webhook'): class TestListAlerts (line 61) | class TestListAlerts: method test_list_alerts_empty (line 64) | def test_list_alerts_empty(self, auth_client, app): method test_list_alerts_paginated (line 73) | def test_list_alerts_paginated(self, auth_client, app): method test_list_alerts_filter_rule_id (line 84) | def test_list_alerts_filter_rule_id(self, auth_client, app): method test_list_alerts_filter_severity (line 94) | def test_list_alerts_filter_severity(self, auth_client, app): method test_list_alerts_requires_auth (line 104) | def test_list_alerts_requires_auth(self, client): class TestDryRunActionPreview (line 115) | class TestDryRunActionPreview: method test_dry_run_action_preview (line 118) | def test_dry_run_action_preview(self, auth_client, app): method test_dry_run_action_preview_publish (line 139) | def test_dry_run_action_preview_publish(self, auth_client, app): method test_dry_run_action_preview_log (line 155) | def test_dry_run_action_preview_log(self, auth_client, app): method test_dry_run_no_preview_when_no_match (line 171) | def test_dry_run_no_preview_when_no_match(self, auth_client, app): FILE: tests/test_analytics.py class TestTopicAnalytics (line 9) | class TestTopicAnalytics: method setup_method (line 12) | def setup_method(self): method test_record_increments_message_count (line 15) | def test_record_increments_message_count(self): method test_get_rate_per_minute (line 22) | def test_get_rate_per_minute(self): method test_get_rate_per_hour (line 30) | def test_get_rate_per_hour(self): method test_expired_timestamps_not_counted (line 38) | def test_expired_timestamps_not_counted(self): method test_numeric_payload_updates_histogram (line 48) | def test_numeric_payload_updates_histogram(self): method test_non_numeric_payload_does_not_crash (line 60) | def test_non_numeric_payload_does_not_crash(self): method test_get_topic_stats_returns_full_dict (line 69) | def test_get_topic_stats_returns_full_dict(self): method test_get_all_stats_sorted_by_rate (line 81) | def test_get_all_stats_sorted_by_rate(self): class TestAnalyticsAPI (line 100) | class TestAnalyticsAPI: method test_get_topics_returns_200 (line 103) | def test_get_topics_returns_200(self, auth_client, app): method test_get_single_topic_returns_200 (line 118) | def test_get_single_topic_returns_200(self, auth_client, app): method test_get_unknown_topic_returns_404 (line 131) | def test_get_unknown_topic_returns_404(self, auth_client): method test_unauthenticated_request_rejected (line 139) | def test_unauthenticated_request_rejected(self, client): class TestAnalyticsPartial (line 146) | class TestAnalyticsPartial: method test_analytics_partial_returns_200 (line 149) | def test_analytics_partial_returns_200(self, auth_client): method test_analytics_partial_contains_rate_per_min (line 155) | def test_analytics_partial_contains_rate_per_min(self, auth_client): method test_analytics_partial_requires_auth (line 161) | def test_analytics_partial_requires_auth(self, client): FILE: tests/test_api_v1.py function test_json_envelope_success (line 5) | def test_json_envelope_success(auth_client): function test_json_envelope_error (line 16) | def test_json_envelope_error(auth_client): function test_messages_endpoint (line 27) | def test_messages_endpoint(auth_client): function test_topics_endpoint (line 36) | def test_topics_endpoint(auth_client): function test_version_public (line 45) | def test_version_public(client): function test_docs_endpoint (line 53) | def test_docs_endpoint(client): function test_openapi_spec (line 60) | def test_openapi_spec(client): function test_cors_headers (line 70) | def test_cors_headers(client): function test_publish_requires_auth (line 80) | def test_publish_requires_auth(client): function test_stats_requires_auth (line 86) | def test_stats_requires_auth(client): function test_messages_requires_auth (line 92) | def test_messages_requires_auth(client): function test_rate_limit_publish (line 98) | def test_rate_limit_publish(auth_client, app): FILE: tests/test_app_factory.py function test_create_app (line 1) | def test_create_app(app): function test_create_app_has_blueprints (line 6) | def test_create_app_has_blueprints(app): function test_create_app_custom_config (line 13) | def test_create_app_custom_config(tmp_path): function test_socketio_async_mode (line 31) | def test_socketio_async_mode(app): FILE: tests/test_auth.py function test_login_page_loads (line 4) | def test_login_page_loads(client): function test_unauthenticated_redirect (line 12) | def test_unauthenticated_redirect(client): function test_login_valid_credentials (line 19) | def test_login_valid_credentials(client, app): function test_login_invalid_credentials (line 35) | def test_login_invalid_credentials(client, app): function test_logout (line 42) | def test_logout(auth_client): function test_api_token_auth (line 49) | def test_api_token_auth(client, api_token): function test_api_token_invalid (line 58) | def test_api_token_invalid(client): function test_secret_key_guard (line 65) | def test_secret_key_guard(): function test_token_get (line 84) | def test_token_get(auth_client, app): function test_token_regenerate (line 94) | def test_token_regenerate(auth_client, app): function test_token_revoke (line 104) | def test_token_revoke(auth_client, app): FILE: tests/test_cooldown.py class TestCooldownTracker (line 14) | class TestCooldownTracker: method test_cooldown_allows_first_alert (line 17) | def test_cooldown_allows_first_alert(self): method test_cooldown_blocks_during_window (line 22) | def test_cooldown_blocks_during_window(self): method test_cooldown_allows_after_expiry (line 28) | def test_cooldown_allows_after_expiry(self): method test_cooldown_different_rules_independent (line 38) | def test_cooldown_different_rules_independent(self): method test_cooldown_custom_window (line 48) | def test_cooldown_custom_window(self): method test_cooldown_suppressed_count (line 63) | def test_cooldown_suppressed_count(self): method test_cooldown_suppressed_count_resets_on_new_fire (line 75) | def test_cooldown_suppressed_count_resets_on_new_fire(self): class TestWebhookCooldownIntegration (line 94) | class TestWebhookCooldownIntegration: method test_webhook_skipped_during_cooldown (line 97) | def test_webhook_skipped_during_cooldown(self, app): FILE: tests/test_database.py function test_wal_mode (line 4) | def test_wal_mode(test_db): function test_busy_timeout (line 10) | def test_busy_timeout(test_db): function test_store_and_retrieve (line 16) | def test_store_and_retrieve(test_db): function test_get_topics (line 31) | def test_get_topics(test_db): function test_message_count (line 40) | def test_message_count(test_db): FILE: tests/test_frontend.py class TestPartialRoutes (line 6) | class TestPartialRoutes: method test_rules_list_partial_returns_html (line 9) | def test_rules_list_partial_returns_html(self, auth_client): method test_alerts_list_partial_returns_html (line 14) | def test_alerts_list_partial_returns_html(self, auth_client): method test_rule_form_partial_returns_html (line 19) | def test_rule_form_partial_returns_html(self, auth_client): method test_partials_require_auth (line 24) | def test_partials_require_auth(self, client): class TestIndexTemplate (line 31) | class TestIndexTemplate: method test_index_contains_alpine (line 34) | def test_index_contains_alpine(self, auth_client): method test_index_contains_htmx (line 39) | def test_index_contains_htmx(self, auth_client): method test_index_contains_tabs (line 43) | def test_index_contains_tabs(self, auth_client): method test_index_contains_alpine_xdata (line 50) | def test_index_contains_alpine_xdata(self, auth_client): class TestBatchEmitter (line 55) | class TestBatchEmitter: method test_enqueue_adds_to_buffer (line 58) | def test_enqueue_adds_to_buffer(self): method test_flush_emits_batch_and_clears (line 65) | def test_flush_emits_batch_and_clears(self): method test_flush_noop_when_empty (line 78) | def test_flush_noop_when_empty(self): FILE: tests/test_observability.py class TestStructlogConfiguration (line 6) | class TestStructlogConfiguration: method test_configure_logging_debug_uses_console_renderer (line 9) | def test_configure_logging_debug_uses_console_renderer(self): method test_configure_logging_production_uses_json_renderer (line 29) | def test_configure_logging_production_uses_json_renderer(self): method test_structlog_get_logger_returns_bound_logger (line 44) | def test_structlog_get_logger_returns_bound_logger(self): class TestPrometheusMetricsEndpoint (line 56) | class TestPrometheusMetricsEndpoint: method test_metrics_returns_200 (line 59) | def test_metrics_returns_200(self, client): method test_metrics_contains_mqtt_messages_total (line 65) | def test_metrics_contains_mqtt_messages_total(self, client): method test_metrics_contains_mqtt_connected_gauge (line 70) | def test_metrics_contains_mqtt_connected_gauge(self, client): method test_metrics_contains_rule_firings_total (line 75) | def test_metrics_contains_rule_firings_total(self, client): method test_metrics_no_auth_required (line 80) | def test_metrics_no_auth_required(self, client): FILE: tests/test_plugin_registry.py function _ensure_plugin_table (line 7) | def _ensure_plugin_table(app): class TestMQTTUIPluginHookspec (line 15) | class TestMQTTUIPluginHookspec: method test_has_on_message_hookspec (line 18) | def test_has_on_message_hookspec(self): method test_has_on_connect_hookspec (line 22) | def test_has_on_connect_hookspec(self): method test_has_on_rule_trigger_hookspec (line 26) | def test_has_on_rule_trigger_hookspec(self): method test_hookspec_markers_applied (line 30) | def test_hookspec_markers_applied(self): method test_hookimpl_marker_exported (line 37) | def test_hookimpl_marker_exported(self): class TestPluginConfigModel (line 42) | class TestPluginConfigModel: method test_create_plugin_config (line 45) | def test_create_plugin_config(self, app): method test_update_enabled_state (line 66) | def test_update_enabled_state(self, app): method test_to_dict (line 85) | def test_to_dict(self, app): class TestPluginRegistry (line 110) | class TestPluginRegistry: method test_discover_with_no_entry_points (line 113) | def test_discover_with_no_entry_points(self, app): method test_discover_with_mock_entry_point (line 122) | def test_discover_with_mock_entry_point(self, app): method test_list_plugins (line 142) | def test_list_plugins(self, app): method test_enable_plugin (line 161) | def test_enable_plugin(self, app): method test_disable_plugin (line 182) | def test_disable_plugin(self, app): method test_enable_nonexistent_returns_false (line 203) | def test_enable_nonexistent_returns_false(self, app): method test_disable_nonexistent_returns_false (line 209) | def test_disable_nonexistent_returns_false(self, app): method test_get_enabled_plugins (line 215) | def test_get_enabled_plugins(self, app): FILE: tests/test_plugin_runner.py function runner (line 12) | def runner(): function mock_plugin (line 18) | def mock_plugin(): class TestCallPlugin (line 28) | class TestCallPlugin: method test_spawns_subprocess_with_correct_args (line 31) | def test_spawns_subprocess_with_correct_args(self, runner, mock_plugin): method test_sends_json_on_stdin (line 46) | def test_sends_json_on_stdin(self, runner, mock_plugin): method test_parses_valid_json_response (line 62) | def test_parses_valid_json_response(self, runner, mock_plugin): method test_timeout_kills_subprocess (line 74) | def test_timeout_kills_subprocess(self, runner, mock_plugin): method test_invalid_json_returns_empty (line 86) | def test_invalid_json_returns_empty(self, runner, mock_plugin): method test_empty_env_for_security_isolation (line 97) | def test_empty_env_for_security_isolation(self, runner, mock_plugin): class TestDispatchMessage (line 111) | class TestDispatchMessage: method test_calls_all_enabled_plugins (line 114) | def test_calls_all_enabled_plugins(self, runner): method test_collects_all_actions (line 130) | def test_collects_all_actions(self, runner): class TestDispatchActions (line 150) | class TestDispatchActions: method test_publish_action (line 153) | def test_publish_action(self, runner): method test_log_action (line 161) | def test_log_action(self, runner): method test_unknown_action_type (line 167) | def test_unknown_action_type(self, runner): class TestPluginTimeout (line 174) | class TestPluginTimeout: method test_timeout_is_5_seconds (line 177) | def test_timeout_is_5_seconds(self): FILE: tests/test_plugins_api.py class TestPluginsAPI (line 12) | class TestPluginsAPI: method seed_plugin (line 16) | def seed_plugin(self, app): method test_list_plugins (line 32) | def test_list_plugins(self, auth_client): method test_enable_plugin (line 42) | def test_enable_plugin(self, auth_client, app): method test_disable_plugin (line 56) | def test_disable_plugin(self, auth_client, app): method test_enable_nonexistent_returns_404 (line 72) | def test_enable_nonexistent_returns_404(self, auth_client): method test_disable_nonexistent_returns_404 (line 79) | def test_disable_nonexistent_returns_404(self, auth_client): method test_partials_plugins_returns_html (line 86) | def test_partials_plugins_returns_html(self, auth_client): class TestJsonFormatterPlugin (line 96) | class TestJsonFormatterPlugin: method test_formats_json_payload (line 99) | def test_formats_json_payload(self): method test_non_json_payload_returns_empty_actions (line 119) | def test_non_json_payload_returns_empty_actions(self): method test_non_message_event_returns_empty_actions (line 135) | def test_non_message_event_returns_empty_actions(self): class TestTopicLoggerPlugin (line 152) | class TestTopicLoggerPlugin: method test_logs_message (line 155) | def test_logs_message(self): method test_logs_to_stderr (line 174) | def test_logs_to_stderr(self): FILE: tests/test_routes.py function test_index_redirects_unauthenticated (line 1) | def test_index_redirects_unauthenticated(client): function test_index_returns_200_authenticated (line 8) | def test_index_returns_200_authenticated(client, app): function test_stats_returns_json (line 16) | def test_stats_returns_json(client): function test_version_returns_json (line 26) | def test_version_returns_json(client): function test_api_messages_returns_json (line 33) | def test_api_messages_returns_json(client): function test_api_topics_returns_json (line 40) | def test_api_topics_returns_json(client): function test_database_stats (line 47) | def test_database_stats(client): FILE: tests/test_rules_api.py function _create_rule (line 9) | def _create_rule(auth_client, **overrides): function test_list_rules_empty (line 25) | def test_list_rules_empty(auth_client): function test_list_rules_with_data (line 34) | def test_list_rules_with_data(auth_client): function test_create_rule (line 48) | def test_create_rule(auth_client): function test_create_rule_missing_name (line 63) | def test_create_rule_missing_name(auth_client): function test_create_rule_missing_action (line 75) | def test_create_rule_missing_action(auth_client): function test_create_rule_missing_trigger_topic (line 87) | def test_create_rule_missing_trigger_topic(auth_client): function test_get_rule (line 102) | def test_get_rule(auth_client): function test_get_rule_not_found (line 111) | def test_get_rule_not_found(auth_client): function test_update_rule (line 123) | def test_update_rule(auth_client): function test_update_rule_not_found (line 140) | def test_update_rule_not_found(auth_client): function test_delete_rule (line 150) | def test_delete_rule(auth_client): function test_delete_rule_not_found (line 164) | def test_delete_rule_not_found(auth_client): function test_enable_disable (line 174) | def test_enable_disable(auth_client): function test_enable_not_found (line 190) | def test_enable_not_found(auth_client): function test_dry_run_match (line 200) | def test_dry_run_match(auth_client): function test_dry_run_no_match_condition (line 218) | def test_dry_run_no_match_condition(auth_client): function test_dry_run_no_match_topic (line 235) | def test_dry_run_no_match_topic(auth_client): function test_dry_run_dict_payload (line 250) | def test_dry_run_dict_payload(auth_client): function test_dry_run_missing_topic (line 263) | def test_dry_run_missing_topic(auth_client): function test_unauthenticated_access (line 278) | def test_unauthenticated_access(client): FILE: tests/test_rules_engine.py function _create_rule (line 17) | def _create_rule(app, **overrides): function _send_message (line 38) | def _send_message(topic, payload_dict): function engine (line 51) | def engine(app): function fire_log (line 63) | def fire_log(): class TestLoopPrevention (line 79) | class TestLoopPrevention: method test_loop_prevention_skips_automation_messages (line 82) | def test_loop_prevention_skips_automation_messages(self, app, engine, ... class TestTopicMatching (line 95) | class TestTopicMatching: method test_wildcard_topic_matching (line 98) | def test_wildcard_topic_matching(self, app, engine, fire_log): method test_non_matching_topic (line 109) | def test_non_matching_topic(self, app, engine, fire_log): class TestConditionEvaluation (line 119) | class TestConditionEvaluation: method test_matching_condition_fires (line 122) | def test_matching_condition_fires(self, app, engine, fire_log): method test_non_matching_condition_does_not_fire (line 136) | def test_non_matching_condition_does_not_fire(self, app, engine, fire_... class TestDisabledRule (line 150) | class TestDisabledRule: method test_disabled_rule_not_in_cache (line 153) | def test_disabled_rule_not_in_cache(self, app, engine, fire_log): class TestPerRuleRateLimit (line 163) | class TestPerRuleRateLimit: method test_rate_limit_blocks_excess (line 166) | def test_rate_limit_blocks_excess(self, app, engine, fire_log): class TestGlobalCircuitBreaker (line 182) | class TestGlobalCircuitBreaker: method test_global_limit_blocks_excess (line 185) | def test_global_limit_blocks_excess(self, app, engine, fire_log): class TestPublishActionSourceMarker (line 206) | class TestPublishActionSourceMarker: method test_publish_injects_source_marker (line 209) | def test_publish_injects_source_marker(self, app): class TestLogActionCreatesAlert (line 226) | class TestLogActionCreatesAlert: method test_log_creates_alert_history (line 229) | def test_log_creates_alert_history(self, app): class TestRuleFiredSignal (line 246) | class TestRuleFiredSignal: method test_signal_emitted_on_fire (line 249) | def test_signal_emitted_on_fire(self, app, engine, fire_log): class TestHotReload (line 272) | class TestHotReload: method test_hot_reload_on_rule_changed (line 275) | def test_hot_reload_on_rule_changed(self, app, engine): class TestCronScheduleSync (line 298) | class TestCronScheduleSync: method test_cron_schedule_sync (line 301) | def test_cron_schedule_sync(self, app, engine): method test_removed_rule_job_cleaned_up (line 316) | def test_removed_rule_job_cleaned_up(self, app, engine): class TestFireScheduledRule (line 331) | class TestFireScheduledRule: method test_fire_scheduled_rule (line 334) | def test_fire_scheduled_rule(self, app, engine): method test_fire_scheduled_rule_missing_id (line 354) | def test_fire_scheduled_rule_missing_id(self, app, engine): class TestAppCreatesRuleEngine (line 362) | class TestAppCreatesRuleEngine: method test_rules_blueprint_registered (line 365) | def test_rules_blueprint_registered(self, app): FILE: tests/test_rules_evaluator.py function test_simple_gt_true (line 6) | def test_simple_gt_true(): function test_simple_gt_false (line 11) | def test_simple_gt_false(): function test_nested_path_eq (line 16) | def test_nested_path_eq(): function test_compound_all_true (line 23) | def test_compound_all_true(): function test_compound_all_false (line 32) | def test_compound_all_false(): function test_compound_any_true (line 41) | def test_compound_any_true(): function test_compound_any_false (line 50) | def test_compound_any_false(): function test_contains (line 59) | def test_contains(): function test_not_contains (line 64) | def test_not_contains(): function test_regex_match (line 69) | def test_regex_match(): function test_regex_no_match (line 74) | def test_regex_no_match(): function test_exists_true (line 79) | def test_exists_true(): function test_exists_false (line 84) | def test_exists_false(): function test_not_exists_true (line 89) | def test_not_exists_true(): function test_not_exists_false (line 94) | def test_not_exists_false(): function test_non_json_payload_returns_false (line 99) | def test_non_json_payload_returns_false(): function test_numeric_coercion (line 104) | def test_numeric_coercion(): function test_numeric_coercion_lt (line 109) | def test_numeric_coercion_lt(): function test_empty_condition_always_true (line 114) | def test_empty_condition_always_true(): function test_none_condition_always_true (line 119) | def test_none_condition_always_true(): function test_unknown_operator_raises (line 124) | def test_unknown_operator_raises(): function test_eq_operator (line 130) | def test_eq_operator(): function test_ne_operator (line 136) | def test_ne_operator(): function test_gte_operator (line 142) | def test_gte_operator(): function test_lte_operator (line 148) | def test_lte_operator(): function test_missing_path_returns_false (line 154) | def test_missing_path_returns_false(): FILE: tests/test_rules_models.py function test_rule_model_columns (line 6) | def test_rule_model_columns(app): function test_rule_tablename (line 21) | def test_rule_tablename(app): function test_rule_to_dict (line 28) | def test_rule_to_dict(app): function test_alert_history_model_columns (line 57) | def test_alert_history_model_columns(app): function test_alert_history_tablename (line 67) | def test_alert_history_tablename(app): function test_alert_history_to_dict (line 74) | def test_alert_history_to_dict(app): FILE: tests/test_ux_features.py class TestTopicFavorites (line 5) | class TestTopicFavorites: method test_bookmark_creates_favorite (line 8) | def test_bookmark_creates_favorite(self, auth_client, app): method test_bookmark_toggle_removes_favorite (line 16) | def test_bookmark_toggle_removes_favorite(self, auth_client, app): method test_get_favorites_returns_bookmarked_topics (line 27) | def test_get_favorites_returns_bookmarked_topics(self, auth_client, app): method test_topics_includes_is_favorite (line 43) | def test_topics_includes_is_favorite(self, auth_client, app): method test_unauthenticated_bookmark_rejected (line 57) | def test_unauthenticated_bookmark_rejected(self, client): FILE: tests/test_webhook.py class TestSSRFValidator (line 14) | class TestSSRFValidator: method test_ssrf_blocks_private_10 (line 17) | def test_ssrf_blocks_private_10(self): method test_ssrf_blocks_private_172 (line 23) | def test_ssrf_blocks_private_172(self): method test_ssrf_blocks_private_192 (line 28) | def test_ssrf_blocks_private_192(self): method test_ssrf_blocks_localhost (line 33) | def test_ssrf_blocks_localhost(self): method test_ssrf_blocks_link_local (line 38) | def test_ssrf_blocks_link_local(self): method test_ssrf_allows_public (line 46) | def test_ssrf_allows_public(self, mock_dns): method test_ssrf_blocks_ipv6_localhost (line 51) | def test_ssrf_blocks_ipv6_localhost(self): class TestWebhookDelivery (line 61) | class TestWebhookDelivery: method test_webhook_success (line 65) | def test_webhook_success(self, mock_post, app): method test_webhook_retry_on_5xx (line 93) | def test_webhook_retry_on_5xx(self, mock_post, app): method test_webhook_no_retry_on_4xx (line 123) | def test_webhook_no_retry_on_4xx(self, mock_post, app): method test_webhook_payload_template (line 150) | def test_webhook_payload_template(self, app): method test_webhook_runs_in_thread (line 166) | def test_webhook_runs_in_thread(self, mock_post, app): class TestSSRFEndpoints (line 193) | class TestSSRFEndpoints: method test_create_rule_ssrf_blocked (line 196) | def test_create_rule_ssrf_blocked(self, auth_client, app): method test_create_rule_ssrf_allowed (line 214) | def test_create_rule_ssrf_allowed(self, mock_dns, auth_client, app): method test_update_rule_ssrf_blocked (line 227) | def test_update_rule_ssrf_blocked(self, auth_client, app):