From bbd747070137d06b5753ea67744c749de6b2eb75 Mon Sep 17 00:00:00 2001 From: agessaman Date: Mon, 7 Sep 2026 17:15:30 -0700 Subject: [PATCH] test: derive time-window fixtures from the current clock MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit test_neighbor_evidence_edges.py pinned RECENT to 2026-08-01 and used it as the default last_seen for the seeded links. The two days=30 tests compare that against wall-clock now, so once 2026-08-31 passed, the "recent" link filtered out as stale and both assertions saw an empty set. RECENT, EARLIER and ANCIENT now derive from datetime.now(timezone.utc), which fixes their relationship to the window no matter when CI runs. Nothing else in the file depended on the literal values—the other assertions compare against the same constants, and the filter only ever reads last_seen, never first_seen. Swept the rest of tests/ for the same shape by running the suite under a clock shifted forward 400 days, then 10 years. That turned up one more: test_packet_capture_neighbors.py stored 1774482900.0 (2026-03-25) as the persisted neighbors timestamp, and _load_neighbors_timestamp rejects anything older than now-400d, so those two round-trip tests would have started failing on 2027-04-29. That value and the far-future one (2**31, i.e. 2038) are both relative now. The failures that remain under a shifted clock are all fixtures seeding through SQLite's datetime('now') or time.strftime() while the code under test reads Python's clock. Those two move together on a real runner, so they are artifacts of the sweep rather than time bombs. --- tests/unit/test_neighbor_evidence_edges.py | 24 ++++++++++++++++----- tests/unit/test_packet_capture_neighbors.py | 22 +++++++++++++------ 2 files changed, 34 insertions(+), 12 deletions(-) diff --git a/tests/unit/test_neighbor_evidence_edges.py b/tests/unit/test_neighbor_evidence_edges.py index 85ef274..c8d8d98 100644 --- a/tests/unit/test_neighbor_evidence_edges.py +++ b/tests/unit/test_neighbor_evidence_edges.py @@ -9,6 +9,7 @@ from __future__ import annotations import contextlib import logging import sqlite3 +from datetime import datetime, timedelta, timezone import pytest @@ -21,8 +22,21 @@ SELF_KEY = "ff" * 32 KEY_A = "aa" * 32 KEY_B = "bb" * 32 -RECENT = "2026-08-01T00:00:00+00:00" -ANCIENT = "2020-01-01T00:00:00+00:00" + +def ago(days: float) -> str: + """A fixture timestamp `days` before now, in the format the bot stores. + + These have to be relative: the days= filters compare last_seen against + wall-clock now, so an absolute "recent" literal silently ages out of the + window and turns the filter tests red on a date nobody picked. + """ + stamp = datetime.now(timezone.utc) - timedelta(days=days) + return stamp.replace(microsecond=0).isoformat() + + +RECENT = ago(1) # inside every window these tests exercise +EARLIER = ago(250) # a lifetime first_seen, well outside a 30-day window +ANCIENT = ago(365 * 6) # outside any window the viewer offers class ViewerStub: @@ -84,7 +98,7 @@ def seeded(viewer): with viewer._with_db_connection() as conn: insert_link(conn, SELF_KEY, KEY_A, observations=4, snr_sum=30.0, snr_count=4, best_snr=9.5, last_snr=7.0, - first_seen="2026-01-01T00:00:00+00:00", last_seen=RECENT) + first_seen=EARLIER, last_seen=RECENT) insert_link(conn, SELF_KEY, KEY_B, observations=1, snr_sum=-3.0, snr_count=1, best_snr=-3.0, last_snr=-3.0, last_seen=ANCIENT) @@ -134,7 +148,7 @@ def test_edges_are_tagged_and_treated_as_first_hop(seeded): def test_edges_preserve_lifetime_counts_and_timestamps(seeded): edge = find_edge(seeded._compute_neighbor_evidence_edges(), SELF_KEY, KEY_A) assert edge["observation_count"] == 4 - assert edge["first_seen"] == "2026-01-01T00:00:00+00:00" + assert edge["first_seen"] == EARLIER assert edge["last_seen"] == RECENT @@ -192,7 +206,7 @@ def test_edge_keys_honour_the_days_window(seeded): """neighbor_links is never pruned, so stale evidence must not label edges.""" keys = seeded._neighbor_evidence_edge_keys(days=30) assert (SELF_KEY[:6], KEY_A[:6]) in keys.prefixes - # KEY_B was last heard in 2020. + # KEY_B was last heard years ago. assert (SELF_KEY[:6], KEY_B[:6]) not in keys.prefixes assert (SELF_KEY, KEY_B) not in keys.public_keys diff --git a/tests/unit/test_packet_capture_neighbors.py b/tests/unit/test_packet_capture_neighbors.py index ca13d0d..5e41b89 100644 --- a/tests/unit/test_packet_capture_neighbors.py +++ b/tests/unit/test_packet_capture_neighbors.py @@ -8,6 +8,7 @@ import contextlib import json import logging import sqlite3 +import time import types from unittest.mock import MagicMock @@ -488,28 +489,35 @@ def test_capability_false_without_a_radio(): # State persistence # --------------------------------------------------------------------------- +# _load_neighbors_timestamp rejects anything outside now-400d .. now+300s, so +# both of these have to be relative: an absolute epoch literal drifts out of +# the accepted range and fails on a date nobody picked. +STORED_EPOCH = float(round(time.time()) - 3600) +FAR_FUTURE_EPOCH = round(time.time()) + 10 * 365 * 86400 + + def test_state_round_trips_through_bot_metadata(db_manager): service = build_service(BASE_INI, db_manager=db_manager) assert service.last_neighbors_publish == 0.0 - service.last_neighbors_publish = 1774482900.0 + service.last_neighbors_publish = STORED_EPOCH service._save_neighbors_state() - assert db_manager.metadata[NEIGHBORS_STATE_KEY] == "1774482900.0" + assert db_manager.metadata[NEIGHBORS_STATE_KEY] == str(STORED_EPOCH) reloaded = build_service(BASE_INI, db_manager=db_manager) - assert reloaded.last_neighbors_publish == 1774482900.0 + assert reloaded.last_neighbors_publish == STORED_EPOCH def test_attempt_state_round_trips_through_bot_metadata(db_manager): service = build_service(BASE_INI, db_manager=db_manager) assert service.last_neighbors_attempt == 0.0 - service.last_neighbors_attempt = 1774482900.0 + service.last_neighbors_attempt = STORED_EPOCH service._save_neighbors_attempt_state() - assert db_manager.metadata[NEIGHBORS_ATTEMPT_STATE_KEY] == "1774482900.0" + assert db_manager.metadata[NEIGHBORS_ATTEMPT_STATE_KEY] == str(STORED_EPOCH) reloaded = build_service(BASE_INI, db_manager=db_manager) - assert reloaded.last_neighbors_attempt == 1774482900.0 + assert reloaded.last_neighbors_attempt == STORED_EPOCH def test_malformed_state_is_ignored(db_manager): @@ -519,7 +527,7 @@ def test_malformed_state_is_ignored(db_manager): def test_far_future_state_is_ignored(db_manager): """A clock jump forward would otherwise suppress cycles indefinitely.""" - db_manager.metadata[NEIGHBORS_STATE_KEY] = str(2**31) + db_manager.metadata[NEIGHBORS_STATE_KEY] = str(FAR_FUTURE_EPOCH) assert build_service(BASE_INI, db_manager=db_manager).last_neighbors_publish == 0.0