caching_test.rb 25.0 KB
Newer Older
1
require 'logger'
2
require 'abstract_unit'
J
Jeremy Kemper 已提交
3
require 'active_support/cache'
4

5
class CacheKeyTest < ActiveSupport::TestCase
6
  def test_expand_cache_key
7 8
    assert_equal 'Array/1/2/true', ActiveSupport::Cache.expand_cache_key([1, '2', true])
    assert_equal 'name/Array/1/2/true', ActiveSupport::Cache.expand_cache_key([1, '2', true], :name)
9
  end
10 11

  def test_expand_cache_key_with_rails_cache_id
12 13 14
    begin
      ENV['RAILS_CACHE_ID'] = 'c99'
      assert_equal 'c99/foo', ActiveSupport::Cache.expand_cache_key(:foo)
15 16
      assert_equal 'c99/Array/foo', ActiveSupport::Cache.expand_cache_key([:foo])
      assert_equal 'c99/Array/foo/bar', ActiveSupport::Cache.expand_cache_key([:foo, :bar])
17
      assert_equal 'nm/c99/foo', ActiveSupport::Cache.expand_cache_key(:foo, :nm)
18 19
      assert_equal 'nm/c99/Array/foo', ActiveSupport::Cache.expand_cache_key([:foo], :nm)
      assert_equal 'nm/c99/Array/foo/bar', ActiveSupport::Cache.expand_cache_key([:foo, :bar], :nm)
20 21 22
    ensure
      ENV['RAILS_CACHE_ID'] = nil
    end
23
  end
24 25

  def test_expand_cache_key_with_rails_app_version
26 27 28 29 30 31
    begin
      ENV['RAILS_APP_VERSION'] = 'rails3'
      assert_equal 'rails3/foo', ActiveSupport::Cache.expand_cache_key(:foo)
    ensure
      ENV['RAILS_APP_VERSION'] = nil
    end
32 33 34
  end

  def test_expand_cache_key_rails_cache_id_should_win_over_rails_app_version
35 36 37 38 39 40 41 42 43 44
    begin
      ENV['RAILS_CACHE_ID'] = 'c99'
      ENV['RAILS_APP_VERSION'] = 'rails3'
      assert_equal 'c99/foo', ActiveSupport::Cache.expand_cache_key(:foo)
    ensure
      ENV['RAILS_CACHE_ID'] = nil
      ENV['RAILS_APP_VERSION'] = nil
    end
  end

45
  def test_expand_cache_key_respond_to_cache_key
46 47 48 49 50
    key = 'foo'
    def key.cache_key
      :foo_key
    end
    assert_equal 'foo_key', ActiveSupport::Cache.expand_cache_key(key)
51 52
  end

53
  def test_expand_cache_key_array_with_something_that_responds_to_cache_key
54 55 56 57
    key = 'foo'
    def key.cache_key
      :foo_key
    end
58
    assert_equal 'Array/foo_key', ActiveSupport::Cache.expand_cache_key([key])
59 60
  end

61 62 63 64 65 66 67 68 69 70 71
  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
72 73 74 75 76 77 78 79

  def test_expand_cache_key_of_one_element_array_different_than_key_of_element
    element = 'foo'
    array = [element]
    element_cache_key = ActiveSupport::Cache.expand_cache_key(element)
    array_cache_key = ActiveSupport::Cache.expand_cache_key(array)
    assert_not_equal element_cache_key, array_cache_key
  end
80 81
end

82
class CacheStoreSettingTest < ActiveSupport::TestCase
83 84 85 86 87
  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
88

89
  def test_mem_cache_fragment_cache_store
90
    MemCache.expects(:new).with(%w[localhost], {})
91 92
    store = ActiveSupport::Cache.lookup_store :mem_cache_store, "localhost"
    assert_kind_of(ActiveSupport::Cache::MemCacheStore, store)
93 94 95 96 97 98 99
  end

  def test_mem_cache_fragment_cache_store_with_given_mem_cache
    mem_cache = MemCache.new
    MemCache.expects(:new).never
    store = ActiveSupport::Cache.lookup_store :mem_cache_store, mem_cache
    assert_kind_of(ActiveSupport::Cache::MemCacheStore, store)
100
  end
101

102 103
  def test_mem_cache_fragment_cache_store_with_given_mem_cache_like_object
    MemCache.expects(:new).never
104 105 106
    memcache = Object.new
    def memcache.get() true end
    store = ActiveSupport::Cache.lookup_store :mem_cache_store, memcache
