Skip to content

Commit be3ed75

Browse files
authored
Merge pull request rails#43718 from esparta/fix_race_conditions_test_cache_v
ActiveSupport::Cache, fix race conditions on test/cache - part V
2 parents 223ba6f + c677229 commit be3ed75

File tree

2 files changed

+136
-85
lines changed

2 files changed

+136
-85
lines changed

activesupport/test/cache/behaviors/local_cache_behavior.rb

Lines changed: 128 additions & 83 deletions
Original file line numberDiff line numberDiff line change
@@ -2,15 +2,16 @@
22

33
module LocalCacheBehavior
44
def test_instrumentation_with_local_cache
5+
key = SecureRandom.uuid
56
events = with_instrumentation "write" do
6-
@cache.write("foo", "bar")
7+
@cache.write(key, SecureRandom.uuid)
78
end
89
assert_equal @cache.class.name, events[0].payload[:store]
910

1011
@cache.with_local_cache do
1112
events = with_instrumentation "read" do
12-
@cache.read("foo")
13-
@cache.read("foo")
13+
@cache.read(key)
14+
@cache.read(key)
1415
end
1516

1617
expected = [@cache.class.name, @cache.send(:local_cache).class.name]
@@ -19,21 +20,24 @@ def test_instrumentation_with_local_cache
1920
end
2021

2122
def test_local_writes_are_persistent_on_the_remote_cache
23+
key = SecureRandom.uuid
24+
value = SecureRandom.alphanumeric
2225
retval = @cache.with_local_cache do
23-
@cache.write("foo", "bar")
26+
@cache.write(key, value)
2427
end
2528
assert retval
26-
assert_equal "bar", @cache.read("foo")
29+
assert_equal value, @cache.read(key)
2730
end
2831

2932
def test_clear_also_clears_local_cache
33+
key = SecureRandom.uuid
3034
@cache.with_local_cache do
31-
@cache.write("foo", "bar")
35+
@cache.write(key, SecureRandom.alphanumeric)
3236
@cache.clear
33-
assert_nil @cache.read("foo")
37+
assert_nil @cache.read(key)
3438
end
3539

36-
assert_nil @cache.read("foo")
40+
assert_nil @cache.read(key)
3741
end
3842

3943
def test_cleanup_clears_local_cache_but_not_remote_cache
@@ -43,79 +47,98 @@ def test_cleanup_clears_local_cache_but_not_remote_cache
4347
skip
4448
end
4549

50+
key = SecureRandom.uuid
51+
value = SecureRandom.alphanumeric
52+
other_value = SecureRandom.alphanumeric
53+
4654
@cache.with_local_cache do
47-
@cache.write("foo", "bar")
48-
assert_equal "bar", @cache.read("foo")
55+
@cache.write(key, value)
56+
assert_equal value, @cache.read(key)
4957

50-
@cache.send(:bypass_local_cache) { @cache.write("foo", "baz") }
51-
assert_equal "bar", @cache.read("foo")
58+
@cache.send(:bypass_local_cache) { @cache.write(key, other_value) }
59+
assert_equal value, @cache.read(key)
5260

5361
@cache.cleanup
54-
assert_equal "baz", @cache.read("foo")
62+
assert_equal other_value, @cache.read(key)
5563
end
5664
end
5765

5866
def test_local_cache_of_write
67+
key = SecureRandom.uuid
68+
value = SecureRandom.alphanumeric
5969
@cache.with_local_cache do
60-
@cache.write("foo", "bar")
61-
@peek.delete("foo")
62-
assert_equal "bar", @cache.read("foo")
70+
@cache.write(key, value)
71+
@peek.delete(key)
72+
assert_equal value, @cache.read(key)
6373
end
6474
end
6575

