mirror of
https://github.com/jokob-sk/NetAlertX.git
synced 2026-03-31 07:12:23 -07:00
Refactor event and session column names to camelCase
- Updated test cases to reflect new column names (eve_MAC -> eveMac, eve_DateTime -> eveDateTime, etc.) across various test files. - Modified SQL table definitions in the database cleanup and migration tests to use camelCase naming conventions. - Implemented migration tests to ensure legacy column names are correctly renamed to camelCase equivalents. - Ensured that existing data is preserved during the migration process and that views referencing old column names are dropped before renaming. - Verified that the migration function is idempotent, allowing for safe re-execution without data loss.
This commit is contained in:
@@ -61,7 +61,7 @@ def test_create_event(client, api_token, test_mac):
|
||||
resp = list_events(client, api_token, test_mac)
|
||||
assert resp.status_code == 200
|
||||
events = resp.get_json().get("events", [])
|
||||
assert any(ev.get("eve_MAC") == test_mac for ev in events)
|
||||
assert any(ev.get("eveMac") == test_mac for ev in events)
|
||||
|
||||
|
||||
def test_delete_events_for_mac(client, api_token, test_mac):
|
||||
@@ -73,7 +73,7 @@ def test_delete_events_for_mac(client, api_token, test_mac):
|
||||
resp = list_events(client, api_token, test_mac)
|
||||
assert resp.status_code == 200
|
||||
events = resp.json.get("events", [])
|
||||
assert any(ev["eve_MAC"] == test_mac for ev in events)
|
||||
assert any(ev["eveMac"] == test_mac for ev in events)
|
||||
|
||||
# delete
|
||||
resp = client.delete(f"/events/{test_mac}", headers=auth_headers(api_token))
|
||||
@@ -143,10 +143,10 @@ def test_delete_events_dynamic_days(client, api_token, test_mac):
|
||||
thirty_days_ago = timeNowUTC(as_string=False) - timedelta(days=30)
|
||||
initial_younger_count = 0
|
||||
for ev in initial_events:
|
||||
if ev.get("eve_MAC") == test_mac and ev.get("eve_DateTime"):
|
||||
if ev.get("eveMac") == test_mac and ev.get("eveDateTime"):
|
||||
try:
|
||||
# Parse event datetime (handle ISO format)
|
||||
ev_time_str = ev["eve_DateTime"]
|
||||
ev_time_str = ev["eveDateTime"]
|
||||
# Try parsing with timezone info
|
||||
try:
|
||||
ev_time = datetime.fromisoformat(ev_time_str.replace("Z", "+00:00"))
|
||||
@@ -176,6 +176,6 @@ def test_delete_events_dynamic_days(client, api_token, test_mac):
|
||||
# confirm only recent events remain (pre-existing younger + newly created 5-day-old)
|
||||
resp = list_events(client, api_token, test_mac)
|
||||
events = resp.get_json().get("events", [])
|
||||
mac_events = [ev for ev in events if ev.get("eve_MAC") == test_mac]
|
||||
mac_events = [ev for ev in events if ev.get("eveMac") == test_mac]
|
||||
expected_remaining = initial_younger_count + 1 # 1 for the 5-day-old event we created
|
||||
assert len(mac_events) == expected_remaining
|
||||
|
||||
@@ -116,7 +116,7 @@ def test_get_open_ports_ip(mock_device_db_conn, mock_plugin_db_conn, client, api
|
||||
mock_execute_result = MagicMock()
|
||||
|
||||
# Mock for PluginObjectInstance.getByField (returns port data)
|
||||
mock_execute_result.fetchall.return_value = [{"Object_SecondaryID": "22", "Watched_Value2": "ssh"}, {"Object_SecondaryID": "80", "Watched_Value2": "http"}]
|
||||
mock_execute_result.fetchall.return_value = [{"objectSecondaryId": "22", "watchedValue2": "ssh"}, {"objectSecondaryId": "80", "watchedValue2": "http"}]
|
||||
# Mock for DeviceInstance.getByIP (returns device with MAC)
|
||||
mock_execute_result.fetchone.return_value = {"devMac": "aa:bb:cc:dd:ee:ff"}
|
||||
|
||||
@@ -141,7 +141,7 @@ def test_get_open_ports_mac_resolve(mock_plugin_db_conn, client, api_token):
|
||||
# Mock database connection for MAC-based open ports query
|
||||
mock_conn = MagicMock()
|
||||
mock_execute_result = MagicMock()
|
||||
mock_execute_result.fetchall.return_value = [{"Object_SecondaryID": "80", "Watched_Value2": "http"}]
|
||||
mock_execute_result.fetchall.return_value = [{"objectSecondaryId": "80", "watchedValue2": "http"}]
|
||||
mock_conn.execute.return_value = mock_execute_result
|
||||
mock_plugin_db_conn.return_value = mock_conn
|
||||
|
||||
@@ -189,7 +189,7 @@ def test_get_recent_alerts(mock_db_conn, client, api_token):
|
||||
mock_conn = MagicMock()
|
||||
mock_execute_result = MagicMock()
|
||||
now = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
|
||||
mock_execute_result.fetchall.return_value = [{"eve_DateTime": now, "eve_EventType": "New Device", "eve_MAC": "aa:bb:cc:dd:ee:ff"}]
|
||||
mock_execute_result.fetchall.return_value = [{"eveDateTime": now, "eveEventType": "New Device", "eveMac": "aa:bb:cc:dd:ee:ff"}]
|
||||
mock_conn.execute.return_value = mock_execute_result
|
||||
mock_db_conn.return_value = mock_conn
|
||||
|
||||
|
||||
@@ -74,7 +74,7 @@ def test_list_sessions(client, api_token, test_mac):
|
||||
assert resp.status_code == 200
|
||||
assert resp.json.get("success") is True
|
||||
sessions = resp.json.get("sessions")
|
||||
assert any(ses["ses_MAC"] == test_mac for ses in sessions)
|
||||
assert any(ses["sesMac"] == test_mac for ses in sessions)
|
||||
|
||||
|
||||
def test_device_sessions_by_period(client, api_token, test_mac):
|
||||
@@ -105,7 +105,7 @@ def test_device_sessions_by_period(client, api_token, test_mac):
|
||||
print(test_mac)
|
||||
|
||||
assert isinstance(sessions, list)
|
||||
assert any(s["ses_MAC"] == test_mac for s in sessions)
|
||||
assert any(s["sesMac"] == test_mac for s in sessions)
|
||||
|
||||
|
||||
def test_device_session_events(client, api_token, test_mac):
|
||||
@@ -178,7 +178,7 @@ def test_delete_session(client, api_token, test_mac):
|
||||
# Confirm deletion
|
||||
resp = client.get(f"/sessions/list?mac={test_mac}", headers=auth_headers(api_token))
|
||||
sessions = resp.json.get("sessions")
|
||||
assert not any(ses["ses_MAC"] == test_mac for ses in sessions)
|
||||
assert not any(ses["sesMac"] == test_mac for ses in sessions)
|
||||
|
||||
|
||||
def test_get_sessions_calendar(client, api_token, test_mac):
|
||||
|
||||
@@ -20,10 +20,10 @@ class SafeConditionBuilder:
|
||||
|
||||
# Whitelist of allowed column names for filtering
|
||||
ALLOWED_COLUMNS = {
|
||||
"eve_MAC",
|
||||
"eve_DateTime",
|
||||
"eve_IP",
|
||||
"eve_EventType",
|
||||
"eveMac",
|
||||
"eveDateTime",
|
||||
"eveIp",
|
||||
"eveEventType",
|
||||
"devName",
|
||||
"devComments",
|
||||
"devLastIP",
|
||||
@@ -34,15 +34,15 @@ class SafeConditionBuilder:
|
||||
"devPresentLastScan",
|
||||
"devFavorite",
|
||||
"devIsNew",
|
||||
"Plugin",
|
||||
"Object_PrimaryId",
|
||||
"Object_SecondaryId",
|
||||
"DateTimeChanged",
|
||||
"Watched_Value1",
|
||||
"Watched_Value2",
|
||||
"Watched_Value3",
|
||||
"Watched_Value4",
|
||||
"Status",
|
||||
"plugin",
|
||||
"objectPrimaryId",
|
||||
"objectSecondaryId",
|
||||
"dateTimeChanged",
|
||||
"watchedValue1",
|
||||
"watchedValue2",
|
||||
"watchedValue3",
|
||||
"watchedValue4",
|
||||
"status",
|
||||
}
|
||||
|
||||
# Whitelist of allowed comparison operators
|
||||
@@ -403,7 +403,7 @@ class SafeConditionBuilder:
|
||||
This method handles basic patterns like:
|
||||
- devName = 'value' (with optional AND/OR prefix)
|
||||
- devComments LIKE '%value%'
|
||||
- eve_EventType IN ('type1', 'type2')
|
||||
- eveEventType IN ('type1', 'type2')
|
||||
|
||||
Args:
|
||||
condition: Single condition string to parse
|
||||
@@ -633,7 +633,7 @@ class SafeConditionBuilder:
|
||||
self.parameters[param_name] = event_type
|
||||
param_names.append(f":{param_name}")
|
||||
|
||||
sql_snippet = f"AND eve_EventType IN ({', '.join(param_names)})"
|
||||
sql_snippet = f"AND eveEventType IN ({', '.join(param_names)})"
|
||||
return sql_snippet, self.parameters
|
||||
|
||||
def get_safe_condition_legacy(
|
||||
|
||||
@@ -174,7 +174,7 @@ def test_compound_with_like_patterns(builder):
|
||||
|
||||
def test_compound_with_inequality_operators(builder):
|
||||
"""Test compound conditions with various inequality operators."""
|
||||
condition = "AND eve_DateTime > '2024-01-01' AND eve_DateTime < '2024-12-31'"
|
||||
condition = "AND eveDateTime > '2024-01-01' AND eveDateTime < '2024-12-31'"
|
||||
|
||||
sql, params = builder.build_safe_condition(condition)
|
||||
|
||||
|
||||
@@ -32,25 +32,25 @@ def _make_json(section, devices, column_names, title="Test Section"):
|
||||
SAMPLE_NEW_DEVICES = [
|
||||
{
|
||||
"devName": "MyPhone",
|
||||
"eve_MAC": "aa:bb:cc:dd:ee:ff",
|
||||
"eveMac": "aa:bb:cc:dd:ee:ff",
|
||||
"devVendor": "",
|
||||
"eve_IP": "192.168.1.42",
|
||||
"eve_DateTime": "2025-01-15 10:30:00",
|
||||
"eve_EventType": "New Device",
|
||||
"eveIp": "192.168.1.42",
|
||||
"eveDateTime": "2025-01-15 10:30:00",
|
||||
"eveEventType": "New Device",
|
||||
"devComments": "",
|
||||
},
|
||||
{
|
||||
"devName": "Laptop",
|
||||
"eve_MAC": "11:22:33:44:55:66",
|
||||
"eveMac": "11:22:33:44:55:66",
|
||||
"devVendor": "Dell",
|
||||
"eve_IP": "192.168.1.99",
|
||||
"eve_DateTime": "2025-01-15 11:00:00",
|
||||
"eve_EventType": "New Device",
|
||||
"eveIp": "192.168.1.99",
|
||||
"eveDateTime": "2025-01-15 11:00:00",
|
||||
"eveEventType": "New Device",
|
||||
"devComments": "Office",
|
||||
},
|
||||
]
|
||||
|
||||
NEW_DEVICE_COLUMNS = ["devName", "eve_MAC", "devVendor", "eve_IP", "eve_DateTime", "eve_EventType", "devComments"]
|
||||
NEW_DEVICE_COLUMNS = ["devName", "eveMac", "devVendor", "eveIp", "eveDateTime", "eveEventType", "devComments"]
|
||||
|
||||
|
||||
class TestConstructNotificationsTemplates(unittest.TestCase):
|
||||
@@ -100,7 +100,7 @@ class TestConstructNotificationsTemplates(unittest.TestCase):
|
||||
self.assertIn("---------", text)
|
||||
|
||||
# Legacy format: each header appears as "Header: \tValue"
|
||||
self.assertIn("eve_MAC:", text)
|
||||
self.assertIn("eveMac:", text)
|
||||
self.assertIn("aa:bb:cc:dd:ee:ff", text)
|
||||
self.assertIn("devName:", text)
|
||||
self.assertIn("MyPhone", text)
|
||||
@@ -117,7 +117,7 @@ class TestConstructNotificationsTemplates(unittest.TestCase):
|
||||
|
||||
mock_setting.side_effect = self._setting_factory({
|
||||
"NTFPRCS_TEXT_SECTION_HEADERS": True,
|
||||
"NTFPRCS_TEXT_TEMPLATE_new_devices": "{devName} ({eve_MAC}) - {eve_IP}",
|
||||
"NTFPRCS_TEXT_TEMPLATE_new_devices": "{devName} ({eveMac}) - {eveIp}",
|
||||
})
|
||||
|
||||
json_data = _make_json(
|
||||
@@ -157,7 +157,7 @@ class TestConstructNotificationsTemplates(unittest.TestCase):
|
||||
|
||||
mock_setting.side_effect = self._setting_factory({
|
||||
"NTFPRCS_TEXT_SECTION_HEADERS": False,
|
||||
"NTFPRCS_TEXT_TEMPLATE_new_devices": "{devName} ({eve_MAC})",
|
||||
"NTFPRCS_TEXT_TEMPLATE_new_devices": "{devName} ({eveMac})",
|
||||
})
|
||||
|
||||
json_data = _make_json(
|
||||
@@ -198,7 +198,7 @@ class TestConstructNotificationsTemplates(unittest.TestCase):
|
||||
|
||||
mock_setting.side_effect = self._setting_factory({
|
||||
"NTFPRCS_TEXT_SECTION_HEADERS": True,
|
||||
"NTFPRCS_TEXT_TEMPLATE_new_devices": "{devName} ({BadField}) - {eve_IP}",
|
||||
"NTFPRCS_TEXT_TEMPLATE_new_devices": "{devName} ({BadField}) - {eveIp}",
|
||||
})
|
||||
|
||||
json_data = _make_json(
|
||||
@@ -217,21 +217,21 @@ class TestConstructNotificationsTemplates(unittest.TestCase):
|
||||
|
||||
mock_setting.side_effect = self._setting_factory({
|
||||
"NTFPRCS_TEXT_SECTION_HEADERS": True,
|
||||
"NTFPRCS_TEXT_TEMPLATE_down_devices": "{devName} ({eve_MAC}) down since {eve_DateTime}",
|
||||
"NTFPRCS_TEXT_TEMPLATE_down_devices": "{devName} ({eveMac}) down since {eveDateTime}",
|
||||
})
|
||||
|
||||
down_devices = [
|
||||
{
|
||||
"devName": "Router",
|
||||
"eve_MAC": "ff:ee:dd:cc:bb:aa",
|
||||
"eveMac": "ff:ee:dd:cc:bb:aa",
|
||||
"devVendor": "Cisco",
|
||||
"eve_IP": "10.0.0.1",
|
||||
"eve_DateTime": "2025-01-15 08:00:00",
|
||||
"eve_EventType": "Device Down",
|
||||
"eveIp": "10.0.0.1",
|
||||
"eveDateTime": "2025-01-15 08:00:00",
|
||||
"eveEventType": "Device Down",
|
||||
"devComments": "",
|
||||
}
|
||||
]
|
||||
columns = ["devName", "eve_MAC", "devVendor", "eve_IP", "eve_DateTime", "eve_EventType", "devComments"]
|
||||
columns = ["devName", "eveMac", "devVendor", "eveIp", "eveDateTime", "eveEventType", "devComments"]
|
||||
|
||||
json_data = _make_json("down_devices", down_devices, columns, "🔴 Down devices")
|
||||
_, text = construct_notifications(json_data, "down_devices")
|
||||
|
||||
@@ -15,7 +15,7 @@ sys.modules['logger'] = Mock()
|
||||
class SafeConditionBuilderForTesting:
|
||||
"""Minimal SafeConditionBuilder implementation for tests."""
|
||||
|
||||
ALLOWED_COLUMNS = {'devName', 'eve_MAC', 'eve_EventType'}
|
||||
ALLOWED_COLUMNS = {'devName', 'eveMac', 'eveEventType'}
|
||||
ALLOWED_OPERATORS = {'=', '!=', '<', '>', '<=', '>=', 'LIKE', 'NOT LIKE'}
|
||||
ALLOWED_LOGICAL_OPERATORS = {'AND', 'OR'}
|
||||
|
||||
|
||||
@@ -174,13 +174,13 @@ def test_null_byte_injection(builder):
|
||||
def test_build_condition_with_allowed_values(builder):
|
||||
"""Test building condition with specific allowed values."""
|
||||
conditions = [
|
||||
{"column": "eve_EventType", "operator": "=", "value": "Connected"},
|
||||
{"column": "eveEventType", "operator": "=", "value": "Connected"},
|
||||
{"column": "devName", "operator": "LIKE", "value": "%test%"}
|
||||
]
|
||||
condition, params = builder.build_condition(conditions, "AND")
|
||||
|
||||
# Should create valid parameterized condition
|
||||
assert "eve_EventType = :" in condition
|
||||
assert "eveEventType = :" in condition
|
||||
assert "devName LIKE :" in condition
|
||||
assert len(params) == 2
|
||||
|
||||
|
||||
@@ -58,9 +58,9 @@ class TestSafeConditionBuilder(unittest.TestCase):
|
||||
def test_validate_column_name(self):
|
||||
"""Test column name validation against whitelist."""
|
||||
# Valid columns
|
||||
self.assertTrue(self.builder._validate_column_name('eve_MAC'))
|
||||
self.assertTrue(self.builder._validate_column_name('eveMac'))
|
||||
self.assertTrue(self.builder._validate_column_name('devName'))
|
||||
self.assertTrue(self.builder._validate_column_name('eve_EventType'))
|
||||
self.assertTrue(self.builder._validate_column_name('eveEventType'))
|
||||
|
||||
# Invalid columns
|
||||
self.assertFalse(self.builder._validate_column_name('malicious_column'))
|
||||
@@ -103,9 +103,9 @@ class TestSafeConditionBuilder(unittest.TestCase):
|
||||
|
||||
def test_build_in_condition_valid(self):
|
||||
"""Test building valid IN conditions."""
|
||||
sql, params = self.builder._build_in_condition('AND', 'eve_EventType', 'IN', "'Connected', 'Disconnected'")
|
||||
sql, params = self.builder._build_in_condition('AND', 'eveEventType', 'IN', "'Connected', 'Disconnected'")
|
||||
|
||||
self.assertIn('AND eve_EventType IN', sql)
|
||||
self.assertIn('AND eveEventType IN', sql)
|
||||
self.assertEqual(len(params), 2)
|
||||
self.assertIn('Connected', params.values())
|
||||
self.assertIn('Disconnected', params.values())
|
||||
@@ -162,7 +162,7 @@ class TestSafeConditionBuilder(unittest.TestCase):
|
||||
event_types = ['Connected', 'Disconnected']
|
||||
sql, params = self.builder.build_event_type_filter(event_types)
|
||||
|
||||
self.assertIn('AND eve_EventType IN', sql)
|
||||
self.assertIn('AND eveEventType IN', sql)
|
||||
self.assertEqual(len(params), 2)
|
||||
self.assertIn('Connected', params.values())
|
||||
self.assertIn('Disconnected', params.values())
|
||||
@@ -354,9 +354,9 @@ class TestSecurityBenchmarks(unittest.TestCase):
|
||||
"""Test coverage of condition patterns."""
|
||||
patterns_tested = [
|
||||
"AND devName = 'value'",
|
||||
"OR eve_EventType LIKE '%test%'",
|
||||
"OR eveEventType LIKE '%test%'",
|
||||
"AND devComments IS NULL",
|
||||
"AND eve_EventType IN ('Connected', 'Disconnected')",
|
||||
"AND eveEventType IN ('Connected', 'Disconnected')",
|
||||
]
|
||||
|
||||
for pattern in patterns_tested:
|
||||
|
||||
307
test/db/test_camelcase_migration.py
Normal file
307
test/db/test_camelcase_migration.py
Normal file
@@ -0,0 +1,307 @@
|
||||
"""
|
||||
Unit tests for migrate_to_camelcase() in db_upgrade.
|
||||
|
||||
Covers:
|
||||
- Already-migrated schema (eveMac present) → skip, return True
|
||||
- Unrecognised schema (neither eveMac nor eve_MAC) → skip, return True
|
||||
- Legacy Events columns renamed to camelCase equivalents
|
||||
- Legacy Sessions columns renamed to camelCase equivalents
|
||||
- Legacy Online_History columns renamed to camelCase equivalents
|
||||
- Legacy Plugins_Objects columns renamed to camelCase equivalents
|
||||
- Legacy Plugins_Language_Strings columns renamed to camelCase equivalents
|
||||
- Missing tables are silently skipped without error
|
||||
- Existing row data is preserved through the column rename
|
||||
- Views referencing old column names are dropped before ALTER TABLE runs
|
||||
- Migration is idempotent (second call detects eveMac and returns early)
|
||||
"""
|
||||
|
||||
import sys
|
||||
import os
|
||||
import sqlite3
|
||||
|
||||
INSTALL_PATH = os.getenv('NETALERTX_APP', '/app')
|
||||
sys.path.extend([f"{INSTALL_PATH}/front/plugins", f"{INSTALL_PATH}/server"])
|
||||
|
||||
from db.db_upgrade import migrate_to_camelcase # noqa: E402
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Helpers
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
def _make_cursor():
|
||||
"""Return an in-memory SQLite cursor and its parent connection."""
|
||||
conn = sqlite3.connect(":memory:")
|
||||
return conn.cursor(), conn
|
||||
|
||||
|
||||
def _col_names(cursor, table):
|
||||
"""Return the set of column names for a given table."""
|
||||
cursor.execute(f'PRAGMA table_info("{table}")')
|
||||
return {row[1] for row in cursor.fetchall()}
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Legacy DDL fixtures (pre-migration schema with old column names)
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
_LEGACY_EVENTS_DDL = """
|
||||
CREATE TABLE Events (
|
||||
eve_MAC TEXT NOT NULL,
|
||||
eve_IP TEXT NOT NULL,
|
||||
eve_DateTime DATETIME NOT NULL,
|
||||
eve_EventType TEXT NOT NULL,
|
||||
eve_AdditionalInfo TEXT DEFAULT '',
|
||||
eve_PendingAlertEmail INTEGER NOT NULL DEFAULT 1,
|
||||
eve_PairEventRowid INTEGER
|
||||
)
|
||||
"""
|
||||
|
||||
_LEGACY_SESSIONS_DDL = """
|
||||
CREATE TABLE Sessions (
|
||||
ses_MAC TEXT,
|
||||
ses_IP TEXT,
|
||||
ses_EventTypeConnection TEXT,
|
||||
ses_DateTimeConnection DATETIME,
|
||||
ses_EventTypeDisconnection TEXT,
|
||||
ses_DateTimeDisconnection DATETIME,
|
||||
ses_StillConnected INTEGER,
|
||||
ses_AdditionalInfo TEXT
|
||||
)
|
||||
"""
|
||||
|
||||
_LEGACY_ONLINE_HISTORY_DDL = """
|
||||
CREATE TABLE Online_History (
|
||||
"Index" INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
"Scan_Date" TEXT,
|
||||
"Online_Devices" INTEGER,
|
||||
"Down_Devices" INTEGER,
|
||||
"All_Devices" INTEGER,
|
||||
"Archived_Devices" INTEGER,
|
||||
"Offline_Devices" INTEGER
|
||||
)
|
||||
"""
|
||||
|
||||
_LEGACY_PLUGINS_OBJECTS_DDL = """
|
||||
CREATE TABLE Plugins_Objects (
|
||||
"Index" INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
Plugin TEXT NOT NULL,
|
||||
Object_PrimaryID TEXT NOT NULL,
|
||||
Object_SecondaryID TEXT NOT NULL,
|
||||
DateTimeCreated TEXT NOT NULL,
|
||||
DateTimeChanged TEXT NOT NULL,
|
||||
Watched_Value1 TEXT NOT NULL,
|
||||
Watched_Value2 TEXT NOT NULL,
|
||||
Watched_Value3 TEXT NOT NULL,
|
||||
Watched_Value4 TEXT NOT NULL,
|
||||
Status TEXT NOT NULL,
|
||||
Extra TEXT NOT NULL,
|
||||
UserData TEXT NOT NULL,
|
||||
ForeignKey TEXT NOT NULL,
|
||||
SyncHubNodeName TEXT,
|
||||
HelpVal1 TEXT,
|
||||
HelpVal2 TEXT,
|
||||
HelpVal3 TEXT,
|
||||
HelpVal4 TEXT,
|
||||
ObjectGUID TEXT
|
||||
)
|
||||
"""
|
||||
|
||||
_LEGACY_PLUGINS_LANG_DDL = """
|
||||
CREATE TABLE Plugins_Language_Strings (
|
||||
"Index" INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
Language_Code TEXT NOT NULL,
|
||||
String_Key TEXT NOT NULL,
|
||||
String_Value TEXT NOT NULL,
|
||||
Extra TEXT NOT NULL
|
||||
)
|
||||
"""
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Tests
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
class TestMigrateToCamelCase:
|
||||
|
||||
def test_returns_true_if_already_camelcase(self):
|
||||
"""DB already on camelCase schema → skip silently, return True."""
|
||||
cur, conn = _make_cursor()
|
||||
cur.execute("""
|
||||
CREATE TABLE Events (
|
||||
eveMac TEXT NOT NULL, eveIp TEXT NOT NULL,
|
||||
eveDateTime DATETIME NOT NULL, eveEventType TEXT NOT NULL,
|
||||
eveAdditionalInfo TEXT, evePendingAlertEmail INTEGER,
|
||||
evePairEventRowid INTEGER
|
||||
)
|
||||
""")
|
||||
conn.commit()
|
||||
|
||||
result = migrate_to_camelcase(cur)
|
||||
|
||||
assert result is True
|
||||
assert "eveMac" in _col_names(cur, "Events")
|
||||
|
||||
def test_returns_true_if_unknown_schema(self):
|
||||
"""Events exists but has neither eve_MAC nor eveMac → skip, return True."""
|
||||
cur, conn = _make_cursor()
|
||||
cur.execute("CREATE TABLE Events (someOtherCol TEXT)")
|
||||
conn.commit()
|
||||
|
||||
result = migrate_to_camelcase(cur)
|
||||
|
||||
assert result is True
|
||||
|
||||
def test_events_legacy_columns_renamed(self):
|
||||
"""All legacy eve_* columns are renamed to their camelCase equivalents."""
|
||||
cur, conn = _make_cursor()
|
||||
cur.execute(_LEGACY_EVENTS_DDL)
|
||||
conn.commit()
|
||||
|
||||
result = migrate_to_camelcase(cur)
|
||||
|
||||
assert result is True
|
||||
cols = _col_names(cur, "Events")
|
||||
expected_new = {
|
||||
"eveMac", "eveIp", "eveDateTime", "eveEventType",
|
||||
"eveAdditionalInfo", "evePendingAlertEmail", "evePairEventRowid",
|
||||
}
|
||||
old_names = {
|
||||
"eve_MAC", "eve_IP", "eve_DateTime", "eve_EventType",
|
||||
"eve_AdditionalInfo", "eve_PendingAlertEmail", "eve_PairEventRowid",
|
||||
}
|
||||
assert expected_new.issubset(cols), f"Missing new columns: {expected_new - cols}"
|
||||
assert not old_names & cols, f"Old columns still present: {old_names & cols}"
|
||||
|
||||
def test_sessions_legacy_columns_renamed(self):
|
||||
"""All legacy ses_* columns are renamed to their camelCase equivalents."""
|
||||
cur, conn = _make_cursor()
|
||||
cur.execute(_LEGACY_EVENTS_DDL)
|
||||
cur.execute(_LEGACY_SESSIONS_DDL)
|
||||
conn.commit()
|
||||
|
||||
result = migrate_to_camelcase(cur)
|
||||
|
||||
assert result is True
|
||||
cols = _col_names(cur, "Sessions")
|
||||
assert {
|
||||
"sesMac", "sesIp", "sesEventTypeConnection", "sesDateTimeConnection",
|
||||
"sesEventTypeDisconnection", "sesDateTimeDisconnection",
|
||||
"sesStillConnected", "sesAdditionalInfo",
|
||||
}.issubset(cols)
|
||||
assert not {"ses_MAC", "ses_IP", "ses_DateTimeConnection"} & cols
|
||||
|
||||
def test_online_history_legacy_columns_renamed(self):
|
||||
"""Quoted legacy Online_History column names are renamed to camelCase."""
|
||||
cur, conn = _make_cursor()
|
||||
cur.execute(_LEGACY_EVENTS_DDL)
|
||||
cur.execute(_LEGACY_ONLINE_HISTORY_DDL)
|
||||
conn.commit()
|
||||
|
||||
migrate_to_camelcase(cur)
|
||||
|
||||
cols = _col_names(cur, "Online_History")
|
||||
assert {
|
||||
"scanDate", "onlineDevices", "downDevices",
|
||||
"allDevices", "archivedDevices", "offlineDevices",
|
||||
}.issubset(cols)
|
||||
assert not {"Scan_Date", "Online_Devices", "Down_Devices"} & cols
|
||||
|
||||
def test_plugins_objects_legacy_columns_renamed(self):
|
||||
"""All renamed Plugins_Objects columns receive their camelCase names."""
|
||||
cur, conn = _make_cursor()
|
||||
cur.execute(_LEGACY_EVENTS_DDL)
|
||||
cur.execute(_LEGACY_PLUGINS_OBJECTS_DDL)
|
||||
conn.commit()
|
||||
|
||||
migrate_to_camelcase(cur)
|
||||
|
||||
cols = _col_names(cur, "Plugins_Objects")
|
||||
assert {
|
||||
"plugin", "objectPrimaryId", "objectSecondaryId",
|
||||
"dateTimeCreated", "dateTimeChanged",
|
||||
"watchedValue1", "watchedValue2", "watchedValue3", "watchedValue4",
|
||||
"status", "extra", "userData", "foreignKey", "syncHubNodeName",
|
||||
"helpVal1", "helpVal2", "helpVal3", "helpVal4", "objectGuid",
|
||||
}.issubset(cols)
|
||||
assert not {
|
||||
"Object_PrimaryID", "Watched_Value1", "ObjectGUID",
|
||||
"ForeignKey", "UserData", "Plugin",
|
||||
} & cols
|
||||
|
||||
def test_plugins_language_strings_renamed(self):
|
||||
"""Plugins_Language_Strings legacy column names are renamed to camelCase."""
|
||||
cur, conn = _make_cursor()
|
||||
cur.execute(_LEGACY_EVENTS_DDL)
|
||||
cur.execute(_LEGACY_PLUGINS_LANG_DDL)
|
||||
conn.commit()
|
||||
|
||||
migrate_to_camelcase(cur)
|
||||
|
||||
cols = _col_names(cur, "Plugins_Language_Strings")
|
||||
assert {"languageCode", "stringKey", "stringValue", "extra"}.issubset(cols)
|
||||
assert not {"Language_Code", "String_Key", "String_Value"} & cols
|
||||
|
||||
def test_missing_table_silently_skipped(self):
|
||||
"""Tables in the migration map that don't exist are skipped without error."""
|
||||
cur, conn = _make_cursor()
|
||||
# Only Events (legacy) exists — all other mapped tables are absent
|
||||
cur.execute(_LEGACY_EVENTS_DDL)
|
||||
conn.commit()
|
||||
|
||||
result = migrate_to_camelcase(cur)
|
||||
|
||||
assert result is True
|
||||
assert "eveMac" in _col_names(cur, "Events")
|
||||
|
||||
def test_data_preserved_after_rename(self):
|
||||
"""Existing rows remain accessible under the new camelCase column names."""
|
||||
cur, conn = _make_cursor()
|
||||
cur.execute(_LEGACY_EVENTS_DDL)
|
||||
cur.execute(
|
||||
"INSERT INTO Events (eve_MAC, eve_IP, eve_DateTime, eve_EventType) "
|
||||
"VALUES ('aa:bb:cc:dd:ee:ff', '192.168.1.1', '2025-01-01 12:00:00', 'Connected')"
|
||||
)
|
||||
conn.commit()
|
||||
|
||||
migrate_to_camelcase(cur)
|
||||
|
||||
cur.execute(
|
||||
"SELECT eveMac, eveIp, eveEventType FROM Events WHERE eveMac = 'aa:bb:cc:dd:ee:ff'"
|
||||
)
|
||||
row = cur.fetchone()
|
||||
assert row is not None, "Row missing after camelCase migration"
|
||||
assert row[0] == "aa:bb:cc:dd:ee:ff"
|
||||
assert row[1] == "192.168.1.1"
|
||||
assert row[2] == "Connected"
|
||||
|
||||
def test_views_dropped_before_migration(self):
|
||||
"""Views referencing old column names do not block ALTER TABLE RENAME COLUMN."""
|
||||
cur, conn = _make_cursor()
|
||||
cur.execute(_LEGACY_EVENTS_DDL)
|
||||
# A view that references old column names would normally block the rename
|
||||
cur.execute("CREATE VIEW Events_Devices AS SELECT eve_MAC, eve_IP FROM Events")
|
||||
conn.commit()
|
||||
|
||||
result = migrate_to_camelcase(cur)
|
||||
|
||||
assert result is True
|
||||
assert "eveMac" in _col_names(cur, "Events")
|
||||
# View is dropped (ensure_views() is responsible for recreation separately)
|
||||
cur.execute("SELECT name FROM sqlite_master WHERE type='view' AND name='Events_Devices'")
|
||||
assert cur.fetchone() is None
|
||||
|
||||
def test_idempotent_second_run(self):
|
||||
"""Running migration twice is safe — second call detects eveMac and exits early."""
|
||||
cur, conn = _make_cursor()
|
||||
cur.execute(_LEGACY_EVENTS_DDL)
|
||||
conn.commit()
|
||||
|
||||
first = migrate_to_camelcase(cur)
|
||||
second = migrate_to_camelcase(cur)
|
||||
|
||||
assert first is True
|
||||
assert second is True
|
||||
cols = _col_names(cur, "Events")
|
||||
assert "eveMac" in cols
|
||||
assert "eve_MAC" not in cols
|
||||
@@ -25,26 +25,26 @@ def _make_db():
|
||||
|
||||
cur.execute("""
|
||||
CREATE TABLE Events (
|
||||
eve_MAC TEXT NOT NULL,
|
||||
eve_IP TEXT NOT NULL,
|
||||
eve_DateTime DATETIME NOT NULL,
|
||||
eve_EventType TEXT NOT NULL,
|
||||
eve_AdditionalInfo TEXT DEFAULT '',
|
||||
eve_PendingAlertEmail INTEGER NOT NULL DEFAULT 1,
|
||||
eve_PairEventRowid INTEGER
|
||||
eveMac TEXT NOT NULL,
|
||||
eveIp TEXT NOT NULL,
|
||||
eveDateTime DATETIME NOT NULL,
|
||||
eveEventType TEXT NOT NULL,
|
||||
eveAdditionalInfo TEXT DEFAULT '',
|
||||
evePendingAlertEmail INTEGER NOT NULL DEFAULT 1,
|
||||
evePairEventRowid INTEGER
|
||||
)
|
||||
""")
|
||||
|
||||
cur.execute("""
|
||||
CREATE TABLE Sessions (
|
||||
ses_MAC TEXT,
|
||||
ses_IP TEXT,
|
||||
ses_EventTypeConnection TEXT,
|
||||
ses_DateTimeConnection DATETIME,
|
||||
ses_EventTypeDisconnection TEXT,
|
||||
ses_DateTimeDisconnection DATETIME,
|
||||
ses_StillConnected INTEGER,
|
||||
ses_AdditionalInfo TEXT
|
||||
sesMac TEXT,
|
||||
sesIp TEXT,
|
||||
sesEventTypeConnection TEXT,
|
||||
sesDateTimeConnection DATETIME,
|
||||
sesEventTypeDisconnection TEXT,
|
||||
sesDateTimeDisconnection DATETIME,
|
||||
sesStillConnected INTEGER,
|
||||
sesAdditionalInfo TEXT
|
||||
)
|
||||
""")
|
||||
|
||||
@@ -59,13 +59,13 @@ def _seed_sessions(cur, old_count: int, recent_count: int, days: int):
|
||||
"""
|
||||
for i in range(old_count):
|
||||
cur.execute(
|
||||
"INSERT INTO Sessions (ses_MAC, ses_DateTimeConnection) "
|
||||
"INSERT INTO Sessions (sesMac, sesDateTimeConnection) "
|
||||
"VALUES (?, date('now', ?))",
|
||||
(f"AA:BB:CC:DD:EE:{i:02X}", f"-{days + 1} day"),
|
||||
)
|
||||
for i in range(recent_count):
|
||||
cur.execute(
|
||||
"INSERT INTO Sessions (ses_MAC, ses_DateTimeConnection) "
|
||||
"INSERT INTO Sessions (sesMac, sesDateTimeConnection) "
|
||||
"VALUES (?, date('now'))",
|
||||
(f"11:22:33:44:55:{i:02X}",),
|
||||
)
|
||||
@@ -75,7 +75,7 @@ def _run_sessions_trim(cur, days: int) -> int:
|
||||
"""Execute the exact DELETE used by db_cleanup and return rowcount."""
|
||||
cur.execute(
|
||||
f"DELETE FROM Sessions "
|
||||
f"WHERE ses_DateTimeConnection <= date('now', '-{days} day')"
|
||||
f"WHERE sesDateTimeConnection <= date('now', '-{days} day')"
|
||||
)
|
||||
return cur.rowcount
|
||||
|
||||
@@ -126,20 +126,20 @@ class TestSessionsTrim:
|
||||
cur = conn.cursor()
|
||||
# Row exactly AT the boundary (date = 'now' - days exactly)
|
||||
cur.execute(
|
||||
"INSERT INTO Sessions (ses_MAC, ses_DateTimeConnection) "
|
||||
"INSERT INTO Sessions (sesMac, sesDateTimeConnection) "
|
||||
"VALUES (?, date('now', ?))",
|
||||
("AA:BB:CC:00:00:01", "-30 day"),
|
||||
)
|
||||
# Row just inside the window
|
||||
cur.execute(
|
||||
"INSERT INTO Sessions (ses_MAC, ses_DateTimeConnection) "
|
||||
"INSERT INTO Sessions (sesMac, sesDateTimeConnection) "
|
||||
"VALUES (?, date('now', '-29 day'))",
|
||||
("AA:BB:CC:00:00:02",),
|
||||
)
|
||||
|
||||
_run_sessions_trim(cur, days=30)
|
||||
|
||||
cur.execute("SELECT ses_MAC FROM Sessions")
|
||||
cur.execute("SELECT sesMac FROM Sessions")
|
||||
remaining_macs = {row[0] for row in cur.fetchall()}
|
||||
# Boundary row (== threshold) is deleted; inside row survives
|
||||
assert "AA:BB:CC:00:00:02" in remaining_macs, "Row inside window was wrongly deleted"
|
||||
@@ -157,8 +157,8 @@ class TestSessionsTrim:
|
||||
with open(script_path) as fh:
|
||||
source = fh.read()
|
||||
|
||||
events_expr = "DELETE FROM Events WHERE eve_DateTime <= date('now', '-{str(DAYS_TO_KEEP_EVENTS)} day')"
|
||||
sessions_expr = "DELETE FROM Sessions WHERE ses_DateTimeConnection <= date('now', '-{str(DAYS_TO_KEEP_EVENTS)} day')"
|
||||
events_expr = "DELETE FROM Events WHERE eveDateTime <= date('now', '-{str(DAYS_TO_KEEP_EVENTS)} day')"
|
||||
sessions_expr = "DELETE FROM Sessions WHERE sesDateTimeConnection <= date('now', '-{str(DAYS_TO_KEEP_EVENTS)} day')"
|
||||
|
||||
assert events_expr in source, "Events DELETE expression changed unexpectedly"
|
||||
assert sessions_expr in source, "Sessions DELETE is not aligned with Events DELETE"
|
||||
@@ -181,7 +181,7 @@ class TestAnalyze:
|
||||
# Seed some rows so ANALYZE has something to measure
|
||||
for i in range(20):
|
||||
cur.execute(
|
||||
"INSERT INTO Events (eve_MAC, eve_IP, eve_DateTime, eve_EventType) "
|
||||
"INSERT INTO Events (eveMac, eveIp, eveDateTime, eveEventType) "
|
||||
"VALUES (?, '1.2.3.4', date('now'), 'Connected')",
|
||||
(f"AA:BB:CC:DD:EE:{i:02X}",),
|
||||
)
|
||||
@@ -238,7 +238,7 @@ class TestPragmaOptimize:
|
||||
|
||||
for i in range(50):
|
||||
cur.execute(
|
||||
"INSERT INTO Sessions (ses_MAC, ses_DateTimeConnection) "
|
||||
"INSERT INTO Sessions (sesMac, sesDateTimeConnection) "
|
||||
"VALUES (?, date('now', '-60 day'))",
|
||||
(f"AA:BB:CC:DD:EE:{i:02X}",),
|
||||
)
|
||||
@@ -247,7 +247,7 @@ class TestPragmaOptimize:
|
||||
# Mirror the tail sequence from cleanup_database.
|
||||
# WAL checkpoints are omitted: they require no open transaction and are
|
||||
# not supported on :memory: databases (SQLite raises OperationalError).
|
||||
cur.execute("DELETE FROM Sessions WHERE ses_DateTimeConnection <= date('now', '-30 day')")
|
||||
cur.execute("DELETE FROM Sessions WHERE sesDateTimeConnection <= date('now', '-30 day')")
|
||||
conn.commit()
|
||||
cur.execute("ANALYZE;")
|
||||
conn.execute("VACUUM;")
|
||||
|
||||
@@ -76,16 +76,16 @@ CREATE_DEVICES = """
|
||||
)
|
||||
"""
|
||||
|
||||
# Includes eve_PairEventRowid — required by insert_events().
|
||||
# Includes evePairEventRowid — required by insert_events().
|
||||
CREATE_EVENTS = """
|
||||
CREATE TABLE IF NOT EXISTS Events (
|
||||
eve_MAC TEXT,
|
||||
eve_IP TEXT,
|
||||
eve_DateTime TEXT,
|
||||
eve_EventType TEXT,
|
||||
eve_AdditionalInfo TEXT,
|
||||
eve_PendingAlertEmail INTEGER,
|
||||
eve_PairEventRowid INTEGER
|
||||
eveMac TEXT,
|
||||
eveIp TEXT,
|
||||
eveDateTime TEXT,
|
||||
eveEventType TEXT,
|
||||
eveAdditionalInfo TEXT,
|
||||
evePendingAlertEmail INTEGER,
|
||||
evePairEventRowid INTEGER
|
||||
)
|
||||
"""
|
||||
|
||||
@@ -327,8 +327,8 @@ def sync_insert_devices(
|
||||
|
||||
def down_event_macs(cur) -> set:
|
||||
"""Return the set of MACs that have a 'Device Down' event row (lowercased)."""
|
||||
cur.execute("SELECT eve_MAC FROM Events WHERE eve_EventType = 'Device Down'")
|
||||
return {r["eve_MAC"].lower() for r in cur.fetchall()}
|
||||
cur.execute("SELECT eveMac FROM Events WHERE eveEventType = 'Device Down'")
|
||||
return {r["eveMac"].lower() for r in cur.fetchall()}
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
@@ -39,15 +39,15 @@ def test_db(test_db_path):
|
||||
# Minimal schema for integration testing
|
||||
cur.execute('''
|
||||
CREATE TABLE IF NOT EXISTS Events_Devices (
|
||||
eve_MAC TEXT,
|
||||
eve_DateTime TEXT,
|
||||
eveMac TEXT,
|
||||
eveDateTime TEXT,
|
||||
devLastIP TEXT,
|
||||
eve_IP TEXT,
|
||||
eve_EventType TEXT,
|
||||
eveIp TEXT,
|
||||
eveEventType TEXT,
|
||||
devName TEXT,
|
||||
devVendor TEXT,
|
||||
devComments TEXT,
|
||||
eve_PendingAlertEmail INTEGER
|
||||
evePendingAlertEmail INTEGER
|
||||
)
|
||||
''')
|
||||
|
||||
@@ -63,24 +63,24 @@ def test_db(test_db_path):
|
||||
|
||||
cur.execute('''
|
||||
CREATE TABLE IF NOT EXISTS Events (
|
||||
eve_MAC TEXT,
|
||||
eve_DateTime TEXT,
|
||||
eve_EventType TEXT,
|
||||
eve_PendingAlertEmail INTEGER
|
||||
eveMac TEXT,
|
||||
eveDateTime TEXT,
|
||||
eveEventType TEXT,
|
||||
evePendingAlertEmail INTEGER
|
||||
)
|
||||
''')
|
||||
|
||||
cur.execute('''
|
||||
CREATE TABLE IF NOT EXISTS Plugins_Events (
|
||||
Plugin TEXT,
|
||||
Object_PrimaryId TEXT,
|
||||
Object_SecondaryId TEXT,
|
||||
DateTimeChanged TEXT,
|
||||
Watched_Value1 TEXT,
|
||||
Watched_Value2 TEXT,
|
||||
Watched_Value3 TEXT,
|
||||
Watched_Value4 TEXT,
|
||||
Status TEXT
|
||||
plugin TEXT,
|
||||
objectPrimaryId TEXT,
|
||||
objectSecondaryId TEXT,
|
||||
dateTimeChanged TEXT,
|
||||
watchedValue1 TEXT,
|
||||
watchedValue2 TEXT,
|
||||
watchedValue3 TEXT,
|
||||
watchedValue4 TEXT,
|
||||
"status" TEXT
|
||||
)
|
||||
''')
|
||||
|
||||
@@ -91,7 +91,7 @@ def test_db(test_db_path):
|
||||
('77:88:99:aa:bb:cc', '2024-01-01 12:02:00', '192.168.1.102', '192.168.1.102', 'Disconnected', 'Test Device 3', 'Cisco', 'Third Comment', 1),
|
||||
]
|
||||
cur.executemany('''
|
||||
INSERT INTO Events_Devices (eve_MAC, eve_DateTime, devLastIP, eve_IP, eve_EventType, devName, devVendor, devComments, eve_PendingAlertEmail)
|
||||
INSERT INTO Events_Devices (eveMac, eveDateTime, devLastIP, eveIp, eveEventType, devName, devVendor, devComments, evePendingAlertEmail)
|
||||
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)
|
||||
''', test_data)
|
||||
|
||||
@@ -117,7 +117,7 @@ def test_fresh_install_compatibility(builder):
|
||||
def test_existing_db_compatibility():
|
||||
mock_db = Mock()
|
||||
mock_result = Mock()
|
||||
mock_result.columnNames = ['devName', 'eve_MAC', 'devVendor', 'eve_IP', 'eve_DateTime', 'eve_EventType', 'devComments']
|
||||
mock_result.columnNames = ['devName', 'eveMac', 'devVendor', 'eveIp', 'eveDateTime', 'eveEventType', 'devComments']
|
||||
mock_result.json = {'data': []}
|
||||
mock_db.get_table_as_json.return_value = mock_result
|
||||
|
||||
@@ -145,9 +145,9 @@ def test_notification_system_integration(builder):
|
||||
assert "devName = :" in condition
|
||||
assert 'EmailTestDevice' in params.values()
|
||||
|
||||
apprise_condition = "AND eve_EventType = 'Connected'"
|
||||
apprise_condition = "AND eveEventType = 'Connected'"
|
||||
condition, params = builder.get_safe_condition_legacy(apprise_condition)
|
||||
assert "eve_EventType = :" in condition
|
||||
assert "eveEventType = :" in condition
|
||||
assert 'Connected' in params.values()
|
||||
|
||||
webhook_condition = "AND devComments LIKE '%webhook%'"
|
||||
@@ -155,9 +155,9 @@ def test_notification_system_integration(builder):
|
||||
assert "devComments LIKE :" in condition
|
||||
assert '%webhook%' in params.values()
|
||||
|
||||
mqtt_condition = "AND eve_MAC = 'aa:bb:cc:dd:ee:ff'"
|
||||
mqtt_condition = "AND eveMac = 'aa:bb:cc:dd:ee:ff'"
|
||||
condition, params = builder.get_safe_condition_legacy(mqtt_condition)
|
||||
assert "eve_MAC = :" in condition
|
||||
assert "eveMac = :" in condition
|
||||
assert 'aa:bb:cc:dd:ee:ff' in params.values()
|
||||
|
||||
|
||||
@@ -165,7 +165,7 @@ def test_settings_persistence(builder):
|
||||
test_settings = [
|
||||
"AND devName = 'Persistent Device'",
|
||||
"AND devComments = {s-quote}Legacy Quote{s-quote}",
|
||||
"AND eve_EventType IN ('Connected', 'Disconnected')",
|
||||
"AND eveEventType IN ('Connected', 'Disconnected')",
|
||||
"AND devLastIP = '192.168.1.1'",
|
||||
""
|
||||
]
|
||||
@@ -190,9 +190,9 @@ def test_device_operations(builder):
|
||||
|
||||
def test_plugin_functionality(builder):
|
||||
plugin_conditions = [
|
||||
"AND Plugin = 'TestPlugin'",
|
||||
"AND Object_PrimaryId = 'primary123'",
|
||||
"AND Status = 'Active'"
|
||||
"AND plugin = 'TestPlugin'",
|
||||
"AND objectPrimaryId = 'primary123'",
|
||||
"AND status = 'Active'"
|
||||
]
|
||||
for cond in plugin_conditions:
|
||||
safe_condition, params = builder.get_safe_condition_legacy(cond)
|
||||
|
||||
@@ -258,8 +258,8 @@ class TestInsertEventsSleepSuppression:
|
||||
can_sleep=1, last_connection=last_conn)
|
||||
# Simulate: a Device Down event already exists for this absence
|
||||
cur.execute(
|
||||
"INSERT INTO Events (eve_MAC, eve_IP, eve_DateTime, eve_EventType, "
|
||||
"eve_AdditionalInfo, eve_PendingAlertEmail) "
|
||||
"INSERT INTO Events (eveMac, eveIp, eveDateTime, eveEventType, "
|
||||
"eveAdditionalInfo, evePendingAlertEmail) "
|
||||
"VALUES (?, '192.168.1.1', ?, 'Device Down', '', 1)",
|
||||
("bb:00:00:00:00:04", _minutes_ago(15)),
|
||||
)
|
||||
@@ -269,7 +269,7 @@ class TestInsertEventsSleepSuppression:
|
||||
|
||||
cur.execute(
|
||||
"SELECT COUNT(*) as cnt FROM Events "
|
||||
"WHERE eve_MAC = 'bb:00:00:00:00:04' AND eve_EventType = 'Device Down'"
|
||||
"WHERE eveMac = 'bb:00:00:00:00:04' AND eveEventType = 'Device Down'"
|
||||
)
|
||||
count = cur.fetchone()["cnt"]
|
||||
assert count == 1, (
|
||||
|
||||
@@ -117,12 +117,12 @@ def scan_db_for_new_devices():
|
||||
cur.execute(
|
||||
"""
|
||||
CREATE TABLE Events (
|
||||
eve_MAC TEXT,
|
||||
eve_IP TEXT,
|
||||
eve_DateTime TEXT,
|
||||
eve_EventType TEXT,
|
||||
eve_AdditionalInfo TEXT,
|
||||
eve_PendingAlertEmail INTEGER
|
||||
eveMac TEXT,
|
||||
eveIp TEXT,
|
||||
eveDateTime TEXT,
|
||||
eveEventType TEXT,
|
||||
eveAdditionalInfo TEXT,
|
||||
evePendingAlertEmail INTEGER
|
||||
)
|
||||
"""
|
||||
)
|
||||
@@ -130,14 +130,14 @@ def scan_db_for_new_devices():
|
||||
cur.execute(
|
||||
"""
|
||||
CREATE TABLE Sessions (
|
||||
ses_MAC TEXT,
|
||||
ses_IP TEXT,
|
||||
ses_EventTypeConnection TEXT,
|
||||
ses_DateTimeConnection TEXT,
|
||||
ses_EventTypeDisconnection TEXT,
|
||||
ses_DateTimeDisconnection TEXT,
|
||||
ses_StillConnected INTEGER,
|
||||
ses_AdditionalInfo TEXT
|
||||
sesMac TEXT,
|
||||
sesIp TEXT,
|
||||
sesEventTypeConnection TEXT,
|
||||
sesDateTimeConnection TEXT,
|
||||
sesEventTypeDisconnection TEXT,
|
||||
sesDateTimeDisconnection TEXT,
|
||||
sesStillConnected INTEGER,
|
||||
sesAdditionalInfo TEXT
|
||||
)
|
||||
"""
|
||||
)
|
||||
|
||||
Reference in New Issue
Block a user