RedixSandbox
RedixSandbox provides isolated, process-scoped Redis connections for
concurrent ExUnit tests. Each test
checks out a logical Redis database, which is flushed before use and returned
to the pool when the owner exits.
Installation
Add redix_sandbox to the test dependencies in mix.exs:
defp deps do
[
{:redix_sandbox, "~> 0.1.0", only: :test}
]
end
Then fetch the dependency with mix deps.get.
Usage
Suppose application code uses a named Redix connection:
# config/config.exs
config :my_app, :redis_connection, :redis
@redis Application.compile_env!(:my_app, :redis_connection)
def set(key, value), do: Redix.command(@redis, ["SET", key, value])
def get(key), do: Redix.command(@redis, ["GET", key])
Use a :via tuple in the test environment. The tuple can be configured
directly, so no library code runs while configuration is evaluated:
# config/test.exs
config :my_app, :redis_connection, {:via, RedixSandbox, :redis}
Start the sandbox once in test/test_helper.exs:
ExUnit.start()
{:ok, _pid} =
RedixSandbox.start_link(
name: :redis,
connection: [host: "127.0.0.1", port: 6379],
databases: 1..5
)
The connection options are passed to Redix; databases accepts any
enumerable of Redis logical database numbers. Check out a database in each
test:
use ExUnit.Case, async: true
setup do
:ok = RedixSandbox.checkout(:redis)
end
Application code can now continue to call Redix.command/2 without knowing
that the connection is sandboxed.
Processes outside the caller chain
Task.async/1 automatically inherits its parent test's checkout. A process
started under a supervisor, or another detached process, must be explicitly
allowed to use the owner's connection:
owner = self()
{:ok, worker} = MyWorker.start_link()
:ok = RedixSandbox.checkout(:redis)
:ok = RedixSandbox.allow(:redis, owner, worker)
The allowed process shares the owner's logical database. It does not receive a separate lease, and the allowance is removed when the owner or child exits.
Shared ownership mode
Use shared mode when several unrelated processes must resolve the same connection and explicit allowances are not practical:
use ExUnit.Case, async: false
setup do
:ok = RedixSandbox.checkout(:redis)
:ok = RedixSandbox.mode(:redis, {:shared, self()})
end
Restore process isolation with RedixSandbox.mode(:redis, :private). Shared
mode is global to the named sandbox, so it must not be used by concurrent tests
sharing that sandbox. It also requires exactly one active checkout.
License
This project is released under the MIT License.