107 108 109
    assert_kind_of(ActiveSupport::Cache::MemCacheStore, store)
  end

110
  def test_mem_cache_fragment_cache_store_with_multiple_servers
111
    MemCache.expects(:new).with(%w[localhost 192.168.1.1], {})
112 113 114
    store = ActiveSupport::Cache.lookup_store :mem_cache_store, "localhost", '192.168.1.1'
    assert_kind_of(ActiveSupport::Cache::MemCacheStore, store)
  end
115

116
  def test_mem_cache_fragment_cache_store_with_options
B
Brian Durand 已提交
117 118
    MemCache.expects(:new).with(%w[localhost 192.168.1.1], { :timeout => 10 })
    store = ActiveSupport::Cache.lookup_store :mem_cache_store, "localhost", '192.168.1.1', :namespace => 'foo', :timeout => 10
119
    assert_kind_of(ActiveSupport::Cache::MemCacheStore, store)
B
Brian Durand 已提交
120
    assert_equal 'foo', store.options[:namespace]
121
  end
122 123 124 125 126 127 128

  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
129

B
Brian Durand 已提交
130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151
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/)
152 153
    assert !cache.exist?("foo")
    assert cache.exist?("fu")
B
Brian Durand 已提交
154 155 156 157 158 159 160
  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)
161 162
    assert !cache.exist?("foo")
    assert cache.exist?("fu")
B
Brian Durand 已提交
163 164 165 166 167 168
  end
end

# Tests the base functionality that should be identical across all cache stores.
module CacheStoreBehavior
  def test_should_read_and_write_strings
169
    assert @cache.write('foo', 'bar')
B
Brian Durand 已提交
170 171 172 173 174 175 176
    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')
177
  end
178

179
  def test_fetch_without_cache_miss
B
Brian Durand 已提交
180
    @cache.write('foo', 'bar')
181 182 183
    @cache.expects(:write).never
    assert_equal 'bar', @cache.fetch('foo') { 'baz' }
  end
184

185
  def test_fetch_with_cache_miss
B
Brian Durand 已提交
186
    @cache.expects(:write).with('foo', 'baz', @cache.options)
187 188
    assert_equal 'baz', @cache.fetch('foo') { 'baz' }
  end
189

190
  def test_fetch_with_forced_cache_miss
B
Brian Durand 已提交
191
    @cache.write('foo', 'bar')
192
    @cache.expects(:read).never
B
Brian Durand 已提交
193
    @cache.expects(:write).with('foo', 'bar', @cache.options.merge(:force => true))
194
    @cache.fetch('foo', :force => true) { 'bar' }
195
  end
J
Joshua Peek 已提交
196

B
Brian Durand 已提交
197 198 199 200
  def test_fetch_with_cached_nil
    @cache.write('foo', nil)
    @cache.expects(:write).never
    assert_nil @cache.fetch('foo') { 'baz' }
J
Joshua Peek 已提交
201 202 203
  end

  def test_should_read_and_write_hash
204
    assert @cache.write('foo', {:a => "b"})
J
Joshua Peek 已提交
205 206 207
    assert_equal({:a => "b"}, @cache.read('foo'))
  end

208
  def test_should_read_and_write_integer
209
    assert @cache.write('foo', 1)
210 211 212
    assert_equal 1, @cache.read('foo')
  end

J
Joshua Peek 已提交
213
  def test_should_read_and_write_nil
214
    assert @cache.write('foo', nil)
J
Joshua Peek 已提交
215
    assert_equal nil, @cache.read('foo')
216 217
  end

218
  def test_should_read_and_write_false
219
    assert @cache.write('foo', false)
220
    assert_equal false, @cache.read('foo')
221 222
  end

B
Brian Durand 已提交
223
  def test_read_multi
224
    @cache.write('foo', 'bar')
B
Brian Durand 已提交
225 226 227
    @cache.write('fu', 'baz')
    @cache.write('fud', 'biz')
    assert_equal({"foo" => "bar", "fu" => "baz"}, @cache.read_multi('foo', 'fu'))
228
  end
229

230 231 232 233 234 235 236
  def test_read_multi_with_expires
    @cache.write('foo', 'bar', :expires_in => 0.001)
    @cache.write('fu', 'baz')
    @cache.write('fud', 'biz')
    sleep(0.002)
    assert_equal({"fu" => "baz"}, @cache.read_multi('foo', 'fu'))
  end
