Packages
wallaby
0.28.0
0.31.0
0.30.12
0.30.11
0.30.10
0.30.9
0.30.8
0.30.7
0.30.6
0.30.5
0.30.4
0.30.3
0.30.2
0.30.1
0.30.0
0.29.1
0.29.0
0.28.1
0.28.0
0.27.0
0.26.2
0.26.1
0.26.0
0.25.1
0.25.0
0.24.1
0.24.0
0.23.0
0.22.0
0.21.0
0.20.0
0.19.2
0.19.1
0.19.0
0.18.1
0.18.0
0.17.0
0.16.1
0.16.0
0.15.0
0.14.0
0.13.0
0.12.0
0.11.1
0.11.0
0.10.0
0.9.0
0.8.0
0.7.0
0.6.0
0.5.0
0.4.0
0.3.1
0.3.0
0.2.0
0.1.0
0.0.1
Concurrent feature tests for elixir
Current section
Files
Jump to
Current section
Files
lib/event_emitter.ex
defmodule EventEmitter do
@moduledoc """
This module offers telemetry style event emission for testing purposes.
If you'd like to emit a message to the event stream, you can call `emit/1` from your implementation code. This is macro, and will not result in any AST injection when not being compiled in the test env.
```elixir
defmodule ImplMod do
use EventEmitter, :emitter
def implementation do
# some logic
emit %{name: :implementation, module: __MODULE__, metadata: %{unique_identifier: some_variable}}
end
end
```
If you'd like to await on a message emitted by implementation code, you can call `await/3` from your test code after registering a handler for your test process
```elixir
defmodule TestMod do
use EventEmitter, :receiver
test "some test" do
EventEmitter.add_handler(self())
# some tricky asynchronous code
await :implementation, __MODULE__, %{unique_identifier: some_variable}
end
end
```
You can use EventEmitter by starting it in your test helper.
```elixir
# test_helper.exs
EventEmitter.start_link([])
ExUnit.start()
```
"""
use GenServer
@type event :: %{
optional(:metadata) => map(),
required(:name) => String.t()
}
def emitter do
quote do
import EventEmitter, only: [emit: 1]
end
end
def receiver do
quote do
import EventEmitter, only: [await: 3]
end
end
defmacro __using__(which) do
apply(__MODULE__, which, [])
end
defmacro emit(event) do
if Mix.env() == :test do
quote do
EventEmitter.emit_event(unquote(event))
end
else
nil
end
end
def await(name, metadata, module) do
e = {:event, %{metadata: metadata, name: name, module: module}}
receive do
^e -> :ok
end
end
def start_link(args) do
GenServer.start_link(__MODULE__, args, name: __MODULE__)
end
def add_handler(pid), do: GenServer.call(__MODULE__, {:add_handler, pid})
def emit_event(event), do: GenServer.cast(__MODULE__, {:event, event})
@impl GenServer
def init(_) do
{:ok, %{handlers: []}}
end
@impl GenServer
def handle_call({:add_handler, pid}, _, state) do
{:reply, pid, %{state | handlers: [pid | state.handlers]}}
end
@impl GenServer
def handle_cast({:event, event}, %{handlers: handlers} = state) do
for h <- handlers do
send(h, {:event, event})
end
{:noreply, state}
end
end