Skip to content

Commit

Permalink
better docstring for Context
Browse files Browse the repository at this point in the history
  • Loading branch information
PietroPasotti committed Sep 19, 2023
1 parent 39352ac commit 181f103
Show file tree
Hide file tree
Showing 3 changed files with 45 additions and 4 deletions.
2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ build-backend = "setuptools.build_meta"
[project]
name = "ops-scenario"

version = "5.2.1"
version = "5.2.2"

authors = [
{ name = "Pietro Pasotti", email = "[email protected]" }
Expand Down
45 changes: 43 additions & 2 deletions scenario/context.py
Original file line number Diff line number Diff line change
Expand Up @@ -150,7 +150,49 @@ def __init__(
charm_root: "PathLike" = None,
juju_version: str = "3.0",
):
"""Initializer.
"""Represents a simulated charm's execution context.
It is the main entry point to running a scenario test.
It contains: the charm source code being executed, the metadata files associated with it,
a charm project repository root, and the juju version to be simulated.
After you have instantiated Context, typically you will call one of `run()` or
`run_action()` to execute the charm once, write any assertions you like on the output
state returned by the call, write any assertions you like on the Context attributes,
then discard the Context.
Each Context instance is in principle designed to be single-use:
Context is not cleaned up automatically between charm runs.
You can call `.clear()` to do some clean up, but we don't guarantee all state will be gone.
Any side effects generated by executing the charm, that are not rightful part of the State,
are in fact stored in the Context:
- ``juju_log``: record of what the charm has sent to juju-log
- ``app_status_history``: record of the app statuses the charm has set
- ``unit_status_history``: record of the unit statuses the charm has set
- ``workload_version_history``: record of the workload versions the charm has set
- ``emitted_events``: record of the events (including custom ones) that the charm has
processed
This allows you to write assertions not only on the output state, but also, to some
extent, on the path the charm took to get there.
A typical scenario test will look like:
>>> from scenario import Context, State
>>> from ops import ActiveStatus
>>> from charm import MyCharm, MyCustomEvent
>>>
>>> def test_foo():
>>> # Arrange: set the context up
>>> c = Context(MyCharm)
>>> # Act: prepare the state and emit an event
>>> state_out = c.run('update-status', State())
>>> # Assert: verify the output state is what you think it should be
>>> assert state_out.unit_status == ActiveStatus('foobar')
>>> # Assert: verify the Context contains what you think it should
>>> assert len(c.emitted_events) == 4
>>> assert isinstance(c.emitted_events[3], MyCustomEvent)
:arg charm_type: the CharmBase subclass to call ``ops.main()`` on.
:arg meta: charm metadata to use. Needs to be a valid metadata.yaml format (as a dict).
Expand All @@ -171,7 +213,6 @@ def __init__(
>>> (local_path / 'foo').mkdir()
>>> (local_path / 'foo' / 'bar.yaml').write_text('foo: bar')
>>> scenario.Context(... charm_root=virtual_root).run(...)
"""

if not any((meta, actions, config)):
Expand Down
2 changes: 1 addition & 1 deletion scenario/scripts/state_apply.py
Original file line number Diff line number Diff line change
Expand Up @@ -223,7 +223,7 @@ def state_apply(
"of k8s charms, this might mean files obtained through Mounts,",
),
):
"""Gather and output the State of a remote target unit.
"""Apply a State to a remote target unit.
If black is available, the output will be piped through it for formatting.
Expand Down

0 comments on commit 181f103

Please sign in to comment.