LemonPlatformTest. EventsFixtures
(lemon_platform_test v0.1.0)
View Source
Builders for valid typed LemonCore.Events.* payloads, for use in tests.
Tests that publish onto LemonCore.Bus used to hand-construct raw payload maps:
LemonCore.Bus.broadcast(
LemonCore.Bus.run_topic(run_id),
LemonCore.Event.new(:run_completed, %{completed: %{ok: true, answer: "Done"}}, meta)
)A raw map drifts from the contract the moment a field is added, renamed, or made
mandatory — and it silently omits enforced keys (the %{seq: 1, text: "..."} delta
map above is missing its run_id, which the typed Delta requires). These
builders produce the real struct instead, so a test payload is exactly as valid as a
production one:
LemonCore.Bus.broadcast(
LemonCore.Bus.run_topic(run_id),
LemonCore.Event.new(:run_completed, EventsFixtures.run_completed(answer: "Done"), meta)
)Defaults and overrides
Every builder fills the payload's enforced keys with sensible sample values and leaves optional keys at their struct default, so a no-argument call is always a valid payload. Pass a keyword list or map to override any field:
EventsFixtures.delta(text: "chunk two", seq: 2)
EventsFixtures.run_started(run_id: "run_42", engine: "native")Unknown keys raise, because each builder ends in the payload's strict new/1 — a typo
in a test fixture should fail at the fixture, not surface as a nil field three
assertions later.
Nested payloads
Payloads that wrap another payload accept shorthand: fields belonging to the nested
struct can be passed at the top level and are routed inward. For run_completed the
nested LemonCore.Events.Completion fields (:ok, :answer, :error, :usage, …)
are lifted automatically:
EventsFixtures.run_completed(ok: false, error: :timeout, duration_ms: 30)Pass :completed (a Completion struct or an attrs map) explicitly to build it
yourself; an explicit :completed wins over any shorthand. The nested builders
(completion/1, action/1, approval_pending/1) are public so you can compose them
directly.
This module is the fixture companion to LemonPlatformTest.EventsCase, which asserts
the payload contract. Like that case, it needs :lemon_core (the EventsCase -> lemon_core row in the kit's dep table); anyone building event payloads already has it.
Summary
Types
Field overrides for a builder, as a keyword list or map.
Functions
A LemonCore.Events.Action — the nested record inside engine_action.
A LemonCore.Events.ApprovalPending — the nested record inside the approval events.
A LemonCore.Events.Completion — the terminal result nested in run_completed.
A LemonCore.Events.CronJobChanged (the cron_job_created/updated/deleted payload).
A LemonCore.Events.CronTick. Enforced: :timestamp_ms (default a fixed sample).
A LemonCore.Events.Delta — a chunk of streamed text.
A LemonCore.Events.RunCompleted wrapping a Completion.
A LemonCore.Events.RunStarted. Enforced: :run_id (default "run_test").
Types
@type overrides() :: Enumerable.t()
Field overrides for a builder, as a keyword list or map.
Functions
@spec action(overrides()) :: LemonCore.Events.Action.t()
A LemonCore.Events.Action — the nested record inside engine_action.
Enforced: :id (default "act_1"), :kind (default :tool), :title
(default "Example action").
@spec approval_pending(overrides()) :: LemonCore.Events.ApprovalPending.t()
A LemonCore.Events.ApprovalPending — the nested record inside the approval events.
Enforced: :id (default "appr_1"), :tool (default "bash").
@spec approval_requested(overrides()) :: LemonCore.Events.ApprovalRequested.t()
A LemonCore.Events.ApprovalRequested.
Enforced: :approval_id (default "appr_1") and :pending (default
approval_pending/1). Pass :pending as an ApprovalPending struct or an attrs map.
@spec approval_resolved(overrides()) :: LemonCore.Events.ApprovalResolved.t()
A LemonCore.Events.ApprovalResolved.
Enforced: :approval_id (default "appr_1") and :decision (default :approve_once;
see LemonCore.Events.ApprovalResolved.decisions/0). :pending is optional; pass an
ApprovalPending struct or an attrs map to include it.
@spec completion(overrides()) :: LemonCore.Events.Completion.t()
A LemonCore.Events.Completion — the terminal result nested in run_completed.
Enforced: :ok (default true). Defaults :answer to "ok".
@spec cron_job_changed(overrides()) :: LemonCore.Events.CronJobChanged.t()
A LemonCore.Events.CronJobChanged (the cron_job_created/updated/deleted payload).
Enforced: :action (default :created), :job_id (default "job_1").
@spec cron_run_completed(overrides()) :: LemonCore.Events.CronRunCompleted.t()
A LemonCore.Events.CronRunCompleted.
Enforced: :cron_run_id (default "cron_run_1"), :job_id (default "job_1").
Defaults :status to :ok.
@spec cron_run_started(overrides()) :: LemonCore.Events.CronRunStarted.t()
A LemonCore.Events.CronRunStarted.
Enforced: :cron_run_id (default "cron_run_1"), :job_id (default "job_1").
@spec cron_tick(overrides()) :: LemonCore.Events.CronTick.t()
A LemonCore.Events.CronTick. Enforced: :timestamp_ms (default a fixed sample).
@spec delta(overrides()) :: LemonCore.Events.Delta.t()
A LemonCore.Events.Delta — a chunk of streamed text.
Enforced: :run_id (default "run_test"), :seq (default 0), :text
(default "delta"). Unlike the legacy raw map, run_id lives in the payload
where the typed contract requires it.
@spec run_completed(overrides()) :: LemonCore.Events.RunCompleted.t()
A LemonCore.Events.RunCompleted wrapping a Completion.
The nested completion is built from :completed when given, otherwise from any
Completion shorthand fields passed at the top level (:ok, :answer, :error,
:usage, …). Everything else (:duration_ms) is a RunCompleted field.
EventsFixtures.run_completed() # ok: true, answer: "ok"
EventsFixtures.run_completed(answer: "Done", duration_ms: 100)
EventsFixtures.run_completed(ok: false, error: :timeout)
EventsFixtures.run_completed(completed: EventsFixtures.completion(ok: false))
@spec run_failed(overrides()) :: LemonCore.Events.RunFailed.t()
Enforced: :run_id (default "run_test"), :reason (default :test_failure).
@spec run_started(overrides()) :: LemonCore.Events.RunStarted.t()
A LemonCore.Events.RunStarted. Enforced: :run_id (default "run_test").