Skip to content

Commit

Permalink
fix: raise ModelError on unknown/error status set in Scenario (canoni…
Browse files Browse the repository at this point in the history
…cal#1417)

This copies across the fix from Harness to also be present in Scenario:
if `status_set` is passed anything other than the valid statuses, then
`ModelError` is raised (to better mimic what the Juju hook would
actually do).

Closes canonical/ops-scenario#202 (rather than
copying it over to this repo).

---------

Co-authored-by: Ben Hoyt <[email protected]>
  • Loading branch information
tonyandrewmeyer and benhoyt authored Oct 11, 2024
1 parent 86d71fd commit 68cf2d7
Show file tree
Hide file tree
Showing 2 changed files with 54 additions and 2 deletions.
10 changes: 8 additions & 2 deletions testing/src/mocking.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
Tuple,
Union,
cast,
get_args,
)

from ops import JujuVersion, pebble
Expand All @@ -35,6 +36,7 @@
SecretRotate,
_format_action_result_dict,
_ModelBackend,
_SettableStatusName,
)
from ops.pebble import Client, ExecError

Expand All @@ -53,7 +55,6 @@
_EntityStatus,
_port_cls_by_protocol,
_RawPortProtocolLiteral,
_RawStatusLiteral,
)

if TYPE_CHECKING: # pragma: no cover
Expand Down Expand Up @@ -351,11 +352,16 @@ def application_version_set(self, version: str):

def status_set(
self,
status: _RawStatusLiteral,
status: _SettableStatusName,
message: str = "",
*,
is_app: bool = False,
):
valid_names = get_args(_SettableStatusName)
if status not in valid_names:
raise ModelError(
f'ERROR invalid status "{status}", expected one of [{", ".join(valid_names)}]',
)
self._context._record_status(self._state, is_app)
status_obj = _EntityStatus.from_status_name(status, message)
self._state._update_status(status_obj, is_app)
Expand Down
46 changes: 46 additions & 0 deletions testing/tests/test_e2e/test_status.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
UnknownStatus,
WaitingStatus,
)
from scenario.errors import UncaughtCharmError
from ..helpers import trigger


Expand Down Expand Up @@ -169,3 +170,48 @@ def test_status_comparison(status):
assert isinstance(status, type(ops_status))
# The repr of the scenario and ops classes should be identical.
assert repr(status) == repr(ops_status)


@pytest.mark.parametrize(
"status",
(
ActiveStatus("foo"),
WaitingStatus("bar"),
BlockedStatus("baz"),
MaintenanceStatus("qux"),
),
)
def test_status_success(status: ops.StatusBase):
class MyCharm(CharmBase):
def __init__(self, framework: Framework):
super().__init__(framework)
framework.observe(self.on.update_status, self._on_update_status)

def _on_update_status(self, _):
self.unit.status = status

ctx = Context(MyCharm, meta={"name": "foo"})
ctx.run(ctx.on.update_status(), State())


@pytest.mark.parametrize(
"status",
(
ErrorStatus("fiz"),
UnknownStatus(),
),
)
def test_status_error(status: ops.StatusBase):
class MyCharm(CharmBase):
def __init__(self, framework: Framework):
super().__init__(framework)
framework.observe(self.on.update_status, self._on_update_status)

def _on_update_status(self, _):
self.unit.status = status

ctx = Context(MyCharm, meta={"name": "foo"})
with pytest.raises(UncaughtCharmError) as excinfo:
ctx.run(ctx.on.update_status(), State())
assert isinstance(excinfo.value.__cause__, ops.ModelError)
assert f'invalid status "{status.name}"' in str(excinfo.value.__cause__)

0 comments on commit 68cf2d7

Please sign in to comment.