6676
def test_local_cache_of_read_returns_a_copy_of_the_entry
77+
key = SecureRandom.alphanumeric.to_sym
78+
value = SecureRandom.alphanumeric
6779
@cache.with_local_cache do
68-
@cache.write(:foo, type: "bar")
69-
value = @cache.read(:foo)
70-
assert_equal("bar", value.delete(:type))
71-
assert_equal({ type: "bar" }, @cache.read(:foo))
80+
@cache.write(key, type: value)
81+
local_value = @cache.read(key)
82+
assert_equal(value, local_value.delete(:type))
83+
assert_equal({ type: value }, @cache.read(key))
7284
end
7385
end
7486

7587
def test_local_cache_of_read
76-
@cache.write("foo", "bar")
88+
key = SecureRandom.uuid
89+
value = SecureRandom.alphanumeric
90+
@cache.write(key, value)
7791
@cache.with_local_cache do
78-
assert_equal "bar", @cache.read("foo")
92+
assert_equal value, @cache.read(key)
7993
end
8094
end
8195

8296
def test_local_cache_of_read_nil
97+
key = SecureRandom.uuid
98+
value = SecureRandom.alphanumeric
8399
@cache.with_local_cache do
84-
assert_nil @cache.read("foo")
85-
@cache.send(:bypass_local_cache) { @cache.write "foo", "bar" }
86-
assert_nil @cache.read("foo")
100+
assert_nil @cache.read(key)
101+
@cache.send(:bypass_local_cache) { @cache.write(key, value) }
102+
assert_nil @cache.read(key)
87103
end
88104
end
89105

90106
def test_local_cache_fetch
107+
key = SecureRandom.uuid
108+
value = SecureRandom.alphanumeric
91109
@cache.with_local_cache do
92-
@cache.send(:local_cache).write_entry "foo", "bar"
93-
assert_equal "bar", @cache.send(:local_cache).fetch_entry("foo")
110+
@cache.send(:local_cache).write_entry(key, value)
111+
assert_equal value, @cache.send(:local_cache).fetch_entry(key)
94112
end
95113
end
96114

97115
def test_local_cache_of_write_nil
116+
key = SecureRandom.uuid
117+
value = SecureRandom.alphanumeric
98118
@cache.with_local_cache do
99-
assert @cache.write("foo", nil)
100-
assert_nil @cache.read("foo")
101-
@peek.write("foo", "bar")
102-
assert_nil @cache.read("foo")
119+
assert @cache.write(key, nil)
120+
assert_nil @cache.read(key)
121+
@peek.write(key, value)
122+
assert_nil @cache.read(key)
103123
end
104124
end
105125

106126
def test_local_cache_of_write_with_unless_exist
127+
key = SecureRandom.uuid
128+
value = SecureRandom.alphanumeric
107129
@cache.with_local_cache do
108-
@cache.write("foo", "bar")
109-
@cache.write("foo", "baz", unless_exist: true)
110-
assert_equal @peek.read("foo"), @cache.read("foo")
130+
@cache.write(key, value)
131+
@cache.write(key, SecureRandom.alphanumeric, unless_exist: true)
132+
assert_equal @peek.read(key), @cache.read(key)
111133
end
112134
end
113135

114136
def test_local_cache_of_delete
137+
key = SecureRandom.uuid
115138
@cache.with_local_cache do
116-
@cache.write("foo", "bar")
117-
@cache.delete("foo")
118-
assert_nil @cache.read("foo")
139+
@cache.write(key, SecureRandom.alphanumeric)
140+
@cache.delete(key)
141+
assert_nil @cache.read(key)
119142
end
120143
end
121144

@@ -126,94 +149,112 @@ def test_local_cache_of_delete_matched
126149
skip
127150
end
128151

