Skip to content

Commit 89139fe

Browse files
committed
Add update_sync_hub_node function and corresponding tests for backfilling devSyncHubNode #1609
1 parent 285bd3e commit 89139fe

3 files changed

Lines changed: 136 additions & 0 deletions

File tree

server/scan/device_handling.py

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -240,6 +240,29 @@ def update_devLastConnection_from_CurrentScan(db):
240240
""")
241241

242242

243+
def update_sync_hub_node(db):
244+
"""
245+
Backfill devSyncHubNode with SYNC_node_name for devices where it is empty.
246+
Mirrors the fallback already used in create_new_devices.
247+
"""
248+
sql = db.sql
249+
node_name = get_setting_value("SYNC_node_name")
250+
251+
if not node_name:
252+
return
253+
254+
sql.execute(
255+
"""
256+
UPDATE Devices
257+
SET devSyncHubNode = ?
258+
WHERE COALESCE(devSyncHubNode, '') IN ('', 'null')
259+
""",
260+
(node_name,),
261+
)
262+
263+
db.commitDB()
264+
265+
243266
def update_devices_data_from_scan(db):
244267
sql = db.sql
245268

server/scan/session_events.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
save_scanned_devices,
55
exclude_ignored_devices,
66
update_devices_data_from_scan,
7+
update_sync_hub_node,
78
update_vendors_from_mac,
89
update_icons_and_types,
910
update_devPresentLastScan_based_on_force_status,
@@ -62,6 +63,10 @@ def process_scan(db):
6263
mylog("verbose", "[Process Scan] Updating Devices Info")
6364
update_devices_data_from_scan(db)
6465

66+
# Backfill devSyncHubNode for devices where it is empty
67+
mylog("verbose", "[Process Scan] Updating Sync Hub Node")
68+
update_sync_hub_node(db)
69+
6570
# Last Connection Time stamp from CurrentScan
6671
mylog("verbose", "[Process Scan] Updating devLastConnection from CurrentScan")
6772
update_devLastConnection_from_CurrentScan(db)
Lines changed: 108 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,108 @@
1+
"""Tests for update_sync_hub_node backfill."""
2+
3+
import sqlite3
4+
from unittest.mock import patch
5+
6+
from server.scan import device_handling
7+
8+
9+
class DummyDB:
10+
"""Minimal DB wrapper compatible with device_handling helpers."""
11+
12+
def __init__(self, conn):
13+
self.sql = conn.cursor()
14+
self._conn = conn
15+
16+
def commitDB(self):
17+
self._conn.commit()
18+
19+
20+
def _make_db(devices):
21+
"""Create an in-memory DB with a Devices table and seed rows."""
22+
conn = sqlite3.connect(":memory:")
23+
conn.row_factory = sqlite3.Row
24+
cur = conn.cursor()
25+
26+
cur.execute(
27+
"""
28+
CREATE TABLE Devices (
29+
devMac TEXT PRIMARY KEY,
30+
devSyncHubNode TEXT
31+
)
32+
"""
33+
)
34+
35+
cur.executemany(
36+
"INSERT INTO Devices (devMac, devSyncHubNode) VALUES (?, ?)",
37+
devices,
38+
)
39+
conn.commit()
40+
return conn
41+
42+
43+
def _read_nodes(conn):
44+
"""Return a dict of devMac -> devSyncHubNode."""
45+
return {
46+
row["devMac"]: row["devSyncHubNode"]
47+
for row in conn.execute("SELECT devMac, devSyncHubNode FROM Devices")
48+
}
49+
50+
51+
@patch.object(device_handling, "get_setting_value", return_value="MyNode")
52+
def test_backfill_empty_values(mock_setting):
53+
"""Empty and null devSyncHubNode should be backfilled with SYNC_node_name."""
54+
conn = _make_db([
55+
("AA:AA:AA:AA:AA:01", ""),
56+
("AA:AA:AA:AA:AA:02", None),
57+
("AA:AA:AA:AA:AA:03", "null"),
58+
])
59+
60+
device_handling.update_sync_hub_node(DummyDB(conn))
61+
nodes = _read_nodes(conn)
62+
63+
assert nodes["AA:AA:AA:AA:AA:01"] == "MyNode"
64+
assert nodes["AA:AA:AA:AA:AA:02"] == "MyNode"
65+
assert nodes["AA:AA:AA:AA:AA:03"] == "MyNode"
66+
67+
68+
@patch.object(device_handling, "get_setting_value", return_value="MyNode")
69+
def test_no_overwrite_existing(mock_setting):
70+
"""Devices with a real devSyncHubNode should not be overwritten."""
71+
conn = _make_db([
72+
("AA:AA:AA:AA:AA:01", "RemoteNode"),
73+
("AA:AA:AA:AA:AA:02", ""),
74+
])
75+
76+
device_handling.update_sync_hub_node(DummyDB(conn))
77+
nodes = _read_nodes(conn)
78+
79+
assert nodes["AA:AA:AA:AA:AA:01"] == "RemoteNode"
80+
assert nodes["AA:AA:AA:AA:AA:02"] == "MyNode"
81+
82+
83+
@patch.object(device_handling, "get_setting_value", return_value="")
84+
def test_noop_when_setting_empty(mock_setting):
85+
"""No updates when SYNC_node_name is empty."""
86+
conn = _make_db([
87+
("AA:AA:AA:AA:AA:01", ""),
88+
("AA:AA:AA:AA:AA:02", None),
89+
])
90+
91+
device_handling.update_sync_hub_node(DummyDB(conn))
92+
nodes = _read_nodes(conn)
93+
94+
assert nodes["AA:AA:AA:AA:AA:01"] == ""
95+
assert nodes["AA:AA:AA:AA:AA:02"] is None
96+
97+
98+
@patch.object(device_handling, "get_setting_value", return_value=None)
99+
def test_noop_when_setting_none(mock_setting):
100+
"""No updates when SYNC_node_name is None."""
101+
conn = _make_db([
102+
("AA:AA:AA:AA:AA:01", ""),
103+
])
104+
105+
device_handling.update_sync_hub_node(DummyDB(conn))
106+
nodes = _read_nodes(conn)
107+
108+
assert nodes["AA:AA:AA:AA:AA:01"] == ""

0 commit comments

Comments
 (0)