LemonPlatformTest.EventsCase (lemon_platform_test v0.1.0)

View Source

Contract suite for typed bus payloads (LemonCore.Events.*).

Run it against the platform's own registry, or against your extension's payload modules if you publish your own events onto LemonCore.Bus:

defmodule MyApp.EventsContractTest do
  use LemonPlatformTest.EventsCase, modules: [MyApp.Events.ThingHappened]
end

With no :modules option it exercises everything in LemonCore.Events.modules/0.

What it asserts

  1. Registry completeness — every registered type resolves to a loaded module that exports the payload callbacks.
  2. Round-tripstruct |> Map.from_struct() |> from_map() returns the struct, which is what makes the legacy-map acceptance path honest rather than lossy.
  3. String keysfrom_map/1 accepts the string-keyed form that arrives from the control-plane event methods.
  4. Unknown keysnew/1 rejects them (publisher-side typo protection) and from_map/1 drops them (consumer-side tolerance).
  5. Introspection compatibility — a struct payload sanitizes to the same map its untyped predecessor did, so Introspection.record/3 needs no per-event handling.
  6. JSON encodability — payloads survive Jason.encode/1, which the JSONL store backend and the control plane both require.
  7. Envelope discipline and backend parity — publishing through LemonCore.Bus.broadcast_event/4 delivers a %LemonCore.Event{} carrying the struct intact, asserted under both bus backends. Publishers that check for a specific backend process rather than using the Bus API are inert under the Registry fallback; running every delivery assertion twice is what catches that.
  8. Deprecation hygiene — payload modules implement Access only as a temporary shim, so each must carry a deprecation note pointing at its removal.

Example values

Payload modules with enforced keys need a sample to test. Supply them with :examples when the defaults cannot be inferred:

use LemonPlatformTest.EventsCase,
  modules: [MyApp.Events.ThingHappened],
  examples: %{MyApp.Events.ThingHappened => %{thing_id: "t_1"}}

See also

LemonPlatformTest.EventsFixtures builds valid typed payloads (with defaults and overrides) for use in other tests that publish onto the bus — the fixture companion to this contract suite.

Summary

Functions

The functions a module marks @deprecated, read from its docs chunk.

Build a sample payload for a module, from examples or by filling enforced keys.

Replace every true in a payload with false, recursively, leaving other values alone.

Strip every struct out of a payload, recursively, leaving plain maps.

Run fun with the bus forced onto a specific backend, restoring the previous setting.

Functions

deprecated_functions(module)

@spec deprecated_functions(module()) :: [{atom(), arity()}]

The functions a module marks @deprecated, read from its docs chunk.

@deprecated is recorded as doc metadata rather than a module attribute, so it is only visible here — and only when the module was compiled with docs.

example(module, examples)

@spec example(module(), %{optional(module()) => map()}) :: struct()

Build a sample payload for a module, from examples or by filling enforced keys.

falsify_booleans(struct)

@spec falsify_booleans(term()) :: term()

Replace every true in a payload with false, recursively, leaving other values alone.

to_plain_maps(struct)

@spec to_plain_maps(term()) :: term()

Strip every struct out of a payload, recursively, leaving plain maps.

Approximates what a payload looks like after a JSON round-trip, which is how one arrives from the control-plane event methods or an external agent.

with_backend(backend, fun)

@spec with_backend(:pubsub | :registry, (-> any())) :: any()

Run fun with the bus forced onto a specific backend, restoring the previous setting.

The Registry fallback is a supported deployment (see LemonCore.Bus), so contract assertions have to hold under it too.