152+
prefix = SecureRandom.alphanumeric
153+
key = "#{prefix}#{SecureRandom.uuid}"
154+
other_key = "#{prefix}#{SecureRandom.uuid}"
155+
third_key = SecureRandom.uuid
156+
value = SecureRandom.alphanumeric
129157
@cache.with_local_cache do
130-
@cache.write("foo", "bar")
131-
@cache.write("fop", "bar")
132-
@cache.write("bar", "foo")
133-
@cache.delete_matched("fo*")
134-
assert_not @cache.exist?("foo")
135-
assert_not @cache.exist?("fop")
136-
assert_equal "foo", @cache.read("bar")
158+
@cache.write(key, SecureRandom.alphanumeric)
159+
@cache.write(other_key, SecureRandom.alphanumeric)
160+
@cache.write(third_key, value)
161+
@cache.delete_matched("#{prefix}*")
162+
assert_not @cache.exist?(key)
163+
assert_not @cache.exist?(other_key)
164+
assert_equal value, @cache.read(third_key)
137165
end
138166
end
139167

140168
def test_local_cache_of_exist
169+
key = SecureRandom.uuid
141170
@cache.with_local_cache do
142-
@cache.write("foo", "bar")
143-
@peek.delete("foo")
144-
assert @cache.exist?("foo")
171+
@cache.write(key, SecureRandom.alphanumeric)
172+
@peek.delete(key)
173+
assert @cache.exist?(key)
145174
end
146175
end
147176

148177
def test_local_cache_of_increment
178+
key = SecureRandom.uuid
149179
@cache.with_local_cache do
150-
@cache.write("foo", 1, raw: true)
151-
@peek.write("foo", 2, raw: true)
152-
@cache.increment("foo")
180+
@cache.write(key, 1, raw: true)
181+
@peek.write(key, 2, raw: true)
182+
@cache.increment(key)
153183

154-
expected = @peek.read("foo", raw: true)
184+
expected = @peek.read(key, raw: true)
155185
assert_equal 3, Integer(expected)
156-
assert_equal expected, @cache.read("foo", raw: true)
186+
assert_equal expected, @cache.read(key, raw: true)
157187
end
158188
end
159189

160190
def test_local_cache_of_decrement
191+
key = SecureRandom.uuid
161192
@cache.with_local_cache do
162-
@cache.write("foo", 1, raw: true)
163-
@peek.write("foo", 3, raw: true)
193+
@cache.write(key, 1, raw: true)
194+
@peek.write(key, 3, raw: true)
164195

165-
@cache.decrement("foo")
166-
expected = @peek.read("foo", raw: true)
196+
@cache.decrement(key)
197+
expected = @peek.read(key, raw: true)
167198
assert_equal 2, Integer(expected)
168-
assert_equal expected, @cache.read("foo", raw: true)
199+
assert_equal expected, @cache.read(key, raw: true)
169200
end
170201
end
171202

172203
def test_local_cache_of_fetch_multi
204+
key = SecureRandom.uuid
205+
other_key = SecureRandom.uuid
173206
@cache.with_local_cache do
174-
@cache.fetch_multi("foo", "bar") { |_key| true }
175-
@peek.delete("foo")
176-
@peek.delete("bar")
177-
assert_equal true, @cache.read("foo")
178-
assert_equal true, @cache.read("bar")
207+
@cache.fetch_multi(key, other_key) { |_key| true }
208+
@peek.delete(key)
209+
@peek.delete(other_key)
210+
assert_equal true, @cache.read(key)
211+
assert_equal true, @cache.read(other_key)
179212
end
180213
end
181214

182215
def test_local_cache_of_read_multi
216+
key = SecureRandom.uuid
217+
value = SecureRandom.alphanumeric
218+
other_key = SecureRandom.uuid
219+
other_value = SecureRandom.alphanumeric
183220
@cache.with_local_cache do
184-
@cache.write("foo", "foo", raw: true)
185-
@cache.write("bar", "bar", raw: true)
186-
values = @cache.read_multi("foo", "bar", raw: true)
187-
assert_equal "foo", @cache.read("foo", raw: true)
188-
assert_equal "bar", @cache.read("bar", raw: true)
189-
assert_equal "foo", values["foo"]
190-
assert_equal "bar", values["bar"]
221+
@cache.write(key, value, raw: true)
222+
@cache.write(other_key, other_value, raw: true)
223+
values = @cache.read_multi(key, other_key, raw: true)
224+
assert_equal value, @cache.read(key, raw: true)
225+
assert_equal other_value, @cache.read(other_key, raw: true)
226+
assert_equal value, values[key]
227+
assert_equal other_value, values[other_key]
191228
end
192229
end
193230

