diff --git a/test/aggregates/aggregate_lifespan_test.exs b/test/aggregates/aggregate_lifespan_test.exs index f19e4a4c..d9af19c2 100644 --- a/test/aggregates/aggregate_lifespan_test.exs +++ b/test/aggregates/aggregate_lifespan_test.exs @@ -3,8 +3,8 @@ defmodule Commanded.Aggregates.AggregateLifespanTest do alias Commanded.Aggregates.{Aggregate, DefaultLifespanRouter, LifespanAggregate, LifespanRouter} alias Commanded.Aggregates.LifespanAggregate.{Command, Event} + alias Commanded.TestSupport.Factory alias Commanded.{DefaultApp, EventStore} - alias Commanded.EventStore.RecordedEvent alias Commanded.{Registration, UUID} describe "aggregate lifespan" do @@ -375,11 +375,11 @@ defmodule Commanded.Aggregates.AggregateLifespanTest do ref: ref } do events = [ - %RecordedEvent{ - event_id: UUID.uuid4(), - stream_version: 1, - data: %Event{uuid: aggregate_uuid} - } + Factory.build_recorded_event( + data: %Event{uuid: aggregate_uuid}, + event_number: 1, + stream_version: 1 + ) ] # Simulate sending an event directly to the aggregate process diff --git a/test/event_store/adapters/in_memory/in_memory_test.exs b/test/event_store/adapters/in_memory/in_memory_test.exs index 2cc31596..9aaa7b9e 100644 --- a/test/event_store/adapters/in_memory/in_memory_test.exs +++ b/test/event_store/adapters/in_memory/in_memory_test.exs @@ -1,14 +1,8 @@ defmodule Commanded.EventStore.Adapters.InMemoryTest do use Commanded.EventStore.InMemoryTestCase + alias Commanded.EventStore.AdapterTestData alias Commanded.EventStore.Adapters.InMemory - alias Commanded.EventStore.EventData - alias Commanded.UUID - - defmodule BankAccountOpened do - @derive Jason.Encoder - defstruct [:account_number, :initial_balance] - end describe "reset!/0" do test "wipes all data from memory", %{event_store_meta: event_store_meta} do @@ -45,17 +39,11 @@ defmodule Commanded.EventStore.Adapters.InMemoryTest do end end - defp build_event(account_number) do - %EventData{ - causation_id: UUID.uuid4(), - correlation_id: UUID.uuid4(), - event_type: "#{__MODULE__}.BankAccountOpened", - data: %BankAccountOpened{account_number: account_number, initial_balance: 1_000}, - metadata: %{"user_id" => "test"} - } - end + defp build_event(account_number), + do: + AdapterTestData.build_opened_events(1, start_account_number: account_number) |> List.first() defp build_events(count) do - for account_number <- 1..count, do: build_event(account_number) + AdapterTestData.build_opened_events(count) end end diff --git a/test/event_store/recorded_event_test.exs b/test/event_store/recorded_event_test.exs index ac991d4f..5bc16c1b 100644 --- a/test/event_store/recorded_event_test.exs +++ b/test/event_store/recorded_event_test.exs @@ -1,21 +1,14 @@ defmodule Commanded.EventStore.RecordedEventTest do use ExUnit.Case + alias Commanded.EventStore.AdapterTestData alias Commanded.EventStore.EnrichedMetadata alias Commanded.EventStore.RecordedEvent - alias Commanded.Helpers.EventFactory - - defmodule BankAccountOpened do - @derive Jason.Encoder - defstruct [:account_number, :initial_balance] - end setup do [event] = - EventFactory.map_to_recorded_events( - [ - %BankAccountOpened{account_number: "123", initial_balance: 1_000} - ], + AdapterTestData.build_recorded_events( + [AdapterTestData.build_opened_event(account_number: "123")], 1, metadata: %{"key1" => "value1", "key2" => "value2"} ) @@ -56,5 +49,20 @@ defmodule Commanded.EventStore.RecordedEventTest do metadata: %{"key1" => "value1", "key2" => "value2"} } = enriched_metadata end + + test "keeps explicit event ids when mapping recorded events" do + transfer_uuid = Commanded.UUID.uuid4() + + [event] = + AdapterTestData.build_recorded_events([ + AdapterTestData.build_deposited_event( + account_number: "123", + transfer_uuid: transfer_uuid + ) + ]) + + assert event.event_id == transfer_uuid + assert event.data.transfer_uuid == transfer_uuid + end end end diff --git a/test/event_store/support/adapter_test_data.ex b/test/event_store/support/adapter_test_data.ex new file mode 100644 index 00000000..7fbf846c --- /dev/null +++ b/test/event_store/support/adapter_test_data.ex @@ -0,0 +1,113 @@ +defmodule Commanded.EventStore.AdapterTestData do + alias Commanded.Event.Mapper + alias Commanded.Helpers.EventFactory + alias Commanded.EventStore.SnapshotData + alias Commanded.EventStore.TypeProvider + alias Commanded.ExampleDomain.BankAccount + alias Commanded.ExampleDomain.BankAccount.Events.{BankAccountOpened, MoneyDeposited} + alias Commanded.UUID + + def build_opened_event(opts \\ []) do + %BankAccountOpened{ + account_number: Keyword.get(opts, :account_number, 1), + initial_balance: Keyword.get(opts, :initial_balance, 1_000) + } + end + + def build_opened_event_data(opts \\ []) do + correlation_id = Keyword.get_lazy(opts, :correlation_id, &UUID.uuid4/0) + causation_id = Keyword.get_lazy(opts, :causation_id, &UUID.uuid4/0) + metadata = Keyword.get(opts, :metadata, default_metadata()) + + build_opened_event(opts) + |> Mapper.map_to_event_data( + correlation_id: correlation_id, + causation_id: causation_id, + metadata: metadata + ) + end + + def build_opened_events(count, opts \\ []) do + correlation_id = Keyword.get_lazy(opts, :correlation_id, &UUID.uuid4/0) + causation_id = Keyword.get_lazy(opts, :causation_id, &UUID.uuid4/0) + initial_balance = Keyword.get(opts, :initial_balance, 1_000) + metadata = Keyword.get(opts, :metadata, default_metadata()) + start_account_number = Keyword.get(opts, :start_account_number, 1) + + start_account_number..(start_account_number + count - 1) + |> Enum.map(fn account_number -> + build_opened_event(account_number: account_number, initial_balance: initial_balance) + end) + |> Mapper.map_to_event_data( + correlation_id: correlation_id, + causation_id: causation_id, + metadata: metadata + ) + end + + def build_deposited_event(opts \\ []) do + transfer_uuid = Keyword.get_lazy(opts, :transfer_uuid, &UUID.uuid4/0) + + %MoneyDeposited{ + account_number: Keyword.get(opts, :account_number, 1), + transfer_uuid: transfer_uuid, + amount: Keyword.get(opts, :amount, 250), + balance: Keyword.get(opts, :balance, 1_250) + } + end + + def build_deposited_event_data(opts \\ []) do + correlation_id = Keyword.get_lazy(opts, :correlation_id, &UUID.uuid4/0) + causation_id = Keyword.get_lazy(opts, :causation_id, &UUID.uuid4/0) + metadata = Keyword.get(opts, :metadata, default_metadata()) + + build_deposited_event(opts) + |> Mapper.map_to_event_data( + correlation_id: correlation_id, + causation_id: causation_id, + metadata: metadata + ) + end + + def build_deposit_event(account_number, opts \\ []) do + build_deposited_event_data(Keyword.put(opts, :account_number, account_number)) + end + + def build_recorded_events(events, initial_event_number \\ 1, opts \\ []) do + EventFactory.map_to_recorded_events(events, initial_event_number, opts) + end + + def build_snapshot_data(source_version, opts \\ []) do + created_at = Keyword.get(opts, :created_at, DateTime.utc_now()) + metadata = Keyword.get(opts, :metadata, nil) + source_uuid = Keyword.get_lazy(opts, :source_uuid, &UUID.uuid4/0) + + account_state = + Keyword.get_lazy(opts, :data, fn -> + %BankAccount{ + account_number: Keyword.get(opts, :account_number, source_version), + state: :active, + balance: Keyword.get(opts, :balance, 1_000) + } + end) + + %SnapshotData{ + source_uuid: source_uuid, + source_version: source_version, + source_type: TypeProvider.to_string(account_state), + data: account_state, + metadata: metadata, + created_at: created_at + } + end + + def default_metadata do + %{ + "channel" => "web", + "request" => %{ + "actor_id" => "customer-123", + "actor_type" => "customer" + } + } + end +end diff --git a/test/event_store/support/append_events_test_case.ex b/test/event_store/support/append_events_test_case.ex index ae296d56..111e0aa3 100644 --- a/test/event_store/support/append_events_test_case.ex +++ b/test/event_store/support/append_events_test_case.ex @@ -4,14 +4,9 @@ defmodule Commanded.EventStore.AppendEventsTestCase do define_tests do import Commanded.Enumerable, only: [pluck: 2] - alias Commanded.EventStore.EventData + alias Commanded.EventStore.AdapterTestData alias Commanded.UUID - defmodule BankAccountOpened do - @derive Jason.Encoder - defstruct [:account_number, :initial_balance] - end - describe "event store adapter" do test "should implement `Commanded.EventStore.Adapter` behaviour", %{ event_store: event_store @@ -147,6 +142,35 @@ defmodule Commanded.EventStore.AppendEventsTestCase do assert :ok == event_store.append_to_stream(event_store_meta, "stream", 3, build_events(1)) end + + test "should preserve explicit event ids and reject duplicates across streams", %{ + event_store: event_store, + event_store_meta: event_store_meta + } do + transfer_uuid = UUID.uuid4() + + assert :ok == + event_store.append_to_stream( + event_store_meta, + "stream-1", + 0, + [build_deposit_event(101, transfer_uuid: transfer_uuid)] + ) + + [recorded_event] = + event_store.stream_forward(event_store_meta, "stream-1") |> Enum.to_list() + + assert recorded_event.event_id == transfer_uuid + assert recorded_event.data.transfer_uuid == transfer_uuid + + assert {:error, :duplicate_event} == + event_store.append_to_stream( + event_store_meta, + "stream-2", + 0, + [build_deposit_event(202, transfer_uuid: transfer_uuid)] + ) + end end describe "stream events from an unknown stream" do @@ -177,7 +201,7 @@ defmodule Commanded.EventStore.AppendEventsTestCase do assert event.stream_id == "stream" assert event.correlation_id == correlation_id assert event.causation_id == causation_id - assert event.metadata == %{"metadata" => "value"} + assert event.metadata == AdapterTestData.default_metadata() assert %DateTime{} = event.created_at end) @@ -225,21 +249,17 @@ defmodule Commanded.EventStore.AppendEventsTestCase do end end - defp build_event(account_number, correlation_id, causation_id) do - %EventData{ - correlation_id: correlation_id, - causation_id: causation_id, - event_type: "#{__MODULE__}.BankAccountOpened", - data: %BankAccountOpened{account_number: account_number, initial_balance: 1_000}, - metadata: %{"metadata" => "value"} - } - end - defp build_events(count, correlation_id \\ UUID.uuid4(), causation_id \\ UUID.uuid4()) defp build_events(count, correlation_id, causation_id) do - for account_number <- 1..count, - do: build_event(account_number, correlation_id, causation_id) + AdapterTestData.build_opened_events(count, + correlation_id: correlation_id, + causation_id: causation_id + ) + end + + defp build_deposit_event(account_number, opts) do + AdapterTestData.build_deposit_event(account_number, opts) end defp assert_is_uuid(uuid) do @@ -259,6 +279,7 @@ defmodule Commanded.EventStore.AppendEventsTestCase do &%{ causation_id: &1.causation_id, correlation_id: &1.correlation_id, + event_type: &1.event_type, data: &1.data, metadata: &1.metadata } diff --git a/test/event_store/support/event_store_prefix_test_case.ex b/test/event_store/support/event_store_prefix_test_case.ex index e8b86e02..4c6c76b9 100644 --- a/test/event_store/support/event_store_prefix_test_case.ex +++ b/test/event_store/support/event_store_prefix_test_case.ex @@ -2,14 +2,9 @@ defmodule Commanded.EventStore.EventStorePrefixTestCase do import Commanded.SharedTestCase define_tests do - alias Commanded.EventStore.EventData + alias Commanded.EventStore.AdapterTestData alias Commanded.UUID - defmodule BankAccountOpened do - @derive Jason.Encoder - defstruct [:account_number, :initial_balance] - end - describe "event store prefix" do setup do {:ok, event_store_meta1} = start_event_store(name: :prefix1, prefix: "prefix1") @@ -35,18 +30,10 @@ defmodule Commanded.EventStore.EventStorePrefixTestCase do defp build_events(count, correlation_id \\ UUID.uuid4(), causation_id \\ UUID.uuid4()) defp build_events(count, correlation_id, causation_id) do - for account_number <- 1..count, - do: build_event(account_number, correlation_id, causation_id) - end - - defp build_event(account_number, correlation_id, causation_id) do - %EventData{ + AdapterTestData.build_opened_events(count, correlation_id: correlation_id, - causation_id: causation_id, - event_type: "#{__MODULE__}.BankAccountOpened", - data: %BankAccountOpened{account_number: account_number, initial_balance: 1_000}, - metadata: %{"metadata" => "value"} - } + causation_id: causation_id + ) end end end diff --git a/test/event_store/support/snapshot_test_case.ex b/test/event_store/support/snapshot_test_case.ex index 73514a20..05a2ac5c 100644 --- a/test/event_store/support/snapshot_test_case.ex +++ b/test/event_store/support/snapshot_test_case.ex @@ -2,13 +2,7 @@ defmodule Commanded.EventStore.SnapshotTestCase do import Commanded.SharedTestCase define_tests do - alias Commanded.EventStore.SnapshotData - alias Commanded.UUID - - defmodule BankAccountOpened do - @derive Jason.Encoder - defstruct [:account_number, :initial_balance] - end + alias Commanded.EventStore.AdapterTestData describe "record a snapshot" do test "should record the snapshot", %{ @@ -36,9 +30,36 @@ defmodule Commanded.EventStore.SnapshotTestCase do {:ok, snapshot} = event_store.read_snapshot(event_store_meta, snapshot3.source_uuid) + assert snapshot.source_uuid == snapshot3.source_uuid + assert snapshot.source_version == snapshot3.source_version + assert snapshot.source_type == snapshot3.source_type + assert snapshot.metadata == snapshot3.metadata + assert snapshot.data.__struct__ == snapshot3.data.__struct__ + assert snapshot.data.account_number == snapshot3.data.account_number + assert snapshot.data.balance == snapshot3.data.balance + assert snapshot.data.state == to_string(snapshot3.data.state) assert snapshot_timestamps_within_delta?(snapshot, snapshot3, 60) end + test "should preserve snapshot metadata", %{ + event_store: event_store, + event_store_meta: event_store_meta + } do + metadata = %{ + "request" => %{"actor_id" => "customer-123", "roles" => ["admin", "support"]}, + "trace_id" => "trace-123" + } + + snapshot = build_snapshot_data(100, metadata: metadata) + + assert :ok == event_store.record_snapshot(event_store_meta, snapshot) + + assert {:ok, read_snapshot} = + event_store.read_snapshot(event_store_meta, snapshot.source_uuid) + + assert read_snapshot.metadata == metadata + end + test "should error when snapshot does not exist", %{ event_store: event_store, event_store_meta: event_store_meta @@ -66,16 +87,8 @@ defmodule Commanded.EventStore.SnapshotTestCase do end end - defp build_snapshot_data(account_number) do - %SnapshotData{ - source_uuid: UUID.uuid4(), - source_version: account_number, - source_type: "#{__MODULE__}.BankAccountOpened", - data: %BankAccountOpened{account_number: account_number, initial_balance: 1_000}, - metadata: nil, - created_at: DateTime.utc_now() - } - end + defp build_snapshot_data(account_number, opts \\ []), + do: AdapterTestData.build_snapshot_data(account_number, opts) defp snapshot_timestamps_within_delta?(snapshot, other_snapshot, delta_seconds) do DateTime.diff(snapshot.created_at, other_snapshot.created_at, :second) < delta_seconds diff --git a/test/event_store/support/subscription_test_case.ex b/test/event_store/support/subscription_test_case.ex index 7c17432a..8b818952 100644 --- a/test/event_store/support/subscription_test_case.ex +++ b/test/event_store/support/subscription_test_case.ex @@ -2,15 +2,10 @@ defmodule Commanded.EventStore.SubscriptionTestCase do import Commanded.SharedTestCase define_tests do - alias Commanded.EventStore.{EventData, RecordedEvent, Subscriber} + alias Commanded.EventStore.{AdapterTestData, RecordedEvent, Subscriber} alias Commanded.Helpers.ProcessHelper alias Commanded.UUID - defmodule BankAccountOpened do - @derive Jason.Encoder - defstruct [:account_number, :initial_balance] - end - describe "transient subscription to single stream" do test "should receive events appended to the stream", %{ event_store: event_store, @@ -899,18 +894,8 @@ defmodule Commanded.EventStore.SubscriptionTestCase do end end - defp build_event(account_number) do - %EventData{ - causation_id: UUID.uuid4(), - correlation_id: UUID.uuid4(), - event_type: "#{__MODULE__}.BankAccountOpened", - data: %BankAccountOpened{account_number: account_number, initial_balance: 1_000}, - metadata: %{"user_id" => "test"} - } - end - defp build_events(count) do - for account_number <- 1..count, do: build_event(account_number) + AdapterTestData.build_opened_events(count) end end end diff --git a/test/event_store/telemetry_test.exs b/test/event_store/telemetry_test.exs index 35eec7fe..ad6d8911 100644 --- a/test/event_store/telemetry_test.exs +++ b/test/event_store/telemetry_test.exs @@ -5,10 +5,9 @@ defmodule Commanded.EventStore.TelemetryTest do alias Commanded.DefaultApp alias Commanded.EventStore + alias Commanded.EventStore.AdapterTestData alias Commanded.EventStore.Adapters.Mock, as: MockEventStore - alias Commanded.EventStore.EventData alias Commanded.EventStore.RecordedEvent - alias Commanded.EventStore.SnapshotData alias Commanded.Middleware.Commands.IncrementCount alias Commanded.Middleware.Commands.RaiseError alias Commanded.MockedApp @@ -40,7 +39,7 @@ defmodule Commanded.EventStore.TelemetryTest do describe "snapshotting telemetry events" do test "emit `[:commanded, :event_store, :record_snapshot, :start | :stop]` event" do - snapshot = %SnapshotData{} + snapshot = build_snapshot() assert :ok = EventStore.record_snapshot(DefaultApp, snapshot) assert_receive {[:commanded, :event_store, :record_snapshot, :start], 1, _meas, _meta} @@ -85,7 +84,7 @@ defmodule Commanded.EventStore.TelemetryTest do test "emit stream_forward start/stop when adapter returns a list (before caller enumerates)" do uuid = UUID.uuid4() - assert :ok = EventStore.append_to_stream(DefaultApp, uuid, 0, [%EventData{}]) + assert :ok = EventStore.append_to_stream(DefaultApp, uuid, 0, build_events(1)) assert_receive {[:commanded, :event_store, :append_to_stream, :start], 1, _meas, _meta} assert_receive {[:commanded, :event_store, :append_to_stream, :stop], 2, _meas, _meta} @@ -192,7 +191,7 @@ defmodule Commanded.EventStore.TelemetryTest do describe "append_to_stream telemetry events" do test "emit `[:commanded, :event_store, :append_to_stream, :start | :stop]` event" do uuid = UUID.uuid4() - assert :ok = EventStore.append_to_stream(DefaultApp, uuid, 0, [%EventData{}]) + assert :ok = EventStore.append_to_stream(DefaultApp, uuid, 0, build_events(1)) assert_receive {[:commanded, :event_store, :append_to_stream, :start], 1, _meas, _meta} assert_receive {[:commanded, :event_store, :append_to_stream, :stop], 2, _meas, meta} @@ -320,4 +319,10 @@ defmodule Commanded.EventStore.TelemetryTest do :telemetry.detach(handler) end) end + + defp build_events(count), do: AdapterTestData.build_opened_events(count) + + defp build_snapshot(source_uuid \\ UUID.uuid4()) do + AdapterTestData.build_snapshot_data(5, source_uuid: source_uuid) + end end diff --git a/test/helpers/event_factory.ex b/test/helpers/event_factory.ex index 30b6c19d..cc0bb656 100644 --- a/test/helpers/event_factory.ex +++ b/test/helpers/event_factory.ex @@ -5,9 +5,9 @@ defmodule Commanded.Helpers.EventFactory do alias Commanded.UUID def map_to_recorded_events(events, initial_event_number \\ 1, opts \\ []) do - stream_id = UUID.uuid4() - causation_id = Keyword.get(opts, :causation_id, UUID.uuid4()) - correlation_id = Keyword.get(opts, :correlation_id, UUID.uuid4()) + stream_id = Keyword.get_lazy(opts, :stream_id, &UUID.uuid4/0) + causation_id = Keyword.get_lazy(opts, :causation_id, &UUID.uuid4/0) + correlation_id = Keyword.get_lazy(opts, :correlation_id, &UUID.uuid4/0) metadata = Keyword.get(opts, :metadata, %{}) fields = [causation_id: causation_id, correlation_id: correlation_id, metadata: metadata] @@ -17,7 +17,7 @@ defmodule Commanded.Helpers.EventFactory do |> Enum.with_index(initial_event_number) |> Enum.map(fn {event, index} -> %RecordedEvent{ - event_id: UUID.uuid4(), + event_id: event.event_id || UUID.uuid4(), event_number: index, stream_id: stream_id, stream_version: index, diff --git a/test/opentelemetry/event_store_test.exs b/test/opentelemetry/event_store_test.exs index 2bd7e244..1d98abbe 100644 --- a/test/opentelemetry/event_store_test.exs +++ b/test/opentelemetry/event_store_test.exs @@ -13,7 +13,7 @@ defmodule Commanded.OpenTelemetry.EventStoreTest do alias Commanded.Application.Config, as: AppConfig alias Commanded.DefaultApp alias Commanded.EventStore - alias Commanded.EventStore.{EventData, SnapshotData} + alias Commanded.EventStore.{AdapterTestData, SnapshotData} alias Commanded.OpenTelemetry.EventStore, as: OTelEventStore alias Commanded.UUID @@ -82,7 +82,7 @@ defmodule Commanded.OpenTelemetry.EventStoreTest do } do stream_uuid = UUID.uuid4() - assert :ok = EventStore.append_to_stream(DefaultApp, stream_uuid, 0, [%EventData{}]) + assert :ok = EventStore.append_to_stream(DefaultApp, stream_uuid, 0, build_events(1)) assert span(kind: :internal, attributes: attributes) = assert_receive_span_named("append_to_stream #{destination_name}") @@ -104,7 +104,7 @@ defmodule Commanded.OpenTelemetry.EventStoreTest do } do stream_uuid = UUID.uuid4() - assert :ok = EventStore.append_to_stream(DefaultApp, stream_uuid, 0, [%EventData{}]) + assert :ok = EventStore.append_to_stream(DefaultApp, stream_uuid, 0, build_events(1)) _ = assert_receive_span_named("append_to_stream #{destination_name}") assert [_event] = EventStore.stream_forward(DefaultApp, stream_uuid, 0) @@ -162,7 +162,7 @@ defmodule Commanded.OpenTelemetry.EventStoreTest do assert_receive {:subscribed, ^subscription}, 1000 _ = assert_receive_span_named("subscribe_to #{destination_name}") - assert :ok = EventStore.append_to_stream(DefaultApp, stream_uuid, 0, [%EventData{}]) + assert :ok = EventStore.append_to_stream(DefaultApp, stream_uuid, 0, build_events(1)) assert_receive {:events, [event]}, 1000 _ = assert_receive_span_named("append_to_stream #{destination_name}") @@ -358,7 +358,7 @@ defmodule Commanded.OpenTelemetry.EventStoreTest do application = MissingApplication assert_raise RuntimeError, fn -> - EventStore.append_to_stream(application, stream_uuid, 0, [%EventData{}]) + EventStore.append_to_stream(application, stream_uuid, 0, build_events(1)) end assert_receive {:warning, [:commanded, :opentelemetry, :warning], %{count: 1}, @@ -379,7 +379,7 @@ defmodule Commanded.OpenTelemetry.EventStoreTest do application = "not-an-application" assert_raise FunctionClauseError, fn -> - EventStore.append_to_stream(application, stream_uuid, 0, [%EventData{}]) + EventStore.append_to_stream(application, stream_uuid, 0, build_events(1)) end assert_receive {:warning, [:commanded, :opentelemetry, :warning], %{count: 1}, @@ -407,7 +407,7 @@ defmodule Commanded.OpenTelemetry.EventStoreTest do AppConfig.__put__(DefaultApp, :event_store, nil) assert_raise MatchError, fn -> - EventStore.append_to_stream(DefaultApp, stream_uuid, 0, [%EventData{}]) + EventStore.append_to_stream(DefaultApp, stream_uuid, 0, build_events(1)) end assert span( @@ -454,7 +454,7 @@ defmodule Commanded.OpenTelemetry.EventStoreTest do ) assert_raise FunctionClauseError, fn -> - EventStore.append_to_stream(DefaultApp, stream_uuid, 0, [%EventData{}]) + EventStore.append_to_stream(DefaultApp, stream_uuid, 0, build_events(1)) end assert span( @@ -587,7 +587,7 @@ defmodule Commanded.OpenTelemetry.EventStoreTest do span_name = expected_span_name("append_to_stream", nil) assert_raise RuntimeError, fn -> - EventStore.append_to_stream(DefaultApp, stream_uuid, 0, [%EventData{}]) + EventStore.append_to_stream(DefaultApp, stream_uuid, 0, build_events(1)) end assert span( @@ -632,16 +632,11 @@ defmodule Commanded.OpenTelemetry.EventStoreTest do defp expected_span_name(action_name, destination_name), do: "#{action_name} #{destination_name}" defp build_snapshot(source_uuid) do - %SnapshotData{ - source_uuid: source_uuid, - source_version: 5, - source_type: "Elixir.Commanded.TestSupport.TestDomain.Account", - data: build_account(account_id: source_uuid), - metadata: %{}, - created_at: DateTime.utc_now() - } + AdapterTestData.build_snapshot_data(5, source_uuid: source_uuid, metadata: %{}) end + defp build_events(count), do: AdapterTestData.build_opened_events(count) + defp unique_subscription_name do "subscription-#{System.unique_integer([:positive])}" end diff --git a/test/projections/error_callback_test.exs b/test/projections/error_callback_test.exs index 27338a2d..b62ca702 100644 --- a/test/projections/error_callback_test.exs +++ b/test/projections/error_callback_test.exs @@ -4,8 +4,6 @@ defmodule Commanded.Projections.ErrorCallbackTest do import Commanded.Projections.ProjectionAssertions import ExUnit.CaptureLog - alias Commanded.EventStore.RecordedEvent - alias Commanded.Projections.Events.{ AnEvent, ErrorEvent, @@ -16,7 +14,7 @@ defmodule Commanded.Projections.ErrorCallbackTest do alias Commanded.Projections.Projection alias Commanded.Projections.Repo - alias Commanded.UUID + alias Commanded.TestSupport.Factory alias Ecto.Adapters.SQL.Sandbox describe "error handling" do @@ -28,9 +26,7 @@ defmodule Commanded.Projections.ErrorCallbackTest do event = %ErrorEvent{pid: self()} metadata = %{handler_name: "ErrorProjector", event_number: 1} - events = [ - %RecordedEvent{event_number: 1, event_id: UUID.uuid4(), data: event, metadata: metadata} - ] + events = [build_projection_event(event, 1, metadata)] send(projector, {:events, events}) @@ -41,9 +37,7 @@ defmodule Commanded.Projections.ErrorCallbackTest do event = %RaiseEvent{pid: self(), message: "it crashed, it crashed, it crashed"} metadata = %{event_number: 1} - events = [ - %RecordedEvent{event_number: 1, event_id: UUID.uuid4(), data: event, metadata: metadata} - ] + events = [build_projection_event(event, 1, metadata)] log = capture_log(fn -> @@ -66,9 +60,7 @@ defmodule Commanded.Projections.ErrorCallbackTest do event = %ErrorEvent{pid: self()} metadata = %{event_number: 1} - events = [ - %RecordedEvent{event_number: 1, event_id: UUID.uuid4(), data: event, metadata: metadata} - ] + events = [build_projection_event(event, 1, metadata)] send(projector, {:events, events}) @@ -80,9 +72,7 @@ defmodule Commanded.Projections.ErrorCallbackTest do event = %ExceptionEvent{pid: self()} metadata = %{event_number: 1} - events = [ - %RecordedEvent{event_number: 1, event_id: UUID.uuid4(), data: event, metadata: metadata} - ] + events = [build_projection_event(event, 1, metadata)] send(projector, {:events, events}) @@ -94,9 +84,7 @@ defmodule Commanded.Projections.ErrorCallbackTest do event = %InvalidMultiEvent{pid: self()} metadata = %{event_number: 1} - events = [ - %RecordedEvent{event_number: 1, event_id: UUID.uuid4(), data: event, metadata: metadata} - ] + events = [build_projection_event(event, 1, metadata)] send(projector, {:events, events}) @@ -106,24 +94,9 @@ defmodule Commanded.Projections.ErrorCallbackTest do test "should continue on error after skipping problematic events", %{projector: projector} do events = [ - %RecordedEvent{ - event_number: 1, - event_id: UUID.uuid4(), - data: %ErrorEvent{pid: self()}, - metadata: %{event_number: 1} - }, - %RecordedEvent{ - event_number: 2, - event_id: UUID.uuid4(), - data: %ExceptionEvent{pid: self()}, - metadata: %{event_number: 2} - }, - %RecordedEvent{ - event_number: 3, - event_id: UUID.uuid4(), - data: %AnEvent{pid: self()}, - metadata: %{event_number: 3} - } + build_projection_event(%ErrorEvent{pid: self()}, 1, %{event_number: 1}), + build_projection_event(%ExceptionEvent{pid: self()}, 2, %{event_number: 2}), + build_projection_event(%AnEvent{pid: self()}, 3, %{event_number: 3}) ] send(projector, {:events, events}) @@ -145,4 +118,13 @@ defmodule Commanded.Projections.ErrorCallbackTest do [projector: projector] end + + defp build_projection_event(event, event_number, metadata) do + Factory.build_recorded_event( + data: event, + event_number: event_number, + stream_version: event_number, + metadata: metadata + ) + end end diff --git a/test/projections/runtime_config_projector_test.exs b/test/projections/runtime_config_projector_test.exs index cfb04a8a..39d86031 100644 --- a/test/projections/runtime_config_projector_test.exs +++ b/test/projections/runtime_config_projector_test.exs @@ -1,10 +1,9 @@ defmodule Commanded.Projections.RuntimeConfigProjectorTest do use Commanded.MockProjectionCase - alias Commanded.EventStore.RecordedEvent alias Commanded.Projections.Events.AnEvent alias Commanded.Projections.{Projection, ProjectionAssertions, Repo, RuntimeConfigProjector} - alias Commanded.UUID + alias Commanded.TestSupport.Factory alias Ecto.Adapters.SQL.Sandbox import ProjectionAssertions @@ -29,12 +28,11 @@ defmodule Commanded.Projections.RuntimeConfigProjectorTest do test "should handle a projected event", %{projector1: projector1} do send_events(projector1, [ - %RecordedEvent{ - event_number: 1, - event_id: UUID.uuid4(), + Factory.build_recorded_event( data: %AnEvent{pid: self()}, - metadata: %{} - } + event_number: 1, + stream_version: 1 + ) ]) assert_receive {:project, "AnEvent"} diff --git a/test/support/factory.ex b/test/support/factory.ex index 917370ac..bd99246a 100644 --- a/test/support/factory.ex +++ b/test/support/factory.ex @@ -1,6 +1,7 @@ defmodule Commanded.TestSupport.Factory do alias Commanded.Aggregates.ExecutionContext alias Commanded.EventStore.RecordedEvent + alias Commanded.Helpers.EventFactory alias Commanded.TestSupport.TestDomain alias Commanded.UUID @@ -127,39 +128,66 @@ defmodule Commanded.TestSupport.Factory do def build_recorded_event(opts) when is_list(opts) do account_id = Keyword.get(opts, :account_id, UUID.uuid4()) - default_data = %TestDomain.AccountOpened{ - account_id: account_id, - owner: "Test", - initial_balance: 1000 - } - - defaults = [ - event_id: UUID.uuid4(), - event_number: 1, - stream_id: "account-#{account_id}", - stream_version: 1, - causation_id: UUID.uuid4(), - correlation_id: UUID.uuid4(), - event_type: "Elixir.Commanded.TestSupport.TestDomain.AccountOpened", - data: default_data, - created_at: DateTime.utc_now(), - metadata: %{} - ] + data = + Keyword.get_lazy(opts, :data, fn -> + %TestDomain.AccountOpened{ + account_id: account_id, + owner: "Test", + initial_balance: 1000 + } + end) - opts = Keyword.merge(defaults, opts) + event_number = Keyword.get(opts, :event_number, 1) + + case data do + %{__struct__: _} -> + [%RecordedEvent{} = recorded_event] = + EventFactory.map_to_recorded_events( + [data], + event_number, + stream_id: Keyword.get(opts, :stream_id, "account-#{account_id}"), + causation_id: Keyword.get_lazy(opts, :causation_id, &UUID.uuid4/0), + correlation_id: Keyword.get_lazy(opts, :correlation_id, &UUID.uuid4/0), + metadata: Keyword.get(opts, :metadata, %{}) + ) + + %RecordedEvent{ + recorded_event + | event_id: Keyword.get(opts, :event_id, recorded_event.event_id), + stream_version: Keyword.get(opts, :stream_version, recorded_event.stream_version), + event_type: Keyword.get(opts, :event_type, recorded_event.event_type), + created_at: Keyword.get(opts, :created_at, recorded_event.created_at) + } - %RecordedEvent{ - event_id: Keyword.fetch!(opts, :event_id), - event_number: Keyword.fetch!(opts, :event_number), - stream_id: Keyword.fetch!(opts, :stream_id), - stream_version: Keyword.fetch!(opts, :stream_version), - causation_id: Keyword.fetch!(opts, :causation_id), - correlation_id: Keyword.fetch!(opts, :correlation_id), - event_type: Keyword.fetch!(opts, :event_type), - data: Keyword.fetch!(opts, :data), - created_at: Keyword.fetch!(opts, :created_at), - metadata: Keyword.fetch!(opts, :metadata) - } + _ -> + defaults = [ + event_id: UUID.uuid4(), + event_number: event_number, + stream_id: "account-#{account_id}", + stream_version: event_number, + causation_id: UUID.uuid4(), + correlation_id: UUID.uuid4(), + event_type: "Elixir.Commanded.TestSupport.TestDomain.AccountOpened", + data: data, + created_at: DateTime.utc_now(), + metadata: %{} + ] + + opts = Keyword.merge(defaults, opts) + + %RecordedEvent{ + event_id: Keyword.fetch!(opts, :event_id), + event_number: Keyword.fetch!(opts, :event_number), + stream_id: Keyword.fetch!(opts, :stream_id), + stream_version: Keyword.fetch!(opts, :stream_version), + causation_id: Keyword.fetch!(opts, :causation_id), + correlation_id: Keyword.fetch!(opts, :correlation_id), + event_type: Keyword.fetch!(opts, :event_type), + data: Keyword.fetch!(opts, :data), + created_at: Keyword.fetch!(opts, :created_at), + metadata: Keyword.fetch!(opts, :metadata) + } + end end def build_recorded_event(:account_projector, opts) do