Skip to content

Commit c79a7cd

Browse files
authored
✅ Fix flaky tests (#113)
For a while now, I've been seeing spurious test failures, but hadn't been able to figure out the root cause. It turns out that clearing the entire `InMemoryCache` before tests was causing test interference. This is obvious in retrospect. There's also a spurious failure in CI with the integration tests where a second instance tries to start with the same SDK key as another. I'm not sure if I've fixed that one with these changes. Changes: - Clear only a specific cache key from the InMemoryCache, and only when multiple tests will use the same key. - Mark the integration tests as `async: false` to be sure they run in isolation. - Eliminate log noise from the tests.
1 parent a0dfa81 commit c79a7cd

File tree

5 files changed

+25
-16
lines changed

5 files changed

+25
-16
lines changed

lib/config_cat/in_memory_cache.ex

+5-5
Original file line numberDiff line numberDiff line change
@@ -22,9 +22,9 @@ defmodule ConfigCat.InMemoryCache do
2222
GenServer.call(__MODULE__, {:set, cache_key, value})
2323
end
2424

25-
@spec clear :: :ok
26-
def clear do
27-
GenServer.call(__MODULE__, :clear)
25+
@spec clear(ConfigCache.key()) :: :ok
26+
def clear(cache_key) do
27+
GenServer.call(__MODULE__, {:clear, cache_key})
2828
end
2929

3030
@impl GenServer
@@ -33,8 +33,8 @@ defmodule ConfigCat.InMemoryCache do
3333
end
3434

3535
@impl GenServer
36-
def handle_call(:clear, _from, _state) do
37-
{:reply, :ok, %{}}
36+
def handle_call({:clear, cache_key}, _from, state) do
37+
{:reply, :ok, Map.delete(state, cache_key)}
3838
end
3939

4040
@impl GenServer
+8-8
Original file line numberDiff line numberDiff line change
@@ -1,34 +1,34 @@
11
defmodule ConfigCat.InMemoryCacheTest do
22
use ExUnit.Case, async: true
33

4-
alias ConfigCat.InMemoryCache, as: Cache
4+
alias ConfigCat.InMemoryCache
55

66
@cache_key "CACHE_KEY"
77

88
setup do
9-
Cache.clear()
9+
InMemoryCache.clear(@cache_key)
1010

1111
:ok
1212
end
1313

1414
test "cache is initially empty" do
15-
assert Cache.get(@cache_key) == {:error, :not_found}
15+
assert InMemoryCache.get(@cache_key) == {:error, :not_found}
1616
end
1717

1818
test "returns cached value" do
1919
entry = "serialized-cache-entry"
2020

21-
:ok = Cache.set(@cache_key, entry)
21+
:ok = InMemoryCache.set(@cache_key, entry)
2222

23-
assert {:ok, ^entry} = Cache.get(@cache_key)
23+
assert {:ok, ^entry} = InMemoryCache.get(@cache_key)
2424
end
2525

2626
test "cache is empty after clearing" do
2727
entry = "serialized-cache-entry"
2828

29-
:ok = Cache.set(@cache_key, entry)
29+
:ok = InMemoryCache.set(@cache_key, entry)
3030

31-
assert :ok = Cache.clear()
32-
assert Cache.get(@cache_key) == {:error, :not_found}
31+
assert :ok = InMemoryCache.clear(@cache_key)
32+
assert InMemoryCache.get(@cache_key) == {:error, :not_found}
3333
end
3434
end

test/config_cat_test.exs

+3
Original file line numberDiff line numberDiff line change
@@ -114,6 +114,7 @@ defmodule ConfigCatTest do
114114
} = ConfigCat.get_value_details("testStringKey", "", user, client: client)
115115
end
116116

117+
@tag capture_log: true
117118
test "get_all_value_details/2 returns evaluation details for all keys", %{client: client} do
118119
all_details = ConfigCat.get_all_value_details(client: client)
119120
details_by_key = fn key -> Enum.find(all_details, &(&1.key == key)) end
@@ -133,6 +134,8 @@ defmodule ConfigCatTest do
133134
end
134135

135136
describe "when the configuration has not been fetched" do
137+
@describetag capture_log: true
138+
136139
setup do
137140
{:ok, client} = start_client()
138141

test/integration_test.exs

+9-2
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,10 @@
11
defmodule ConfigCat.IntegrationTest do
2-
use ExUnit.Case, async: true
2+
# Must be async: false to avoid a collision with other tests.
3+
# Now that we only allow a single ConfigCat instance to use the same SDK key,
4+
# one of the async tests would fail due to the existing running instance.
5+
use ExUnit.Case, async: false
36

7+
alias ConfigCat.Cache
48
alias ConfigCat.CachePolicy
59
alias ConfigCat.InMemoryCache
610

@@ -16,6 +20,7 @@ defmodule ConfigCat.IntegrationTest do
1620
|> assert_sdk_key_required()
1721
end
1822

23+
@tag capture_log: true
1924
test "raises error when starting another instance with the same SDK key" do
2025
{:ok, _} = start_config_cat(@sdk_key, name: :original)
2126

@@ -108,7 +113,9 @@ defmodule ConfigCat.IntegrationTest do
108113
end
109114

110115
defp start_config_cat(sdk_key, options \\ []) do
111-
InMemoryCache.clear()
116+
sdk_key
117+
|> Cache.generate_key()
118+
|> InMemoryCache.clear()
112119

113120
name = UUID.uuid4() |> String.to_atom()
114121
default_options = [name: name, sdk_key: sdk_key]

test/support/cache_policy_case.ex

-1
Original file line numberDiff line numberDiff line change
@@ -85,7 +85,6 @@ defmodule ConfigCat.CachePolicyCase do
8585

8686
defp start_cache(instance_id) do
8787
cache_key = UUID.uuid4()
88-
InMemoryCache.clear()
8988

9089
{:ok, _pid} =
9190
start_supervised(

0 commit comments

Comments
 (0)