237

B
Brian Durand 已提交
238 239 240 241
  def test_read_and_write_compressed_small_data
    @cache.write('foo', 'bar', :compress => true)
    raw_value = @cache.send(:read_entry, 'foo', {}).raw_value
    assert_equal 'bar', @cache.read('foo')
242
    assert_equal 'bar', Marshal.load(raw_value)
243 244
  end

B
Brian Durand 已提交
245 246 247 248 249
  def test_read_and_write_compressed_large_data
    @cache.write('foo', 'bar', :compress => true, :compress_threshold => 2)
    raw_value = @cache.send(:read_entry, 'foo', {}).raw_value
    assert_equal 'bar', @cache.read('foo')
    assert_equal 'bar', Marshal.load(Zlib::Inflate.inflate(raw_value))
250
  end
251

B
Brian Durand 已提交
252 253 254
  def test_read_and_write_compressed_nil
    @cache.write('foo', nil, :compress => true)
    assert_nil @cache.read('foo')
255 256
  end

B
Brian Durand 已提交
257 258 259 260 261 262 263
  def test_cache_key
    obj = Object.new
    def obj.cache_key
      :foo
    end
    @cache.write(obj, "bar")
    assert_equal "bar", @cache.read("foo")
264
  end
265

B
Brian Durand 已提交
266 267 268 269 270 271 272
  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")
273
  end
274

B
Brian Durand 已提交
275 276 277
  def test_array_as_cache_key
    @cache.write([:fu, "foo"], "bar")
    assert_equal "bar", @cache.read("fu/foo")
278 279
  end

B
Brian Durand 已提交
280 281 282
  def test_hash_as_cache_key
    @cache.write({:foo => 1, :fu => 2}, "bar")
    assert_equal "bar", @cache.read("foo=1/fu=2")
283 284
  end

B
Brian Durand 已提交
285 286 287 288
  def test_keys_are_case_sensitive
    @cache.write("foo", "bar")
    assert_nil @cache.read("FOO")
  end
289

B
Brian Durand 已提交
290
  def test_exist
291
    @cache.write('foo', 'bar')
292 293
    assert @cache.exist?('foo')
    assert !@cache.exist?('bar')
294
  end
295

B
Brian Durand 已提交
296 297
  def test_nil_exist
    @cache.write('foo', nil)
298
    assert @cache.exist?('foo')
299 300
  end

B
Brian Durand 已提交
301 302 303
  def test_delete
    @cache.write('foo', 'bar')
    assert @cache.exist?('foo')
304
    assert @cache.delete('foo')
B
Brian Durand 已提交
305 306
    assert !@cache.exist?('foo')
  end
307

308
  def test_read_should_return_a_different_object_id_each_time_it_is_called
309
    @cache.write('foo', 'bar')
310 311 312 313
    assert_not_equal @cache.read('foo').object_id, @cache.read('foo').object_id
    value = @cache.read('foo')
    value << 'bingo'
    assert_not_equal value, @cache.read('foo')
314
  end
315 316 317 318 319 320

  def test_original_store_objects_should_not_be_immutable
    bar = 'bar'
    @cache.write('foo', bar)
    assert_nothing_raised { bar.gsub!(/.*/, 'baz') }
  end
321

B
Brian Durand 已提交
322 323 324 325 326 327 328 329 330 331 332 333
  def test_expires_in
    time = Time.local(2008, 4, 24)
    Time.stubs(:now).returns(time)

    @cache.write('foo', 'bar')
    assert_equal 'bar', @cache.read('foo')

    Time.stubs(:now).returns(time + 30)
    assert_equal 'bar', @cache.read('foo')

    Time.stubs(:now).returns(time + 61)
    assert_nil @cache.read('foo')
334
  end
335

B
Brian Durand 已提交
336 337 338 339 340 341 342
  def test_race_condition_protection
    time = Time.now
    @cache.write('foo', 'bar', :expires_in => 60)
    Time.stubs(:now).returns(time + 61)
    result = @cache.fetch('foo', :race_condition_ttl => 10) do
      assert_equal 'bar', @cache.read('foo')
      "baz"
343
    end
B
Brian Durand 已提交
344 345
    assert_equal "baz", result
  end
346

