aboutsummaryrefslogtreecommitdiffstats
path: root/activesupport/test/cache/behaviors/cache_store_behavior.rb
diff options
context:
space:
mode:
Diffstat (limited to 'activesupport/test/cache/behaviors/cache_store_behavior.rb')
-rw-r--r--activesupport/test/cache/behaviors/cache_store_behavior.rb250
1 files changed, 227 insertions, 23 deletions
diff --git a/activesupport/test/cache/behaviors/cache_store_behavior.rb b/activesupport/test/cache/behaviors/cache_store_behavior.rb
index 73a9b2a71c..a696760bb2 100644
--- a/activesupport/test/cache/behaviors/cache_store_behavior.rb
+++ b/activesupport/test/cache/behaviors/cache_store_behavior.rb
@@ -33,7 +33,7 @@ module CacheStoreBehavior
cache_miss = false
assert_equal 3, @cache.fetch("foo") { |key| cache_miss = true; key.length }
- assert !cache_miss
+ assert_not cache_miss
end
def test_fetch_with_forced_cache_miss
@@ -52,6 +52,13 @@ module CacheStoreBehavior
end
end
+ def test_fetch_cache_miss_with_skip_nil
+ assert_not_called(@cache, :write) do
+ assert_nil @cache.fetch("foo", skip_nil: true) { nil }
+ assert_equal false, @cache.exist?("foo")
+ end
+ end
+
def test_fetch_with_forced_cache_miss_with_block
@cache.write("foo", "bar")
assert_equal "foo_bar", @cache.fetch("foo", force: true) { "foo_bar" }
@@ -113,7 +120,17 @@ module CacheStoreBehavior
assert_equal("fufu", @cache.read("fu"))
end
- def test_multi_with_objects
+ def test_fetch_multi_without_expires_in
+ @cache.write("foo", "bar")
+ @cache.write("fud", "biz")
+
+ values = @cache.fetch_multi("foo", "fu", "fud", expires_in: nil) { |value| value * 2 }
+
+ assert_equal({ "foo" => "bar", "fu" => "fufu", "fud" => "biz" }, values)
+ assert_equal("fufu", @cache.read("fu"))
+ end
+
+ def test_fetch_multi_with_objects
cache_struct = Struct.new(:cache_key, :title)
foo = cache_struct.new("foo", "FOO!")
bar = cache_struct.new("bar")
@@ -125,35 +142,125 @@ module CacheStoreBehavior
assert_equal({ foo => "FOO!", bar => "BAM!" }, values)
end
+ def test_fetch_multi_returns_ordered_names
+ @cache.write("bam", "BAM")
+
+ values = @cache.fetch_multi("foo", "bar", "bam") { |key| key.upcase }
+
+ assert_equal(%w(foo bar bam), values.keys)
+ end
+
def test_fetch_multi_without_block
assert_raises(ArgumentError) do
@cache.fetch_multi("foo")
end
end
- def test_read_and_write_compressed_small_data
- @cache.write("foo", "bar", compress: true)
- assert_equal "bar", @cache.read("foo")
+ # Use strings that are guaranteed to compress well, so we can easily tell if
+ # the compression kicked in or not.
+ SMALL_STRING = "0" * 100
+ LARGE_STRING = "0" * 2.kilobytes
+
+ SMALL_OBJECT = { data: SMALL_STRING }
+ LARGE_OBJECT = { data: LARGE_STRING }
+
+ def test_nil_with_default_compression_settings
+ assert_uncompressed(nil)
end
- def test_read_and_write_compressed_large_data
- @cache.write("foo", "bar", compress: true, compress_threshold: 2)
- assert_equal "bar", @cache.read("foo")
+ def test_nil_with_compress_true
+ assert_uncompressed(nil, compress: true)
end
- def test_read_and_write_compressed_nil
- @cache.write("foo", nil, compress: true)
- assert_nil @cache.read("foo")
+ def test_nil_with_compress_false
+ assert_uncompressed(nil, compress: false)
end
- def test_read_and_write_uncompressed_small_data
- @cache.write("foo", "bar", compress: false)
- assert_equal "bar", @cache.read("foo")
+ def test_nil_with_compress_low_compress_threshold
+ assert_uncompressed(nil, compress: true, compress_threshold: 1)
end
- def test_read_and_write_uncompressed_nil
- @cache.write("foo", nil, compress: false)
- assert_nil @cache.read("foo")
+ def test_small_string_with_default_compression_settings
+ assert_uncompressed(SMALL_STRING)
+ end
+
+ def test_small_string_with_compress_true
+ assert_uncompressed(SMALL_STRING, compress: true)
+ end
+
+ def test_small_string_with_compress_false
+ assert_uncompressed(SMALL_STRING, compress: false)
+ end
+
+ def test_small_string_with_low_compress_threshold
+ assert_compressed(SMALL_STRING, compress: true, compress_threshold: 1)
+ end
+
+ def test_small_object_with_default_compression_settings
+ assert_uncompressed(SMALL_OBJECT)
+ end
+
+ def test_small_object_with_compress_true
+ assert_uncompressed(SMALL_OBJECT, compress: true)
+ end
+
+ def test_small_object_with_compress_false
+ assert_uncompressed(SMALL_OBJECT, compress: false)
+ end
+
+ def test_small_object_with_low_compress_threshold
+ assert_compressed(SMALL_OBJECT, compress: true, compress_threshold: 1)
+ end
+
+ def test_large_string_with_default_compression_settings
+ assert_compressed(LARGE_STRING)
+ end
+
+ def test_large_string_with_compress_true
+ assert_compressed(LARGE_STRING, compress: true)
+ end
+
+ def test_large_string_with_compress_false
+ assert_uncompressed(LARGE_STRING, compress: false)
+ end
+
+ def test_large_string_with_high_compress_threshold
+ assert_uncompressed(LARGE_STRING, compress: true, compress_threshold: 1.megabyte)
+ end
+
+ def test_large_object_with_default_compression_settings
+ assert_compressed(LARGE_OBJECT)
+ end
+
+ def test_large_object_with_compress_true
+ assert_compressed(LARGE_OBJECT, compress: true)
+ end
+
+ def test_large_object_with_compress_false
+ assert_uncompressed(LARGE_OBJECT, compress: false)
+ end
+
+ def test_large_object_with_high_compress_threshold
+ assert_uncompressed(LARGE_OBJECT, compress: true, compress_threshold: 1.megabyte)
+ end
+
+ def test_incompressable_data
+ assert_uncompressed(nil, compress: true, compress_threshold: 1)
+ assert_uncompressed(true, compress: true, compress_threshold: 1)
+ assert_uncompressed(false, compress: true, compress_threshold: 1)
+ assert_uncompressed(0, compress: true, compress_threshold: 1)
+ assert_uncompressed(1.2345, compress: true, compress_threshold: 1)
+ assert_uncompressed("", compress: true, compress_threshold: 1)
+
+ incompressible = nil
+
+ # generate an incompressible string
+ loop do
+ incompressible = SecureRandom.random_bytes(1.kilobyte)
+ break if incompressible.bytesize < Zlib::Deflate.deflate(incompressible).bytesize
+ end
+
+ assert_uncompressed(incompressible, compress: true, compress_threshold: 1)
end
def test_cache_key
@@ -174,11 +281,72 @@ module CacheStoreBehavior
assert_equal "bar", @cache.read("foo")
end
+ def test_unversioned_cache_key
+ obj = Object.new
+ def obj.cache_key
+ "foo"
+ end
+ def obj.cache_key_with_version
+ "foo-v1"
+ end
+ @cache.write(obj, "bar")
+ assert_equal "bar", @cache.read("foo")
+ end
+
def test_array_as_cache_key
@cache.write([:fu, "foo"], "bar")
assert_equal "bar", @cache.read("fu/foo")
end
+ InstanceTest = Struct.new(:name, :id) do
+ def cache_key
+ "#{name}/#{id}"
+ end
+
+ def to_param
+ "hello"
+ end
+ end
+
+ def test_array_with_single_instance_as_cache_key_uses_cache_key_method
+ test_instance_one = InstanceTest.new("test", 1)
+ test_instance_two = InstanceTest.new("test", 2)
+
+ @cache.write([test_instance_one], "one")
+ @cache.write([test_instance_two], "two")
+
+ assert_equal "one", @cache.read([test_instance_one])
+ assert_equal "two", @cache.read([test_instance_two])
+ end
+
+ def test_array_with_multiple_instances_as_cache_key_uses_cache_key_method
+ test_instance_one = InstanceTest.new("test", 1)
+ test_instance_two = InstanceTest.new("test", 2)
+ test_instance_three = InstanceTest.new("test", 3)
+
+ @cache.write([test_instance_one, test_instance_three], "one")
+ @cache.write([test_instance_two, test_instance_three], "two")
+
+ assert_equal "one", @cache.read([test_instance_one, test_instance_three])
+ assert_equal "two", @cache.read([test_instance_two, test_instance_three])
+ end
+
+ def test_format_of_expanded_key_for_single_instance
+ test_instance_one = InstanceTest.new("test", 1)
+
+ expanded_key = @cache.send(:expanded_key, test_instance_one)
+
+ assert_equal expanded_key, test_instance_one.cache_key
+ end
+
+ def test_format_of_expanded_key_for_single_instance_in_array
+ test_instance_one = InstanceTest.new("test", 1)
+
+ expanded_key = @cache.send(:expanded_key, [test_instance_one])
+
+ assert_equal expanded_key, test_instance_one.cache_key
+ end
+
def test_hash_as_cache_key
@cache.write({ foo: 1, fu: 2 }, "bar")
assert_equal "bar", @cache.read("foo=1/fu=2")
@@ -204,11 +372,11 @@ module CacheStoreBehavior
@cache.write("foo", "bar")
assert @cache.exist?("foo")
assert @cache.delete("foo")
- assert !@cache.exist?("foo")
+ assert_not @cache.exist?("foo")
end
def test_original_store_objects_should_not_be_immutable
- bar = "bar".dup
+ bar = +"bar"
@cache.write("foo", bar)
assert_nothing_raised { bar.gsub!(/.*/, "baz") }
end
@@ -297,8 +465,7 @@ module CacheStoreBehavior
end
def test_really_long_keys
- key = "".dup
- 900.times { key << "x" }
+ key = "x" * 2048
assert @cache.write(key, "bar")
assert_equal "bar", @cache.read(key)
assert_equal "bar", @cache.fetch(key)
@@ -314,7 +481,7 @@ module CacheStoreBehavior
@events << ActiveSupport::Notifications::Event.new(*args)
end
assert @cache.write(key, "1", raw: true)
- assert @cache.fetch(key) {}
+ assert @cache.fetch(key) { }
assert_equal 1, @events.length
assert_equal "cache_read.active_support", @events[0].name
assert_equal :fetch, @events[0].payload[:super_operation]
@@ -328,7 +495,7 @@ module CacheStoreBehavior
ActiveSupport::Notifications.subscribe(/^cache_(.*)\.active_support$/) do |*args|
@events << ActiveSupport::Notifications::Event.new(*args)
end
- assert_not @cache.fetch("bad_key") {}
+ assert_not @cache.fetch("bad_key") { }
assert_equal 3, @events.length
assert_equal "cache_read.active_support", @events[0].name
assert_equal "cache_generate.active_support", @events[1].name
@@ -338,4 +505,41 @@ module CacheStoreBehavior
ensure
ActiveSupport::Notifications.unsubscribe "cache_read.active_support"
end
+
+ private
+
+ def assert_compressed(value, **options)
+ assert_compression(true, value, **options)
+ end
+
+ def assert_uncompressed(value, **options)
+ assert_compression(false, value, **options)
+ end
+
+ def assert_compression(should_compress, value, **options)
+ freeze_time do
+ @cache.write("actual", value, options)
+ @cache.write("uncompressed", value, options.merge(compress: false))
+ end
+
+ if value.nil?
+ assert_nil @cache.read("actual")
+ assert_nil @cache.read("uncompressed")
+ else
+ assert_equal value, @cache.read("actual")
+ assert_equal value, @cache.read("uncompressed")
+ end
+
+ actual_entry = @cache.send(:read_entry, @cache.send(:normalize_key, "actual", {}), {})
+ uncompressed_entry = @cache.send(:read_entry, @cache.send(:normalize_key, "uncompressed", {}), {})
+
+ actual_size = Marshal.dump(actual_entry).bytesize
+ uncompressed_size = Marshal.dump(uncompressed_entry).bytesize
+
+ if should_compress
+ assert_operator actual_size, :<, uncompressed_size, "value should be compressed"
+ else
+ assert_equal uncompressed_size, actual_size, "value should not be compressed"
+ end
+ end
end