From 3ba87b85a77748572b591c19c9818c61344f077d Mon Sep 17 00:00:00 2001 From: Yordis Prieto Date: Tue, 15 Sep 2026 18:04:53 -0400 Subject: [PATCH 1/2] chore(test): stop the test environment from hiding compiler warnings `--warnings-as-errors` never reaches test files, so warnings there accumulate unchecked and drown out new ones. One of them was pointing at genuinely unreachable code, and the two manual scripts were `.exs`, so nothing ever compiled them. Signed-off-by: Yordis Prieto --- .dialyzer_ignore.exs | 4 - lib/event_store.ex | 2 - mix.exs | 1 - test/manual/long_running_subscription.exs | 80 -------------- test/migrated_event_store_test.exs | 10 -- test/storage/append_events_test.exs | 16 +-- test/storage/read_events_test.exs | 4 +- test/support/event_factory.ex | 2 +- test/support/long_running_subscription.ex | 102 ++++++++++++++++++ test/support/migration_fixtures.ex | 9 ++ .../migration_seed.ex} | 36 ++----- 11 files changed, 133 insertions(+), 133 deletions(-) delete mode 100644 .dialyzer_ignore.exs delete mode 100644 test/manual/long_running_subscription.exs create mode 100644 test/support/long_running_subscription.ex create mode 100644 test/support/migration_fixtures.ex rename test/{manual/seed_eventstore.exs => support/migration_seed.ex} (78%) diff --git a/.dialyzer_ignore.exs b/.dialyzer_ignore.exs deleted file mode 100644 index d9e7bc51..00000000 --- a/.dialyzer_ignore.exs +++ /dev/null @@ -1,4 +0,0 @@ -[ - {"deps/postgrex/lib/postgrex/type_module.ex", :improper_list_constr}, - {"lib/postgrex/type_module.ex", :improper_list_constr} -] diff --git a/lib/event_store.ex b/lib/event_store.ex index c748d21a..e4321da0 100644 --- a/lib/event_store.ex +++ b/lib/event_store.ex @@ -637,8 +637,6 @@ defmodule EventStore do |> Map.new() end - defp pagination_metadata(_opts), do: %{} - defp telemetry_span(operation, opts, metadata, fun) do Telemetry.span(operation, Telemetry.metadata(__MODULE__, opts, metadata), fun) end diff --git a/mix.exs b/mix.exs index ab14c91a..530e7e65 100644 --- a/mix.exs +++ b/mix.exs @@ -158,7 +158,6 @@ defmodule EventStore.Mixfile do defp dialyzer do [ - ignore_warnings: ".dialyzer_ignore.exs", plt_add_apps: [:ex_unit, :jason, :mix], plt_add_deps: :app_tree, plt_file: {:no_warn, "priv/plts/eventstore.plt"} diff --git a/test/manual/long_running_subscription.exs b/test/manual/long_running_subscription.exs deleted file mode 100644 index a0cb6bf7..00000000 --- a/test/manual/long_running_subscription.exs +++ /dev/null @@ -1,80 +0,0 @@ -# -# Long running subscription manual test. -# -# mix run --no-halt test/manual/long_running_subscription.exs -# - -alias EventStore.{EventData, UUID} - -defmodule LoggingSubscriber do - use GenServer - require Logger - - def start_link(stream_uuid) do - GenServer.start_link(__MODULE__, stream_uuid) - end - - def init(stream_uuid) do - {:ok, subscribe_to_stream(stream_uuid)} - end - - def handle_info({:subscribed, subscription}, subscription) do - Logger.debug("Subscribed to stream") - - {:noreply, subscription} - end - - def handle_info({:events, events}, subscription) do - Logger.debug("Received event(s): #{inspect(events)}") - - :ok = EventStore.ack(subscription, events) - - {:noreply, subscription} - end - - defp subscribe_to_stream(stream_uuid) do - with {:ok, subscription} <- EventStore.subscribe_to_stream(stream_uuid, UUID.uuid4(), self()) do - subscription - end - end -end - -defmodule ExampleEvent do - defstruct [:event] -end - -defmodule IntervalAppender do - def start_link(stream_uuid, expected_version \\ 0, interval \\ 30_000) do - GenServer.start_link(__MODULE__, {stream_uuid, expected_version, interval}) - end - - def init({stream_uuid, expected_version, interval}) do - Process.send_after(self(), :append_to_stream, interval) - - {:ok, {stream_uuid, expected_version, interval}} - end - - def handle_info(:append_to_stream, {stream_uuid, expected_version, interval}) do - events = [ - %EventData{ - correlation_id: UUID.uuid4(), - causation_id: UUID.uuid4(), - event_type: "Elixir.ExampleEvent", - data: %ExampleEvent{event: expected_version + 1}, - metadata: %{"user" => "user@example.com"} - } - ] - - :ok = EventStore.append_to_stream(stream_uuid, expected_version, events) - - Process.send_after(self(), :append_to_stream, interval) - - {:noreply, {stream_uuid, expected_version + 1, interval}} - end -end - -stream_uuid = UUID.uuid4() - -{:ok, _subscriber1} = LoggingSubscriber.start_link("$all") -{:ok, _subscriber2} = LoggingSubscriber.start_link(stream_uuid) -{:ok, _appender} = IntervalAppender.start_link(stream_uuid) diff --git a/test/migrated_event_store_test.exs b/test/migrated_event_store_test.exs index b5700027..fa7c7a4e 100644 --- a/test/migrated_event_store_test.exs +++ b/test/migrated_event_store_test.exs @@ -1,13 +1,3 @@ -defmodule Event do - @derive Jason.Encoder - defstruct [:data, version: "1"] -end - -defmodule Snapshot do - @derive Jason.Encoder - defstruct [:data, version: "1"] -end - defmodule EventStore.MigratedEventStoreTest do use ExUnit.Case diff --git a/test/storage/append_events_test.exs b/test/storage/append_events_test.exs index 504d1807..94e43a9b 100644 --- a/test/storage/append_events_test.exs +++ b/test/storage/append_events_test.exs @@ -189,12 +189,12 @@ defmodule EventStore.Storage.AppendEventsTest do events = EventFactory.create_recorded_events(3, stream_uuid) :ok = Appender.append(conn, stream_id, events, append_opts(context)) - for event <- events do - events = [%RecordedEvent{event | stream_version: 4}] + Enum.each(events, fn %RecordedEvent{} = event -> + duplicate_events = [%RecordedEvent{event | stream_version: 4}] assert {:error, :duplicate_event} = - Appender.append(conn, stream_id, events, append_opts(context)) - end + Appender.append(conn, stream_id, duplicate_events, append_opts(context)) + end) end test "append existing events to a different stream should fail", context do @@ -205,14 +205,14 @@ defmodule EventStore.Storage.AppendEventsTest do events = EventFactory.create_recorded_events(3, stream1_uuid) :ok = Appender.append(conn, stream1_id, events, append_opts(context)) - for event <- events do - events = [ + Enum.each(events, fn %RecordedEvent{} = event -> + duplicate_events = [ %RecordedEvent{event | stream_uuid: stream2_uuid, stream_version: 1} ] assert {:error, :duplicate_event} = - Appender.append(conn, stream2_id, events, append_opts(context)) - end + Appender.append(conn, stream2_id, duplicate_events, append_opts(context)) + end) end test "append event to schema which does not exist", %{conn: conn} do diff --git a/test/storage/read_events_test.exs b/test/storage/read_events_test.exs index 04cde8df..34ebf915 100644 --- a/test/storage/read_events_test.exs +++ b/test/storage/read_events_test.exs @@ -36,7 +36,7 @@ defmodule EventStore.Storage.ReadEventsTest do test "without correlation_id", context do {:ok, stream_uuid, stream_id} = create_stream(context) - [recorded_event] = EventFactory.create_recorded_events(1, stream_uuid) + [%RecordedEvent{} = recorded_event] = EventFactory.create_recorded_events(1, stream_uuid) recorded_event = %RecordedEvent{recorded_event | correlation_id: nil} @@ -49,7 +49,7 @@ defmodule EventStore.Storage.ReadEventsTest do test "without causation_id", context do {:ok, stream_uuid, stream_id} = create_stream(context) - [recorded_event] = EventFactory.create_recorded_events(1, stream_uuid) + [%RecordedEvent{} = recorded_event] = EventFactory.create_recorded_events(1, stream_uuid) recorded_event = %RecordedEvent{recorded_event | causation_id: nil} diff --git a/test/support/event_factory.ex b/test/support/event_factory.ex index b9ef9f17..a14a6664 100644 --- a/test/support/event_factory.ex +++ b/test/support/event_factory.ex @@ -60,7 +60,7 @@ defmodule EventStore.EventFactory do def deserialize_events(events) do events - |> Enum.map(fn event -> + |> Enum.map(fn %RecordedEvent{} = event -> %RecordedEvent{ event | data: deserialize(event.data, type: "Elixir.EventStore.EventFactory.Event"), diff --git a/test/support/long_running_subscription.ex b/test/support/long_running_subscription.ex new file mode 100644 index 00000000..e43b83b5 --- /dev/null +++ b/test/support/long_running_subscription.ex @@ -0,0 +1,102 @@ +defmodule EventStore.LongRunningSubscription do + @moduledoc """ + Appends to a stream on an interval and logs everything a subscription receives. + + MIX_ENV=test mix run --no-halt -e "EventStore.LongRunningSubscription.start()" + """ + + alias EventStore.UUID + + defmodule ExampleEvent do + defstruct [:event] + end + + defmodule LoggingSubscriber do + use GenServer + + alias EventStore.UUID + + require Logger + + def start_link(stream_uuid) do + GenServer.start_link(__MODULE__, stream_uuid) + end + + @impl GenServer + def init(stream_uuid) do + {:ok, subscribe_to_stream(stream_uuid)} + end + + @impl GenServer + def handle_info({:subscribed, subscription}, subscription) do + Logger.debug("Subscribed to stream") + + {:noreply, subscription} + end + + @impl GenServer + def handle_info({:events, events}, subscription) do + Logger.debug("Received event(s): #{inspect(events)}") + + :ok = TestEventStore.ack(subscription, events) + + {:noreply, subscription} + end + + defp subscribe_to_stream(stream_uuid) do + {:ok, subscription} = + TestEventStore.subscribe_to_stream(stream_uuid, UUID.uuid4(), self()) + + subscription + end + end + + defmodule IntervalAppender do + use GenServer + + alias EventStore.{EventData, UUID} + alias EventStore.LongRunningSubscription.ExampleEvent + + def start_link(stream_uuid, expected_version \\ 0, interval \\ 30_000) do + GenServer.start_link(__MODULE__, {stream_uuid, expected_version, interval}) + end + + @impl GenServer + def init({stream_uuid, expected_version, interval}) do + Process.send_after(self(), :append_to_stream, interval) + + {:ok, {stream_uuid, expected_version, interval}} + end + + @impl GenServer + def handle_info(:append_to_stream, {stream_uuid, expected_version, interval}) do + events = [ + %EventData{ + correlation_id: UUID.uuid4(), + causation_id: UUID.uuid4(), + event_type: "Elixir.EventStore.LongRunningSubscription.ExampleEvent", + data: %ExampleEvent{event: expected_version + 1}, + metadata: %{"user" => "user@example.com"} + } + ] + + :ok = TestEventStore.append_to_stream(stream_uuid, expected_version, events) + + Process.send_after(self(), :append_to_stream, interval) + + {:noreply, {stream_uuid, expected_version + 1, interval}} + end + end + + def start do + {:ok, _pid} = TestEventStore.start_link() + + stream_uuid = UUID.uuid4() + + {:ok, _subscriber} = LoggingSubscriber.start_link("$all") + {:ok, _subscriber} = LoggingSubscriber.start_link(stream_uuid) + {:ok, _appender} = IntervalAppender.start_link(stream_uuid) + + :ok + end +end diff --git a/test/support/migration_fixtures.ex b/test/support/migration_fixtures.ex new file mode 100644 index 00000000..e44874b0 --- /dev/null +++ b/test/support/migration_fixtures.ex @@ -0,0 +1,9 @@ +defmodule Event do + @derive Jason.Encoder + defstruct [:data, version: "1"] +end + +defmodule Snapshot do + @derive Jason.Encoder + defstruct [:data, version: "1"] +end diff --git a/test/manual/seed_eventstore.exs b/test/support/migration_seed.ex similarity index 78% rename from test/manual/seed_eventstore.exs rename to test/support/migration_seed.ex index e3274136..40be500c 100644 --- a/test/manual/seed_eventstore.exs +++ b/test/support/migration_seed.ex @@ -1,28 +1,19 @@ -# -# Seed EventStore with data to test migrations. -# -# MIX_ENV=test mix es.reset -# MIX_ENV=test mix run test/manual/seed_eventstore.exs -# -# pg_dump eventstore_test > test/fixture/eventstore_seed.sql -# pg_dump -Fc eventstore_test > test/fixture/eventstore_seed.dump -# - -defmodule Event do - @derive Jason.Encoder - defstruct [:data, version: "1"] -end +defmodule EventStore.MigrationSeed do + @moduledoc """ + Seeds an event store with the data captured in `test/fixture/eventstore_seed.dump`. -defmodule Snapshot do - @derive Jason.Encoder - defstruct [:data, version: "1"] -end + MIX_ENV=test mix es.reset + MIX_ENV=test mix run -e "EventStore.MigrationSeed.seed()" + + pg_dump -Fc eventstore_test > test/fixture/eventstore_seed.dump + """ -defmodule Seed do alias EventStore.{EventData, UUID} alias EventStore.Snapshots.SnapshotData - def run(opts \\ []) do + def seed(opts \\ []) do + {:ok, _pid} = TestEventStore.start_link() + append_events(opts) link_events(opts) record_snapshots(opts) @@ -96,8 +87,3 @@ defmodule Seed do ) end end - -{:ok, _pid} = TestEventStore.start_link() - -# Seed.run(stream_count: 1_000, event_count: 100, snapshot_count: 1_000) -Seed.run() From 6212b8c3f4d840ea27e41b5517aa5e95650d39a0 Mon Sep 17 00:00:00 2001 From: Yordis Prieto Date: Tue, 15 Sep 2026 18:13:46 -0400 Subject: [PATCH 2/2] fix(test): keep the manual subscription script serializable The test event store serializes with `Jason`, so the event struct has to derive the encoder or the first append raises. Signed-off-by: Yordis Prieto --- test/support/long_running_subscription.ex | 1 + 1 file changed, 1 insertion(+) diff --git a/test/support/long_running_subscription.ex b/test/support/long_running_subscription.ex index e43b83b5..998d94a7 100644 --- a/test/support/long_running_subscription.ex +++ b/test/support/long_running_subscription.ex @@ -8,6 +8,7 @@ defmodule EventStore.LongRunningSubscription do alias EventStore.UUID defmodule ExampleEvent do + @derive Jason.Encoder defstruct [:event] end