B
Brian Durand 已提交
347 348 349 350 351 352 353 354 355 356
  def test_race_condition_protection_is_limited
    time = Time.now
    @cache.write('foo', 'bar', :expires_in => 60)
    Time.stubs(:now).returns(time + 71)
    result = @cache.fetch('foo', :race_condition_ttl => 10) do
      assert_equal nil, @cache.read('foo')
      "baz"
    end
    assert_equal "baz", result
  end
357

B
Brian Durand 已提交
358 359 360 361 362 363
  def test_race_condition_protection_is_safe
    time = Time.now
    @cache.write('foo', 'bar', :expires_in => 60)
    Time.stubs(:now).returns(time + 61)
    begin
      @cache.fetch('foo', :race_condition_ttl => 10) do
364
        assert_equal 'bar', @cache.read('foo')
B
Brian Durand 已提交
365
        raise ArgumentError.new
366
      end
S
Santiago Pastorino 已提交
367
    rescue ArgumentError
368
    end
B
Brian Durand 已提交
369 370 371 372 373 374 375
    assert_equal "bar", @cache.read('foo')
    Time.stubs(:now).returns(time + 71)
    assert_nil @cache.read('foo')
  end

  def test_crazy_key_characters
    crazy_key = "#/:*(<+=> )&$%@?;'\"\'`~-"
376
    assert @cache.write(crazy_key, "1", :raw => true)
B
Brian Durand 已提交
377 378
    assert_equal "1", @cache.read(crazy_key)
    assert_equal "1", @cache.fetch(crazy_key)
379
    assert @cache.delete(crazy_key)
B
Brian Durand 已提交
380 381 382 383 384 385 386
    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 = ""
387
    900.times{key << "x"}
388
    assert @cache.write(key, "bar")
B
Brian Durand 已提交
389 390 391 392
    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))
393
    assert @cache.delete(key)
B
Brian Durand 已提交
394 395
  end
end
396

397 398 399 400
# https://rails.lighthouseapp.com/projects/8994/tickets/6225-memcachestore-cant-deal-with-umlauts-and-special-characters
# The error is caused by charcter encodings that can't be compared with ASCII-8BIT regular expressions and by special
# characters like the umlaut in UTF-8.
module EncodedKeyCacheBehavior
401 402 403
  Encoding.list.each do |encoding|
    define_method "test_#{encoding.name.underscore}_encoded_values" do
      key = "foo".force_encoding(encoding)
404
      assert @cache.write(key, "1", :raw => true)
405 406
      assert_equal "1", @cache.read(key)
      assert_equal "1", @cache.fetch(key)
407
      assert @cache.delete(key)
408 409 410 411
      assert_equal "2", @cache.fetch(key, :raw => true) { "2" }
      assert_equal 3, @cache.increment(key)
      assert_equal 2, @cache.decrement(key)
    end
412
  end
413

414 415 416 417 418 419 420 421 422 423 424 425 426 427 428
  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
429 430 431
  end
end

B
Brian Durand 已提交
432 433 434 435
module CacheDeleteMatchedBehavior
  def test_delete_matched
    @cache.write("foo", "bar")
    @cache.write("fu", "baz")
436 437
    @cache.write("foo/bar", "baz")
    @cache.write("fu/baz", "bar")
B
Brian Durand 已提交
438
    @cache.delete_matched(/oo/)
439 440 441 442
    assert !@cache.exist?("foo")
    assert @cache.exist?("fu")
    assert !@cache.exist?("foo/bar")
    assert @cache.exist?("fu/baz")
B
Brian Durand 已提交
443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469
  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
  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
  end
end

module LocalCacheBehavior
  def test_local_writes_are_persistent_on_the_remote_cache
    retval = @cache.with_local_cache do
      @cache.write('foo', 'bar')
470
    end
471
    assert retval
B
Brian Durand 已提交
472 473
    assert_equal 'bar', @cache.read('foo')
  end
474

B
Brian Durand 已提交
475 476 477 478 479
  def test_clear_also_clears_local_cache
    @cache.with_local_cache do
      @cache.write('foo', 'bar')
      @cache.clear
      assert_nil @cache.read('foo')
480 481
    end

B
Brian Durand 已提交
482 483
    assert_nil @cache.read('foo')
  end
484

B
Brian Durand 已提交
485 486 487 488
  def test_local_cache_of_write
    @cache.with_local_cache do
      @cache.write('foo', 'bar')
      @peek.delete('foo')
489 490
      assert_equal 'bar', @cache.read('foo')
    end
B
Brian Durand 已提交
491
  end
492

