RedixSandbox

CIHex.pmDocumentation

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.