refactor(sync): drop favorite-folder tracking and deal
This commit is contained in:
1 parent
62abbd7ea1
commit
6c4287b43a
21 files changed
+1390
-2766
No files matched your search
+142
-142
@@ -1,142 +1,142 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
"""数据库单写队列测试(不联网): uv run python tests/test_database.py"""
|
||||
|
||||
import os
|
||||
import sqlite3
|
||||
import sys
|
||||
import tempfile
|
||||
import threading
|
||||
from pathlib import Path
|
||||
|
||||
sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
|
||||
sys.stdout.reconfigure(encoding="utf-8")
|
||||
|
||||
from reaction_board.database import Database, DatabaseClosed # noqa: E402
|
||||
|
||||
|
||||
def make_db(tmp):
|
||||
db = Database(Path(tmp) / "app.db", backup_dir=Path(tmp) / "backup")
|
||||
db.initialize()
|
||||
return db
|
||||
|
||||
|
||||
def test_write_read_transaction():
|
||||
with tempfile.TemporaryDirectory() as tmp:
|
||||
db = make_db(tmp)
|
||||
try:
|
||||
assert db.schema_version == 4
|
||||
db.write(lambda c: c.execute("INSERT INTO kv(k, v) VALUES ('a', '1')"))
|
||||
assert db.read(lambda c: c.execute("SELECT v FROM kv WHERE k='a'").fetchone()[0]) == "1"
|
||||
|
||||
def boom(conn):
|
||||
conn.execute("UPDATE kv SET v='2' WHERE k='a'")
|
||||
raise RuntimeError("boom")
|
||||
try:
|
||||
db.transaction(boom)
|
||||
except RuntimeError as exc:
|
||||
assert str(exc) == "boom"
|
||||
else:
|
||||
raise AssertionError("事务应抛错")
|
||||
assert db.read(lambda c: c.execute("SELECT v FROM kv WHERE k='a'").fetchone()[0]) == "1"
|
||||
finally:
|
||||
db.close()
|
||||
|
||||
|
||||
def test_concurrent_writes_are_serialized():
|
||||
with tempfile.TemporaryDirectory() as tmp:
|
||||
db = make_db(tmp)
|
||||
try:
|
||||
db.write(lambda c: c.execute(
|
||||
"CREATE TABLE counter (id INTEGER PRIMARY KEY, n INTEGER NOT NULL)"
|
||||
))
|
||||
db.write(lambda c: c.execute("INSERT INTO counter(id, n) VALUES (1, 0)"))
|
||||
errors = []
|
||||
|
||||
def worker():
|
||||
try:
|
||||
for _ in range(10):
|
||||
db.transaction(
|
||||
lambda conn: conn.execute(
|
||||
"UPDATE counter SET n = n + 1 WHERE id = 1"
|
||||
)
|
||||
)
|
||||
except Exception as exc: # noqa: BLE001
|
||||
errors.append(exc)
|
||||
|
||||
threads = [threading.Thread(target=worker) for _ in range(8)]
|
||||
for t in threads:
|
||||
t.start()
|
||||
for t in threads:
|
||||
t.join()
|
||||
assert not errors, errors
|
||||
assert db.read(lambda c: c.execute("SELECT n FROM counter").fetchone()[0]) == 80
|
||||
finally:
|
||||
db.close()
|
||||
|
||||
|
||||
def test_close_and_reinitialize():
|
||||
with tempfile.TemporaryDirectory() as tmp:
|
||||
db = make_db(tmp)
|
||||
db.close()
|
||||
db.close() # 幂等
|
||||
try:
|
||||
db.write(lambda c: None)
|
||||
except DatabaseClosed:
|
||||
pass
|
||||
else:
|
||||
raise AssertionError("关闭后写入应失败")
|
||||
try:
|
||||
db.read(lambda c: None)
|
||||
except DatabaseClosed:
|
||||
pass
|
||||
else:
|
||||
raise AssertionError("关闭后读取应失败")
|
||||
|
||||
db2 = make_db(tmp)
|
||||
try:
|
||||
assert db2.schema_version == 4
|
||||
assert db2.read(lambda c: c.execute("SELECT MAX(version) FROM schema_version").fetchone()[0]) == 4
|
||||
finally:
|
||||
db2.close()
|
||||
|
||||
|
||||
def test_wal_enabled():
|
||||
with tempfile.TemporaryDirectory() as tmp:
|
||||
db = make_db(tmp)
|
||||
try:
|
||||
mode = db.read(lambda c: c.execute("PRAGMA journal_mode").fetchone()[0])
|
||||
assert str(mode).lower() == "wal"
|
||||
assert db.read(lambda c: c.execute("PRAGMA foreign_keys").fetchone()[0]) == 1
|
||||
finally:
|
||||
db.close()
|
||||
|
||||
|
||||
def test_migration_backup_on_existing_db():
|
||||
"""已有数据升级时由 Database 自动备份。"""
|
||||
with tempfile.TemporaryDirectory() as tmp:
|
||||
path = Path(tmp) / "app.db"
|
||||
# 先建一个旧库(只有 schema_version v0),Database.initialize 会升级并备份
|
||||
conn = sqlite3.connect(path)
|
||||
conn.execute("CREATE TABLE legacy (x INTEGER)")
|
||||
conn.commit()
|
||||
conn.close()
|
||||
db = Database(path, backup_dir=Path(tmp) / "backup")
|
||||
try:
|
||||
applied = db.initialize()
|
||||
assert applied == [1, 2, 3, 4]
|
||||
assert len(list((Path(tmp) / "backup").glob("app-pre-v0-*.db"))) == 1
|
||||
finally:
|
||||
db.close()
|
||||
|
||||
|
||||
def main():
|
||||
test_write_read_transaction()
|
||||
test_concurrent_writes_are_serialized()
|
||||
test_close_and_reinitialize()
|
||||
test_wal_enabled()
|
||||
test_migration_backup_on_existing_db()
|
||||
print("OK: 数据库单写队列与迁移入口测试全部通过")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
# -*- coding: utf-8 -*-
|
||||
"""数据库单写队列测试(不联网): uv run python tests/test_database.py"""
|
||||
|
||||
import os
|
||||
import sqlite3
|
||||
import sys
|
||||
import tempfile
|
||||
import threading
|
||||
from pathlib import Path
|
||||
|
||||
sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
|
||||
sys.stdout.reconfigure(encoding="utf-8")
|
||||
|
||||
from reaction_board.database import Database, DatabaseClosed # noqa: E402
|
||||
|
||||
|
||||
def make_db(tmp):
|
||||
db = Database(Path(tmp) / "app.db", backup_dir=Path(tmp) / "backup")
|
||||
db.initialize()
|
||||
return db
|
||||
|
||||
|
||||
def test_write_read_transaction():
|
||||
with tempfile.TemporaryDirectory() as tmp:
|
||||
db = make_db(tmp)
|
||||
try:
|
||||
assert db.schema_version == 5
|
||||
db.write(lambda c: c.execute("INSERT INTO kv(k, v) VALUES ('a', '1')"))
|
||||
assert db.read(lambda c: c.execute("SELECT v FROM kv WHERE k='a'").fetchone()[0]) == "1"
|
||||
|
||||
def boom(conn):
|
||||
conn.execute("UPDATE kv SET v='2' WHERE k='a'")
|
||||
raise RuntimeError("boom")
|
||||
try:
|
||||
db.transaction(boom)
|
||||
except RuntimeError as exc:
|
||||
assert str(exc) == "boom"
|
||||
else:
|
||||
raise AssertionError("事务应抛错")
|
||||
assert db.read(lambda c: c.execute("SELECT v FROM kv WHERE k='a'").fetchone()[0]) == "1"
|
||||
finally:
|
||||
db.close()
|
||||
|
||||
|
||||
def test_concurrent_writes_are_serialized():
|
||||
with tempfile.TemporaryDirectory() as tmp:
|
||||
db = make_db(tmp)
|
||||
try:
|
||||
db.write(lambda c: c.execute(
|
||||
"CREATE TABLE counter (id INTEGER PRIMARY KEY, n INTEGER NOT NULL)"
|
||||
))
|
||||
db.write(lambda c: c.execute("INSERT INTO counter(id, n) VALUES (1, 0)"))
|
||||
errors = []
|
||||
|
||||
def worker():
|
||||
try:
|
||||
for _ in range(10):
|
||||
db.transaction(
|
||||
lambda conn: conn.execute(
|
||||
"UPDATE counter SET n = n + 1 WHERE id = 1"
|
||||
)
|
||||
)
|
||||
except Exception as exc: # noqa: BLE001
|
||||
errors.append(exc)
|
||||
|
||||
threads = [threading.Thread(target=worker) for _ in range(8)]
|
||||
for t in threads:
|
||||
t.start()
|
||||
for t in threads:
|
||||
t.join()
|
||||
assert not errors, errors
|
||||
assert db.read(lambda c: c.execute("SELECT n FROM counter").fetchone()[0]) == 80
|
||||
finally:
|
||||
db.close()
|
||||
|
||||
|
||||
def test_close_and_reinitialize():
|
||||
with tempfile.TemporaryDirectory() as tmp:
|
||||
db = make_db(tmp)
|
||||
db.close()
|
||||
db.close() # 幂等
|
||||
try:
|
||||
db.write(lambda c: None)
|
||||
except DatabaseClosed:
|
||||
pass
|
||||
else:
|
||||
raise AssertionError("关闭后写入应失败")
|
||||
try:
|
||||
db.read(lambda c: None)
|
||||
except DatabaseClosed:
|
||||
pass
|
||||
else:
|
||||
raise AssertionError("关闭后读取应失败")
|
||||
|
||||
db2 = make_db(tmp)
|
||||
try:
|
||||
assert db2.schema_version == 5
|
||||
assert db2.read(lambda c: c.execute("SELECT MAX(version) FROM schema_version").fetchone()[0]) == 5
|
||||
finally:
|
||||
db2.close()
|
||||
|
||||
|
||||
def test_wal_enabled():
|
||||
with tempfile.TemporaryDirectory() as tmp:
|
||||
db = make_db(tmp)
|
||||
try:
|
||||
mode = db.read(lambda c: c.execute("PRAGMA journal_mode").fetchone()[0])
|
||||
assert str(mode).lower() == "wal"
|
||||
assert db.read(lambda c: c.execute("PRAGMA foreign_keys").fetchone()[0]) == 1
|
||||
finally:
|
||||
db.close()
|
||||
|
||||
|
||||
def test_migration_backup_on_existing_db():
|
||||
"""已有数据升级时由 Database 自动备份。"""
|
||||
with tempfile.TemporaryDirectory() as tmp:
|
||||
path = Path(tmp) / "app.db"
|
||||
# 先建一个旧库(只有 schema_version v0),Database.initialize 会升级并备份
|
||||
conn = sqlite3.connect(path)
|
||||
conn.execute("CREATE TABLE legacy (x INTEGER)")
|
||||
conn.commit()
|
||||
conn.close()
|
||||
db = Database(path, backup_dir=Path(tmp) / "backup")
|
||||
try:
|
||||
applied = db.initialize()
|
||||
assert applied == [1, 2, 3, 4, 5]
|
||||
assert len(list((Path(tmp) / "backup").glob("app-pre-v0-*.db"))) == 1
|
||||
finally:
|
||||
db.close()
|
||||
|
||||
|
||||
def main():
|
||||
test_write_read_transaction()
|
||||
test_concurrent_writes_are_serialized()
|
||||
test_close_and_reinitialize()
|
||||
test_wal_enabled()
|
||||
test_migration_backup_on_existing_db()
|
||||
print("OK: 数据库单写队列与迁移入口测试全部通过")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
Reference in new issue
Block a user