Skip to content

fix(test): keep adapter coverage aligned with EventStore semantics#87

Merged
yordis merged 3 commits intomainfrom
yordis/fix-eventstore-test-parity
Apr 16, 2026
Merged

fix(test): keep adapter coverage aligned with EventStore semantics#87
yordis merged 3 commits intomainfrom
yordis/fix-eventstore-test-parity

Conversation

@yordis
Copy link
Copy Markdown
Member

@yordis yordis commented Apr 16, 2026

  • Reduces the risk of the in-memory adapter masking behaviors that only fail against the Postgres-backed EventStore.
  • Keeps the shared adapter contract anchored in realistic domain events and snapshots instead of synthetic fixtures.
  • Protects duplicate event-id semantics so compatibility gaps surface in adapter tests before they reach production paths.

Signed-off-by: Yordis Prieto <yordis.prieto@gmail.com>
@cursor
Copy link
Copy Markdown

cursor bot commented Apr 16, 2026

PR Summary

Low Risk
Changes are confined to test/support code and test expectations; the main risk is accidental breakage of existing tests due to updated fixture generation and stricter semantics around event_id and snapshot metadata.

Overview
Adapter contract tests now use a new shared helper (Commanded.EventStore.AdapterTestData) built around example domain events/snapshots, replacing ad-hoc %EventData{}/inline structs and standardizing default metadata.

Test helpers were updated so Commanded.Helpers.EventFactory.map_to_recorded_events/3 preserves explicit event_ids (instead of always generating new ones), and Commanded.TestSupport.Factory.build_recorded_event/1 now delegates struct-backed events through EventFactory while still supporting raw data.

Coverage is expanded to assert explicit event-id propagation and duplicate event-id rejection across streams, and to verify snapshot reads preserve key fields and metadata across adapters; telemetry/opentelemetry and projection tests were updated to use the new builders.

Reviewed by Cursor Bugbot for commit e3c70ac. Bugbot is set up for automated code reviews on this repo. Configure here.

@coderabbitai
Copy link
Copy Markdown

coderabbitai bot commented Apr 16, 2026

Walkthrough

A new test support module Commanded.EventStore.AdapterTestData is introduced with builder functions for events and snapshots. Multiple test modules are refactored to use centralized event/snapshot construction via this module and updated factory helpers, replacing local test data construction.

Changes

Cohort / File(s) Summary
New Test Support Module
test/event_store/support/adapter_test_data.ex
Introduces AdapterTestData with public builder functions for BankAccountOpened and MoneyDeposited events, recorded events, and snapshot data with customizable options (IDs, metadata, defaults).
Factory & Helper Updates
test/support/factory.ex, test/helpers/event_factory.ex
Updates build_recorded_event/1 to lazily generate IDs/metadata and conditionally delegate to EventFactory.map_to_recorded_events/3 for struct data. Updates map_to_recorded_events/3 to lazily generate UUIDs and reuse existing event_id when present.
Event Store Test Suite
test/event_store/adapters/in_memory/in_memory_test.exs, test/event_store/recorded_event_test.exs, test/event_store/support/append_events_test_case.ex, test/event_store/support/event_store_prefix_test_case.ex, test/event_store/support/snapshot_test_case.ex, test/event_store/support/subscription_test_case.ex, test/event_store/telemetry_test.exs
Migrate from local event/snapshot construction to delegating to AdapterTestData builders; remove embedded BankAccountOpened structs and direct EventData construction.
Aggregate & Projection Tests
test/aggregates/aggregate_lifespan_test.exs, test/projections/error_callback_test.exs, test/projections/runtime_config_projector_test.exs, test/opentelemetry/event_store_test.exs
Replace manual RecordedEvent struct construction with Factory.build_recorded_event/1 and AdapterTestData builders; remove local test struct definitions.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related PRs

Poem

🐰 Factories and helpers unite at last,
Test data scattered, now consolidated fast!
No more duplication in every test file,
One shared builder makes testing worthwhile! 🎯

🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Title check ✅ Passed The title accurately summarizes the main change: refactoring test fixtures and helpers to improve adapter test coverage alignment with EventStore semantics.
Description check ✅ Passed The description directly relates to the changeset by explaining the intent and benefits of the refactoring work across test files and test data helpers.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch yordis/fix-eventstore-test-parity

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

yordis added 2 commits April 16, 2026 17:22
Signed-off-by: Yordis Prieto <yordis.prieto@gmail.com>
Signed-off-by: Yordis Prieto <yordis.prieto@gmail.com>
Copy link
Copy Markdown

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick comments (3)
test/event_store/support/adapter_test_data.ex (3)

17-28: Optional: forwarding opts to build_opened_event/1 is harmless but opaque.