194231
def test_initial_object_mutation_after_write
232+
key = SecureRandom.uuid
195233
@cache.with_local_cache do
196234
initial = +"bar"
197-
@cache.write("foo", initial)
235+
@cache.write(key, initial)
198236
initial << "baz"
199-
assert_equal "bar", @cache.read("foo")
237+
assert_equal "bar", @cache.read(key)
200238
end
201239
end
202240

203241
def test_initial_object_mutation_after_fetch
242+
key = SecureRandom.uuid
204243
@cache.with_local_cache do
205244
initial = +"bar"
206-
@cache.fetch("foo") { initial }
245+
@cache.fetch(key) { initial }
207246
initial << "baz"
208-
assert_equal "bar", @cache.read("foo")
209-
assert_equal "bar", @cache.fetch("foo")
247+
assert_equal "bar", @cache.read(key)
248+
assert_equal "bar", @cache.fetch(key)
210249
end
211250
end
212251

213252
def test_middleware
253+
key = SecureRandom.uuid
254+
value = SecureRandom.alphanumeric
214255
app = lambda { |env|
215-
result = @cache.write("foo", "bar")
216-
assert_equal "bar", @cache.read("foo") # make sure 'foo' was written
256+
result = @cache.write(key, value)
257+
assert_equal value, @cache.read(key) # make sure 'foo' was written
217258
assert result
218259
[200, {}, []]
219260
}
@@ -222,23 +263,27 @@ def test_middleware
222263
end
223264

224265
def test_local_race_condition_protection
266+
key = SecureRandom.uuid
267+
value = SecureRandom.alphanumeric
268+
other_value = SecureRandom.alphanumeric
225269
@cache.with_local_cache do
226270
time = Time.now
227-
@cache.write("foo", "bar", expires_in: 60)
271+
@cache.write(key, value, expires_in: 60)
228272
Time.stub(:now, time + 61) do
229-
result = @cache.fetch("foo", race_condition_ttl: 10) do
230-
assert_equal "bar", @cache.read("foo")
231-
"baz"
273+
result = @cache.fetch(key, race_condition_ttl: 10) do
274+
assert_equal value, @cache.read(key)
275+
other_value
232276
end
233-
assert_equal "baz", result
277+
assert_equal other_value, result
234278
end
235279
end
236280
end
237281

238282
def test_local_cache_should_read_and_write_false
283+
key = SecureRandom.uuid
239284
@cache.with_local_cache do
240-
assert @cache.write("foo", false)
241-
assert_equal false, @cache.read("foo")
285+
assert @cache.write(key, false)
286+
assert_equal false, @cache.read(key)
242287
end
243288
end
244289
end

activesupport/test/cache/stores/mem_cache_store_test.rb

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -79,9 +79,15 @@ def after_teardown
7979
# Overrides test from LocalCacheBehavior in order to stub out the cache clear
8080
# and replace it with a delete.
8181
def test_clear_also_clears_local_cache
82-
key = "#{@namespace}:foo"
82+
key = SecureRandom.uuid
83+
cache = lookup_store(raw: true)
8384
client.stub(:flush_all, -> { client.delete(key) }) do
84-
super
85+
cache.with_local_cache do
86+
cache.write(key, SecureRandom.alphanumeric)
87+
cache.clear
88+
assert_nil cache.read(key)
89+
end
90+
assert_nil cache.read(key)
8591
end
8692
end
8793

0 commit comments

Comments
 (0)