Quarantine malformed database schema SQLite errors

Currently if an sqlite3.DatabaseError is thrown when caused by
a corrupted database schema, it get logged and the database is isn't
quarantined.

This patch adds the malformed database schema case to the list of
SQLite errors in possibly_quarantine that will trigger the db to be
quarantined.

Also it improved the possibly_quarantined unit test to test all existing
exceptions, and catches exceptions based on the real world except we use
in code.

Closes-Bug: #1646247

Change-Id: Id9452c88f8394a2a910c34c69361442543aa206d
This commit is contained in:
Matthew Oliver 2016-12-01 09:46:53 +11:00
parent a92836074c
commit 3bde14b5cf
3 changed files with 44 additions and 19 deletions

View File

@ -331,6 +331,8 @@ class DatabaseBroker(object):
"""
if 'database disk image is malformed' in str(exc_value):
exc_hint = 'malformed'
elif 'malformed database schema' in str(exc_value):
exc_hint = 'malformed'
elif 'file is encrypted or is not a database' in str(exc_value):
exc_hint = 'corrupted'
elif 'disk I/O error' in str(exc_value):

Binary file not shown.

View File

@ -749,6 +749,22 @@ class TestDatabaseBroker(unittest.TestCase):
broker = DatabaseBroker(os.path.join(dbpath, '1.db'))
broker.db_type = 'test'
exc = None
try:
with broker.get() as conn:
conn.execute('SELECT * FROM test')
except Exception as err:
exc = err
self.assertEqual(
str(exc),
'Quarantined %s to %s due to malformed database' %
(dbpath, qpath))
# Test malformed schema database
copy(os.path.join(os.path.dirname(__file__),
'malformed_schema_example.db'),
os.path.join(dbpath, '1.db'))
broker = DatabaseBroker(os.path.join(dbpath, '1.db'))
broker.db_type = 'test'
exc = None
try:
with broker.get() as conn:
conn.execute('SELECT * FROM test')
@ -1214,29 +1230,36 @@ class TestDatabaseBroker(unittest.TestCase):
message = str(e)
self.assertEqual(message, '400 Bad Request')
def test_possibly_quarantine_disk_error(self):
def test_possibly_quarantine_db_errors(self):
dbpath = os.path.join(self.testdir, 'dev', 'dbs', 'par', 'pre', 'db')
mkdirs(dbpath)
qpath = os.path.join(self.testdir, 'dev', 'quarantined', 'tests', 'db')
broker = DatabaseBroker(os.path.join(dbpath, '1.db'))
broker.db_type = 'test'
# Data is a list of Excpetions to be raised and expected values in the
# log
data = [
(sqlite3.DatabaseError('database disk image is malformed'),
'malformed'),
(sqlite3.DatabaseError('malformed database schema'), 'malformed'),
(sqlite3.DatabaseError('file is encrypted or is not a database'),
'corrupted'),
(sqlite3.OperationalError('disk I/O error'),
'disk error while accessing')]
def stub():
raise sqlite3.OperationalError('disk I/O error')
try:
stub()
except Exception:
for i, (ex, hint) in enumerate(data):
mkdirs(dbpath)
broker = DatabaseBroker(os.path.join(dbpath, '%d.db' % (i)))
broker.db_type = 'test'
try:
broker.possibly_quarantine(*sys.exc_info())
except Exception as exc:
self.assertEqual(
str(exc),
'Quarantined %s to %s due to disk error '
'while accessing database' %
(dbpath, qpath))
else:
self.fail('Expected an exception to be raised')
raise ex
except (sqlite3.DatabaseError, DatabaseConnectionError):
try:
broker.possibly_quarantine(*sys.exc_info())
except Exception as exc:
self.assertEqual(
str(exc),
'Quarantined %s to %s due to %s database' %
(dbpath, qpath, hint))
else:
self.fail('Expected an exception to be raised')
if __name__ == '__main__':
unittest.main()