Repository: commanded/commanded
Pull request #175 (2018-06-02 21:52:41)

Proposal: InMemory.reset!() for testing purposes
# Some background

I'm struggling to get the InMemory store to work with my test suite
Following this [wiki page](https://github.com/commanded/commanded/wiki/In-memory-event-store), my conclusion is that the samples shown there are a rather complex way of rebooting the in-memory event store, which requires rebooting the app itself
(I presume this is because the event store is a dependency of the app, or something like that)

The thing is, needing `test --no-start`, and killing my app between tests is a complex thing that leaks that behaviour to the rest of the test suite. I now have to manually start my app in other test files as well, due to the.

# My proposal

Studying the InMemory store for a bit, it seems to be exactly what the name suggests: it keeps stuff in memory. Which is great
If true, that means it should be pretty easy to reset its state. Just change it to whatever it was in the beginning.
That's what I attempted to do here, and it seems to work. I don't know much about the internals of commanded so I might be missing something, though

With this, instead of the whole setup described in the wiki page linked above, the test setup could just become something like:

```
setup do
  Commanded.EventStore.Adapters.InMemory.reset!()

  :ok
end
```

no need to restart/reboot anything, and also no need for `--no-start`


Patch:
diff --git a/lib/commanded/event_store/adapters/in_memory.ex b/lib/commanded/event_store/adapters/in_memory.ex
index 96b4812..0b0456a 100644
--- a/lib/commanded/event_store/adapters/in_memory.ex
+++ b/lib/commanded/event_store/adapters/in_memory.ex
@@ -106,6 +106,10 @@ defmodule Commanded.EventStore.Adapters.InMemory do
     GenServer.call(__MODULE__, {:delete_snapshot, source_uuid})
   end
 
+  def reset! do
+    GenServer.call(__MODULE__, :reset!)
+  end
+
   @impl GenServer
   def handle_call({:append_to_stream, stream_uuid, expected_version, events}, _from, %State{streams: streams} = state) do
     case Map.get(streams, stream_uuid) do
@@ -211,6 +215,10 @@ defmodule Commanded.EventStore.Adapters.InMemory do
     {:reply, :ok, state}
   end
 
+  def handle_call(:reset!, _from, %State{serializer: serializer}) do
+    {:reply, :ok, %State{serializer: serializer}}
+  end
+
   @impl GenServer
   def handle_cast({:ack_event, event, subscriber}, %State{persistent_subscriptions: subscriptions} = state) do
     state = %State{state |


Test patch:
diff --git a/test/event_store_adapter/in_memory_test.exs b/test/event_store_adapter/in_memory_test.exs
new file mode 100644
index 0000000..4eec9a6
--- /dev/null
+++ b/test/event_store_adapter/in_memory_test.exs
@@ -0,0 +1,45 @@
+defmodule Commanded.EventStoreAdapter.InMemoryTest do
+  use ExUnit.Case
+
+  alias Commanded.EventStore.Adapters.InMemory
+  alias Commanded.EventStore.EventData
+
+  defmodule(BankAccountOpened, do: defstruct([:account_number, :initial_balance]))
+
+  setup do
+    default_event_store_adapter = Application.get_env(:commanded, :event_store_adapter)
+
+    Application.put_env(:commanded, :event_store_adapter, InMemory)
+
+    on_exit(fn ->
+      Application.put_env(:commanded, :event_store_adapter, default_event_store_adapter)
+    end)
+  end
+
+  describe "reset!/0" do
+    test "wipes all data from memory" do
+      {:ok, pid} = InMemory.start_link()
+      initial = :sys.get_state(pid)
+
+      {:ok, 1} = InMemory.append_to_stream("stream", 0, [build_event(1)])
+      after_event = :sys.get_state(pid)
+
+      InMemory.reset!()
+      after_reset = :sys.get_state(pid)
+
+      assert initial == after_reset
+      assert length(Map.get(after_event.streams, "stream")) == 1
+      assert after_reset.streams == %{}
+    end
+  end
+
+  defp build_event(account_number) do
+    %EventData{
+      causation_id: UUID.uuid4(),
+      correlation_id: UUID.uuid4(),
+      event_type: "Elixir.Commanded.EventStore.Adapter.SubscriptionTest.BankAccountOpened",
+      data: %BankAccountOpened{account_number: account_number, initial_balance: 1_000},
+      metadata: %{"user_id" => "test"}
+    }
+  end
+end