Sometimes you’d like your integration tests to simulate lots of different event sequences that might be thrown at your charm. What if immediately after install
you get a pebble-ready
? What if you get it before install
? What if you get it again, twice in a row, after a relation-joined
event in the middle of a charm’s operation phase.
This is why I wrote the CharmEventSimulator
, a python class that takes care of generating valid but random sequences of events based on what you decide are the plausible actions and events that might hit a charm during its lifetime. You can find it here.
It’s just a prototype and could use some validation and testing, but the idea is this: suppose you have a Charm with a storage mount called storage1
, a peer relation called replicas
, and a non-peer relation called http
.
You write:
sim = CharmEventSimulator(
# relations & storage we start with
storage_mounts=[
StorageMount('storage1')],
relations=[
Relation('http'),
Relation('replicas', is_peer=True)
],
# relations & storage that ATM we don't have but might have in
# the future if another charm is deployed and related to this one
potential_relations=[
Relation('mongo')
],
potential_storage_mounts=[
StorageMount('ephemeral1')
]
)
sim.run()
sim.pprint()
and you obtain:
simulation:
PHASE Phase.setup:
Event :: workload-pebble-ready
Event :: storage1-storage-attached
Event :: install
Event :: update-status
Event :: replicas-relation-created
Event :: leader-elected
Event :: config-changed
Event :: start
PHASE Phase.operation:
Action :: Source.user --> 'config-change'
Event :: config-changed
Action :: Source.user --> 'scale+'
Event :: replicas-relation-joined
Event :: replicas-relation-changed
Action :: Source.user --> 'attach'(ephemeral1)
Event :: update-status
Event :: ephemeral1-storage-attached
Action :: Source.other_charm --> 'change'(replicas)
Event :: replicas-relation-changed
Action :: Source.other_charm --> 'change'(replicas)
Event :: replicas-relation-changed
Action :: Source.user --> 'create'(mongo)
Event :: workload-pebble-ready
Event :: mongo-relation-created
Action :: Source.user --> 'break'(http)
Event :: http-relation-broken
Action :: Source.this_charm --> 'change'(http)
Event :: http-relation-changed
Action :: Source.user --> 'leadership_change'
Event :: leader-settings-changed
Action :: Source.other_charm --> 'change'(replicas)
Event :: replicas-relation-changed
Action :: Source.user --> 'detach'(storage1)
Event :: workload-pebble-ready
Event :: storage1-storage-detached
PHASE Phase.teardown:
Event :: replicas-relation-broken
Event :: mongo-relation-broken
Event :: update-status
Event :: ephemeral1-storage-detached
Event :: stop
Event :: remove
end.
This is a temporally-ordered sequence of events that realistically emulates a possible happy-path execution of your charm in a unit. It tells a story:
- This is a charm that begins with 1 unit;
- the workload container is immediately ready, after which a standard startup phase follows;
- The user changes the charm’s config;
- The user scales the unit up; this triggers replicas-relation-joined->replicas-relation-changed.
- The user attaches
ephemeral1
storage; triggering a 'ephemeral1-storage-attached event - …
And so on and so forth.
To be continued!