import hashlib from pathlib import Path import sqlite3 import tempfile import unittest from sqlite_readonly import inspect_readonly class PreOpenSchemaGate(unittest.TestCase): def test_old_and_unknown_schemas_refuse_without_mutation(self): with tempfile.TemporaryDirectory() as folder: for version in (0, 1, 2, 3, 4, 6): db = Path(folder) / (str(version) + '.sqlite') with sqlite3.connect(db) as connection: connection.execute('PRAGMA user_version=' + str(version)) before = hashlib.sha256(db.read_bytes()).hexdigest() with self.assertRaises(ValueError): inspect_readonly(db) self.assertEqual(hashlib.sha256(db.read_bytes()).hexdigest(), before) with sqlite3.connect(db) as connection: self.assertEqual(connection.execute('PRAGMA user_version').fetchone()[0], version) def test_schema5_frozen_snapshot_counts_and_integrity(self): with tempfile.TemporaryDirectory() as folder: db = Path(folder) / 'snapshot.sqlite' with sqlite3.connect(db) as connection: connection.executescript('PRAGMA user_version=5; CREATE TABLE lifecycle_records(x); CREATE TABLE lifecycle_events(x); CREATE TABLE lifecycle_pending(x); CREATE TABLE outbox(state); CREATE TABLE submissions(state); INSERT INTO lifecycle_records VALUES(1); INSERT INTO outbox VALUES("pending"); INSERT INTO submissions VALUES("confirmed");') before = hashlib.sha256(db.read_bytes()).hexdigest() proof = inspect_readonly(db) self.assertEqual(proof['schema_version'], 5) self.assertEqual(proof['lifecycle']['records'], 1) self.assertEqual(proof['outbox'], {'pending': 1}) self.assertEqual(proof['submissions'], {'confirmed': 1}) self.assertEqual(proof['integrity'], 'ok') self.assertFalse(proof['store_constructed']) self.assertEqual(hashlib.sha256(db.read_bytes()).hexdigest(), before) def test_missing_database_is_not_created(self): with tempfile.TemporaryDirectory() as folder: missing = Path(folder) / 'missing.sqlite' with self.assertRaises(ValueError): inspect_readonly(missing) self.assertFalse(missing.exists()) if __name__ == '__main__': unittest.main()