Skip to content

Commit b1c81ce

Browse files
Pedro Piñera Buendíaclaude
authored andcommitted
Eliminate global state from tests via injectable :config option
Add a :config option to create/1 and create/2 that overrides Application.get_env lookups. All tests now run with async: true and never call Application.put_env. Co-Authored-By: Claude Opus 4.6 (1M context) <[email protected]>
1 parent 1385ede commit b1c81ce

File tree

2 files changed

+30
-33
lines changed

2 files changed

+30
-33
lines changed

lib/terrarium.ex

Lines changed: 15 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -79,12 +79,14 @@ defmodule Terrarium do
7979
def create(provider_or_opts \\ [], opts \\ [])
8080

8181
def create(name, opts) when is_atom(name) and name != nil do
82-
{provider, provider_opts} = resolve_named_or_module(name)
82+
{config, opts} = Keyword.pop(opts, :config)
83+
{provider, provider_opts} = resolve_named_or_module(name, config)
8384
provider.create(Keyword.merge(provider_opts, opts))
8485
end
8586

8687
def create(opts, []) when is_list(opts) do
87-
{provider, provider_opts, opts} = resolve_from_opts(opts)
88+
{config, opts} = Keyword.pop(opts, :config)
89+
{provider, provider_opts, opts} = resolve_from_opts(opts, config)
8890
provider.create(Keyword.merge(provider_opts, opts))
8991
end
9092

@@ -205,10 +207,13 @@ defmodule Terrarium do
205207
provider.ls(sandbox, path)
206208
end
207209

210+
defp get_config(nil, key, default), do: Application.get_env(:terrarium, key, default)
211+
defp get_config(config, key, default), do: Keyword.get(config, key, default)
212+
208213
# Resolves an atom that could be either a named provider from config
209214
# or a direct provider module.
210-
defp resolve_named_or_module(name) do
211-
providers = Application.get_env(:terrarium, :providers, [])
215+
defp resolve_named_or_module(name, config) do
216+
providers = get_config(config, :providers, [])
212217

213218
case Keyword.fetch(providers, name) do
214219
{:ok, {module, opts}} -> {module, opts}
@@ -219,30 +224,30 @@ defmodule Terrarium do
219224

220225
# Resolves the provider from opts (inline :provider key) or falls back
221226
# to the configured default.
222-
defp resolve_from_opts(opts) do
227+
defp resolve_from_opts(opts, config) do
223228
case Keyword.pop(opts, :provider) do
224229
{nil, opts} ->
225-
{provider, provider_opts} = resolve_default!()
230+
{provider, provider_opts} = resolve_default!(config)
226231
{provider, provider_opts, opts}
227232

228233
{{module, provider_opts}, opts} when is_atom(module) ->
229234
{module, provider_opts, opts}
230235

231236
{module, opts} when is_atom(module) ->
232-
{provider, provider_opts} = resolve_named_or_module(module)
237+
{provider, provider_opts} = resolve_named_or_module(module, config)
233238
{provider, provider_opts, opts}
234239
end
235240
end
236241

237-
defp resolve_default! do
238-
case Application.get_env(:terrarium, :default) do
242+
defp resolve_default!(config) do
243+
case get_config(config, :default, nil) do
239244
nil ->
240245
raise ArgumentError,
241246
"no default provider configured. Either pass a provider explicitly " <>
242247
"or configure one: config :terrarium, default: :local, providers: [local: Terrarium.Providers.Local]"
243248

244249
name ->
245-
resolve_named_or_module(name)
250+
resolve_named_or_module(name, config)
246251
end
247252
end
248253
end

test/terrarium/config_test.exs

Lines changed: 15 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -1,45 +1,37 @@
11
defmodule Terrarium.ConfigTest do
2-
use ExUnit.Case, async: false
2+
use ExUnit.Case, async: true
33

44
alias Terrarium.Sandbox
55

6-
# These tests modify Application config and must run sequentially.
7-
8-
setup do
9-
on_exit(fn ->
10-
Application.delete_env(:terrarium, :default)
11-
Application.delete_env(:terrarium, :providers)
12-
end)
13-
end
6+
@config [
7+
default: :test,
8+
providers: [
9+
test: {Terrarium.TestProvider, from_config: true},
10+
bare: Terrarium.TestProvider
11+
]
12+
]
1413

1514
describe "named providers from config" do
1615
test "resolves a named provider" do
17-
Application.put_env(:terrarium, :providers, test: Terrarium.TestProvider)
18-
19-
assert {:ok, %Sandbox{provider: Terrarium.TestProvider}} = Terrarium.create(:test)
16+
assert {:ok, %Sandbox{provider: Terrarium.TestProvider}} =
17+
Terrarium.create(:bare, config: @config)
2018
end
2119

2220
test "resolves a named provider with {module, opts} tuple" do
23-
Application.put_env(:terrarium, :providers, test: {Terrarium.TestProvider, some: "config"})
24-
25-
assert {:ok, %Sandbox{provider: Terrarium.TestProvider}} = Terrarium.create(:test)
21+
assert {:ok, %Sandbox{provider: Terrarium.TestProvider}} =
22+
Terrarium.create(:test, config: @config)
2623
end
2724
end
2825

2926
describe "default provider from config" do
3027
test "uses the configured default provider" do
31-
Application.put_env(:terrarium, :default, :test)
32-
Application.put_env(:terrarium, :providers, test: Terrarium.TestProvider)
33-
34-
assert {:ok, %Sandbox{provider: Terrarium.TestProvider}} = Terrarium.create()
28+
assert {:ok, %Sandbox{provider: Terrarium.TestProvider}} =
29+
Terrarium.create(config: @config)
3530
end
3631

3732
test "merges config opts with call-site opts" do
38-
Application.put_env(:terrarium, :default, :test)
39-
Application.put_env(:terrarium, :providers, test: {Terrarium.TestProvider, from_config: true})
40-
4133
assert {:ok, %Sandbox{provider: Terrarium.TestProvider}} =
42-
Terrarium.create(from_call: true)
34+
Terrarium.create(config: @config, from_call: true)
4335
end
4436
end
4537
end

0 commit comments

Comments
 (0)