)]}'
{"/COMMIT_MSG":[{"author":{"_account_id":11604,"name":"sean mooney","email":"smooney@redhat.com","username":"sean-k-mooney"},"change_message_id":"f69f07fc2a54b1d7744e3e723d32c7652f582dc4","unresolved":true,"context_lines":[{"line_number":10,"context_line":"structure (keys and types) against the JSON sample files in"},{"line_number":11,"context_line":"doc/api_samples/. This catches structural drift between the API and"},{"line_number":12,"context_line":"its documentation without being sensitive to value changes like UUIDs"},{"line_number":13,"context_line":"or timestamps."},{"line_number":14,"context_line":""},{"line_number":15,"context_line":"The test infrastructure boots a real Pecan/WSME app against an"},{"line_number":16,"context_line":"in-memory SQLite database, seeds test data, and compares responses"}],"source_content_type":"text/x-gerrit-commit-message","patch_set":6,"id":"2d6609f7_7d4d9559","line":13,"updated":"2026-07-07 12:37:01.000000000","message":"so this is great but can you write or generate a detail contibutor doc similar to\nhttps://github.com/openstack/cyborg/blob/master/doc/source/contributor/tempest-testing.rst\n\nas a new doc and that move the tempest testign doc and the new doc into a new testing section in https://github.com/openstack/cyborg/blob/master/doc/source/contributor/index.rst\n\nthis can be a followup but i think ti would be good to get this into the docs\nso that we codefy how this works for humans and llms","commit_id":"7edf57d8b318bcd45d11ee0fb76d74ba393c8193"},{"author":{"_account_id":11604,"name":"sean mooney","email":"smooney@redhat.com","username":"sean-k-mooney"},"change_message_id":"eb6c546a64095c98ebf4f9ee26681d6b35a41224","unresolved":false,"context_lines":[{"line_number":10,"context_line":"structure (keys and types) against the JSON sample files in"},{"line_number":11,"context_line":"doc/api_samples/. This catches structural drift between the API and"},{"line_number":12,"context_line":"its documentation without being sensitive to value changes like UUIDs"},{"line_number":13,"context_line":"or timestamps."},{"line_number":14,"context_line":""},{"line_number":15,"context_line":"The test infrastructure boots a real Pecan/WSME app against an"},{"line_number":16,"context_line":"in-memory SQLite database, seeds test data, and compares responses"}],"source_content_type":"text/x-gerrit-commit-message","patch_set":6,"id":"96d1aed7_dc91116d","line":13,"in_reply_to":"2881c398_fd67a7ed","updated":"2026-07-16 12:05:20.000000000","message":"Acknowledged","commit_id":"7edf57d8b318bcd45d11ee0fb76d74ba393c8193"},{"author":{"_account_id":4690,"name":"melanie witt","display_name":"melwitt","email":"melwittt@gmail.com","username":"melwitt"},"change_message_id":"7ad6c5733d29f12e3e84ab61748c22315331abc5","unresolved":true,"context_lines":[{"line_number":10,"context_line":"structure (keys and types) against the JSON sample files in"},{"line_number":11,"context_line":"doc/api_samples/. This catches structural drift between the API and"},{"line_number":12,"context_line":"its documentation without being sensitive to value changes like UUIDs"},{"line_number":13,"context_line":"or timestamps."},{"line_number":14,"context_line":""},{"line_number":15,"context_line":"The test infrastructure boots a real Pecan/WSME app against an"},{"line_number":16,"context_line":"in-memory SQLite database, seeds test data, and compares responses"}],"source_content_type":"text/x-gerrit-commit-message","patch_set":6,"id":"9237098b_db46c827","line":13,"in_reply_to":"2d6609f7_7d4d9559","updated":"2026-07-08 01:17:55.000000000","message":"Agreed this is a good idea, I will add a follow up patch on top of this one.","commit_id":"7edf57d8b318bcd45d11ee0fb76d74ba393c8193"},{"author":{"_account_id":4690,"name":"melanie witt","display_name":"melwitt","email":"melwittt@gmail.com","username":"melwitt"},"change_message_id":"39ad2b53760272161f45a8019ef09a76efa92448","unresolved":true,"context_lines":[{"line_number":10,"context_line":"structure (keys and types) against the JSON sample files in"},{"line_number":11,"context_line":"doc/api_samples/. This catches structural drift between the API and"},{"line_number":12,"context_line":"its documentation without being sensitive to value changes like UUIDs"},{"line_number":13,"context_line":"or timestamps."},{"line_number":14,"context_line":""},{"line_number":15,"context_line":"The test infrastructure boots a real Pecan/WSME app against an"},{"line_number":16,"context_line":"in-memory SQLite database, seeds test data, and compares responses"}],"source_content_type":"text/x-gerrit-commit-message","patch_set":6,"id":"2881c398_fd67a7ed","line":13,"in_reply_to":"9237098b_db46c827","updated":"2026-07-08 15:52:42.000000000","message":"Proposed here https://review.opendev.org/c/openstack/cyborg/+/996390","commit_id":"7edf57d8b318bcd45d11ee0fb76d74ba393c8193"}],"/PATCHSET_LEVEL":[{"author":{"_account_id":34452,"name":"Joan Gilabert","display_name":"jgilaber","email":"jgilaber@redhat.com","username":"jgilaber"},"change_message_id":"4eff53a62bd3e8e027ac1690e6ff1d260349c0f0","unresolved":false,"context_lines":[],"source_content_type":"","patch_set":6,"id":"67e65eef_2da1447d","updated":"2026-07-06 15:01:24.000000000","message":"looks good to me, and will be very useful, thanks","commit_id":"7edf57d8b318bcd45d11ee0fb76d74ba393c8193"},{"author":{"_account_id":11604,"name":"sean mooney","email":"smooney@redhat.com","username":"sean-k-mooney"},"change_message_id":"eb6c546a64095c98ebf4f9ee26681d6b35a41224","unresolved":false,"context_lines":[],"source_content_type":"","patch_set":7,"id":"2630cf66_a317c8aa","updated":"2026-07-16 12:05:20.000000000","message":"i dont really have any concerns that cant be adress in followups so i think i will appove this later today","commit_id":"edce5fb28c9f39c0af95ba0729857586ca6bbc70"},{"author":{"_account_id":34452,"name":"Joan Gilabert","display_name":"jgilaber","email":"jgilaber@redhat.com","username":"jgilaber"},"change_message_id":"6503f9905a1a1a94b050f7cb74ce8f66d1f83194","unresolved":false,"context_lines":[],"source_content_type":"","patch_set":7,"id":"ca776ccb_be3e7822","updated":"2026-07-10 11:03:33.000000000","message":"lgtm","commit_id":"edce5fb28c9f39c0af95ba0729857586ca6bbc70"},{"author":{"_account_id":12393,"name":"chandan kumar","display_name":"Chandan Kumar","email":"chkumar@redhat.com","username":"chkumar246"},"change_message_id":"de4090c3d5823b7aa4a1ab10586d644285689d10","unresolved":false,"context_lines":[],"source_content_type":"","patch_set":7,"id":"156fb3ec_1ec8960e","updated":"2026-07-13 06:57:26.000000000","message":"looks good!","commit_id":"edce5fb28c9f39c0af95ba0729857586ca6bbc70"}],"cyborg/tests/__init__.py":[{"author":{"_account_id":28006,"name":"teim-ci","display_name":"teim-ci","email":"ci@seanmooney.info","username":"ci-sean-mooney","status":"this is a third-party ci account run by sean-k-mooney on irc\nhosted at zuul.teim.app"},"tag":"autogenerated:zuul:automatic-ci","change_message_id":"3c95be4e32bc2edadfaf789605559cc694defbd6","unresolved":false,"context_lines":[{"line_number":1,"context_line":"import oslo_service.backend as service"},{"line_number":2,"context_line":""},{"line_number":3,"context_line":""},{"line_number":4,"context_line":"service.init_backend(service.BackendType.THREADING)"}],"source_content_type":"text/x-python","patch_set":4,"id":"5e906838_c437a7f7","line":1,"updated":"2026-06-25 20:26:34.000000000","message":"cyborg/tests/__init__.py now contains executable code (oslo_service backend init) but has no Apache license header, unlike the moved unit/__init__.py.\n\n**Severity**: WARNING | **Confidence**: 0.8\n\n**Impact**: The repo runs flake8 with select\u003dH (hacking) and H102 (missing license header) is not ignored. The file was previously empty so passed; now non-empty, tox -epep8 may newly fail on H102.\n\n**Suggestion**:\nAdd the standard Apache 2.0 license header used elsewhere in the repo (e.g. the header on cyborg/tests/unit/__init__.py) to cyborg/tests/__init__.py, then run tox -epep8 to confirm no H102.","commit_id":"7400129897644343f7f51cfa943442dde9165b63"},{"author":{"_account_id":11604,"name":"sean mooney","email":"smooney@redhat.com","username":"sean-k-mooney"},"change_message_id":"f69f07fc2a54b1d7744e3e723d32c7652f582dc4","unresolved":false,"context_lines":[{"line_number":1,"context_line":"import oslo_service.backend as service"},{"line_number":2,"context_line":""},{"line_number":3,"context_line":""},{"line_number":4,"context_line":"service.init_backend(service.BackendType.THREADING)"}],"source_content_type":"text/x-python","patch_set":6,"id":"51313589_a1d233d6","line":4,"updated":"2026-07-07 12:37:01.000000000","message":"sure we can do this here since we are not supprotign eventlet we dont need ot do this at a lower level of with a env var so we can just hard code it","commit_id":"7edf57d8b318bcd45d11ee0fb76d74ba393c8193"}],"cyborg/tests/functional/__init__.py":[{"author":{"_account_id":11604,"name":"sean mooney","email":"smooney@redhat.com","username":"sean-k-mooney"},"change_message_id":"eb6c546a64095c98ebf4f9ee26681d6b35a41224","unresolved":true,"context_lines":[{"line_number":1,"context_line":"from cyborg import objects"},{"line_number":2,"context_line":""},{"line_number":3,"context_line":""},{"line_number":4,"context_line":"objects.register_all()"}],"source_content_type":"text/x-python","patch_set":7,"id":"ac7d6126_6e69ef05","line":4,"updated":"2026-07-16 12:05:20.000000000","message":"this is fine but i wonder if we want to do this somewhere else eventually.\ndeciding where to initallise the object registry has alwasy been a littel annoying\n\nim not sure jsut doing this in cyborg/objects/__init__.py or somethign liek that would make sesne so +1 for now\n\nim often tempted to put it into the base test class but it is not something we have to do per test its once per test executor process\n\nsince we need ot do this in the unit test as well (and init the oslo backend) we could put this in `cyborg/tests/__init__.py`","commit_id":"edce5fb28c9f39c0af95ba0729857586ca6bbc70"}],"cyborg/tests/functional/api/test_api_samples.py":[{"author":{"_account_id":28006,"name":"teim-ci","display_name":"teim-ci","email":"ci@seanmooney.info","username":"ci-sean-mooney","status":"this is a third-party ci account run by sean-k-mooney on irc\nhosted at zuul.teim.app"},"tag":"autogenerated:zuul:automatic-ci","change_message_id":"9e20a2118acc1dea285e8bc1934ab54bf5867416","unresolved":false,"context_lines":[{"line_number":140,"context_line":"            os.path.join(SAMPLES_DIR, \u0027accelerator_requests\u0027,"},{"line_number":141,"context_line":"                         \u0027accelerator_requests-getone-resp.json\u0027))"},{"line_number":142,"context_line":""},{"line_number":143,"context_line":"    def test_arqs_before_update(self):"},{"line_number":144,"context_line":"        uuid \u003d self.test_data[\u0027arq\u0027][\u0027uuid\u0027]"},{"line_number":145,"context_line":"        self._check_sample("},{"line_number":146,"context_line":"            \u0027/v2/accelerator_requests/%s\u0027 % uuid,"}],"source_content_type":"text/x-python","patch_set":1,"id":"bb64158a_121e2591","line":143,"updated":"2026-06-24 23:10:00.000000000","message":"test_arqs_before_update is structurally identical to test_arqs_get_one. Both GET /v2/accelerator_requests/{uuid} with the same seeded data in \u0027Initial\u0027 state, and the sample files have identical key sets. Structural comparison ignores values, adding no coverage.\n\n**Severity**: SUGGESTION | **Confidence**: 0.9\n\n**Benefit**: Removing or differentiating this test reduces maintenance burden and makes the test suite\u0027s intent clearer. If the goal is to validate a pre-update ARQ structure, the test should seed an ARQ in a different state or hit a different endpoint to provide meaningful additional coverage.\n\n**Recommendation**:\nEither remove test_arqs_before_update as redundant, or differentiate it by seeding the ARQ in a \u0027Bound\u0027 or post-update state and using a sample that reflects that state\u0027s structure (e.g., non-null attach_handle fields).","commit_id":"6668d4e840edd5271b4c417ccd92d2db0a51b44b"},{"author":{"_account_id":28006,"name":"teim-ci","display_name":"teim-ci","email":"ci@seanmooney.info","username":"ci-sean-mooney","status":"this is a third-party ci account run by sean-k-mooney on irc\nhosted at zuul.teim.app"},"tag":"autogenerated:zuul:automatic-ci","change_message_id":"3c95be4e32bc2edadfaf789605559cc694defbd6","unresolved":false,"context_lines":[{"line_number":16,"context_line":"and compares the response *structure* (keys and value types) against"},{"line_number":17,"context_line":"the corresponding sample JSON file.  Values like UUIDs, timestamps,"},{"line_number":18,"context_line":"and URLs are ignored — only shape matters."},{"line_number":19,"context_line":""},{"line_number":20,"context_line":"Set GENERATE_SAMPLES\u003d1 to overwrite sample files with actual responses."},{"line_number":21,"context_line":"\"\"\""},{"line_number":22,"context_line":""}],"source_content_type":"text/x-python","patch_set":4,"id":"378f53fc_5fbbd626","line":19,"updated":"2026-06-25 20:26:34.000000000","message":"GENERATE_SAMPLES write path uses os.makedirs without exist_ok and computes the samples dir via four os.pardir levels relative to the test file.\n\n**Severity**: SUGGESTION | **Confidence**: 0.6\n\n**Benefit**: Coupling the path to directory depth is fragile, and os.makedirs(sample_dir) without exist_ok\u003dTrue raises if the dir already exists when regenerating a second sample in the same run.\n\n**Recommendation**:\nUse os.makedirs(sample_dir, exist_ok\u003dTrue) in the GENERATE_SAMPLES block of test_api_samples_base.py, and optionally centralize SAMPLES_DIR in common.py so the depth calculation lives in one place.","commit_id":"7400129897644343f7f51cfa943442dde9165b63"},{"author":{"_account_id":11604,"name":"sean mooney","email":"smooney@redhat.com","username":"sean-k-mooney"},"change_message_id":"f69f07fc2a54b1d7744e3e723d32c7652f582dc4","unresolved":true,"context_lines":[{"line_number":28,"context_line":""},{"line_number":29,"context_line":"SAMPLES_DIR \u003d os.path.join("},{"line_number":30,"context_line":"    os.path.dirname(__file__),"},{"line_number":31,"context_line":"    os.pardir,"},{"line_number":32,"context_line":"    os.pardir,"},{"line_number":33,"context_line":"    os.pardir,"},{"line_number":34,"context_line":"    os.pardir,"}],"source_content_type":"text/x-python","patch_set":6,"id":"815f8bf3_3a47d2d7","line":31,"range":{"start_line":31,"start_character":2,"end_line":31,"end_character":14},"updated":"2026-07-07 12:37:01.000000000","message":"nit: i wonder if there is a cleaner way to do this.\n\nis this `..` ? i asume yes so you using the fully quallifed directory name then walking up to the repo root and back down into the sampels dir.\n\nnova does effectivly the same.\n```\n    @classmethod\n    def _get_sample(cls, name, api_version\u003dNone):\n        dirname \u003d os.path.dirname(os.path.abspath(__file__))\n        dirname \u003d os.path.normpath(os.path.join(dirname,\n                                                \"../../../doc\"))\n        return cls._get_sample_path(name, dirname, api_version\u003dapi_version)\n```\nhttps://github.com/openstack/nova/blob/master/nova/tests/functional/api_samples_test_base.py#L112-L117\n\nos.pardir is i aguess more correct even if its less readable.","commit_id":"7edf57d8b318bcd45d11ee0fb76d74ba393c8193"},{"author":{"_account_id":4690,"name":"melanie witt","display_name":"melwitt","email":"melwittt@gmail.com","username":"melwitt"},"change_message_id":"39ad2b53760272161f45a8019ef09a76efa92448","unresolved":false,"context_lines":[{"line_number":28,"context_line":""},{"line_number":29,"context_line":"SAMPLES_DIR \u003d os.path.join("},{"line_number":30,"context_line":"    os.path.dirname(__file__),"},{"line_number":31,"context_line":"    os.pardir,"},{"line_number":32,"context_line":"    os.pardir,"},{"line_number":33,"context_line":"    os.pardir,"},{"line_number":34,"context_line":"    os.pardir,"}],"source_content_type":"text/x-python","patch_set":6,"id":"83835f65_f730d9c1","line":31,"range":{"start_line":31,"start_character":2,"end_line":31,"end_character":14},"in_reply_to":"1bdd5166_39469bb3","updated":"2026-07-08 15:52:42.000000000","message":"Done","commit_id":"7edf57d8b318bcd45d11ee0fb76d74ba393c8193"},{"author":{"_account_id":4690,"name":"melanie witt","display_name":"melwitt","email":"melwittt@gmail.com","username":"melwitt"},"change_message_id":"7ad6c5733d29f12e3e84ab61748c22315331abc5","unresolved":true,"context_lines":[{"line_number":28,"context_line":""},{"line_number":29,"context_line":"SAMPLES_DIR \u003d os.path.join("},{"line_number":30,"context_line":"    os.path.dirname(__file__),"},{"line_number":31,"context_line":"    os.pardir,"},{"line_number":32,"context_line":"    os.pardir,"},{"line_number":33,"context_line":"    os.pardir,"},{"line_number":34,"context_line":"    os.pardir,"}],"source_content_type":"text/x-python","patch_set":6,"id":"1bdd5166_39469bb3","line":31,"range":{"start_line":31,"start_character":2,"end_line":31,"end_character":14},"in_reply_to":"815f8bf3_3a47d2d7","updated":"2026-07-08 01:17:55.000000000","message":"Yeah it\u0027s \"parent directory\" but somehow \"pardir\" does not convey that too well IMHO. I\u0027ll try and make this nicer looking.","commit_id":"7edf57d8b318bcd45d11ee0fb76d74ba393c8193"},{"author":{"_account_id":11604,"name":"sean mooney","email":"smooney@redhat.com","username":"sean-k-mooney"},"change_message_id":"f69f07fc2a54b1d7744e3e723d32c7652f582dc4","unresolved":true,"context_lines":[{"line_number":33,"context_line":"    os.pardir,"},{"line_number":34,"context_line":"    os.pardir,"},{"line_number":35,"context_line":"    \u0027doc\u0027,"},{"line_number":36,"context_line":"    \u0027api_samples\u0027,"},{"line_number":37,"context_line":")"},{"line_number":38,"context_line":""},{"line_number":39,"context_line":""}],"source_content_type":"text/x-python","patch_set":6,"id":"03a9168f_c35922fb","line":36,"range":{"start_line":36,"start_character":17,"end_line":36,"end_character":18},"updated":"2026-07-07 12:37:01.000000000","message":"ideally you shoudl avoid addign this comman\nthat force on line per parmater","commit_id":"7edf57d8b318bcd45d11ee0fb76d74ba393c8193"},{"author":{"_account_id":4690,"name":"melanie witt","display_name":"melwitt","email":"melwittt@gmail.com","username":"melwitt"},"change_message_id":"39ad2b53760272161f45a8019ef09a76efa92448","unresolved":false,"context_lines":[{"line_number":33,"context_line":"    os.pardir,"},{"line_number":34,"context_line":"    os.pardir,"},{"line_number":35,"context_line":"    \u0027doc\u0027,"},{"line_number":36,"context_line":"    \u0027api_samples\u0027,"},{"line_number":37,"context_line":")"},{"line_number":38,"context_line":""},{"line_number":39,"context_line":""}],"source_content_type":"text/x-python","patch_set":6,"id":"46d0c91f_e84e6838","line":36,"range":{"start_line":36,"start_character":17,"end_line":36,"end_character":18},"in_reply_to":"03a9168f_c35922fb","updated":"2026-07-08 15:52:42.000000000","message":"Acknowledged","commit_id":"7edf57d8b318bcd45d11ee0fb76d74ba393c8193"},{"author":{"_account_id":34452,"name":"Joan Gilabert","display_name":"jgilaber","email":"jgilaber@redhat.com","username":"jgilaber"},"change_message_id":"4eff53a62bd3e8e027ac1690e6ff1d260349c0f0","unresolved":true,"context_lines":[{"line_number":36,"context_line":"    \u0027api_samples\u0027,"},{"line_number":37,"context_line":")"},{"line_number":38,"context_line":""},{"line_number":39,"context_line":""},{"line_number":40,"context_line":"class TestDeviceSamples(base.ApiSampleTestBase):"},{"line_number":41,"context_line":"    def setUp(self):"},{"line_number":42,"context_line":"        super().setUp()"}],"source_content_type":"text/x-python","patch_set":6,"id":"5d430ca4_2d8c2440","line":39,"updated":"2026-07-06 15:01:24.000000000","message":"the tests cases covered here seem to validate all the existing json samples, but I\u0027m thinking it might be good to add a couple of negative cases to sanity check the `_check_sample` and `_assert_structure_matches` methods, wdyt?","commit_id":"7edf57d8b318bcd45d11ee0fb76d74ba393c8193"},{"author":{"_account_id":34452,"name":"Joan Gilabert","display_name":"jgilaber","email":"jgilaber@redhat.com","username":"jgilaber"},"change_message_id":"6503f9905a1a1a94b050f7cb74ce8f66d1f83194","unresolved":false,"context_lines":[{"line_number":36,"context_line":"    \u0027api_samples\u0027,"},{"line_number":37,"context_line":")"},{"line_number":38,"context_line":""},{"line_number":39,"context_line":""},{"line_number":40,"context_line":"class TestDeviceSamples(base.ApiSampleTestBase):"},{"line_number":41,"context_line":"    def setUp(self):"},{"line_number":42,"context_line":"        super().setUp()"}],"source_content_type":"text/x-python","patch_set":6,"id":"8536a162_ab53d972","line":39,"in_reply_to":"59e55956_96affd10","updated":"2026-07-10 11:03:33.000000000","message":"Done","commit_id":"7edf57d8b318bcd45d11ee0fb76d74ba393c8193"},{"author":{"_account_id":11604,"name":"sean mooney","email":"smooney@redhat.com","username":"sean-k-mooney"},"change_message_id":"f69f07fc2a54b1d7744e3e723d32c7652f582dc4","unresolved":true,"context_lines":[{"line_number":36,"context_line":"    \u0027api_samples\u0027,"},{"line_number":37,"context_line":")"},{"line_number":38,"context_line":""},{"line_number":39,"context_line":""},{"line_number":40,"context_line":"class TestDeviceSamples(base.ApiSampleTestBase):"},{"line_number":41,"context_line":"    def setUp(self):"},{"line_number":42,"context_line":"        super().setUp()"}],"source_content_type":"text/x-python","patch_set":6,"id":"e2537ecf_a2c09468","line":39,"in_reply_to":"5d430ca4_2d8c2440","updated":"2026-07-07 12:37:01.000000000","message":"am we could but in that is really testing the tests not testign the code.\n\nso i would not add them to the samples dir or this file. i would test that in \n\ntest_api_samples_base and keep the negitive tests only there likly passing strings or a local sample test file relive to the test file","commit_id":"7edf57d8b318bcd45d11ee0fb76d74ba393c8193"},{"author":{"_account_id":4690,"name":"melanie witt","display_name":"melwitt","email":"melwittt@gmail.com","username":"melwitt"},"change_message_id":"39ad2b53760272161f45a8019ef09a76efa92448","unresolved":true,"context_lines":[{"line_number":36,"context_line":"    \u0027api_samples\u0027,"},{"line_number":37,"context_line":")"},{"line_number":38,"context_line":""},{"line_number":39,"context_line":""},{"line_number":40,"context_line":"class TestDeviceSamples(base.ApiSampleTestBase):"},{"line_number":41,"context_line":"    def setUp(self):"},{"line_number":42,"context_line":"        super().setUp()"}],"source_content_type":"text/x-python","patch_set":6,"id":"59e55956_96affd10","line":39,"in_reply_to":"e2537ecf_a2c09468","updated":"2026-07-08 15:52:42.000000000","message":"I have added tests for this here: https://review.opendev.org/c/openstack/cyborg/+/994830/7/cyborg/tests/functional/api/test_api_samples_base.py#134","commit_id":"7edf57d8b318bcd45d11ee0fb76d74ba393c8193"},{"author":{"_account_id":11604,"name":"sean mooney","email":"smooney@redhat.com","username":"sean-k-mooney"},"change_message_id":"f69f07fc2a54b1d7744e3e723d32c7652f582dc4","unresolved":true,"context_lines":[{"line_number":72,"context_line":"    def test_deployables_get_one(self):"},{"line_number":73,"context_line":"        uuid \u003d self.test_data[\u0027deployable\u0027][\u0027uuid\u0027]"},{"line_number":74,"context_line":"        self._check_sample("},{"line_number":75,"context_line":"            \u0027/v2/deployables/%s\u0027 % uuid,"},{"line_number":76,"context_line":"            os.path.join("},{"line_number":77,"context_line":"                SAMPLES_DIR, \u0027deployables\u0027, \u0027deployables-getone-resp.json\u0027"},{"line_number":78,"context_line":"            ),"}],"source_content_type":"text/x-python","patch_set":6,"id":"7d7ec532_af764052","line":75,"range":{"start_line":75,"start_character":12,"end_line":75,"end_character":40},"updated":"2026-07-07 12:37:01.000000000","message":"nit: we allow % formating currently but is there any reason not to perfer an fstring here","commit_id":"7edf57d8b318bcd45d11ee0fb76d74ba393c8193"},{"author":{"_account_id":4690,"name":"melanie witt","display_name":"melwitt","email":"melwittt@gmail.com","username":"melwitt"},"change_message_id":"7ad6c5733d29f12e3e84ab61748c22315331abc5","unresolved":true,"context_lines":[{"line_number":72,"context_line":"    def test_deployables_get_one(self):"},{"line_number":73,"context_line":"        uuid \u003d self.test_data[\u0027deployable\u0027][\u0027uuid\u0027]"},{"line_number":74,"context_line":"        self._check_sample("},{"line_number":75,"context_line":"            \u0027/v2/deployables/%s\u0027 % uuid,"},{"line_number":76,"context_line":"            os.path.join("},{"line_number":77,"context_line":"                SAMPLES_DIR, \u0027deployables\u0027, \u0027deployables-getone-resp.json\u0027"},{"line_number":78,"context_line":"            ),"}],"source_content_type":"text/x-python","patch_set":6,"id":"b17b1be5_fca59642","line":75,"range":{"start_line":75,"start_character":12,"end_line":75,"end_character":40},"in_reply_to":"7d7ec532_af764052","updated":"2026-07-08 01:17:55.000000000","message":"No particular reason. Will change to f-strings.","commit_id":"7edf57d8b318bcd45d11ee0fb76d74ba393c8193"},{"author":{"_account_id":4690,"name":"melanie witt","display_name":"melwitt","email":"melwittt@gmail.com","username":"melwitt"},"change_message_id":"39ad2b53760272161f45a8019ef09a76efa92448","unresolved":false,"context_lines":[{"line_number":72,"context_line":"    def test_deployables_get_one(self):"},{"line_number":73,"context_line":"        uuid \u003d self.test_data[\u0027deployable\u0027][\u0027uuid\u0027]"},{"line_number":74,"context_line":"        self._check_sample("},{"line_number":75,"context_line":"            \u0027/v2/deployables/%s\u0027 % uuid,"},{"line_number":76,"context_line":"            os.path.join("},{"line_number":77,"context_line":"                SAMPLES_DIR, \u0027deployables\u0027, \u0027deployables-getone-resp.json\u0027"},{"line_number":78,"context_line":"            ),"}],"source_content_type":"text/x-python","patch_set":6,"id":"01c661ea_631c0025","line":75,"range":{"start_line":75,"start_character":12,"end_line":75,"end_character":40},"in_reply_to":"b17b1be5_fca59642","updated":"2026-07-08 15:52:42.000000000","message":"Done","commit_id":"7edf57d8b318bcd45d11ee0fb76d74ba393c8193"},{"author":{"_account_id":11604,"name":"sean mooney","email":"smooney@redhat.com","username":"sean-k-mooney"},"change_message_id":"eb6c546a64095c98ebf4f9ee26681d6b35a41224","unresolved":true,"context_lines":[{"line_number":28,"context_line":""},{"line_number":29,"context_line":"SAMPLES_DIR \u003d os.path.normpath("},{"line_number":30,"context_line":"    os.path.join(os.path.dirname(__file__), \u0027../../../../doc/api_samples\u0027)"},{"line_number":31,"context_line":")"},{"line_number":32,"context_line":""},{"line_number":33,"context_line":""},{"line_number":34,"context_line":"class TestDeviceSamples(base.ApiSampleTestBase):"}],"source_content_type":"text/x-python","patch_set":7,"id":"b6560e34_b82cebf4","line":31,"updated":"2026-07-16 12:05:20.000000000","message":"thanks that a lott more readable\n\ni know its technial more correct to use the os contatns for the parent and seperator but this is just a lot simpler to grok","commit_id":"edce5fb28c9f39c0af95ba0729857586ca6bbc70"}],"cyborg/tests/functional/api/test_api_samples_base.py":[{"author":{"_account_id":28006,"name":"teim-ci","display_name":"teim-ci","email":"ci@seanmooney.info","username":"ci-sean-mooney","status":"this is a third-party ci account run by sean-k-mooney on irc\nhosted at zuul.teim.app"},"tag":"autogenerated:zuul:automatic-ci","change_message_id":"9e20a2118acc1dea285e8bc1934ab54bf5867416","unresolved":false,"context_lines":[{"line_number":58,"context_line":"            _assert_structure_matches("},{"line_number":59,"context_line":"                expected[key], actual[key], \u0027%s.%s\u0027 % (path, key))"},{"line_number":60,"context_line":"    elif type(expected) is list and type(actual) is list:"},{"line_number":61,"context_line":"        if expected and actual:"},{"line_number":62,"context_line":"            _assert_structure_matches("},{"line_number":63,"context_line":"                expected[0], actual[0], \u0027%s[0]\u0027 % path)"},{"line_number":64,"context_line":"    elif type(expected) is not type(actual):"}],"source_content_type":"text/x-python","patch_set":1,"id":"d46e36bb_7f541703","line":61,"updated":"2026-06-24 23:10:00.000000000","message":"The _assert_structure_matches function only compares list element [0] for lists. The device_profiles-list-resp.json sample has 2 entries with different group key structures (entry 0 has 3 trait keys, entry 1 has 2), but only entry 0 is ever validated against the actual response.\n\n**Severity**: SUGGESTION | **Confidence**: 0.9\n\n**Benefit**: Documenting this limitation or iterating over all list elements would catch structural drift in later list entries that the current approach misses.\n\n**Recommendation**:\nConsider adding a comment documenting that only the first list element is structurally compared (intentional for heterogeneous lists), or iterate over all elements when they exist. For the device_profiles case, ensure the sample\u0027s second entry reflects a real-world variant or remove it to avoid confusion.","commit_id":"6668d4e840edd5271b4c417ccd92d2db0a51b44b"},{"author":{"_account_id":28006,"name":"teim-ci","display_name":"teim-ci","email":"ci@seanmooney.info","username":"ci-sean-mooney","status":"this is a third-party ci account run by sean-k-mooney on irc\nhosted at zuul.teim.app"},"tag":"autogenerated:zuul:automatic-ci","change_message_id":"9e20a2118acc1dea285e8bc1934ab54bf5867416","unresolved":false,"context_lines":[{"line_number":97,"context_line":"        self.test_data.update(result)"},{"line_number":98,"context_line":""},{"line_number":99,"context_line":"    def seed_arqs(self):"},{"line_number":100,"context_line":"        self._agent_patcher \u003d mock.patch("},{"line_number":101,"context_line":"            \u0027cyborg.objects.ext_arq.AgentAPI\u0027, autospec\u003dFalse)"},{"line_number":102,"context_line":"        self._agent_patcher.start()"},{"line_number":103,"context_line":"        self.seed_device_profiles()"}],"source_content_type":"text/x-python","patch_set":1,"id":"65b81cd1_9b844263","line":100,"updated":"2026-06-24 23:10:00.000000000","message":"mock.patch for AgentAPI uses autospec\u003dFalse, disabling spec checking on the mock. This means typos in method names or wrong signatures on the mock will silently pass instead of raising at call time. The existing codebase has mixed autospec usage, but new code should follow the recommended practice.\n\n**Severity**: WARNING | **Confidence**: 0.8\n\n**Impact**: If the AgentAPI interface changes (new required methods, signature changes), this mock will not catch the mismatch, potentially masking real integration issues in functional tests.\n\n**Suggestion**:\nUse autospec\u003dTrue (the default recommendation) or omit the autospec parameter entirely. If autospec\u003dTrue causes issues with the AgentAPI class, document why autospec\u003dFalse is necessary. For example: mock.patch(\u0027cyborg.objects.ext_arq.AgentAPI\u0027, autospec\u003dTrue)","commit_id":"6668d4e840edd5271b4c417ccd92d2db0a51b44b"},{"author":{"_account_id":28006,"name":"teim-ci","display_name":"teim-ci","email":"ci@seanmooney.info","username":"ci-sean-mooney","status":"this is a third-party ci account run by sean-k-mooney on irc\nhosted at zuul.teim.app"},"tag":"autogenerated:zuul:automatic-ci","change_message_id":"c5a99028859b7923b0b3d047a345389f09d25f86","unresolved":false,"context_lines":[{"line_number":35,"context_line":""},{"line_number":36,"context_line":"    Checks that *expected* and *actual* have the same shape: identical"},{"line_number":37,"context_line":"    dict keys, matching value types, and consistent list-element"},{"line_number":38,"context_line":"    structure.  Scalar *values* (strings, numbers) are not compared —"},{"line_number":39,"context_line":"    only their types."},{"line_number":40,"context_line":""},{"line_number":41,"context_line":"    None/null in either position is treated as a wildcard that matches"}],"source_content_type":"text/x-python","patch_set":2,"id":"189e2870_774799e7","line":38,"updated":"2026-06-25 16:54:07.000000000","message":"The structural comparison for list responses requires exact list length match (len(expected) !\u003d len(actual)). This couples the number of seeded objects to the sample file entry count, making test data and samples tightly coupled.\n\n**Severity**: WARNING | **Confidence**: 0.7\n\n**Impact**: If someone adds a third device profile in seed_device_profiles(), the list test will fail with a confusing length mismatch rather than a structural error. The structural validation intent is to verify shape, not count, but the implementation conflates the two.\n\n**Suggestion**:\nConsider comparing only the first element\u0027s structure for list responses (or documenting that the count must match). If exact count matching is intentional for detecting added/removed items, add a comment explaining this design choice so future maintainers understand the coupling.","commit_id":"4201679d071af83523027f567fbc2515132a22b8"},{"author":{"_account_id":28006,"name":"teim-ci","display_name":"teim-ci","email":"ci@seanmooney.info","username":"ci-sean-mooney","status":"this is a third-party ci account run by sean-k-mooney on irc\nhosted at zuul.teim.app"},"tag":"autogenerated:zuul:automatic-ci","change_message_id":"c5a99028859b7923b0b3d047a345389f09d25f86","unresolved":false,"context_lines":[{"line_number":45,"context_line":"    \"\"\""},{"line_number":46,"context_line":"    if expected is None or actual is None:"},{"line_number":47,"context_line":"        return"},{"line_number":48,"context_line":""},{"line_number":49,"context_line":"    if type(expected) is dict and type(actual) is dict:"},{"line_number":50,"context_line":"        expected_keys \u003d set(expected.keys())"},{"line_number":51,"context_line":"        actual_keys \u003d set(actual.keys())"}],"source_content_type":"text/x-python","patch_set":2,"id":"f6890496_e82a6fb5","line":48,"updated":"2026-06-25 16:54:07.000000000","message":"ApiSampleTestBase.setUp() does not reset global Pecan configuration after tests. The existing unit test base (cyborg/tests/unit/api/base.py) explicitly calls pecan.set_config({}, overwrite\u003dTrue) in addCleanup after load_test_app, but the new functional base omits this.\n\n**Severity**: HIGH | **Confidence**: 0.8\n\n**Risk**: pecan.testing.load_test_app() sets global Pecan configuration state. Without resetting it in tearDown/addCleanup, this state leaks across test modules, potentially causing failures in other test classes that assume default Pecan configuration.\n\n**Priority**: Before merge\n**Why This Matters**: The existing BaseApiTest pattern (unit/api/base.py lines 44-46) was specifically designed to clean up Pecan global state. The new functional base should follow the same pattern to avoid test pollution when functional and unit tests run in the same stestr session.\n\n**Recommendation**:\nAdd cleanup after self.app \u003d common.make_app() in setUp: self.addCleanup(lambda: pecan.set_config({}, overwrite\u003dTrue)). Import pecan at the top of test_api_samples_base.py.","commit_id":"4201679d071af83523027f567fbc2515132a22b8"},{"author":{"_account_id":28006,"name":"teim-ci","display_name":"teim-ci","email":"ci@seanmooney.info","username":"ci-sean-mooney","status":"this is a third-party ci account run by sean-k-mooney on irc\nhosted at zuul.teim.app"},"tag":"autogenerated:zuul:automatic-ci","change_message_id":"c5a99028859b7923b0b3d047a345389f09d25f86","unresolved":false,"context_lines":[{"line_number":50,"context_line":"        expected_keys \u003d set(expected.keys())"},{"line_number":51,"context_line":"        actual_keys \u003d set(actual.keys())"},{"line_number":52,"context_line":"        missing \u003d expected_keys - actual_keys"},{"line_number":53,"context_line":"        extra \u003d actual_keys - expected_keys"},{"line_number":54,"context_line":"        if missing:"},{"line_number":55,"context_line":"            raise AssertionError("},{"line_number":56,"context_line":"                \u0027%s: missing keys in response: %s\u0027 % (path, missing)"}],"source_content_type":"text/x-python","patch_set":2,"id":"2c3117a6_7fb7f724","line":53,"updated":"2026-06-25 16:54:07.000000000","message":"The seed_arqs() method in test_api_samples_base.py sets self._agent_patcher but the tearDown() uses hasattr() to check for it. A cleaner pattern would be to always set it to None in setUp or use addCleanup.\n\n**Severity**: SUGGESTION | **Confidence**: 0.7\n\n**Benefit**: Using addCleanup(self._agent_patcher.stop) in seed_arqs() instead of hasattr-checking in tearDown() eliminates the conditional teardown logic and ensures cleanup always runs for tests that mock the agent API.\n\n**Recommendation**:\nIn seed_arqs(), after self._agent_patcher.start(), add self.addCleanup(self._agent_patcher.stop). Then remove the hasattr check from tearDown(). This follows the addCleanup pattern recommended by the previous issue as well.","commit_id":"4201679d071af83523027f567fbc2515132a22b8"},{"author":{"_account_id":28006,"name":"teim-ci","display_name":"teim-ci","email":"ci@seanmooney.info","username":"ci-sean-mooney","status":"this is a third-party ci account run by sean-k-mooney on irc\nhosted at zuul.teim.app"},"tag":"autogenerated:zuul:automatic-ci","change_message_id":"c5a99028859b7923b0b3d047a345389f09d25f86","unresolved":false,"context_lines":[{"line_number":160,"context_line":"                \u0027%s\\nSample path: %s\u0027 % (e, os.path.normpath(sample_path))"},{"line_number":161,"context_line":"            )"},{"line_number":162,"context_line":""},{"line_number":163,"context_line":"    def tearDown(self):"},{"line_number":164,"context_line":"        if hasattr(self, \u0027_agent_patcher\u0027):"},{"line_number":165,"context_line":"            self._agent_patcher.stop()"},{"line_number":166,"context_line":"        self._policy.cleanUp()"}],"source_content_type":"text/x-python","patch_set":2,"id":"3e16e281_5b711f7e","line":163,"updated":"2026-06-25 16:54:07.000000000","message":"tearDown() calls cleanUp() on fixtures in manual order instead of using addCleanup, which is fragile: if any cleanUp() raises, remaining fixtures leak and subsequent tests may fail with confusing errors.\n\n**Severity**: HIGH | **Confidence**: 0.8\n\n**Risk**: If _ef.cleanUp() or _policy.cleanUp() raises an exception, the subsequent cleanUp() calls are skipped, leaving global CONF state polluted for the next test. This can cause cascading test failures that are hard to debug.\n\n**Priority**: Before merge\n**Why This Matters**: Fixture teardown ordering bugs are a common source of flaky functional test suites. The oslotest/fixtures library strongly recommends addCleanup over manual tearDown chains precisely to avoid this.\n\n**Recommendation**:\nRegister each cleanup in setUp using self.addCleanup() instead of a manual tearDown chain. For example: self.addCleanup(self._policy.cleanUp) immediately after self._policy \u003d common.setup_policy(). This ensures all cleanups run even if one fails. Alternatively, use self.useFixture() for fixtures that support it.","commit_id":"4201679d071af83523027f567fbc2515132a22b8"},{"author":{"_account_id":28006,"name":"teim-ci","display_name":"teim-ci","email":"ci@seanmooney.info","username":"ci-sean-mooney","status":"this is a third-party ci account run by sean-k-mooney on irc\nhosted at zuul.teim.app"},"tag":"autogenerated:zuul:automatic-ci","change_message_id":"160f95bc02f6ff1387bdd9cbe13057b8dccc8d28","unresolved":false,"context_lines":[{"line_number":123,"context_line":"        self.test_data.update(result)"},{"line_number":124,"context_line":""},{"line_number":125,"context_line":"    def seed_arqs(self):"},{"line_number":126,"context_line":"        patcher \u003d mock.patch(\u0027cyborg.objects.ext_arq.AgentAPI\u0027)"},{"line_number":127,"context_line":"        patcher.start()"},{"line_number":128,"context_line":"        self.addCleanup(patcher.stop)"},{"line_number":129,"context_line":"        self.seed_device_profiles()"}],"source_content_type":"text/x-python","patch_set":3,"id":"933d3617_c6d9e628","line":126,"updated":"2026-06-25 18:39:45.000000000","message":"The mock.patch in seed_arqs uses mock.patch(\u0027cyborg.objects.ext_arq.AgentAPI\u0027) without autospec\u003dTrue. Project guidelines recommend autospec\u003dTrue for new code to catch interface mismatches.\n\n**Severity**: SUGGESTION | **Confidence**: 0.8\n\n**Benefit**: Using autospec\u003dTrue ensures the mock validates attribute access against the real AgentAPI class interface, catching typos or interface changes at test time.\n\n**Recommendation**:\nChange to mock.patch(\u0027cyborg.objects.ext_arq.AgentAPI\u0027, autospec\u003dTrue) for interface safety. Since this is new code, following the recommended practice is appropriate.","commit_id":"12891c37320ee48b3316724b0ce277a3355740f6"},{"author":{"_account_id":28006,"name":"teim-ci","display_name":"teim-ci","email":"ci@seanmooney.info","username":"ci-sean-mooney","status":"this is a third-party ci account run by sean-k-mooney on irc\nhosted at zuul.teim.app"},"tag":"autogenerated:zuul:automatic-ci","change_message_id":"3c95be4e32bc2edadfaf789605559cc694defbd6","unresolved":false,"context_lines":[{"line_number":45,"context_line":""},{"line_number":46,"context_line":"    List comparison is order-independent (same approach as Nova\u0027s"},{"line_number":47,"context_line":"    api_samples_test_base): each actual element is greedily paired"},{"line_number":48,"context_line":"    with a structurally matching expected element."},{"line_number":49,"context_line":""},{"line_number":50,"context_line":"    Raises AssertionError with a JSONPath-style breadcrumb on mismatch."},{"line_number":51,"context_line":"    \"\"\""}],"source_content_type":"text/x-python","patch_set":4,"id":"1a975252_76fa58bc","line":48,"updated":"2026-06-25 20:26:34.000000000","message":"_assert_structure_matches treats any None in either expected or actual as a wildcard that matches everything and returns immediately, skipping key/type checks beneath that node.\n\n**Severity**: SUGGESTION | **Confidence**: 0.7\n\n**Benefit**: When a sample deliberately uses null for an optional field whose actual value is a dict/list, the comparison would no longer verify the nested structure, weakening drift detection at exactly the fields most prone to schema change.\n\n**Recommendation**:\nConsider narrowing the wildcard so None matches only scalar positions, or document explicitly in the docstring that null samples intentionally disable subtree checking. For these samples the current values are scalars so impact is low, but a comment would prevent future drift being silently hidden.","commit_id":"7400129897644343f7f51cfa943442dde9165b63"},{"author":{"_account_id":28006,"name":"teim-ci","display_name":"teim-ci","email":"ci@seanmooney.info","username":"ci-sean-mooney","status":"this is a third-party ci account run by sean-k-mooney on irc\nhosted at zuul.teim.app"},"tag":"autogenerated:zuul:automatic-ci","change_message_id":"79573af5aa3e66bd3ad920cad0da79696b53a1e9","unresolved":false,"context_lines":[{"line_number":52,"context_line":"    if expected is None or actual is None:"},{"line_number":53,"context_line":"        return"},{"line_number":54,"context_line":""},{"line_number":55,"context_line":"    if type(expected) is dict and type(actual) is dict:"},{"line_number":56,"context_line":"        expected_keys \u003d set(expected.keys())"},{"line_number":57,"context_line":"        actual_keys \u003d set(actual.keys())"},{"line_number":58,"context_line":"        missing \u003d expected_keys - actual_keys"}],"source_content_type":"text/x-python","patch_set":5,"id":"1cc0d04a_e2135b55","line":55,"updated":"2026-06-25 20:52:44.000000000","message":"The _assert_structure_matches function uses identity comparison (type(expected) is dict) instead of isinstance. This is intentional for strict structural matching and correctly distinguishes bool from int, but warrants a comment explaining the choice.\n\n**Severity**: SUGGESTION | **Confidence**: 0.9\n\n**Benefit**: Adding a one-line comment (e.g., \u0027# Use type() identity, not isinstance, so bool !\u003d int and dict subclasses do not silently match\u0027) prevents future maintainers from \u0027fixing\u0027 this to isinstance, which would introduce bool/int false matches.\n\n**Recommendation**:\nAdd a brief inline comment near the type() comparisons (lines 55, 72, 107) explaining that identity comparison is intentional: it ensures bool values do not match int samples, and prevents dict subclasses from matching.","commit_id":"1a9c396706c15e01c3409d925ad8b017e7785636"},{"author":{"_account_id":11604,"name":"sean mooney","email":"smooney@redhat.com","username":"sean-k-mooney"},"change_message_id":"f69f07fc2a54b1d7744e3e723d32c7652f582dc4","unresolved":true,"context_lines":[{"line_number":24,"context_line":"from cyborg.tests.functional.fixtures import capture"},{"line_number":25,"context_line":"from cyborg.tests.functional.fixtures import common"},{"line_number":26,"context_line":""},{"line_number":27,"context_line":""},{"line_number":28,"context_line":"GENERATE_SAMPLES \u003d os.environ.get(\u0027GENERATE_SAMPLES\u0027, \u0027\u0027).lower() in ("},{"line_number":29,"context_line":"    \u00271\u0027,"},{"line_number":30,"context_line":"    \u0027true\u0027,"},{"line_number":31,"context_line":"    \u0027yes\u0027,"},{"line_number":32,"context_line":")"},{"line_number":33,"context_line":""},{"line_number":34,"context_line":""},{"line_number":35,"context_line":"def _assert_structure_matches(expected, actual, path\u003d\u0027$\u0027):"}],"source_content_type":"text/x-python","patch_set":6,"id":"8332a0c6_81712306","line":32,"range":{"start_line":27,"start_character":1,"end_line":32,"end_character":1},"updated":"2026-07-07 12:37:01.000000000","message":"that works although i woudl be tempted to use oslo.utils bool_from_string fuction\n\n\n```suggestion\nfrom oslo_utils import strutils\n\nGENERATE_SAMPLES \u003d strutils.bool_from_string(\n    os.environ.get(\u0027GENERATE_SAMPLES\u0027, \u0027n\u0027).lower())\n```","commit_id":"7edf57d8b318bcd45d11ee0fb76d74ba393c8193"},{"author":{"_account_id":4690,"name":"melanie witt","display_name":"melwitt","email":"melwittt@gmail.com","username":"melwitt"},"change_message_id":"39ad2b53760272161f45a8019ef09a76efa92448","unresolved":false,"context_lines":[{"line_number":24,"context_line":"from cyborg.tests.functional.fixtures import capture"},{"line_number":25,"context_line":"from cyborg.tests.functional.fixtures import common"},{"line_number":26,"context_line":""},{"line_number":27,"context_line":""},{"line_number":28,"context_line":"GENERATE_SAMPLES \u003d os.environ.get(\u0027GENERATE_SAMPLES\u0027, \u0027\u0027).lower() in ("},{"line_number":29,"context_line":"    \u00271\u0027,"},{"line_number":30,"context_line":"    \u0027true\u0027,"},{"line_number":31,"context_line":"    \u0027yes\u0027,"},{"line_number":32,"context_line":")"},{"line_number":33,"context_line":""},{"line_number":34,"context_line":""},{"line_number":35,"context_line":"def _assert_structure_matches(expected, actual, path\u003d\u0027$\u0027):"}],"source_content_type":"text/x-python","patch_set":6,"id":"2170132d_b6783945","line":32,"range":{"start_line":27,"start_character":1,"end_line":32,"end_character":1},"in_reply_to":"8332a0c6_81712306","updated":"2026-07-08 15:52:42.000000000","message":"Done","commit_id":"7edf57d8b318bcd45d11ee0fb76d74ba393c8193"},{"author":{"_account_id":28006,"name":"teim-ci","display_name":"teim-ci","email":"ci@seanmooney.info","username":"ci-sean-mooney","status":"this is a third-party ci account run by sean-k-mooney on irc\nhosted at zuul.teim.app"},"tag":"autogenerated:zuul:automatic-ci","change_message_id":"03e903a53dd8d25cb8970306fca9cca7abe35944","unresolved":false,"context_lines":[{"line_number":80,"context_line":"        # Order-independent matching, like Nova\u0027s _compare_result:"},{"line_number":81,"context_line":"        # greedily pair each actual element with a structurally"},{"line_number":82,"context_line":"        # matching expected element."},{"line_number":83,"context_line":"        remaining \u003d list(expected)"},{"line_number":84,"context_line":"        extra \u003d []"},{"line_number":85,"context_line":"        for act_obj in actual:"},{"line_number":86,"context_line":"            for i, exp_obj in enumerate(remaining):"}],"source_content_type":"text/x-python","patch_set":6,"id":"85d76c10_b66f60b6","line":83,"updated":"2026-06-25 22:16:20.000000000","message":"The greedy order-independent list matching in _assert_structure_matches uses O(n^2) nested iteration: for each actual element it scans all remaining expected elements. For API response lists this is negligible, but a comment noting the complexity trade-off (intentional, mirrors Nova) would help future maintainers.\n\n**Severity**: SUGGESTION | **Confidence**: 0.8\n\n**Benefit**: Documents the deliberate complexity trade-off so future maintainers understand this is the same proven approach from Nova and not an oversight, preventing unnecessary optimization refactors.\n\n**Recommendation**:\nNo code change needed. The existing comment on lines 80-82 already references Nova _compare_result. Consider adding a brief note that the O(n^2) cost is acceptable for small list sizes typical of API responses.","commit_id":"7edf57d8b318bcd45d11ee0fb76d74ba393c8193"},{"author":{"_account_id":4690,"name":"melanie witt","display_name":"melwitt","email":"melwittt@gmail.com","username":"melwitt"},"change_message_id":"39ad2b53760272161f45a8019ef09a76efa92448","unresolved":false,"context_lines":[{"line_number":80,"context_line":"        # Order-independent matching, like Nova\u0027s _compare_result:"},{"line_number":81,"context_line":"        # greedily pair each actual element with a structurally"},{"line_number":82,"context_line":"        # matching expected element."},{"line_number":83,"context_line":"        remaining \u003d list(expected)"},{"line_number":84,"context_line":"        extra \u003d []"},{"line_number":85,"context_line":"        for act_obj in actual:"},{"line_number":86,"context_line":"            for i, exp_obj in enumerate(remaining):"}],"source_content_type":"text/x-python","patch_set":6,"id":"88dd9d11_9a09c75a","line":83,"in_reply_to":"3ce3b679_3ab36dd8","updated":"2026-07-08 15:52:42.000000000","message":"Done","commit_id":"7edf57d8b318bcd45d11ee0fb76d74ba393c8193"},{"author":{"_account_id":11604,"name":"sean mooney","email":"smooney@redhat.com","username":"sean-k-mooney"},"change_message_id":"5c65011095ac22902cadb377a9871a4888317a41","unresolved":true,"context_lines":[{"line_number":80,"context_line":"        # Order-independent matching, like Nova\u0027s _compare_result:"},{"line_number":81,"context_line":"        # greedily pair each actual element with a structurally"},{"line_number":82,"context_line":"        # matching expected element."},{"line_number":83,"context_line":"        remaining \u003d list(expected)"},{"line_number":84,"context_line":"        extra \u003d []"},{"line_number":85,"context_line":"        for act_obj in actual:"},{"line_number":86,"context_line":"            for i, exp_obj in enumerate(remaining):"}],"source_content_type":"text/x-python","patch_set":6,"id":"8fd8df4e_9d24ee98","line":83,"in_reply_to":"85d76c10_b66f60b6","updated":"2026-07-07 12:51:55.000000000","message":"so this seams very complx.\n\nim inclide to say that we shoudl jsut do json.dumps with sort_keys\u003dtrue and then to self.assertEqual on teh result.\n\nalthough brainstomign this a bit with ai gemini suggests\n\nadding\n```\nimport json\n\ndef to_canonical(obj):\n    \"\"\"Deeply normalizes a JSON-like structure so lists are sorted deterministically.\"\"\"\n    if isinstance(obj, dict):\n        return {k: to_canonical(v) for k, v in obj.items()}\n    if isinstance(obj, list):\n        # Recursively normalize children, then sort them by their JSON string representation\n        normalized_list \u003d [to_canonical(x) for x in obj]\n        return sorted(normalized_list, key\u003dlambda x: json.dumps(x, sort_keys\u003dTrue))\n    return obj\n```\n\nand instead doing \n\n```\ndef test_json_payload(self):\n        expected \u003d {\n            \"status\": \"success\",\n            \"roles\": [\"admin\", \"user\"],\n            \"data\": [{\"id\": 2, \"name\": \"Bob\"}, {\"id\": 1, \"name\": \"Alice\"}]\n        }\n        \n        actual \u003d {\n            \"roles\": [\"user\", \"admin\"],  # Different order\n            \"status\": \"success\",\n            \"data\": [{\"id\": 1, \"name\": \"Alice\"}, {\"id\": 2, \"name\": \"Bob\"}]  # Different order\n        }\n        \n        # Standard assertEqual works perfectly once data is canonicalized\n        self.assertEqual(to_canonical(expected), to_canonical(actual)\n```\n\nthat does more then just assert the types and keys are present but do we really need to ignore the values of those keys in these tests?","commit_id":"7edf57d8b318bcd45d11ee0fb76d74ba393c8193"},{"author":{"_account_id":4690,"name":"melanie witt","display_name":"melwitt","email":"melwittt@gmail.com","username":"melwitt"},"change_message_id":"7ad6c5733d29f12e3e84ab61748c22315331abc5","unresolved":true,"context_lines":[{"line_number":80,"context_line":"        # Order-independent matching, like Nova\u0027s _compare_result:"},{"line_number":81,"context_line":"        # greedily pair each actual element with a structurally"},{"line_number":82,"context_line":"        # matching expected element."},{"line_number":83,"context_line":"        remaining \u003d list(expected)"},{"line_number":84,"context_line":"        extra \u003d []"},{"line_number":85,"context_line":"        for act_obj in actual:"},{"line_number":86,"context_line":"            for i, exp_obj in enumerate(remaining):"}],"source_content_type":"text/x-python","patch_set":6,"id":"3ce3b679_3ab36dd8","line":83,"in_reply_to":"8fd8df4e_9d24ee98","updated":"2026-07-08 01:17:55.000000000","message":"Yeah ... fair point. Let me try to make this simpler. Avoiding the values comparison is so that the seeding data did not have to be a hard-coded exact match for UUIDs and timestamps etc.","commit_id":"7edf57d8b318bcd45d11ee0fb76d74ba393c8193"},{"author":{"_account_id":11604,"name":"sean mooney","email":"smooney@redhat.com","username":"sean-k-mooney"},"change_message_id":"f69f07fc2a54b1d7744e3e723d32c7652f582dc4","unresolved":true,"context_lines":[{"line_number":113,"context_line":"        )"},{"line_number":114,"context_line":""},{"line_number":115,"context_line":""},{"line_number":116,"context_line":"class ApiSampleTestBase(unittest.TestCase):"},{"line_number":117,"context_line":"    \"\"\"Functional test base that boots a real Pecan app against SQLite.\"\"\""},{"line_number":118,"context_line":""},{"line_number":119,"context_line":"    def setUp(self):"}],"source_content_type":"text/x-python","patch_set":6,"id":"b86fbbf8_096b1c1b","line":116,"range":{"start_line":116,"start_character":23,"end_line":116,"end_character":41},"updated":"2026-07-07 12:37:01.000000000","message":"so we really should be using cybrogs base test class here\nhttps://github.com/openstack/cyborg/blob/master/cyborg/tests/base.py#L43\n\nthen if there is common base test setup for funtional tests add a functional base as an intermediary. \n\nthe base test class fo our test in general shousl alos be oslo.test not unittest.TestCase","commit_id":"7edf57d8b318bcd45d11ee0fb76d74ba393c8193"},{"author":{"_account_id":4690,"name":"melanie witt","display_name":"melwitt","email":"melwittt@gmail.com","username":"melwitt"},"change_message_id":"39ad2b53760272161f45a8019ef09a76efa92448","unresolved":false,"context_lines":[{"line_number":113,"context_line":"        )"},{"line_number":114,"context_line":""},{"line_number":115,"context_line":""},{"line_number":116,"context_line":"class ApiSampleTestBase(unittest.TestCase):"},{"line_number":117,"context_line":"    \"\"\"Functional test base that boots a real Pecan app against SQLite.\"\"\""},{"line_number":118,"context_line":""},{"line_number":119,"context_line":"    def setUp(self):"}],"source_content_type":"text/x-python","patch_set":6,"id":"804765d0_df660ee8","line":116,"range":{"start_line":116,"start_character":23,"end_line":116,"end_character":41},"in_reply_to":"6ec4965f_4ce4f7d2","updated":"2026-07-08 15:52:42.000000000","message":"Done","commit_id":"7edf57d8b318bcd45d11ee0fb76d74ba393c8193"},{"author":{"_account_id":4690,"name":"melanie witt","display_name":"melwitt","email":"melwittt@gmail.com","username":"melwitt"},"change_message_id":"7ad6c5733d29f12e3e84ab61748c22315331abc5","unresolved":true,"context_lines":[{"line_number":113,"context_line":"        )"},{"line_number":114,"context_line":""},{"line_number":115,"context_line":""},{"line_number":116,"context_line":"class ApiSampleTestBase(unittest.TestCase):"},{"line_number":117,"context_line":"    \"\"\"Functional test base that boots a real Pecan app against SQLite.\"\"\""},{"line_number":118,"context_line":""},{"line_number":119,"context_line":"    def setUp(self):"}],"source_content_type":"text/x-python","patch_set":6,"id":"6ec4965f_4ce4f7d2","line":116,"range":{"start_line":116,"start_character":23,"end_line":116,"end_character":41},"in_reply_to":"b86fbbf8_096b1c1b","updated":"2026-07-08 01:17:55.000000000","message":"Good point, will update it.","commit_id":"7edf57d8b318bcd45d11ee0fb76d74ba393c8193"},{"author":{"_account_id":11604,"name":"sean mooney","email":"smooney@redhat.com","username":"sean-k-mooney"},"change_message_id":"f69f07fc2a54b1d7744e3e723d32c7652f582dc4","unresolved":true,"context_lines":[{"line_number":119,"context_line":"    def setUp(self):"},{"line_number":120,"context_line":"        super().setUp()"},{"line_number":121,"context_line":"        self.test_data \u003d {}"},{"line_number":122,"context_line":""},{"line_number":123,"context_line":"        self._logging \u003d capture.Logging()"},{"line_number":124,"context_line":"        self._logging.setUp()"},{"line_number":125,"context_line":"        self.addCleanup(self._logging.cleanUp)"},{"line_number":126,"context_line":""},{"line_number":127,"context_line":"        self._warnings \u003d capture.WarningsFixture()"},{"line_number":128,"context_line":"        self._warnings.setUp()"},{"line_number":129,"context_line":"        self.addCleanup(self._warnings.cleanUp)"},{"line_number":130,"context_line":""},{"line_number":131,"context_line":"        self._conf \u003d common.setup_config()"},{"line_number":132,"context_line":"        self.addCleanup(self._conf.cleanUp)"},{"line_number":133,"context_line":""},{"line_number":134,"context_line":"        self._db, self._ef \u003d common.setup_database()"},{"line_number":135,"context_line":"        self.addCleanup(self._ef.cleanUp)"},{"line_number":136,"context_line":""},{"line_number":137,"context_line":"        self._policy \u003d common.setup_policy()"},{"line_number":138,"context_line":"        self.addCleanup(self._policy.cleanUp)"},{"line_number":139,"context_line":""},{"line_number":140,"context_line":"        self.app \u003d common.make_app()"},{"line_number":141,"context_line":"        self.addCleanup(pecan.set_config, {}, overwrite\u003dTrue)"}],"source_content_type":"text/x-python","patch_set":6,"id":"e95dd986_643ca3f7","line":138,"range":{"start_line":122,"start_character":1,"end_line":138,"end_character":45},"updated":"2026-07-07 12:37:01.000000000","message":"```\n        self._logging \u003d self.useFixture(capture.Logging())\n        self._warnings \u003d self.useFixture(capture.WarningsFixture())\n        ...\n```","commit_id":"7edf57d8b318bcd45d11ee0fb76d74ba393c8193"},{"author":{"_account_id":4690,"name":"melanie witt","display_name":"melwitt","email":"melwittt@gmail.com","username":"melwitt"},"change_message_id":"39ad2b53760272161f45a8019ef09a76efa92448","unresolved":false,"context_lines":[{"line_number":119,"context_line":"    def setUp(self):"},{"line_number":120,"context_line":"        super().setUp()"},{"line_number":121,"context_line":"        self.test_data \u003d {}"},{"line_number":122,"context_line":""},{"line_number":123,"context_line":"        self._logging \u003d capture.Logging()"},{"line_number":124,"context_line":"        self._logging.setUp()"},{"line_number":125,"context_line":"        self.addCleanup(self._logging.cleanUp)"},{"line_number":126,"context_line":""},{"line_number":127,"context_line":"        self._warnings \u003d capture.WarningsFixture()"},{"line_number":128,"context_line":"        self._warnings.setUp()"},{"line_number":129,"context_line":"        self.addCleanup(self._warnings.cleanUp)"},{"line_number":130,"context_line":""},{"line_number":131,"context_line":"        self._conf \u003d common.setup_config()"},{"line_number":132,"context_line":"        self.addCleanup(self._conf.cleanUp)"},{"line_number":133,"context_line":""},{"line_number":134,"context_line":"        self._db, self._ef \u003d common.setup_database()"},{"line_number":135,"context_line":"        self.addCleanup(self._ef.cleanUp)"},{"line_number":136,"context_line":""},{"line_number":137,"context_line":"        self._policy \u003d common.setup_policy()"},{"line_number":138,"context_line":"        self.addCleanup(self._policy.cleanUp)"},{"line_number":139,"context_line":""},{"line_number":140,"context_line":"        self.app \u003d common.make_app()"},{"line_number":141,"context_line":"        self.addCleanup(pecan.set_config, {}, overwrite\u003dTrue)"}],"source_content_type":"text/x-python","patch_set":6,"id":"40e1801b_b5c3bf58","line":138,"range":{"start_line":122,"start_character":1,"end_line":138,"end_character":45},"in_reply_to":"e95dd986_643ca3f7","updated":"2026-07-08 15:52:42.000000000","message":"Done","commit_id":"7edf57d8b318bcd45d11ee0fb76d74ba393c8193"},{"author":{"_account_id":11604,"name":"sean mooney","email":"smooney@redhat.com","username":"sean-k-mooney"},"change_message_id":"f69f07fc2a54b1d7744e3e723d32c7652f582dc4","unresolved":true,"context_lines":[{"line_number":119,"context_line":"    def setUp(self):"},{"line_number":120,"context_line":"        super().setUp()"},{"line_number":121,"context_line":"        self.test_data \u003d {}"},{"line_number":122,"context_line":""},{"line_number":123,"context_line":"        self._logging \u003d capture.Logging()"},{"line_number":124,"context_line":"        self._logging.setUp()"},{"line_number":125,"context_line":"        self.addCleanup(self._logging.cleanUp)"},{"line_number":126,"context_line":""},{"line_number":127,"context_line":"        self._warnings \u003d capture.WarningsFixture()"},{"line_number":128,"context_line":"        self._warnings.setUp()"},{"line_number":129,"context_line":"        self.addCleanup(self._warnings.cleanUp)"},{"line_number":130,"context_line":""},{"line_number":131,"context_line":"        self._conf \u003d common.setup_config()"},{"line_number":132,"context_line":"        self.addCleanup(self._conf.cleanUp)"},{"line_number":133,"context_line":""},{"line_number":134,"context_line":"        self._db, self._ef \u003d common.setup_database()"},{"line_number":135,"context_line":"        self.addCleanup(self._ef.cleanUp)"},{"line_number":136,"context_line":""},{"line_number":137,"context_line":"        self._policy \u003d common.setup_policy()"},{"line_number":138,"context_line":"        self.addCleanup(self._policy.cleanUp)"},{"line_number":139,"context_line":""},{"line_number":140,"context_line":"        self.app \u003d common.make_app()"},{"line_number":141,"context_line":"        self.addCleanup(pecan.set_config, {}, overwrite\u003dTrue)"},{"line_number":142,"context_line":""},{"line_number":143,"context_line":"        self._ctx \u003d cyborg_context.get_admin_context()"},{"line_number":144,"context_line":""},{"line_number":145,"context_line":"    def seed_devices(self):"}],"source_content_type":"text/x-python","patch_set":6,"id":"cd48417f_a1527a17","line":142,"range":{"start_line":122,"start_character":1,"end_line":142,"end_character":1},"updated":"2026-07-07 12:37:01.000000000","message":"this is also not realy correct you shoudl be using self.useFixture()\nfor each of these fixtures that wont work because of the current pareent test case i belive but we shoudl fix this.","commit_id":"7edf57d8b318bcd45d11ee0fb76d74ba393c8193"},{"author":{"_account_id":4690,"name":"melanie witt","display_name":"melwitt","email":"melwittt@gmail.com","username":"melwitt"},"change_message_id":"39ad2b53760272161f45a8019ef09a76efa92448","unresolved":false,"context_lines":[{"line_number":119,"context_line":"    def setUp(self):"},{"line_number":120,"context_line":"        super().setUp()"},{"line_number":121,"context_line":"        self.test_data \u003d {}"},{"line_number":122,"context_line":""},{"line_number":123,"context_line":"        self._logging \u003d capture.Logging()"},{"line_number":124,"context_line":"        self._logging.setUp()"},{"line_number":125,"context_line":"        self.addCleanup(self._logging.cleanUp)"},{"line_number":126,"context_line":""},{"line_number":127,"context_line":"        self._warnings \u003d capture.WarningsFixture()"},{"line_number":128,"context_line":"        self._warnings.setUp()"},{"line_number":129,"context_line":"        self.addCleanup(self._warnings.cleanUp)"},{"line_number":130,"context_line":""},{"line_number":131,"context_line":"        self._conf \u003d common.setup_config()"},{"line_number":132,"context_line":"        self.addCleanup(self._conf.cleanUp)"},{"line_number":133,"context_line":""},{"line_number":134,"context_line":"        self._db, self._ef \u003d common.setup_database()"},{"line_number":135,"context_line":"        self.addCleanup(self._ef.cleanUp)"},{"line_number":136,"context_line":""},{"line_number":137,"context_line":"        self._policy \u003d common.setup_policy()"},{"line_number":138,"context_line":"        self.addCleanup(self._policy.cleanUp)"},{"line_number":139,"context_line":""},{"line_number":140,"context_line":"        self.app \u003d common.make_app()"},{"line_number":141,"context_line":"        self.addCleanup(pecan.set_config, {}, overwrite\u003dTrue)"},{"line_number":142,"context_line":""},{"line_number":143,"context_line":"        self._ctx \u003d cyborg_context.get_admin_context()"},{"line_number":144,"context_line":""},{"line_number":145,"context_line":"    def seed_devices(self):"}],"source_content_type":"text/x-python","patch_set":6,"id":"d7a06ec2_5bb5efbb","line":142,"range":{"start_line":122,"start_character":1,"end_line":142,"end_character":1},"in_reply_to":"cd48417f_a1527a17","updated":"2026-07-08 15:52:42.000000000","message":"Done","commit_id":"7edf57d8b318bcd45d11ee0fb76d74ba393c8193"},{"author":{"_account_id":11604,"name":"sean mooney","email":"smooney@redhat.com","username":"sean-k-mooney"},"change_message_id":"f69f07fc2a54b1d7744e3e723d32c7652f582dc4","unresolved":true,"context_lines":[{"line_number":151,"context_line":"        self.test_data.update(result)"},{"line_number":152,"context_line":""},{"line_number":153,"context_line":"    def seed_arqs(self):"},{"line_number":154,"context_line":"        patcher \u003d mock.patch(\u0027cyborg.objects.ext_arq.AgentAPI\u0027, autospec\u003dTrue)"},{"line_number":155,"context_line":"        patcher.start()"},{"line_number":156,"context_line":"        self.addCleanup(patcher.stop)"},{"line_number":157,"context_line":"        self.seed_device_profiles()"},{"line_number":158,"context_line":"        result \u003d common.seed_arqs(self._ctx, self._db)"},{"line_number":159,"context_line":"        self.test_data.update(result)"}],"source_content_type":"text/x-python","patch_set":6,"id":"d848a07b_00a98288","line":156,"range":{"start_line":154,"start_character":6,"end_line":156,"end_character":37},"updated":"2026-07-07 12:37:01.000000000","message":"this would be more like \n```\nself.mock_agent_api \u003d self.useFixture(\n    fixtures.MockPatch(\u0027cyborg.objects.ext_arq.AgentAPI\u0027, autospec\u003dTrue)\n).mock\n```\n\nalthouhg im not sure these seed funcitons are really correct.\nwe do certenly need to seed the db but i question why are we also updating\n\nself.test_data ?\n\nfor the functional test we actully want to hit the sqlite db when we call the object method to list the arqs ectra so keeping a copy of the test data in memoy feels weried to me.","commit_id":"7edf57d8b318bcd45d11ee0fb76d74ba393c8193"},{"author":{"_account_id":4690,"name":"melanie witt","display_name":"melwitt","email":"melwittt@gmail.com","username":"melwitt"},"change_message_id":"39ad2b53760272161f45a8019ef09a76efa92448","unresolved":false,"context_lines":[{"line_number":151,"context_line":"        self.test_data.update(result)"},{"line_number":152,"context_line":""},{"line_number":153,"context_line":"    def seed_arqs(self):"},{"line_number":154,"context_line":"        patcher \u003d mock.patch(\u0027cyborg.objects.ext_arq.AgentAPI\u0027, autospec\u003dTrue)"},{"line_number":155,"context_line":"        patcher.start()"},{"line_number":156,"context_line":"        self.addCleanup(patcher.stop)"},{"line_number":157,"context_line":"        self.seed_device_profiles()"},{"line_number":158,"context_line":"        result \u003d common.seed_arqs(self._ctx, self._db)"},{"line_number":159,"context_line":"        self.test_data.update(result)"}],"source_content_type":"text/x-python","patch_set":6,"id":"cf49de89_c2d01696","line":156,"range":{"start_line":154,"start_character":6,"end_line":156,"end_character":37},"in_reply_to":"05e6501e_727fcc31","updated":"2026-07-08 15:52:42.000000000","message":"Done","commit_id":"7edf57d8b318bcd45d11ee0fb76d74ba393c8193"},{"author":{"_account_id":4690,"name":"melanie witt","display_name":"melwitt","email":"melwittt@gmail.com","username":"melwitt"},"change_message_id":"7ad6c5733d29f12e3e84ab61748c22315331abc5","unresolved":true,"context_lines":[{"line_number":151,"context_line":"        self.test_data.update(result)"},{"line_number":152,"context_line":""},{"line_number":153,"context_line":"    def seed_arqs(self):"},{"line_number":154,"context_line":"        patcher \u003d mock.patch(\u0027cyborg.objects.ext_arq.AgentAPI\u0027, autospec\u003dTrue)"},{"line_number":155,"context_line":"        patcher.start()"},{"line_number":156,"context_line":"        self.addCleanup(patcher.stop)"},{"line_number":157,"context_line":"        self.seed_device_profiles()"},{"line_number":158,"context_line":"        result \u003d common.seed_arqs(self._ctx, self._db)"},{"line_number":159,"context_line":"        self.test_data.update(result)"}],"source_content_type":"text/x-python","patch_set":6,"id":"05e6501e_727fcc31","line":156,"range":{"start_line":154,"start_character":6,"end_line":156,"end_character":37},"in_reply_to":"d848a07b_00a98288","updated":"2026-07-08 01:17:55.000000000","message":"Yeah let me redo some of this.","commit_id":"7edf57d8b318bcd45d11ee0fb76d74ba393c8193"},{"author":{"_account_id":11604,"name":"sean mooney","email":"smooney@redhat.com","username":"sean-k-mooney"},"change_message_id":"f69f07fc2a54b1d7744e3e723d32c7652f582dc4","unresolved":false,"context_lines":[{"line_number":188,"context_line":"            if not os.path.isdir(sample_dir):"},{"line_number":189,"context_line":"                os.makedirs(sample_dir)"},{"line_number":190,"context_line":"            with open(sample_path, \u0027w\u0027) as f:"},{"line_number":191,"context_line":"                json.dump(actual, f, indent\u003d4, sort_keys\u003dFalse)"},{"line_number":192,"context_line":"                f.write(\u0027\\n\u0027)"},{"line_number":193,"context_line":"            return"},{"line_number":194,"context_line":""}],"source_content_type":"text/x-python","patch_set":6,"id":"ed9c33f8_2e83d44d","line":191,"range":{"start_line":191,"start_character":46,"end_line":191,"end_character":62},"updated":"2026-07-07 12:37:01.000000000","message":"nit: so we could pass True here.\ni know we are goign to ignore order in teh actual comparisons but that might lead to smaller diffs if we are adding new fields.\non the other hand we can jsut add the at the end f the sampel so either works","commit_id":"7edf57d8b318bcd45d11ee0fb76d74ba393c8193"},{"author":{"_account_id":11604,"name":"sean mooney","email":"smooney@redhat.com","username":"sean-k-mooney"},"change_message_id":"f56a38667a2ce142fb26ec2d00abd410c90c6da0","unresolved":true,"context_lines":[{"line_number":37,"context_line":")"},{"line_number":38,"context_line":""},{"line_number":39,"context_line":""},{"line_number":40,"context_line":"def _structure(obj):"},{"line_number":41,"context_line":"    \"\"\"Reduce a JSON object to its structural skeleton."},{"line_number":42,"context_line":""},{"line_number":43,"context_line":"    Dicts keep their keys; scalar values are replaced by their type"}],"source_content_type":"text/x-python","patch_set":7,"id":"8e17d3cf_6e6e1cf1","line":40,"range":{"start_line":40,"start_character":4,"end_line":40,"end_character":14},"updated":"2026-07-16 12:09:04.000000000","message":"this is a lot simpler the the previous approch","commit_id":"edce5fb28c9f39c0af95ba0729857586ca6bbc70"},{"author":{"_account_id":11604,"name":"sean mooney","email":"smooney@redhat.com","username":"sean-k-mooney"},"change_message_id":"f56a38667a2ce142fb26ec2d00abd410c90c6da0","unresolved":true,"context_lines":[{"line_number":52,"context_line":"    if isinstance(obj, list):"},{"line_number":53,"context_line":"        return sorted("},{"line_number":54,"context_line":"            [_structure(x) for x in obj],"},{"line_number":55,"context_line":"            key\u003dlambda x: json.dumps(x, sort_keys\u003dTrue, default\u003drepr),"},{"line_number":56,"context_line":"        )"},{"line_number":57,"context_line":"    return type(obj).__name__"},{"line_number":58,"context_line":""}],"source_content_type":"text/x-python","patch_set":7,"id":"a3a47ae8_05ad96e2","line":55,"range":{"start_line":55,"start_character":55,"end_line":55,"end_character":68},"updated":"2026-07-16 12:09:04.000000000","message":"that a neat tick by the way :)","commit_id":"edce5fb28c9f39c0af95ba0729857586ca6bbc70"}],"cyborg/tests/functional/fixtures/capture.py":[{"author":{"_account_id":28006,"name":"teim-ci","display_name":"teim-ci","email":"ci@seanmooney.info","username":"ci-sean-mooney","status":"this is a third-party ci account run by sean-k-mooney on irc\nhosted at zuul.teim.app"},"tag":"autogenerated:zuul:automatic-ci","change_message_id":"79573af5aa3e66bd3ad920cad0da79696b53a1e9","unresolved":false,"context_lines":[{"line_number":29,"context_line":"        pass"},{"line_number":30,"context_line":""},{"line_number":31,"context_line":"    def createLock(self):"},{"line_number":32,"context_line":"        self.lock \u003d None"},{"line_number":33,"context_line":""},{"line_number":34,"context_line":""},{"line_number":35,"context_line":"class Logging(log.ConfigureLogging):"}],"source_content_type":"text/x-python","patch_set":5,"id":"14bb2eee_9761ca56","line":32,"updated":"2026-06-25 20:52:44.000000000","message":"NullHandler.createLock sets self.lock \u003d None, disabling thread safety. The overridden handle() bypasses the lock, but the base Handler.emit() still acquires self.lock. If emit() is ever called directly, it crashes with AttributeError on None.lock.\n\n**Severity**: WARNING | **Confidence**: 0.8\n\n**Impact**: If a future Python version or logging framework change causes emit() to be called on this handler (instead of the overridden handle()), tests would crash with AttributeError instead of degrading gracefully.\n\n**Suggestion**:\nEither use the standard library logging.NullHandler (which has a no-op emit without touching the lock), or set self.lock \u003d threading.Lock() in createLock if the goal is a lightweight lock. The custom NullHandler\u0027s value-add is calling self.format() to detect format string errors, which can be preserved without nullifying the lock.","commit_id":"1a9c396706c15e01c3409d925ad8b017e7785636"},{"author":{"_account_id":11604,"name":"sean mooney","email":"smooney@redhat.com","username":"sean-k-mooney"},"change_message_id":"f69f07fc2a54b1d7744e3e723d32c7652f582dc4","unresolved":false,"context_lines":[],"source_content_type":"","patch_set":6,"id":"a931e9aa_07959b04","line":68,"range":{"start_line":22,"start_character":0,"end_line":68,"end_character":1},"updated":"2026-07-07 12:37:01.000000000","message":"i guess this is a prot of https://github.com/openstack/placement/blob/master/placement/tests/functional/fixtures/capture.py\n\ni was more or less expecting to port  eventully.\nhttps://github.com/openstack/watcher/blob/master/watcher/tests/local_fixtures/watcher.py#L30-L126\ninsetad for the logging fixture\n\nbut i guess the oslo version should more or less do the same so ok","commit_id":"7edf57d8b318bcd45d11ee0fb76d74ba393c8193"}],"cyborg/tests/functional/fixtures/common.py":[{"author":{"_account_id":28006,"name":"teim-ci","display_name":"teim-ci","email":"ci@seanmooney.info","username":"ci-sean-mooney","status":"this is a third-party ci account run by sean-k-mooney on irc\nhosted at zuul.teim.app"},"tag":"autogenerated:zuul:automatic-ci","change_message_id":"c5a99028859b7923b0b3d047a345389f09d25f86","unresolved":false,"context_lines":[{"line_number":58,"context_line":"    conf.config("},{"line_number":59,"context_line":"        connection\u003d\u0027sqlite://\u0027, sqlite_synchronous\u003dFalse, group\u003d\u0027database\u0027"},{"line_number":60,"context_line":"    )"},{"line_number":61,"context_line":"    CONF([], default_config_files\u003d[])"},{"line_number":62,"context_line":"    return conf"},{"line_number":63,"context_line":""},{"line_number":64,"context_line":""}],"source_content_type":"text/x-python","patch_set":2,"id":"02016e26_fe3866a1","line":61,"updated":"2026-06-25 16:54:07.000000000","message":"setup_database() configures the connection string in two places: setup_config() sets \u0027connection\u003dsqlite://\u0027 via conf.config(group\u003d\u0027database\u0027), and setup_database() configures it again via enginefacade.transaction_context(). This redundant configuration could lead to confusion.\n\n**Severity**: SUGGESTION | **Confidence**: 0.8\n\n**Benefit**: Reducing redundant configuration paths makes the database setup clearer and ensures there is a single source of truth for the test connection string. It also reduces the chance of the two configurations diverging.\n\n**Recommendation**:\nVerify whether both configuration paths are needed (one for oslo_config CONF, one for the enginefacade fixture). If the enginefacade fixture overrides CONF, add a comment explaining why both are necessary. If not, remove the redundant conf.config() call in setup_config().","commit_id":"4201679d071af83523027f567fbc2515132a22b8"},{"author":{"_account_id":28006,"name":"teim-ci","display_name":"teim-ci","email":"ci@seanmooney.info","username":"ci-sean-mooney","status":"this is a third-party ci account run by sean-k-mooney on irc\nhosted at zuul.teim.app"},"tag":"autogenerated:zuul:automatic-ci","change_message_id":"c5a99028859b7923b0b3d047a345389f09d25f86","unresolved":false,"context_lines":[{"line_number":99,"context_line":"def make_app():"},{"line_number":100,"context_line":"    \"\"\"Build a WebTest-wrapped Pecan app for functional tests.\"\"\""},{"line_number":101,"context_line":"    app_config \u003d {"},{"line_number":102,"context_line":"        \u0027app\u0027: {"},{"line_number":103,"context_line":"            \u0027root\u0027: \u0027cyborg.api.controllers.root.RootController\u0027,"},{"line_number":104,"context_line":"            \u0027modules\u0027: [\u0027cyborg.api\u0027],"},{"line_number":105,"context_line":"            \u0027acl_public_routes\u0027: [\u0027/\u0027, \u0027/v1/.*\u0027],"}],"source_content_type":"text/x-python","patch_set":2,"id":"daeb96da_f138bdde","line":102,"updated":"2026-06-25 16:54:07.000000000","message":"make_app() uses acl_public_routes [\u0027/\u0027, \u0027/v1/.*\u0027] but the API only exposes v2 routes (RootController has v2 \u003d v2.Controller(), no v1). The v1 pattern is carried over from the unit test base without verification.\n\n**Severity**: SUGGESTION | **Confidence**: 0.7\n\n**Benefit**: Aligning the public routes with actual API versions makes the test configuration more accurate and avoids confusion for future developers who may wonder about v1 routing.\n\n**Recommendation**:\nVerify whether \u0027/v1/.*\u0027 is intentional (perhaps for version negotiation). If it is a copy-paste artifact, consider using \u0027/\u0027 alone or adding \u0027/v2/.*\u0027 as the public route. This matches the existing unit test base pattern but should be confirmed for the functional context.","commit_id":"4201679d071af83523027f567fbc2515132a22b8"},{"author":{"_account_id":28006,"name":"teim-ci","display_name":"teim-ci","email":"ci@seanmooney.info","username":"ci-sean-mooney","status":"this is a third-party ci account run by sean-k-mooney on irc\nhosted at zuul.teim.app"},"tag":"autogenerated:zuul:automatic-ci","change_message_id":"c5a99028859b7923b0b3d047a345389f09d25f86","unresolved":false,"context_lines":[{"line_number":112,"context_line":"        return pecan.testing.load_test_app(app_config)"},{"line_number":113,"context_line":""},{"line_number":114,"context_line":""},{"line_number":115,"context_line":"def seed_devices(context, db):"},{"line_number":116,"context_line":"    \"\"\"Create a test device with a deployable and attribute.\"\"\""},{"line_number":117,"context_line":"    dev \u003d objects.Device("},{"line_number":118,"context_line":"        context,"}],"source_content_type":"text/x-python","patch_set":2,"id":"2e9d6c03_845c8914","line":115,"updated":"2026-06-25 16:54:07.000000000","message":"The \u0027db\u0027 parameter in seed_devices() and seed_device_profiles() is accepted but never used inside the function body. Only seed_arqs() actually uses it (for db.extarq_update).\n\n**Severity**: WARNING | **Confidence**: 0.9\n\n**Impact**: Dead parameters are misleading to future developers who may assume db is needed and pass it unnecessarily, or who may not realize seed_arqs is the only function with a real db dependency. It also makes the API inconsistent.\n\n**Suggestion**:\nRemove the \u0027db\u0027 parameter from seed_devices() and seed_device_profiles() signatures, and update the callers in test_api_samples_base.py (seed_devices, seed_device_profiles methods) to not pass self._db. Keep it only for seed_arqs() where it is actually used.","commit_id":"4201679d071af83523027f567fbc2515132a22b8"},{"author":{"_account_id":28006,"name":"teim-ci","display_name":"teim-ci","email":"ci@seanmooney.info","username":"ci-sean-mooney","status":"this is a third-party ci account run by sean-k-mooney on irc\nhosted at zuul.teim.app"},"tag":"autogenerated:zuul:automatic-ci","change_message_id":"160f95bc02f6ff1387bdd9cbe13057b8dccc8d28","unresolved":false,"context_lines":[{"line_number":160,"context_line":"    Group keys are chosen to match doc/api_samples/ so structural"},{"line_number":161,"context_line":"    comparison passes for every list entry."},{"line_number":162,"context_line":"    \"\"\""},{"line_number":163,"context_line":"    dp1 \u003d objects.DeviceProfile("},{"line_number":164,"context_line":"        context,"},{"line_number":165,"context_line":"        uuid\u003duuidutils.generate_uuid(),"},{"line_number":166,"context_line":"        name\u003d\u0027test-dp-1\u0027,"}],"source_content_type":"text/x-python","patch_set":3,"id":"608dd2ec_62056dcd","line":163,"updated":"2026-06-25 18:39:45.000000000","message":"The device_profiles list test relies on insertion order matching between seed data (dp1 has 3 group keys, dp2 has 2) and the sample file. _assert_structure_matches compares list elements by index, so a different DB return order causes a false structural mismatch on group keys.\n\n**Severity**: WARNING | **Confidence**: 0.8\n\n**Impact**: Test could fail intermittently if DB list ordering changes (e.g., after a DB migration or concurrent test runs). The fragility is that positional comparison of heterogeneous list elements depends on stable sort order.\n\n**Suggestion**:\nConsider either sorting the expected and actual lists by a stable key (e.g., name) before structural comparison, or add a comment in seed_device_profiles documenting that list ordering must match the sample file. Alternatively, make all seed profiles structurally identical (same group keys) so order does not matter.","commit_id":"12891c37320ee48b3316724b0ce277a3355740f6"},{"author":{"_account_id":28006,"name":"teim-ci","display_name":"teim-ci","email":"ci@seanmooney.info","username":"ci-sean-mooney","status":"this is a third-party ci account run by sean-k-mooney on irc\nhosted at zuul.teim.app"},"tag":"autogenerated:zuul:automatic-ci","change_message_id":"3c95be4e32bc2edadfaf789605559cc694defbd6","unresolved":false,"context_lines":[{"line_number":49,"context_line":"        state.request.conductor_api \u003d self.conductor_api"},{"line_number":50,"context_line":""},{"line_number":51,"context_line":""},{"line_number":52,"context_line":"def setup_config():"},{"line_number":53,"context_line":"    \"\"\"Configure global cfg.CONF for functional testing.\"\"\""},{"line_number":54,"context_line":"    objects.register_all()"},{"line_number":55,"context_line":"    conf \u003d config_fixture.Config(cfg.CONF)"}],"source_content_type":"text/x-python","patch_set":4,"id":"fb729bce_f0f158e6","line":52,"updated":"2026-06-25 20:26:34.000000000","message":"The in-memory SQLite connection is configured twice: once in setup_config (conf.config connection\u003dsqlite://, group\u003ddatabase) and again in setup_database (local_ef.configure(connection\u003d...)).\n\n**Severity**: SUGGESTION | **Confidence**: 0.7\n\n**Benefit**: Removing the redundant cfg.CONF database override (or adding a comment explaining why both the CONF default and the enginefacade configure call are needed) would clarify the setup and avoid confusion about which value is authoritative.\n\n**Recommendation**:\nKeep the enginefacade.configure in setup_database (it wires the StaticPool in-memory connection) and either drop the group\u003d\u0027database\u0027 conf.config in setup_config or annotate that it only satisfies code reading CONF.database.connection directly. A note suffices since this mirrors tests/base.py.","commit_id":"7400129897644343f7f51cfa943442dde9165b63"},{"author":{"_account_id":28006,"name":"teim-ci","display_name":"teim-ci","email":"ci@seanmooney.info","username":"ci-sean-mooney","status":"this is a third-party ci account run by sean-k-mooney on irc\nhosted at zuul.teim.app"},"tag":"autogenerated:zuul:automatic-ci","change_message_id":"3c95be4e32bc2edadfaf789605559cc694defbd6","unresolved":false,"context_lines":[{"line_number":272,"context_line":"        ),"},{"line_number":273,"context_line":"    )"},{"line_number":274,"context_line":"    bound_obj.create(context)"},{"line_number":275,"context_line":"    db.extarq_update("},{"line_number":276,"context_line":"        context,"},{"line_number":277,"context_line":"        bound_obj.arq.uuid,"},{"line_number":278,"context_line":"        {"}],"source_content_type":"text/x-python","patch_set":4,"id":"39441c8d_66b7133f","line":275,"updated":"2026-06-25 20:26:34.000000000","message":"seed_arqs directly calls db.extarq_update to force a Bound state, bypassing the ExtARQ state machine that normally drives state transitions and sets attach_handle fields.\n\n**Severity**: SUGGESTION | **Confidence**: 0.6\n\n**Benefit**: The structural test only verifies shape so this is acceptable for a fixture, but it means the Bound sample is exercised against a hand-set row rather than the real bind path. If bind logic later changes which fields it populates, the sample could drift silently.\n\n**Recommendation**:\nThe comment at lines 271-272 partially explains this; consider also asserting the seeded attach_handle_uuid is non-null so a future bind-path field addition is caught rather than masked by the None wildcard.","commit_id":"7400129897644343f7f51cfa943442dde9165b63"},{"author":{"_account_id":11604,"name":"sean mooney","email":"smooney@redhat.com","username":"sean-k-mooney"},"change_message_id":"f69f07fc2a54b1d7744e3e723d32c7652f582dc4","unresolved":true,"context_lines":[{"line_number":61,"context_line":"    CONF([], default_config_files\u003d[])"},{"line_number":62,"context_line":"    return conf"},{"line_number":63,"context_line":""},{"line_number":64,"context_line":""},{"line_number":65,"context_line":"def setup_database():"},{"line_number":66,"context_line":"    \"\"\"Create an in-memory SQLite database for one test run."},{"line_number":67,"context_line":""},{"line_number":68,"context_line":"    Uses in-memory SQLite so oslo.db selects StaticPool (single shared"},{"line_number":69,"context_line":"    connection).  This ensures data seeded in test setup is visible to"},{"line_number":70,"context_line":"    the WSGI app\u0027s sessions during WebTest requests."},{"line_number":71,"context_line":""},{"line_number":72,"context_line":"    Returns (dbapi_instance, enginefacade_fixture)."},{"line_number":73,"context_line":"    \"\"\""},{"line_number":74,"context_line":"    local_ef \u003d enginefacade.transaction_context()"},{"line_number":75,"context_line":"    local_ef.configure("},{"line_number":76,"context_line":"        connection\u003d\u0027sqlite://\u0027,"},{"line_number":77,"context_line":"        sqlite_synchronous\u003dFalse,"},{"line_number":78,"context_line":"    )"},{"line_number":79,"context_line":"    ef_fixture \u003d test_fixtures.ReplaceEngineFacadeFixture("},{"line_number":80,"context_line":"        sqlalchemy_api.main_context_manager, local_ef"},{"line_number":81,"context_line":"    )"},{"line_number":82,"context_line":"    ef_fixture.setUp()"},{"line_number":83,"context_line":""},{"line_number":84,"context_line":"    engine \u003d local_ef.writer.get_engine()"},{"line_number":85,"context_line":"    models.Base.metadata.create_all(engine)"},{"line_number":86,"context_line":""},{"line_number":87,"context_line":"    return dbapi.get_instance(), ef_fixture"},{"line_number":88,"context_line":""},{"line_number":89,"context_line":""},{"line_number":90,"context_line":"def setup_policy():"},{"line_number":91,"context_line":"    \"\"\"Set up a permissive policy for functional tests.\"\"\""}],"source_content_type":"text/x-python","patch_set":6,"id":"e7cde06b_db3cc300","line":88,"range":{"start_line":64,"start_character":1,"end_line":88,"end_character":1},"updated":"2026-07-07 12:37:01.000000000","message":"so we actully want to use file backed dbs not in memory \n\nhttps://github.com/openstack/cyborg/blob/master/cyborg/tests/unit/db/base.py#L41-L87\n\nbecause of the usage or threaing we cant actully sue in memory dbs safely\n\nit was cause python to segfault in ci intermitently\n\nso i had to replace them with file backed dbs as part of \n\nhttps://github.com/openstack/cyborg/commit/caecf3438030d314e6de717b9680e9d2f8243e34\n\nwhat we shoudl do instead is factor out the db setup into a resuabel fixutre that we can share between the db test cases and the functional test","commit_id":"7edf57d8b318bcd45d11ee0fb76d74ba393c8193"},{"author":{"_account_id":4690,"name":"melanie witt","display_name":"melwitt","email":"melwittt@gmail.com","username":"melwitt"},"change_message_id":"86c282c2dceb0432e396a7c3efc513df867a1980","unresolved":false,"context_lines":[{"line_number":61,"context_line":"    CONF([], default_config_files\u003d[])"},{"line_number":62,"context_line":"    return conf"},{"line_number":63,"context_line":""},{"line_number":64,"context_line":""},{"line_number":65,"context_line":"def setup_database():"},{"line_number":66,"context_line":"    \"\"\"Create an in-memory SQLite database for one test run."},{"line_number":67,"context_line":""},{"line_number":68,"context_line":"    Uses in-memory SQLite so oslo.db selects StaticPool (single shared"},{"line_number":69,"context_line":"    connection).  This ensures data seeded in test setup is visible to"},{"line_number":70,"context_line":"    the WSGI app\u0027s sessions during WebTest requests."},{"line_number":71,"context_line":""},{"line_number":72,"context_line":"    Returns (dbapi_instance, enginefacade_fixture)."},{"line_number":73,"context_line":"    \"\"\""},{"line_number":74,"context_line":"    local_ef \u003d enginefacade.transaction_context()"},{"line_number":75,"context_line":"    local_ef.configure("},{"line_number":76,"context_line":"        connection\u003d\u0027sqlite://\u0027,"},{"line_number":77,"context_line":"        sqlite_synchronous\u003dFalse,"},{"line_number":78,"context_line":"    )"},{"line_number":79,"context_line":"    ef_fixture \u003d test_fixtures.ReplaceEngineFacadeFixture("},{"line_number":80,"context_line":"        sqlalchemy_api.main_context_manager, local_ef"},{"line_number":81,"context_line":"    )"},{"line_number":82,"context_line":"    ef_fixture.setUp()"},{"line_number":83,"context_line":""},{"line_number":84,"context_line":"    engine \u003d local_ef.writer.get_engine()"},{"line_number":85,"context_line":"    models.Base.metadata.create_all(engine)"},{"line_number":86,"context_line":""},{"line_number":87,"context_line":"    return dbapi.get_instance(), ef_fixture"},{"line_number":88,"context_line":""},{"line_number":89,"context_line":""},{"line_number":90,"context_line":"def setup_policy():"},{"line_number":91,"context_line":"    \"\"\"Set up a permissive policy for functional tests.\"\"\""}],"source_content_type":"text/x-python","patch_set":6,"id":"e635806e_55dbcd2d","line":88,"range":{"start_line":64,"start_character":1,"end_line":88,"end_character":1},"in_reply_to":"ae236a51_58e96a01","updated":"2026-07-08 15:53:15.000000000","message":"Done","commit_id":"7edf57d8b318bcd45d11ee0fb76d74ba393c8193"},{"author":{"_account_id":4690,"name":"melanie witt","display_name":"melwitt","email":"melwittt@gmail.com","username":"melwitt"},"change_message_id":"7ad6c5733d29f12e3e84ab61748c22315331abc5","unresolved":true,"context_lines":[{"line_number":61,"context_line":"    CONF([], default_config_files\u003d[])"},{"line_number":62,"context_line":"    return conf"},{"line_number":63,"context_line":""},{"line_number":64,"context_line":""},{"line_number":65,"context_line":"def setup_database():"},{"line_number":66,"context_line":"    \"\"\"Create an in-memory SQLite database for one test run."},{"line_number":67,"context_line":""},{"line_number":68,"context_line":"    Uses in-memory SQLite so oslo.db selects StaticPool (single shared"},{"line_number":69,"context_line":"    connection).  This ensures data seeded in test setup is visible to"},{"line_number":70,"context_line":"    the WSGI app\u0027s sessions during WebTest requests."},{"line_number":71,"context_line":""},{"line_number":72,"context_line":"    Returns (dbapi_instance, enginefacade_fixture)."},{"line_number":73,"context_line":"    \"\"\""},{"line_number":74,"context_line":"    local_ef \u003d enginefacade.transaction_context()"},{"line_number":75,"context_line":"    local_ef.configure("},{"line_number":76,"context_line":"        connection\u003d\u0027sqlite://\u0027,"},{"line_number":77,"context_line":"        sqlite_synchronous\u003dFalse,"},{"line_number":78,"context_line":"    )"},{"line_number":79,"context_line":"    ef_fixture \u003d test_fixtures.ReplaceEngineFacadeFixture("},{"line_number":80,"context_line":"        sqlalchemy_api.main_context_manager, local_ef"},{"line_number":81,"context_line":"    )"},{"line_number":82,"context_line":"    ef_fixture.setUp()"},{"line_number":83,"context_line":""},{"line_number":84,"context_line":"    engine \u003d local_ef.writer.get_engine()"},{"line_number":85,"context_line":"    models.Base.metadata.create_all(engine)"},{"line_number":86,"context_line":""},{"line_number":87,"context_line":"    return dbapi.get_instance(), ef_fixture"},{"line_number":88,"context_line":""},{"line_number":89,"context_line":""},{"line_number":90,"context_line":"def setup_policy():"},{"line_number":91,"context_line":"    \"\"\"Set up a permissive policy for functional tests.\"\"\""}],"source_content_type":"text/x-python","patch_set":6,"id":"ae236a51_58e96a01","line":88,"range":{"start_line":64,"start_character":1,"end_line":88,"end_character":1},"in_reply_to":"e7cde06b_db3cc300","updated":"2026-07-08 01:17:55.000000000","message":"OK good to know, I\u0027ll change it.","commit_id":"7edf57d8b318bcd45d11ee0fb76d74ba393c8193"}],"cyborg/tests/local_fixtures/db_fixture.py":[{"author":{"_account_id":11604,"name":"sean mooney","email":"smooney@redhat.com","username":"sean-k-mooney"},"change_message_id":"eb6c546a64095c98ebf4f9ee26681d6b35a41224","unresolved":true,"context_lines":[{"line_number":25,"context_line":"from cyborg.db import api as dbapi"},{"line_number":26,"context_line":"from cyborg.db.sqlalchemy import api as sqlalchemy_api"},{"line_number":27,"context_line":"from cyborg.db.sqlalchemy import models"},{"line_number":28,"context_line":"from cyborg.tests.local_fixtures.db_lock_fixture import DatabaseWriteLock"},{"line_number":29,"context_line":""},{"line_number":30,"context_line":""},{"line_number":31,"context_line":"CONF \u003d cfg.CONF"}],"source_content_type":"text/x-python","patch_set":7,"id":"21f8f667_617a5d34","line":28,"range":{"start_line":28,"start_character":56,"end_line":28,"end_character":73},"updated":"2026-07-16 12:05:20.000000000","message":"nit you should not import classes directly\n\nthat was in the code your portign but we shoudl eventally clean that up everywhere","commit_id":"edce5fb28c9f39c0af95ba0729857586ca6bbc70"}],"cyborg/tests/policy_fixture.py":[{"author":{"_account_id":11604,"name":"sean mooney","email":"smooney@redhat.com","username":"sean-k-mooney"},"change_message_id":"f69f07fc2a54b1d7744e3e723d32c7652f582dc4","unresolved":true,"context_lines":[{"line_number":1,"context_line":"# Copyright 2017 Huawei Technologies Co.,LTD."},{"line_number":2,"context_line":"# All Rights Reserved."},{"line_number":3,"context_line":"#"},{"line_number":4,"context_line":"#    Licensed under the Apache License, Version 2.0 (the \"License\"); you may"}],"source_content_type":"text/x-python","patch_set":6,"id":"75130fea_eeb68370","line":1,"updated":"2026-07-07 12:37:01.000000000","message":"unless we just move all the fixutres to cyborg/tests/ lets create a local_fixtures directory under tests and put this there instead and also move all the unit/fucntional fixture there\n\nnote local_fixtures is intentional\n\nhttps://review.opendev.org/c/openstack/nova/+/978346\n\nif we want to be able to confure ides to use cyborg/tests as the test idrectory we need to not alias the fixture package by having a fixtures dir\n\nand since we are eventlet free i woudl really like to be able to single step debug tough all our tests when needed.","commit_id":"7edf57d8b318bcd45d11ee0fb76d74ba393c8193"},{"author":{"_account_id":4690,"name":"melanie witt","display_name":"melwitt","email":"melwittt@gmail.com","username":"melwitt"},"change_message_id":"86c282c2dceb0432e396a7c3efc513df867a1980","unresolved":false,"context_lines":[{"line_number":1,"context_line":"# Copyright 2017 Huawei Technologies Co.,LTD."},{"line_number":2,"context_line":"# All Rights Reserved."},{"line_number":3,"context_line":"#"},{"line_number":4,"context_line":"#    Licensed under the Apache License, Version 2.0 (the \"License\"); you may"}],"source_content_type":"text/x-python","patch_set":6,"id":"1a515ca4_45e38064","line":1,"in_reply_to":"3518fb59_63d86429","updated":"2026-07-08 15:53:15.000000000","message":"Done","commit_id":"7edf57d8b318bcd45d11ee0fb76d74ba393c8193"},{"author":{"_account_id":4690,"name":"melanie witt","display_name":"melwitt","email":"melwittt@gmail.com","username":"melwitt"},"change_message_id":"7ad6c5733d29f12e3e84ab61748c22315331abc5","unresolved":true,"context_lines":[{"line_number":1,"context_line":"# Copyright 2017 Huawei Technologies Co.,LTD."},{"line_number":2,"context_line":"# All Rights Reserved."},{"line_number":3,"context_line":"#"},{"line_number":4,"context_line":"#    Licensed under the Apache License, Version 2.0 (the \"License\"); you may"}],"source_content_type":"text/x-python","patch_set":6,"id":"3518fb59_63d86429","line":1,"in_reply_to":"75130fea_eeb68370","updated":"2026-07-08 01:17:55.000000000","message":"OK, will do.","commit_id":"7edf57d8b318bcd45d11ee0fb76d74ba393c8193"}],"doc/api_samples/accelerator_requests/accelerator_requests-getone-resp.json":[{"author":{"_account_id":11604,"name":"sean mooney","email":"smooney@redhat.com","username":"sean-k-mooney"},"change_message_id":"f69f07fc2a54b1d7744e3e723d32c7652f582dc4","unresolved":true,"context_lines":[{"line_number":15,"context_line":"   \"state\":\"Initial\","},{"line_number":16,"context_line":"   \"device_rp_uuid\":null,"},{"line_number":17,"context_line":"   \"device_profile_name\":\"tmp-dp1\","},{"line_number":18,"context_line":"   \"project_id\":null,"},{"line_number":19,"context_line":"   \"attach_handle_uuid\":null,"},{"line_number":20,"context_line":"   \"attach_handle_info\":{"},{"line_number":21,"context_line":"   }"}],"source_content_type":"application/json","patch_set":6,"id":"3910838e_9ad678ab","line":18,"range":{"start_line":18,"start_character":1,"end_line":18,"end_character":21},"updated":"2026-07-07 12:37:01.000000000","message":"nit: this shoudl alwasy be none Null now\n\nin the past this was not set but i fixed that and provided a backfil\n\nso if an arq is created it shoudl alwasy have a owning project now.","commit_id":"7edf57d8b318bcd45d11ee0fb76d74ba393c8193"},{"author":{"_account_id":4690,"name":"melanie witt","display_name":"melwitt","email":"melwittt@gmail.com","username":"melwitt"},"change_message_id":"7ad6c5733d29f12e3e84ab61748c22315331abc5","unresolved":true,"context_lines":[{"line_number":15,"context_line":"   \"state\":\"Initial\","},{"line_number":16,"context_line":"   \"device_rp_uuid\":null,"},{"line_number":17,"context_line":"   \"device_profile_name\":\"tmp-dp1\","},{"line_number":18,"context_line":"   \"project_id\":null,"},{"line_number":19,"context_line":"   \"attach_handle_uuid\":null,"},{"line_number":20,"context_line":"   \"attach_handle_info\":{"},{"line_number":21,"context_line":"   }"}],"source_content_type":"application/json","patch_set":6,"id":"bec873bd_cb192449","line":18,"range":{"start_line":18,"start_character":1,"end_line":18,"end_character":21},"in_reply_to":"3910838e_9ad678ab","updated":"2026-07-08 01:17:55.000000000","message":"OK, I didn\u0027t realize this. Will fix.","commit_id":"7edf57d8b318bcd45d11ee0fb76d74ba393c8193"},{"author":{"_account_id":4690,"name":"melanie witt","display_name":"melwitt","email":"melwittt@gmail.com","username":"melwitt"},"change_message_id":"39ad2b53760272161f45a8019ef09a76efa92448","unresolved":false,"context_lines":[{"line_number":15,"context_line":"   \"state\":\"Initial\","},{"line_number":16,"context_line":"   \"device_rp_uuid\":null,"},{"line_number":17,"context_line":"   \"device_profile_name\":\"tmp-dp1\","},{"line_number":18,"context_line":"   \"project_id\":null,"},{"line_number":19,"context_line":"   \"attach_handle_uuid\":null,"},{"line_number":20,"context_line":"   \"attach_handle_info\":{"},{"line_number":21,"context_line":"   }"}],"source_content_type":"application/json","patch_set":6,"id":"b8b4fb4c_af0dcd63","line":18,"range":{"start_line":18,"start_character":1,"end_line":18,"end_character":21},"in_reply_to":"bec873bd_cb192449","updated":"2026-07-08 15:52:42.000000000","message":"Done","commit_id":"7edf57d8b318bcd45d11ee0fb76d74ba393c8193"},{"author":{"_account_id":11604,"name":"sean mooney","email":"smooney@redhat.com","username":"sean-k-mooney"},"change_message_id":"f69f07fc2a54b1d7744e3e723d32c7652f582dc4","unresolved":false,"context_lines":[{"line_number":16,"context_line":"   \"device_rp_uuid\":null,"},{"line_number":17,"context_line":"   \"device_profile_name\":\"tmp-dp1\","},{"line_number":18,"context_line":"   \"project_id\":null,"},{"line_number":19,"context_line":"   \"attach_handle_uuid\":null,"},{"line_number":20,"context_line":"   \"attach_handle_info\":{"},{"line_number":21,"context_line":"   }"},{"line_number":22,"context_line":"}"}],"source_content_type":"application/json","patch_set":6,"id":"1acbbc93_007feb80","line":19,"range":{"start_line":19,"start_character":0,"end_line":19,"end_character":29},"updated":"2026-07-07 12:37:01.000000000","message":"i think this can be ull while it not boudn to any spefiic instance/host.\nso this is correct","commit_id":"7edf57d8b318bcd45d11ee0fb76d74ba393c8193"}],"doc/api_samples/accelerator_requests/accelerator_requests-list-resp.json":[{"author":{"_account_id":28006,"name":"teim-ci","display_name":"teim-ci","email":"ci@seanmooney.info","username":"ci-sean-mooney","status":"this is a third-party ci account run by sean-k-mooney on irc\nhosted at zuul.teim.app"},"tag":"autogenerated:zuul:automatic-ci","change_message_id":"c5a99028859b7923b0b3d047a345389f09d25f86","unresolved":false,"context_lines":[{"line_number":40,"context_line":"         \"state\":\"Bound\","},{"line_number":41,"context_line":"         \"device_rp_uuid\":\"03631f82-20a9-3f67-a29d-dc1abe4041bf\","},{"line_number":42,"context_line":"         \"device_profile_name\":\"temp-dp1\","},{"line_number":43,"context_line":"         \"project_id\":\"a]fake-project-id\","},{"line_number":44,"context_line":"         \"attach_handle_uuid\":\"a1fake-attach-handle-uuid\","},{"line_number":45,"context_line":"         \"attach_handle_info\":{"},{"line_number":46,"context_line":"            \"device\":\"00\","}],"source_content_type":"application/json","patch_set":2,"id":"dadc7ae6_d2fd4c69","line":43,"updated":"2026-06-25 16:54:07.000000000","message":"The accelerator_requests-list-resp.json sample contains a malformed project_id value \u0027a]fake-project-id\u0027 with a stray closing bracket, and the attach_handle_uuid \u0027a1fake-attach-handle-uuid\u0027 appears to be a placeholder artifact.\n\n**Severity**: WARNING | **Confidence**: 0.8\n\n**Impact**: While the structural comparison test only checks keys and types (not values), these sample files serve as API documentation in the api-ref. The malformed value \u0027a]fake-project-id\u0027 looks like a typo from sample generation or editing and would be confusing to API consumers reading the docs.\n\n**Suggestion**:\nFix the project_id value to a proper UUID-like placeholder (e.g., \u0027fake-project-id\u0027 without the bracket, or a real-looking UUID). If this is intentional placeholder syntax, document the convention, but the stray \u0027]\u0027 strongly suggests a typo.","commit_id":"4201679d071af83523027f567fbc2515132a22b8"},{"author":{"_account_id":11604,"name":"sean mooney","email":"smooney@redhat.com","username":"sean-k-mooney"},"change_message_id":"f69f07fc2a54b1d7744e3e723d32c7652f582dc4","unresolved":true,"context_lines":[{"line_number":17,"context_line":"         \"state\":\"Initial\","},{"line_number":18,"context_line":"         \"device_rp_uuid\":null,"},{"line_number":19,"context_line":"         \"device_profile_name\":\"temp-dp1\","},{"line_number":20,"context_line":"         \"project_id\":null,"},{"line_number":21,"context_line":"         \"attach_handle_uuid\":null,"},{"line_number":22,"context_line":"         \"attach_handle_info\":{"},{"line_number":23,"context_line":""}],"source_content_type":"application/json","patch_set":6,"id":"ff517aaf_67275393","line":20,"range":{"start_line":20,"start_character":8,"end_line":20,"end_character":27},"updated":"2026-07-07 12:37:01.000000000","message":"same comment here this shoudl be set to a real proejct at this point","commit_id":"7edf57d8b318bcd45d11ee0fb76d74ba393c8193"},{"author":{"_account_id":4690,"name":"melanie witt","display_name":"melwitt","email":"melwittt@gmail.com","username":"melwitt"},"change_message_id":"39ad2b53760272161f45a8019ef09a76efa92448","unresolved":false,"context_lines":[{"line_number":17,"context_line":"         \"state\":\"Initial\","},{"line_number":18,"context_line":"         \"device_rp_uuid\":null,"},{"line_number":19,"context_line":"         \"device_profile_name\":\"temp-dp1\","},{"line_number":20,"context_line":"         \"project_id\":null,"},{"line_number":21,"context_line":"         \"attach_handle_uuid\":null,"},{"line_number":22,"context_line":"         \"attach_handle_info\":{"},{"line_number":23,"context_line":""}],"source_content_type":"application/json","patch_set":6,"id":"c4f37969_d1b97bf0","line":20,"range":{"start_line":20,"start_character":8,"end_line":20,"end_character":27},"in_reply_to":"ff517aaf_67275393","updated":"2026-07-08 15:52:42.000000000","message":"Done","commit_id":"7edf57d8b318bcd45d11ee0fb76d74ba393c8193"}],"doc/api_samples/device_profiles/device_profiles-list-resp.json":[{"author":{"_account_id":11604,"name":"sean mooney","email":"smooney@redhat.com","username":"sean-k-mooney"},"change_message_id":"f69f07fc2a54b1d7744e3e723d32c7652f582dc4","unresolved":true,"context_lines":[{"line_number":1,"context_line":"{"},{"line_number":2,"context_line":"   \"device_profiles\":["},{"line_number":3,"context_line":"      {"},{"line_number":4,"context_line":"         \"name\":\"fpga-dp1\","},{"line_number":5,"context_line":"         \"uuid\":\"5518a925-1c2c-49a2-a8bf-0927d9456f3e\","},{"line_number":6,"context_line":"         \"description\": \"\","},{"line_number":7,"context_line":"         \"groups\":["}],"source_content_type":"application/json","patch_set":6,"id":"5c8fade3_8c44eae5","line":4,"updated":"2026-07-07 12:37:01.000000000","message":"im not sure why the ordring matters here?\nthis does not appre to be sorted by name or uuid\ndid something require this change?\n\ni dont actully care about the order just wonderign why it was meoved?","commit_id":"7edf57d8b318bcd45d11ee0fb76d74ba393c8193"},{"author":{"_account_id":4690,"name":"melanie witt","display_name":"melwitt","email":"melwittt@gmail.com","username":"melwitt"},"change_message_id":"7ad6c5733d29f12e3e84ab61748c22315331abc5","unresolved":true,"context_lines":[{"line_number":1,"context_line":"{"},{"line_number":2,"context_line":"   \"device_profiles\":["},{"line_number":3,"context_line":"      {"},{"line_number":4,"context_line":"         \"name\":\"fpga-dp1\","},{"line_number":5,"context_line":"         \"uuid\":\"5518a925-1c2c-49a2-a8bf-0927d9456f3e\","},{"line_number":6,"context_line":"         \"description\": \"\","},{"line_number":7,"context_line":"         \"groups\":["}],"source_content_type":"application/json","patch_set":6,"id":"ee4438ff_4885b25a","line":4,"in_reply_to":"5c8fade3_8c44eae5","updated":"2026-07-08 01:17:55.000000000","message":"Not sure why this happened, agree the order should not matter.","commit_id":"7edf57d8b318bcd45d11ee0fb76d74ba393c8193"},{"author":{"_account_id":4690,"name":"melanie witt","display_name":"melwitt","email":"melwittt@gmail.com","username":"melwitt"},"change_message_id":"39ad2b53760272161f45a8019ef09a76efa92448","unresolved":false,"context_lines":[{"line_number":1,"context_line":"{"},{"line_number":2,"context_line":"   \"device_profiles\":["},{"line_number":3,"context_line":"      {"},{"line_number":4,"context_line":"         \"name\":\"fpga-dp1\","},{"line_number":5,"context_line":"         \"uuid\":\"5518a925-1c2c-49a2-a8bf-0927d9456f3e\","},{"line_number":6,"context_line":"         \"description\": \"\","},{"line_number":7,"context_line":"         \"groups\":["}],"source_content_type":"application/json","patch_set":6,"id":"9ea905b5_b062e3c4","line":4,"in_reply_to":"ee4438ff_4885b25a","updated":"2026-07-08 15:52:42.000000000","message":"Done","commit_id":"7edf57d8b318bcd45d11ee0fb76d74ba393c8193"}],"tox.ini":[{"author":{"_account_id":12393,"name":"chandan kumar","display_name":"Chandan Kumar","email":"chkumar@redhat.com","username":"chkumar246"},"change_message_id":"83da27dbd81f13cc1449fb9a950acc87b23f9f66","unresolved":true,"context_lines":[{"line_number":17,"context_line":""},{"line_number":18,"context_line":"commands \u003d stestr run --slowest {posargs}"},{"line_number":19,"context_line":""},{"line_number":20,"context_line":"[testenv:functional]"},{"line_number":21,"context_line":"usedevelop \u003d True"},{"line_number":22,"context_line":"setenv \u003d"},{"line_number":23,"context_line":"  OS_TEST_PATH\u003d./cyborg/tests/functional"},{"line_number":24,"context_line":"passenv \u003d GENERATE_SAMPLES"},{"line_number":25,"context_line":"deps \u003d"},{"line_number":26,"context_line":"  {[testenv]deps}"},{"line_number":27,"context_line":"commands \u003d"},{"line_number":28,"context_line":"  stestr run --slowest {posargs}"},{"line_number":29,"context_line":""},{"line_number":30,"context_line":"[testenv:genpolicy]"},{"line_number":31,"context_line":"sitepackages \u003d False"}],"source_content_type":"text/x-properties","patch_set":6,"id":"9a717729_1d4a913f","line":28,"range":{"start_line":20,"start_character":0,"end_line":28,"end_character":32},"updated":"2026-07-07 11:16:44.000000000","message":"Thank you for adding this new tox target.\n\nWe have https://zuul.opendev.org/t/openstack/job/openstack-tox-functional openstack-tox-functional job, we can reuse the same to add a new zuul job so that it will execute the functional tests in CI.","commit_id":"7edf57d8b318bcd45d11ee0fb76d74ba393c8193"},{"author":{"_account_id":4690,"name":"melanie witt","display_name":"melwitt","email":"melwittt@gmail.com","username":"melwitt"},"change_message_id":"39ad2b53760272161f45a8019ef09a76efa92448","unresolved":true,"context_lines":[{"line_number":17,"context_line":""},{"line_number":18,"context_line":"commands \u003d stestr run --slowest {posargs}"},{"line_number":19,"context_line":""},{"line_number":20,"context_line":"[testenv:functional]"},{"line_number":21,"context_line":"usedevelop \u003d True"},{"line_number":22,"context_line":"setenv \u003d"},{"line_number":23,"context_line":"  OS_TEST_PATH\u003d./cyborg/tests/functional"},{"line_number":24,"context_line":"passenv \u003d GENERATE_SAMPLES"},{"line_number":25,"context_line":"deps \u003d"},{"line_number":26,"context_line":"  {[testenv]deps}"},{"line_number":27,"context_line":"commands \u003d"},{"line_number":28,"context_line":"  stestr run --slowest {posargs}"},{"line_number":29,"context_line":""},{"line_number":30,"context_line":"[testenv:genpolicy]"},{"line_number":31,"context_line":"sitepackages \u003d False"}],"source_content_type":"text/x-properties","patch_set":6,"id":"735b86d6_08e593cf","line":28,"range":{"start_line":20,"start_character":0,"end_line":28,"end_character":32},"in_reply_to":"9a717729_1d4a913f","updated":"2026-07-08 15:52:42.000000000","message":"Proposed the job here: https://review.opendev.org/c/openstack/cyborg/+/996389","commit_id":"7edf57d8b318bcd45d11ee0fb76d74ba393c8193"}]}
