Hi all! Scenario 5.2 just released with a new interface for introspecting the charm state during a scenario test execution.
Normally, a scenario test is a black-box, state-transition test.
state-in
state-out
this leaves little room for getting a hold of the charm instance and, say, checking that my_charm.charm_lib._foo.bar(42) == "foo"
.
For a long time there has been an experimental, undocumented ‘callback’ API exposing pre-event and post-event hooks, callbacks that would be called with the charm instance before and after the event emission took place.
That API was however a bit obscure and unpythonic, so we refactored it to be a context manager:
from ops import CharmBase, StoredState
from charms.bar.lib_name.v1.charm_lib import CharmLib
from scenario import Context, State
class MyCharm(CharmBase):
META = {"name": "mycharm"}
_stored = StoredState()
def __init__(self, framework):
super().__init__(framework)
self._stored.set_default(a="a")
self.my_charm_lib = CharmLib()
framework.observe(self.on.start, self._on_start)
def _on_start(self, event):
self._stored.a = "b"
def test_live_charm_introspection(mycharm):
ctx = Context(mycharm, meta=mycharm.META)
# If you want to do this with actions, you can use `Context.action_manager` instead.
with ctx.manager("start", State()) as manager:
# this is your charm instance, after ops has set it up
charm: MyCharm = manager.charm
# we can check attributes on nested Objects or the charm itself
assert charm.my_charm_lib.foo == "foo"
# such as stored state
assert charm._stored.a == "a"
# this will tell ops.main to proceed with normal execution and emit the "start" event on the charm
state_out = manager.run()
# after that is done, we are handed back control, and we can again do some introspection
assert charm.my_charm_lib.foo == "bar"
# and check that the charm's internal state is as we expect
assert charm._stored.a == "b"
# state_out is, as in regular scenario tests, a State object you can assert on:
assert state_out.unit_status == ...
Do you think that Context.manager()
is cheeky? Totally agree, and you can blame @benhoyt for that idea. But we love it and we’re going to stick to it.
Give it a try and let us know!