)]}'
{"/COMMIT_MSG":[{"author":{"_account_id":9531,"name":"liuyulong","display_name":"LIU Yulong","email":"i@liuyulong.me","username":"LIU-Yulong"},"change_message_id":"9de3822be9c904974942511e25e0c8eb1f93bd7a","unresolved":false,"context_lines":[{"line_number":15,"context_line":"when the router has been concurrently deleted). This patch puts this"},{"line_number":16,"context_line":"check back in."},{"line_number":17,"context_line":""},{"line_number":18,"context_line":"Closes-Bug: #1607381"},{"line_number":19,"context_line":"Change-Id: I047e53ea9b3e20a21051f29d0a44624e2a31c83c"}],"source_content_type":"text/x-gerrit-commit-message","patch_set":1,"id":"9a89bdaa_6fc7a612","line":18,"updated":"2016-09-05 14:49:53.000000000","message":"Should this fire a new bug? Or add the related old bug ?","commit_id":"d690f3fe73f5388ef54153cc6167a0ee948bb59e"},{"author":{"_account_id":12444,"name":"John Schwarz","email":"jschwarz@redhat.com","username":"jschwarz"},"change_message_id":"502b944bc1a544469882586f74a24729078e7c2b","unresolved":false,"context_lines":[{"line_number":15,"context_line":"when the router has been concurrently deleted). This patch puts this"},{"line_number":16,"context_line":"check back in."},{"line_number":17,"context_line":""},{"line_number":18,"context_line":"Closes-Bug: #1607381"},{"line_number":19,"context_line":"Change-Id: I047e53ea9b3e20a21051f29d0a44624e2a31c83c"}],"source_content_type":"text/x-gerrit-commit-message","patch_set":1,"id":"9a89bdaa_8fc14ae7","line":18,"in_reply_to":"9a89bdaa_6fc7a612","updated":"2016-09-05 14:52:51.000000000","message":"This patch claims to fix the problem that 1607381 reports, so it should close it as well. No need for another bug.","commit_id":"d690f3fe73f5388ef54153cc6167a0ee948bb59e"}],"neutron/db/l3_hamode_db.py":[{"author":{"_account_id":9531,"name":"liuyulong","display_name":"LIU Yulong","email":"i@liuyulong.me","username":"LIU-Yulong"},"change_message_id":"9de3822be9c904974942511e25e0c8eb1f93bd7a","unresolved":false,"context_lines":[{"line_number":715,"context_line":"            if interface:"},{"line_number":716,"context_line":"                self._populate_mtu_and_subnets_for_ports(context, [interface])"},{"line_number":717,"context_line":""},{"line_number":718,"context_line":"        return [r for r in list(routers_dict.values())"},{"line_number":719,"context_line":"                if not r.get(\u0027ha\u0027) or r.get(constants.HA_INTERFACE_KEY)]"},{"line_number":720,"context_line":""},{"line_number":721,"context_line":"    @log_helpers.log_method_call"},{"line_number":722,"context_line":"    def get_ha_sync_data_for_host(self, context, host, agent,"}],"source_content_type":"text/x-python","patch_set":1,"id":"9a89bdaa_cf46f222","line":719,"range":{"start_line":718,"start_character":8,"end_line":719,"end_character":72},"updated":"2016-09-05 14:49:53.000000000","message":"Please make sure that all kinds of router,\nLegacy, HA, DVR, DVR + snat HA cloud running properly.\n\n\nNo stale processes, resources, etc leave in l3 agent side.","commit_id":"d690f3fe73f5388ef54153cc6167a0ee948bb59e"},{"author":{"_account_id":12444,"name":"John Schwarz","email":"jschwarz@redhat.com","username":"jschwarz"},"change_message_id":"502b944bc1a544469882586f74a24729078e7c2b","unresolved":false,"context_lines":[{"line_number":715,"context_line":"            if interface:"},{"line_number":716,"context_line":"                self._populate_mtu_and_subnets_for_ports(context, [interface])"},{"line_number":717,"context_line":""},{"line_number":718,"context_line":"        return [r for r in list(routers_dict.values())"},{"line_number":719,"context_line":"                if not r.get(\u0027ha\u0027) or r.get(constants.HA_INTERFACE_KEY)]"},{"line_number":720,"context_line":""},{"line_number":721,"context_line":"    @log_helpers.log_method_call"},{"line_number":722,"context_line":"    def get_ha_sync_data_for_host(self, context, host, agent,"}],"source_content_type":"text/x-python","patch_set":1,"id":"9a89bdaa_4fa82220","line":719,"range":{"start_line":718,"start_character":8,"end_line":719,"end_character":72},"in_reply_to":"9a89bdaa_cf46f222","updated":"2016-09-05 14:52:51.000000000","message":"The only case that isn\u0027t working here is the DVR case for agents whose mode is \u0027dvr\u0027 (and not \u0027dvr_snat\u0027). I\u0027m working on this now.\n\nAs long as this doesn\u0027t trigger the endless loop on the agent\u0027s side, I\u0027m happy.","commit_id":"d690f3fe73f5388ef54153cc6167a0ee948bb59e"},{"author":{"_account_id":9531,"name":"liuyulong","display_name":"LIU Yulong","email":"i@liuyulong.me","username":"LIU-Yulong"},"change_message_id":"2a96d44d949ea71a08a5905e4e2a94a481e84549","unresolved":false,"context_lines":[{"line_number":719,"context_line":"        # mode (as opposed to \u0027dvr_snat\u0027), then we want to always return it"},{"line_number":720,"context_line":"        # even though it\u0027s missing the \u0027_ha_interface\u0027 key."},{"line_number":721,"context_line":"        return [r for r in list(routers_dict.values())"},{"line_number":722,"context_line":"                if (agent_mode \u003d\u003d constants.L3_AGENT_MODE_DVR or"},{"line_number":723,"context_line":"                    not r.get(\u0027ha\u0027) or r.get(constants.HA_INTERFACE_KEY))]"},{"line_number":724,"context_line":""},{"line_number":725,"context_line":"    @log_helpers.log_method_call"}],"source_content_type":"text/x-python","patch_set":3,"id":"9a89bdaa_c07877f5","line":722,"range":{"start_line":722,"start_character":20,"end_line":722,"end_character":61},"updated":"2016-09-06 02:04:24.000000000","message":"Whoopee, there are some use case that compute host also run the dvr_snat l3 agent. You may need dig this more deeply. : )","commit_id":"ca0d26700f4cc6eba6d8d1eea0aab38d4d953536"},{"author":{"_account_id":12444,"name":"John Schwarz","email":"jschwarz@redhat.com","username":"jschwarz"},"change_message_id":"2ca00588605dd2e5113551e83c055a50a56f61ea","unresolved":false,"context_lines":[{"line_number":719,"context_line":"        # mode (as opposed to \u0027dvr_snat\u0027), then we want to always return it"},{"line_number":720,"context_line":"        # even though it\u0027s missing the \u0027_ha_interface\u0027 key."},{"line_number":721,"context_line":"        return [r for r in list(routers_dict.values())"},{"line_number":722,"context_line":"                if (agent_mode \u003d\u003d constants.L3_AGENT_MODE_DVR or"},{"line_number":723,"context_line":"                    not r.get(\u0027ha\u0027) or r.get(constants.HA_INTERFACE_KEY))]"},{"line_number":724,"context_line":""},{"line_number":725,"context_line":"    @log_helpers.log_method_call"}],"source_content_type":"text/x-python","patch_set":3,"id":"9a89bdaa_593ffed5","line":722,"range":{"start_line":722,"start_character":20,"end_line":722,"end_character":61},"in_reply_to":"9a89bdaa_c07877f5","updated":"2016-09-06 05:39:42.000000000","message":"So if a (compute) host is running dvr_snat, there are 2 possibilities:\n\n1. either it\u0027s not a DVR+HA router (making this a simple DVR router), and then line 723 will match the \"not r.get(\u0027ha\u0027) and the router won\u0027t get filtered out.\n2. or it\u0027s a DVR+HA (making this an HA router), in which case it should only be filtered out if the _ha_interface key is not present (which is what the last predicate of the for loop does).\n\n:)","commit_id":"ca0d26700f4cc6eba6d8d1eea0aab38d4d953536"},{"author":{"_account_id":9531,"name":"liuyulong","display_name":"LIU Yulong","email":"i@liuyulong.me","username":"LIU-Yulong"},"change_message_id":"2a96d44d949ea71a08a5905e4e2a94a481e84549","unresolved":false,"context_lines":[{"line_number":720,"context_line":"        # even though it\u0027s missing the \u0027_ha_interface\u0027 key."},{"line_number":721,"context_line":"        return [r for r in list(routers_dict.values())"},{"line_number":722,"context_line":"                if (agent_mode \u003d\u003d constants.L3_AGENT_MODE_DVR or"},{"line_number":723,"context_line":"                    not r.get(\u0027ha\u0027) or r.get(constants.HA_INTERFACE_KEY))]"},{"line_number":724,"context_line":""},{"line_number":725,"context_line":"    @log_helpers.log_method_call"},{"line_number":726,"context_line":"    def get_ha_sync_data_for_host(self, context, host, agent,"}],"source_content_type":"text/x-python","patch_set":3,"id":"9a89bdaa_2064c347","line":723,"updated":"2016-09-06 02:04:24.000000000","message":"Adding a new function seems more reasonable.","commit_id":"ca0d26700f4cc6eba6d8d1eea0aab38d4d953536"},{"author":{"_account_id":9531,"name":"liuyulong","display_name":"LIU Yulong","email":"i@liuyulong.me","username":"LIU-Yulong"},"change_message_id":"4116cefd583eb3a0a16805d2668d91ae20206021","unresolved":false,"context_lines":[{"line_number":720,"context_line":"        # even though it\u0027s missing the \u0027_ha_interface\u0027 key."},{"line_number":721,"context_line":"        return [r for r in list(routers_dict.values())"},{"line_number":722,"context_line":"                if (agent_mode \u003d\u003d constants.L3_AGENT_MODE_DVR or"},{"line_number":723,"context_line":"                    not r.get(\u0027ha\u0027) or r.get(constants.HA_INTERFACE_KEY))]"},{"line_number":724,"context_line":""},{"line_number":725,"context_line":"    @log_helpers.log_method_call"},{"line_number":726,"context_line":"    def get_ha_sync_data_for_host(self, context, host, agent,"}],"source_content_type":"text/x-python","patch_set":3,"id":"9a89bdaa_2f7d8ce7","line":723,"in_reply_to":"9a89bdaa_1400dd00","updated":"2016-09-06 06:26:32.000000000","message":"It\u0027s up to you.","commit_id":"ca0d26700f4cc6eba6d8d1eea0aab38d4d953536"},{"author":{"_account_id":12444,"name":"John Schwarz","email":"jschwarz@redhat.com","username":"jschwarz"},"change_message_id":"2ca00588605dd2e5113551e83c055a50a56f61ea","unresolved":false,"context_lines":[{"line_number":720,"context_line":"        # even though it\u0027s missing the \u0027_ha_interface\u0027 key."},{"line_number":721,"context_line":"        return [r for r in list(routers_dict.values())"},{"line_number":722,"context_line":"                if (agent_mode \u003d\u003d constants.L3_AGENT_MODE_DVR or"},{"line_number":723,"context_line":"                    not r.get(\u0027ha\u0027) or r.get(constants.HA_INTERFACE_KEY))]"},{"line_number":724,"context_line":""},{"line_number":725,"context_line":"    @log_helpers.log_method_call"},{"line_number":726,"context_line":"    def get_ha_sync_data_for_host(self, context, host, agent,"}],"source_content_type":"text/x-python","patch_set":3,"id":"9a89bdaa_1400dd00","line":723,"in_reply_to":"9a89bdaa_2064c347","updated":"2016-09-06 05:39:42.000000000","message":"I disagree. The original code didn\u0027t have a function here and all I did was add a new predicate. Adding another function \u003d adding more lines of code which may fail \u003d adding more unit tests \u003d adding more code to maintain \u003d bad.\n\n\"Less is more\" :)","commit_id":"ca0d26700f4cc6eba6d8d1eea0aab38d4d953536"},{"author":{"_account_id":7448,"name":"Carl Baldwin","email":"carl@ecbaldwin.net","username":"carl-baldwin"},"change_message_id":"b2bd644c68af28017020a645386d0558653eb282","unresolved":false,"context_lines":[{"line_number":718,"context_line":"        # If this is a DVR+HA router, but the agent is question is in \u0027dvr\u0027"},{"line_number":719,"context_line":"        # mode (as opposed to \u0027dvr_snat\u0027), then we want to always return it"},{"line_number":720,"context_line":"        # even though it\u0027s missing the \u0027_ha_interface\u0027 key."},{"line_number":721,"context_line":"        return [r for r in list(routers_dict.values())"},{"line_number":722,"context_line":"                if (agent_mode \u003d\u003d constants.L3_AGENT_MODE_DVR or"},{"line_number":723,"context_line":"                    not r.get(\u0027ha\u0027) or r.get(constants.HA_INTERFACE_KEY))]"},{"line_number":724,"context_line":""}],"source_content_type":"text/x-python","patch_set":5,"id":"9a89bdaa_0ec08e29","line":721,"range":{"start_line":721,"start_character":27,"end_line":721,"end_character":32},"updated":"2016-09-07 04:17:23.000000000","message":"Why do you need list(...)? It seems a bit wasteful and extra verbose.","commit_id":"29cec0345617627b64a73b9de35c46bccdc4ffa3"}],"neutron/tests/unit/db/test_l3_hamode_db.py":[{"author":{"_account_id":12444,"name":"John Schwarz","email":"jschwarz@redhat.com","username":"jschwarz"},"change_message_id":"38abb7d25fa12eb6caf84153ab3d9de3925952f1","unresolved":false,"context_lines":[{"line_number":806,"context_line":"        self.assertEqual(2, len(bindings))"},{"line_number":807,"context_line":""},{"line_number":808,"context_line":"        fake_binding \u003d mock.Mock()"},{"line_number":809,"context_line":"        fake_binding.router_id \u003d router2[\u0027id\u0027]"},{"line_number":810,"context_line":"        fake_binding.port \u003d None"},{"line_number":811,"context_line":"        with mock.patch.object("},{"line_number":812,"context_line":"                self.plugin, \"get_ha_router_port_bindings\","}],"source_content_type":"text/x-python","patch_set":1,"id":"9a89bdaa_36633bde","side":"PARENT","line":809,"range":{"start_line":809,"start_character":33,"end_line":809,"end_character":46},"updated":"2016-09-05 13:42:29.000000000","message":"This was a weird one and took a while to get - router2[\u0027id\u0027] might non-deterministiclly equal bindings[0], causing this test to non-deterministiclly fail. Yippee!","commit_id":"717b57dc8d3763725336bdf41852665aeedb7f35"},{"author":{"_account_id":9531,"name":"liuyulong","display_name":"LIU Yulong","email":"i@liuyulong.me","username":"LIU-Yulong"},"change_message_id":"9de3822be9c904974942511e25e0c8eb1f93bd7a","unresolved":false,"context_lines":[{"line_number":806,"context_line":"        self.assertEqual(2, len(bindings))"},{"line_number":807,"context_line":""},{"line_number":808,"context_line":"        fake_binding \u003d mock.Mock()"},{"line_number":809,"context_line":"        fake_binding.router_id \u003d router2[\u0027id\u0027]"},{"line_number":810,"context_line":"        fake_binding.port \u003d None"},{"line_number":811,"context_line":"        with mock.patch.object("},{"line_number":812,"context_line":"                self.plugin, \"get_ha_router_port_bindings\","}],"source_content_type":"text/x-python","patch_set":1,"id":"9a89bdaa_6c7974fc","side":"PARENT","line":809,"range":{"start_line":809,"start_character":33,"end_line":809,"end_character":46},"in_reply_to":"9a89bdaa_36633bde","updated":"2016-09-05 14:49:53.000000000","message":"This test_sync_ha_router_info_ha_interface_port_concurrently_deleted will fail non-deterministiclly?","commit_id":"717b57dc8d3763725336bdf41852665aeedb7f35"},{"author":{"_account_id":12444,"name":"John Schwarz","email":"jschwarz@redhat.com","username":"jschwarz"},"change_message_id":"502b944bc1a544469882586f74a24729078e7c2b","unresolved":false,"context_lines":[{"line_number":806,"context_line":"        self.assertEqual(2, len(bindings))"},{"line_number":807,"context_line":""},{"line_number":808,"context_line":"        fake_binding \u003d mock.Mock()"},{"line_number":809,"context_line":"        fake_binding.router_id \u003d router2[\u0027id\u0027]"},{"line_number":810,"context_line":"        fake_binding.port \u003d None"},{"line_number":811,"context_line":"        with mock.patch.object("},{"line_number":812,"context_line":"                self.plugin, \"get_ha_router_port_bindings\","}],"source_content_type":"text/x-python","patch_set":1,"id":"9a89bdaa_6f4a4685","side":"PARENT","line":809,"range":{"start_line":809,"start_character":33,"end_line":809,"end_character":46},"in_reply_to":"9a89bdaa_6c7974fc","updated":"2016-09-05 14:52:51.000000000","message":"With my implementation, yes.","commit_id":"717b57dc8d3763725336bdf41852665aeedb7f35"},{"author":{"_account_id":7787,"name":"Kevin Benton","email":"kevin@benton.pub","username":"blak111"},"change_message_id":"09bae97a104087c704c7c8820334e0cf759bc265","unresolved":false,"context_lines":[{"line_number":826,"context_line":"            self.assertEqual(0, len(routers))"},{"line_number":827,"context_line":""},{"line_number":828,"context_line":"    def test_sync_ha_router_info_router_concurrently_deleted_agent_dvr(self):"},{"line_number":829,"context_line":"        router \u003d self._create_router()"},{"line_number":830,"context_line":""},{"line_number":831,"context_line":"        orig_func \u003d self.plugin._process_sync_ha_data"},{"line_number":832,"context_line":"        def process_sync_ha_data(context, routers, host, agent_mode):"}],"source_content_type":"text/x-python","patch_set":2,"id":"9a89bdaa_3a45d516","line":829,"updated":"2016-09-05 16:39:18.000000000","message":"this function is a pep8 disaster!","commit_id":"1e4cc8ad4929df5b93732aee370d59ecc10a0dd4"},{"author":{"_account_id":12444,"name":"John Schwarz","email":"jschwarz@redhat.com","username":"jschwarz"},"change_message_id":"6644b3fc5f010338c6bcd44e158ac0c709357e1f","unresolved":false,"context_lines":[{"line_number":826,"context_line":"            self.assertEqual(0, len(routers))"},{"line_number":827,"context_line":""},{"line_number":828,"context_line":"    def test_sync_ha_router_info_router_concurrently_deleted_agent_dvr(self):"},{"line_number":829,"context_line":"        router \u003d self._create_router()"},{"line_number":830,"context_line":""},{"line_number":831,"context_line":"        orig_func \u003d self.plugin._process_sync_ha_data"},{"line_number":832,"context_line":"        def process_sync_ha_data(context, routers, host, agent_mode):"}],"source_content_type":"text/x-python","patch_set":2,"id":"9a89bdaa_e62cb84c","line":829,"in_reply_to":"9a89bdaa_3a45d516","updated":"2016-09-05 20:19:08.000000000","message":"lol oops :\u003c","commit_id":"1e4cc8ad4929df5b93732aee370d59ecc10a0dd4"},{"author":{"_account_id":9531,"name":"liuyulong","display_name":"LIU Yulong","email":"i@liuyulong.me","username":"LIU-Yulong"},"change_message_id":"2a96d44d949ea71a08a5905e4e2a94a481e84549","unresolved":false,"context_lines":[{"line_number":806,"context_line":"        self.assertEqual(2, len(bindings))"},{"line_number":807,"context_line":""},{"line_number":808,"context_line":"        fake_binding \u003d mock.Mock()"},{"line_number":809,"context_line":"        fake_binding.router_id \u003d bindings[1].router_id"},{"line_number":810,"context_line":"        fake_binding.port \u003d None"},{"line_number":811,"context_line":"        with mock.patch.object("},{"line_number":812,"context_line":"                self.plugin, \"get_ha_router_port_bindings\","}],"source_content_type":"text/x-python","patch_set":3,"id":"9a89bdaa_00bdff67","line":809,"range":{"start_line":809,"start_character":8,"end_line":809,"end_character":54},"updated":"2016-09-06 02:04:24.000000000","message":"This change reduced the test case readability. Both line 796, 804 are using such `router2[\u0027id\u0027]`, why could not here? The bindings are treated as unreliable in this test case, aka router2\u0027s binding is used to act as race condition effect. And also a unrelated change. You may need to find out why your change will break this test non-deterministiclly.","commit_id":"ca0d26700f4cc6eba6d8d1eea0aab38d4d953536"},{"author":{"_account_id":12444,"name":"John Schwarz","email":"jschwarz@redhat.com","username":"jschwarz"},"change_message_id":"2ca00588605dd2e5113551e83c055a50a56f61ea","unresolved":false,"context_lines":[{"line_number":806,"context_line":"        self.assertEqual(2, len(bindings))"},{"line_number":807,"context_line":""},{"line_number":808,"context_line":"        fake_binding \u003d mock.Mock()"},{"line_number":809,"context_line":"        fake_binding.router_id \u003d bindings[1].router_id"},{"line_number":810,"context_line":"        fake_binding.port \u003d None"},{"line_number":811,"context_line":"        with mock.patch.object("},{"line_number":812,"context_line":"                self.plugin, \"get_ha_router_port_bindings\","}],"source_content_type":"text/x-python","patch_set":3,"id":"9a89bdaa_94dead6b","line":809,"range":{"start_line":809,"start_character":8,"end_line":809,"end_character":54},"in_reply_to":"9a89bdaa_00bdff67","updated":"2016-09-06 05:39:42.000000000","message":"I thought I\u0027d spare you the pain, but oh well ;-)\n\nLine 796 is using \"router2[\u0027id\u0027]\" because it must - otherwise get_ha_router_port_binding() won\u0027t return the bindings for that router (and we can\u0027t get its router id any other way yet - in line 803 we got the binding and it contains the router_id so we can use it).\n\nThe reason for the race condition (which isn\u0027t a race condition per-se - a race condition requires 2 concurrent threads, whereas this unit test in single threaded - it\u0027s simply a non-deterministic error) is that \u0027bindings\u0027 (from line 803) is unordered, and in 50% of the time bindings[1].router_id may equal router1[\u0027id\u0027] and in the other 50% of the time it may equal router2[\u0027id\u0027].\n\nIn case it did equal router2[\u0027id\u0027], this means that the call in line 814, that will eventually trigger get_ha_router_port_bindings, will return the same router twice: router2. Lets examine the flow of the code:\n\nThe first return value is a good and valid binding (bindings[0], which we got from line 803). This will successfully go through the loop and specifically [1] to add the complete HA information about that router. Alas, the second return value lacks the \u0027binding.port\u0027 (it\u0027s mocked right here in line 810 to have the value of None), and then [2] will remove the single entry from the return value. The effect will be that the call in line 814 will return an empty list, failing the test.\n\nWhy didn\u0027t this pop up before this patch? Simple - in both cases (where bindings[0].router_id \u003d\u003d router2[\u0027id\u0027] and where it doesn\u0027t) a single binding is returned, but when they are equal the router that is returned doesn\u0027t have the \u0027_ha_interface\u0027 key (because the bindings for router1[\u0027id\u0027] never got returned in get_ha_router_port_bindings, which mean [2] was never invoked for that router), and this patch specifically filters that binding out because it should *never* be returned to the agent. In other words, this test is flawed in that it didn\u0027t check that all the routers returned from \u0027get_ha_sync_data_for_host\u0027 have the \u0027_ha_interface\u0027 key.\n\nIn that sense, this is a completely relevant change - if this patch breaks this test, it should also fix it. Done. :)\n\nIn second thought, this test could also use a new check to make sure that the router that was returned has the \u0027_ha_interface\u0027 key. Will publish a new commit for this. Thanks for bringing this to my attention.\n\n[1]: https://review.openstack.org/#/c/365653/3/neutron/db/l3_hamode_db.py@710\n[2]: https://review.openstack.org/#/c/365653/3/neutron/db/l3_hamode_db.py@705","commit_id":"ca0d26700f4cc6eba6d8d1eea0aab38d4d953536"},{"author":{"_account_id":9531,"name":"liuyulong","display_name":"LIU Yulong","email":"i@liuyulong.me","username":"LIU-Yulong"},"change_message_id":"4116cefd583eb3a0a16805d2668d91ae20206021","unresolved":false,"context_lines":[{"line_number":806,"context_line":"        self.assertEqual(2, len(bindings))"},{"line_number":807,"context_line":""},{"line_number":808,"context_line":"        fake_binding \u003d mock.Mock()"},{"line_number":809,"context_line":"        fake_binding.router_id \u003d bindings[1].router_id"},{"line_number":810,"context_line":"        fake_binding.port \u003d None"},{"line_number":811,"context_line":"        with mock.patch.object("},{"line_number":812,"context_line":"                self.plugin, \"get_ha_router_port_bindings\","}],"source_content_type":"text/x-python","patch_set":3,"id":"9a89bdaa_af3b5c37","line":809,"range":{"start_line":809,"start_character":8,"end_line":809,"end_character":54},"in_reply_to":"9a89bdaa_94dead6b","updated":"2016-09-06 06:26:32.000000000","message":"You tell me a really long story.\nI\u0027ve figure out why: get_ha_router_port_bindings may return a list not in a corresponding zip.\nWhat we want is:\nInput: [router_id_1, router_id_2]\noutput: [binding_id_1, binding_id_2]\n\nBut it may return:\nInput: [router_id_1, router_id_2]\noutput: [binding_id_2, binding_id_1]\n\nThe db may sort bindings by using the router_id.","commit_id":"ca0d26700f4cc6eba6d8d1eea0aab38d4d953536"},{"author":{"_account_id":12444,"name":"John Schwarz","email":"jschwarz@redhat.com","username":"jschwarz"},"change_message_id":"c8a803556a61f6bbdea2ac10c9db219e0802cde6","unresolved":false,"context_lines":[{"line_number":806,"context_line":"        self.assertEqual(2, len(bindings))"},{"line_number":807,"context_line":""},{"line_number":808,"context_line":"        fake_binding \u003d mock.Mock()"},{"line_number":809,"context_line":"        fake_binding.router_id \u003d bindings[1].router_id"},{"line_number":810,"context_line":"        fake_binding.port \u003d None"},{"line_number":811,"context_line":"        with mock.patch.object("},{"line_number":812,"context_line":"                self.plugin, \"get_ha_router_port_bindings\","}],"source_content_type":"text/x-python","patch_set":3,"id":"9a89bdaa_eaa9d27c","line":809,"range":{"start_line":809,"start_character":8,"end_line":809,"end_character":54},"in_reply_to":"9a89bdaa_af3b5c37","updated":"2016-09-06 06:50:32.000000000","message":"Exactly :)","commit_id":"ca0d26700f4cc6eba6d8d1eea0aab38d4d953536"},{"author":{"_account_id":9531,"name":"liuyulong","display_name":"LIU Yulong","email":"i@liuyulong.me","username":"LIU-Yulong"},"change_message_id":"4ff929942daafe83fbf3b9617d5515608a79bf23","unresolved":false,"context_lines":[{"line_number":814,"context_line":"            routers \u003d self.plugin.get_ha_sync_data_for_host("},{"line_number":815,"context_line":"                self.admin_ctx, self.agent1[\u0027host\u0027], self.agent1)"},{"line_number":816,"context_line":"            self.assertEqual(1, len(routers))"},{"line_number":817,"context_line":"            self.assertIsNotNone(routers[0].get(constants.HA_INTERFACE_KEY))"},{"line_number":818,"context_line":""},{"line_number":819,"context_line":"    def test_sync_ha_router_info_router_concurrently_deleted(self):"},{"line_number":820,"context_line":"        self._create_router()"}],"source_content_type":"text/x-python","patch_set":4,"id":"9a89bdaa_af0fdc2c","line":817,"range":{"start_line":817,"start_character":11,"end_line":817,"end_character":76},"updated":"2016-09-06 06:21:55.000000000","message":"This line is really a  relevant change. Well done.","commit_id":"7b2d2fd24df8fe34b538ad9e5a9ddfa08a81bd47"},{"author":{"_account_id":12444,"name":"John Schwarz","email":"jschwarz@redhat.com","username":"jschwarz"},"change_message_id":"2f8737ed5c4911269f811083738cbfa8ff2af882","unresolved":false,"context_lines":[{"line_number":814,"context_line":"            routers \u003d self.plugin.get_ha_sync_data_for_host("},{"line_number":815,"context_line":"                self.admin_ctx, self.agent1[\u0027host\u0027], self.agent1)"},{"line_number":816,"context_line":"            self.assertEqual(1, len(routers))"},{"line_number":817,"context_line":"            self.assertIsNotNone(routers[0].get(constants.HA_INTERFACE_KEY))"},{"line_number":818,"context_line":""},{"line_number":819,"context_line":"    def test_sync_ha_router_info_router_concurrently_deleted(self):"},{"line_number":820,"context_line":"        self._create_router()"}],"source_content_type":"text/x-python","patch_set":4,"id":"9a89bdaa_ea72b248","line":817,"range":{"start_line":817,"start_character":11,"end_line":817,"end_character":76},"in_reply_to":"9a89bdaa_af0fdc2c","updated":"2016-09-06 06:49:52.000000000","message":"Thank you :)","commit_id":"7b2d2fd24df8fe34b538ad9e5a9ddfa08a81bd47"},{"author":{"_account_id":9531,"name":"liuyulong","display_name":"LIU Yulong","email":"i@liuyulong.me","username":"LIU-Yulong"},"change_message_id":"4ff929942daafe83fbf3b9617d5515608a79bf23","unresolved":false,"context_lines":[{"line_number":839,"context_line":"            routers \u003d self.plugin.get_ha_sync_data_for_host("},{"line_number":840,"context_line":"                self.admin_ctx, self.agent1[\u0027host\u0027], self.agent1)"},{"line_number":841,"context_line":"            self.assertEqual(1, len(routers))"},{"line_number":842,"context_line":"            self.assertIsNone(routers[0].get(constants.HA_INTERFACE_KEY))"},{"line_number":843,"context_line":""},{"line_number":844,"context_line":"    def test_set_router_states_handles_concurrently_deleted_router(self):"},{"line_number":845,"context_line":"        router1 \u003d self._create_router()"}],"source_content_type":"text/x-python","patch_set":4,"id":"9a89bdaa_2fe10cd1","line":842,"range":{"start_line":842,"start_character":12,"end_line":842,"end_character":73},"updated":"2016-09-06 06:21:55.000000000","message":"This line is not passed in my test.","commit_id":"7b2d2fd24df8fe34b538ad9e5a9ddfa08a81bd47"},{"author":{"_account_id":12444,"name":"John Schwarz","email":"jschwarz@redhat.com","username":"jschwarz"},"change_message_id":"2f8737ed5c4911269f811083738cbfa8ff2af882","unresolved":false,"context_lines":[{"line_number":839,"context_line":"            routers \u003d self.plugin.get_ha_sync_data_for_host("},{"line_number":840,"context_line":"                self.admin_ctx, self.agent1[\u0027host\u0027], self.agent1)"},{"line_number":841,"context_line":"            self.assertEqual(1, len(routers))"},{"line_number":842,"context_line":"            self.assertIsNone(routers[0].get(constants.HA_INTERFACE_KEY))"},{"line_number":843,"context_line":""},{"line_number":844,"context_line":"    def test_set_router_states_handles_concurrently_deleted_router(self):"},{"line_number":845,"context_line":"        router1 \u003d self._create_router()"}],"source_content_type":"text/x-python","patch_set":4,"id":"9a89bdaa_2a93ba50","line":842,"range":{"start_line":842,"start_character":12,"end_line":842,"end_character":73},"in_reply_to":"9a89bdaa_2fe10cd1","updated":"2016-09-06 06:49:52.000000000","message":"I\u0027ll re-check this to make sure and will remove it if it doesn\u0027t make sense.","commit_id":"7b2d2fd24df8fe34b538ad9e5a9ddfa08a81bd47"}]}
