From 97501fd7dcef41a009a5ed2f3f3af63a541f40b1 Mon Sep 17 00:00:00 2001 From: Tony Meyer Date: Wed, 18 Sep 2024 14:53:38 +1200 Subject: [PATCH 1/4] Catch the correct error when a relation doesn't exist. --- pyproject.toml | 2 +- scenario/mocking.py | 2 +- tests/test_e2e/test_relations.py | 48 +++++++++++++++++++++++++++----- 3 files changed, 43 insertions(+), 9 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index 7151bf22..59986c60 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -8,7 +8,7 @@ build-backend = "setuptools.build_meta" [project] name = "ops-scenario" -version = "7.0.2" +version = "7.0.3" authors = [ { name = "Pietro Pasotti", email = "pietro.pasotti@canonical.com" } diff --git a/scenario/mocking.py b/scenario/mocking.py index 5b91c15b..9e004af4 100644 --- a/scenario/mocking.py +++ b/scenario/mocking.py @@ -181,7 +181,7 @@ def get_pebble(self, socket_path: str) -> "Client": def _get_relation_by_id(self, rel_id) -> "RelationBase": try: return self._state.get_relation(rel_id) - except ValueError: + except KeyError: raise RelationNotFoundError() from None def _get_secret(self, id=None, label=None): diff --git a/tests/test_e2e/test_relations.py b/tests/test_e2e/test_relations.py index b7880425..cc77734d 100644 --- a/tests/test_e2e/test_relations.py +++ b/tests/test_e2e/test_relations.py @@ -13,6 +13,7 @@ from ops.framework import EventBase, Framework from scenario import Context +from scenario.errors import UncaughtCharmError from scenario.state import ( _DEFAULT_JUJU_DATABAG, PeerRelation, @@ -411,17 +412,50 @@ def test_relation_ids(): assert rel.id == initial_id + i -def test_broken_relation_not_in_model_relations(mycharm): - rel = Relation("foo") +def test_get_relation_when_missing(): + class MyCharm(CharmBase): + def __init__(self, framework): + super().__init__(framework) + self.framework.observe(self.on.update_status, self._on_update_status) + self.framework.observe(self.on.config_changed, self._on_config_changed) + self.relation = None + + def _on_update_status(self, _): + self.relation = self.model.get_relation("foo") + + def _on_config_changed(self, _): + self.relation = self.model.get_relation("foo", self.config["relation-id"]) ctx = Context( - mycharm, meta={"name": "local", "requires": {"foo": {"interface": "foo"}}} + MyCharm, + meta={"name": "foo", "requires": {"foo": {"interface": "foo"}}}, + config={"options": {"relation-id": {"type": "int", "description": "foo"}}}, ) - with ctx(ctx.on.relation_broken(rel), state=State(relations={rel})) as mgr: - charm = mgr.charm + # There should be no error if the relation is missing - get_relation returns + # None in that case. + with ctx(ctx.on.update_status(), State()) as mgr: + mgr.run() + assert mgr.charm.relation is None - assert charm.model.get_relation("foo") is None - assert charm.model.relations["foo"] == [] + # There should also be no error if the relation is present, of course. + rel = Relation("foo") + with ctx(ctx.on.update_status(), State(relations={rel})) as mgr: + mgr.run() + assert mgr.charm.relation.id == rel.id + + # If a relation that doesn't exist is requested, that should also not raise + # an error. + with ctx(ctx.on.config_changed(), State(config={"relation-id": 42})) as mgr: + mgr.run() + rel = mgr.charm.relation + assert rel.id == 42 + assert not rel.active + + # If there's no defined relation with the name, then get_relation raises KeyError. + ctx = Context(MyCharm, meta={"name": "foo"}) + with pytest.raises(UncaughtCharmError) as exc: + ctx.run(ctx.on.update_status(), State()) + assert isinstance(exc.value.__cause__, KeyError) @pytest.mark.parametrize("klass", (Relation, PeerRelation, SubordinateRelation)) From 7be495f9dd6e146f7426a0153cd856dd939a385e Mon Sep 17 00:00:00 2001 From: Tony Meyer Date: Wed, 18 Sep 2024 15:00:19 +1200 Subject: [PATCH 2/4] Restore test removed by mistake. --- tests/test_e2e/test_relations.py | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/tests/test_e2e/test_relations.py b/tests/test_e2e/test_relations.py index cc77734d..ca39cc98 100644 --- a/tests/test_e2e/test_relations.py +++ b/tests/test_e2e/test_relations.py @@ -412,6 +412,19 @@ def test_relation_ids(): assert rel.id == initial_id + i +def test_broken_relation_not_in_model_relations(mycharm): + rel = Relation("foo") + + ctx = Context( + mycharm, meta={"name": "local", "requires": {"foo": {"interface": "foo"}}} + ) + with ctx(ctx.on.relation_broken(rel), state=State(relations={rel})) as mgr: + charm = mgr.charm + + assert charm.model.get_relation("foo") is None + assert charm.model.relations["foo"] == [] + + def test_get_relation_when_missing(): class MyCharm(CharmBase): def __init__(self, framework): From 614545a742d784c43ec17eef90448daa2db4aa1a Mon Sep 17 00:00:00 2001 From: Tony Meyer Date: Wed, 18 Sep 2024 21:43:55 +1200 Subject: [PATCH 3/4] Add py.typed stub file. --- scenario/py.typed | 0 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 scenario/py.typed diff --git a/scenario/py.typed b/scenario/py.typed new file mode 100644 index 00000000..e69de29b From 0a1b4a87b69bda4c8648388e7a7cf1e4fb718cb9 Mon Sep 17 00:00:00 2001 From: Tony Meyer Date: Wed, 18 Sep 2024 21:46:02 +1200 Subject: [PATCH 4/4] Bump version. --- pyproject.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyproject.toml b/pyproject.toml index 59986c60..67dca9a9 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -8,7 +8,7 @@ build-backend = "setuptools.build_meta" [project] name = "ops-scenario" -version = "7.0.3" +version = "7.0.4" authors = [ { name = "Pietro Pasotti", email = "pietro.pasotti@canonical.com" }