From 2c5dcd0060323ac882a6a93ed2b79c80a2b69421 Mon Sep 17 00:00:00 2001 From: Pavlina Bortlova Date: Thu, 15 Oct 2020 17:44:56 +0200 Subject: [PATCH] Add models specific to request_type --- docs/source/CHANGELOG.md | 13 + iiblib/iib_build_details_model.py | 271 +++++++++-------- setup.py | 2 +- tests/test_iib_build_details_model.py | 413 +++++++++++++++++++++++--- tests/test_iib_build_details_pager.py | 58 ++-- tests/test_iib_client.py | 236 ++++++++------- 6 files changed, 688 insertions(+), 305 deletions(-) diff --git a/docs/source/CHANGELOG.md b/docs/source/CHANGELOG.md index 13b6e47..88e7981 100644 --- a/docs/source/CHANGELOG.md +++ b/docs/source/CHANGELOG.md @@ -9,6 +9,19 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - N/A +## 2.0.0. - 2020-11-02 + +### Add + - new models AddModel, RmModel and RegenerateBundleModel to IIBBuildDetailsModel + - new function get_args and \_\_get_attribute\_\_ in IIBBuildDetailsModel + - use \__slots\__ for backward compatibility + +### Changed + - version set to 2.0.0. + - class IIBBuildDetailsModel change to generic class which is inherited by new models + - functions from\_dict, to\_dict and \__eq\__ in IIBBuildDetailsModel + + ## 1.0.0 - 2020-10-20 ### Changed diff --git a/iiblib/iib_build_details_model.py b/iiblib/iib_build_details_model.py index cf41b41..2c68313 100644 --- a/iiblib/iib_build_details_model.py +++ b/iiblib/iib_build_details_model.py @@ -1,135 +1,160 @@ class IIBBuildDetailsModel(object): """Model class handling data about index build task""" - def __init__( - self, - _id, - state, - reason, - state_history, - from_index, - from_index_resolved, - bundles, - removed_operators, - organization, - binary_image, - binary_image_resolved, - index_image, - request_type, - arches, - bundle_mapping, - omps_operator_version, - ): - """ - Args: - _id (int) - Id of build - state (str) - State of build - state (str) - Reason for state change - from_index (str) - Reference of index image used as source for rebuild - from_index_resolved (str) - Reference of new index image - bundles (list) - List of bundles to be added to index image - removed_operators (list) - List of operators to be removed from index image - organization (str) - Name of organization to push to in the legacy app registry - binary_image (str) - Reference of binary image used for rebuilding - binary_image_resolved (str) - Checksum reference of binary image that was used for rebuilding - index_image (str) - Reference of index image to rebuild - request_type (str) - Type of iib build task (add or remove) - arches (list) - List of architectures supported in new index image - bundle_mapping (dict) - Operator names in "bundles" map to: list of "bundles" which - map to the operator key - omps_operator_version (dict) - Operator version returned from OMPS API call used for Add request - """ - self.id = _id - self.state = state - self.reason = reason - self.state_history = state_history - self.from_index = from_index - self.from_index_resolved = from_index_resolved - self.bundles = bundles - self.removed_operators = removed_operators - self.organization = organization - self.binary_image = binary_image - self.binary_image_resolved = binary_image_resolved - self.index_image = index_image - self.request_type = request_type - self.arches = arches - self.bundle_mapping = bundle_mapping - self.omps_operator_version = omps_operator_version + __slots__ = [ + "id", + "arches", + "state", + "state_reason", + "request_type", + "batch", + "updated", + "user", + "state_history", + "batch_annotations", + "logs", + "__dict__", + ] + + _general_attrs = [ + "id", + "arches", + "state", + "state_reason", + "request_type", + "batch", + "updated", + "user", + ] + + _optional_attrs = { + "state_history": lambda: list(), + "batch_annotations": lambda: dict(), + "logs": lambda: dict(), + } + + _operational_attrs = [] + + def __init__(self, *args, **kwargs): + self._data = self.get_args(kwargs) @classmethod def from_dict(cls, data): - return cls( - data["id"], - data["state"], - data["state_reason"], - data.get("state_history", []), - data["from_index"], - data["from_index_resolved"], - data.get("bundles", []), - data.get("removed_operators", []), - data.get("organization"), - data["binary_image"], - data["binary_image_resolved"], - data["index_image"], - data["request_type"], - data["arches"], - data["bundle_mapping"], - data.get("omps_operator_version", {}), - ) + if data["request_type"] == "add": + return AddModel(**data) + elif data["request_type"] == "rm": + return RmModel(**data) + elif data["request_type"] == "regenerate-bundle": + return RegenerateBundleModel(**data) + raise KeyError("Unsupported request type: %s" % data["request_type"]) + + def get_args(self, data): + attrs = {} + for general_attr in self._general_attrs: + attrs[general_attr] = data[general_attr] + for optional_attr, default_maker in self._optional_attrs.items(): + if optional_attr in data: + attrs[optional_attr] = data[optional_attr] + else: + attrs[optional_attr] = default_maker() + for operation_attr in self._operation_attrs: + attrs[operation_attr] = data[operation_attr] + return attrs def to_dict(self): - return { - "id": self.id, - "state": self.state, - "state_reason": self.reason, - "state_history": self.state_history, - "from_index": self.from_index, - "from_index_resolved": self.from_index, - "bundles": self.bundles, - "removed_operators": self.removed_operators, - "organization": self.organization, - "binary_image": self.binary_image, - "binary_image_resolved": self.binary_image_resolved, - "index_image": self.index_image, - "request_type": self.request_type, - "arches": self.arches, - "bundle_mapping": self.bundle_mapping, - "omps_operator_version": self.omps_operator_version, - } + result = {} + for key in self._general_attrs: + result[key] = self._data[key] + for key in self._optional_attrs.items(): + result[key] = self._data.get(key) + for key in self._operation_attrs: + result[key] = self._data[key] + return result def __eq__(self, other): + return isinstance(other, IIBBuildDetailsModel) and self._data == other._data + + def __getattribute__(self, name): if ( - self.id == other.id - and self.state == other.state - and self.reason == other.reason - and self.state_history == other.state_history - and self.from_index == other.from_index - and self.from_index_resolved == other.from_index_resolved - and self.bundles == other.bundles - and self.removed_operators == other.removed_operators - and self.organization == other.organization - and self.binary_image == other.binary_image - and self.binary_image_resolved == other.binary_image_resolved - and self.index_image == other.index_image - and self.request_type == other.request_type - and self.arches == other.arches - and self.bundle_mapping == other.bundle_mapping - and self.omps_operator_version == other.omps_operator_version + name in object.__getattribute__(self, "_operation_attrs") + or name in object.__getattribute__(self, "_optional_attrs") + or name in object.__getattribute__(self, "_general_attrs") ): - return True - return False + return object.__getattribute__(self, "_data")[name] + else: + return object.__getattribute__(self, name) + + +class AddModel(IIBBuildDetailsModel): + + __slots__ = [ + "binary_image", + "binary_image_resolved", + "bundles", + "bundle_mapping", + "from_index", + "from_index_resolved", + "index_image", + "removed_operators", + "organization", + "omps_operator_version", + "distribution_scope", + ] + + _operation_attrs = [ + "binary_image", + "binary_image_resolved", + "bundles", + "bundle_mapping", + "from_index", + "from_index_resolved", + "index_image", + "removed_operators", + "organization", + "omps_operator_version", + "distribution_scope", + ] + + +class RmModel(IIBBuildDetailsModel): + + __slots__ = [ + "binary_image", + "binary_image_resolved", + "bundles", + "bundle_mapping", + "from_index", + "from_index_resolved", + "index_image", + "removed_operators", + "organization", + "distribution_scope", + ] + _operation_attrs = [ + "binary_image", + "binary_image_resolved", + "bundles", + "bundle_mapping", + "from_index", + "from_index_resolved", + "index_image", + "removed_operators", + "organization", + "distribution_scope", + ] + + +class RegenerateBundleModel(IIBBuildDetailsModel): + + __slots__ = [ + "bundle_image", + "from_bundle_image", + "from_bundle_image_resolved", + "organization", + ] + _operation_attrs = [ + "bundle_image", + "from_bundle_image", + "from_bundle_image_resolved", + "organization", + ] diff --git a/setup.py b/setup.py index 667b5e4..633dd4b 100644 --- a/setup.py +++ b/setup.py @@ -62,7 +62,7 @@ def read_content(filepath): setup( name="iiblib", - version="1.0.0", + version="2.0.0", description="IIB client library", long_description=long_description, long_description_content_type="text/markdown", diff --git a/tests/test_iib_build_details_model.py b/tests/test_iib_build_details_model.py index 33868e9..241d32e 100644 --- a/tests/test_iib_build_details_model.py +++ b/tests/test_iib_build_details_model.py @@ -1,72 +1,391 @@ import pytest -from iiblib.iib_build_details_model import IIBBuildDetailsModel +from iiblib.iib_build_details_model import ( + IIBBuildDetailsModel, + AddModel, + RmModel, + RegenerateBundleModel, +) @pytest.fixture -def fixture_build_details_json(): +def fixture_add_build_details_json(): json = { "id": 1, + "arches": ["x86_64"], "state": "in_progress", "state_reason": "state_reason", + "request_type": "add", "state_history": [], + "batch": 1, + "batch_annotations": {"batch_annotations": 1}, + "logs": {}, + "updated": "updated", + "user": "user@example.com", + "binary_image": "binary_image", + "binary_image_resolved": "binary_image_resolved", + "bundles": ["bundles1"], + "bundle_mapping": {"bundle_mapping": "map"}, "from_index": "from_index", "from_index_resolved": "from_index_resolved", - "bundles": ["bundles1"], + "index_image": "index_image", "removed_operators": ["operator1"], "organization": "organization", + "omps_operator_version": {"operator": "1.0"}, + "distribution_scope": "null", + } + return json + + +@pytest.fixture +def fixture_rm_build_details_json(): + json = { + "id": 2, + "arches": ["x86_64"], + "state": "in_progress", + "state_reason": "state_reason", + "request_type": "rm", + "state_history": [], + "batch": 1, + "batch_annotations": {"batch_annotations": 1}, + "logs": {}, + "updated": "updated", + "user": "user@example.com", "binary_image": "binary_image", "binary_image_resolved": "binary_image_resolved", + "bundles": ["bundles1"], + "bundle_mapping": {"bundle_mapping": "map"}, + "from_index": "from_index", + "from_index_resolved": "from_index_resolved", "index_image": "index_image", - "request_type": "request_type", + "removed_operators": ["operator1"], + "organization": "organization", + "distribution_scope": "null", + } + return json + + +@pytest.fixture +def fixture_regenerate_bundle_build_details_json(): + json = { + "id": 3, "arches": ["x86_64"], - "bundle_mapping": {"bundle_mapping": "map"}, - "omps_operator_version": {"operator": "1.0"}, + "state": "in_progress", + "state_reason": "state_reason", + "request_type": "regenerate-bundle", + "state_history": [], + "batch": 1, + "batch_annotations": {"batch_annotations": 1}, + "logs": {}, + "updated": "updated", + "user": "user@example.com", + "bundle_image": "bundle_image", + "from_bundle_image": "from_bundle_image", + "from_bundle_image_resolved": "from_bundle_image_resolved", + "organization": "organization", + } + return json + + +@pytest.fixture +def fixture_unknown_build_details_json(): + json = { + "id": 3, + "arches": ["x86_64"], + "state": "in_progress", + "state_reason": "state_reason", + "request_type": "unknown", + "state_history": [], + "batch": 1, + "batch_annotations": {"batch_annotations": 1}, + "logs": {}, + "updated": "updated", + "user": "user@example.com", + "bundle_image": "bundle_image", + "from_bundle_image": "from_bundle_image", + "from_bundle_image_resolved": "from_bundle_image_resolved", + "organization": "organization", + } + return json + + +@pytest.fixture +def fixture_bundle_image_missing_json(): + json = { + "id": 3, + "arches": ["x86_64"], + "state": "in_progress", + "state_reason": "state_reason", + "request_type": "regenerate-bundle", + "state_history": [], + "batch": 1, + "batch_annotations": {"batch_annotations": 1}, + "logs": {}, + "updated": "updated", + "user": "user@example.com", + "from_bundle_image": "from_bundle_image", + "from_bundle_image_resolved": "from_bundle_image_resolved", + "organization": "organization", + } + return json + + +@pytest.fixture +def fixture_optional_args_missing_json(): + json = { + "id": 3, + "arches": ["x86_64"], + "state": "in_progress", + "state_reason": "state_reason", + "request_type": "regenerate-bundle", + "batch": 1, + "updated": "updated", + "user": "user@example.com", + "bundle_image": "bundle_image", + "from_bundle_image": "from_bundle_image", + "from_bundle_image_resolved": "from_bundle_image_resolved", + "organization": "organization", } return json -def test_iibbuilddetailsmodel(fixture_build_details_json): - unexpected_model = IIBBuildDetailsModel( - 1, - "finished", - "state_reason", - [], - "from_index", - "from_index_resolved", - ["bundles1"], - ["operator1"], - "organization", - "binary_image", - "binary_image_resolved", - "index_image", - "request_type", - ["x86_64"], - {"bundle_mapping": "map"}, - {"operator": "1.0"}, +def test_from_dict_success( + fixture_add_build_details_json, + fixture_rm_build_details_json, + fixture_regenerate_bundle_build_details_json, + fixture_optional_args_missing_json, +): + add_model = AddModel( + id=1, + arches=["x86_64"], + state="in_progress", + state_reason="state_reason", + request_type="add", + state_history=[], + batch=1, + batch_annotations={"batch_annotations": 1}, + logs={}, + updated="updated", + user="user@example.com", + binary_image="binary_image", + binary_image_resolved="binary_image_resolved", + bundles=["bundles1"], + bundle_mapping={"bundle_mapping": "map"}, + from_index="from_index", + from_index_resolved="from_index_resolved", + index_image="index_image", + removed_operators=["operator1"], + organization="organization", + omps_operator_version={"operator": "1.0"}, + distribution_scope="null", + ) + rm_model = RmModel( + id=2, + arches=["x86_64"], + state="in_progress", + state_reason="state_reason", + request_type="rm", + state_history=[], + batch=1, + batch_annotations={"batch_annotations": 1}, + logs={}, + updated="updated", + user="user@example.com", + binary_image="binary_image", + binary_image_resolved="binary_image_resolved", + bundles=["bundles1"], + bundle_mapping={"bundle_mapping": "map"}, + from_index="from_index", + from_index_resolved="from_index_resolved", + index_image="index_image", + removed_operators=["operator1"], + organization="organization", + distribution_scope="null", + ) + + regenerate_bundle_model = RegenerateBundleModel( + id=3, + arches=["x86_64"], + state="in_progress", + state_reason="state_reason", + request_type="regenerate-bundle", + state_history=[], + batch=1, + batch_annotations={"batch_annotations": 1}, + logs={}, + updated="updated", + user="user@example.com", + bundle_image="bundle_image", + from_bundle_image="from_bundle_image", + from_bundle_image_resolved="from_bundle_image_resolved", + organization="organization", + ) + + optional_args_empty = RegenerateBundleModel( + id=3, + arches=["x86_64"], + state="in_progress", + state_reason="state_reason", + request_type="regenerate-bundle", + batch=1, + updated="updated", + user="user@example.com", + state_history=[], + batch_annotations={}, + logs={}, + bundle_image="bundle_image", + from_bundle_image="from_bundle_image", + from_bundle_image_resolved="from_bundle_image_resolved", + organization="organization", + ) + + model1 = IIBBuildDetailsModel.from_dict(fixture_add_build_details_json) + assert model1 == add_model + + model2 = IIBBuildDetailsModel.from_dict(fixture_rm_build_details_json) + assert model2 == rm_model + + model3 = IIBBuildDetailsModel.from_dict( + fixture_regenerate_bundle_build_details_json + ) + assert model3 == regenerate_bundle_model + + model4 = IIBBuildDetailsModel.from_dict(fixture_optional_args_missing_json) + assert model4 == optional_args_empty + + +def test_from_dict_failure( + fixture_add_build_details_json, + fixture_rm_build_details_json, + fixture_bundle_image_missing_json, + fixture_unknown_build_details_json, +): + + error_msg = "Unsupported request type: unknown" + + add_model_state_finished = AddModel( + id=1, + arches=["x86_64"], + state="finished", + state_reason="state_reason", + request_type="add", + state_history=[], + batch=1, + batch_annotations={"batch_annotations": 1}, + logs={}, + updated="updated", + user="user@example.com", + binary_image="binary_image", + binary_image_resolved="binary_image_resolved", + bundles=["bundles1"], + bundle_mapping={"bundle_mapping": "map"}, + from_index="from_index", + from_index_resolved="from_index_resolved", + index_image="index_image", + removed_operators=["operator1"], + organization="organization", + omps_operator_version={"operator": "1.0"}, + distribution_scope="null", ) - expected_model = IIBBuildDetailsModel( - 1, - "in_progress", - "state_reason", - [], - "from_index", - "from_index_resolved", - ["bundles1"], - ["operator1"], - "organization", - "binary_image", - "binary_image_resolved", - "index_image", - "request_type", - ["x86_64"], - {"bundle_mapping": "map"}, - {"operator": "1.0"}, + + model1 = IIBBuildDetailsModel.from_dict(fixture_add_build_details_json) + assert model1 != add_model_state_finished + + with pytest.raises(KeyError): + IIBBuildDetailsModel.from_dict(fixture_bundle_image_missing_json) + + with pytest.raises(KeyError, match=error_msg): + IIBBuildDetailsModel.from_dict(fixture_unknown_build_details_json) + + +def test_to_dict_success(fixture_rm_build_details_json): + + rm_model = RmModel( + id=2, + arches=["x86_64"], + state="in_progress", + state_reason="state_reason", + request_type="rm", + state_history=[], + batch=1, + batch_annotations={"batch_annotations": 1}, + logs={}, + updated="updated", + user="user@example.com", + binary_image="binary_image", + binary_image_resolved="binary_image_resolved", + bundles=["bundles1"], + bundle_mapping={"bundle_mapping": "map"}, + from_index="from_index", + from_index_resolved="from_index_resolved", + index_image="index_image", + removed_operators=["operator1"], + organization="organization", + distribution_scope="null", ) - model = IIBBuildDetailsModel.from_dict(fixture_build_details_json) - assert model == expected_model - assert model != unexpected_model - model = IIBBuildDetailsModel.from_dict(fixture_build_details_json).to_dict() - assert model == expected_model.to_dict() - assert model != unexpected_model.to_dict() + model = IIBBuildDetailsModel.from_dict(fixture_rm_build_details_json).to_dict() + assert model == rm_model.to_dict() + + +def test_general_attributes(fixture_add_build_details_json): + model = IIBBuildDetailsModel.from_dict(fixture_add_build_details_json) + + assert model.id == model._data["id"] + assert model.arches == model._data["arches"] + assert model.state == model._data["state"] + assert model.state_reason == model._data["state_reason"] + assert model.request_type == model._data["request_type"] + assert model.batch == model._data["batch"] + assert model.updated == model._data["updated"] + assert model.user == model._data["user"] + + +def test_optional_attributes(fixture_add_build_details_json): + model = IIBBuildDetailsModel.from_dict(fixture_add_build_details_json) + + assert model.state_history == model._data["state_history"] + assert model.batch_annotations == model._data["batch_annotations"] + assert model.logs == model._data["logs"] + + +def test_add_model_attributes(fixture_add_build_details_json): + model = IIBBuildDetailsModel.from_dict(fixture_add_build_details_json) + + assert model.binary_image == model._data["binary_image"] + assert model.binary_image_resolved == model._data["binary_image_resolved"] + assert model.bundles == model._data["bundles"] + assert model.bundle_mapping == model._data["bundle_mapping"] + assert model.from_index == model._data["from_index"] + assert model.from_index_resolved == model._data["from_index_resolved"] + assert model.index_image == model._data["index_image"] + assert model.removed_operators == model._data["removed_operators"] + assert model.organization == model._data["organization"] + assert model.omps_operator_version == model._data["omps_operator_version"] + assert model.distribution_scope == model._data["distribution_scope"] + + +def test_rm_model_attributes(fixture_rm_build_details_json): + model = IIBBuildDetailsModel.from_dict(fixture_rm_build_details_json) + + assert model.binary_image == model._data["binary_image"] + assert model.binary_image_resolved == model._data["binary_image_resolved"] + assert model.bundles == model._data["bundles"] + assert model.bundle_mapping == model._data["bundle_mapping"] + assert model.from_index == model._data["from_index"] + assert model.from_index_resolved == model._data["from_index_resolved"] + assert model.index_image == model._data["index_image"] + assert model.removed_operators == model._data["removed_operators"] + assert model.organization == model._data["organization"] + assert model.distribution_scope == model._data["distribution_scope"] + + +def test_regenerate_bundle_model_attributes( + fixture_regenerate_bundle_build_details_json, +): + model = IIBBuildDetailsModel.from_dict(fixture_regenerate_bundle_build_details_json) + + assert model.bundle_image == model._data["bundle_image"] + assert model.from_bundle_image == model._data["from_bundle_image"] + assert model.from_bundle_image_resolved == model._data["from_bundle_image_resolved"] + assert model.organization == model._data["organization"] diff --git a/tests/test_iib_build_details_pager.py b/tests/test_iib_build_details_pager.py index fc843a4..afe13b2 100644 --- a/tests/test_iib_build_details_pager.py +++ b/tests/test_iib_build_details_pager.py @@ -7,55 +7,67 @@ @pytest.fixture -def fixture_build_details_json(): +def fixture_add_build_details_json(): json = { "id": 1, + "arches": ["x86_64"], "state": "in_progress", "state_reason": "state_reason", + "request_type": "add", "state_history": [], + "batch": 1, + "batch_annotations": {"batch_annotations": 1}, + "logs": {}, + "updated": "updated", + "user": "user@example.com", + "binary_image": "binary_image", + "binary_image_resolved": "binary_image_resolved", + "bundles": ["bundles1"], + "bundle_mapping": {"bundle_mapping": "map"}, "from_index": "from_index", "from_index_resolved": "from_index_resolved", - "bundles": ["bundles1"], + "index_image": "index_image", "removed_operators": ["operator1"], "organization": "organization", - "binary_image": "binary_image", - "binary_image_resolved": "binary_image_resolved", - "index_image": "index_image", - "request_type": "request_type", - "arches": ["x86_64"], - "bundle_mapping": {"bundle_mapping": "map"}, "omps_operator_version": {"operator": "1.0"}, + "distribution_scope": "null", } return json @pytest.fixture -def fixture_build_details_json2(): +def fixture_add_build_details_json2(): json = { "id": 2, + "arches": ["x86_64"], "state": "in_progress", "state_reason": "state_reason", + "request_type": "add", "state_history": [], + "batch": 2, + "batch_annotations": {"batch_annotations": 2}, + "logs": {}, + "updated": "updated", + "user": "user@example.com", + "binary_image": "binary_image", + "binary_image_resolved": "binary_image_resolved", + "bundles": ["bundles1"], + "bundle_mapping": {"bundle_mapping": "map"}, "from_index": "from_index", "from_index_resolved": "from_index_resolved", - "bundles": ["bundles1"], + "index_image": "index_image", "removed_operators": ["operator1"], "organization": "organization", - "binary_image": "binary_image", - "binary_image_resolved": "binary_image_resolved", - "index_image": "index_image", - "request_type": "request_type", - "arches": ["x86_64"], - "bundle_mapping": {"bundle_mapping": "map"}, "omps_operator_version": {"operator": "1.0"}, + "distribution_scope": "null", } return json @pytest.fixture -def fixture_builds_page1_json(fixture_build_details_json): +def fixture_builds_page1_json(fixture_add_build_details_json): json = { - "items": [fixture_build_details_json], + "items": [fixture_add_build_details_json], "meta": { "first": "", "last": "", @@ -71,9 +83,9 @@ def fixture_builds_page1_json(fixture_build_details_json): @pytest.fixture -def fixture_builds_page2_json(fixture_build_details_json2): +def fixture_builds_page2_json(fixture_add_build_details_json2): json = { - "items": [fixture_build_details_json2], + "items": [fixture_add_build_details_json2], "meta": { "first": "", "last": "", @@ -88,11 +100,11 @@ def fixture_builds_page2_json(fixture_build_details_json2): return json -def test_iibbuilddetails_pager( +def test_iib_build_details_pager( fixture_builds_page1_json, fixture_builds_page2_json, - fixture_build_details_json, - fixture_build_details_json2, + fixture_add_build_details_json, + fixture_add_build_details_json2, ): with requests_mock.Mocker() as m: m.register_uri( diff --git a/tests/test_iib_client.py b/tests/test_iib_client.py index 70d7d3f..1a4cba6 100644 --- a/tests/test_iib_client.py +++ b/tests/test_iib_client.py @@ -13,78 +13,88 @@ @pytest.fixture -def fixture_build_details_json(): +def fixture_add_build_details_json(): json = { "id": 1, + "arches": ["x86_64"], "state": "in_progress", "state_reason": "state_reason", + "request_type": "add", "state_history": [], + "batch": 1, + "batch_annotations": {"batch_annotations": 1}, + "logs": {}, + "updated": "updated", + "user": "user@example.com", + "binary_image": "binary_image", + "binary_image_resolved": "binary_image_resolved", + "bundles": ["bundles1"], + "bundle_mapping": {"bundle_mapping": "map"}, "from_index": "from_index", "from_index_resolved": "from_index_resolved", - "bundles": ["bundles1"], + "index_image": "index_image", "removed_operators": ["operator1"], "organization": "organization", - "binary_image": "binary_image", - "binary_image_resolved": "binary_image_resolved", - "index_image": "index_image", - "request_type": "request_type", - "arches": ["x86_64"], - "bundle_mapping": {"bundle_mapping": "map"}, "omps_operator_version": {"operator": "1.0"}, + "distribution_scope": "null", } return json @pytest.fixture -def fixture_build_details_json2(): +def fixture_rm_build_details_json(): json = { "id": 2, + "arches": ["x86_64"], "state": "in_progress", "state_reason": "state_reason", + "request_type": "rm", "state_history": [], + "batch": 1, + "batch_annotations": {"batch_annotations": 1}, + "logs": {}, + "updated": "updated", + "user": "user@example.com", + "binary_image": "binary_image", + "binary_image_resolved": "binary_image_resolved", + "bundles": ["bundles1"], + "bundle_mapping": {"bundle_mapping": "map"}, "from_index": "from_index", "from_index_resolved": "from_index_resolved", - "bundles": ["bundles1"], + "index_image": "index_image", "removed_operators": ["operator1"], "organization": "organization", - "binary_image": "binary_image", - "binary_image_resolved": "binary_image_resolved", - "index_image": "index_image", - "request_type": "request_type", - "arches": ["x86_64"], - "bundle_mapping": {"bundle_mapping": "map"}, - "omps_operator_version": {"operator": "1.0"}, + "distribution_scope": "null", } return json @pytest.fixture -def fixture_build_details_json3(): +def fixture_regenerate_bundle_build_details_json(): json = { - "id": 1, + "id": 3, + "arches": ["x86_64"], "state": "in_progress", "state_reason": "state_reason", + "request_type": "regenerate-bundle", "state_history": [], - "from_index": "from_index", - "from_index_resolved": "from_index_resolved", - "bundles": ["bundles1"], - "removed_operators": ["operator1"], + "batch": 1, + "batch_annotations": {"batch_annotations": 1}, + "logs": {}, + "updated": "updated", + "user": "user@example.com", + "bundle_image": "bundle_image", + "from_bundle_image": "from_bundle_image", + "from_bundle_image_resolved": "from_bundle_image_resolved", "organization": "organization", - "binary_image": "mapped_binary_image", - "binary_image_resolved": "mapped_binary_image_resolved", - "index_image": "index_image", - "request_type": "request_type", - "arches": ["x86_64"], - "bundle_mapping": {"bundle_mapping": "map"}, - "omps_operator_version": {"operator": "1.0"}, } return json @pytest.fixture -def fixture_builds_page1_json(fixture_build_details_json): +def fixture_builds_page1_json(fixture_add_build_details_json): json = { - "items": [fixture_build_details_json], + "items": [fixture_add_build_details_json], "meta": { "first": "", "last": "", @@ -100,9 +110,9 @@ def fixture_builds_page1_json(fixture_build_details_json): @pytest.fixture -def fixture_builds_page2_json(fixture_build_details_json2): +def fixture_builds_page2_json(fixture_rm_build_details_json): json = { - "items": [fixture_build_details_json2], + "items": [fixture_rm_build_details_json], "meta": { "first": "", "last": "", @@ -117,31 +127,59 @@ def fixture_builds_page2_json(fixture_build_details_json2): return json -def test_iib_client(fixture_build_details_json, fixture_builds_page1_json): +def test_iib_client( + fixture_add_build_details_json, + fixture_rm_build_details_json, + fixture_regenerate_bundle_build_details_json, + fixture_builds_page1_json, +): with requests_mock.Mocker() as m: m.register_uri( "POST", "/api/v1/builds/add", status_code=200, - json=fixture_build_details_json, + json=fixture_add_build_details_json, ) m.register_uri( "POST", "/api/v1/builds/rm", status_code=200, - json=fixture_build_details_json, + json=fixture_rm_build_details_json, + ) + # TODO add other request types + + m.register_uri( + "POST", + "/api/v1/builds/regenerate-bundle", + status_code=200, + json=fixture_regenerate_bundle_build_details_json, ) m.register_uri( "GET", "/api/v1/builds", status_code=200, json=fixture_builds_page1_json ) m.register_uri( - "GET", "/api/v1/builds/1", status_code=200, json=fixture_build_details_json + "GET", + "/api/v1/builds/1", + status_code=200, + json=fixture_add_build_details_json, + ) + m.register_uri( + "GET", + "/api/v1/builds/2", + status_code=200, + json=fixture_rm_build_details_json, + ) + m.register_uri( + "GET", + "/api/v1/builds/3", + status_code=200, + json=fixture_regenerate_bundle_build_details_json, ) iibc = IIBClient("fake-host") assert iibc.add_bundles( "index-image", ["bundles-map"], [], binary_image="binary" - ) == IIBBuildDetailsModel.from_dict(fixture_build_details_json) + ) == IIBBuildDetailsModel.from_dict(fixture_add_build_details_json) assert ( iibc.add_bundles( "index-image", @@ -153,13 +191,13 @@ def test_iib_client(fixture_build_details_json, fixture_builds_page1_json): overwrite_from_index=True, overwrite_from_index_token="str", ) - == IIBBuildDetailsModel.from_dict(fixture_build_details_json) + == IIBBuildDetailsModel.from_dict(fixture_add_build_details_json) ) assert ( iibc.add_bundles( "index-image", ["bundles-map"], [], binary_image="binary", raw=True ) - == fixture_build_details_json + == fixture_add_build_details_json ) assert ( iibc.remove_operators( @@ -170,18 +208,34 @@ def test_iib_client(fixture_build_details_json, fixture_builds_page1_json): overwrite_from_index=True, overwrite_from_index_token="str", ) - == IIBBuildDetailsModel.from_dict(fixture_build_details_json) + == IIBBuildDetailsModel.from_dict(fixture_rm_build_details_json) ) assert ( iibc.remove_operators( "index-image", ["operator1"], [], binary_image="binary", raw=True ) - == fixture_build_details_json + == fixture_rm_build_details_json ) + + # get_builds - request_type is "add" assert iibc.get_build(1) == IIBBuildDetailsModel.from_dict( - fixture_build_details_json + fixture_add_build_details_json + ) + assert iibc.get_build(1, raw=True) == fixture_add_build_details_json + + # get_builds - request_type is "rm" + assert iibc.get_build(2) == IIBBuildDetailsModel.from_dict( + fixture_rm_build_details_json + ) + assert iibc.get_build(2, raw=True) == fixture_rm_build_details_json + + # get_builds - request_type is "regenerate-bundle" + assert iibc.get_build(3) == IIBBuildDetailsModel.from_dict( + fixture_regenerate_bundle_build_details_json + ) + assert ( + iibc.get_build(3, raw=True) == fixture_regenerate_bundle_build_details_json ) - assert iibc.get_build(1, raw=True) == fixture_build_details_json assert iibc.get_builds() == IIBBuildDetailsPager.from_dict( iibc, fixture_builds_page1_json @@ -189,7 +243,9 @@ def test_iib_client(fixture_build_details_json, fixture_builds_page1_json): assert iibc.get_builds(raw=True) == fixture_builds_page1_json -def test_iib_client_failure(fixture_build_details_json): +def test_iib_client_no_overwrite_from_index_or_token( + fixture_add_build_details_json, fixture_rm_build_details_json +): error_msg = ( "Either both or neither of overwrite-from-index " "and overwrite-from-index-token should be specified." @@ -199,13 +255,13 @@ def test_iib_client_failure(fixture_build_details_json): "POST", "/api/v1/builds/add", status_code=200, - json=fixture_build_details_json, + json=fixture_add_build_details_json, ) m.register_uri( "POST", "/api/v1/builds/rm", status_code=200, - json=fixture_build_details_json, + json=fixture_rm_build_details_json, ) iibc = IIBClient("fake-host") with pytest.raises(ValueError, match=error_msg): @@ -246,71 +302,23 @@ def test_iib_client_failure(fixture_build_details_json): ) -def test_iib_client_no_binary_image(fixture_build_details_json3): - with requests_mock.Mocker() as m: - m.register_uri( - "POST", - "/api/v1/builds/add", - status_code=200, - json=fixture_build_details_json3, - ) - m.register_uri( - "POST", - "/api/v1/builds/rm", - status_code=200, - json=fixture_build_details_json3, - ) - - iibc = IIBClient("fake-host") - assert iibc.add_bundles( - "index-image", ["bundles-map"], [] - ) == IIBBuildDetailsModel.from_dict(fixture_build_details_json3) - assert ( - iibc.add_bundles( - "index-image", - ["bundles-map"], - [], - cnr_token="cnr", - organization="org", - overwrite_from_index=True, - overwrite_from_index_token="str", - ) - == IIBBuildDetailsModel.from_dict(fixture_build_details_json3) - ) - assert ( - iibc.add_bundles("index-image", ["bundles-map"], [], raw=True) - == fixture_build_details_json3 - ) - assert ( - iibc.remove_operators( - "index-image", - ["operator1"], - [], - overwrite_from_index=True, - overwrite_from_index_token="str", - ) - == IIBBuildDetailsModel.from_dict(fixture_build_details_json3) - ) - assert ( - iibc.remove_operators("index-image", ["operator1"], [], raw=True) - == fixture_build_details_json3 - ) - - -def test_client_wait_for_build(fixture_build_details_json): +# there add model used +def test_client_wait_for_build(fixture_add_build_details_json): iibc = IIBClient("fake-host", poll_interval=1) - bdetails_finished = copy.copy(fixture_build_details_json) + bdetails_finished = copy.copy(fixture_add_build_details_json) bdetails_finished["state"] = "complete" with requests_mock.Mocker() as m: m.register_uri( "GET", "/api/v1/builds/1", [ - {"json": fixture_build_details_json, "status_code": 200}, + {"json": fixture_add_build_details_json, "status_code": 200}, {"json": bdetails_finished, "status_code": 200}, ], ) - iibc.wait_for_build(IIBBuildDetailsModel.from_dict(fixture_build_details_json)) + iibc.wait_for_build( + IIBBuildDetailsModel.from_dict(fixture_add_build_details_json) + ) bdetails_finished["state"] = "failed" with requests_mock.Mocker() as m: @@ -318,37 +326,43 @@ def test_client_wait_for_build(fixture_build_details_json): "GET", "/api/v1/builds/1", [ - {"json": fixture_build_details_json, "status_code": 200}, + {"json": fixture_add_build_details_json, "status_code": 200}, {"json": bdetails_finished, "status_code": 200}, ], ) - iibc.wait_for_build(IIBBuildDetailsModel.from_dict(fixture_build_details_json)) + iibc.wait_for_build( + IIBBuildDetailsModel.from_dict(fixture_add_build_details_json) + ) -def test_client_wait_for_build_retry(fixture_build_details_json): +# add model used +def test_client_wait_for_build_retry(fixture_add_build_details_json): iibc = IIBClient("fake-host.test", poll_interval=1, retries=10, backoff_factor=0) with pytest.raises( requests.exceptions.RequestException, match=".*Max retries exceeded*." ): - iibc.wait_for_build(IIBBuildDetailsModel.from_dict(fixture_build_details_json)) + iibc.wait_for_build( + IIBBuildDetailsModel.from_dict(fixture_add_build_details_json) + ) -def test_client_wait_for_build_timeout(fixture_build_details_json): +# add model used +def test_client_wait_for_build_timeout(fixture_add_build_details_json): # set wait timeout for 2 seconds iibc = IIBClient("fake-host.test", poll_interval=1, wait_for_build_timeout=2) with requests_mock.Mocker() as m: m.register_uri( "GET", - "/api/v1/builds/{}".format(fixture_build_details_json["id"]), + "/api/v1/builds/{}".format(fixture_add_build_details_json["id"]), status_code=200, - json=fixture_build_details_json, + json=fixture_add_build_details_json, ) with pytest.raises(IIBException, match="Timeout*."): iibc.wait_for_build( - IIBBuildDetailsModel.from_dict(fixture_build_details_json) + IIBBuildDetailsModel.from_dict(fixture_add_build_details_json) )