Files
seismo-relay/tests/test_db_snapshot.py
T

134 lines
4.5 KiB
Python

"""
test_db_snapshot.py — unit tests for sfm/db_snapshot.py (snapshot/restore
helpers behind the /db/snapshot, /db/waveforms/recent.zip, /db/restore routes).
Run:
python -m pytest tests/test_db_snapshot.py -v
"""
from __future__ import annotations
import os
import sys
import sqlite3
from pathlib import Path
sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
def _make_db(path: Path, rows: int = 3) -> None:
conn = sqlite3.connect(str(path))
conn.execute("CREATE TABLE t (id INTEGER PRIMARY KEY, v TEXT)")
conn.executemany("INSERT INTO t (v) VALUES (?)", [(f"row{i}",) for i in range(rows)])
conn.commit()
conn.close()
def _seed_event(db_path: Path, serial: str, fn: str, ts: str) -> None:
conn = sqlite3.connect(str(db_path))
conn.execute(
"INSERT INTO events (id, serial, waveform_key, timestamp, "
"blastware_filename, a5_pickle_filename, sidecar_filename, false_trigger) "
"VALUES (?, ?, ?, ?, ?, ?, ?, 0)",
(f"id-{fn}", serial, fn[:8], ts, fn, f"{fn}.a5.pkl", f"{fn}.sfm.json"),
)
conn.commit()
conn.close()
def test_snapshot_db_produces_queryable_copy(tmp_path):
from sfm.db_snapshot import snapshot_db
src = tmp_path / "src.db"
_make_db(src, rows=5)
dest = tmp_path / "snap.db"
out = snapshot_db(src, dest)
assert out == dest and dest.exists()
conn = sqlite3.connect(str(dest))
n = conn.execute("SELECT COUNT(*) FROM t").fetchone()[0]
conn.close()
assert n == 5
def test_recent_waveforms_zip_bundles_all_per_event_files(tmp_path):
import zipfile
from sfm.database import SeismoDb
from sfm.waveform_store import WaveformStore
from sfm.db_snapshot import build_recent_waveforms_zip
db = SeismoDb(tmp_path / "seismo_relay.db") # creates schema on init
store = WaveformStore(tmp_path / "waveforms")
def add(serial, fn, ts):
d = store.root / serial
d.mkdir(parents=True, exist_ok=True)
for suffix in ("", ".h5", ".a5.pkl", ".sfm.json"):
(d / f"{fn}{suffix}").write_bytes(b"data")
_seed_event(db.db_path, serial, fn, ts)
add("BE111", "AAAA1111.OE0H", "2026-06-01T00:00:00")
add("BE111", "BBBB2222.OE0H", "2026-06-02T00:00:00") # newest
dest = tmp_path / "wf.zip"
stats = build_recent_waveforms_zip(db, store, n=1, dest_path=dest)
assert stats["events"] == 1
assert stats["files"] == 4
with zipfile.ZipFile(dest) as zf:
names = set(zf.namelist())
assert names == {
"BE111/BBBB2222.OE0H",
"BE111/BBBB2222.OE0H.h5",
"BE111/BBBB2222.OE0H.a5.pkl",
"BE111/BBBB2222.OE0H.sfm.json",
}
def test_sfm_db_restore_enabled_reads_env(monkeypatch):
from sfm.db_snapshot import sfm_db_restore_enabled
monkeypatch.delenv("SFM_DB_RESTORE_ENABLED", raising=False)
assert sfm_db_restore_enabled() is False
monkeypatch.setenv("SFM_DB_RESTORE_ENABLED", "true")
assert sfm_db_restore_enabled() is True
monkeypatch.setenv("SFM_DB_RESTORE_ENABLED", "0")
assert sfm_db_restore_enabled() is False
def test_restore_swaps_db_and_unpacks_waveforms(tmp_path):
import zipfile
from sfm.db_snapshot import restore_db_and_waveforms
db_path = tmp_path / "seismo_relay.db"
_make_db(db_path, rows=1)
(tmp_path / "seismo_relay.db-wal").write_bytes(b"stale") # must be cleared
new_db = tmp_path / "incoming.db"
_make_db(new_db, rows=9)
wf_root = tmp_path / "waveforms"
wf_root.mkdir()
wf_zip = tmp_path / "wf.zip"
with zipfile.ZipFile(wf_zip, "w") as zf:
zf.writestr("BE111/AAAA.OE0H", b"x")
zf.writestr("BE111/AAAA.OE0H.h5", b"x")
result = restore_db_and_waveforms(db_path, wf_root, new_db, wf_zip)
conn = sqlite3.connect(str(db_path))
assert conn.execute("SELECT COUNT(*) FROM t").fetchone()[0] == 9
conn.close()
assert not (tmp_path / "seismo_relay.db-wal").exists()
assert (wf_root / "BE111" / "AAAA.OE0H.h5").exists()
assert result["ok"] and result["waveforms_unpacked"] == 2
assert result["safety_backup"] is not None
def test_restore_rejects_non_sqlite(tmp_path):
import pytest
from sfm.db_snapshot import restore_db_and_waveforms
db_path = tmp_path / "seismo_relay.db"
_make_db(db_path, rows=1)
bogus = tmp_path / "bogus.db"
bogus.write_bytes(b"not a sqlite file at all")
wf_root = tmp_path / "waveforms"
wf_root.mkdir()
with pytest.raises(ValueError):
restore_db_and_waveforms(db_path, wf_root, bogus, None)