保存今天的修改
This commit is contained in:
@@ -8,6 +8,9 @@ import time
|
||||
import unittest
|
||||
from concurrent.futures import ThreadPoolExecutor
|
||||
from threading import Barrier
|
||||
from unittest.mock import patch
|
||||
from contextlib import closing
|
||||
import sqlite3
|
||||
|
||||
from flask import Flask
|
||||
from werkzeug.datastructures import FileStorage
|
||||
@@ -115,6 +118,95 @@ class StorageTests(unittest.TestCase):
|
||||
self.assertFalse(old.exists())
|
||||
self.assertEqual((uploads/'new.txt').read_text(), 'new')
|
||||
|
||||
def test_schema_version_and_pre_migration_snapshot_are_recorded_before_upgrade(self):
|
||||
connection = db.connect()
|
||||
connection.execute('DROP TABLE IF EXISTS schema_meta')
|
||||
connection.commit()
|
||||
connection.close()
|
||||
db.init_db()
|
||||
connection = db.connect()
|
||||
self.assertEqual(connection.execute("SELECT value FROM schema_meta WHERE key='schema_version'").fetchone()[0], str(db.SCHEMA_VERSION))
|
||||
connection.close()
|
||||
snapshots = list((self.root/'backups').glob('pre-migration-*.db'))
|
||||
self.assertEqual(len(snapshots), 1)
|
||||
self.assertEqual(db.check_database(snapshots[0]), 'ok')
|
||||
with closing(sqlite3.connect(snapshots[0])) as snapshot:
|
||||
self.assertIsNone(snapshot.execute("SELECT 1 FROM sqlite_master WHERE name='schema_meta'").fetchone())
|
||||
|
||||
def test_startup_migration_snapshots_keep_only_the_latest_five(self):
|
||||
for _ in range(7):
|
||||
db.init_db()
|
||||
snapshots = sorted((self.root/'backups').glob('pre-migration-*.db'))
|
||||
self.assertEqual(len(snapshots), 5)
|
||||
self.assertTrue(all(path.is_file() for path in snapshots))
|
||||
self.assertTrue(all(db.check_database(path) == 'ok' for path in snapshots))
|
||||
|
||||
def test_backup_failure_prevents_any_schema_changes(self):
|
||||
with closing(db.connect()) as connection:
|
||||
connection.execute('DROP TABLE schema_meta')
|
||||
connection.commit()
|
||||
with patch('logistics_chat.db.snapshot_database', side_effect=OSError('fixture disk full')):
|
||||
with self.assertRaisesRegex(OSError, 'disk full'):
|
||||
db.init_db()
|
||||
with closing(db.connect()) as connection:
|
||||
self.assertIsNone(connection.execute("SELECT 1 FROM sqlite_master WHERE name='schema_meta'").fetchone())
|
||||
|
||||
def test_failed_startup_snapshot_does_not_prune_previous_backups(self):
|
||||
backups = self.root/'backups'
|
||||
backups.mkdir()
|
||||
previous = []
|
||||
for index in range(6):
|
||||
path = backups/f'pre-migration-20260101-00000{index}-000000-{index:08x}.db'
|
||||
db.snapshot_database(self.root/'history.db', path)
|
||||
previous.append(path)
|
||||
with patch('logistics_chat.db.snapshot_database', side_effect=OSError('fixture disk full')):
|
||||
with self.assertRaises(OSError):
|
||||
db.init_db()
|
||||
self.assertTrue(all(path.exists() for path in previous))
|
||||
|
||||
def test_failed_migration_rolls_back_schema_and_data_and_keeps_preimage(self):
|
||||
with closing(db.connect()) as connection:
|
||||
connection.execute('DROP TABLE schema_meta')
|
||||
connection.commit()
|
||||
def broken(connection):
|
||||
connection.execute('CREATE TABLE partial_upgrade(value TEXT)')
|
||||
connection.execute("INSERT INTO tickets(content) VALUES('must roll back')")
|
||||
raise RuntimeError('fixture migration failed')
|
||||
with patch('logistics_chat.db.MIGRATIONS', ((1, broken), *db.MIGRATIONS[1:])):
|
||||
with self.assertRaisesRegex(RuntimeError, 'migration failed'):
|
||||
db.init_db()
|
||||
with closing(db.connect()) as connection:
|
||||
self.assertIsNone(connection.execute("SELECT 1 FROM sqlite_master WHERE name='partial_upgrade'").fetchone())
|
||||
self.assertEqual(connection.execute('SELECT COUNT(*) FROM tickets').fetchone()[0], 0)
|
||||
self.assertEqual(len(list((self.root/'backups').glob('pre-migration-*.db'))), 1)
|
||||
|
||||
def test_newer_database_version_is_never_downgraded(self):
|
||||
with closing(db.connect()) as connection:
|
||||
connection.execute("UPDATE schema_meta SET value='999' WHERE key='schema_version'")
|
||||
connection.commit()
|
||||
with self.assertRaisesRegex(RuntimeError, 'newer'):
|
||||
db.init_db()
|
||||
with closing(db.connect()) as connection:
|
||||
self.assertEqual(connection.execute("SELECT value FROM schema_meta WHERE key='schema_version'").fetchone()[0], '999')
|
||||
|
||||
def test_missing_migration_step_cannot_mark_database_as_upgraded(self):
|
||||
with patch('logistics_chat.db.SCHEMA_VERSION', db.SCHEMA_VERSION + 1):
|
||||
with self.assertRaisesRegex(RuntimeError, 'migration'):
|
||||
db.init_db()
|
||||
with closing(db.connect()) as connection:
|
||||
self.assertEqual(connection.execute("SELECT value FROM schema_meta WHERE key='schema_version'").fetchone()[0], str(db.SCHEMA_VERSION))
|
||||
|
||||
def test_snapshot_backup_is_verified_and_restore_source_is_not_modified(self):
|
||||
destination = self.root/'backups'/'manual.db'
|
||||
db.snapshot_database(self.root/'history.db', destination)
|
||||
self.assertEqual(db.check_database(destination), 'ok')
|
||||
original = destination.read_bytes()
|
||||
connection = db.connect()
|
||||
connection.execute("INSERT INTO chat_history(title,ctime) VALUES('after-backup','now')")
|
||||
connection.commit()
|
||||
connection.close()
|
||||
self.assertEqual(destination.read_bytes(), original)
|
||||
|
||||
def test_upload_uses_generated_name_and_configured_directory(self):
|
||||
upload = FileStorage(stream=io.BytesIO(b'hello'), filename='../report.txt')
|
||||
result = file_service.upload_file({'file': upload})
|
||||
|
||||
Reference in New Issue
Block a user