feat(service-storage-harness): slice 4 — cascade-delete wiring + integration test
Wire ServiceDataHarness.cascade_delete into SettingsStore.delete_service (best-effort try/except, logs on failure). Fix migration runner to also catch 'no such table' on fresh DBs (ALTER TABLE before init_schema). Integration test proves end-to-end cascade across both concerns (qBit samples + media items) with multi-instance preservation. Backend: 322 pytest pass, ruff clean.
This commit is contained in:
@@ -396,6 +396,77 @@ def test_delete_service_cascades_to_widgets(client, tmp_path):
|
||||
assert int(remaining[0]) == 0
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Harness cascade-delete (Slice 4)
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
|
||||
def test_cascade_delete_removes_harness_data_across_concerns(tmp_path, monkeypatch):
|
||||
"""Deleting a service cascades to both qbittorrent samples and media items.
|
||||
|
||||
Proves end-to-end cascade across both harness-managed concerns, and that
|
||||
deleting one service preserves another service's data (multi-instance).
|
||||
"""
|
||||
monkeypatch.setenv("BACKEND_CACHE_DIR", str(tmp_path))
|
||||
|
||||
from media_library_viewer_api.services.media_index_impl import MediaIndex
|
||||
from media_library_viewer_api.services.qbittorrent_store import QbittorrentSampleStore
|
||||
from media_library_viewer_api.services.service_data import (
|
||||
get_service_data_harness,
|
||||
reset_service_data_harness,
|
||||
)
|
||||
|
||||
reset_service_data_harness()
|
||||
harness = get_service_data_harness()
|
||||
|
||||
store = SettingsStore(tmp_path / "settings.sqlite")
|
||||
store.ensure_defaults()
|
||||
|
||||
# --- qBit: create service, add samples, delete, verify gone ---
|
||||
qbit_a = store.upsert_service(
|
||||
{"service_type": "qbittorrent", "name": "qA", "config": {"base_url": "http://a"}, "enabled": True}
|
||||
)
|
||||
qbit_b = store.upsert_service(
|
||||
{"service_type": "qbittorrent", "name": "qB", "config": {"base_url": "http://b"}, "enabled": True}
|
||||
)
|
||||
sample_store = QbittorrentSampleStore(harness)
|
||||
sample_store.append(qbit_a["id"], ts=1000, dl_speed=500, up_speed=100)
|
||||
sample_store.append(qbit_b["id"], ts=1000, dl_speed=200, up_speed=50)
|
||||
|
||||
assert len(sample_store.window(qbit_a["id"])) == 1
|
||||
assert len(sample_store.window(qbit_b["id"])) == 1
|
||||
|
||||
store.delete_service(qbit_a["id"])
|
||||
|
||||
assert sample_store.window(qbit_a["id"]) == []
|
||||
assert len(sample_store.window(qbit_b["id"])) == 1 # B survives
|
||||
|
||||
# --- MediaIndex: create services, add items, delete, verify scoped ---
|
||||
jelly_a = store.upsert_service(
|
||||
{"service_type": "jellyfin", "name": "jA", "config": {"base_url": "http://ja"}, "enabled": True}
|
||||
)
|
||||
jelly_b = store.upsert_service(
|
||||
{"service_type": "jellyfin", "name": "jB", "config": {"base_url": "http://jb"}, "enabled": True}
|
||||
)
|
||||
index = MediaIndex(harness.db_path("media_index"))
|
||||
index.init_schema()
|
||||
index.replace_items([{"id": "m1", "title": "A1"}], service_id=jelly_a["id"])
|
||||
index.replace_items([{"id": "m2", "title": "B1"}], service_id=jelly_b["id"])
|
||||
|
||||
rows_a, total_a = index.query(service_id=jelly_a["id"])
|
||||
rows_b, total_b = index.query(service_id=jelly_b["id"])
|
||||
assert total_a == 1 and total_b == 1
|
||||
|
||||
store.delete_service(jelly_a["id"])
|
||||
|
||||
rows_a_after, total_a_after = index.query(service_id=jelly_a["id"])
|
||||
rows_b_after, total_b_after = index.query(service_id=jelly_b["id"])
|
||||
assert total_a_after == 0 # deleted
|
||||
assert total_b_after == 1 # survives
|
||||
|
||||
reset_service_data_harness()
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Service task run history
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
Reference in New Issue
Block a user