mirror of
https://github.com/BigBodyCobain/Shadowbroker.git
synced 2026-05-07 18:06:49 +02:00
147 lines
4.4 KiB
Python
147 lines
4.4 KiB
Python
"""Tests for the shared in-memory data store."""
|
|
|
|
import threading
|
|
import time
|
|
import pytest
|
|
from services.fetchers._store import (
|
|
latest_data,
|
|
source_timestamps,
|
|
_mark_fresh,
|
|
_data_lock,
|
|
get_data_version,
|
|
bump_data_version,
|
|
)
|
|
|
|
|
|
class TestLatestDataStructure:
|
|
"""Verify the store has the expected keys and default values."""
|
|
|
|
def test_has_all_required_keys(self):
|
|
expected_keys = {
|
|
"last_updated",
|
|
"news",
|
|
"stocks",
|
|
"oil",
|
|
"flights",
|
|
"ships",
|
|
"military_flights",
|
|
"tracked_flights",
|
|
"cctv",
|
|
"weather",
|
|
"earthquakes",
|
|
"uavs",
|
|
"frontlines",
|
|
"gdelt",
|
|
"liveuamap",
|
|
"kiwisdr",
|
|
"space_weather",
|
|
"internet_outages",
|
|
"firms_fires",
|
|
"datacenters",
|
|
}
|
|
assert expected_keys.issubset(set(latest_data.keys()))
|
|
|
|
def test_list_keys_default_to_empty_list(self):
|
|
list_keys = [
|
|
"news",
|
|
"flights",
|
|
"ships",
|
|
"military_flights",
|
|
"tracked_flights",
|
|
"cctv",
|
|
"earthquakes",
|
|
"uavs",
|
|
"gdelt",
|
|
"liveuamap",
|
|
"kiwisdr",
|
|
"internet_outages",
|
|
"firms_fires",
|
|
"datacenters",
|
|
]
|
|
for key in list_keys:
|
|
assert isinstance(latest_data[key], list), f"{key} should default to list"
|
|
|
|
def test_dict_keys_default_to_empty_dict(self):
|
|
dict_keys = ["stocks", "oil"]
|
|
for key in dict_keys:
|
|
assert isinstance(latest_data[key], dict), f"{key} should default to dict"
|
|
|
|
|
|
class TestMarkFresh:
|
|
"""Tests for _mark_fresh timestamp helper."""
|
|
|
|
def test_records_timestamp_for_single_key(self):
|
|
_mark_fresh("test_key_1")
|
|
assert "test_key_1" in source_timestamps
|
|
assert isinstance(source_timestamps["test_key_1"], str)
|
|
|
|
def test_records_timestamps_for_multiple_keys(self):
|
|
_mark_fresh("multi_a", "multi_b", "multi_c")
|
|
assert "multi_a" in source_timestamps
|
|
assert "multi_b" in source_timestamps
|
|
assert "multi_c" in source_timestamps
|
|
|
|
def test_timestamps_are_iso_format(self):
|
|
_mark_fresh("iso_test")
|
|
ts = source_timestamps["iso_test"]
|
|
# ISO format: YYYY-MM-DDTHH:MM:SS.ffffff
|
|
assert "T" in ts
|
|
assert len(ts) >= 19 # At least YYYY-MM-DDTHH:MM:SS
|
|
|
|
def test_successive_calls_update_timestamp(self):
|
|
_mark_fresh("update_test")
|
|
ts1 = source_timestamps["update_test"]
|
|
time.sleep(0.01)
|
|
_mark_fresh("update_test")
|
|
ts2 = source_timestamps["update_test"]
|
|
assert ts2 >= ts1
|
|
|
|
def test_mark_fresh_bumps_data_version(self):
|
|
version_before = get_data_version()
|
|
_mark_fresh("version_test")
|
|
assert get_data_version() == version_before + 1
|
|
|
|
|
|
class TestDataVersion:
|
|
"""Tests for the monotonic data version counter."""
|
|
|
|
def test_bump_data_version_increments_counter(self):
|
|
version_before = get_data_version()
|
|
bump_data_version()
|
|
assert get_data_version() == version_before + 1
|
|
|
|
|
|
class TestDataLock:
|
|
"""Verify the data lock works for thread safety."""
|
|
|
|
def test_lock_exists_and_is_a_lock(self):
|
|
assert isinstance(_data_lock, type(threading.Lock()))
|
|
|
|
def test_concurrent_writes_dont_corrupt(self):
|
|
"""Simulate concurrent writes to latest_data through the lock."""
|
|
errors = []
|
|
|
|
def writer(key, value, iterations=100):
|
|
try:
|
|
for _ in range(iterations):
|
|
with _data_lock:
|
|
latest_data[key] = value
|
|
# Read back immediately — should be our value
|
|
assert latest_data[key] == value
|
|
except Exception as e:
|
|
errors.append(e)
|
|
|
|
threads = [
|
|
threading.Thread(target=writer, args=("test_concurrent", [1, 2, 3])),
|
|
threading.Thread(target=writer, args=("test_concurrent", [4, 5, 6])),
|
|
threading.Thread(target=writer, args=("test_concurrent", [7, 8, 9])),
|
|
]
|
|
for t in threads:
|
|
t.start()
|
|
for t in threads:
|
|
t.join()
|
|
|
|
assert len(errors) == 0, f"Thread safety errors: {errors}"
|
|
# Restore default
|
|
latest_data["test_concurrent"] = []
|