diff --git a/swift/obj/ssync_sender.py b/swift/obj/ssync_sender.py index 7496189ad8..dc288c0113 100644 --- a/swift/obj/ssync_sender.py +++ b/swift/obj/ssync_sender.py @@ -301,7 +301,7 @@ class Sender(object): """ Sends a DELETE subrequest with the given information. """ - msg = ['DELETE ' + url_path, 'X-Timestamp: ' + timestamp] + msg = ['DELETE ' + url_path, 'X-Timestamp: ' + timestamp.internal] msg = '\r\n'.join(msg) + '\r\n\r\n' with exceptions.MessageTimeout( self.daemon.node_timeout, 'send_delete'): diff --git a/test/probe/test_object_metadata_replication.py b/test/probe/test_object_metadata_replication.py index 0af46250f3..fffdf2e4bf 100644 --- a/test/probe/test_object_metadata_replication.py +++ b/test/probe/test_object_metadata_replication.py @@ -111,11 +111,65 @@ class Test(ReplProbeTest): self.int_client.set_object_metadata(self.account, self.container_name, self.object_name, headers) + def _delete_object(self): + self.int_client.delete_object(self.account, self.container_name, + self.object_name) + + def _get_object(self, headers=None, expect_statuses=(2,)): + return self.int_client.get_object(self.account, + self.container_name, + self.object_name, + headers, + acceptable_statuses=expect_statuses) + def _get_object_metadata(self): return self.int_client.get_object_metadata(self.account, self.container_name, self.object_name) + def test_object_delete_is_replicated(self): + self.brain.put_container(policy_index=0) + # put object + self._put_object() + + # put newer object with sysmeta to first server subset + self.brain.stop_primary_half() + self._put_object() + self.brain.start_primary_half() + + # delete object on second server subset + self.brain.stop_handoff_half() + self._delete_object() + self.brain.start_handoff_half() + + # run replicator + get_to_final_state() + + # check object deletion has been replicated on first server set + self.brain.stop_primary_half() + self._get_object(expect_statuses=(4,)) + self.brain.start_primary_half() + + # check object deletion persists on second server set + self.brain.stop_handoff_half() + self._get_object(expect_statuses=(4,)) + + # put newer object to second server set + self._put_object() + self.brain.start_handoff_half() + + # run replicator + get_to_final_state() + + # check new object has been replicated on first server set + self.brain.stop_primary_half() + self._get_object() + self.brain.start_primary_half() + + # check new object persists on second server set + self.brain.stop_handoff_half() + self._get_object() + @expected_failure_with_ssync def test_sysmeta_after_replication_with_subsequent_post(self): sysmeta = {'x-object-sysmeta-foo': 'sysmeta-foo'} diff --git a/test/unit/obj/test_ssync_sender.py b/test/unit/obj/test_ssync_sender.py index d4538b454d..87efd64cc7 100644 --- a/test/unit/obj/test_ssync_sender.py +++ b/test/unit/obj/test_ssync_sender.py @@ -762,6 +762,33 @@ class TestSender(unittest.TestCase): '11\r\n:UPDATES: START\r\n\r\n' 'f\r\n:UPDATES: END\r\n\r\n') + def test_update_send_delete(self): + device = 'dev' + part = '9' + object_parts = ('a', 'c', 'o') + df = self._make_open_diskfile(device, part, *object_parts) + object_hash = utils.hash_path(*object_parts) + delete_timestamp = utils.normalize_timestamp(time.time()) + df.delete(delete_timestamp) + self.sender.connection = FakeConnection() + self.sender.job = {'device': device, 'partition': part} + self.sender.node = {} + self.sender.send_list = [object_hash] + self.sender.response = FakeResponse( + chunk_body=( + ':UPDATES: START\r\n' + ':UPDATES: END\r\n')) + self.sender.updates() + self.assertEqual( + ''.join(self.sender.connection.sent), + '11\r\n:UPDATES: START\r\n\r\n' + '30\r\n' + 'DELETE /a/c/o\r\n' + 'X-Timestamp: %s\r\n\r\n\r\n' + 'f\r\n:UPDATES: END\r\n\r\n' + % delete_timestamp + ) + def test_updates_put(self): device = 'dev' part = '9' @@ -937,14 +964,16 @@ class TestSender(unittest.TestCase): self.sender.daemon.node_timeout = 0.01 exc = None try: - self.sender.send_delete('/a/c/o', '1381679759.90941') + self.sender.send_delete('/a/c/o', + utils.Timestamp('1381679759.90941')) except exceptions.MessageTimeout as err: exc = err self.assertEqual(str(exc), '0.01 seconds: send_delete') def test_send_delete(self): self.sender.connection = FakeConnection() - self.sender.send_delete('/a/c/o', '1381679759.90941') + self.sender.send_delete('/a/c/o', + utils.Timestamp('1381679759.90941')) self.assertEqual( ''.join(self.sender.connection.sent), '30\r\n'