@ -128,6 +128,53 @@ class TestDatabaseArchive(integrated_helpers._IntegratedTestBase):
# Verify that the pci_devices record has not been dropped
"""This tests a scenario where archive_deleted_rows is run with
--max_rows and does not run to completion.
That is, the archive is stopped before all archivable records have been
archived. Specifically, the problematic state is when a single instance
becomes partially archived (example: 'instance_extra' record for one
instance has been archived while its 'instances' record remains). Any
access of the instance (example: listing deleted instances) that
triggers the retrieval of a dependent record that has been archived
away, results in undefined behavior that may raise an error.
We will force the system into a state where a single deleted instance
is partially archived. We want to verify that we can, for example,
successfully do a GET /servers/detail at any point between partial
archive_deleted_rows runs without errors.
# Boots a server, deletes it, and then tries to archive it.
server = self._create_server()
server_id = server['id']
# Assert that there are instance_actions. instance_actions are
# interesting since we don't soft delete them but they have a foreign
# key back to the instances table.
actions = self.api.get_instance_actions(server_id)
'No instance actions for server: %s' % server_id)
# Archive deleted records iteratively, 1 row at a time, and try to do a
# GET /servers/detail between each run. All should succeed.
exceptions = 
_, _, archived = db.archive_deleted_rows(max_rows=1)
# Need to use the admin API to list deleted servers.
except Exception as ex:
if archived == 0:
# FIXME(melwitt): OrphanedObjectError is raised because of the bug.
for ex in exceptions:
# FIXME(melwitt): Uncomment when the bug is fixed.
engine = sqlalchemy_api.get_engine()
conn = engine.connect()