Merge pull request #43718 from esparta/fix_race_conditions_test_cache_v
ActiveSupport::Cache, fix race conditions on test/cache - part V
This commit is contained in:
commit
be3ed75ec7
|
@ -2,15 +2,16 @@
|
|||
|
||||
module LocalCacheBehavior
|
||||
def test_instrumentation_with_local_cache
|
||||
key = SecureRandom.uuid
|
||||
events = with_instrumentation "write" do
|
||||
@cache.write("foo", "bar")
|
||||
@cache.write(key, SecureRandom.uuid)
|
||||
end
|
||||
assert_equal @cache.class.name, events[0].payload[:store]
|
||||
|
||||
@cache.with_local_cache do
|
||||
events = with_instrumentation "read" do
|
||||
@cache.read("foo")
|
||||
@cache.read("foo")
|
||||
@cache.read(key)
|
||||
@cache.read(key)
|
||||
end
|
||||
|
||||
expected = [@cache.class.name, @cache.send(:local_cache).class.name]
|
||||
|
@ -19,21 +20,24 @@ module LocalCacheBehavior
|
|||
end
|
||||
|
||||
def test_local_writes_are_persistent_on_the_remote_cache
|
||||
key = SecureRandom.uuid
|
||||
value = SecureRandom.alphanumeric
|
||||
retval = @cache.with_local_cache do
|
||||
@cache.write("foo", "bar")
|
||||
@cache.write(key, value)
|
||||
end
|
||||
assert retval
|
||||
assert_equal "bar", @cache.read("foo")
|
||||
assert_equal value, @cache.read(key)
|
||||
end
|
||||
|
||||
def test_clear_also_clears_local_cache
|
||||
key = SecureRandom.uuid
|
||||
@cache.with_local_cache do
|
||||
@cache.write("foo", "bar")
|
||||
@cache.write(key, SecureRandom.alphanumeric)
|
||||
@cache.clear
|
||||
assert_nil @cache.read("foo")
|
||||
assert_nil @cache.read(key)
|
||||
end
|
||||
|
||||
assert_nil @cache.read("foo")
|
||||
assert_nil @cache.read(key)
|
||||
end
|
||||
|
||||
def test_cleanup_clears_local_cache_but_not_remote_cache
|
||||
|
@ -43,79 +47,98 @@ module LocalCacheBehavior
|
|||
skip
|
||||
end
|
||||
|
||||
@cache.with_local_cache do
|
||||
@cache.write("foo", "bar")
|
||||
assert_equal "bar", @cache.read("foo")
|
||||
key = SecureRandom.uuid
|
||||
value = SecureRandom.alphanumeric
|
||||
other_value = SecureRandom.alphanumeric
|
||||
|
||||
@cache.send(:bypass_local_cache) { @cache.write("foo", "baz") }
|
||||
assert_equal "bar", @cache.read("foo")
|
||||
@cache.with_local_cache do
|
||||
@cache.write(key, value)
|
||||
assert_equal value, @cache.read(key)
|
||||
|
||||
@cache.send(:bypass_local_cache) { @cache.write(key, other_value) }
|
||||
assert_equal value, @cache.read(key)
|
||||
|
||||
@cache.cleanup
|
||||
assert_equal "baz", @cache.read("foo")
|
||||
assert_equal other_value, @cache.read(key)
|
||||
end
|
||||
end
|
||||
|
||||
def test_local_cache_of_write
|
||||
key = SecureRandom.uuid
|
||||
value = SecureRandom.alphanumeric
|
||||
@cache.with_local_cache do
|
||||
@cache.write("foo", "bar")
|
||||
@peek.delete("foo")
|
||||
assert_equal "bar", @cache.read("foo")
|
||||
@cache.write(key, value)
|
||||
@peek.delete(key)
|
||||
assert_equal value, @cache.read(key)
|
||||
end
|
||||
end
|
||||
|
||||
def test_local_cache_of_read_returns_a_copy_of_the_entry
|
||||
key = SecureRandom.alphanumeric.to_sym
|
||||
value = SecureRandom.alphanumeric
|
||||
@cache.with_local_cache do
|
||||
@cache.write(:foo, type: "bar")
|
||||
value = @cache.read(:foo)
|
||||
assert_equal("bar", value.delete(:type))
|
||||
assert_equal({ type: "bar" }, @cache.read(:foo))
|
||||
@cache.write(key, type: value)
|
||||
local_value = @cache.read(key)
|
||||
assert_equal(value, local_value.delete(:type))
|
||||
assert_equal({ type: value }, @cache.read(key))
|
||||
end
|
||||
end
|
||||
|
||||
def test_local_cache_of_read
|
||||
@cache.write("foo", "bar")
|
||||
key = SecureRandom.uuid
|
||||
value = SecureRandom.alphanumeric
|
||||
@cache.write(key, value)
|
||||
@cache.with_local_cache do
|
||||
assert_equal "bar", @cache.read("foo")
|
||||
assert_equal value, @cache.read(key)
|
||||
end
|
||||
end
|
||||
|
||||
def test_local_cache_of_read_nil
|
||||
key = SecureRandom.uuid
|
||||
value = SecureRandom.alphanumeric
|
||||
@cache.with_local_cache do
|
||||
assert_nil @cache.read("foo")
|
||||
@cache.send(:bypass_local_cache) { @cache.write "foo", "bar" }
|
||||
assert_nil @cache.read("foo")
|
||||
assert_nil @cache.read(key)
|
||||
@cache.send(:bypass_local_cache) { @cache.write(key, value) }
|
||||
assert_nil @cache.read(key)
|
||||
end
|
||||
end
|
||||
|
||||
def test_local_cache_fetch
|
||||
key = SecureRandom.uuid
|
||||
value = SecureRandom.alphanumeric
|
||||
@cache.with_local_cache do
|
||||
@cache.send(:local_cache).write_entry "foo", "bar"
|
||||
assert_equal "bar", @cache.send(:local_cache).fetch_entry("foo")
|
||||
@cache.send(:local_cache).write_entry(key, value)
|
||||
assert_equal value, @cache.send(:local_cache).fetch_entry(key)
|
||||
end
|
||||
end
|
||||
|
||||
def test_local_cache_of_write_nil
|
||||
key = SecureRandom.uuid
|
||||
value = SecureRandom.alphanumeric
|
||||
@cache.with_local_cache do
|
||||
assert @cache.write("foo", nil)
|
||||
assert_nil @cache.read("foo")
|
||||
@peek.write("foo", "bar")
|
||||
assert_nil @cache.read("foo")
|
||||
assert @cache.write(key, nil)
|
||||
assert_nil @cache.read(key)
|
||||
@peek.write(key, value)
|
||||
assert_nil @cache.read(key)
|
||||
end
|
||||
end
|
||||
|
||||
def test_local_cache_of_write_with_unless_exist
|
||||
key = SecureRandom.uuid
|
||||
value = SecureRandom.alphanumeric
|
||||
@cache.with_local_cache do
|
||||
@cache.write("foo", "bar")
|
||||
@cache.write("foo", "baz", unless_exist: true)
|
||||
assert_equal @peek.read("foo"), @cache.read("foo")
|
||||
@cache.write(key, value)
|
||||
@cache.write(key, SecureRandom.alphanumeric, unless_exist: true)
|
||||
assert_equal @peek.read(key), @cache.read(key)
|
||||
end
|
||||
end
|
||||
|
||||
def test_local_cache_of_delete
|
||||
key = SecureRandom.uuid
|
||||
@cache.with_local_cache do
|
||||
@cache.write("foo", "bar")
|
||||
@cache.delete("foo")
|
||||
assert_nil @cache.read("foo")
|
||||
@cache.write(key, SecureRandom.alphanumeric)
|
||||
@cache.delete(key)
|
||||
assert_nil @cache.read(key)
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -126,94 +149,112 @@ module LocalCacheBehavior
|
|||
skip
|
||||
end
|
||||
|
||||
prefix = SecureRandom.alphanumeric
|
||||
key = "#{prefix}#{SecureRandom.uuid}"
|
||||
other_key = "#{prefix}#{SecureRandom.uuid}"
|
||||
third_key = SecureRandom.uuid
|
||||
value = SecureRandom.alphanumeric
|
||||
@cache.with_local_cache do
|
||||
@cache.write("foo", "bar")
|
||||
@cache.write("fop", "bar")
|
||||
@cache.write("bar", "foo")
|
||||
@cache.delete_matched("fo*")
|
||||
assert_not @cache.exist?("foo")
|
||||
assert_not @cache.exist?("fop")
|
||||
assert_equal "foo", @cache.read("bar")
|
||||
@cache.write(key, SecureRandom.alphanumeric)
|
||||
@cache.write(other_key, SecureRandom.alphanumeric)
|
||||
@cache.write(third_key, value)
|
||||
@cache.delete_matched("#{prefix}*")
|
||||
assert_not @cache.exist?(key)
|
||||
assert_not @cache.exist?(other_key)
|
||||
assert_equal value, @cache.read(third_key)
|
||||
end
|
||||
end
|
||||
|
||||
def test_local_cache_of_exist
|
||||
key = SecureRandom.uuid
|
||||
@cache.with_local_cache do
|
||||
@cache.write("foo", "bar")
|
||||
@peek.delete("foo")
|
||||
assert @cache.exist?("foo")
|
||||
@cache.write(key, SecureRandom.alphanumeric)
|
||||
@peek.delete(key)
|
||||
assert @cache.exist?(key)
|
||||
end
|
||||
end
|
||||
|
||||
def test_local_cache_of_increment
|
||||
key = SecureRandom.uuid
|
||||
@cache.with_local_cache do
|
||||
@cache.write("foo", 1, raw: true)
|
||||
@peek.write("foo", 2, raw: true)
|
||||
@cache.increment("foo")
|
||||
@cache.write(key, 1, raw: true)
|
||||
@peek.write(key, 2, raw: true)
|
||||
@cache.increment(key)
|
||||
|
||||
expected = @peek.read("foo", raw: true)
|
||||
expected = @peek.read(key, raw: true)
|
||||
assert_equal 3, Integer(expected)
|
||||
assert_equal expected, @cache.read("foo", raw: true)
|
||||
assert_equal expected, @cache.read(key, raw: true)
|
||||
end
|
||||
end
|
||||
|
||||
def test_local_cache_of_decrement
|
||||
key = SecureRandom.uuid
|
||||
@cache.with_local_cache do
|
||||
@cache.write("foo", 1, raw: true)
|
||||
@peek.write("foo", 3, raw: true)
|
||||
@cache.write(key, 1, raw: true)
|
||||
@peek.write(key, 3, raw: true)
|
||||
|
||||
@cache.decrement("foo")
|
||||
expected = @peek.read("foo", raw: true)
|
||||
@cache.decrement(key)
|
||||
expected = @peek.read(key, raw: true)
|
||||
assert_equal 2, Integer(expected)
|
||||
assert_equal expected, @cache.read("foo", raw: true)
|
||||
assert_equal expected, @cache.read(key, raw: true)
|
||||
end
|
||||
end
|
||||
|
||||
def test_local_cache_of_fetch_multi
|
||||
key = SecureRandom.uuid
|
||||
other_key = SecureRandom.uuid
|
||||
@cache.with_local_cache do
|
||||
@cache.fetch_multi("foo", "bar") { |_key| true }
|
||||
@peek.delete("foo")
|
||||
@peek.delete("bar")
|
||||
assert_equal true, @cache.read("foo")
|
||||
assert_equal true, @cache.read("bar")
|
||||
@cache.fetch_multi(key, other_key) { |_key| true }
|
||||
@peek.delete(key)
|
||||
@peek.delete(other_key)
|
||||
assert_equal true, @cache.read(key)
|
||||
assert_equal true, @cache.read(other_key)
|
||||
end
|
||||
end
|
||||
|
||||
def test_local_cache_of_read_multi
|
||||
key = SecureRandom.uuid
|
||||
value = SecureRandom.alphanumeric
|
||||
other_key = SecureRandom.uuid
|
||||
other_value = SecureRandom.alphanumeric
|
||||
@cache.with_local_cache do
|
||||
@cache.write("foo", "foo", raw: true)
|
||||
@cache.write("bar", "bar", raw: true)
|
||||
values = @cache.read_multi("foo", "bar", raw: true)
|
||||
assert_equal "foo", @cache.read("foo", raw: true)
|
||||
assert_equal "bar", @cache.read("bar", raw: true)
|
||||
assert_equal "foo", values["foo"]
|
||||
assert_equal "bar", values["bar"]
|
||||
@cache.write(key, value, raw: true)
|
||||
@cache.write(other_key, other_value, raw: true)
|
||||
values = @cache.read_multi(key, other_key, raw: true)
|
||||
assert_equal value, @cache.read(key, raw: true)
|
||||
assert_equal other_value, @cache.read(other_key, raw: true)
|
||||
assert_equal value, values[key]
|
||||
assert_equal other_value, values[other_key]
|
||||
end
|
||||
end
|
||||
|
||||
def test_initial_object_mutation_after_write
|
||||
key = SecureRandom.uuid
|
||||
@cache.with_local_cache do
|
||||
initial = +"bar"
|
||||
@cache.write("foo", initial)
|
||||
@cache.write(key, initial)
|
||||
initial << "baz"
|
||||
assert_equal "bar", @cache.read("foo")
|
||||
assert_equal "bar", @cache.read(key)
|
||||
end
|
||||
end
|
||||
|
||||
def test_initial_object_mutation_after_fetch
|
||||
key = SecureRandom.uuid
|
||||
@cache.with_local_cache do
|
||||
initial = +"bar"
|
||||
@cache.fetch("foo") { initial }
|
||||
@cache.fetch(key) { initial }
|
||||
initial << "baz"
|
||||
assert_equal "bar", @cache.read("foo")
|
||||
assert_equal "bar", @cache.fetch("foo")
|
||||
assert_equal "bar", @cache.read(key)
|
||||
assert_equal "bar", @cache.fetch(key)
|
||||
end
|
||||
end
|
||||
|
||||
def test_middleware
|
||||
key = SecureRandom.uuid
|
||||
value = SecureRandom.alphanumeric
|
||||
app = lambda { |env|
|
||||
result = @cache.write("foo", "bar")
|
||||
assert_equal "bar", @cache.read("foo") # make sure 'foo' was written
|
||||
result = @cache.write(key, value)
|
||||
assert_equal value, @cache.read(key) # make sure 'foo' was written
|
||||
assert result
|
||||
[200, {}, []]
|
||||
}
|
||||
|
@ -222,23 +263,27 @@ module LocalCacheBehavior
|
|||
end
|
||||
|
||||
def test_local_race_condition_protection
|
||||
key = SecureRandom.uuid
|
||||
value = SecureRandom.alphanumeric
|
||||
other_value = SecureRandom.alphanumeric
|
||||
@cache.with_local_cache do
|
||||
time = Time.now
|
||||
@cache.write("foo", "bar", expires_in: 60)
|
||||
@cache.write(key, value, expires_in: 60)
|
||||
Time.stub(:now, time + 61) do
|
||||
result = @cache.fetch("foo", race_condition_ttl: 10) do
|
||||
assert_equal "bar", @cache.read("foo")
|
||||
"baz"
|
||||
result = @cache.fetch(key, race_condition_ttl: 10) do
|
||||
assert_equal value, @cache.read(key)
|
||||
other_value
|
||||
end
|
||||
assert_equal "baz", result
|
||||
assert_equal other_value, result
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def test_local_cache_should_read_and_write_false
|
||||
key = SecureRandom.uuid
|
||||
@cache.with_local_cache do
|
||||
assert @cache.write("foo", false)
|
||||
assert_equal false, @cache.read("foo")
|
||||
assert @cache.write(key, false)
|
||||
assert_equal false, @cache.read(key)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -79,9 +79,15 @@ class MemCacheStoreTest < ActiveSupport::TestCase
|
|||
# Overrides test from LocalCacheBehavior in order to stub out the cache clear
|
||||
# and replace it with a delete.
|
||||
def test_clear_also_clears_local_cache
|
||||
key = "#{@namespace}:foo"
|
||||
key = SecureRandom.uuid
|
||||
cache = lookup_store(raw: true)
|
||||
client.stub(:flush_all, -> { client.delete(key) }) do
|
||||
super
|
||||
cache.with_local_cache do
|
||||
cache.write(key, SecureRandom.alphanumeric)
|
||||
cache.clear
|
||||
assert_nil cache.read(key)
|
||||
end
|
||||
assert_nil cache.read(key)
|
||||
end
|
||||
end
|
||||
|
||||
|
|
Loading…
Reference in New Issue