)]}'
{"/COMMIT_MSG":[{"author":{"_account_id":1179,"name":"Clay Gerrard","email":"clay.gerrard@gmail.com","username":"clay-gerrard"},"change_message_id":"e4ed2db0b4d14d074e263a47e448969d9c93fd5e","unresolved":true,"context_lines":[{"line_number":9,"context_line":"Add assertions to proxy unit tests to verify that the s3api adds"},{"line_number":10,"context_line":"a valid x-timestamp header to some swift requests:"},{"line_number":11,"context_line":""},{"line_number":12,"context_line":"  - object POST and DELETE requests"},{"line_number":13,"context_line":"  - multi-upload part PUT requests"},{"line_number":14,"context_line":""},{"line_number":15,"context_line":"Add assertions to proxy unit tests to verify that the s3api does not"}],"source_content_type":"text/x-gerrit-commit-message","patch_set":3,"id":"c3a046a8_7551a881","line":12,"updated":"2026-01-09 19:15:58.000000000","message":"what?  I saw the asserts for object PUT - does s3api *have* \"an object POST\" request?\n\n```\n    @public\n    def POST(self, req):\n        raise S3NotImplemented()\n```\n\n```\n    def test_object_DELETE_no_multipart(self):\n        self.s3api.conf.allow_multipart_uploads \u003d False\n        req \u003d Request.blank(\u0027/bucket/object\u0027,\n                            environ\u003d{\u0027REQUEST_METHOD\u0027: \u0027DELETE\u0027},\n                            headers\u003d{\u0027Authorization\u0027: \u0027AWS test:tester:hmac\u0027,\n                                     \u0027Date\u0027: self.get_date_header()})\n        status, headers, body \u003d self.call_s3api(req)\n        self.assertEqual(status.split()[0], \u0027204\u0027)\n\n        ...\n        self.assertNotIn(\u0027X-Timestamp\u0027, sw_headers)\n```","commit_id":"e6bc8d44506ca39ecac9b30ef793738ee80cffba"},{"author":{"_account_id":15343,"name":"Tim Burke","email":"tburke@nvidia.com","username":"tburke"},"change_message_id":"b7525afec0e27f5b487561d35d4a1f123e915a91","unresolved":true,"context_lines":[{"line_number":9,"context_line":"Add assertions to proxy unit tests to verify that the s3api adds"},{"line_number":10,"context_line":"a valid x-timestamp header to some swift requests:"},{"line_number":11,"context_line":""},{"line_number":12,"context_line":"  - object POST and DELETE requests"},{"line_number":13,"context_line":"  - multi-upload part PUT requests"},{"line_number":14,"context_line":""},{"line_number":15,"context_line":"Add assertions to proxy unit tests to verify that the s3api does not"}],"source_content_type":"text/x-gerrit-commit-message","patch_set":3,"id":"ccbe4b0a_06cd9629","line":12,"in_reply_to":"c3a046a8_7551a881","updated":"2026-01-09 19:49:01.000000000","message":"https://docs.aws.amazon.com/AmazonS3/latest/API/RESTObjectPOST.html\n\nIt\u0027s a lot like formpost, but we haven\u0027t seen much demand to implement it.","commit_id":"e6bc8d44506ca39ecac9b30ef793738ee80cffba"},{"author":{"_account_id":7847,"name":"Alistair Coles","email":"alistairncoles@gmail.com","username":"acoles"},"change_message_id":"1fafc384ecd2671d6fad066654e5688b5c29272d","unresolved":true,"context_lines":[{"line_number":9,"context_line":"Add assertions to proxy unit tests to verify that the s3api adds"},{"line_number":10,"context_line":"a valid x-timestamp header to some swift requests:"},{"line_number":11,"context_line":""},{"line_number":12,"context_line":"  - object POST and DELETE requests"},{"line_number":13,"context_line":"  - multi-upload part PUT requests"},{"line_number":14,"context_line":""},{"line_number":15,"context_line":"Add assertions to proxy unit tests to verify that the s3api does not"}],"source_content_type":"text/x-gerrit-commit-message","patch_set":3,"id":"2506d4e0_280bd60d","line":12,"in_reply_to":"ccbe4b0a_06cd9629","updated":"2026-01-13 10:05:34.000000000","message":"sorry, my mistake, should say \"PUT and DELETE\"","commit_id":"e6bc8d44506ca39ecac9b30ef793738ee80cffba"},{"author":{"_account_id":1179,"name":"Clay Gerrard","email":"clay.gerrard@gmail.com","username":"clay-gerrard"},"change_message_id":"e4ed2db0b4d14d074e263a47e448969d9c93fd5e","unresolved":true,"context_lines":[{"line_number":20,"context_line":"  - bucket PUT and DELETE requests"},{"line_number":21,"context_line":""},{"line_number":22,"context_line":"Note: It is left to other middleware or the proxy server app to add the"},{"line_number":23,"context_line":"x-timestamp header to these requests."},{"line_number":24,"context_line":""},{"line_number":25,"context_line":"The mocked_http_conn helper is preferred over set_http_connect in"},{"line_number":26,"context_line":"tests because it captures backend requests and detects unused"}],"source_content_type":"text/x-gerrit-commit-message","patch_set":3,"id":"08c5ba19_7698fa67","line":23,"updated":"2026-01-09 19:15:58.000000000","message":"good note; confirmed.","commit_id":"e6bc8d44506ca39ecac9b30ef793738ee80cffba"},{"author":{"_account_id":7847,"name":"Alistair Coles","email":"alistairncoles@gmail.com","username":"acoles"},"change_message_id":"1fafc384ecd2671d6fad066654e5688b5c29272d","unresolved":false,"context_lines":[{"line_number":20,"context_line":"  - bucket PUT and DELETE requests"},{"line_number":21,"context_line":""},{"line_number":22,"context_line":"Note: It is left to other middleware or the proxy server app to add the"},{"line_number":23,"context_line":"x-timestamp header to these requests."},{"line_number":24,"context_line":""},{"line_number":25,"context_line":"The mocked_http_conn helper is preferred over set_http_connect in"},{"line_number":26,"context_line":"tests because it captures backend requests and detects unused"}],"source_content_type":"text/x-gerrit-commit-message","patch_set":3,"id":"b0187582_fdc25111","line":23,"in_reply_to":"08c5ba19_7698fa67","updated":"2026-01-13 10:05:34.000000000","message":"Acknowledged","commit_id":"e6bc8d44506ca39ecac9b30ef793738ee80cffba"},{"author":{"_account_id":1179,"name":"Clay Gerrard","email":"clay.gerrard@gmail.com","username":"clay-gerrard"},"change_message_id":"e4ed2db0b4d14d074e263a47e448969d9c93fd5e","unresolved":true,"context_lines":[{"line_number":24,"context_line":""},{"line_number":25,"context_line":"The mocked_http_conn helper is preferred over set_http_connect in"},{"line_number":26,"context_line":"tests because it captures backend requests and detects unused"},{"line_number":27,"context_line":"responses."},{"line_number":28,"context_line":""},{"line_number":29,"context_line":"Change-Id: Iab68f4b596dfa7f23bc587fbde859d854faff87f"},{"line_number":30,"context_line":"Signed-off-by: Alistair Coles \u003calistairncoles@gmail.com\u003e"}],"source_content_type":"text/x-gerrit-commit-message","patch_set":3,"id":"0e874172_17526efc","line":27,"updated":"2026-01-09 19:15:58.000000000","message":"so say we all","commit_id":"e6bc8d44506ca39ecac9b30ef793738ee80cffba"},{"author":{"_account_id":15343,"name":"Tim Burke","email":"tburke@nvidia.com","username":"tburke"},"change_message_id":"b7525afec0e27f5b487561d35d4a1f123e915a91","unresolved":true,"context_lines":[{"line_number":24,"context_line":""},{"line_number":25,"context_line":"The mocked_http_conn helper is preferred over set_http_connect in"},{"line_number":26,"context_line":"tests because it captures backend requests and detects unused"},{"line_number":27,"context_line":"responses."},{"line_number":28,"context_line":""},{"line_number":29,"context_line":"Change-Id: Iab68f4b596dfa7f23bc587fbde859d854faff87f"},{"line_number":30,"context_line":"Signed-off-by: Alistair Coles \u003calistairncoles@gmail.com\u003e"}],"source_content_type":"text/x-gerrit-commit-message","patch_set":3,"id":"8ddbd4fc_983fa029","line":27,"in_reply_to":"0e874172_17526efc","updated":"2026-01-09 19:49:01.000000000","message":"Should we be working to convert existing tests with `set_http_connect` to use `mocked_http_conn`? Then we could _remove_ `set_http_connect`","commit_id":"e6bc8d44506ca39ecac9b30ef793738ee80cffba"},{"author":{"_account_id":7847,"name":"Alistair Coles","email":"alistairncoles@gmail.com","username":"acoles"},"change_message_id":"1fafc384ecd2671d6fad066654e5688b5c29272d","unresolved":true,"context_lines":[{"line_number":24,"context_line":""},{"line_number":25,"context_line":"The mocked_http_conn helper is preferred over set_http_connect in"},{"line_number":26,"context_line":"tests because it captures backend requests and detects unused"},{"line_number":27,"context_line":"responses."},{"line_number":28,"context_line":""},{"line_number":29,"context_line":"Change-Id: Iab68f4b596dfa7f23bc587fbde859d854faff87f"},{"line_number":30,"context_line":"Signed-off-by: Alistair Coles \u003calistairncoles@gmail.com\u003e"}],"source_content_type":"text/x-gerrit-commit-message","patch_set":3,"id":"28f98759_9690a6a8","line":27,"in_reply_to":"8ddbd4fc_983fa029","updated":"2026-01-13 10:05:34.000000000","message":"+1 this patch showed me how set_http_connect can lead to deceptive test scenarios vs. the \"rigour\" of mocked_http_connect","commit_id":"e6bc8d44506ca39ecac9b30ef793738ee80cffba"}],"/PATCHSET_LEVEL":[{"author":{"_account_id":7847,"name":"Alistair Coles","email":"alistairncoles@gmail.com","username":"acoles"},"change_message_id":"821804611cd9479623f9282762199637bef9068d","unresolved":false,"context_lines":[],"source_content_type":"","patch_set":3,"id":"5a900cbb_f858f788","updated":"2026-01-09 13:08:14.000000000","message":"I left a print statement in the tests 😞","commit_id":"e6bc8d44506ca39ecac9b30ef793738ee80cffba"},{"author":{"_account_id":1179,"name":"Clay Gerrard","email":"clay.gerrard@gmail.com","username":"clay-gerrard"},"change_message_id":"e4ed2db0b4d14d074e263a47e448969d9c93fd5e","unresolved":false,"context_lines":[],"source_content_type":"","patch_set":4,"id":"106fbdf7_a860470e","updated":"2026-01-09 19:15:58.000000000","message":"maybe worth splitting the proxy/basetest stuff into a quick win?\n\nThe pre-existing s3api behavior to add special handling for obj requests is suspicious enough that a targeted commit message might be useful.  Generally I like \"add the test to show/maintain the current behavior\" even if we DON\u0027T know why the behavior is that way; but it\u0027s best with a commit message that says \"do we even want this!?\"\n\n-1 b/c I think the commit message wrt to the s3api object POST/DELETE is wrong?","commit_id":"104995d16391170b77a66cfcd68dde13ec101ef3"},{"author":{"_account_id":1179,"name":"Clay Gerrard","email":"clay.gerrard@gmail.com","username":"clay-gerrard"},"change_message_id":"3e425ed59c19b6be8c1c7a782b6989bc99d6a12c","unresolved":false,"context_lines":[],"source_content_type":"","patch_set":5,"id":"1e766343_05200d2c","updated":"2026-01-12 20:29:40.000000000","message":"I\u0027m +2 and would like this change to merge - holding +1 ~24hrs in-case there\u0027s any more comments; feel free to click the buttons or push back as needed tho!","commit_id":"a35ca5eb44b0b123ad4f9ec50f5dcfeda9a28f57"},{"author":{"_account_id":7847,"name":"Alistair Coles","email":"alistairncoles@gmail.com","username":"acoles"},"change_message_id":"be93aa25655ce578804398b5ea8faae043737e79","unresolved":false,"context_lines":[],"source_content_type":"","patch_set":6,"id":"14a2dc0d_2eb4002b","updated":"2026-01-13 10:08:50.000000000","message":"rebased, merging based on previous +2+1","commit_id":"949f0fdac8624c1a40381edd1948e82b3092d350"}],"test/__init__.py":[{"author":{"_account_id":1179,"name":"Clay Gerrard","email":"clay.gerrard@gmail.com","username":"clay-gerrard"},"change_message_id":"e4ed2db0b4d14d074e263a47e448969d9c93fd5e","unresolved":true,"context_lines":[{"line_number":88,"context_line":""},{"line_number":89,"context_line":""},{"line_number":90,"context_line":"class BaseTestCase(unittest.TestCase):"},{"line_number":91,"context_line":"    def _assertDictContainsSubset(self, subset, dictionary, msg\u003dNone):"},{"line_number":92,"context_line":"        \"\"\"Checks whether dictionary is a superset of subset.\"\"\""},{"line_number":93,"context_line":"        # This is almost identical to the method in python3.4 version of"},{"line_number":94,"context_line":"        # unitest.case.TestCase.assertDictContainsSubset, reproduced here to"}],"source_content_type":"text/x-python","patch_set":3,"id":"13cb6d26_cea668f7","line":91,"updated":"2026-01-09 19:15:58.000000000","message":"I guess there\u0027s prior art on the underscore...","commit_id":"e6bc8d44506ca39ecac9b30ef793738ee80cffba"},{"author":{"_account_id":1179,"name":"Clay Gerrard","email":"clay.gerrard@gmail.com","username":"clay-gerrard"},"change_message_id":"e4ed2db0b4d14d074e263a47e448969d9c93fd5e","unresolved":true,"context_lines":[{"line_number":92,"context_line":"        \"\"\"Checks whether dictionary is a superset of subset.\"\"\""},{"line_number":93,"context_line":"        # This is almost identical to the method in python3.4 version of"},{"line_number":94,"context_line":"        # unitest.case.TestCase.assertDictContainsSubset, reproduced here to"},{"line_number":95,"context_line":"        # avoid the deprecation warning in the original when using python3."},{"line_number":96,"context_line":"        missing \u003d []"},{"line_number":97,"context_line":"        mismatched \u003d []"},{"line_number":98,"context_line":"        for key, value in subset.items():"}],"source_content_type":"text/x-python","patch_set":3,"id":"206e5423_add8d360","line":95,"updated":"2026-01-09 19:15:58.000000000","message":"... but this is strange reasoning\n\napparently it\u0027s suggested we spell this\n\n```\nself.assertEqual(dictionary, dictionary | subset)\n```\n\nwhich doesn\u0027t seem like it\u0027d have the best failure output.\n\nMaybe now that 3.12 has *removed* `assertDictContainsSubset` we can just take over the name; or make our own `assertSubsetInDict` to avoid name collision.","commit_id":"e6bc8d44506ca39ecac9b30ef793738ee80cffba"},{"author":{"_account_id":1179,"name":"Clay Gerrard","email":"clay.gerrard@gmail.com","username":"clay-gerrard"},"change_message_id":"e4ed2db0b4d14d074e263a47e448969d9c93fd5e","unresolved":true,"context_lines":[{"line_number":117,"context_line":""},{"line_number":118,"context_line":"        self.fail(self._formatMessage(msg, standardMsg))"},{"line_number":119,"context_line":""},{"line_number":120,"context_line":"    def _assert_valid_timestamp(self, timestamp):"},{"line_number":121,"context_line":"        \"\"\""},{"line_number":122,"context_line":"        Helper that asserts the given timestamp is a valid Timestamp"},{"line_number":123,"context_line":"        representation."}],"source_content_type":"text/x-python","patch_set":3,"id":"1caeef6b_6d3096e5","line":120,"updated":"2026-01-09 19:15:58.000000000","message":"what\u0027s with the underscore?   this is ment to be a public helper used by subclasses\u0027 no? `self.assertValidTimestamp`","commit_id":"e6bc8d44506ca39ecac9b30ef793738ee80cffba"},{"author":{"_account_id":7847,"name":"Alistair Coles","email":"alistairncoles@gmail.com","username":"acoles"},"change_message_id":"1fafc384ecd2671d6fad066654e5688b5c29272d","unresolved":true,"context_lines":[{"line_number":117,"context_line":""},{"line_number":118,"context_line":"        self.fail(self._formatMessage(msg, standardMsg))"},{"line_number":119,"context_line":""},{"line_number":120,"context_line":"    def _assert_valid_timestamp(self, timestamp):"},{"line_number":121,"context_line":"        \"\"\""},{"line_number":122,"context_line":"        Helper that asserts the given timestamp is a valid Timestamp"},{"line_number":123,"context_line":"        representation."}],"source_content_type":"text/x-python","patch_set":3,"id":"244bba1f_3d017dd8","line":120,"in_reply_to":"1caeef6b_6d3096e5","updated":"2026-01-13 10:05:34.000000000","message":"agree, will fix, I was probably either stupidly thinking I need to conform with the \"_\" in the above helper, or more likely had a version when this was a helper in a single subclass, and then bumped it up to this superclass","commit_id":"e6bc8d44506ca39ecac9b30ef793738ee80cffba"},{"author":{"_account_id":7847,"name":"Alistair Coles","email":"alistairncoles@gmail.com","username":"acoles"},"change_message_id":"821804611cd9479623f9282762199637bef9068d","unresolved":true,"context_lines":[{"line_number":127,"context_line":"        try:"},{"line_number":128,"context_line":"            timestamp \u003d Timestamp(timestamp)"},{"line_number":129,"context_line":"        except (ValueError, TypeError) as e:"},{"line_number":130,"context_line":"            self.fail(\u0027Invalid timestamp (%r): %r\u0027 % (timestamp, e))"}],"source_content_type":"text/x-python","patch_set":3,"id":"e0a1c3b5_0a8f5fb4","line":130,"updated":"2026-01-09 13:08:14.000000000","message":"later in the patch chain this helper grows to check jitter https://review.opendev.org/c/openstack/swift/+/967738/42/test/__init__.py","commit_id":"e6bc8d44506ca39ecac9b30ef793738ee80cffba"}],"test/unit/common/middleware/s3api/test_bucket.py":[{"author":{"_account_id":1179,"name":"Clay Gerrard","email":"clay.gerrard@gmail.com","username":"clay-gerrard"},"change_message_id":"e4ed2db0b4d14d074e263a47e448969d9c93fd5e","unresolved":true,"context_lines":[{"line_number":288,"context_line":"                            environ\u003d{\u0027REQUEST_METHOD\u0027: \u0027PUT\u0027},"},{"line_number":289,"context_line":"                            headers\u003d{\u0027Authorization\u0027: \u0027AWS test:tester:hmac\u0027,"},{"line_number":290,"context_line":"                                     \u0027Date\u0027: self.get_date_header(),"},{"line_number":291,"context_line":"                                     \u0027Transfer-Encoding\u0027: \u0027chunked\u0027})"},{"line_number":292,"context_line":"        status, headers, body \u003d self.call_s3api(req)"},{"line_number":293,"context_line":"        self.assertEqual(body, b\u0027\u0027)"},{"line_number":294,"context_line":"        self.assertEqual(status.split()[0], \u0027200\u0027)"}],"source_content_type":"text/x-python","patch_set":3,"id":"38498935_1fae8124","line":291,"updated":"2026-01-09 19:15:58.000000000","message":"i tried adding `req.ensure_x_timestamp()` and it didn\u0027t seem to propogate to the sw_req - so how *does* s3api get an X-Timestamp in it\u0027s swift PUT requests!?\n\nis it just letting the proxy do it?\n\nhttps://github.com/NVIDIA/swift/blob/master/swift/proxy/controllers/container.py#L750\n\nOK, I guess that\u0027s normal (even for swift requests):\n\n```\n\ndiff --git a/swift/proxy/controllers/container.py b/swift/proxy/controllers/container.py\nindex da7b0e3ae..ae85cecb7 100644\n--- a/swift/proxy/controllers/container.py\n+++ b/swift/proxy/controllers/container.py\n@@ -666,9 +666,11 @@ class ContainerController(Controller):\n                 return resp\n         container_partition, containers \u003d self.app.container_ring.get_nodes(\n             self.account_name, self.container_name)\n+        self.logger.info(\u0027pre-backend req.headers: %r\u0027, dict(req.headers))\n         headers \u003d self._backend_requests(req, len(containers),\n                                          account_partition, accounts,\n                                          policy_index)\n+        self.logger.info(\u0027post-backend headers: %r\u0027, headers)\n         resp \u003d self.make_requests(\n             req, self.app.container_ring,\n             container_partition, \u0027PUT\u0027, req.swift_entity_path, headers)\n\n\ncurl -H \u0027x-auth-token: AUTH_tkc1ecae7a8a2946299bad4db631f7888a\u0027 -XPUT http://saio:8080/v1/AUTH_test/swift-bucket-test2 -v\n\nJan  9 18:29:21 saio proxy-server: pre-backend req.headers: {\u0027Host\u0027: \u0027saio:8080\u0027, \u0027User-Agent\u0027: \u0027curl/7.81.0\u0027, \u0027Accept\u0027: \u0027*/*\u0027, \u0027X-Auth-Token\u0027: \u0027AUTH_tkc1ecae7a8a2946299bad4db631f7888a\u0027, \u0027X-Trans-Id\u0027: \u0027txb815af23a97a4f7590fc5-0069614901\u0027, \u0027Content-Type\u0027: \u0027\u0027}\nJan  9 18:29:21 saio proxy-server: post-backend headers: [{\u0027X-Timestamp\u0027: \u00271767983361.06292\u0027, \u0027X-Backend-Storage-Policy-Default\u0027: \u00270\u0027, \u0027X-Trans-Id\u0027: \u0027txb815af23a97a4f7590fc5-0069614901\u0027, \u0027Connection\u0027: \u0027close\u0027, \u0027User-Agent\u0027: \u0027proxy-server 6479\u0027, \u0027Referer\u0027: \u0027PUT http://saio:8080/v1/AUTH_test/swift-bucket-test2\u0027, \u0027X-Account-Partition\u0027: \u0027802\u0027, \u0027X-Account-Host\u0027: \u0027127.0.0.4:6042\u0027, \u0027X-Account-Device\u0027: \u0027sdb4\u0027}, {\u0027X-Timestamp\u0027: \u00271767983361.06292\u0027, \u0027X-Backend-Storage-Policy-Default\u0027: \u00270\u0027, \u0027X-Trans-Id\u0027: \u0027txb815af23a97a4f7590fc5-0069614901\u0027, \u0027Connection\u0027: \u0027close\u0027, \u0027User-Agent\u0027: \u0027proxy-server 6479\u0027, \u0027Referer\u0027: \u0027PUT http://saio:8080/v1/AUTH_test/swift-bucket-test2\u0027, \u0027X-Account-Partition\u0027: \u0027802\u0027, \u0027X-Account-Host\u0027: \u0027127.0.0.2:6022\u0027, \u0027X-Account-Device\u0027: \u0027sdb2\u0027}, {\u0027X-Timestamp\u0027: \u00271767983361.06292\u0027, \u0027X-Backend-Storage-Policy-Default\u0027: \u00270\u0027, \u0027X-Trans-Id\u0027: \u0027txb815af23a97a4f7590fc5-0069614901\u0027, \u0027Connection\u0027: \u0027close\u0027, \u0027User-Agent\u0027: \u0027proxy-server 6479\u0027, \u0027Referer\u0027: \u0027PUT http://saio:8080/v1/AUTH_test/swift-bucket-test2\u0027, \u0027X-Account-Partition\u0027: \u0027802\u0027, \u0027X-Account-Host\u0027: \u0027127.0.0.3:6032\u0027, \u0027X-Account-Device\u0027: \u0027sdb3\u0027}]\n\n```\n\ns3api *does* add a X-Amz-Date header that I guess doesn\u0027t matter:\n\n\n```\n\nvagrant@saio:~$ aws s3api create-bucket --bucket s3api-bucket-test\n{\n    \"Location\": \"/s3api-bucket-test\"\n}\n\n\nJan  9 18:31:29 saio proxy-server: pre-backend req.headers: {\u0027Host\u0027: \u0027saio:8080\u0027, \u0027Accept-Encoding\u0027: \u0027identity\u0027, \u0027User-Agent\u0027: \u0027aws-cli/1.42.71 md/Botocore#1.40.71 ua/2.1 os/linux#5.15.0-116-generic md/arch#x86_64 lang/python#3.10.12 md/pyimpl#CPython m/b,D,N,Z,n cfg/retry-mode#legacy botocore/1.40.71\u0027, \u0027X-Amz-Date\u0027: \u002720260109T183129Z\u0027, \u0027X-Amz-Content-Sha256\u0027: \u0027e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855\u0027, \u0027Authorization\u0027: \u0027AWS4-HMAC-SHA256 Credential\u003dtest:tester/20260109/us-east-1/s3/aws4_request, SignedHeaders\u003dhost;x-amz-content-sha256;x-amz-date, Signature\u003d11489ac7c5c559e5cdb90142ed842882f794492ed0b3f8c524d5f11d687e5a2f\u0027, \u0027Amz-Sdk-Invocation-Id\u0027: \u0027189cbdf4-b8e8-4c6a-9774-c35d8bd74876\u0027, \u0027Amz-Sdk-Request\u0027: \u0027attempt\u003d1\u0027, \u0027X-Trans-Id\u0027: \u0027tx5eab872e5063488db9fd2-0069614981\u0027, \u0027Content-Length\u0027: \u00270\u0027, \u0027Content-Type\u0027: \u0027\u0027}\nJan  9 18:31:29 saio proxy-server: post-backend headers: [{\u0027X-Timestamp\u0027: \u00271767983489.50372\u0027, \u0027X-Backend-Storage-Policy-Default\u0027: \u00270\u0027, \u0027X-Trans-Id\u0027: \u0027tx5eab872e5063488db9fd2-0069614981\u0027, \u0027Connection\u0027: \u0027close\u0027, \u0027User-Agent\u0027: \u0027proxy-server 6479\u0027, \u0027Referer\u0027: \u0027PUT http://saio:8080/v1/AUTH_test/s3api-bucket-test\u0027, \u0027X-Account-Partition\u0027: \u0027802\u0027, \u0027X-Account-Host\u0027: \u0027127.0.0.4:6042\u0027, \u0027X-Account-Device\u0027: \u0027sdb4\u0027}, {\u0027X-Timestamp\u0027: \u00271767983489.50372\u0027, \u0027X-Backend-Storage-Policy-Default\u0027: \u00270\u0027, \u0027X-Trans-Id\u0027: \u0027tx5eab872e5063488db9fd2-0069614981\u0027, \u0027Connection\u0027: \u0027close\u0027, \u0027User-Agent\u0027: \u0027proxy-server 6479\u0027, \u0027Referer\u0027: \u0027PUT http://saio:8080/v1/AUTH_test/s3api-bucket-test\u0027, \u0027X-Account-Partition\u0027: \u0027802\u0027, \u0027X-Account-Host\u0027: \u0027127.0.0.2:6022\u0027, \u0027X-Account-Device\u0027: \u0027sdb2\u0027}, {\u0027X-Timestamp\u0027: \u00271767983489.50372\u0027, \u0027X-Backend-Storage-Policy-Default\u0027: \u00270\u0027, \u0027X-Trans-Id\u0027: \u0027tx5eab872e5063488db9fd2-0069614981\u0027, \u0027Connection\u0027: \u0027close\u0027, \u0027User-Agent\u0027: \u0027proxy-server 6479\u0027, \u0027Referer\u0027: \u0027PUT http://saio:8080/v1/AUTH_test/s3api-bucket-test\u0027, \u0027X-Account-Partition\u0027: \u0027802\u0027, \u0027X-Account-Host\u0027: \u0027127.0.0.3:6032\u0027, \u0027X-Account-Device\u0027: \u0027sdb3\u0027}]\n\n```","commit_id":"e6bc8d44506ca39ecac9b30ef793738ee80cffba"},{"author":{"_account_id":7847,"name":"Alistair Coles","email":"alistairncoles@gmail.com","username":"acoles"},"change_message_id":"1fafc384ecd2671d6fad066654e5688b5c29272d","unresolved":true,"context_lines":[{"line_number":288,"context_line":"                            environ\u003d{\u0027REQUEST_METHOD\u0027: \u0027PUT\u0027},"},{"line_number":289,"context_line":"                            headers\u003d{\u0027Authorization\u0027: \u0027AWS test:tester:hmac\u0027,"},{"line_number":290,"context_line":"                                     \u0027Date\u0027: self.get_date_header(),"},{"line_number":291,"context_line":"                                     \u0027Transfer-Encoding\u0027: \u0027chunked\u0027})"},{"line_number":292,"context_line":"        status, headers, body \u003d self.call_s3api(req)"},{"line_number":293,"context_line":"        self.assertEqual(body, b\u0027\u0027)"},{"line_number":294,"context_line":"        self.assertEqual(status.split()[0], \u0027200\u0027)"}],"source_content_type":"text/x-python","patch_set":3,"id":"ec02c512_69d3f688","line":291,"in_reply_to":"38498935_1fae8124","updated":"2026-01-13 10:05:34.000000000","message":"I added req.ensure_x_timestamp() here and the (updated patchset) test did fail\n```\nAssertionError: \u0027X-Timestamp\u0027 unexpectedly found in {\u0027Host\u0027: \u0027localhost:80\u0027, \u0027Authorization\u0027: \u0027AWS test:tester:hmac\u0027, \u0027Date\u0027: \u0027Mon, 12 Jan 2026 16:24:14 -0000\u0027, \u0027Transfer-Encoding\u0027: \u0027chunked\u0027, \u0027X-Timestamp\u0027: \u00271768235054.30691\u0027, \u0027User-Agent\u0027: \u0027Mozzarella Foxfire\u0027}\n```\n\nthe env from the client request is copied to the swift request here https://github.com/openstack/swift/blob/db578c1077d25aa28ef704df94caa7de6cf782bb/swift/common/middleware/s3api/s3request.py#L1862","commit_id":"e6bc8d44506ca39ecac9b30ef793738ee80cffba"},{"author":{"_account_id":1179,"name":"Clay Gerrard","email":"clay.gerrard@gmail.com","username":"clay-gerrard"},"change_message_id":"e4ed2db0b4d14d074e263a47e448969d9c93fd5e","unresolved":true,"context_lines":[{"line_number":295,"context_line":"        self.assertEqual(headers[\u0027Location\u0027], \u0027/bucket\u0027)"},{"line_number":296,"context_line":"        _, path, sw_headers \u003d self.swift.calls_with_headers[-1]"},{"line_number":297,"context_line":"        self.assertEqual(\u0027/v1/AUTH_test/bucket\u0027, path)"},{"line_number":298,"context_line":"        self.assertNotIn(\u0027X-Timestamp\u0027, sw_headers)"},{"line_number":299,"context_line":""},{"line_number":300,"context_line":"        with UnreadableInput(self) as fake_input:"},{"line_number":301,"context_line":"            req \u003d Request.blank("}],"source_content_type":"text/x-python","patch_set":3,"id":"5ff1791c_f4b0a577","line":298,"updated":"2026-01-09 19:15:58.000000000","message":"why add this assertion to \"request 2/3\" - does it work on the others?  is \"bucket PUT has no x-timestamp\" even a behavior we WANT???\n\nUPDATE: seems fine/resonable to let proxy add x-timestamp - the question for me is now more about \"why is s3api inconsistent about adding x-timestamp?\"","commit_id":"e6bc8d44506ca39ecac9b30ef793738ee80cffba"},{"author":{"_account_id":7847,"name":"Alistair Coles","email":"alistairncoles@gmail.com","username":"acoles"},"change_message_id":"1fafc384ecd2671d6fad066654e5688b5c29272d","unresolved":true,"context_lines":[{"line_number":295,"context_line":"        self.assertEqual(headers[\u0027Location\u0027], \u0027/bucket\u0027)"},{"line_number":296,"context_line":"        _, path, sw_headers \u003d self.swift.calls_with_headers[-1]"},{"line_number":297,"context_line":"        self.assertEqual(\u0027/v1/AUTH_test/bucket\u0027, path)"},{"line_number":298,"context_line":"        self.assertNotIn(\u0027X-Timestamp\u0027, sw_headers)"},{"line_number":299,"context_line":""},{"line_number":300,"context_line":"        with UnreadableInput(self) as fake_input:"},{"line_number":301,"context_line":"            req \u003d Request.blank("}],"source_content_type":"text/x-python","patch_set":3,"id":"8691931d_8f6f4097","line":298,"in_reply_to":"5ff1791c_f4b0a577","updated":"2026-01-13 10:05:34.000000000","message":"\u003e why add this assertion to \"request 2/3\" - does it work on the others? is \"bucket PUT has no x-timestamp\" even a behavior we WANT???\n\nIDK why I spot-checked just the one case. will fix.\n\n\u003e the question for me is now more about \"why is s3api inconsistent about adding x-timestamp?\"\n\nI have the same question, but I chose not to address it in this patch. My goal is to test that wherever x-timestamp is added it is of the expected form, thinking ahead to PUTs and POSTs having different forms of timestamps.\n\nHaving discovered that s3api sometimes add timestamps, I wanted to be sure I had caught *all* of those cases, hence the negative assertion in other parts of the s3api interface (such as here).\n\nIt *would* be a good thing to figure out if there was any reason why the original author chose to have s3api controllers add the x-timestamp to *some* requests, and assuming there isn\u0027t, remove those and always delegate to the proxy app for consistency. But I chose not to put that ahead of fixing timestamp collisions.\n\nRevisiting this patch, I can now also see that removing the anomaly might make the timestamp changer *simpler* (less places where we create x-timestamp). So perhaps I should do that first! But IDK whether to gamble that making s3api code changes will sail through review and the gate with no delay, or leave the s3api changes for a later patch.\n\nI\u0027m also realising that perhaps I also need (in a later patch, not here) something like ``ensure_x_timestamp_is_correct_form_for_the_method`` to guard against any future case where someone decides to add (the wrong format) x-timestamp header in a middleware.\n\nAlso playing on my mind is a parallel proposal to set x-timestamp *earlier* in the patch chain https://review.opendev.org/c/openstack/swift/+/972988","commit_id":"e6bc8d44506ca39ecac9b30ef793738ee80cffba"}],"test/unit/common/middleware/s3api/test_multi_delete.py":[{"author":{"_account_id":1179,"name":"Clay Gerrard","email":"clay.gerrard@gmail.com","username":"clay-gerrard"},"change_message_id":"e4ed2db0b4d14d074e263a47e448969d9c93fd5e","unresolved":true,"context_lines":[{"line_number":231,"context_line":"            (\u0027DELETE\u0027, \u0027/v1/AUTH_test/bucket/business/caf\\xc3\\xa9\u0027),"},{"line_number":232,"context_line":"        ])"},{"line_number":233,"context_line":"        # s3api doesn\u0027t set storage policy index nor x-timestamp"},{"line_number":234,"context_line":"        # on backend requests"},{"line_number":235,"context_line":"        spi \u003d [hdrs.get(\u0027X-Backend-Storage-Policy-Index\u0027)"},{"line_number":236,"context_line":"               for _, _, hdrs in self.swift.calls_with_headers]"},{"line_number":237,"context_line":"        self.assertEqual(spi, [None] * 11)"}],"source_content_type":"text/x-python","patch_set":3,"id":"3b35bca6_4cf49dd0","line":234,"updated":"2026-01-09 19:15:58.000000000","message":"FWIW I think \"backend requests\" \u003d\u003d \"storage layer requests\" (like the proxy makes!)\n\n... in s3api I\u0027d probably say \"subrequest\" or \"proxy requests\" or \"swift requests\" to reference the app.getresponse calls that move downstream of the s3api middleware in the pipeline.\n\nEDIT: we do have swift.backend_path; so at least there\u0027s prior art for using \"backend\" ambiguously\n\n1) in the proxy *app* \"backend\" means \"storage request\"\n2) in the proxy *pipeline* \"backend\" means \"sub request\"","commit_id":"e6bc8d44506ca39ecac9b30ef793738ee80cffba"},{"author":{"_account_id":7847,"name":"Alistair Coles","email":"alistairncoles@gmail.com","username":"acoles"},"change_message_id":"1fafc384ecd2671d6fad066654e5688b5c29272d","unresolved":true,"context_lines":[{"line_number":231,"context_line":"            (\u0027DELETE\u0027, \u0027/v1/AUTH_test/bucket/business/caf\\xc3\\xa9\u0027),"},{"line_number":232,"context_line":"        ])"},{"line_number":233,"context_line":"        # s3api doesn\u0027t set storage policy index nor x-timestamp"},{"line_number":234,"context_line":"        # on backend requests"},{"line_number":235,"context_line":"        spi \u003d [hdrs.get(\u0027X-Backend-Storage-Policy-Index\u0027)"},{"line_number":236,"context_line":"               for _, _, hdrs in self.swift.calls_with_headers]"},{"line_number":237,"context_line":"        self.assertEqual(spi, [None] * 11)"}],"source_content_type":"text/x-python","patch_set":3,"id":"b3037c34_c4cec891","line":234,"in_reply_to":"3b35bca6_4cf49dd0","updated":"2026-01-13 10:05:34.000000000","message":"yeah, that\u0027s a fair point: \"subrequests\" would be clearer despite the precedence with backend path","commit_id":"e6bc8d44506ca39ecac9b30ef793738ee80cffba"},{"author":{"_account_id":1179,"name":"Clay Gerrard","email":"clay.gerrard@gmail.com","username":"clay-gerrard"},"change_message_id":"e4ed2db0b4d14d074e263a47e448969d9c93fd5e","unresolved":true,"context_lines":[{"line_number":237,"context_line":"        self.assertEqual(spi, [None] * 11)"},{"line_number":238,"context_line":"        ts \u003d [hdrs.get(\u0027X-Timestamp\u0027)"},{"line_number":239,"context_line":"              for _, _, hdrs in self.swift.calls_with_headers]"},{"line_number":240,"context_line":"        self.assertEqual(ts, [None] * 11)"},{"line_number":241,"context_line":""},{"line_number":242,"context_line":"    def test_object_multi_DELETE_with_error(self):"},{"line_number":243,"context_line":"        self.swift.register(\u0027DELETE\u0027, \u0027/v1/AUTH_test/bucket/Key1\u0027,"}],"source_content_type":"text/x-python","patch_set":3,"id":"aa1ddf44_ead83219","line":240,"updated":"2026-01-09 19:15:58.000000000","message":"oic, this s3api request made 11 subrequests - which probably would make even MORE \"backend\" requests for each write... the subrequests don\u0027t have x-timestamp, but the backend request writes DO (it\u0027s just FakeSwift doesn\u0027t *make* \"backend\" requests - it just stubs the proxy subrequest responses)","commit_id":"e6bc8d44506ca39ecac9b30ef793738ee80cffba"}],"test/unit/common/middleware/s3api/test_multi_upload.py":[{"author":{"_account_id":1179,"name":"Clay Gerrard","email":"clay.gerrard@gmail.com","username":"clay-gerrard"},"change_message_id":"e4ed2db0b4d14d074e263a47e448969d9c93fd5e","unresolved":true,"context_lines":[{"line_number":970,"context_line":"        self._assert_policy_index(req.headers, headers,"},{"line_number":971,"context_line":"                                  segment_bucket_policy_index)"},{"line_number":972,"context_line":"        put_headers \u003d self.swift.calls_with_headers[-1][2]"},{"line_number":973,"context_line":"        self._assert_valid_timestamp(put_headers.get(\u0027X-Timestamp\u0027))"},{"line_number":974,"context_line":""},{"line_number":975,"context_line":"    def test_bucket_upload_part_success(self):"},{"line_number":976,"context_line":"        self._do_test_bucket_upload_part_success(0, 0)"}],"source_content_type":"text/x-python","patch_set":3,"id":"4ab07562_3bba9c2b","line":973,"updated":"2026-01-09 19:15:58.000000000","message":"and so why does a multi_upload.PartController.PUT add an x-timestamp to the segment PUT?\n\nhttps://github.com/NVIDIA/swift/blob/master/swift/common/middleware/s3api/controllers/multi_upload.py#L207\n\n```\ndiff --git a/swift/common/middleware/s3api/controllers/multi_upload.py b/swift/common/middleware/s3api/controllers/multi_upload.py\nindex 657d9f30d..504cd5992 100644\n--- a/swift/common/middleware/s3api/controllers/multi_upload.py\n+++ b/swift/common/middleware/s3api/controllers/multi_upload.py\n@@ -204,7 +204,7 @@ class PartController(Controller):\n                                         part_number)\n \n         req_timestamp \u003d S3Timestamp.now()\n-        req.headers[\u0027X-Timestamp\u0027] \u003d req_timestamp.internal\n+        # req.headers[\u0027X-Timestamp\u0027] \u003d req_timestamp.internal\n         source_resp \u003d req.check_copy_source(self.app)\n         if \u0027X-Amz-Copy-Source\u0027 in req.headers and \\\n                 \u0027X-Amz-Copy-Source-Range\u0027 in req.headers:\n\nvagrant@saio:~$ pytest swift/test/unit/common/middleware/s3api/\n...\nvagrant@saio:~$ echo $?\n0\n```\n\nNOT IDEAL!  code goes back to original swift3 import.\n\nUPDATE: maybe cargo cult from object PUT behavior!?","commit_id":"e6bc8d44506ca39ecac9b30ef793738ee80cffba"},{"author":{"_account_id":7847,"name":"Alistair Coles","email":"alistairncoles@gmail.com","username":"acoles"},"change_message_id":"1fafc384ecd2671d6fad066654e5688b5c29272d","unresolved":true,"context_lines":[{"line_number":970,"context_line":"        self._assert_policy_index(req.headers, headers,"},{"line_number":971,"context_line":"                                  segment_bucket_policy_index)"},{"line_number":972,"context_line":"        put_headers \u003d self.swift.calls_with_headers[-1][2]"},{"line_number":973,"context_line":"        self._assert_valid_timestamp(put_headers.get(\u0027X-Timestamp\u0027))"},{"line_number":974,"context_line":""},{"line_number":975,"context_line":"    def test_bucket_upload_part_success(self):"},{"line_number":976,"context_line":"        self._do_test_bucket_upload_part_success(0, 0)"}],"source_content_type":"text/x-python","patch_set":3,"id":"db92f66d_adeb7a92","line":973,"in_reply_to":"4ab07562_3bba9c2b","updated":"2026-01-13 10:05:34.000000000","message":"Yep, it\u0027s frustrating to not know the mind of the original author!","commit_id":"e6bc8d44506ca39ecac9b30ef793738ee80cffba"},{"author":{"_account_id":1179,"name":"Clay Gerrard","email":"clay.gerrard@gmail.com","username":"clay-gerrard"},"change_message_id":"e4ed2db0b4d14d074e263a47e448969d9c93fd5e","unresolved":true,"context_lines":[{"line_number":1449,"context_line":"        self.assertEqual(headers.get(\u0027X-Object-Sysmeta-S3Api-Upload-Id\u0027), \u0027X\u0027)"},{"line_number":1450,"context_line":""},{"line_number":1451,"context_line":"        # s3api doesn\u0027t set storage policy index nor x-timestamp"},{"line_number":1452,"context_line":"        # on backend requests"},{"line_number":1453,"context_line":"        spi \u003d [hdrs.get(\u0027X-Backend-Storage-Policy-Index\u0027)"},{"line_number":1454,"context_line":"               for _, _, hdrs in self.swift.calls_with_headers]"},{"line_number":1455,"context_line":"        self.assertEqual(spi, [None] * 5)"}],"source_content_type":"text/x-python","patch_set":3,"id":"b8b28397_2022d6f4","line":1452,"updated":"2026-01-09 19:15:58.000000000","message":"it does on SOME of them!?  the inconsistency bugs me; but not as much as not knowing WHY there\u0027s inconsistency and adding tests to ensure we maintain the inconsistency w/o any explanation/justification.","commit_id":"e6bc8d44506ca39ecac9b30ef793738ee80cffba"},{"author":{"_account_id":7847,"name":"Alistair Coles","email":"alistairncoles@gmail.com","username":"acoles"},"change_message_id":"1fafc384ecd2671d6fad066654e5688b5c29272d","unresolved":true,"context_lines":[{"line_number":1449,"context_line":"        self.assertEqual(headers.get(\u0027X-Object-Sysmeta-S3Api-Upload-Id\u0027), \u0027X\u0027)"},{"line_number":1450,"context_line":""},{"line_number":1451,"context_line":"        # s3api doesn\u0027t set storage policy index nor x-timestamp"},{"line_number":1452,"context_line":"        # on backend requests"},{"line_number":1453,"context_line":"        spi \u003d [hdrs.get(\u0027X-Backend-Storage-Policy-Index\u0027)"},{"line_number":1454,"context_line":"               for _, _, hdrs in self.swift.calls_with_headers]"},{"line_number":1455,"context_line":"        self.assertEqual(spi, [None] * 5)"}],"source_content_type":"text/x-python","patch_set":3,"id":"eeb3a166_84ddde15","line":1452,"in_reply_to":"b8b28397_2022d6f4","updated":"2026-01-13 10:05:34.000000000","message":"\u003e it does on SOME of them!? \n\nok, but the comment is written in the context of MPU. I\u0027ll clarify.\n\n\u003e adding tests to ensure we maintain the inconsistency \n\nI\u0027m not adding tests to ensure that the inconsistency is maintained, I\u0027m adding them to ensure that where a timestamp is added *it is valid*. I don\u0027t feel that should oblige me to understand and then possibly fix the inconsistency in *where a timestamp is added*, particularly given the urgency of the timestamp collision work. But I do think I should add some comment to indicate that the test assertion is questionable. (I think I\u0027ll do that where the header IS added)\n\nOh, and I think this is where I picked up the existing use of \"backend requests\"","commit_id":"e6bc8d44506ca39ecac9b30ef793738ee80cffba"}],"test/unit/common/middleware/s3api/test_obj.py":[{"author":{"_account_id":1179,"name":"Clay Gerrard","email":"clay.gerrard@gmail.com","username":"clay-gerrard"},"change_message_id":"e4ed2db0b4d14d074e263a47e448969d9c93fd5e","unresolved":true,"context_lines":[{"line_number":717,"context_line":"        _, _, sw_headers \u003d self.swift.calls_with_headers[-1]"},{"line_number":718,"context_line":"        # Check that s3api converts a Content-MD5 header into an etag."},{"line_number":719,"context_line":"        self.assertEqual(sw_headers[\u0027etag\u0027], etag)"},{"line_number":720,"context_line":"        self._assert_valid_timestamp(sw_headers.get(\u0027X-Timestamp\u0027))"},{"line_number":721,"context_line":""},{"line_number":722,"context_line":"    def test_object_PUT_bad_hash(self):"},{"line_number":723,"context_line":"        # FakeSwift doesn\u0027t care if the etag matches, so we explicitly register"}],"source_content_type":"text/x-python","patch_set":3,"id":"bdc357b8_732c57ed","line":720,"updated":"2026-01-09 19:15:58.000000000","message":"what happened to \"s3api doesn\u0027t set x-timestamp on subrequests\" !?\n\nGD\n\n```\n(vagrant-swift-all-in-one) cgerrard@NVStation:~/Workspace/vagrant-swift-all-in-one/swift$ git diff\ndiff --git a/swift/common/middleware/s3api/controllers/obj.py b/swift/common/middleware/s3api/controllers/obj.py\nindex 930beb0fe..111b72d60 100644\n--- a/swift/common/middleware/s3api/controllers/obj.py\n+++ b/swift/common/middleware/s3api/controllers/obj.py\n@@ -164,7 +164,7 @@ class ObjectController(Controller):\n             raise KeyTooLongError()\n         # set X-Timestamp by s3api to use at copy resp body\n         req_timestamp \u003d S3Timestamp.now()\n-        req.headers[\u0027X-Timestamp\u0027] \u003d req_timestamp.internal\n+        # req.headers[\u0027X-Timestamp\u0027] \u003d req_timestamp.internal\n         if all(h in req.headers\n                for h in (\u0027X-Amz-Copy-Source\u0027, \u0027X-Amz-Copy-Source-Range\u0027)):\n             raise InvalidArgument(\u0027x-amz-copy-source-range\u0027,\n\nvagrant@saio:~$ pytest swift/test/unit/common/middleware/s3api/ -vsx\n...\nvagrant@saio:~$ echo $?\n0\n```\n\n😭\n\n^ N.B. this is a pre-existing tragedy on master, after THIS change if someone tries to ask the question \"why does s3api set x-timestamp on obj/segment PUT and nowhere else!?\" they\u0027ll have a clear answer:\n\n```\n\u003e       self._assert_valid_timestamp(sw_headers.get(\u0027X-Timestamp\u0027))\n\nswift/test/unit/common/middleware/s3api/test_obj.py:720: \n_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ \nswift/test/__init__.py:130: in _assert_valid_timestamp\n    self.fail(\u0027Invalid timestamp (%r): %r\u0027 % (timestamp, e))\nE   AssertionError: Invalid timestamp (None): TypeError(\"float() argument must be a string or a real number, not \u0027NoneType\u0027\")\n\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d short test summary info \u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\nFAILED swift/test/unit/common/middleware/s3api/test_obj.py::TestS3ApiObj::test_object_PUT - AssertionError: Invalid timestamp (None): TypeError(\"float() argument must be a string or a real number, not \u0027NoneType\u0027\")\n```\n\nbecause \"None is not a float\" - that\u0027s WHY 😜\n\nHT this guy https://www.youtube.com/shorts/VSgiDX8Op_8 - \"why would you think?\"","commit_id":"e6bc8d44506ca39ecac9b30ef793738ee80cffba"},{"author":{"_account_id":7847,"name":"Alistair Coles","email":"alistairncoles@gmail.com","username":"acoles"},"change_message_id":"1fafc384ecd2671d6fad066654e5688b5c29272d","unresolved":true,"context_lines":[{"line_number":717,"context_line":"        _, _, sw_headers \u003d self.swift.calls_with_headers[-1]"},{"line_number":718,"context_line":"        # Check that s3api converts a Content-MD5 header into an etag."},{"line_number":719,"context_line":"        self.assertEqual(sw_headers[\u0027etag\u0027], etag)"},{"line_number":720,"context_line":"        self._assert_valid_timestamp(sw_headers.get(\u0027X-Timestamp\u0027))"},{"line_number":721,"context_line":""},{"line_number":722,"context_line":"    def test_object_PUT_bad_hash(self):"},{"line_number":723,"context_line":"        # FakeSwift doesn\u0027t care if the etag matches, so we explicitly register"}],"source_content_type":"text/x-python","patch_set":3,"id":"398893bc_57cb0fc0","line":720,"in_reply_to":"bdc357b8_732c57ed","updated":"2026-01-13 10:05:34.000000000","message":"LOL","commit_id":"e6bc8d44506ca39ecac9b30ef793738ee80cffba"}],"test/unit/common/middleware/s3api/test_utils.py":[{"author":{"_account_id":1179,"name":"Clay Gerrard","email":"clay.gerrard@gmail.com","username":"clay-gerrard"},"change_message_id":"e4ed2db0b4d14d074e263a47e448969d9c93fd5e","unresolved":true,"context_lines":[{"line_number":317,"context_line":"                return_value\u003d1234567890.123451):"},{"line_number":318,"context_line":"            ts \u003d utils.S3Timestamp.now()"},{"line_number":319,"context_line":"        self.assertEqual(\u00271234567890.12345\u0027, ts.internal)"},{"line_number":320,"context_line":"        self.assertEqual(1234567890.12345, float(ts))"},{"line_number":321,"context_line":""},{"line_number":322,"context_line":"    def test_s3xmlformat(self):"},{"line_number":323,"context_line":"        expected \u003d \u00271970-01-01T00:00:01.000Z\u0027"}],"source_content_type":"text/x-python","patch_set":3,"id":"04d781ce_d7f77722","line":320,"updated":"2026-01-09 19:15:58.000000000","message":"i don\u0027t think I get these tests - S3Timestamp\u0027s ARE utils.Timestamps (with extra s3xml helpers) ... are we trying to confirm/verifiy something?","commit_id":"e6bc8d44506ca39ecac9b30ef793738ee80cffba"},{"author":{"_account_id":7847,"name":"Alistair Coles","email":"alistairncoles@gmail.com","username":"acoles"},"change_message_id":"1fafc384ecd2671d6fad066654e5688b5c29272d","unresolved":true,"context_lines":[{"line_number":317,"context_line":"                return_value\u003d1234567890.123451):"},{"line_number":318,"context_line":"            ts \u003d utils.S3Timestamp.now()"},{"line_number":319,"context_line":"        self.assertEqual(\u00271234567890.12345\u0027, ts.internal)"},{"line_number":320,"context_line":"        self.assertEqual(1234567890.12345, float(ts))"},{"line_number":321,"context_line":""},{"line_number":322,"context_line":"    def test_s3xmlformat(self):"},{"line_number":323,"context_line":"        expected \u003d \u00271970-01-01T00:00:01.000Z\u0027"}],"source_content_type":"text/x-python","patch_set":3,"id":"83305fac_e107e17c","line":320,"in_reply_to":"04d781ce_d7f77722","updated":"2026-01-13 10:05:34.000000000","message":"\u003e are we trying to confirm/verifiy something?\nthat S3Timestamps *are* Timestamps ;-) specifically that they do not override the behaviour that I care about right now.\n\ncf. https://review.opendev.org/c/openstack/swift/+/972212\n\nI think we always run into this problem with subclassing i.e. how far do we go to verify that the subclass hasn\u0027t modified the superclass behaviour? \n\nIt\u0027d be nice if there was a way to assert that subclass.foo IS superclass.foo but TIL:\n```\ns3u.S3Timestamp.now is ts.Timestamp.now\nFalse\n```\n\nAm I worrying too much? Perhaps I wouldn\u0027t if I\u0027d never seen a call to S3Timestamp.now() 😂","commit_id":"e6bc8d44506ca39ecac9b30ef793738ee80cffba"}],"test/unit/proxy/controllers/test_obj.py":[{"author":{"_account_id":1179,"name":"Clay Gerrard","email":"clay.gerrard@gmail.com","username":"clay-gerrard"},"change_message_id":"e4ed2db0b4d14d074e263a47e448969d9c93fd5e","unresolved":true,"context_lines":[{"line_number":1422,"context_line":"                      for captured in mock_conn.requests]"},{"line_number":1423,"context_line":"        self.assertEqual(self.replicas(), len(timestamps))"},{"line_number":1424,"context_line":"        self.assertEqual(1, len(set(timestamps)))"},{"line_number":1425,"context_line":"        self._assert_valid_timestamp(timestamps[0])"},{"line_number":1426,"context_line":""},{"line_number":1427,"context_line":"    def test_POST_sufficient_primaries_succeed_others_404(self):"},{"line_number":1428,"context_line":"        req \u003d swift.common.swob.Request.blank(\u0027/v1/a/c/o\u0027, method\u003d\u0027POST\u0027)"}],"source_content_type":"text/x-python","patch_set":3,"id":"e6b98fab_ef6d411b","line":1425,"updated":"2026-01-09 19:15:58.000000000","message":"these \"captured[\u0027headers\u0027]\" are the REAL headers sent on the wire to the object server?\n\nThe comment in assertValidTimestamp suggest that we\u0027ll verify jitter - but I thought POST wasn\u0027t going to GET a jitter sent to object-server b/c of upgrade concerns?","commit_id":"e6bc8d44506ca39ecac9b30ef793738ee80cffba"},{"author":{"_account_id":7847,"name":"Alistair Coles","email":"alistairncoles@gmail.com","username":"acoles"},"change_message_id":"1fafc384ecd2671d6fad066654e5688b5c29272d","unresolved":true,"context_lines":[{"line_number":1422,"context_line":"                      for captured in mock_conn.requests]"},{"line_number":1423,"context_line":"        self.assertEqual(self.replicas(), len(timestamps))"},{"line_number":1424,"context_line":"        self.assertEqual(1, len(set(timestamps)))"},{"line_number":1425,"context_line":"        self._assert_valid_timestamp(timestamps[0])"},{"line_number":1426,"context_line":""},{"line_number":1427,"context_line":"    def test_POST_sufficient_primaries_succeed_others_404(self):"},{"line_number":1428,"context_line":"        req \u003d swift.common.swob.Request.blank(\u0027/v1/a/c/o\u0027, method\u003d\u0027POST\u0027)"}],"source_content_type":"text/x-python","patch_set":3,"id":"935a51ac_c90eda0d","line":1425,"in_reply_to":"e6b98fab_ef6d411b","updated":"2026-01-13 10:05:34.000000000","message":"Yes, so the jitter patch will change this assertion to \n```\nself._assert_valid_timestamp_without_jitter(timestamps[0])\n```","commit_id":"e6bc8d44506ca39ecac9b30ef793738ee80cffba"},{"author":{"_account_id":1179,"name":"Clay Gerrard","email":"clay.gerrard@gmail.com","username":"clay-gerrard"},"change_message_id":"e4ed2db0b4d14d074e263a47e448969d9c93fd5e","unresolved":true,"context_lines":[{"line_number":7357,"context_line":"                      for captured in mock_conn.requests]"},{"line_number":7358,"context_line":"        self.assertEqual(self.replicas(), len(timestamps))"},{"line_number":7359,"context_line":"        self.assertEqual(1, len(set(timestamps)))"},{"line_number":7360,"context_line":"        self._assert_valid_timestamp(timestamps[0])"},{"line_number":7361,"context_line":""},{"line_number":7362,"context_line":"    def test_PUT_with_body_and_bad_etag(self):"},{"line_number":7363,"context_line":"        segment_size \u003d self.policy.ec_segment_size"}],"source_content_type":"text/x-python","patch_set":3,"id":"d333ab24_75941f70","line":7360,"updated":"2026-01-09 19:15:58.000000000","message":"i think this is pretty good","commit_id":"e6bc8d44506ca39ecac9b30ef793738ee80cffba"}],"test/unit/proxy/test_server.py":[{"author":{"_account_id":1179,"name":"Clay Gerrard","email":"clay.gerrard@gmail.com","username":"clay-gerrard"},"change_message_id":"e4ed2db0b4d14d074e263a47e448969d9c93fd5e","unresolved":true,"context_lines":[{"line_number":10274,"context_line":"                                                          \u0027container\u0027)"},{"line_number":10275,"context_line":""},{"line_number":10276,"context_line":"            def test_status_map(statuses, expected, **kwargs):"},{"line_number":10277,"context_line":"                set_http_connect(*statuses, **kwargs)"},{"line_number":10278,"context_line":"                req \u003d Request.blank(\u0027/v1/a/c\u0027, {})"},{"line_number":10279,"context_line":"                req.content_length \u003d 0"},{"line_number":10280,"context_line":"                self.app.update_request(req)"}],"source_content_type":"text/x-python","patch_set":3,"id":"d089dd39_7470d032","side":"PARENT","line":10277,"updated":"2026-01-09 19:15:58.000000000","message":"IMHO mocked_http_conn is always an improvement for maintainability over the lower level set_http_connect","commit_id":"97ec6333c417dec196c79787596a5a28885638d4"},{"author":{"_account_id":7847,"name":"Alistair Coles","email":"alistairncoles@gmail.com","username":"acoles"},"change_message_id":"1fafc384ecd2671d6fad066654e5688b5c29272d","unresolved":false,"context_lines":[{"line_number":10274,"context_line":"                                                          \u0027container\u0027)"},{"line_number":10275,"context_line":""},{"line_number":10276,"context_line":"            def test_status_map(statuses, expected, **kwargs):"},{"line_number":10277,"context_line":"                set_http_connect(*statuses, **kwargs)"},{"line_number":10278,"context_line":"                req \u003d Request.blank(\u0027/v1/a/c\u0027, {})"},{"line_number":10279,"context_line":"                req.content_length \u003d 0"},{"line_number":10280,"context_line":"                self.app.update_request(req)"}],"source_content_type":"text/x-python","patch_set":3,"id":"bfe42c4e_e8295946","side":"PARENT","line":10277,"in_reply_to":"d089dd39_7470d032","updated":"2026-01-13 10:05:34.000000000","message":"Acknowledged","commit_id":"97ec6333c417dec196c79787596a5a28885638d4"},{"author":{"_account_id":1179,"name":"Clay Gerrard","email":"clay.gerrard@gmail.com","username":"clay-gerrard"},"change_message_id":"e4ed2db0b4d14d074e263a47e448969d9c93fd5e","unresolved":true,"context_lines":[{"line_number":10288,"context_line":"            test_status_map((200, 204, 500, 404), 503, missing_container\u003dTrue)"},{"line_number":10289,"context_line":"            self.assertFalse(self.app.account_autocreate)"},{"line_number":10290,"context_line":"            test_status_map((404, 404, 404), 404, missing_container\u003dTrue)"},{"line_number":10291,"context_line":"            self.app.account_autocreate \u003d True"},{"line_number":10292,"context_line":"            # fail to retrieve account info"},{"line_number":10293,"context_line":"            test_status_map("},{"line_number":10294,"context_line":"                (503, 503, 503),  # account_info fails on 503"}],"source_content_type":"text/x-python","patch_set":3,"id":"89420911_2d894901","side":"PARENT","line":10291,"updated":"2026-01-09 19:15:58.000000000","message":"oic, I missed the mode change in this test","commit_id":"97ec6333c417dec196c79787596a5a28885638d4"},{"author":{"_account_id":7847,"name":"Alistair Coles","email":"alistairncoles@gmail.com","username":"acoles"},"change_message_id":"821804611cd9479623f9282762199637bef9068d","unresolved":true,"context_lines":[{"line_number":10291,"context_line":"            self.app.account_autocreate \u003d True"},{"line_number":10292,"context_line":"            # fail to retrieve account info"},{"line_number":10293,"context_line":"            test_status_map("},{"line_number":10294,"context_line":"                (503, 503, 503),  # account_info fails on 503"},{"line_number":10295,"context_line":"                503, missing_container\u003dTrue)"},{"line_number":10296,"context_line":"            # account fail after creation"},{"line_number":10297,"context_line":"            test_status_map("}],"source_content_type":"text/x-python","patch_set":3,"id":"92b389a7_abaf96d6","side":"PARENT","line":10294,"updated":"2026-01-09 13:08:14.000000000","message":"in reality this scenario goes on to attempt to create the account: set_http_connect does not flag up the unexpected requests, mocked_http_conn does","commit_id":"97ec6333c417dec196c79787596a5a28885638d4"},{"author":{"_account_id":1179,"name":"Clay Gerrard","email":"clay.gerrard@gmail.com","username":"clay-gerrard"},"change_message_id":"e4ed2db0b4d14d074e263a47e448969d9c93fd5e","unresolved":true,"context_lines":[{"line_number":10303,"context_line":"                (503, 503, 404,   # account_info fails on 404"},{"line_number":10304,"context_line":"                 503, 503, 503,   # PUT account"},{"line_number":10305,"context_line":"                 503, 503, 404),  # account_info fail"},{"line_number":10306,"context_line":"                503, missing_container\u003dTrue)"},{"line_number":10307,"context_line":"            # put fails"},{"line_number":10308,"context_line":"            test_status_map("},{"line_number":10309,"context_line":"                (404, 404, 404,   # account_info fails on 404"}],"source_content_type":"text/x-python","patch_set":3,"id":"250ead75_41bf643e","side":"PARENT","line":10306,"updated":"2026-01-09 19:15:58.000000000","message":"UPDATE:\n\nmaybe this hunk would have been more obvious as:\n\n```\n@@ -10291,18 +10313,18 @@ class TestContainerController(unittest.TestCase):\n             self.app.account_autocreate \u003d True\n             # fail to retrieve account info\n             test_status_map(\n-                (503, 503, 503),  # account_info fails on 503\n+                (503, 503, 503,   # account_info fails on 503\n+                 503, 503, 503),  # account PUT fails\n                 503, missing_container\u003dTrue)\n+            test_status_map(\n+                (503, 503, 404,    # account_info fails on 404\n+                 503, 503, 503),   # account PUT fails\n             # account fail after creation\n             test_status_map(\n                 (404, 404, 404,   # account_info fails on 404\n                  201, 201, 201,   # PUT account\n                  404, 404, 404),  # account_info fail\n                 404, missing_container\u003dTrue)\n-            test_status_map(\n-                (503, 503, 404,   # account_info fails on 404\n-                 503, 503, 503,   # PUT account\n-                 503, 503, 404),  # account_info fail\n                 503, missing_container\u003dTrue)\n             # put fails\n             test_status_map(\n```\n\nORIGINAL CONFUSION:\n\nheh, what happened here?  was this just non-sense?\n\nthat\u0027s WEIRD\n\n```\nAssertionError: left over status [503, 503, 503, 503, 503, 404]\n```\n\nthat\u0027s SUSPICIOUS\n```\n    self.assertEqual(res.status[:len(expected)], expected)\nE   AssertionError: \u0027404\u0027 !\u003d \u0027503\u0027\nE   - 404\nE   + 503\n```\n\nok, so this ends up becoming *almost* the same as the other case:\n\n```\n(503, 503, 404,  # account_info fails on 404\n503, 503, 503),  # account PUT fails\n```\n\n... so why remove it, \"(503, 503, 404) is another account_info failure that results in account PUT\"???","commit_id":"97ec6333c417dec196c79787596a5a28885638d4"},{"author":{"_account_id":7847,"name":"Alistair Coles","email":"alistairncoles@gmail.com","username":"acoles"},"change_message_id":"1fafc384ecd2671d6fad066654e5688b5c29272d","unresolved":true,"context_lines":[{"line_number":10303,"context_line":"                (503, 503, 404,   # account_info fails on 404"},{"line_number":10304,"context_line":"                 503, 503, 503,   # PUT account"},{"line_number":10305,"context_line":"                 503, 503, 404),  # account_info fail"},{"line_number":10306,"context_line":"                503, missing_container\u003dTrue)"},{"line_number":10307,"context_line":"            # put fails"},{"line_number":10308,"context_line":"            test_status_map("},{"line_number":10309,"context_line":"                (404, 404, 404,   # account_info fails on 404"}],"source_content_type":"text/x-python","patch_set":3,"id":"7c2d0508_1dcdd127","side":"PARENT","line":10306,"in_reply_to":"250ead75_41bf643e","updated":"2026-01-13 10:05:34.000000000","message":"\u003e so why remove it, \"(503, 503, 404) is another account_info failure that results in account PUT\"???\n\nbecause I\u0027m dumb or had very tired eyes or both :D . will fix","commit_id":"97ec6333c417dec196c79787596a5a28885638d4"},{"author":{"_account_id":1179,"name":"Clay Gerrard","email":"clay.gerrard@gmail.com","username":"clay-gerrard"},"change_message_id":"e4ed2db0b4d14d074e263a47e448969d9c93fd5e","unresolved":true,"context_lines":[{"line_number":10337,"context_line":"                 201, 201, 201),  # put container success"},{"line_number":10338,"context_line":"                201, missing_container\u003dTrue)"},{"line_number":10339,"context_line":"            test_status_map("},{"line_number":10340,"context_line":"                (503, 404, 404,   # account_info fails on 404"},{"line_number":10341,"context_line":"                 503, 201, 201,   # PUT account"},{"line_number":10342,"context_line":"                 503, 200,        # account_info success"},{"line_number":10343,"context_line":"                 503, 201, 201),  # put container success"}],"source_content_type":"text/x-python","patch_set":3,"id":"44138e0b_c0de1cf4","line":10340,"updated":"2026-01-09 19:15:58.000000000","message":"ahh, maybe remove it b/c \"mixed-503+404 account_info failure that results in account PUT\" iS tested even MORE here!!!???  Except this one has the PUT account succeed...\n\nidk, probably better not to remove scenario asserts even if they seem somewhat redundant - if they *exactly* duplicate another scenario there\u0027s a test maintenance win to remove one of them, but even if they\u0027re just *slightly* different it\u0027s maybe not worth the reviewer overhead to ask them to verify/conclude \"yes, the interesting parts of this scenario are sufficiently covered elsewhere\"","commit_id":"e6bc8d44506ca39ecac9b30ef793738ee80cffba"},{"author":{"_account_id":7847,"name":"Alistair Coles","email":"alistairncoles@gmail.com","username":"acoles"},"change_message_id":"1fafc384ecd2671d6fad066654e5688b5c29272d","unresolved":true,"context_lines":[{"line_number":10337,"context_line":"                 201, 201, 201),  # put container success"},{"line_number":10338,"context_line":"                201, missing_container\u003dTrue)"},{"line_number":10339,"context_line":"            test_status_map("},{"line_number":10340,"context_line":"                (503, 404, 404,   # account_info fails on 404"},{"line_number":10341,"context_line":"                 503, 201, 201,   # PUT account"},{"line_number":10342,"context_line":"                 503, 200,        # account_info success"},{"line_number":10343,"context_line":"                 503, 201, 201),  # put container success"}],"source_content_type":"text/x-python","patch_set":3,"id":"0a792a38_c2e38626","line":10340,"in_reply_to":"44138e0b_c0de1cf4","updated":"2026-01-13 10:05:34.000000000","message":"I *think* I removed the scenario because once I had cleaned up the unused responses (flagged by mocked_http_connect) I mistakenly saw (with tired eyes??):\n\n```\n            test_status_map(\n                (503, 503, 503,   # account_info fails on 503\n                 503, 503, 503),  # account PUT fails\n                503, missing_container\u003dTrue)\n```\nas the same as \n```\n            test_status_map(\n                (503, 503, 404,   # account_info fails on 503\n                 503, 503, 503),  # PUT account\n                503, missing_container\u003dTrue)\n```\n\nApologies for the confusion!","commit_id":"e6bc8d44506ca39ecac9b30ef793738ee80cffba"},{"author":{"_account_id":7847,"name":"Alistair Coles","email":"alistairncoles@gmail.com","username":"acoles"},"change_message_id":"821804611cd9479623f9282762199637bef9068d","unresolved":true,"context_lines":[{"line_number":11488,"context_line":"            self.assert_status_map(controller.HEAD, (503, 503, 200), 200, 200)"},{"line_number":11489,"context_line":"            self.assert_status_map(controller.HEAD, (204,), 204, 204)"},{"line_number":11490,"context_line":"            self.assert_status_map(controller.HEAD, (503, 204), 204, 204)"},{"line_number":11491,"context_line":"            self.assert_status_map(controller.HEAD, (204,), 204, 204)"},{"line_number":11492,"context_line":"            self.assert_status_map(controller.HEAD, (204,), 204, 204)"},{"line_number":11493,"context_line":"            self.assert_status_map(controller.HEAD, (404, 404, 404), 404, 404)"},{"line_number":11494,"context_line":"            self.assert_status_map(controller.HEAD, (404, 404, 200), 200, 200)"}],"source_content_type":"text/x-python","patch_set":3,"id":"4e0a1b44_72bb3772","line":11491,"updated":"2026-01-09 13:08:14.000000000","message":"mocked_http_conn is more rigorous and checks for unused responses","commit_id":"e6bc8d44506ca39ecac9b30ef793738ee80cffba"},{"author":{"_account_id":7847,"name":"Alistair Coles","email":"alistairncoles@gmail.com","username":"acoles"},"change_message_id":"1fafc384ecd2671d6fad066654e5688b5c29272d","unresolved":false,"context_lines":[{"line_number":11488,"context_line":"            self.assert_status_map(controller.HEAD, (503, 503, 200), 200, 200)"},{"line_number":11489,"context_line":"            self.assert_status_map(controller.HEAD, (204,), 204, 204)"},{"line_number":11490,"context_line":"            self.assert_status_map(controller.HEAD, (503, 204), 204, 204)"},{"line_number":11491,"context_line":"            self.assert_status_map(controller.HEAD, (204,), 204, 204)"},{"line_number":11492,"context_line":"            self.assert_status_map(controller.HEAD, (204,), 204, 204)"},{"line_number":11493,"context_line":"            self.assert_status_map(controller.HEAD, (404, 404, 404), 404, 404)"},{"line_number":11494,"context_line":"            self.assert_status_map(controller.HEAD, (404, 404, 200), 200, 200)"}],"source_content_type":"text/x-python","patch_set":3,"id":"da28c94d_8037f8b3","line":11491,"in_reply_to":"4e0a1b44_72bb3772","updated":"2026-01-13 10:05:34.000000000","message":"Acknowledged","commit_id":"e6bc8d44506ca39ecac9b30ef793738ee80cffba"},{"author":{"_account_id":7847,"name":"Alistair Coles","email":"alistairncoles@gmail.com","username":"acoles"},"change_message_id":"821804611cd9479623f9282762199637bef9068d","unresolved":true,"context_lines":[{"line_number":11552,"context_line":"                headers\u003dheaders)"},{"line_number":11553,"context_line":"            self.assertEqual(9, len(mock_conn.requests))"},{"line_number":11554,"context_line":"            for request in mock_conn.requests:"},{"line_number":11555,"context_line":"                print(request)"},{"line_number":11556,"context_line":"                self.assertIn(key, request[\u0027headers\u0027],"},{"line_number":11557,"context_line":"                              \u0027%s call, key %s missing in headers %s\u0027 %"},{"line_number":11558,"context_line":"                              (request[\u0027method\u0027], key, request[\u0027headers\u0027]))"}],"source_content_type":"text/x-python","patch_set":3,"id":"3340cc35_05263fb0","line":11555,"updated":"2026-01-09 13:08:14.000000000","message":"gah!","commit_id":"e6bc8d44506ca39ecac9b30ef793738ee80cffba"},{"author":{"_account_id":1179,"name":"Clay Gerrard","email":"clay.gerrard@gmail.com","username":"clay-gerrard"},"change_message_id":"e4ed2db0b4d14d074e263a47e448969d9c93fd5e","unresolved":true,"context_lines":[{"line_number":11552,"context_line":"                headers\u003dheaders)"},{"line_number":11553,"context_line":"            self.assertEqual(9, len(mock_conn.requests))"},{"line_number":11554,"context_line":"            for request in mock_conn.requests:"},{"line_number":11555,"context_line":"                print(request)"},{"line_number":11556,"context_line":"                self.assertIn(key, request[\u0027headers\u0027],"},{"line_number":11557,"context_line":"                              \u0027%s call, key %s missing in headers %s\u0027 %"},{"line_number":11558,"context_line":"                              (request[\u0027method\u0027], key, request[\u0027headers\u0027]))"}],"source_content_type":"text/x-python","patch_set":3,"id":"e3aa3514_da274a47","line":11555,"in_reply_to":"3340cc35_05263fb0","updated":"2026-01-09 19:15:58.000000000","message":"😄","commit_id":"e6bc8d44506ca39ecac9b30ef793738ee80cffba"},{"author":{"_account_id":7847,"name":"Alistair Coles","email":"alistairncoles@gmail.com","username":"acoles"},"change_message_id":"1fafc384ecd2671d6fad066654e5688b5c29272d","unresolved":false,"context_lines":[{"line_number":11552,"context_line":"                headers\u003dheaders)"},{"line_number":11553,"context_line":"            self.assertEqual(9, len(mock_conn.requests))"},{"line_number":11554,"context_line":"            for request in mock_conn.requests:"},{"line_number":11555,"context_line":"                print(request)"},{"line_number":11556,"context_line":"                self.assertIn(key, request[\u0027headers\u0027],"},{"line_number":11557,"context_line":"                              \u0027%s call, key %s missing in headers %s\u0027 %"},{"line_number":11558,"context_line":"                              (request[\u0027method\u0027], key, request[\u0027headers\u0027]))"}],"source_content_type":"text/x-python","patch_set":3,"id":"e3ab6ef3_7f15fea4","line":11555,"in_reply_to":"e3aa3514_da274a47","updated":"2026-01-13 10:05:34.000000000","message":"Done","commit_id":"e6bc8d44506ca39ecac9b30ef793738ee80cffba"},{"author":{"_account_id":7847,"name":"Alistair Coles","email":"alistairncoles@gmail.com","username":"acoles"},"change_message_id":"821804611cd9479623f9282762199637bef9068d","unresolved":true,"context_lines":[{"line_number":11625,"context_line":"            test_status_map((201, 500, 500), 503)"},{"line_number":11626,"context_line":"            test_status_map((204, 500, 404), 503)"},{"line_number":11627,"context_line":""},{"line_number":11628,"context_line":"    def test_PUT_allow_account_management_false(self):"},{"line_number":11629,"context_line":"        with save_globals():"},{"line_number":11630,"context_line":"            controller \u003d proxy_server.AccountController(self.app, \u0027account\u0027)"},{"line_number":11631,"context_line":"            self.assertFalse(self.app.allow_account_management)"}],"source_content_type":"text/x-python","patch_set":3,"id":"0dc67791_421aff7d","line":11628,"updated":"2026-01-09 13:08:14.000000000","message":"move this to separate test because no backend requests are made so we cannot assert backend timestamp headers","commit_id":"e6bc8d44506ca39ecac9b30ef793738ee80cffba"},{"author":{"_account_id":7847,"name":"Alistair Coles","email":"alistairncoles@gmail.com","username":"acoles"},"change_message_id":"821804611cd9479623f9282762199637bef9068d","unresolved":true,"context_lines":[{"line_number":11848,"context_line":"            test_status_map((201, 500, 500), 503)"},{"line_number":11849,"context_line":"            test_status_map((204, 500, 404), 503)"},{"line_number":11850,"context_line":""},{"line_number":11851,"context_line":"    def test_DELETE_allow_account_management_false(self):"},{"line_number":11852,"context_line":"        with save_globals():"},{"line_number":11853,"context_line":"            controller \u003d proxy_server.AccountController(self.app, \u0027account\u0027)"},{"line_number":11854,"context_line":"            self.assertFalse(self.app.allow_account_management)"}],"source_content_type":"text/x-python","patch_set":3,"id":"52a88c3a_6a51abc3","line":11851,"updated":"2026-01-09 13:08:14.000000000","message":"move this to separate test because no backend requests are made so we cannot assert backend timestamp headers","commit_id":"e6bc8d44506ca39ecac9b30ef793738ee80cffba"}]}
