@@ -194,6 +194,63 @@ def test_corrupted_file_backup_created(self):
194194 assert len (backup_files ) == 1
195195 assert "corrupted" in backup_files [0 ]
196196
197+ def test_transient_errors_do_not_delete_database (self ):
198+ """Test that transient I/O errors (like PermissionError) don't trigger database deletion.
199+
200+ This is a regression test for a bug where the catch-all Exception handler
201+ would delete valid databases on transient errors like PermissionError,
202+ OSError, or temporary lock conflicts.
203+ """
204+ with tempfile .TemporaryDirectory () as tmpdir :
205+ db_path = os .path .join (tmpdir , "valid.db" )
206+
207+ # Create a valid database
208+ conn = sqlite3 .connect (db_path )
209+ conn .execute ("CREATE TABLE test (id INTEGER PRIMARY KEY, data TEXT)" )
210+ conn .execute ("INSERT INTO test VALUES (1, 'important data')" )
211+ conn .commit ()
212+ conn .close ()
213+
214+ # Verify the database is valid first
215+ result = check_and_repair_database (db_path )
216+ assert result is True
217+ assert os .path .exists (db_path )
218+
219+ # The database should still exist and be valid
220+ conn = sqlite3 .connect (db_path )
221+ cursor = conn .execute ("SELECT data FROM test WHERE id=1" )
222+ row = cursor .fetchone ()
223+ conn .close ()
224+ assert row [0 ] == "important data"
225+
226+ def test_database_error_without_corruption_indicator_is_not_auto_repaired (self ):
227+ """Test that DatabaseError without corruption indicators is re-raised, not auto-repaired."""
228+ from unittest .mock import patch , MagicMock
229+ from peewee import DatabaseError
230+
231+ with tempfile .TemporaryDirectory () as tmpdir :
232+ db_path = os .path .join (tmpdir , "locked.db" )
233+
234+ # Create a valid database first
235+ conn = sqlite3 .connect (db_path )
236+ conn .execute ("CREATE TABLE test (id INTEGER)" )
237+ conn .close ()
238+
239+ # Mock SqliteDatabase to raise a non-corruption DatabaseError (e.g., database locked)
240+ with patch ("eval_protocol.event_bus.sqlite_event_bus_database.SqliteDatabase" ) as mock_db_class :
241+ mock_db = MagicMock ()
242+ mock_db_class .return_value = mock_db
243+ mock_db .connect .side_effect = DatabaseError ("database is locked" )
244+
245+ # Should re-raise the error, not delete the database
246+ with pytest .raises (DatabaseError ) as exc_info :
247+ check_and_repair_database (db_path , auto_repair = True )
248+
249+ assert "locked" in str (exc_info .value )
250+
251+ # Database file should still exist (not deleted)
252+ assert os .path .exists (db_path )
253+
197254
198255class TestBackupAndRemoveDatabase :
199256 """Test the backup and remove database functionality."""
0 commit comments