tinyweb/tests/test_db_schema.py
lichenblankie 4d522ce62c added pytest test suite (174 tests)
174 tests covering URL normalization, FTS5 query sanitization, SSRF/CSRF
guards, sharing-mode logic, DB schema and upsert paths, handler
end-to-end flows, and gateway body-size / mesh-whitelist guards. Each
recent bug-fix commit (6ffd38d, 1bc695f, 8dffd8c) has an explicit
regression test in test_regressions.py. One xfail documents a minor
latent bug in clean_url where port 80 is not stripped from upgraded
https URLs.
2026-06-05 05:29:36 +00:00

90 lines
2.6 KiB
Python

"""Tests for `init_db` and the settings key-value store.
`init_db` is called unconditionally on startup, so it must be idempotent
and create every table/trigger the rest of the app expects.
"""
from db import get_db, return_db, init_db, get_setting, set_setting, get_site_name
EXPECTED_TABLES = {
"pages", "links", "settings", "subscriptions",
"remote_pages", "tags", "page_tags", "chunks",
# FTS5 virtual tables:
"pages_fts", "remote_pages_fts",
}
def test_all_expected_tables_exist(temp_db):
db = get_db()
try:
rows = db.execute(
"SELECT name FROM sqlite_master WHERE type IN ('table') AND name NOT LIKE 'sqlite_%'"
).fetchall()
names = {r["name"] for r in rows}
finally:
return_db(db)
missing = EXPECTED_TABLES - names
assert not missing, f"tables missing after init_db: {missing}"
def test_fts_triggers_exist(temp_db):
db = get_db()
try:
rows = db.execute(
"SELECT name FROM sqlite_master WHERE type = 'trigger'"
).fetchall()
names = {r["name"] for r in rows}
finally:
return_db(db)
# These triggers keep pages_fts in sync with pages on insert/update/delete.
for trigger in ("pages_ai", "pages_ad", "pages_au"):
assert trigger in names, f"missing trigger {trigger}"
def test_init_db_is_idempotent(temp_db):
"""Running init_db twice on the same DB must not error or duplicate anything."""
init_db()
init_db() # second call should be a no-op
db = get_db()
try:
count = db.execute(
"SELECT count(*) FROM sqlite_master WHERE name = 'pages'"
).fetchone()[0]
finally:
return_db(db)
assert count == 1
def test_get_setting_returns_default_when_missing(temp_db):
assert get_setting("nonexistent", "fallback") == "fallback"
assert get_setting("nonexistent") == ""
def test_set_setting_then_get(temp_db):
set_setting("site_name", "my-personal-index")
assert get_setting("site_name") == "my-personal-index"
def test_set_setting_updates_existing(temp_db):
set_setting("key", "first")
set_setting("key", "second")
assert get_setting("key") == "second"
def test_get_site_name_has_default(temp_db):
assert get_site_name() == "tinyweb"
def test_get_site_name_reflects_override(temp_db):
set_setting("site_name", "custom-site")
assert get_site_name() == "custom-site"
def test_foreign_keys_pragma_enabled(temp_db):
"""Pool connections should have foreign_keys=ON so CASCADE deletes work."""
db = get_db()
try:
row = db.execute("PRAGMA foreign_keys").fetchone()
finally:
return_db(db)
assert row[0] == 1