"""Tests for subscription handlers. Subscription add validates the destination hash (32-char hex) locally before calling `fetch_remote_sites`; browse uses cached remote_pages when available and falls back to a live fetch otherwise. """ from unittest.mock import patch import handlers as handlers_module from db import get_db, return_db from handlers import handle_subscription_add, handle_subscription_browse VALID_HASH = "a" * 32 def _subscription_count(): db = get_db() try: return db.execute("SELECT count(*) FROM subscriptions").fetchone()[0] finally: return_db(db) def test_rejects_empty_dest_hash(temp_db, csrf_session): resp = handle_subscription_add({"dest_hash": [""]}) assert "32-character" in resp["body"] assert _subscription_count() == 0 def test_rejects_wrong_length(temp_db, csrf_session): resp = handle_subscription_add({"dest_hash": ["abc123"]}) assert "32-character" in resp["body"] assert _subscription_count() == 0 def test_rejects_non_hex(temp_db, csrf_session): resp = handle_subscription_add({"dest_hash": ["z" * 32]}) assert "hex" in resp["body"].lower() assert _subscription_count() == 0 def test_rejects_unreachable_peer(temp_db, csrf_session): with patch.object(handlers_module, "fetch_remote_sites") as fetch: fetch.side_effect = ConnectionError("unreachable") resp = handle_subscription_add({"dest_hash": [VALID_HASH]}) assert "Could not reach" in resp["body"] assert _subscription_count() == 0 def test_rejects_peer_with_sharing_disabled(temp_db, csrf_session): with patch.object(handlers_module, "fetch_remote_sites") as fetch: fetch.side_effect = PermissionError("sharing disabled") resp = handle_subscription_add({"dest_hash": [VALID_HASH]}) assert "sharing disabled" in resp["body"] assert _subscription_count() == 0 def test_successful_add_records_subscription(temp_db, csrf_session): with patch.object(handlers_module, "fetch_remote_sites") as fetch: fetch.return_value = {"name": "alice", "sites": []} resp = handle_subscription_add({"dest_hash": [VALID_HASH]}) assert "Subscribed to alice" in resp["body"] assert _subscription_count() == 1 def test_dest_hash_strips_angle_brackets(temp_db, csrf_session): """Users often paste hashes as `` from RNS log output; strip them.""" with patch.object(handlers_module, "fetch_remote_sites") as fetch: fetch.return_value = {"name": "bob", "sites": []} resp = handle_subscription_add({"dest_hash": [f"<{VALID_HASH}>"]}) assert _subscription_count() == 1 def test_browse_unknown_subscription_is_404(temp_db, csrf_session): resp = handle_subscription_browse(99999) assert resp["status"] == 404 def test_browse_marks_already_indexed_urls(seeded_db, csrf_session): # Insert a subscription + some remote pages (one duplicate of local, one new). db = get_db() try: db.execute( "INSERT INTO subscriptions (dest_hash, name) VALUES (?, ?)", (VALID_HASH, "alice"), ) sub_id = db.execute("SELECT id FROM subscriptions").fetchone()["id"] db.execute( "INSERT INTO remote_pages (subscription_id, url, title, note, tags) " "VALUES (?, ?, ?, ?, ?)", (sub_id, "https://example.com/rust-intro", "Alice rust pick", "", ""), ) db.execute( "INSERT INTO remote_pages (subscription_id, url, title, note, tags) " "VALUES (?, ?, ?, ?, ?)", (sub_id, "https://new.example.com/shiny", "Shiny New Link", "note", "tag1"), ) db.commit() finally: return_db(db) resp = handle_subscription_browse(sub_id) body = resp["body"] assert resp["status"] == 200 assert "already indexed" in body # The duplicate URL should appear in the "already indexed" section. assert "Alice rust pick" in body # The new URL should be in the selectable section. assert "Shiny New Link" in body # Count summary: "2 site(s) available, 1 new" assert "1 new" in body