build_opened_event(opts) on Line 22 is handed the full opts keyword (including :correlation_id, :causation_id, :metadata); those keys are silently ignored by build_opened_event/1 since it only reads :account_number and :initial_balance. This works but makes it unclear which keys belong to which layer. Consider passing only the struct-relevant keys, e.g. build_opened_event(Keyword.take(opts, [:account_number, :initial_balance])).

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@test/event_store/support/adapter_test_data.ex` around lines 17 - 28,
build_opened_event_data currently forwards the entire opts to build_opened_event
(which only uses :account_number and :initial_balance), making ownership of keys
opaque; change build_opened_event_data to pass only the event-struct keys to
build_opened_event (e.g. use Keyword.take(opts, [:account_number,
:initial_balance]) or equivalent) while keeping correlation_id, causation_id,
and metadata handled locally before calling Mapper.map_to_event_data so
build_opened_event receives only the keys it intends to consume.

48-74: Naming: build_deposit_event vs build_deposited_event/build_deposited_event_data is confusing.

Three functions with similar names express different return types:

  • build_deposited_event/1 → raw %MoneyDeposited{} struct
  • build_deposited_event_data/1 → mapped %EventData{}
  • build_deposit_event/2 → mapped %EventData{} (same as build_deposited_event_data) but with a positional account_number

build_deposit_event being a positional-arg wrapper that returns the same shape as build_deposited_event_data — while build_deposited_event returns a different shape — is easy to misuse at call sites. Consider renaming for symmetry with the opened helpers (build_opened_event / build_opened_event_data / build_opened_events), e.g., build_deposited_events/2 or keeping the wrapper but naming it build_deposit_event_data/2.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@test/event_store/support/adapter_test_data.ex` around lines 48 - 74, Rename
the confusing helper build_deposit_event/2 to a name that clearly indicates it
returns EventData (e.g., build_deposit_event_data/2 or build_deposited_events/2)
so it matches build_deposited_event_data/1 and distinguishes from
build_deposited_event/1 (the raw %MoneyDeposited{} struct); update the function
definition (originally named build_deposit_event) and all call sites to the new
name and ensure it still forwards to build_deposited_event_data by passing the
account_number into the opts (use Keyword.put(opts, :account_number,
account_number)) so behavior remains identical.

80-102: Minor: source_version doubling as default account_number reads oddly.

On Line 88, the default account_number falls back to source_version. source_version semantically represents an aggregate version (typically small, monotonically increasing), while account_number is an identifier. Callers in snapshot_test_case.ex pass 100, 101, 102 as source_version purely to get unique default account numbers, which obscures the test intent.

Consider decoupling the defaults (e.g., default source_version to 1 and let callers pass account_number explicitly when uniqueness matters), or renaming the positional arg. Non-blocking.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@test/event_store/support/adapter_test_data.ex` around lines 80 - 102,
build_snapshot_data currently uses source_version as the default account_number
which conflates version with identifier; update build_snapshot_data to decouple
these defaults: change the positional default for source_version to a stable
default (e.g., 1) and stop using source_version for account_number — instead
derive account_number from opts (Keyword.get(opts, :account_number, <a unique
default like UUID.uuid4/0>)) so callers who need unique account numbers pass
:account_number explicitly (adjust snapshot_test_case.ex callers to pass
account_number where uniqueness was previously achieved via source_version).
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@test/event_store/support/adapter_test_data.ex`:
- Around line 17-28: build_opened_event_data currently forwards the entire opts
to build_opened_event (which only uses :account_number and :initial_balance),
making ownership of keys opaque; change build_opened_event_data to pass only the
event-struct keys to build_opened_event (e.g. use Keyword.take(opts,
[:account_number, :initial_balance]) or equivalent) while keeping
correlation_id, causation_id, and metadata handled locally before calling
Mapper.map_to_event_data so build_opened_event receives only the keys it intends
to consume.
- Around line 48-74: Rename the confusing helper build_deposit_event/2 to a name
that clearly indicates it returns EventData (e.g., build_deposit_event_data/2 or
build_deposited_events/2) so it matches build_deposited_event_data/1 and
distinguishes from build_deposited_event/1 (the raw %MoneyDeposited{} struct);
update the function definition (originally named build_deposit_event) and all
call sites to the new name and ensure it still forwards to
build_deposited_event_data by passing the account_number into the opts (use
Keyword.put(opts, :account_number, account_number)) so behavior remains
identical.
- Around line 80-102: build_snapshot_data currently uses source_version as the
default account_number which conflates version with identifier; update
build_snapshot_data to decouple these defaults: change the positional default
for source_version to a stable default (e.g., 1) and stop using source_version
for account_number — instead derive account_number from opts (Keyword.get(opts,
:account_number, <a unique default like UUID.uuid4/0>)) so callers who need
unique account numbers pass :account_number explicitly (adjust
snapshot_test_case.ex callers to pass account_number where uniqueness was
previously achieved via source_version).

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 04e67cc9-9c7f-4f89-91bd-2f56361f789c

📥 Commits

Reviewing files that changed from the base of the PR and between c0e76ba and e3c70ac.

📒 Files selected for processing (14)
  • test/aggregates/aggregate_lifespan_test.exs
  • test/event_store/adapters/in_memory/in_memory_test.exs
  • test/event_store/recorded_event_test.exs
  • test/event_store/support/adapter_test_data.ex
  • test/event_store/support/append_events_test_case.ex
  • test/event_store/support/event_store_prefix_test_case.ex
  • test/event_store/support/snapshot_test_case.ex
  • test/event_store/support/subscription_test_case.ex
  • test/event_store/telemetry_test.exs
  • test/helpers/event_factory.ex
  • test/opentelemetry/event_store_test.exs
  • test/projections/error_callback_test.exs
  • test/projections/runtime_config_projector_test.exs
  • test/support/factory.ex

@yordis yordis merged commit 6aa37fd into main Apr 16, 2026
3 checks passed
@yordis yordis deleted the yordis/fix-eventstore-test-parity branch April 16, 2026 23:43
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant