)]}'
{"/COMMIT_MSG":[{"author":{"_account_id":8576,"name":"Yair Fried","email":"yfried@redhat.com","username":"yfried"},"change_message_id":"7692d322d04f35050a3af14b5c588f3e4dad294b","unresolved":false,"context_lines":[{"line_number":16,"context_line":""},{"line_number":17,"context_line":"To handle async delete actions a class level list of waits is added"},{"line_number":18,"context_line":"which will be iterated over as the last step of clearing the"},{"line_number":19,"context_line":"addCleanup queue. That way all the delete calls are made up front"},{"line_number":20,"context_line":"and the tests won\u0027t succeed unless the deletes are eventually"},{"line_number":21,"context_line":"successful. This is the same basic approach used in the api tests to"},{"line_number":22,"context_line":"limit cleanup execution time except here it is multi-resource,"}],"source_content_type":"text/x-gerrit-commit-message","patch_set":16,"id":"AAAAUX%2F%2Bw6I%3D","line":19,"updated":"2014-02-19 07:53:53.000000000","message":"IMO you should wait for (at least some of) the async resources during the delete-queue.\nFor example - deleting a server (especially with floating ip) takes some time and will prevent net/subnet deletion.\nplease add this as an option (ie - \"force synchronous cleanup\")\n\nhttps://bugs.launchpad.net/neutron/+bug/1269407","commit_id":"e8fa4a7398596c33c852baedc8c1c4b71a932ec7"}],"tempest/scenario/manager.py":[{"author":{"_account_id":7,"name":"Jay Pipes","email":"jaypipes@gmail.com","username":"jaypipes"},"change_message_id":"25585e39d87a469a0ad80548fb2cd15bcbd2b2ea","unresolved":false,"context_lines":[{"line_number":271,"context_line":"            \u0027error_status\u0027: error_status,"},{"line_number":272,"context_line":"            \u0027exc_type\u0027: exc_type,"},{"line_number":273,"context_line":"        }"},{"line_number":274,"context_line":"        self.cleanup_waits.append(wait_dict)"},{"line_number":275,"context_line":""},{"line_number":276,"context_line":"    @classmethod"},{"line_number":277,"context_line":"    def _get_credentials(cls, get_creds, prefix):"}],"source_content_type":"text/x-python","patch_set":10,"id":"AAAAUH%2F%2Fw0c%3D","line":274,"updated":"2014-01-08 18:54:13.000000000","message":"A suggestion here might be to have a single add_cleanup_with_wait() function, instead of relying on the caller to call both addCleanup() and then _append_wait()?\n\nMight look something like this?\n\n def add_cleanup_with_wait(self, resource_id, delete_callable, wait_resource, error_status\u003d\u0027ERROR\u0027, exc_type\u003dnova_exceptions.NotFound):\n   self.addCleanup(delete_callable, resource_id)\n   wait_dict \u003d { ... }\n   self.cleanup_waits.append(wait_dict) \n\nAnd then called like so:\n\n self.add_cleanup_with_wait(server_id, server.delete, self.compute_client.servers)","commit_id":"781b4790720fd3b18e0613b3326bf15a2b253503"},{"author":{"_account_id":5196,"name":"Matthew Treinish","email":"mtreinish@kortar.org","username":"treinish"},"change_message_id":"1bc2dd89e5af01e6f5290891cb18a4c5f1eae1ab","unresolved":false,"context_lines":[{"line_number":271,"context_line":"            \u0027error_status\u0027: error_status,"},{"line_number":272,"context_line":"            \u0027exc_type\u0027: exc_type,"},{"line_number":273,"context_line":"        }"},{"line_number":274,"context_line":"        self.cleanup_waits.append(wait_dict)"},{"line_number":275,"context_line":""},{"line_number":276,"context_line":"    @classmethod"},{"line_number":277,"context_line":"    def _get_credentials(cls, get_creds, prefix):"}],"source_content_type":"text/x-python","patch_set":10,"id":"AAAAUH%2F%2Fwqw%3D","line":274,"in_reply_to":"AAAAUH%2F%2Fw0c%3D","updated":"2014-01-08 19:21:18.000000000","message":"This is a good idea, thanks for the suggestion.","commit_id":"781b4790720fd3b18e0613b3326bf15a2b253503"},{"author":{"_account_id":7,"name":"Jay Pipes","email":"jaypipes@gmail.com","username":"jaypipes"},"change_message_id":"13b1a02b624dda6d746fa6d29275bbac1077372d","unresolved":false,"context_lines":[{"line_number":263,"context_line":"            self.delete_timeout(wait[\u0027resource_class\u0027], wait[\u0027id\u0027],"},{"line_number":264,"context_line":"                                wait[\u0027error_status\u0027], wait[\u0027exc_type\u0027])"},{"line_number":265,"context_line":""},{"line_number":266,"context_line":"    def addCleanup_with_wait(self, resource_class, resource_id, delete_call,"},{"line_number":267,"context_line":"                             error_status\u003d\u0027ERROR\u0027,"},{"line_number":268,"context_line":"                             exc_type\u003dnova_exceptions.NotFound):"},{"line_number":269,"context_line":"        self.addCleanup(delete_call, resource_id)"}],"source_content_type":"text/x-python","patch_set":12,"id":"AAAAUH%2F%2FcdA%3D","line":266,"updated":"2014-01-13 20:22:22.000000000","message":"eww. CamelCase_with_underscore :)","commit_id":"6e88bf02dfb1a85df4a3f7fcdf6eae36e7193523"},{"author":{"_account_id":8576,"name":"Yair Fried","email":"yfried@redhat.com","username":"yfried"},"change_message_id":"f655c5177c36f3778830357e5b7f3855ded1865c","unresolved":false,"context_lines":[{"line_number":250,"context_line":"        cls.volume_client \u003d cls.manager.volume_client"},{"line_number":251,"context_line":"        cls.object_storage_client \u003d cls.manager.object_storage_client"},{"line_number":252,"context_line":"        cls.orchestration_client \u003d cls.manager.orchestration_client"},{"line_number":253,"context_line":"        cls.cleanup_waits \u003d []"},{"line_number":254,"context_line":""},{"line_number":255,"context_line":"    def setUp(self):"},{"line_number":256,"context_line":"        super(OfficialClientTest, self).setUp()"}],"source_content_type":"text/x-python","patch_set":16,"id":"1ae5cdf2_3d88b9c5","line":253,"range":{"start_line":253,"start_character":28,"end_line":253,"end_character":30},"updated":"2014-06-18 14:22:20.000000000","message":"Since this is cleaned at the end of each test (and not the class - see setUp() method), This should be initiated in setUp and not setUpClass","commit_id":"e8fa4a7398596c33c852baedc8c1c4b71a932ec7"},{"author":{"_account_id":8576,"name":"Yair Fried","email":"yfried@redhat.com","username":"yfried"},"change_message_id":"7692d322d04f35050a3af14b5c588f3e4dad294b","unresolved":false,"context_lines":[{"line_number":256,"context_line":"        super(OfficialClientTest, self).setUp()"},{"line_number":257,"context_line":"        # NOTE(mtreinish) This is safe to do in setUp instead of setUp class"},{"line_number":258,"context_line":"        # because scenario tests in the same test class should not share"},{"line_number":259,"context_line":"        # resources. If resources were shared between test cases then it"},{"line_number":260,"context_line":"        # should be a single scenario test instead of multiples."},{"line_number":261,"context_line":"        self.addCleanup(self._wait_for_cleanups)"},{"line_number":262,"context_line":""}],"source_content_type":"text/x-python","patch_set":16,"id":"AAAAUX%2F%2Bw90%3D","line":259,"updated":"2014-02-19 07:53:53.000000000","message":"please be consistent with the naming.\neither use \"thing\" or, even better, rename all references from \"thing\" to \"resource\" as it is more descriptive.","commit_id":"e8fa4a7398596c33c852baedc8c1c4b71a932ec7"},{"author":{"_account_id":8576,"name":"Yair Fried","email":"yfried@redhat.com","username":"yfried"},"change_message_id":"f655c5177c36f3778830357e5b7f3855ded1865c","unresolved":false,"context_lines":[{"line_number":256,"context_line":"        super(OfficialClientTest, self).setUp()"},{"line_number":257,"context_line":"        # NOTE(mtreinish) This is safe to do in setUp instead of setUp class"},{"line_number":258,"context_line":"        # because scenario tests in the same test class should not share"},{"line_number":259,"context_line":"        # resources. If resources were shared between test cases then it"},{"line_number":260,"context_line":"        # should be a single scenario test instead of multiples."},{"line_number":261,"context_line":"        self.addCleanup(self._wait_for_cleanups)"},{"line_number":262,"context_line":""}],"source_content_type":"text/x-python","patch_set":16,"id":"1ae5cdf2_457507f9","line":259,"in_reply_to":"AAAAUX%2F%2Bw90%3D","updated":"2014-06-18 14:22:20.000000000","message":"Done","commit_id":"e8fa4a7398596c33c852baedc8c1c4b71a932ec7"},{"author":{"_account_id":8576,"name":"Yair Fried","email":"yfried@redhat.com","username":"yfried"},"change_message_id":"7692d322d04f35050a3af14b5c588f3e4dad294b","unresolved":false,"context_lines":[{"line_number":269,"context_line":"                             error_status\u003d\u0027ERROR\u0027,"},{"line_number":270,"context_line":"                             exc_type\u003dnova_exceptions.NotFound):"},{"line_number":271,"context_line":"        self.addCleanup(delete_call, resource_id)"},{"line_number":272,"context_line":"        wait_dict \u003d {"},{"line_number":273,"context_line":"            \u0027resource_class\u0027: resource_class,"},{"line_number":274,"context_line":"            \u0027id\u0027: resource_id,"},{"line_number":275,"context_line":"            \u0027error_status\u0027: error_status,"}],"source_content_type":"text/x-python","patch_set":16,"id":"AAAAUX%2F%2Bw%2BM%3D","line":272,"updated":"2014-02-19 07:53:53.000000000","message":"why not use the keywords defined in delete_timeout?\nthat way, you don\u0027t need to the dict values one-by-one.","commit_id":"e8fa4a7398596c33c852baedc8c1c4b71a932ec7"},{"author":{"_account_id":8576,"name":"Yair Fried","email":"yfried@redhat.com","username":"yfried"},"change_message_id":"f655c5177c36f3778830357e5b7f3855ded1865c","unresolved":false,"context_lines":[{"line_number":269,"context_line":"                             error_status\u003d\u0027ERROR\u0027,"},{"line_number":270,"context_line":"                             exc_type\u003dnova_exceptions.NotFound):"},{"line_number":271,"context_line":"        self.addCleanup(delete_call, resource_id)"},{"line_number":272,"context_line":"        wait_dict \u003d {"},{"line_number":273,"context_line":"            \u0027resource_class\u0027: resource_class,"},{"line_number":274,"context_line":"            \u0027id\u0027: resource_id,"},{"line_number":275,"context_line":"            \u0027error_status\u0027: error_status,"}],"source_content_type":"text/x-python","patch_set":16,"id":"1ae5cdf2_7cb8b5c7","line":272,"in_reply_to":"AAAAUX%2F%2Bw%2BM%3D","updated":"2014-06-18 14:22:20.000000000","message":"Done","commit_id":"e8fa4a7398596c33c852baedc8c1c4b71a932ec7"},{"author":{"_account_id":4571,"name":"Steve Baker","email":"sbaker@redhat.com","username":"steve-stevebaker"},"change_message_id":"6b963b2d17503e0a078a7a8e8ae4faafa2398043","unresolved":false,"context_lines":[{"line_number":352,"context_line":"                    return True"},{"line_number":353,"context_line":"                raise"},{"line_number":354,"context_line":"            except Exception as e:"},{"line_number":355,"context_line":"                if (e.__class__.__name__ \u003d\u003d \u0027NotFound\u0027 or"},{"line_number":356,"context_line":"                    hasattr(e, \u0027status_code\u0027) and e.status_code \u003d\u003d 404):"},{"line_number":357,"context_line":"                    return True"},{"line_number":358,"context_line":"                raise"}],"source_content_type":"text/x-python","patch_set":16,"id":"1ae5cdf2_61b052de","line":355,"updated":"2014-05-29 21:47:12.000000000","message":"To support heatclient, could this be:\n\n  in (\u0027NotFound\u0027, \u0027HTTPNotFound\u0027)\n\nas per https://review.openstack.org/#/c/95624/1/tempest/scenario/manager.py","commit_id":"e8fa4a7398596c33c852baedc8c1c4b71a932ec7"},{"author":{"_account_id":8576,"name":"Yair Fried","email":"yfried@redhat.com","username":"yfried"},"change_message_id":"f655c5177c36f3778830357e5b7f3855ded1865c","unresolved":false,"context_lines":[{"line_number":352,"context_line":"                    return True"},{"line_number":353,"context_line":"                raise"},{"line_number":354,"context_line":"            except Exception as e:"},{"line_number":355,"context_line":"                if (e.__class__.__name__ \u003d\u003d \u0027NotFound\u0027 or"},{"line_number":356,"context_line":"                    hasattr(e, \u0027status_code\u0027) and e.status_code \u003d\u003d 404):"},{"line_number":357,"context_line":"                    return True"},{"line_number":358,"context_line":"                raise"}],"source_content_type":"text/x-python","patch_set":16,"id":"1ae5cdf2_dc246910","line":355,"in_reply_to":"1ae5cdf2_61b052de","updated":"2014-06-18 14:22:20.000000000","message":"Done","commit_id":"e8fa4a7398596c33c852baedc8c1c4b71a932ec7"},{"author":{"_account_id":5196,"name":"Matthew Treinish","email":"mtreinish@kortar.org","username":"treinish"},"change_message_id":"5fcc659cf04e239d6afa089f4a675ebe09473aa7","unresolved":false,"context_lines":[{"line_number":21,"context_line":"import subprocess"},{"line_number":22,"context_line":"import time"},{"line_number":23,"context_line":""},{"line_number":24,"context_line":"# Default client libs"},{"line_number":25,"context_line":"from cinderclient import exceptions as cinder_exceptions"},{"line_number":26,"context_line":"import glanceclient"},{"line_number":27,"context_line":"from heatclient import exc as heat_exceptions"}],"source_content_type":"text/x-python","patch_set":20,"id":"1ae5cdf2_c36fdc5e","line":24,"updated":"2014-06-18 23:17:52.000000000","message":"You don\u0027t need this comment","commit_id":"b7fc79090eb92b0c58aec30eedd5c769da00a963"},{"author":{"_account_id":8576,"name":"Yair Fried","email":"yfried@redhat.com","username":"yfried"},"change_message_id":"084815ffc9d9ea02f161b048d4d4ea95e89be484","unresolved":false,"context_lines":[{"line_number":21,"context_line":"import subprocess"},{"line_number":22,"context_line":"import time"},{"line_number":23,"context_line":""},{"line_number":24,"context_line":"# Default client libs"},{"line_number":25,"context_line":"from cinderclient import exceptions as cinder_exceptions"},{"line_number":26,"context_line":"import glanceclient"},{"line_number":27,"context_line":"from heatclient import exc as heat_exceptions"}],"source_content_type":"text/x-python","patch_set":20,"id":"1ae5cdf2_51561b5f","line":24,"in_reply_to":"1ae5cdf2_c36fdc5e","updated":"2014-06-19 08:35:24.000000000","message":"Done","commit_id":"b7fc79090eb92b0c58aec30eedd5c769da00a963"},{"author":{"_account_id":5196,"name":"Matthew Treinish","email":"mtreinish@kortar.org","username":"treinish"},"change_message_id":"5fcc659cf04e239d6afa089f4a675ebe09473aa7","unresolved":false,"context_lines":[{"line_number":126,"context_line":"        \"\"\""},{"line_number":127,"context_line":"        @return: True if exception is of NotFound type"},{"line_number":128,"context_line":"        \"\"\""},{"line_number":129,"context_line":"        return (\u0027NotFound\u0027 in exception.__class__.__name__"},{"line_number":130,"context_line":"                or"},{"line_number":131,"context_line":"                hasattr(exception, \u0027status_code\u0027) and"},{"line_number":132,"context_line":"                exception.status_code \u003d\u003d 404)"}],"source_content_type":"text/x-python","patch_set":20,"id":"1ae5cdf2_9f6a7c18","line":129,"updated":"2014-06-18 23:17:52.000000000","message":"This feels like a bad idea, I think just having a list of expected exceptions and checking against that is a better way.","commit_id":"b7fc79090eb92b0c58aec30eedd5c769da00a963"},{"author":{"_account_id":5196,"name":"Matthew Treinish","email":"mtreinish@kortar.org","username":"treinish"},"change_message_id":"25ab100052b2e597107f71c3f31bf33c5e4f51b7","unresolved":false,"context_lines":[{"line_number":126,"context_line":"        \"\"\""},{"line_number":127,"context_line":"        @return: True if exception is of NotFound type"},{"line_number":128,"context_line":"        \"\"\""},{"line_number":129,"context_line":"        return (\u0027NotFound\u0027 in exception.__class__.__name__"},{"line_number":130,"context_line":"                or"},{"line_number":131,"context_line":"                hasattr(exception, \u0027status_code\u0027) and"},{"line_number":132,"context_line":"                exception.status_code \u003d\u003d 404)"}],"source_content_type":"text/x-python","patch_set":20,"id":"1ae5cdf2_fbf8d9c5","line":129,"in_reply_to":"1ae5cdf2_5bcd5a2f","updated":"2014-06-19 13:46:40.000000000","message":"I was just referring to the NotFound in the class name part of the check. I\u0027m fine with checking the status code attr of the exception objects for the neutronclient exceptions, but I think checking the name of the class is a bad idea. I\u0027d rather see an explicit list of what excpetions are part of this generalized catch. I see that it\u0027s part of the existing resource collection code, but that doesn\u0027t mean it\u0027s a good idea.\n\nAlthough honestly I think it would be better to do 1-1 matchings between what\u0027s kind of exception is expected and what is being checked. We want to be explict about what should be raised and fail otherwise.","commit_id":"b7fc79090eb92b0c58aec30eedd5c769da00a963"},{"author":{"_account_id":8576,"name":"Yair Fried","email":"yfried@redhat.com","username":"yfried"},"change_message_id":"084815ffc9d9ea02f161b048d4d4ea95e89be484","unresolved":false,"context_lines":[{"line_number":126,"context_line":"        \"\"\""},{"line_number":127,"context_line":"        @return: True if exception is of NotFound type"},{"line_number":128,"context_line":"        \"\"\""},{"line_number":129,"context_line":"        return (\u0027NotFound\u0027 in exception.__class__.__name__"},{"line_number":130,"context_line":"                or"},{"line_number":131,"context_line":"                hasattr(exception, \u0027status_code\u0027) and"},{"line_number":132,"context_line":"                exception.status_code \u003d\u003d 404)"}],"source_content_type":"text/x-python","patch_set":20,"id":"1ae5cdf2_5bcd5a2f","line":129,"in_reply_to":"1ae5cdf2_9f6a7c18","updated":"2014-06-19 08:35:24.000000000","message":"this is how it was done so far. it could be improved in later patch. I just moved this to a single place, because this check is needed in multiple places in the code\n\nHowever, neutron-client, wraps these exceptions in a way that forces you to check the status code. That\u0027s why it was like this.\nhttps://bugs.launchpad.net/python-neutronclient/+bug/1247568","commit_id":"b7fc79090eb92b0c58aec30eedd5c769da00a963"},{"author":{"_account_id":5196,"name":"Matthew Treinish","email":"mtreinish@kortar.org","username":"treinish"},"change_message_id":"5fcc659cf04e239d6afa089f4a675ebe09473aa7","unresolved":false,"context_lines":[{"line_number":131,"context_line":"                hasattr(exception, \u0027status_code\u0027) and"},{"line_number":132,"context_line":"                exception.status_code \u003d\u003d 404)"},{"line_number":133,"context_line":""},{"line_number":134,"context_line":"    def addCleanup(self, function, *arguments, **keywordArguments):"},{"line_number":135,"context_line":"        LOG.debug(\"Loading Cleanup function {func} with arguments {args}\"."},{"line_number":136,"context_line":"                  format(func\u003dfunction, args\u003d(arguments, keywordArguments)))"},{"line_number":137,"context_line":"        super(OfficialClientTest, self).addCleanup(function, *arguments,"}],"source_content_type":"text/x-python","patch_set":20,"id":"1ae5cdf2_1fcd8c31","line":134,"updated":"2014-06-18 23:17:52.000000000","message":"why do we need to log this? It feels like it\u0027d be just polluting the logs by doing this.","commit_id":"b7fc79090eb92b0c58aec30eedd5c769da00a963"},{"author":{"_account_id":8576,"name":"Yair Fried","email":"yfried@redhat.com","username":"yfried"},"change_message_id":"084815ffc9d9ea02f161b048d4d4ea95e89be484","unresolved":false,"context_lines":[{"line_number":131,"context_line":"                hasattr(exception, \u0027status_code\u0027) and"},{"line_number":132,"context_line":"                exception.status_code \u003d\u003d 404)"},{"line_number":133,"context_line":""},{"line_number":134,"context_line":"    def addCleanup(self, function, *arguments, **keywordArguments):"},{"line_number":135,"context_line":"        LOG.debug(\"Loading Cleanup function {func} with arguments {args}\"."},{"line_number":136,"context_line":"                  format(func\u003dfunction, args\u003d(arguments, keywordArguments)))"},{"line_number":137,"context_line":"        super(OfficialClientTest, self).addCleanup(function, *arguments,"}],"source_content_type":"text/x-python","patch_set":20,"id":"1ae5cdf2_3817b4a4","line":134,"in_reply_to":"1ae5cdf2_1fcd8c31","updated":"2014-06-19 08:35:24.000000000","message":"I\u0027m going to leave this as it is. If you are still unsatisfied with my answer, or have a better solution, I will change it in the next patch \n\nA - this is \"debug\" level\nB - cleanup is a complicated issue since the method is never used where it\u0027s written in the code, but rather in in \"hidden\" code (running no even as part of tearDown). in most of these places, cleanup is being loaded as part of a helper function (ie \"create_server\") so scenario writer/executor might not be aware of it\u0027s existence. I feel like some form of logging is required so you can know what is being done \"under the hood\" and verify that the right method is cleaning up your resources","commit_id":"b7fc79090eb92b0c58aec30eedd5c769da00a963"},{"author":{"_account_id":5196,"name":"Matthew Treinish","email":"mtreinish@kortar.org","username":"treinish"},"change_message_id":"25ab100052b2e597107f71c3f31bf33c5e4f51b7","unresolved":false,"context_lines":[{"line_number":131,"context_line":"                hasattr(exception, \u0027status_code\u0027) and"},{"line_number":132,"context_line":"                exception.status_code \u003d\u003d 404)"},{"line_number":133,"context_line":""},{"line_number":134,"context_line":"    def addCleanup(self, function, *arguments, **keywordArguments):"},{"line_number":135,"context_line":"        LOG.debug(\"Loading Cleanup function {func} with arguments {args}\"."},{"line_number":136,"context_line":"                  format(func\u003dfunction, args\u003d(arguments, keywordArguments)))"},{"line_number":137,"context_line":"        super(OfficialClientTest, self).addCleanup(function, *arguments,"}],"source_content_type":"text/x-python","patch_set":20,"id":"1ae5cdf2_fb4a9925","line":134,"in_reply_to":"1ae5cdf2_3817b4a4","updated":"2014-06-19 13:46:40.000000000","message":"Maybe for testing things in development it\u0027s useful. (although I\u0027m not convinced) But this will just be adding to the tempest logging mess. Adding a log message for every cleanup in the scenario tests even at the debug level is way too chatty. We only ever care about the cleanup call path if there is a problem (and maybe not even then) there is no reason to be logging it all the time.","commit_id":"b7fc79090eb92b0c58aec30eedd5c769da00a963"},{"author":{"_account_id":5196,"name":"Matthew Treinish","email":"mtreinish@kortar.org","username":"treinish"},"change_message_id":"5fcc659cf04e239d6afa089f4a675ebe09473aa7","unresolved":false,"context_lines":[{"line_number":141,"context_line":"        \"\"\"Ignores NotFound exceptions for delete operations."},{"line_number":142,"context_line":""},{"line_number":143,"context_line":"        @param resource: object with delete() method."},{"line_number":144,"context_line":"            OpenStack resources are assumed to have a delete() method which"},{"line_number":145,"context_line":"            destroys the resource"},{"line_number":146,"context_line":"        \"\"\""},{"line_number":147,"context_line":"        # will block until resource can no longer be retrieved via"}],"source_content_type":"text/x-python","patch_set":20,"id":"1ae5cdf2_dab7b21f","line":144,"updated":"2014-06-18 23:17:52.000000000","message":"Is this a valid assumption for all the python clients moving forward or just what we\u0027re using it for today?","commit_id":"b7fc79090eb92b0c58aec30eedd5c769da00a963"},{"author":{"_account_id":8576,"name":"Yair Fried","email":"yfried@redhat.com","username":"yfried"},"change_message_id":"084815ffc9d9ea02f161b048d4d4ea95e89be484","unresolved":false,"context_lines":[{"line_number":141,"context_line":"        \"\"\"Ignores NotFound exceptions for delete operations."},{"line_number":142,"context_line":""},{"line_number":143,"context_line":"        @param resource: object with delete() method."},{"line_number":144,"context_line":"            OpenStack resources are assumed to have a delete() method which"},{"line_number":145,"context_line":"            destroys the resource"},{"line_number":146,"context_line":"        \"\"\""},{"line_number":147,"context_line":"        # will block until resource can no longer be retrieved via"}],"source_content_type":"text/x-python","patch_set":20,"id":"1ae5cdf2_fb79c6c5","line":144,"in_reply_to":"1ae5cdf2_dab7b21f","updated":"2014-06-19 08:35:24.000000000","message":"that\u0027s the assumption that was in place for the original cleaning method. can be changed later, but this will require extra careful thinking.\nsee next comment","commit_id":"b7fc79090eb92b0c58aec30eedd5c769da00a963"},{"author":{"_account_id":5196,"name":"Matthew Treinish","email":"mtreinish@kortar.org","username":"treinish"},"change_message_id":"25ab100052b2e597107f71c3f31bf33c5e4f51b7","unresolved":false,"context_lines":[{"line_number":141,"context_line":"        \"\"\"Ignores NotFound exceptions for delete operations."},{"line_number":142,"context_line":""},{"line_number":143,"context_line":"        @param resource: object with delete() method."},{"line_number":144,"context_line":"            OpenStack resources are assumed to have a delete() method which"},{"line_number":145,"context_line":"            destroys the resource"},{"line_number":146,"context_line":"        \"\"\""},{"line_number":147,"context_line":"        # will block until resource can no longer be retrieved via"}],"source_content_type":"text/x-python","patch_set":20,"id":"1ae5cdf2_7bba09e2","line":144,"in_reply_to":"1ae5cdf2_fb79c6c5","updated":"2014-06-19 13:46:40.000000000","message":"Ok, I\u0027m fine with making this assumption for now. I was just asking about the longevity of it.","commit_id":"b7fc79090eb92b0c58aec30eedd5c769da00a963"},{"author":{"_account_id":5196,"name":"Matthew Treinish","email":"mtreinish@kortar.org","username":"treinish"},"change_message_id":"5fcc659cf04e239d6afa089f4a675ebe09473aa7","unresolved":false,"context_lines":[{"line_number":153,"context_line":"            resource.delete()"},{"line_number":154,"context_line":"        except Exception as e:"},{"line_number":155,"context_line":"            # If the resource is already missing, mission accomplished."},{"line_number":156,"context_line":"            if self.not_found_exception(e):"},{"line_number":157,"context_line":"                LOG.exception(\u0027Resource %s already deleted\u0027 % resource)"},{"line_number":158,"context_line":"            else:"},{"line_number":159,"context_line":"                raise"}],"source_content_type":"text/x-python","patch_set":20,"id":"1ae5cdf2_dae09228","line":156,"updated":"2014-06-18 23:17:52.000000000","message":"You could always handle this like I did in addCleanup with wait and take in the expected notFound exception as an arg.","commit_id":"b7fc79090eb92b0c58aec30eedd5c769da00a963"},{"author":{"_account_id":8576,"name":"Yair Fried","email":"yfried@redhat.com","username":"yfried"},"change_message_id":"084815ffc9d9ea02f161b048d4d4ea95e89be484","unresolved":false,"context_lines":[{"line_number":153,"context_line":"            resource.delete()"},{"line_number":154,"context_line":"        except Exception as e:"},{"line_number":155,"context_line":"            # If the resource is already missing, mission accomplished."},{"line_number":156,"context_line":"            if self.not_found_exception(e):"},{"line_number":157,"context_line":"                LOG.exception(\u0027Resource %s already deleted\u0027 % resource)"},{"line_number":158,"context_line":"            else:"},{"line_number":159,"context_line":"                raise"}],"source_content_type":"text/x-python","patch_set":20,"id":"1ae5cdf2_fb2706c5","line":156,"in_reply_to":"1ae5cdf2_dae09228","updated":"2014-06-19 08:35:24.000000000","message":"I tried this, but using this in another \"nested callable\" such as addCleanup_with_wait starts getting out of hand.\nAlso, as I mentioned above, neutron-client doesn\u0027t have a specific NotFound error, and catching NeutronError is a source for trouble\n\nhttps://bugs.launchpad.net/python-neutronclient/+bug/1247568","commit_id":"b7fc79090eb92b0c58aec30eedd5c769da00a963"},{"author":{"_account_id":5196,"name":"Matthew Treinish","email":"mtreinish@kortar.org","username":"treinish"},"change_message_id":"25ab100052b2e597107f71c3f31bf33c5e4f51b7","unresolved":false,"context_lines":[{"line_number":153,"context_line":"            resource.delete()"},{"line_number":154,"context_line":"        except Exception as e:"},{"line_number":155,"context_line":"            # If the resource is already missing, mission accomplished."},{"line_number":156,"context_line":"            if self.not_found_exception(e):"},{"line_number":157,"context_line":"                LOG.exception(\u0027Resource %s already deleted\u0027 % resource)"},{"line_number":158,"context_line":"            else:"},{"line_number":159,"context_line":"                raise"}],"source_content_type":"text/x-python","patch_set":20,"id":"1ae5cdf2_7b2be9ea","line":156,"in_reply_to":"1ae5cdf2_fb2706c5","updated":"2014-06-19 13:46:40.000000000","message":"Why? that doesn\u0027t seem like that big a wrinkle to work around. You just special case the neutron exception and check the status code attr in a separate if block. Something like:\n\nexcept expected_exception as e:\n    if isinstance(e, NeutronException):\n       if not e.status_code \u003d\u003d 404:\n          raise\n    LOG\n\nwhere expected_exception is an optional arg for the exception class.\n\nThat would be much cleaner IMO. Catching every exception is a bad idea for many reasons even with the logic like you have it here. Heck you could even just subclass it for the neutron scenario test class and only have this check there. Then keep the default path for the other scenarios simple.","commit_id":"b7fc79090eb92b0c58aec30eedd5c769da00a963"},{"author":{"_account_id":5196,"name":"Matthew Treinish","email":"mtreinish@kortar.org","username":"treinish"},"change_message_id":"5fcc659cf04e239d6afa089f4a675ebe09473aa7","unresolved":false,"context_lines":[{"line_number":200,"context_line":"        }"},{"line_number":201,"context_line":"        self.cleanup_waits.append(wait_dict)"},{"line_number":202,"context_line":""},{"line_number":203,"context_line":"    def status_timeout(self, resources, resource_id, expected_status,"},{"line_number":204,"context_line":"                       error_status\u003d\u0027ERROR\u0027,"},{"line_number":205,"context_line":"                       not_found_exception\u003dnova_exceptions.NotFound):"},{"line_number":206,"context_line":"        \"\"\""}],"source_content_type":"text/x-python","patch_set":20,"id":"1ae5cdf2_439bcc65","line":203,"updated":"2014-06-18 23:17:52.000000000","message":"Why are you changing the name here? It seems unrelated to this patch.","commit_id":"b7fc79090eb92b0c58aec30eedd5c769da00a963"},{"author":{"_account_id":8576,"name":"Yair Fried","email":"yfried@redhat.com","username":"yfried"},"change_message_id":"084815ffc9d9ea02f161b048d4d4ea95e89be484","unresolved":false,"context_lines":[{"line_number":200,"context_line":"        }"},{"line_number":201,"context_line":"        self.cleanup_waits.append(wait_dict)"},{"line_number":202,"context_line":""},{"line_number":203,"context_line":"    def status_timeout(self, resources, resource_id, expected_status,"},{"line_number":204,"context_line":"                       error_status\u003d\u0027ERROR\u0027,"},{"line_number":205,"context_line":"                       not_found_exception\u003dnova_exceptions.NotFound):"},{"line_number":206,"context_line":"        \"\"\""}],"source_content_type":"text/x-python","patch_set":20,"id":"1ae5cdf2_b1503f5f","line":203,"in_reply_to":"1ae5cdf2_439bcc65","updated":"2014-06-19 08:35:24.000000000","message":"Done","commit_id":"b7fc79090eb92b0c58aec30eedd5c769da00a963"},{"author":{"_account_id":5196,"name":"Matthew Treinish","email":"mtreinish@kortar.org","username":"treinish"},"change_message_id":"5fcc659cf04e239d6afa089f4a675ebe09473aa7","unresolved":false,"context_lines":[{"line_number":214,"context_line":"                             error_status\u003derror_status,"},{"line_number":215,"context_line":"                             not_found_exception\u003dnot_found_exception)"},{"line_number":216,"context_line":""},{"line_number":217,"context_line":"    def delete_timeout(self, resource_class, resource_id,"},{"line_number":218,"context_line":"                       error_status\u003d\u0027ERROR\u0027,"},{"line_number":219,"context_line":"                       not_found_exception\u003dnova_exceptions.NotFound):"},{"line_number":220,"context_line":"        \"\"\""}],"source_content_type":"text/x-python","patch_set":20,"id":"1ae5cdf2_2396c03e","line":217,"updated":"2014-06-18 23:17:52.000000000","message":"Why are you changing the name here? It seems unrelated to this patch.","commit_id":"b7fc79090eb92b0c58aec30eedd5c769da00a963"},{"author":{"_account_id":8576,"name":"Yair Fried","email":"yfried@redhat.com","username":"yfried"},"change_message_id":"084815ffc9d9ea02f161b048d4d4ea95e89be484","unresolved":false,"context_lines":[{"line_number":214,"context_line":"                             error_status\u003derror_status,"},{"line_number":215,"context_line":"                             not_found_exception\u003dnot_found_exception)"},{"line_number":216,"context_line":""},{"line_number":217,"context_line":"    def delete_timeout(self, resource_class, resource_id,"},{"line_number":218,"context_line":"                       error_status\u003d\u0027ERROR\u0027,"},{"line_number":219,"context_line":"                       not_found_exception\u003dnova_exceptions.NotFound):"},{"line_number":220,"context_line":"        \"\"\""}],"source_content_type":"text/x-python","patch_set":20,"id":"1ae5cdf2_11c73313","line":217,"in_reply_to":"1ae5cdf2_2396c03e","updated":"2014-06-19 08:35:24.000000000","message":"Done","commit_id":"b7fc79090eb92b0c58aec30eedd5c769da00a963"},{"author":{"_account_id":5196,"name":"Matthew Treinish","email":"mtreinish@kortar.org","username":"treinish"},"change_message_id":"5fcc659cf04e239d6afa089f4a675ebe09473aa7","unresolved":false,"context_lines":[{"line_number":230,"context_line":"                             not_found_exception\u003dnot_found_exception)"},{"line_number":231,"context_line":""},{"line_number":232,"context_line":"    def _status_timeout(self,"},{"line_number":233,"context_line":"                        resource_class,"},{"line_number":234,"context_line":"                        resource_id,"},{"line_number":235,"context_line":"                        expected_status\u003dNone,"},{"line_number":236,"context_line":"                        allow_notfound\u003dFalse,"}],"source_content_type":"text/x-python","patch_set":20,"id":"1ae5cdf2_63d1a8fa","line":233,"updated":"2014-06-18 23:17:52.000000000","message":"Why are you changing the name here? It seems unrelated to this patch.","commit_id":"b7fc79090eb92b0c58aec30eedd5c769da00a963"},{"author":{"_account_id":8576,"name":"Yair Fried","email":"yfried@redhat.com","username":"yfried"},"change_message_id":"084815ffc9d9ea02f161b048d4d4ea95e89be484","unresolved":false,"context_lines":[{"line_number":230,"context_line":"                             not_found_exception\u003dnot_found_exception)"},{"line_number":231,"context_line":""},{"line_number":232,"context_line":"    def _status_timeout(self,"},{"line_number":233,"context_line":"                        resource_class,"},{"line_number":234,"context_line":"                        resource_id,"},{"line_number":235,"context_line":"                        expected_status\u003dNone,"},{"line_number":236,"context_line":"                        allow_notfound\u003dFalse,"}],"source_content_type":"text/x-python","patch_set":20,"id":"1ae5cdf2_51cd3b2f","line":233,"in_reply_to":"1ae5cdf2_63d1a8fa","updated":"2014-06-19 08:35:24.000000000","message":"Done","commit_id":"b7fc79090eb92b0c58aec30eedd5c769da00a963"},{"author":{"_account_id":1192,"name":"David Kranz","email":"dkranz@redhat.com","username":"david-kranz"},"change_message_id":"e6481f39f94353a67e109ff9cc51b005c9e0fac9","unresolved":false,"context_lines":[{"line_number":145,"context_line":"        except Exception as e:"},{"line_number":146,"context_line":"            # If the resource is already missing, mission accomplished."},{"line_number":147,"context_line":"            if self.not_found_exception(e):"},{"line_number":148,"context_line":"                LOG.exception(\u0027Resource %s already deleted\u0027 % thing)"},{"line_number":149,"context_line":"            else:"},{"line_number":150,"context_line":"                raise"},{"line_number":151,"context_line":""}],"source_content_type":"text/x-python","patch_set":22,"id":"1ae5cdf2_58dc61e4","line":148,"updated":"2014-06-19 21:44:43.000000000","message":"I didn\u0027t think this exception was indicative of a tempest bug and so I would expect this to be logged as debug. Is that not true?","commit_id":"52887ba6324f8d6834fa0e2292f4663dfca1a4ef"},{"author":{"_account_id":1192,"name":"David Kranz","email":"dkranz@redhat.com","username":"david-kranz"},"change_message_id":"e6481f39f94353a67e109ff9cc51b005c9e0fac9","unresolved":false,"context_lines":[{"line_number":178,"context_line":"            things.delete(thing_id)"},{"line_number":179,"context_line":"        \"\"\""},{"line_number":180,"context_line":"        if cleanup_callable is None:"},{"line_number":181,"context_line":"            LOG.warn(\"no delete method passed. using {rclass}.delete({id}) as \""},{"line_number":182,"context_line":"                     \"default\".format(rclass\u003dthings, id\u003dthing_id))"},{"line_number":183,"context_line":"            self.addCleanup(things.delete, thing_id)"},{"line_number":184,"context_line":"        else:"}],"source_content_type":"text/x-python","patch_set":22,"id":"1ae5cdf2_189d790a","line":181,"updated":"2014-06-19 21:44:43.000000000","message":"Why is this a warning? Either this argument is required or not.","commit_id":"52887ba6324f8d6834fa0e2292f4663dfca1a4ef"},{"author":{"_account_id":8576,"name":"Yair Fried","email":"yfried@redhat.com","username":"yfried"},"change_message_id":"5418b7e6736e99f7b9b164d56d7129cc5ba07a0d","unresolved":false,"context_lines":[{"line_number":178,"context_line":"            things.delete(thing_id)"},{"line_number":179,"context_line":"        \"\"\""},{"line_number":180,"context_line":"        if cleanup_callable is None:"},{"line_number":181,"context_line":"            LOG.warn(\"no delete method passed. using {rclass}.delete({id}) as \""},{"line_number":182,"context_line":"                     \"default\".format(rclass\u003dthings, id\u003dthing_id))"},{"line_number":183,"context_line":"            self.addCleanup(things.delete, thing_id)"},{"line_number":184,"context_line":"        else:"}],"source_content_type":"text/x-python","patch_set":22,"id":"1ae5cdf2_56b7cd84","line":181,"in_reply_to":"1ae5cdf2_189d790a","updated":"2014-06-20 03:42:01.000000000","message":"There is a default behavior but it might not be suitable in all cases. that\u0027s why it\u0027s a warning.\nBecause it will be called far away from where it\u0027s written. so this should stand out.","commit_id":"52887ba6324f8d6834fa0e2292f4663dfca1a4ef"},{"author":{"_account_id":1192,"name":"David Kranz","email":"dkranz@redhat.com","username":"david-kranz"},"change_message_id":"a55ba8b085d2a69f9a4c6a220192976796b688cf","unresolved":false,"context_lines":[{"line_number":176,"context_line":"            things.delete(thing_id)"},{"line_number":177,"context_line":"        \"\"\""},{"line_number":178,"context_line":"        if cleanup_callable is None:"},{"line_number":179,"context_line":"            LOG.warn(\"no delete method passed. using {rclass}.delete({id}) as \""},{"line_number":180,"context_line":"                     \"default\".format(rclass\u003dthings, id\u003dthing_id))"},{"line_number":181,"context_line":"            self.addCleanup(things.delete, thing_id)"},{"line_number":182,"context_line":"        else:"}],"source_content_type":"text/x-python","patch_set":24,"id":"1ae5cdf2_9b2362bd","line":179,"updated":"2014-06-26 20:37:06.000000000","message":"I do not agree with the response to my previous comment about this. There are many calls to this method in this file that do not pass cleanup_callable. If tempest runs to successful completion under normal conditions, there should not be warnings in the logs. A WARNING indicates an unexpected condition.","commit_id":"4613252d5cbc0a72d8180c1eb84732ae9cc0e718"}],"tempest/scenario/test_aggregates_basic_ops.py":[{"author":{"_account_id":1192,"name":"David Kranz","email":"dkranz@redhat.com","username":"david-kranz"},"change_message_id":"e6481f39f94353a67e109ff9cc51b005c9e0fac9","unresolved":false,"context_lines":[{"line_number":115,"context_line":""},{"line_number":116,"context_line":"        host \u003d self._get_host_name()"},{"line_number":117,"context_line":"        self._add_host(aggregate, host)"},{"line_number":118,"context_line":"        self.addCleanup(self._remove_host, aggregate, host)"},{"line_number":119,"context_line":"        self._check_aggregate_details(aggregate, aggregate_name, az, [host],"},{"line_number":120,"context_line":"                                      metadata)"},{"line_number":121,"context_line":""}],"source_content_type":"text/x-python","patch_set":22,"id":"1ae5cdf2_18e579db","line":118,"updated":"2014-06-19 21:44:43.000000000","message":"This should go in _add_host. This malloc/free stuff is error-prone so we should stick to the paradigm where if you create a resource with a self.xxx call then you do not do an addCleanUp, and if you use a direct client call then the addCleanUp should be in the same code block.","commit_id":"52887ba6324f8d6834fa0e2292f4663dfca1a4ef"}],"tempest/scenario/test_large_ops.py":[{"author":{"_account_id":8576,"name":"Yair Fried","email":"yfried@redhat.com","username":"yfried"},"change_message_id":"7692d322d04f35050a3af14b5c588f3e4dad294b","unresolved":false,"context_lines":[{"line_number":48,"context_line":"        # NOTE(mtreinish) Create secgroup in setUp so cleanup is first entry"},{"line_number":49,"context_line":"        # in addCleanup LIFO. Otherwise the secgroup delete will fail because"},{"line_number":50,"context_line":"        # there are still servers using it."},{"line_number":51,"context_line":"        self.secgroup \u003d self._create_security_group_nova()"},{"line_number":52,"context_line":"        super(TestLargeOpsScenario, self).setUp()"},{"line_number":53,"context_line":""},{"line_number":54,"context_line":"    def _wait_for_server_status(self, status):"}],"source_content_type":"text/x-python","patch_set":16,"id":"AAAAUX%2F%2Bw8M%3D","line":51,"updated":"2014-02-19 07:53:53.000000000","message":"I\u0027m completely unfamiliar with this test, but I\u0027m unable to find where secgroup was created before this patch","commit_id":"e8fa4a7398596c33c852baedc8c1c4b71a932ec7"}],"tempest/scenario/test_network_basic_ops.py":[{"author":{"_account_id":7,"name":"Jay Pipes","email":"jaypipes@gmail.com","username":"jaypipes"},"change_message_id":"25585e39d87a469a0ad80548fb2cd15bcbd2b2ea","unresolved":false,"context_lines":[{"line_number":168,"context_line":""},{"line_number":169,"context_line":"    def _create_keypairs(self):"},{"line_number":170,"context_line":"        self.keypairs[self.tenant_id] \u003d self.create_keypair("},{"line_number":171,"context_line":"            name\u003ddata_utils.rand_name(\u0027keypair-smoke-\u0027))"},{"line_number":172,"context_line":""},{"line_number":173,"context_line":"    def _create_security_groups(self):"},{"line_number":174,"context_line":"        self.security_groups[self.tenant_id] \u003d\\"}],"source_content_type":"text/x-python","patch_set":10,"id":"AAAAUH%2F%2Fw0M%3D","line":171,"updated":"2014-01-08 18:54:13.000000000","message":"What does this have to do with this changeset?","commit_id":"781b4790720fd3b18e0613b3326bf15a2b253503"},{"author":{"_account_id":5196,"name":"Matthew Treinish","email":"mtreinish@kortar.org","username":"treinish"},"change_message_id":"1bc2dd89e5af01e6f5290891cb18a4c5f1eae1ab","unresolved":false,"context_lines":[{"line_number":168,"context_line":""},{"line_number":169,"context_line":"    def _create_keypairs(self):"},{"line_number":170,"context_line":"        self.keypairs[self.tenant_id] \u003d self.create_keypair("},{"line_number":171,"context_line":"            name\u003ddata_utils.rand_name(\u0027keypair-smoke-\u0027))"},{"line_number":172,"context_line":""},{"line_number":173,"context_line":"    def _create_security_groups(self):"},{"line_number":174,"context_line":"        self.security_groups[self.tenant_id] \u003d\\"}],"source_content_type":"text/x-python","patch_set":10,"id":"AAAAUH%2F%2Fwqo%3D","line":171,"in_reply_to":"AAAAUH%2F%2Fw0M%3D","updated":"2014-01-08 19:21:18.000000000","message":"I\u0027m not sure, I don\u0027t remember adding this, it might have been mixed up in a rebase.","commit_id":"781b4790720fd3b18e0613b3326bf15a2b253503"},{"author":{"_account_id":7,"name":"Jay Pipes","email":"jaypipes@gmail.com","username":"jaypipes"},"change_message_id":"918b4027d2b4618a93154a09fb8dd35b86d2a423","unresolved":false,"context_lines":[{"line_number":168,"context_line":""},{"line_number":169,"context_line":"    def _create_keypairs(self):"},{"line_number":170,"context_line":"        self.keypairs[self.tenant_id] \u003d self.create_keypair("},{"line_number":171,"context_line":"            name\u003ddata_utils.rand_name(\u0027keypair-smoke-\u0027))"},{"line_number":172,"context_line":""},{"line_number":173,"context_line":"    def _create_security_groups(self):"},{"line_number":174,"context_line":"        self.security_groups[self.tenant_id] \u003d\\"}],"source_content_type":"text/x-python","patch_set":10,"id":"AAAAUH%2F%2FwlE%3D","line":171,"in_reply_to":"AAAAUH%2F%2Fwqo%3D","updated":"2014-01-08 19:35:10.000000000","message":"LOL, no worries :) It happens. Was just curious, is all...","commit_id":"781b4790720fd3b18e0613b3326bf15a2b253503"}],"tempest/scenario/test_server_basic_ops.py":[{"author":{"_account_id":5196,"name":"Matthew Treinish","email":"mtreinish@kortar.org","username":"treinish"},"change_message_id":"5fcc659cf04e239d6afa089f4a675ebe09473aa7","unresolved":false,"context_lines":[{"line_number":109,"context_line":"        self.security_group \u003d self._create_security_group_nova()"},{"line_number":110,"context_line":"        self.boot_instance()"},{"line_number":111,"context_line":"        self.verify_ssh()"},{"line_number":112,"context_line":"        self.terminate_instance()"}],"source_content_type":"text/x-python","patch_set":20,"id":"1ae5cdf2_7a6dbe31","side":"PARENT","line":112,"updated":"2014-06-18 23:17:52.000000000","message":"This is part of the test path. We don\u0027t want to do it in cleanup it\u0027s explictly deleted because we\u0027re testing the delete. So we should keep it around.","commit_id":"e30f755f8e0454081b3e8351c5749cf6612c3e8b"},{"author":{"_account_id":8576,"name":"Yair Fried","email":"yfried@redhat.com","username":"yfried"},"change_message_id":"084815ffc9d9ea02f161b048d4d4ea95e89be484","unresolved":false,"context_lines":[{"line_number":109,"context_line":"        self.security_group \u003d self._create_security_group_nova()"},{"line_number":110,"context_line":"        self.boot_instance()"},{"line_number":111,"context_line":"        self.verify_ssh()"},{"line_number":112,"context_line":"        self.terminate_instance()"}],"source_content_type":"text/x-python","patch_set":20,"id":"1ae5cdf2_f1d3a7fe","side":"PARENT","line":112,"in_reply_to":"1ae5cdf2_7a6dbe31","updated":"2014-06-19 08:35:24.000000000","message":"tnx for the catch.","commit_id":"e30f755f8e0454081b3e8351c5749cf6612c3e8b"}]}
