BE: FREEBOX dual stack IP fix #1804

This commit is contained in:
jokob-sk committed 2026-09-22 08:43:41 +10:00
1 parent 38866a64db
commit a573eeb0e7
5 files changed
+129 -24

No files matched your search

+93
View File
@@ -169,3 +169,96 @@ def test_ipv6_address_format_variations(scan_db, mock_ip_handlers):
row = cur.execute("SELECT devPrimaryIPv6 FROM Devices WHERE devLastIP = ?", (ipv6,)).fetchone()
assert row is not None
# --- Dual-stack same-cycle tests (regression for GitHub #1804) ---
#
# The tests above all cover a single address family per scan cycle - either
# one row per mac, or two *separate* cycles (CurrentScan cleared between
# them). None of them reproduce #1804: a device reporting both an IPv4 and an
# IPv6 row for the same mac in the *same* cycle. See
# .gemini/internal-docs/PRDs/dual-stack-primary-ip-support.md.
def test_dual_stack_same_cycle_sets_both_primary_ips(scan_db, mock_ip_handlers):
"""A single scan cycle reporting both IPv4 and IPv6 for one MAC, from the
same plugin, must set both devPrimaryIPv4 and devPrimaryIPv6 from that one
cycle - regression test for #1804."""
cur = scan_db.cursor()
cur.execute("INSERT INTO Devices (devMac) VALUES (?)", ("cc:cc:cc:cc:cc:01",))
cur.execute(
"INSERT INTO CurrentScan (scanMac, scanLastIP, scanSourcePlugin, scanLastConnection) VALUES (?, ?, ?, ?)",
("cc:cc:cc:cc:cc:01", "192.168.1.50", "FREEBOX", "2025-01-01 01:00:00")
)
cur.execute(
"INSERT INTO CurrentScan (scanMac, scanLastIP, scanSourcePlugin, scanLastConnection) VALUES (?, ?, ?, ?)",
("cc:cc:cc:cc:cc:01", "fe80::abcd", "FREEBOX", "2025-01-01 01:00:01")
)
scan_db.commit()
db = Mock(sql_connection=scan_db, sql=cur)
device_handling.update_devices_data_from_scan(db)
device_handling.update_ipv4_ipv6(db)
row = cur.execute(
"SELECT devPrimaryIPv4, devPrimaryIPv6 FROM Devices WHERE devMac = ?",
("cc:cc:cc:cc:cc:01",),
).fetchone()
assert row["devPrimaryIPv4"] == "192.168.1.50"
assert row["devPrimaryIPv6"] == "fe80::abcd"
def test_dual_stack_two_plugins_same_cycle_sets_both(scan_db, mock_ip_handlers):
"""Same as above, but the IPv4 row and the IPv6 row come from two
different plugins - confirms the per-family ranking is mac-wide, not
scoped to one plugin's own rows."""
cur = scan_db.cursor()
cur.execute("INSERT INTO Devices (devMac) VALUES (?)", ("cc:cc:cc:cc:cc:02",))
cur.execute(
"INSERT INTO CurrentScan (scanMac, scanLastIP, scanSourcePlugin, scanLastConnection) VALUES (?, ?, ?, ?)",
("cc:cc:cc:cc:cc:02", "192.168.1.60", "ARPSCAN", "2025-01-01 01:00:00")
)
cur.execute(
"INSERT INTO CurrentScan (scanMac, scanLastIP, scanSourcePlugin, scanLastConnection) VALUES (?, ?, ?, ?)",
("cc:cc:cc:cc:cc:02", "fe80::beef", "FREEBOX", "2025-01-01 01:00:00")
)
scan_db.commit()
db = Mock(sql_connection=scan_db, sql=cur)
device_handling.update_devices_data_from_scan(db)
device_handling.update_ipv4_ipv6(db)
row = cur.execute(
"SELECT devPrimaryIPv4, devPrimaryIPv6 FROM Devices WHERE devMac = ?",
("cc:cc:cc:cc:cc:02",),
).fetchone()
assert row["devPrimaryIPv4"] == "192.168.1.60"
assert row["devPrimaryIPv6"] == "fe80::beef"
def test_dual_stack_presence_suppressed_row_excluded(scan_db, mock_ip_handlers):
"""A scanPresence=0 row must not win a device's primary address for that
family, same as it doesn't count as a live sighting elsewhere in the scan
pipeline."""
cur = scan_db.cursor()
cur.execute("INSERT INTO Devices (devMac) VALUES (?)", ("cc:cc:cc:cc:cc:03",))
cur.execute(
"INSERT INTO CurrentScan (scanMac, scanLastIP, scanSourcePlugin, scanLastConnection, scanPresence) VALUES (?, ?, ?, ?, ?)",
("cc:cc:cc:cc:cc:03", "192.168.1.70", "ARPSCAN", "2025-01-01 01:00:00", 1)
)
cur.execute(
"INSERT INTO CurrentScan (scanMac, scanLastIP, scanSourcePlugin, scanLastConnection, scanPresence) VALUES (?, ?, ?, ?, ?)",
("cc:cc:cc:cc:cc:03", "fe80::dead", "SOMEPLG", "2025-01-01 01:00:00", 0)
)
scan_db.commit()
db = Mock(sql_connection=scan_db, sql=cur)
device_handling.update_devices_data_from_scan(db)
device_handling.update_ipv4_ipv6(db)
row = cur.execute(
"SELECT devPrimaryIPv4, devPrimaryIPv6 FROM Devices WHERE devMac = ?",
("cc:cc:cc:cc:cc:03",),
).fetchone()
assert row["devPrimaryIPv4"] == "192.168.1.70"
assert row["devPrimaryIPv6"] in (None, "")