def test_unhandled_exceptions_in_add_remove(self): sds = sync_store.ContainerSyncStore(self.devices_dir, self.logger, False) cfile = self.pick_dbfile() broker = FakeContainerBroker(cfile) with mock.patch('swift.container.sync_store.os.stat', side_effect=OSError(errno.EPERM, 'permission denied')): with self.assertRaises(OSError) as cm: sds.add_synced_container(broker) self.assertEqual(errno.EPERM, cm.exception.errno) with mock.patch('swift.container.sync_store.os.makedirs', side_effect=OSError(errno.EPERM, 'permission denied')): with self.assertRaises(OSError) as cm: sds.add_synced_container(broker) self.assertEqual(errno.EPERM, cm.exception.errno) with mock.patch('swift.container.sync_store.os.symlink', side_effect=OSError(errno.EPERM, 'permission denied')): with self.assertRaises(OSError) as cm: sds.add_synced_container(broker) self.assertEqual(errno.EPERM, cm.exception.errno) with mock.patch('swift.container.sync_store.os.unlink', side_effect=OSError(errno.EPERM, 'permission denied')): with self.assertRaises(OSError) as cm: sds.remove_synced_container(broker) self.assertEqual(errno.EPERM, cm.exception.errno)
def test_remove_synced_container(self): # Add a synced container to remove sds = sync_store.ContainerSyncStore(self.devices_dir, self.logger, False) cfile = self.pick_dbfile() # We keep here the link file so as to validate its deletion later lfile = sds._container_to_synced_container_path(cfile) broker = FakeContainerBroker(cfile) sds.add_synced_container(broker) # Remove existing and non-existing synced containers for i in range(2): sds.remove_synced_container(broker) iterated_synced_containers = list() for db_path in sds.synced_containers_generator(): iterated_synced_containers.append(db_path) self.assertEqual(len(iterated_synced_containers), 0) # Make sure the whole link path gets deleted # recall that the path has the following suffix: # <hexa string of length 6>/<hexa string of length 3>/ # <hexa string of length 32>/<same 32 hexa string>.db # and we expect the .db as well as all path elements # to get deleted self.assertFalse(os.path.exists(lfile)) lfile = os.path.dirname(lfile) for i in range(3): self.assertFalse(os.path.exists(os.path.dirname(lfile))) lfile = os.path.dirname(lfile)
def test_update_sync_store_according_to_metadata_and_deleted(self): # This function tests the update_sync_store 'logics' # with respect to various combinations of the # sync-to and sync-key metadata items and whether # the database is marked for delete. # The table below summarizes the expected result # for the various combinations, e.g.: # If metadata items exist and the database # is not marked for delete then add should be called. results_list = [ [False, 'a', 'b', 'add'], [False, 'a', '', 'remove'], [False, 'a', None, 'remove'], [False, '', 'b', 'remove'], [False, '', '', 'remove'], [False, '', None, 'remove'], [False, None, 'b', 'remove'], [False, None, '', 'remove'], [False, None, None, 'none'], [True, 'a', 'b', 'remove'], [True, 'a', '', 'remove'], [True, 'a', None, 'remove'], [True, '', 'b', 'remove'], [True, '', '', 'remove'], [True, '', None, 'remove'], [True, None, 'b', 'remove'], [True, None, '', 'remove'], [True, None, None, 'none'], ] store = 'swift.container.sync_store.ContainerSyncStore' with mock.patch(store + '.add_synced_container') as add_container: with mock.patch(store + '.remove_synced_container') as remove_container: sds = sync_store.ContainerSyncStore(self.devices_dir, self.logger, False) add_calls = 0 remove_calls = 0 # We now iterate over the list of combinations # Validating that add and removed are called as # expected for deleted, sync_to, sync_key, expected_op in results_list: cfile = self.pick_dbfile() broker = FakeContainerBroker(cfile) broker._is_deleted = deleted if sync_to is not None: broker.metadata['X-Container-Sync-To'] = [sync_to, 1] if sync_key is not None: broker.metadata['X-Container-Sync-Key'] = [sync_key, 1] sds.update_sync_store(broker) if expected_op == 'add': add_calls += 1 if expected_op == 'remove': remove_calls += 1 self.assertEqual(add_container.call_count, add_calls) self.assertEqual(remove_container.call_count, remove_calls)
def test_iterate_synced_containers(self): # populate sync container db sds = sync_store.ContainerSyncStore(self.devices_dir, self.logger, False) containers = list() for i in range(10): cfile = self.pick_dbfile() broker = FakeContainerBroker(cfile) sds.add_synced_container(broker) containers.append(cfile) iterated_synced_containers = list() for db_path in sds.synced_containers_generator(): iterated_synced_containers.append(db_path) self.assertEqual(set(containers), set(iterated_synced_containers))
def test_add_synced_container(self): # Add non-existing and existing synced containers sds = sync_store.ContainerSyncStore(self.devices_dir, self.logger, False) cfile = self.pick_dbfile() broker = FakeContainerBroker(cfile) for i in range(2): sds.add_synced_container(broker) scpath = sds._container_to_synced_container_path(cfile) with open(scpath, 'r') as infile: self.assertEqual(infile.read(), cfile) iterated_synced_containers = list() for db_path in sds.synced_containers_generator(): iterated_synced_containers.append(db_path) self.assertEqual(len(iterated_synced_containers), 1)
def test_container_to_synced_container_path_conversion(self): # The conversion functions are oblivious to the suffix # so we just pick up a constant one. db_path_suffix = self._db_path_suffix() # We build various container path putting in both # DATADIR and SYNC_DATADIR strings in the # device and devices parts. for devices, device in self._container_path_elements_generator(): path = os.path.join(devices, device, DATADIR, db_path_suffix) # Call the conversion function sds = sync_store.ContainerSyncStore(devices, self.logger, False) path = sds._container_to_synced_container_path(path) # Validate that ONLY the DATADIR part was replaced with # sync_store.SYNC_DATADIR self._validate_container_path_parts(path, devices, device, sync_store.SYNC_DATADIR, db_path_suffix)