diff options
Diffstat (limited to 'activesupport/test/caching_test.rb')
-rw-r--r-- | activesupport/test/caching_test.rb | 1301 |
1 files changed, 0 insertions, 1301 deletions
diff --git a/activesupport/test/caching_test.rb b/activesupport/test/caching_test.rb deleted file mode 100644 index f53b98c73e..0000000000 --- a/activesupport/test/caching_test.rb +++ /dev/null @@ -1,1301 +0,0 @@ -require "logger" -require "abstract_unit" -require "active_support/cache" -require "dependencies_test_helpers" - -require "pathname" - -module ActiveSupport - module Cache - module Strategy - module LocalCache - class MiddlewareTest < ActiveSupport::TestCase - def test_local_cache_cleared_on_close - key = "super awesome key" - assert_nil LocalCacheRegistry.cache_for key - middleware = Middleware.new("<3", key).new(->(env) { - assert LocalCacheRegistry.cache_for(key), "should have a cache" - [200, {}, []] - }) - _, _, body = middleware.call({}) - assert LocalCacheRegistry.cache_for(key), "should still have a cache" - body.each {} - assert LocalCacheRegistry.cache_for(key), "should still have a cache" - body.close - assert_nil LocalCacheRegistry.cache_for(key) - end - - def test_local_cache_cleared_and_response_should_be_present_on_invalid_parameters_error - key = "super awesome key" - assert_nil LocalCacheRegistry.cache_for key - middleware = Middleware.new("<3", key).new(->(env) { - assert LocalCacheRegistry.cache_for(key), "should have a cache" - raise Rack::Utils::InvalidParameterError - }) - response = middleware.call({}) - assert response, "response should exist" - assert_nil LocalCacheRegistry.cache_for(key) - end - - def test_local_cache_cleared_on_exception - key = "super awesome key" - assert_nil LocalCacheRegistry.cache_for key - middleware = Middleware.new("<3", key).new(->(env) { - assert LocalCacheRegistry.cache_for(key), "should have a cache" - raise - }) - assert_raises(RuntimeError) { middleware.call({}) } - assert_nil LocalCacheRegistry.cache_for(key) - end - - def test_local_cache_cleared_on_throw - key = "super awesome key" - assert_nil LocalCacheRegistry.cache_for key - middleware = Middleware.new("<3", key).new(->(env) { - assert LocalCacheRegistry.cache_for(key), "should have a cache" - throw :warden - }) - assert_throws(:warden) { middleware.call({}) } - assert_nil LocalCacheRegistry.cache_for(key) - end - end - end - end - end -end - -class CacheKeyTest < ActiveSupport::TestCase - def test_entry_legacy_optional_ivars - legacy = Class.new(ActiveSupport::Cache::Entry) do - def initialize(value, options = {}) - @value = value - @expires_in = nil - @created_at = nil - super - end - end - - entry = legacy.new "foo" - assert_equal "foo", entry.value - end - - def test_expand_cache_key - assert_equal "1/2/true", ActiveSupport::Cache.expand_cache_key([1, "2", true]) - assert_equal "name/1/2/true", ActiveSupport::Cache.expand_cache_key([1, "2", true], :name) - end - - def test_expand_cache_key_with_rails_cache_id - with_env("RAILS_CACHE_ID" => "c99") do - assert_equal "c99/foo", ActiveSupport::Cache.expand_cache_key(:foo) - assert_equal "c99/foo", ActiveSupport::Cache.expand_cache_key([:foo]) - assert_equal "c99/foo/bar", ActiveSupport::Cache.expand_cache_key([:foo, :bar]) - assert_equal "nm/c99/foo", ActiveSupport::Cache.expand_cache_key(:foo, :nm) - assert_equal "nm/c99/foo", ActiveSupport::Cache.expand_cache_key([:foo], :nm) - assert_equal "nm/c99/foo/bar", ActiveSupport::Cache.expand_cache_key([:foo, :bar], :nm) - end - end - - def test_expand_cache_key_with_rails_app_version - with_env("RAILS_APP_VERSION" => "rails3") do - assert_equal "rails3/foo", ActiveSupport::Cache.expand_cache_key(:foo) - end - end - - def test_expand_cache_key_rails_cache_id_should_win_over_rails_app_version - with_env("RAILS_CACHE_ID" => "c99", "RAILS_APP_VERSION" => "rails3") do - assert_equal "c99/foo", ActiveSupport::Cache.expand_cache_key(:foo) - end - end - - def test_expand_cache_key_respond_to_cache_key - key = "foo" - def key.cache_key - :foo_key - end - assert_equal "foo_key", ActiveSupport::Cache.expand_cache_key(key) - end - - def test_expand_cache_key_array_with_something_that_responds_to_cache_key - key = "foo" - def key.cache_key - :foo_key - end - assert_equal "foo_key", ActiveSupport::Cache.expand_cache_key([key]) - end - - def test_expand_cache_key_of_nil - assert_equal "", ActiveSupport::Cache.expand_cache_key(nil) - end - - def test_expand_cache_key_of_false - assert_equal "false", ActiveSupport::Cache.expand_cache_key(false) - end - - def test_expand_cache_key_of_true - assert_equal "true", ActiveSupport::Cache.expand_cache_key(true) - end - - def test_expand_cache_key_of_array_like_object - assert_equal "foo/bar/baz", ActiveSupport::Cache.expand_cache_key(%w{foo bar baz}.to_enum) - end - - private - - def with_env(kv) - old_values = {} - kv.each { |key, value| old_values[key], ENV[key] = ENV[key], value } - yield - ensure - old_values.each { |key, value| ENV[key] = value } - end -end - -class CacheStoreSettingTest < ActiveSupport::TestCase - def test_memory_store_gets_created_if_no_arguments_passed_to_lookup_store_method - store = ActiveSupport::Cache.lookup_store - assert_kind_of(ActiveSupport::Cache::MemoryStore, store) - end - - def test_memory_store - store = ActiveSupport::Cache.lookup_store :memory_store - assert_kind_of(ActiveSupport::Cache::MemoryStore, store) - end - - def test_file_fragment_cache_store - store = ActiveSupport::Cache.lookup_store :file_store, "/path/to/cache/directory" - assert_kind_of(ActiveSupport::Cache::FileStore, store) - assert_equal "/path/to/cache/directory", store.cache_path - end - - def test_mem_cache_fragment_cache_store - assert_called_with(Dalli::Client, :new, [%w[localhost], {}]) do - store = ActiveSupport::Cache.lookup_store :mem_cache_store, "localhost" - assert_kind_of(ActiveSupport::Cache::MemCacheStore, store) - end - end - - def test_mem_cache_fragment_cache_store_with_given_mem_cache - mem_cache = Dalli::Client.new - assert_not_called(Dalli::Client, :new) do - store = ActiveSupport::Cache.lookup_store :mem_cache_store, mem_cache - assert_kind_of(ActiveSupport::Cache::MemCacheStore, store) - end - end - - def test_mem_cache_fragment_cache_store_with_not_dalli_client - assert_not_called(Dalli::Client, :new) do - memcache = Object.new - assert_raises(ArgumentError) do - ActiveSupport::Cache.lookup_store :mem_cache_store, memcache - end - end - end - - def test_mem_cache_fragment_cache_store_with_multiple_servers - assert_called_with(Dalli::Client, :new, [%w[localhost 192.168.1.1], {}]) do - store = ActiveSupport::Cache.lookup_store :mem_cache_store, "localhost", "192.168.1.1" - assert_kind_of(ActiveSupport::Cache::MemCacheStore, store) - end - end - - def test_mem_cache_fragment_cache_store_with_options - assert_called_with(Dalli::Client, :new, [%w[localhost 192.168.1.1], { timeout: 10 }]) do - store = ActiveSupport::Cache.lookup_store :mem_cache_store, "localhost", "192.168.1.1", namespace: "foo", timeout: 10 - assert_kind_of(ActiveSupport::Cache::MemCacheStore, store) - assert_equal "foo", store.options[:namespace] - end - end - - def test_object_assigned_fragment_cache_store - store = ActiveSupport::Cache.lookup_store ActiveSupport::Cache::FileStore.new("/path/to/cache/directory") - assert_kind_of(ActiveSupport::Cache::FileStore, store) - assert_equal "/path/to/cache/directory", store.cache_path - end -end - -class CacheStoreNamespaceTest < ActiveSupport::TestCase - def test_static_namespace - cache = ActiveSupport::Cache.lookup_store(:memory_store, namespace: "tester") - cache.write("foo", "bar") - assert_equal "bar", cache.read("foo") - assert_equal "bar", cache.instance_variable_get(:@data)["tester:foo"].value - end - - def test_proc_namespace - test_val = "tester" - proc = lambda { test_val } - cache = ActiveSupport::Cache.lookup_store(:memory_store, namespace: proc) - cache.write("foo", "bar") - assert_equal "bar", cache.read("foo") - assert_equal "bar", cache.instance_variable_get(:@data)["tester:foo"].value - end - - def test_delete_matched_key_start - cache = ActiveSupport::Cache.lookup_store(:memory_store, namespace: "tester") - cache.write("foo", "bar") - cache.write("fu", "baz") - cache.delete_matched(/^fo/) - assert !cache.exist?("foo") - assert cache.exist?("fu") - end - - def test_delete_matched_key - cache = ActiveSupport::Cache.lookup_store(:memory_store, namespace: "foo") - cache.write("foo", "bar") - cache.write("fu", "baz") - cache.delete_matched(/OO/i) - assert !cache.exist?("foo") - assert cache.exist?("fu") - end -end - -# Tests the base functionality that should be identical across all cache stores. -module CacheStoreBehavior - def test_should_read_and_write_strings - assert @cache.write("foo", "bar") - assert_equal "bar", @cache.read("foo") - end - - def test_should_overwrite - @cache.write("foo", "bar") - @cache.write("foo", "baz") - assert_equal "baz", @cache.read("foo") - end - - def test_fetch_without_cache_miss - @cache.write("foo", "bar") - assert_not_called(@cache, :write) do - assert_equal "bar", @cache.fetch("foo") { "baz" } - end - end - - def test_fetch_with_cache_miss - assert_called_with(@cache, :write, ["foo", "baz", @cache.options]) do - assert_equal "baz", @cache.fetch("foo") { "baz" } - end - end - - def test_fetch_with_cache_miss_passes_key_to_block - cache_miss = false - assert_equal 3, @cache.fetch("foo") { |key| cache_miss = true; key.length } - assert cache_miss - - cache_miss = false - assert_equal 3, @cache.fetch("foo") { |key| cache_miss = true; key.length } - assert !cache_miss - end - - def test_fetch_with_forced_cache_miss - @cache.write("foo", "bar") - assert_not_called(@cache, :read) do - assert_called_with(@cache, :write, ["foo", "bar", @cache.options.merge(force: true)]) do - @cache.fetch("foo", force: true) { "bar" } - end - end - end - - def test_fetch_with_cached_nil - @cache.write("foo", nil) - assert_not_called(@cache, :write) do - assert_nil @cache.fetch("foo") { "baz" } - 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" } - end - - def test_fetch_with_forced_cache_miss_without_block - @cache.write("foo", "bar") - assert_raises(ArgumentError) do - @cache.fetch("foo", force: true) - end - - assert_equal "bar", @cache.read("foo") - end - - def test_should_read_and_write_hash - assert @cache.write("foo", a: "b") - assert_equal({ a: "b" }, @cache.read("foo")) - end - - def test_should_read_and_write_integer - assert @cache.write("foo", 1) - assert_equal 1, @cache.read("foo") - end - - def test_should_read_and_write_nil - assert @cache.write("foo", nil) - assert_nil @cache.read("foo") - end - - def test_should_read_and_write_false - assert @cache.write("foo", false) - assert_equal false, @cache.read("foo") - end - - def test_read_multi - @cache.write("foo", "bar") - @cache.write("fu", "baz") - @cache.write("fud", "biz") - assert_equal({ "foo" => "bar", "fu" => "baz" }, @cache.read_multi("foo", "fu")) - end - - def test_read_multi_with_expires - time = Time.now - @cache.write("foo", "bar", expires_in: 10) - @cache.write("fu", "baz") - @cache.write("fud", "biz") - Time.stub(:now, time + 11) do - assert_equal({ "fu" => "baz" }, @cache.read_multi("foo", "fu")) - end - end - - def test_fetch_multi - @cache.write("foo", "bar") - @cache.write("fud", "biz") - - values = @cache.fetch_multi("foo", "fu", "fud") { |value| value * 2 } - - assert_equal({ "foo" => "bar", "fu" => "fufu", "fud" => "biz" }, values) - assert_equal("fufu", @cache.read("fu")) - end - - def test_multi_with_objects - cache_struct = Struct.new(:cache_key, :title) - foo = cache_struct.new("foo", "FOO!") - bar = cache_struct.new("bar") - - @cache.write("bar", "BAM!") - - values = @cache.fetch_multi(foo, bar) { |object| object.title } - - assert_equal({ foo => "FOO!", bar => "BAM!" }, values) - 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") - end - - def test_read_and_write_compressed_large_data - @cache.write("foo", "bar", compress: true, compress_threshold: 2) - assert_equal "bar", @cache.read("foo") - end - - def test_read_and_write_compressed_nil - @cache.write("foo", nil, compress: true) - assert_nil @cache.read("foo") - end - - def test_cache_key - obj = Object.new - def obj.cache_key - :foo - end - @cache.write(obj, "bar") - assert_equal "bar", @cache.read("foo") - end - - def test_param_as_cache_key - obj = Object.new - def obj.to_param - "foo" - 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 - - def test_hash_as_cache_key - @cache.write({ foo: 1, fu: 2 }, "bar") - assert_equal "bar", @cache.read("foo=1/fu=2") - end - - def test_keys_are_case_sensitive - @cache.write("foo", "bar") - assert_nil @cache.read("FOO") - end - - def test_exist - @cache.write("foo", "bar") - assert_equal true, @cache.exist?("foo") - assert_equal false, @cache.exist?("bar") - end - - def test_nil_exist - @cache.write("foo", nil) - assert @cache.exist?("foo") - end - - def test_delete - @cache.write("foo", "bar") - assert @cache.exist?("foo") - assert @cache.delete("foo") - assert !@cache.exist?("foo") - end - - def test_original_store_objects_should_not_be_immutable - bar = "bar" - @cache.write("foo", bar) - assert_nothing_raised { bar.gsub!(/.*/, "baz") } - end - - def test_expires_in - time = Time.local(2008, 4, 24) - - Time.stub(:now, time) do - @cache.write("foo", "bar") - assert_equal "bar", @cache.read("foo") - end - - Time.stub(:now, time + 30) do - assert_equal "bar", @cache.read("foo") - end - - Time.stub(:now, time + 61) do - assert_nil @cache.read("foo") - end - end - - def test_race_condition_protection_skipped_if_not_defined - @cache.write("foo", "bar") - time = @cache.send(:read_entry, @cache.send(:normalize_key, "foo", {}), {}).expires_at - - Time.stub(:now, Time.at(time)) do - result = @cache.fetch("foo") do - assert_nil @cache.read("foo") - "baz" - end - assert_equal "baz", result - end - end - - def test_race_condition_protection_is_limited - time = Time.now - @cache.write("foo", "bar", expires_in: 60) - Time.stub(:now, time + 71) do - result = @cache.fetch("foo", race_condition_ttl: 10) do - assert_nil @cache.read("foo") - "baz" - end - assert_equal "baz", result - end - end - - def test_race_condition_protection_is_safe - time = Time.now - @cache.write("foo", "bar", expires_in: 60) - Time.stub(:now, time + 61) do - begin - @cache.fetch("foo", race_condition_ttl: 10) do - assert_equal "bar", @cache.read("foo") - raise ArgumentError.new - end - rescue ArgumentError - end - assert_equal "bar", @cache.read("foo") - end - Time.stub(:now, time + 91) do - assert_nil @cache.read("foo") - end - end - - def test_race_condition_protection - time = Time.now - @cache.write("foo", "bar", 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" - end - assert_equal "baz", result - end - end - - def test_crazy_key_characters - crazy_key = "#/:*(<+=> )&$%@?;'\"\'`~-" - assert @cache.write(crazy_key, "1", raw: true) - assert_equal "1", @cache.read(crazy_key) - assert_equal "1", @cache.fetch(crazy_key) - assert @cache.delete(crazy_key) - assert_equal "2", @cache.fetch(crazy_key, raw: true) { "2" } - assert_equal 3, @cache.increment(crazy_key) - assert_equal 2, @cache.decrement(crazy_key) - end - - def test_really_long_keys - key = "" - 900.times { key << "x" } - assert @cache.write(key, "bar") - assert_equal "bar", @cache.read(key) - assert_equal "bar", @cache.fetch(key) - assert_nil @cache.read("#{key}x") - assert_equal({ key => "bar" }, @cache.read_multi(key)) - assert @cache.delete(key) - end - - def test_cache_hit_instrumentation - key = "test_key" - @events = [] - ActiveSupport::Notifications.subscribe "cache_read.active_support" do |*args| - @events << ActiveSupport::Notifications::Event.new(*args) - end - assert @cache.write(key, "1", raw: true) - 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] - assert @events[0].payload[:hit] - ensure - ActiveSupport::Notifications.unsubscribe "cache_read.active_support" - end - - def test_cache_miss_instrumentation - @events = [] - ActiveSupport::Notifications.subscribe(/^cache_(.*)\.active_support$/) do |*args| - @events << ActiveSupport::Notifications::Event.new(*args) - end - 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 - assert_equal "cache_write.active_support", @events[2].name - assert_equal :fetch, @events[0].payload[:super_operation] - assert_not @events[0].payload[:hit] - ensure - ActiveSupport::Notifications.unsubscribe "cache_read.active_support" - end -end - -module CacheStoreVersionBehavior - ModelWithKeyAndVersion = Struct.new(:cache_key, :cache_version) - - def test_fetch_with_right_version_should_hit - @cache.fetch("foo", version: 1) { "bar" } - assert_equal "bar", @cache.read("foo", version: 1) - end - - def test_fetch_with_wrong_version_should_miss - @cache.fetch("foo", version: 1) { "bar" } - assert_nil @cache.read("foo", version: 2) - end - - def test_read_with_right_version_should_hit - @cache.write("foo", "bar", version: 1) - assert_equal "bar", @cache.read("foo", version: 1) - end - - def test_read_with_wrong_version_should_miss - @cache.write("foo", "bar", version: 1) - assert_nil @cache.read("foo", version: 2) - end - - def test_exist_with_right_version_should_be_true - @cache.write("foo", "bar", version: 1) - assert @cache.exist?("foo", version: 1) - end - - def test_exist_with_wrong_version_should_be_false - @cache.write("foo", "bar", version: 1) - assert !@cache.exist?("foo", version: 2) - end - - def test_reading_and_writing_with_model_supporting_cache_version - m1v1 = ModelWithKeyAndVersion.new("model/1", 1) - m1v2 = ModelWithKeyAndVersion.new("model/1", 2) - - @cache.write(m1v1, "bar") - assert_equal "bar", @cache.read(m1v1) - assert_nil @cache.read(m1v2) - end - - def test_reading_and_writing_with_model_supporting_cache_version_using_nested_key - m1v1 = ModelWithKeyAndVersion.new("model/1", 1) - m1v2 = ModelWithKeyAndVersion.new("model/1", 2) - - @cache.write([ "something", m1v1 ], "bar") - assert_equal "bar", @cache.read([ "something", m1v1 ]) - assert_nil @cache.read([ "something", m1v2 ]) - end - - def test_fetching_with_model_supporting_cache_version - m1v1 = ModelWithKeyAndVersion.new("model/1", 1) - m1v2 = ModelWithKeyAndVersion.new("model/1", 2) - - @cache.fetch(m1v1) { "bar" } - assert_equal "bar", @cache.fetch(m1v1) { "bu" } - assert_equal "bu", @cache.fetch(m1v2) { "bu" } - end - - def test_exist_with_model_supporting_cache_version - m1v1 = ModelWithKeyAndVersion.new("model/1", 1) - m1v2 = ModelWithKeyAndVersion.new("model/1", 2) - - @cache.write(m1v1, "bar") - assert @cache.exist?(m1v1) - assert_not @cache.fetch(m1v2) - end - - def test_fetch_multi_with_model_supporting_cache_version - m1v1 = ModelWithKeyAndVersion.new("model/1", 1) - m2v1 = ModelWithKeyAndVersion.new("model/2", 1) - m2v2 = ModelWithKeyAndVersion.new("model/2", 2) - - first_fetch_values = @cache.fetch_multi(m1v1, m2v1) { |m| m.cache_key } - second_fetch_values = @cache.fetch_multi(m1v1, m2v2) { |m| m.cache_key + " 2nd" } - - assert_equal({ m1v1 => "model/1", m2v1 => "model/2" }, first_fetch_values) - assert_equal({ m1v1 => "model/1", m2v2 => "model/2 2nd" }, second_fetch_values) - end - - def test_version_is_normalized - @cache.write("foo", "bar", version: 1) - assert_equal "bar", @cache.read("foo", version: "1") - end -end - -# https://rails.lighthouseapp.com/projects/8994/tickets/6225-memcachestore-cant-deal-with-umlauts-and-special-characters -# The error is caused by character encodings that can't be compared with ASCII-8BIT regular expressions and by special -# characters like the umlaut in UTF-8. -module EncodedKeyCacheBehavior - Encoding.list.each do |encoding| - define_method "test_#{encoding.name.underscore}_encoded_values" do - key = "foo".force_encoding(encoding) - assert @cache.write(key, "1", raw: true) - assert_equal "1", @cache.read(key) - assert_equal "1", @cache.fetch(key) - assert @cache.delete(key) - assert_equal "2", @cache.fetch(key, raw: true) { "2" } - assert_equal 3, @cache.increment(key) - assert_equal 2, @cache.decrement(key) - end - end - - def test_common_utf8_values - key = "\xC3\xBCmlaut".force_encoding(Encoding::UTF_8) - assert @cache.write(key, "1", raw: true) - assert_equal "1", @cache.read(key) - assert_equal "1", @cache.fetch(key) - assert @cache.delete(key) - assert_equal "2", @cache.fetch(key, raw: true) { "2" } - assert_equal 3, @cache.increment(key) - assert_equal 2, @cache.decrement(key) - end - - def test_retains_encoding - key = "\xC3\xBCmlaut".force_encoding(Encoding::UTF_8) - assert @cache.write(key, "1", raw: true) - assert_equal Encoding::UTF_8, key.encoding - end -end - -module CacheDeleteMatchedBehavior - def test_delete_matched - @cache.write("foo", "bar") - @cache.write("fu", "baz") - @cache.write("foo/bar", "baz") - @cache.write("fu/baz", "bar") - @cache.delete_matched(/oo/) - assert !@cache.exist?("foo") - assert @cache.exist?("fu") - assert !@cache.exist?("foo/bar") - assert @cache.exist?("fu/baz") - end -end - -module CacheIncrementDecrementBehavior - def test_increment - @cache.write("foo", 1, raw: true) - assert_equal 1, @cache.read("foo").to_i - assert_equal 2, @cache.increment("foo") - assert_equal 2, @cache.read("foo").to_i - assert_equal 3, @cache.increment("foo") - assert_equal 3, @cache.read("foo").to_i - assert_nil @cache.increment("bar") - end - - def test_decrement - @cache.write("foo", 3, raw: true) - assert_equal 3, @cache.read("foo").to_i - assert_equal 2, @cache.decrement("foo") - assert_equal 2, @cache.read("foo").to_i - assert_equal 1, @cache.decrement("foo") - assert_equal 1, @cache.read("foo").to_i - assert_nil @cache.decrement("bar") - end -end - -module LocalCacheBehavior - def test_local_writes_are_persistent_on_the_remote_cache - retval = @cache.with_local_cache do - @cache.write("foo", "bar") - end - assert retval - assert_equal "bar", @cache.read("foo") - end - - def test_clear_also_clears_local_cache - @cache.with_local_cache do - @cache.write("foo", "bar") - @cache.clear - assert_nil @cache.read("foo") - end - - assert_nil @cache.read("foo") - end - - def test_local_cache_of_write - @cache.with_local_cache do - @cache.write("foo", "bar") - @peek.delete("foo") - assert_equal "bar", @cache.read("foo") - end - end - - def test_local_cache_of_read - @cache.write("foo", "bar") - @cache.with_local_cache do - assert_equal "bar", @cache.read("foo") - end - end - - def test_local_cache_of_read_nil - @cache.with_local_cache do - assert_nil @cache.read("foo") - @cache.send(:bypass_local_cache) { @cache.write "foo", "bar" } - assert_nil @cache.read("foo") - end - end - - def test_local_cache_fetch - @cache.with_local_cache do - @cache.send(:local_cache).write "foo", "bar" - assert_equal "bar", @cache.send(:local_cache).fetch("foo") - end - end - - def test_local_cache_of_write_nil - @cache.with_local_cache do - assert @cache.write("foo", nil) - assert_nil @cache.read("foo") - @peek.write("foo", "bar") - assert_nil @cache.read("foo") - end - end - - def test_local_cache_of_write_with_unless_exist - @cache.with_local_cache do - @cache.write("foo", "bar") - @cache.write("foo", "baz", unless_exist: true) - assert_equal @peek.read("foo"), @cache.read("foo") - end - end - - def test_local_cache_of_delete - @cache.with_local_cache do - @cache.write("foo", "bar") - @cache.delete("foo") - assert_nil @cache.read("foo") - end - end - - def test_local_cache_of_exist - @cache.with_local_cache do - @cache.write("foo", "bar") - @peek.delete("foo") - assert @cache.exist?("foo") - end - end - - def test_local_cache_of_increment - @cache.with_local_cache do - @cache.write("foo", 1, raw: true) - @peek.write("foo", 2, raw: true) - @cache.increment("foo") - assert_equal 3, @cache.read("foo") - end - end - - def test_local_cache_of_decrement - @cache.with_local_cache do - @cache.write("foo", 1, raw: true) - @peek.write("foo", 3, raw: true) - @cache.decrement("foo") - assert_equal 2, @cache.read("foo") - end - end - - def test_middleware - app = lambda { |env| - result = @cache.write("foo", "bar") - assert_equal "bar", @cache.read("foo") # make sure 'foo' was written - assert result - [200, {}, []] - } - app = @cache.middleware.new(app) - app.call({}) - end -end - -module AutoloadingCacheBehavior - include DependenciesTestHelpers - def test_simple_autoloading - with_autoloading_fixtures do - @cache.write("foo", EM.new) - end - - remove_constants(:EM) - ActiveSupport::Dependencies.clear - - with_autoloading_fixtures do - assert_kind_of EM, @cache.read("foo") - end - - remove_constants(:EM) - ActiveSupport::Dependencies.clear - end - - def test_two_classes_autoloading - with_autoloading_fixtures do - @cache.write("foo", [EM.new, ClassFolder.new]) - end - - remove_constants(:EM, :ClassFolder) - ActiveSupport::Dependencies.clear - - with_autoloading_fixtures do - loaded = @cache.read("foo") - assert_kind_of Array, loaded - assert_equal 2, loaded.size - assert_kind_of EM, loaded[0] - assert_kind_of ClassFolder, loaded[1] - end - - remove_constants(:EM, :ClassFolder) - ActiveSupport::Dependencies.clear - end -end - -class FileStoreTest < ActiveSupport::TestCase - def setup - Dir.mkdir(cache_dir) unless File.exist?(cache_dir) - @cache = ActiveSupport::Cache.lookup_store(:file_store, cache_dir, expires_in: 60) - @peek = ActiveSupport::Cache.lookup_store(:file_store, cache_dir, expires_in: 60) - @cache_with_pathname = ActiveSupport::Cache.lookup_store(:file_store, Pathname.new(cache_dir), expires_in: 60) - - @buffer = StringIO.new - @cache.logger = ActiveSupport::Logger.new(@buffer) - end - - def teardown - FileUtils.rm_r(cache_dir) - rescue Errno::ENOENT - end - - def cache_dir - File.join(Dir.pwd, "tmp_cache") - end - - include CacheStoreBehavior - include CacheStoreVersionBehavior - include LocalCacheBehavior - include CacheDeleteMatchedBehavior - include CacheIncrementDecrementBehavior - include AutoloadingCacheBehavior - - def test_clear - gitkeep = File.join(cache_dir, ".gitkeep") - keep = File.join(cache_dir, ".keep") - FileUtils.touch([gitkeep, keep]) - @cache.clear - assert File.exist?(gitkeep) - assert File.exist?(keep) - end - - def test_clear_without_cache_dir - FileUtils.rm_r(cache_dir) - @cache.clear - end - - def test_long_uri_encoded_keys - @cache.write("%" * 870, 1) - assert_equal 1, @cache.read("%" * 870) - end - - def test_key_transformation - key = @cache.send(:normalize_key, "views/index?id=1", {}) - assert_equal "views/index?id=1", @cache.send(:file_path_key, key) - end - - def test_key_transformation_with_pathname - FileUtils.touch(File.join(cache_dir, "foo")) - key = @cache_with_pathname.send(:normalize_key, "views/index?id=1", {}) - assert_equal "views/index?id=1", @cache_with_pathname.send(:file_path_key, key) - end - - # Test that generated cache keys are short enough to have Tempfile stuff added to them and - # remain valid - def test_filename_max_size - key = "#{'A' * ActiveSupport::Cache::FileStore::FILENAME_MAX_SIZE}" - path = @cache.send(:normalize_key, key, {}) - Dir::Tmpname.create(path) do |tmpname, n, opts| - assert File.basename(tmpname + ".lock").length <= 255, "Temp filename too long: #{File.basename(tmpname + '.lock').length}" - end - end - - # Because file systems have a maximum filename size, filenames > max size should be split in to directories - # If filename is 'AAAAB', where max size is 4, the returned path should be AAAA/B - def test_key_transformation_max_filename_size - key = "#{'A' * ActiveSupport::Cache::FileStore::FILENAME_MAX_SIZE}B" - path = @cache.send(:normalize_key, key, {}) - assert path.split("/").all? { |dir_name| dir_name.size <= ActiveSupport::Cache::FileStore::FILENAME_MAX_SIZE } - assert_equal "B", File.basename(path) - end - - # If nothing has been stored in the cache, there is a chance the cache directory does not yet exist - # Ensure delete_matched gracefully handles this case - def test_delete_matched_when_cache_directory_does_not_exist - assert_nothing_raised do - ActiveSupport::Cache::FileStore.new("/test/cache/directory").delete_matched(/does_not_exist/) - end - end - - def test_delete_does_not_delete_empty_parent_dir - sub_cache_dir = File.join(cache_dir, "subdir/") - sub_cache_store = ActiveSupport::Cache::FileStore.new(sub_cache_dir) - assert_nothing_raised do - assert sub_cache_store.write("foo", "bar") - assert sub_cache_store.delete("foo") - end - assert File.exist?(cache_dir), "Parent of top level cache dir was deleted!" - assert File.exist?(sub_cache_dir), "Top level cache dir was deleted!" - assert Dir.entries(sub_cache_dir).reject { |f| ActiveSupport::Cache::FileStore::EXCLUDED_DIRS.include?(f) }.empty? - end - - def test_log_exception_when_cache_read_fails - File.stub(:exist?, -> { raise StandardError.new("failed") }) do - @cache.send(:read_entry, "winston", {}) - assert @buffer.string.present? - end - end - - def test_cleanup_removes_all_expired_entries - time = Time.now - @cache.write("foo", "bar", expires_in: 10) - @cache.write("baz", "qux") - @cache.write("quux", "corge", expires_in: 20) - Time.stub(:now, time + 15) do - @cache.cleanup - assert_not @cache.exist?("foo") - assert @cache.exist?("baz") - assert @cache.exist?("quux") - end - end - - def test_write_with_unless_exist - assert_equal true, @cache.write(1, "aaaaaaaaaa") - assert_equal false, @cache.write(1, "aaaaaaaaaa", unless_exist: true) - @cache.write(1, nil) - assert_equal false, @cache.write(1, "aaaaaaaaaa", unless_exist: true) - end -end - -class MemoryStoreTest < ActiveSupport::TestCase - def setup - @record_size = ActiveSupport::Cache.lookup_store(:memory_store).send(:cached_size, 1, ActiveSupport::Cache::Entry.new("aaaaaaaaaa")) - @cache = ActiveSupport::Cache.lookup_store(:memory_store, expires_in: 60, size: @record_size * 10 + 1) - end - - include CacheStoreBehavior - include CacheStoreVersionBehavior - include CacheDeleteMatchedBehavior - include CacheIncrementDecrementBehavior - - def test_prune_size - @cache.write(1, "aaaaaaaaaa") && sleep(0.001) - @cache.write(2, "bbbbbbbbbb") && sleep(0.001) - @cache.write(3, "cccccccccc") && sleep(0.001) - @cache.write(4, "dddddddddd") && sleep(0.001) - @cache.write(5, "eeeeeeeeee") && sleep(0.001) - @cache.read(2) && sleep(0.001) - @cache.read(4) - @cache.prune(@record_size * 3) - assert @cache.exist?(5) - assert @cache.exist?(4) - assert !@cache.exist?(3), "no entry" - assert @cache.exist?(2) - assert !@cache.exist?(1), "no entry" - end - - def test_prune_size_on_write - @cache.write(1, "aaaaaaaaaa") && sleep(0.001) - @cache.write(2, "bbbbbbbbbb") && sleep(0.001) - @cache.write(3, "cccccccccc") && sleep(0.001) - @cache.write(4, "dddddddddd") && sleep(0.001) - @cache.write(5, "eeeeeeeeee") && sleep(0.001) - @cache.write(6, "ffffffffff") && sleep(0.001) - @cache.write(7, "gggggggggg") && sleep(0.001) - @cache.write(8, "hhhhhhhhhh") && sleep(0.001) - @cache.write(9, "iiiiiiiiii") && sleep(0.001) - @cache.write(10, "kkkkkkkkkk") && sleep(0.001) - @cache.read(2) && sleep(0.001) - @cache.read(4) && sleep(0.001) - @cache.write(11, "llllllllll") - assert @cache.exist?(11) - assert @cache.exist?(10) - assert @cache.exist?(9) - assert @cache.exist?(8) - assert @cache.exist?(7) - assert !@cache.exist?(6), "no entry" - assert !@cache.exist?(5), "no entry" - assert @cache.exist?(4) - assert !@cache.exist?(3), "no entry" - assert @cache.exist?(2) - assert !@cache.exist?(1), "no entry" - end - - def test_prune_size_on_write_based_on_key_length - @cache.write(1, "aaaaaaaaaa") && sleep(0.001) - @cache.write(2, "bbbbbbbbbb") && sleep(0.001) - @cache.write(3, "cccccccccc") && sleep(0.001) - @cache.write(4, "dddddddddd") && sleep(0.001) - @cache.write(5, "eeeeeeeeee") && sleep(0.001) - @cache.write(6, "ffffffffff") && sleep(0.001) - @cache.write(7, "gggggggggg") && sleep(0.001) - @cache.write(8, "hhhhhhhhhh") && sleep(0.001) - @cache.write(9, "iiiiiiiiii") && sleep(0.001) - long_key = "*" * 2 * @record_size - @cache.write(long_key, "llllllllll") - assert @cache.exist?(long_key) - assert @cache.exist?(9) - assert @cache.exist?(8) - assert @cache.exist?(7) - assert @cache.exist?(6) - assert !@cache.exist?(5), "no entry" - assert !@cache.exist?(4), "no entry" - assert !@cache.exist?(3), "no entry" - assert !@cache.exist?(2), "no entry" - assert !@cache.exist?(1), "no entry" - end - - def test_pruning_is_capped_at_a_max_time - def @cache.delete_entry(*args) - sleep(0.01) - super - end - @cache.write(1, "aaaaaaaaaa") && sleep(0.001) - @cache.write(2, "bbbbbbbbbb") && sleep(0.001) - @cache.write(3, "cccccccccc") && sleep(0.001) - @cache.write(4, "dddddddddd") && sleep(0.001) - @cache.write(5, "eeeeeeeeee") && sleep(0.001) - @cache.prune(30, 0.001) - assert @cache.exist?(5) - assert @cache.exist?(4) - assert @cache.exist?(3) - assert @cache.exist?(2) - assert !@cache.exist?(1) - end - - def test_write_with_unless_exist - assert_equal true, @cache.write(1, "aaaaaaaaaa") - assert_equal false, @cache.write(1, "aaaaaaaaaa", unless_exist: true) - @cache.write(1, nil) - assert_equal false, @cache.write(1, "aaaaaaaaaa", unless_exist: true) - end -end - -class MemCacheStoreTest < ActiveSupport::TestCase - require "dalli" - - begin - ss = Dalli::Client.new("localhost:11211").stats - raise Dalli::DalliError unless ss["localhost:11211"] - - MEMCACHE_UP = true - rescue Dalli::DalliError - $stderr.puts "Skipping memcached tests. Start memcached and try again." - MEMCACHE_UP = false - end - - def setup - skip "memcache server is not up" unless MEMCACHE_UP - - @cache = ActiveSupport::Cache.lookup_store(:mem_cache_store, expires_in: 60) - @peek = ActiveSupport::Cache.lookup_store(:mem_cache_store) - @data = @cache.instance_variable_get(:@data) - @cache.clear - @cache.silence! - @cache.logger = ActiveSupport::Logger.new("/dev/null") - end - - include CacheStoreBehavior - include CacheStoreVersionBehavior - include LocalCacheBehavior - include CacheIncrementDecrementBehavior - include EncodedKeyCacheBehavior - include AutoloadingCacheBehavior - - def test_raw_values - cache = ActiveSupport::Cache.lookup_store(:mem_cache_store, raw: true) - cache.clear - cache.write("foo", 2) - assert_equal "2", cache.read("foo") - end - - def test_raw_values_with_marshal - cache = ActiveSupport::Cache.lookup_store(:mem_cache_store, raw: true) - cache.clear - cache.write("foo", Marshal.dump([])) - assert_equal [], cache.read("foo") - end - - def test_local_cache_raw_values - cache = ActiveSupport::Cache.lookup_store(:mem_cache_store, raw: true) - cache.clear - cache.with_local_cache do - cache.write("foo", 2) - assert_equal "2", cache.read("foo") - end - end - - def test_local_cache_raw_values_with_marshal - cache = ActiveSupport::Cache.lookup_store(:mem_cache_store, raw: true) - cache.clear - cache.with_local_cache do - cache.write("foo", Marshal.dump([])) - assert_equal [], cache.read("foo") - end - end - - def test_read_should_return_a_different_object_id_each_time_it_is_called - @cache.write("foo", "bar") - value = @cache.read("foo") - assert_not_equal value.object_id, @cache.read("foo").object_id - value << "bingo" - assert_not_equal value, @cache.read("foo") - end -end - -class NullStoreTest < ActiveSupport::TestCase - def setup - @cache = ActiveSupport::Cache.lookup_store(:null_store) - end - - def test_clear - @cache.clear - end - - def test_cleanup - @cache.cleanup - end - - def test_write - assert_equal true, @cache.write("name", "value") - end - - def test_read - @cache.write("name", "value") - assert_nil @cache.read("name") - end - - def test_delete - @cache.write("name", "value") - assert_equal false, @cache.delete("name") - end - - def test_increment - @cache.write("name", 1, raw: true) - assert_nil @cache.increment("name") - end - - def test_decrement - @cache.write("name", 1, raw: true) - assert_nil @cache.increment("name") - end - - def test_delete_matched - @cache.write("name", "value") - @cache.delete_matched(/name/) - end - - def test_local_store_strategy - @cache.with_local_cache do - @cache.write("name", "value") - assert_equal "value", @cache.read("name") - @cache.delete("name") - assert_nil @cache.read("name") - @cache.write("name", "value") - end - assert_nil @cache.read("name") - end -end - -class CacheStoreLoggerTest < ActiveSupport::TestCase - def setup - @cache = ActiveSupport::Cache.lookup_store(:memory_store) - - @buffer = StringIO.new - @cache.logger = ActiveSupport::Logger.new(@buffer) - end - - def test_logging - @cache.fetch("foo") { "bar" } - assert @buffer.string.present? - end - - def test_log_with_string_namespace - @cache.fetch("foo", namespace: "string_namespace") { "bar" } - assert_match %r{string_namespace:foo}, @buffer.string - end - - def test_log_with_proc_namespace - proc = Proc.new do - "proc_namespace" - end - @cache.fetch("foo", namespace: proc) { "bar" } - assert_match %r{proc_namespace:foo}, @buffer.string - end - - def test_mute_logging - @cache.mute { @cache.fetch("foo") { "bar" } } - assert @buffer.string.blank? - end -end - -class CacheEntryTest < ActiveSupport::TestCase - def test_expired - entry = ActiveSupport::Cache::Entry.new("value") - assert !entry.expired?, "entry not expired" - entry = ActiveSupport::Cache::Entry.new("value", expires_in: 60) - assert !entry.expired?, "entry not expired" - Time.stub(:now, Time.now + 61) do - assert entry.expired?, "entry is expired" - end - end - - def test_compress_values - value = "value" * 100 - entry = ActiveSupport::Cache::Entry.new(value, compress: true, compress_threshold: 1) - assert_equal value, entry.value - assert(value.bytesize > entry.size, "value is compressed") - end - - def test_non_compress_values - value = "value" * 100 - entry = ActiveSupport::Cache::Entry.new(value) - assert_equal value, entry.value - assert_equal value.bytesize, entry.size - end -end |