)]}'
{"test/probe/test_object_expirer.py":[{"author":{"_account_id":7847,"name":"Alistair Coles","email":"alistairncoles@gmail.com","username":"acoles"},"change_message_id":"be5ac7c8d533835b9902165636b1bf001d9c4fff","unresolved":false,"context_lines":[{"line_number":50,"context_line":"        self.brain \u003d BrainSplitter(self.url, self.token, self.container_name,"},{"line_number":51,"context_line":"                                   self.object_name)"},{"line_number":52,"context_line":""},{"line_number":53,"context_line":"    def _check_obj_in_container_listing(self):"},{"line_number":54,"context_line":"        for obj in self.client.iter_objects(self.account,"},{"line_number":55,"context_line":"                                            self.container_name):"},{"line_number":56,"context_line":""}],"source_content_type":"text/x-python","patch_set":8,"id":"9ad45d7e_d6a96ae1","line":53,"updated":"2016-08-08 14:09:10.000000000","message":"nice refactoring","commit_id":"4aa1ae61cb62d9f0e8ca6ceecabb0b9b40fedf96"},{"author":{"_account_id":7847,"name":"Alistair Coles","email":"alistairncoles@gmail.com","username":"acoles"},"change_message_id":"be5ac7c8d533835b9902165636b1bf001d9c4fff","unresolved":false,"context_lines":[{"line_number":251,"context_line":""},{"line_number":252,"context_line":"        # stop primary servers and put a newer version of the object, this"},{"line_number":253,"context_line":"        # time with an expiration. only the handoff servers will have"},{"line_number":254,"context_line":"        # the new version"},{"line_number":255,"context_line":"        obj_brain.stop_primary_half()"},{"line_number":256,"context_line":"        now \u003d time.time()"},{"line_number":257,"context_line":"        delete_at \u003d int(now + 2.0)"}],"source_content_type":"text/x-python","patch_set":8,"id":"9ad45d7e_41cad650","line":254,"updated":"2016-08-08 14:09:10.000000000","message":"bear in mind that for a 3 way replica policy, the \"handoff half\" is actually comprised of one primary and one handoff, whereas the primary half has two primaries","commit_id":"4aa1ae61cb62d9f0e8ca6ceecabb0b9b40fedf96"},{"author":{"_account_id":7847,"name":"Alistair Coles","email":"alistairncoles@gmail.com","username":"acoles"},"change_message_id":"be5ac7c8d533835b9902165636b1bf001d9c4fff","unresolved":false,"context_lines":[{"line_number":253,"context_line":"        # time with an expiration. only the handoff servers will have"},{"line_number":254,"context_line":"        # the new version"},{"line_number":255,"context_line":"        obj_brain.stop_primary_half()"},{"line_number":256,"context_line":"        now \u003d time.time()"},{"line_number":257,"context_line":"        delete_at \u003d int(now + 2.0)"},{"line_number":258,"context_line":"        obj_brain.put_object({\u0027X-Delete-At\u0027: delete_at})"},{"line_number":259,"context_line":""}],"source_content_type":"text/x-python","patch_set":8,"id":"9ad45d7e_961c1279","line":256,"updated":"2016-08-08 14:09:10.000000000","message":"nit: now is only used once, could just write:\n\n  delete_at \u003d int(time.time()) + 2","commit_id":"4aa1ae61cb62d9f0e8ca6ceecabb0b9b40fedf96"},{"author":{"_account_id":7847,"name":"Alistair Coles","email":"alistairncoles@gmail.com","username":"acoles"},"change_message_id":"be5ac7c8d533835b9902165636b1bf001d9c4fff","unresolved":false,"context_lines":[{"line_number":281,"context_line":""},{"line_number":282,"context_line":"        # verify the deletion has failed by checking the container listing"},{"line_number":283,"context_line":"        self.assertTrue(self._check_obj_in_container_listing(),"},{"line_number":284,"context_line":"                        msg\u003d\u0027Did not find listing for %s\u0027 % self.object_name)"},{"line_number":285,"context_line":""},{"line_number":286,"context_line":"        # run expirer again, delete should now succeed"},{"line_number":287,"context_line":"        self.expirer.once()"}],"source_content_type":"text/x-python","patch_set":8,"id":"9ad45d7e_611d5abd","line":284,"updated":"2016-08-08 14:09:10.000000000","message":"this is not a strong check that deletion did not occur on *any* of the primary servers, because this only gets a listing from one of three container servers.\n\nWhen the expirer delete request occurred, we had one primary object server offline and therefore one container server would not have been updated. So it might be that the object *was* deleted on two primaries, but listing comes from the the container server that was not updated.\n\nSo, to be sure all container servers are consistent, run the container-replicator.\n\nAlso, try to GET the original object after the expirer ran - that should succeed.","commit_id":"4aa1ae61cb62d9f0e8ca6ceecabb0b9b40fedf96"},{"author":{"_account_id":7847,"name":"Alistair Coles","email":"alistairncoles@gmail.com","username":"acoles"},"change_message_id":"be5ac7c8d533835b9902165636b1bf001d9c4fff","unresolved":false,"context_lines":[{"line_number":288,"context_line":""},{"line_number":289,"context_line":"        # verify the deletion by checking the container listing"},{"line_number":290,"context_line":"        self.assertFalse(self._check_obj_in_container_listing(),"},{"line_number":291,"context_line":"                         msg\u003d\u0027Found listing for %s\u0027 % self.object_name)"},{"line_number":292,"context_line":""},{"line_number":293,"context_line":"    def test_expirer_delete_returns_outdated_404(self):"},{"line_number":294,"context_line":"        self._test_expirer_delete_outdated_object_version(object_exists\u003dFalse)"}],"source_content_type":"text/x-python","patch_set":8,"id":"9ad45d7e_796d0532","line":291,"updated":"2016-08-08 14:09:10.000000000","message":"ok, this is the bottom line for the bug: previously, the second pass of the expirer would not attempt to delete the newer object that has now been replicated to the primaries, so this assertion would fail.","commit_id":"4aa1ae61cb62d9f0e8ca6ceecabb0b9b40fedf96"},{"author":{"_account_id":7847,"name":"Alistair Coles","email":"alistairncoles@gmail.com","username":"acoles"},"change_message_id":"be5ac7c8d533835b9902165636b1bf001d9c4fff","unresolved":false,"context_lines":[{"line_number":290,"context_line":"        self.assertFalse(self._check_obj_in_container_listing(),"},{"line_number":291,"context_line":"                         msg\u003d\u0027Found listing for %s\u0027 % self.object_name)"},{"line_number":292,"context_line":""},{"line_number":293,"context_line":"    def test_expirer_delete_returns_outdated_404(self):"},{"line_number":294,"context_line":"        self._test_expirer_delete_outdated_object_version(object_exists\u003dFalse)"},{"line_number":295,"context_line":""},{"line_number":296,"context_line":"    def test_expirer_delete_returns_outdated_412(self):"}],"source_content_type":"text/x-python","patch_set":8,"id":"9ad45d7e_d9cb511d","line":293,"updated":"2016-08-08 14:09:10.000000000","message":"passes on master, as expected","commit_id":"4aa1ae61cb62d9f0e8ca6ceecabb0b9b40fedf96"},{"author":{"_account_id":7847,"name":"Alistair Coles","email":"alistairncoles@gmail.com","username":"acoles"},"change_message_id":"be5ac7c8d533835b9902165636b1bf001d9c4fff","unresolved":false,"context_lines":[{"line_number":293,"context_line":"    def test_expirer_delete_returns_outdated_404(self):"},{"line_number":294,"context_line":"        self._test_expirer_delete_outdated_object_version(object_exists\u003dFalse)"},{"line_number":295,"context_line":""},{"line_number":296,"context_line":"    def test_expirer_delete_returns_outdated_412(self):"},{"line_number":297,"context_line":"        self._test_expirer_delete_outdated_object_version(object_exists\u003dTrue)"},{"line_number":298,"context_line":""},{"line_number":299,"context_line":""}],"source_content_type":"text/x-python","patch_set":8,"id":"9ad45d7e_39d1cdce","line":296,"updated":"2016-08-08 14:09:10.000000000","message":"fails on master","commit_id":"4aa1ae61cb62d9f0e8ca6ceecabb0b9b40fedf96"}],"test/unit/obj/test_expirer.py":[{"author":{"_account_id":7847,"name":"Alistair Coles","email":"alistairncoles@gmail.com","username":"acoles"},"change_message_id":"bc4d60ba53f5f2d87d71057bdcf63b7bd2d7c7c1","unresolved":false,"context_lines":[{"line_number":184,"context_line":"        self.assertEqual(containers, deleted_objects)"},{"line_number":185,"context_line":"        self.assertEqual(len(set(x.obj_containers_in_order[:4])), 4)"},{"line_number":186,"context_line":""},{"line_number":187,"context_line":"    def test_delete_object(self):"},{"line_number":188,"context_line":"        class InternalClient(object):"},{"line_number":189,"context_line":""},{"line_number":190,"context_line":"            container_ring \u003d None"}],"source_content_type":"text/x-python","patch_set":3,"id":"7aa08908_3ff24507","line":187,"updated":"2016-06-09 14:40:27.000000000","message":"This test could be improved to cover cases when delete_actual_object raises UnexpectedResponse such as the new case when the response is 412","commit_id":"9e9b8cdc7ce1377b17402f1d391cc3372714fb5a"},{"author":{"_account_id":7847,"name":"Alistair Coles","email":"alistairncoles@gmail.com","username":"acoles"},"change_message_id":"bc4d60ba53f5f2d87d71057bdcf63b7bd2d7c7c1","unresolved":false,"context_lines":[{"line_number":185,"context_line":"        self.assertEqual(len(set(x.obj_containers_in_order[:4])), 4)"},{"line_number":186,"context_line":""},{"line_number":187,"context_line":"    def test_delete_object(self):"},{"line_number":188,"context_line":"        class InternalClient(object):"},{"line_number":189,"context_line":""},{"line_number":190,"context_line":"            container_ring \u003d None"},{"line_number":191,"context_line":""}],"source_content_type":"text/x-python","patch_set":3,"id":"7aa08908_fc48cb8c","line":188,"updated":"2016-06-09 14:40:27.000000000","message":"this class seems to be redundant","commit_id":"9e9b8cdc7ce1377b17402f1d391cc3372714fb5a"},{"author":{"_account_id":7847,"name":"Alistair Coles","email":"alistairncoles@gmail.com","username":"acoles"},"change_message_id":"bc4d60ba53f5f2d87d71057bdcf63b7bd2d7c7c1","unresolved":false,"context_lines":[{"line_number":196,"context_line":"                self.obj \u003d obj"},{"line_number":197,"context_line":"                self.delete_object_called \u003d False"},{"line_number":198,"context_line":""},{"line_number":199,"context_line":"        class DeleteActualObject(object):"},{"line_number":200,"context_line":"            def __init__(self, test, actual_obj, timestamp):"},{"line_number":201,"context_line":"                self.test \u003d test"},{"line_number":202,"context_line":"                self.actual_obj \u003d actual_obj"}],"source_content_type":"text/x-python","patch_set":3,"id":"7aa08908_1ff789f6","line":199,"updated":"2016-06-09 14:40:27.000000000","message":"this class could be paramaterised to raise UnexpectedResponse with 404, 412 status","commit_id":"9e9b8cdc7ce1377b17402f1d391cc3372714fb5a"},{"author":{"_account_id":7847,"name":"Alistair Coles","email":"alistairncoles@gmail.com","username":"acoles"},"change_message_id":"bc4d60ba53f5f2d87d71057bdcf63b7bd2d7c7c1","unresolved":false,"context_lines":[{"line_number":211,"context_line":"        container \u003d \u0027container\u0027"},{"line_number":212,"context_line":"        obj \u003d \u0027obj\u0027"},{"line_number":213,"context_line":"        actual_obj \u003d \u0027actual_obj\u0027"},{"line_number":214,"context_line":"        timestamp \u003d \u0027timestamp\u0027"},{"line_number":215,"context_line":""},{"line_number":216,"context_line":"        x \u003d expirer.ObjectExpirer({}, logger\u003dself.logger)"},{"line_number":217,"context_line":"        x.swift \u003d \\"}],"source_content_type":"text/x-python","patch_set":3,"id":"7aa08908_5f3d91ba","line":214,"updated":"2016-06-09 14:40:27.000000000","message":"this should be Timestamp(time()).normal, or Timestamp(time() - x.reclaim_age -1) in some scenarios","commit_id":"9e9b8cdc7ce1377b17402f1d391cc3372714fb5a"},{"author":{"_account_id":7847,"name":"Alistair Coles","email":"alistairncoles@gmail.com","username":"acoles"},"change_message_id":"bc4d60ba53f5f2d87d71057bdcf63b7bd2d7c7c1","unresolved":false,"context_lines":[{"line_number":214,"context_line":"        timestamp \u003d \u0027timestamp\u0027"},{"line_number":215,"context_line":""},{"line_number":216,"context_line":"        x \u003d expirer.ObjectExpirer({}, logger\u003dself.logger)"},{"line_number":217,"context_line":"        x.swift \u003d \\"},{"line_number":218,"context_line":"            InternalClient(self, x.expiring_objects_account, container, obj)"},{"line_number":219,"context_line":"        x.delete_actual_object \u003d \\"},{"line_number":220,"context_line":"            DeleteActualObject(self, actual_obj, timestamp)"}],"source_content_type":"text/x-python","patch_set":3,"id":"7aa08908_dc34effc","line":217,"updated":"2016-06-09 14:40:27.000000000","message":"not necessary because x.swift is unused in this scenario with x.delete_actual_object being patched.","commit_id":"9e9b8cdc7ce1377b17402f1d391cc3372714fb5a"},{"author":{"_account_id":7847,"name":"Alistair Coles","email":"alistairncoles@gmail.com","username":"acoles"},"change_message_id":"bc4d60ba53f5f2d87d71057bdcf63b7bd2d7c7c1","unresolved":false,"context_lines":[{"line_number":219,"context_line":"        x.delete_actual_object \u003d \\"},{"line_number":220,"context_line":"            DeleteActualObject(self, actual_obj, timestamp)"},{"line_number":221,"context_line":""},{"line_number":222,"context_line":"        delete_object_called \u003d []"},{"line_number":223,"context_line":""},{"line_number":224,"context_line":"        def pop_queue(c, o):"},{"line_number":225,"context_line":"            self.assertEqual(container, c)"}],"source_content_type":"text/x-python","patch_set":3,"id":"7aa08908_bfe63542","line":222,"updated":"2016-06-09 14:40:27.000000000","message":"better name would be pop_queue_called?","commit_id":"9e9b8cdc7ce1377b17402f1d391cc3372714fb5a"},{"author":{"_account_id":7847,"name":"Alistair Coles","email":"alistairncoles@gmail.com","username":"acoles"},"change_message_id":"744eb703501fb8efe51fd8ed6096f44361181fab","unresolved":false,"context_lines":[{"line_number":209,"context_line":"                    x.delete_object(actual_obj, ts, container, obj)"},{"line_number":210,"context_line":""},{"line_number":211,"context_line":"                # delete_actual_object raises no exceptions"},{"line_number":212,"context_line":"                clean_call_to_delete_object()"},{"line_number":213,"context_line":""},{"line_number":214,"context_line":"                # verify sub-routines are called with the right arguments"},{"line_number":215,"context_line":"                delete_actual.assert_called_once_with(actual_obj, timestamp)"}],"source_content_type":"text/x-python","patch_set":7,"id":"bacf61ea_b1f07768","line":212,"updated":"2016-08-05 18:07:33.000000000","message":"this could be done with another entry in the list below, using None for the actual_delete side_effect.","commit_id":"2fee4777f3b83b7b0fd26f2b4c7bd15ee340d10b"},{"author":{"_account_id":7847,"name":"Alistair Coles","email":"alistairncoles@gmail.com","username":"acoles"},"change_message_id":"744eb703501fb8efe51fd8ed6096f44361181fab","unresolved":false,"context_lines":[{"line_number":221,"context_line":"                                            (http_exc[500], reclaim_ts, False),"},{"line_number":222,"context_line":"                                            (exc_other, reclaim_ts, False),"},{"line_number":223,"context_line":"                                            (http_exc[404], reclaim_ts, True),"},{"line_number":224,"context_line":"                                            (http_exc[412], reclaim_ts, True)]:"},{"line_number":225,"context_line":""},{"line_number":226,"context_line":"                    delete_actual.side_effect \u003d exc"},{"line_number":227,"context_line":"                    clean_call_to_delete_object(ts)"}],"source_content_type":"text/x-python","patch_set":7,"id":"bacf61ea_b17b57f4","line":224,"updated":"2016-08-05 18:07:33.000000000","message":"nice idea to loop over the scenarios, but I think I would prefer to set the mocks up for each test condition. I think that is less error prone than resetting existing mocks.","commit_id":"2fee4777f3b83b7b0fd26f2b4c7bd15ee340d10b"},{"author":{"_account_id":7847,"name":"Alistair Coles","email":"alistairncoles@gmail.com","username":"acoles"},"change_message_id":"744eb703501fb8efe51fd8ed6096f44361181fab","unresolved":false,"context_lines":[{"line_number":224,"context_line":"                                            (http_exc[412], reclaim_ts, True)]:"},{"line_number":225,"context_line":""},{"line_number":226,"context_line":"                    delete_actual.side_effect \u003d exc"},{"line_number":227,"context_line":"                    clean_call_to_delete_object(ts)"},{"line_number":228,"context_line":"                    self.assertEqual(pop_queue.called, should_pop,"},{"line_number":229,"context_line":"                                     msg\u003d\"Failed on %r at %f\" % (exc, ts))"},{"line_number":230,"context_line":""}],"source_content_type":"text/x-python","patch_set":7,"id":"bacf61ea_56a49149","line":227,"updated":"2016-08-05 18:07:33.000000000","message":"missing assert that delete_actual was called","commit_id":"2fee4777f3b83b7b0fd26f2b4c7bd15ee340d10b"},{"author":{"_account_id":7847,"name":"Alistair Coles","email":"alistairncoles@gmail.com","username":"acoles"},"change_message_id":"744eb703501fb8efe51fd8ed6096f44361181fab","unresolved":false,"context_lines":[{"line_number":226,"context_line":"                    delete_actual.side_effect \u003d exc"},{"line_number":227,"context_line":"                    clean_call_to_delete_object(ts)"},{"line_number":228,"context_line":"                    self.assertEqual(pop_queue.called, should_pop,"},{"line_number":229,"context_line":"                                     msg\u003d\"Failed on %r at %f\" % (exc, ts))"},{"line_number":230,"context_line":""},{"line_number":231,"context_line":"    def test_report(self):"},{"line_number":232,"context_line":"        x \u003d expirer.ObjectExpirer({}, logger\u003dself.logger)"}],"source_content_type":"text/x-python","patch_set":7,"id":"bacf61ea_b162373c","line":229,"updated":"2016-08-05 18:07:33.000000000","message":"good, include the test conditions in the failure message","commit_id":"2fee4777f3b83b7b0fd26f2b4c7bd15ee340d10b"}]}