B
Brian Durand 已提交
493 494 495 496
  def test_local_cache_of_read
    @cache.write('foo', 'bar')
    @cache.with_local_cache do
      assert_equal 'bar', @cache.read('foo')
497
    end
B
Brian Durand 已提交
498
  end
499

B
Brian Durand 已提交
500 501
  def test_local_cache_of_write_nil
    @cache.with_local_cache do
502
      assert @cache.write('foo', nil)
B
Brian Durand 已提交
503 504 505
      assert_nil @cache.read('foo')
      @peek.write('foo', 'bar')
      assert_nil @cache.read('foo')
506
    end
B
Brian Durand 已提交
507
  end
508

B
Brian Durand 已提交
509 510 511 512 513
  def test_local_cache_of_delete
    @cache.with_local_cache do
      @cache.write('foo', 'bar')
      @cache.delete('foo')
      assert_nil @cache.read('foo')
514
    end
B
Brian Durand 已提交
515
  end
516

B
Brian Durand 已提交
517 518 519 520
  def test_local_cache_of_exist
    @cache.with_local_cache do
      @cache.write('foo', 'bar')
      @peek.delete('foo')
521
      assert @cache.exist?('foo')
522
    end
B
Brian Durand 已提交
523
  end
524

B
Brian Durand 已提交
525 526 527 528 529 530
  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')
531
    end
B
Brian Durand 已提交
532
  end
533

B
Brian Durand 已提交
534 535 536 537 538 539
  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')
540
    end
B
Brian Durand 已提交
541
  end
542

B
Brian Durand 已提交
543 544 545 546 547 548 549 550 551 552
  def test_middleware
    app = lambda { |env|
      result = @cache.write('foo', 'bar')
      assert_equal 'bar', @cache.read('foo') # make sure 'foo' was written
      assert result
    }
    app = @cache.middleware.new(app)
    app.call({})
  end
end
553

B
Brian Durand 已提交
554 555 556 557 558
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)
559
    @cache_with_pathname = ActiveSupport::Cache.lookup_store(:file_store, Pathname.new(cache_dir), :expires_in => 60)
B
Brian Durand 已提交
560 561 562 563 564 565 566 567 568 569 570 571 572 573 574
  end

  def teardown
    FileUtils.rm_r(cache_dir)
  end

  def cache_dir
    File.join(Dir.pwd, 'tmp_cache')
  end

  include CacheStoreBehavior
  include LocalCacheBehavior
  include CacheDeleteMatchedBehavior
  include CacheIncrementDecrementBehavior

575 576 577 578
  def test_key_transformation
    key = @cache.send(:key_file_path, "views/index?id=1")
    assert_equal "views/index?id=1", @cache.send(:file_path_key, key)
  end
579 580 581 582 583 584

  def test_key_transformation_with_pathname
    FileUtils.touch(File.join(cache_dir, "foo"))
    key = @cache_with_pathname.send(:key_file_path, "views/index?id=1")
    assert_equal "views/index?id=1", @cache_with_pathname.send(:file_path_key, key)
  end
585

586 587 588 589
  # 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"
590
    path = @cache.send(:key_file_path, key)
591 592 593
    assert path.split('/').all? { |dir_name| dir_name.size <= ActiveSupport::Cache::FileStore::FILENAME_MAX_SIZE}
    assert_equal 'B', File.basename(path)
  end
594

595 596 597 598 599
  # 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(Exception) do
      ActiveSupport::Cache::FileStore.new('/test/cache/directory').delete_matched(/does_not_exist/)
600 601
    end
  end
B
Brian Durand 已提交
602
end
603

B
Brian Durand 已提交
604 605
class MemoryStoreTest < ActiveSupport::TestCase
  def setup
606 607
    @record_size = Marshal.dump("aaaaaaaaaa").bytesize
    @cache = ActiveSupport::Cache.lookup_store(:memory_store, :expires_in => 60, :size => @record_size * 10)
B
Brian Durand 已提交
608 609 610 611 612 613 614 615 616 617 618 619 620 621
  end

  include CacheStoreBehavior
  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)
622
    @cache.prune(@record_size * 3)
623 624 625 626 627
    assert @cache.exist?(5)
    assert @cache.exist?(4)
    assert !@cache.exist?(3)
    assert @cache.exist?(2)
    assert !@cache.exist?(1)
B
Brian Durand 已提交
628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643
  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")
644 645 646 647 648 649 650 651 652 653 654
    assert @cache.exist?(11)
    assert @cache.exist?(10)
    assert @cache.exist?(9)
    assert @cache.exist?(8)
    assert @cache.exist?(7)
    assert !@cache.exist?(6)
    assert !@cache.exist?(5)
    assert @cache.exist?(4)
    assert !@cache.exist?(3)
    assert @cache.exist?(2)
    assert !@cache.exist?(1)
B
Brian Durand 已提交
655 656 657 658 659 660
  end

  def test_pruning_is_capped_at_a_max_time
    def @cache.delete_entry (*args)
      sleep(0.01)
      super
661
    end
B
Brian Durand 已提交
662 663 664 665 666 667
    @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)
668 669 670 671 672
    assert @cache.exist?(5)
    assert @cache.exist?(4)
    assert @cache.exist?(3)
    assert @cache.exist?(2)
    assert !@cache.exist?(1)
B
Brian Durand 已提交
673 674
  end
end
675

B
Brian Durand 已提交
676 677 678 679 680 681 682 683 684
uses_memcached 'memcached backed store' do
  class MemCacheStoreTest < ActiveSupport::TestCase
    def setup
      @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 = Logger.new("/dev/null")
685 686
    end

B
Brian Durand 已提交
687 688 689
    include CacheStoreBehavior
    include LocalCacheBehavior
    include CacheIncrementDecrementBehavior
690
    include EncodedKeyCacheBehavior
B
Brian Durand 已提交
691 692 693 694 695 696

    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")
697
    end
698

699 700 701 702
    def test_raw_values_with_marshal
      cache = ActiveSupport::Cache.lookup_store(:mem_cache_store, :raw => true)
      cache.clear
      cache.write("foo", Marshal.dump([]))
703
      assert_equal [], cache.read("foo")
704
    end
705

B
Brian Durand 已提交
706 707 708 709 710 711 712
    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
713
    end
714 715 716 717 718 719 720 721 722

    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
723 724
  end
end
725

726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783
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

  def test_setting_nil_cache_store
    assert ActiveSupport::Cache.lookup_store.class.name, ActiveSupport::Cache::NullStore.name
  end
end

784 785 786 787 788 789 790 791 792 793
class CacheStoreLoggerTest < ActiveSupport::TestCase
  def setup
    @cache = ActiveSupport::Cache.lookup_store(:memory_store)

    @buffer = StringIO.new
    @cache.logger = Logger.new(@buffer)
  end

  def test_logging
    @cache.fetch('foo') { 'bar' }
794
    assert_present @buffer.string
795 796 797 798
  end

  def test_mute_logging
    @cache.mute { @cache.fetch('foo') { 'bar' } }
799
    assert_blank @buffer.string
800 801
  end
end
B
Brian Durand 已提交
802 803 804 805 806 807 808

class CacheEntryTest < ActiveSupport::TestCase
  def test_create_raw_entry
    time = Time.now
    entry = ActiveSupport::Cache::Entry.create("raw", time, :compress => false, :expires_in => 300)
    assert_equal "raw", entry.raw_value
    assert_equal time.to_f, entry.created_at
809
    assert !entry.compressed?
B
Brian Durand 已提交
810 811 812 813 814
    assert_equal 300, entry.expires_in
  end

  def test_expired
    entry = ActiveSupport::Cache::Entry.new("value")
815
    assert !entry.expired?, 'entry not expired'
B
Brian Durand 已提交
816
    entry = ActiveSupport::Cache::Entry.new("value", :expires_in => 60)
817
    assert !entry.expired?, 'entry not expired'
B
Brian Durand 已提交
818 819
    time = Time.now + 61
    Time.stubs(:now).returns(time)
820
    assert entry.expired?, 'entry is expired'
B
Brian Durand 已提交
821 822 823 824 825
  end

  def test_compress_values
    entry = ActiveSupport::Cache::Entry.new("value", :compress => true, :compress_threshold => 1)
    assert_equal "value", entry.value
826
    assert entry.compressed?
B
Brian Durand 已提交
827 828 829 830 831 832
    assert_equal "value", Marshal.load(Zlib::Inflate.inflate(entry.raw_value))
  end

  def test_non_compress_values
    entry = ActiveSupport::Cache::Entry.new("value")
    assert_equal "value", entry.value
833
    assert_equal "value", Marshal.load(entry.raw_value)
834
    assert !entry.compressed?
B
Brian Durand 已提交
835 836
  end
end