identity_cache 0.1.0 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -25,7 +25,7 @@ class FetchMultiTest < IdentityCache::TestCase
25
25
  cache_response[bob_blob_key] = cache_response_for(@bob)
26
26
  cache_response[joe_blob_key] = cache_response_for(@joe)
27
27
  cache_response[fred_blob_key] = cache_response_for(@fred)
28
- IdentityCache.cache.expects(:read_multi).with(bob_blob_key, joe_blob_key, fred_blob_key).returns(cache_response)
28
+ IdentityCache.cache.expects(:fetch_multi).with(bob_blob_key, joe_blob_key, fred_blob_key).returns(cache_response)
29
29
  assert_equal [@bob, @joe, @fred], Item.fetch_multi(@bob.id, @joe.id, @fred.id)
30
30
  end
31
31
 
@@ -34,7 +34,7 @@ class FetchMultiTest < IdentityCache::TestCase
34
34
  cache_response[@bob_blob_key] = cache_response_for(@bob)
35
35
  cache_response[@joe_blob_key] = cache_response_for(@joe)
36
36
  cache_response[@fred_blob_key] = cache_response_for(@fred)
37
- IdentityCache.cache.expects(:read_multi).with(@bob_blob_key, @joe_blob_key, @fred_blob_key).returns(cache_response)
37
+ IdentityCache.cache.expects(:fetch_multi).with(@bob_blob_key, @joe_blob_key, @fred_blob_key).returns(cache_response)
38
38
  assert_equal [@bob, @joe, @fred], Item.fetch_multi(@bob.id, @joe.id, @fred.id)
39
39
  end
40
40
 
@@ -43,8 +43,9 @@ class FetchMultiTest < IdentityCache::TestCase
43
43
  cache_response[@bob_blob_key] = nil
44
44
  cache_response[@joe_blob_key] = nil
45
45
  cache_response[@fred_blob_key] = nil
46
- IdentityCache.cache.expects(:read_multi).with(@bob_blob_key, @joe_blob_key, @fred_blob_key).returns(cache_response)
46
+ fetch_multi = fetch_multi_stub(cache_response)
47
47
  assert_equal [@bob, @joe, @fred], Item.fetch_multi(@bob.id, @joe.id, @fred.id)
48
+ assert fetch_multi.has_been_called_with?(@bob_blob_key, @joe_blob_key, @fred_blob_key)
48
49
  end
49
50
 
50
51
  def test_fetch_multi_with_mixed_hits_and_misses
@@ -52,8 +53,9 @@ class FetchMultiTest < IdentityCache::TestCase
52
53
  cache_response[@bob_blob_key] = cache_response_for(@bob)
53
54
  cache_response[@joe_blob_key] = nil
54
55
  cache_response[@fred_blob_key] = cache_response_for(@fred)
55
- IdentityCache.cache.expects(:read_multi).with(@bob_blob_key, @joe_blob_key, @fred_blob_key).returns(cache_response)
56
+ fetch_multi = fetch_multi_stub(cache_response)
56
57
  assert_equal [@bob, @joe, @fred], Item.fetch_multi(@bob.id, @joe.id, @fred.id)
58
+ assert fetch_multi.has_been_called_with?(@bob_blob_key, @joe_blob_key, @fred_blob_key)
57
59
  end
58
60
 
59
61
  def test_fetch_multi_with_mixed_hits_and_misses_and_responses_in_the_wrong_order
@@ -61,22 +63,25 @@ class FetchMultiTest < IdentityCache::TestCase
61
63
  cache_response[@bob_blob_key] = nil
62
64
  cache_response[@joe_blob_key] = nil
63
65
  cache_response[@fred_blob_key] = cache_response_for(@fred)
64
- IdentityCache.cache.expects(:read_multi).with(@bob_blob_key, @fred_blob_key, @joe_blob_key).returns(cache_response)
66
+ fetch_multi = fetch_multi_stub(cache_response)
65
67
  assert_equal [@bob, @fred, @joe], Item.fetch_multi(@bob.id, @fred.id, @joe.id)
68
+ assert fetch_multi.has_been_called_with?(@bob_blob_key, @fred_blob_key, @joe_blob_key)
66
69
  end
67
70
 
68
71
  def test_fetch_multi_with_mixed_hits_and_misses_and_non_existant_keys_1
69
72
  populate_only_fred
70
73
 
71
- IdentityCache.cache.expects(:read_multi).with(@tenth_blob_key, @bob_blob_key, @joe_blob_key, @fred_blob_key).returns(@cache_response)
74
+ fetch_multi = fetch_multi_stub(@cache_response)
72
75
  assert_equal [@bob, @joe, @fred], Item.fetch_multi(10, @bob.id, @joe.id, @fred.id)
76
+ assert fetch_multi.has_been_called_with?(@tenth_blob_key, @bob_blob_key, @joe_blob_key, @fred_blob_key)
73
77
  end
74
78
 
75
79
  def test_fetch_multi_with_mixed_hits_and_misses_and_non_existant_keys_2
76
80
  populate_only_fred
77
81
 
78
- IdentityCache.cache.expects(:read_multi).with(@fred_blob_key, @bob_blob_key, @tenth_blob_key, @joe_blob_key).returns(@cache_response)
82
+ fetch_multi = fetch_multi_stub(@cache_response)
79
83
  assert_equal [@fred, @bob, @joe], Item.fetch_multi(@fred.id, @bob.id, 10, @joe.id)
84
+ assert fetch_multi.has_been_called_with?(@fred_blob_key, @bob_blob_key, @tenth_blob_key, @joe_blob_key)
80
85
  end
81
86
 
82
87
 
@@ -84,9 +89,9 @@ class FetchMultiTest < IdentityCache::TestCase
84
89
  cache_result = {1 => IdentityCache::CACHED_NIL, 2 => IdentityCache::CACHED_NIL}
85
90
  fetch_result = {1 => nil, 2 => nil}
86
91
 
87
- IdentityCache.cache.expects(:read_multi).with(1,2).times(2).returns({1 => nil, 2 => nil}, cache_result)
88
- IdentityCache.cache.expects(:write).with(1, IdentityCache::CACHED_NIL).once
89
- IdentityCache.cache.expects(:write).with(2, IdentityCache::CACHED_NIL).once
92
+ fetcher.expects(:cas_multi).with([1, 2]).twice.returns(nil, cache_result)
93
+ fetcher.expects(:add).with(1, IdentityCache::CACHED_NIL).once
94
+ fetcher.expects(:add).with(2, IdentityCache::CACHED_NIL).once
90
95
 
91
96
  results = IdentityCache.fetch_multi(1,2) do |keys|
92
97
  [nil, nil]
@@ -103,7 +108,7 @@ class FetchMultiTest < IdentityCache::TestCase
103
108
  def test_fetch_multi_works_with_blanks
104
109
  cache_result = {1 => false, 2 => ' '}
105
110
 
106
- IdentityCache.cache.expects(:read_multi).with(1,2).returns(cache_result)
111
+ fetcher.expects(:fetch_multi).with([1,2]).returns(cache_result)
107
112
 
108
113
  results = IdentityCache.fetch_multi(1,2) do |keys|
109
114
  flunk "Contents should have been fetched from cache successfully"
@@ -118,7 +123,7 @@ class FetchMultiTest < IdentityCache::TestCase
118
123
 
119
124
  def test_fetch_multi_with_open_transactions_hits_the_database
120
125
  Item.connection.expects(:open_transactions).at_least_once.returns(1)
121
- IdentityCache.cache.expects(:read_multi).never
126
+ fetcher.expects(:fetch_multi).never
122
127
  assert_equal [@bob, @joe, @fred], Item.fetch_multi(@bob.id, @joe.id, @fred.id)
123
128
  end
124
129
 
@@ -165,15 +170,15 @@ class FetchMultiTest < IdentityCache::TestCase
165
170
  cache_response[@joe_blob_key] = cache_response_for(@joe)
166
171
 
167
172
  with_batch_size 1 do
168
- IdentityCache.cache.expects(:read_multi).with(@bob_blob_key).returns(cache_response).once
169
- IdentityCache.cache.expects(:read_multi).with(@joe_blob_key).returns(cache_response).once
173
+ fetcher.expects(:fetch_multi).with([@bob_blob_key]).returns(cache_response).once
174
+ fetcher.expects(:fetch_multi).with([@joe_blob_key]).returns(cache_response).once
170
175
  assert_equal [@bob, @joe], Item.fetch_multi(@bob.id, @joe.id)
171
176
  end
172
177
  end
173
178
 
174
179
  def test_fetch_multi_max_stack_level
175
180
  cache_response = { @fred_blob_key => cache_response_for(@fred) }
176
- IdentityCache.cache.stubs(:read_multi).returns(cache_response)
181
+ fetcher.stubs(:fetch_multi).returns(cache_response)
177
182
  assert_nothing_raised { Item.fetch_multi([@fred.id] * 200_000) }
178
183
  end
179
184
 
@@ -182,6 +187,18 @@ class FetchMultiTest < IdentityCache::TestCase
182
187
  assert_equal [fixture], KeyedRecord.fetch_multi(123, 456)
183
188
  end
184
189
 
190
+ def test_fetch_multi_after_expiring_a_record
191
+ Item.fetch_multi(@joe.id, @fred.id)
192
+ @bob.send(:expire_cache)
193
+ assert_equal IdentityCache::DELETED, backend.read(@bob.primary_cache_index_key)
194
+
195
+ add = Spy.on(IdentityCache.cache.cache_fetcher, :add).and_call_through
196
+
197
+ assert_equal [@bob, @joe, @fred], Item.fetch_multi(@bob.id, @joe.id, @fred.id)
198
+ refute add.has_been_called?
199
+ assert_equal cache_response_for(Item.find(@bob.id)), backend.read(@bob.primary_cache_index_key)
200
+ end
201
+
185
202
  private
186
203
 
187
204
  def populate_only_fred
@@ -207,4 +224,11 @@ class FetchMultiTest < IdentityCache::TestCase
207
224
  IdentityCache.send(:remove_const, :BATCH_SIZE)
208
225
  IdentityCache.const_set(:BATCH_SIZE, previous_batch_size)
209
226
  end
227
+
228
+ def fetch_multi_stub(cache_response)
229
+ Spy.on(IdentityCache.cache, :fetch_multi).and_return do |*args, &block|
230
+ nil_keys = cache_response.select {|_, v| v.nil? }.keys
231
+ cache_response.merge(Hash[nil_keys.zip(block.call(nil_keys))])
232
+ end
233
+ end
210
234
  end
data/test/fetch_test.rb CHANGED
@@ -26,7 +26,7 @@ class FetchTest < IdentityCache::TestCase
26
26
  end
27
27
 
28
28
  def test_fetch_cache_hit
29
- IdentityCache.cache.expects(:read).with(@blob_key).returns(@cached_value)
29
+ IdentityCache.cache.expects(:fetch).with(@blob_key).returns(@cached_value)
30
30
 
31
31
  assert_equal @record, Item.fetch(1)
32
32
  end
@@ -36,7 +36,7 @@ class FetchTest < IdentityCache::TestCase
36
36
  IdentityCache.cache_namespace = proc { |model| "#{model.table_name}:#{old_ns}" }
37
37
 
38
38
  new_blob_key = "items:#{@blob_key}"
39
- IdentityCache.cache.expects(:read).with(new_blob_key).returns(@cached_value)
39
+ IdentityCache.cache.expects(:fetch).with(new_blob_key).returns(@cached_value)
40
40
 
41
41
  assert_equal @record, Item.fetch(1)
42
42
  ensure
@@ -44,32 +44,36 @@ class FetchTest < IdentityCache::TestCase
44
44
  end
45
45
 
46
46
  def test_exists_with_identity_cache_when_cache_hit
47
- IdentityCache.cache.expects(:read).with(@blob_key).returns(@cached_value)
47
+ IdentityCache.cache.expects(:fetch).with(@blob_key).returns(@cached_value)
48
48
 
49
49
  assert Item.exists_with_identity_cache?(1)
50
50
  end
51
51
 
52
52
  def test_exists_with_identity_cache_when_cache_miss_and_in_db
53
- IdentityCache.cache.expects(:read).with(@blob_key).returns(nil)
53
+ fetch = Spy.on(IdentityCache.cache, :fetch).and_call_through
54
54
  Item.expects(:resolve_cache_miss).with(1).once.returns(@record)
55
55
 
56
56
  assert Item.exists_with_identity_cache?(1)
57
+ assert fetch.has_been_called_with?(@blob_key)
57
58
  end
58
59
 
59
60
  def test_exists_with_identity_cache_when_cache_miss_and_not_in_db
60
- IdentityCache.cache.expects(:read).with(@blob_key).returns(nil)
61
+ fetch = Spy.on(IdentityCache.cache, :fetch).and_call_through
61
62
  Item.expects(:resolve_cache_miss).with(1).once.returns(nil)
62
63
 
63
64
  assert !Item.exists_with_identity_cache?(1)
65
+ assert fetch.has_been_called_with?(@blob_key)
64
66
  end
65
67
 
66
68
  def test_fetch_miss
67
69
  Item.expects(:resolve_cache_miss).with(1).once.returns(@record)
68
70
 
69
- IdentityCache.cache.expects(:read).with(@blob_key).returns(nil)
70
- IdentityCache.cache.expects(:write).with(@blob_key, @cached_value)
71
+ results = []
72
+ fetch = Spy.on(IdentityCache.cache, :fetch).and_return {|_, &block| block.call.tap {|result| results << result}}
71
73
 
72
74
  assert_equal @record, Item.fetch(1)
75
+ assert fetch.has_been_called_with?(@blob_key)
76
+ assert_equal [@cached_value], results
73
77
  end
74
78
 
75
79
  def test_fetch_miss_with_non_id_primary_key
@@ -78,16 +82,45 @@ class FetchTest < IdentityCache::TestCase
78
82
  assert_equal fixture, KeyedRecord.fetch(hashed_key)
79
83
  end
80
84
 
85
+ def test_fetch_conflict
86
+ resolve_cache_miss = Spy.on(Item, :resolve_cache_miss).and_return do
87
+ @record.send(:expire_cache)
88
+ @record
89
+ end
90
+ add = Spy.on(fetcher, :add).and_call_through
91
+
92
+ assert_equal @record, Item.fetch(1)
93
+ assert resolve_cache_miss.has_been_called_with?(1)
94
+ assert add.has_been_called_with?(@blob_key, @cached_value)
95
+ assert_equal IdentityCache::DELETED, backend.read(@record.primary_cache_index_key)
96
+ end
97
+
98
+ def test_fetch_conflict_after_delete
99
+ @record.send(:expire_cache)
100
+ assert_equal IdentityCache::DELETED, backend.read(@record.primary_cache_index_key)
101
+
102
+ resolve_cache_miss = Spy.on(Item, :resolve_cache_miss).and_return do
103
+ @record.send(:expire_cache)
104
+ @record
105
+ end
106
+ add = Spy.on(IdentityCache.cache.cache_fetcher, :add).and_call_through
107
+
108
+ assert_equal @record, Item.fetch(1)
109
+ assert resolve_cache_miss.has_been_called_with?(1)
110
+ refute add.has_been_called?
111
+ assert_equal IdentityCache::DELETED, backend.read(@record.primary_cache_index_key)
112
+ end
113
+
81
114
  def test_fetch_by_id_not_found_should_return_nil
82
115
  nonexistent_record_id = 10
83
- IdentityCache.cache.expects(:write).with(@blob_key + '0', IdentityCache::CACHED_NIL)
116
+ fetcher.expects(:add).with(@blob_key + '0', IdentityCache::CACHED_NIL)
84
117
 
85
118
  assert_equal nil, Item.fetch_by_id(nonexistent_record_id)
86
119
  end
87
120
 
88
121
  def test_fetch_not_found_should_raise
89
122
  nonexistent_record_id = 10
90
- IdentityCache.cache.expects(:write).with(@blob_key + '0', IdentityCache::CACHED_NIL)
123
+ fetcher.expects(:add).with(@blob_key + '0', IdentityCache::CACHED_NIL)
91
124
 
92
125
  assert_raises(ActiveRecord::RecordNotFound) { Item.fetch(nonexistent_record_id) }
93
126
  end
@@ -96,44 +129,51 @@ class FetchTest < IdentityCache::TestCase
96
129
  key = @record.primary_cache_index_key
97
130
 
98
131
  assert_equal nil, Item.fetch_by_id(@record.id)
99
- assert_equal IdentityCache::CACHED_NIL, IdentityCache.cache.read(key)
132
+ assert_equal IdentityCache::CACHED_NIL, backend.read(key)
100
133
 
101
134
  @record.save!
102
- assert_nil IdentityCache.cache.read(key)
135
+ assert_equal IdentityCache::DELETED, backend.read(key)
103
136
  end
104
137
 
105
138
  def test_fetch_by_title_hit
106
- # Read record with title bob
107
- IdentityCache.cache.expects(:read).with(@index_key).returns(nil)
139
+ values = []
140
+ fetch = Spy.on(IdentityCache.cache, :fetch).and_return do |key, &block|
141
+ case key
142
+ # Read record with title bob
143
+ when @index_key then block.call.tap {|val| values << val}
144
+ # got id, do memcache lookup on that, hit -> done
145
+ when @blob_key then @cached_value
146
+ end
147
+ end
108
148
 
109
- # - not found, use sql, SELECT id FROM records WHERE title = '...' LIMIT 1"
149
+ # Id not found, use sql, SELECT id FROM records WHERE title = '...' LIMIT 1"
110
150
  Item.connection.expects(:exec_query).returns(ActiveRecord::Result.new(['id'], [[1]]))
111
151
 
112
- # cache sql result
113
- IdentityCache.cache.expects(:write).with(@index_key, 1)
114
-
115
- # got id, do memcache lookup on that, hit -> done
116
- IdentityCache.cache.expects(:read).with(@blob_key).returns(@cached_value)
117
-
118
152
  assert_equal @record, Item.fetch_by_title('bob')
153
+ assert_equal [1], values
154
+ assert fetch.has_been_called_with?(@index_key)
155
+ assert fetch.has_been_called_with?(@blob_key)
119
156
  end
120
157
 
121
158
  def test_fetch_by_title_cache_namespace
122
159
  Item.send(:include, SwitchNamespace)
123
- IdentityCache.cache.expects(:read).with("ns:#{@index_key}").returns(1)
124
- IdentityCache.cache.expects(:read).with("ns:#{@blob_key}").returns(@cached_value)
160
+ IdentityCache.cache.expects(:fetch).with("ns:#{@index_key}").returns(1)
161
+ IdentityCache.cache.expects(:fetch).with("ns:#{@blob_key}").returns(@cached_value)
125
162
 
126
163
  assert_equal @record, Item.fetch_by_title('bob')
127
164
  end
128
165
 
129
166
  def test_fetch_by_title_stores_idcnil
130
167
  Item.connection.expects(:exec_query).once.returns(ActiveRecord::Result.new([], []))
131
- IdentityCache.cache.expects(:write).with(@index_key, IdentityCache::CACHED_NIL)
132
- IdentityCache.cache.expects(:read).with(@index_key).times(3).returns(nil, IdentityCache::CACHED_NIL, IdentityCache::CACHED_NIL)
168
+ add = Spy.on(fetcher, :add).and_call_through
169
+ fetch = Spy.on(fetcher, :fetch).and_call_through
133
170
  assert_equal nil, Item.fetch_by_title('bob') # exec_query => nil
134
171
 
135
172
  assert_equal nil, Item.fetch_by_title('bob') # returns cached nil
136
173
  assert_equal nil, Item.fetch_by_title('bob') # returns cached nil
174
+
175
+ assert add.has_been_called_with?(@index_key, IdentityCache::CACHED_NIL)
176
+ assert_equal 3, fetch.calls.length
137
177
  end
138
178
 
139
179
  def test_fetch_by_bang_method
@@ -144,8 +184,8 @@ class FetchTest < IdentityCache::TestCase
144
184
  end
145
185
 
146
186
  def test_fetch_does_not_communicate_to_cache_with_nil_id
147
- IdentityCache.cache.expects(:read).never
148
- IdentityCache.cache.expects(:write).never
187
+ fetcher.expects(:fetch).never
188
+ fetcher.expects(:add).never
149
189
  assert_raises(ActiveRecord::RecordNotFound) { Item.fetch(nil) }
150
190
  end
151
191
  end
Binary file
@@ -1,20 +1,16 @@
1
1
  $LOAD_PATH.unshift File.expand_path("../../../lib", __FILE__)
2
2
 
3
+ require 'logger'
3
4
  require 'active_record'
4
5
  require 'memcached_store'
6
+ require 'active_support/cache/memcached_store'
5
7
  require_relative 'serialization_format'
6
- require_relative 'cache'
7
8
  require_relative 'database_connection'
8
9
  require_relative 'active_record_objects'
9
10
  require 'identity_cache'
10
11
 
11
- if ENV['BOXEN_HOME'].present?
12
- $memcached_port = 21211
13
- $mysql_port = 13306
14
- else
15
- $memcached_port = 11211
16
- $mysql_port = 3306
17
- end
12
+ $memcached_port = 11211
13
+ $mysql_port = 3306
18
14
 
19
15
  include SerializationFormat
20
16
  include ActiveRecordObjects
@@ -22,6 +18,8 @@ include ActiveRecordObjects
22
18
  DatabaseConnection.setup
23
19
  DatabaseConnection.drop_tables
24
20
  DatabaseConnection.create_tables
21
+ IdentityCache.logger = Logger.new(nil)
22
+ IdentityCache.cache_backend = ActiveSupport::Cache::MemcachedStore.new("localhost:#{$memcached_port}", :support_cas => true)
25
23
  setup_models
26
24
  File.open(serialized_record_file, 'w') {|file| serialize(serialized_record, file) }
27
25
  puts "Serialized record to #{serialized_record_file}"
@@ -34,21 +34,21 @@ class IndexCacheTest < IdentityCache::TestCase
34
34
  def test_unique_index_caches_nil
35
35
  Item.cache_index :title, :unique => true
36
36
  assert_equal nil, Item.fetch_by_title('bob')
37
- assert_equal IdentityCache::CACHED_NIL, IdentityCache.cache.read(@cache_key)
37
+ assert_equal IdentityCache::CACHED_NIL, backend.read(@cache_key)
38
38
  end
39
39
 
40
40
  def test_unique_index_expired_by_new_record
41
41
  Item.cache_index :title, :unique => true
42
42
  IdentityCache.cache.write(@cache_key, IdentityCache::CACHED_NIL)
43
43
  @record.save!
44
- assert_equal nil, IdentityCache.cache.read(@cache_key)
44
+ assert_equal IdentityCache::DELETED, backend.read(@cache_key)
45
45
  end
46
46
 
47
47
  def test_unique_index_filled_on_fetch_by
48
48
  Item.cache_index :title, :unique => true
49
49
  @record.save!
50
50
  assert_equal @record, Item.fetch_by_title('bob')
51
- assert_equal @record.id, IdentityCache.cache.read(@cache_key)
51
+ assert_equal @record.id, backend.read(@cache_key)
52
52
  end
53
53
 
54
54
  def test_unique_index_expired_by_updated_record
@@ -60,28 +60,28 @@ class IndexCacheTest < IdentityCache::TestCase
60
60
  new_cache_key = "#{NAMESPACE}index:Item:title:#{cache_hash(@record.title)}"
61
61
  IdentityCache.cache.write(new_cache_key, IdentityCache::CACHED_NIL)
62
62
  @record.save!
63
- assert_equal nil, IdentityCache.cache.read(@cache_key)
64
- assert_equal nil, IdentityCache.cache.read(new_cache_key)
63
+ assert_equal IdentityCache::DELETED, backend.read(@cache_key)
64
+ assert_equal IdentityCache::DELETED, backend.read(new_cache_key)
65
65
  end
66
66
 
67
67
  def test_non_unique_index_caches_empty_result
68
68
  Item.cache_index :title
69
69
  assert_equal [], Item.fetch_by_title('bob')
70
- assert_equal [], IdentityCache.cache.read(@cache_key)
70
+ assert_equal [], backend.read(@cache_key)
71
71
  end
72
72
 
73
73
  def test_non_unique_index_expired_by_new_record
74
74
  Item.cache_index :title
75
75
  IdentityCache.cache.write(@cache_key, [])
76
76
  @record.save!
77
- assert_equal nil, IdentityCache.cache.read(@cache_key)
77
+ assert_equal IdentityCache::DELETED, backend.read(@cache_key)
78
78
  end
79
79
 
80
80
  def test_non_unique_index_filled_on_fetch_by
81
81
  Item.cache_index :title
82
82
  @record.save!
83
83
  assert_equal [@record], Item.fetch_by_title('bob')
84
- assert_equal [@record.id], IdentityCache.cache.read(@cache_key)
84
+ assert_equal [@record.id], backend.read(@cache_key)
85
85
  end
86
86
 
87
87
  def test_non_unique_index_fetches_multiple_records
@@ -90,7 +90,7 @@ class IndexCacheTest < IdentityCache::TestCase
90
90
  record2 = Item.create(:id => 2, :title => 'bob')
91
91
 
92
92
  assert_equal [@record, record2], Item.fetch_by_title('bob')
93
- assert_equal [1, 2], IdentityCache.cache.read(@cache_key)
93
+ assert_equal [1, 2], backend.read(@cache_key)
94
94
  end
95
95
 
96
96
  def test_non_unique_index_expired_by_updating_record
@@ -102,8 +102,8 @@ class IndexCacheTest < IdentityCache::TestCase
102
102
  new_cache_key = "#{NAMESPACE}index:Item:title:#{cache_hash(@record.title)}"
103
103
  IdentityCache.cache.write(new_cache_key, [])
104
104
  @record.save!
105
- assert_equal nil, IdentityCache.cache.read(@cache_key)
106
- assert_equal nil, IdentityCache.cache.read(new_cache_key)
105
+ assert_equal IdentityCache::DELETED, backend.read(@cache_key)
106
+ assert_equal IdentityCache::DELETED, backend.read(new_cache_key)
107
107
  end
108
108
 
109
109
  def test_non_unique_index_expired_by_destroying_record
@@ -111,7 +111,7 @@ class IndexCacheTest < IdentityCache::TestCase
111
111
  @record.save!
112
112
  IdentityCache.cache.write(@cache_key, [@record.id])
113
113
  @record.destroy
114
- assert_equal nil, IdentityCache.cache.read(@cache_key)
114
+ assert_equal IdentityCache::DELETED, backend.read(@cache_key)
115
115
  end
116
116
 
117
117
  def test_set_table_name_cache_fetch
@@ -119,6 +119,6 @@ class IndexCacheTest < IdentityCache::TestCase
119
119
  Item.table_name = 'items2'
120
120
  @record.save!
121
121
  assert_equal [@record], Item.fetch_by_title('bob')
122
- assert_equal [@record.id], IdentityCache.cache.read(@cache_key)
122
+ assert_equal [@record.id], backend.read(@cache_key)
123
123
  end
124
124
  end
@@ -1,95 +1,91 @@
1
1
  require "test_helper"
2
2
 
3
3
  class MemoizedCacheProxyTest < IdentityCache::TestCase
4
- def setup
5
- super
6
- @backend = IdentityCache.cache.cache_backend
7
- end
8
-
9
4
  def test_changing_default_cache
10
5
  IdentityCache.cache_backend = ActiveSupport::Cache::MemoryStore.new
11
6
  IdentityCache.cache.write('foo', 'bar')
12
- assert_equal 'bar', IdentityCache.cache.read('foo')
7
+ assert_raises(NoMethodError) { IdentityCache.cache.fetch('foo') }
13
8
  end
14
9
 
15
- def test_read_should_short_circuit_on_memoized_values
16
- @backend.expects(:read).never
10
+ def test_fetch_should_short_circuit_on_memoized_values
11
+ fetcher.expects(:fetch).never
17
12
 
18
13
  IdentityCache.cache.with_memoization do
19
14
  IdentityCache.cache.write('foo', 'bar')
20
- assert_equal 'bar', IdentityCache.cache.read('foo')
15
+ assert_equal 'bar', IdentityCache.cache.fetch('foo')
21
16
  end
22
17
  end
23
18
 
24
- def test_read_should_short_circuit_on_falsy_memoized_values
25
- @backend.expects(:read).never
19
+ def test_fetch_should_short_circuit_on_falsy_memoized_values
20
+ fetcher.expects(:fetch).never
26
21
 
27
22
  IdentityCache.cache.with_memoization do
28
23
  IdentityCache.cache.write('foo', nil)
29
- assert_equal nil, IdentityCache.cache.read('foo')
24
+ assert_equal nil, IdentityCache.cache.fetch('foo')
30
25
  IdentityCache.cache.write('bar', false)
31
- assert_equal false, IdentityCache.cache.read('bar')
26
+ assert_equal false, IdentityCache.cache.fetch('bar')
32
27
  end
33
28
  end
34
29
 
35
- def test_read_should_try_memcached_on_not_memoized_values
36
- @backend.expects(:read).with('foo').returns('bar')
30
+ def test_fetch_should_try_memcached_on_not_memoized_values
31
+ fetcher.expects(:fetch).with('foo').returns('bar')
37
32
 
38
33
  IdentityCache.cache.with_memoization do
39
- assert_equal 'bar', IdentityCache.cache.read('foo')
34
+ assert_equal 'bar', IdentityCache.cache.fetch('foo')
40
35
  end
41
36
  end
42
37
 
43
38
  def test_write_should_memoize_values
44
- @backend.expects(:read).never
45
- @backend.expects(:write).with('foo', 'bar')
39
+ fetcher.expects(:fetch).never
40
+ fetcher.expects(:write).with('foo', 'bar')
46
41
 
47
42
  IdentityCache.cache.with_memoization do
48
43
  IdentityCache.cache.write('foo', 'bar')
49
- assert_equal 'bar', IdentityCache.cache.read('foo')
44
+ assert_equal 'bar', IdentityCache.cache.fetch('foo')
50
45
  end
51
46
  end
52
47
 
53
- def test_read_should_memoize_values
54
- IdentityCache.cache_backend = backend = ActiveSupport::Cache::MemoryStore.new
48
+ def test_fetch_should_memoize_values
55
49
  backend.write('foo', 'bar')
56
50
 
57
51
  IdentityCache.cache.with_memoization do
58
- assert_equal 'bar', IdentityCache.cache.read('foo')
52
+ assert_equal 'bar', IdentityCache.cache.fetch('foo')
59
53
  backend.delete('foo')
60
- assert_equal 'bar', IdentityCache.cache.read('foo')
54
+ assert_equal 'bar', IdentityCache.cache.fetch('foo')
61
55
  end
62
56
  end
63
57
 
64
- def test_read_multi_should_memoize_values
65
- IdentityCache.cache_backend = backend = ActiveSupport::Cache::MemoryStore.new
58
+ def test_fetch_multi_should_memoize_values
59
+ expected_hash = {'foo' => 'bar', 'fooz' => IdentityCache::CACHED_NIL}
60
+
66
61
  backend.write('foo', 'bar')
67
62
 
68
63
  IdentityCache.cache.with_memoization do
69
- assert_equal({'foo' => 'bar'}, IdentityCache.cache.read_multi('foo', 'fooz'))
64
+ assert_equal(expected_hash, IdentityCache.cache.fetch_multi('foo', 'fooz') {|_| [IdentityCache::CACHED_NIL] })
65
+ assert_equal(expected_hash, IdentityCache.cache.memoized_key_values)
70
66
  backend.delete('foo')
71
67
  backend.write('fooz', 'baz')
72
- assert_equal({'foo' => 'bar'}, IdentityCache.cache.read_multi('foo', 'fooz'))
68
+ assert_equal(expected_hash, IdentityCache.cache.fetch_multi('foo', 'fooz'))
73
69
  end
74
70
  end
75
71
 
76
- def test_read_multi_with_partially_memoized_should_read_missing_keys_from_memcache
72
+ def test_fetch_multi_with_partially_memoized_should_read_missing_keys_from_memcache
77
73
  IdentityCache.cache.write('foo', 'bar')
78
74
  @backend.write('fooz', 'baz')
79
75
 
80
76
  IdentityCache.cache.with_memoization do
81
- assert_equal({'foo' => 'bar', 'fooz' => 'baz'}, IdentityCache.cache.read_multi('foo', 'fooz'))
77
+ assert_equal({'foo' => 'bar', 'fooz' => 'baz'}, IdentityCache.cache.fetch_multi('foo', 'fooz'))
82
78
  end
83
79
  end
84
80
 
85
- def test_read_multi_with_blank_values_should_not_hit_the_cache_engine
86
- @backend.expects(:read_multi).never
81
+ def test_fetch_multi_with_blank_values_should_not_hit_the_cache_engine
82
+ @backend.expects(:fetch_multi).never
87
83
 
88
84
  IdentityCache.cache.with_memoization do
89
85
  IdentityCache.cache.write('foo', [])
90
86
  IdentityCache.cache.write('bar', false)
91
87
  IdentityCache.cache.write('baz', {})
92
- assert_equal({'foo' => [], 'bar' => false, 'baz' => {}}, IdentityCache.cache.read_multi('foo', 'bar', 'baz'))
88
+ assert_equal({'foo' => [], 'bar' => false, 'baz' => {}}, IdentityCache.cache.fetch_multi('foo', 'bar', 'baz'))
93
89
  end
94
90
  end
95
91
 
@@ -97,6 +93,6 @@ class MemoizedCacheProxyTest < IdentityCache::TestCase
97
93
  IdentityCache.cache.with_memoization do
98
94
  IdentityCache.cache.write('foo', 'bar')
99
95
  end
100
- assert_equal 'bar', @backend.read('foo')
96
+ assert_equal 'bar', @backend.fetch('foo')
101
97
  end
102
98
  end
data/test/test_helper.rb CHANGED
@@ -4,19 +4,14 @@ require 'mocha/setup'
4
4
  require 'active_record'
5
5
  require 'helpers/database_connection'
6
6
  require 'helpers/active_record_objects'
7
- require 'spy'
7
+ require 'spy/integration'
8
8
  require 'memcached_store'
9
9
  require 'active_support/cache/memcached_store'
10
10
 
11
11
  require File.dirname(__FILE__) + '/../lib/identity_cache'
12
12
 
13
- if ENV['BOXEN_HOME'].present?
14
- $memcached_port = 21211
15
- $mysql_port = 13306
16
- else
17
- $memcached_port = 11211
18
- $mysql_port = 3306
19
- end
13
+ $memcached_port = 11211
14
+ $mysql_port = 3306
20
15
 
21
16
  DatabaseConnection.setup
22
17
  ActiveSupport::Cache::Store.instrument = true
@@ -34,13 +29,15 @@ end
34
29
 
35
30
  class IdentityCache::TestCase < MiniTest::Unit::TestCase
36
31
  include ActiveRecordObjects
32
+ attr_reader :backend, :fetcher
37
33
 
38
34
  def setup
39
35
  DatabaseConnection.drop_tables
40
36
  DatabaseConnection.create_tables
41
37
 
42
38
  IdentityCache.logger = Logger.new(nil)
43
- IdentityCache.cache_backend = ActiveSupport::Cache::MemcachedStore.new("localhost:#{$memcached_port}")
39
+ IdentityCache.cache_backend = @backend = ActiveSupport::Cache::MemcachedStore.new("localhost:#{$memcached_port}", :support_cas => true)
40
+ @fetcher = IdentityCache.cache.cache_fetcher
44
41
 
45
42
  setup_models
46
43
  end
@@ -129,6 +126,6 @@ class CacheCounter
129
126
  end
130
127
 
131
128
  def call(name, start, finish, message_id, values)
132
- self.log << (values[:keys].try(:join, ', ') || values[:key])
129
+ self.log << "#{name} #{(values[:keys].try(:join, ', ') || values[:key])}"
133
130
  end
134
131
  end
data.tar.gz.sig ADDED
@@ -0,0 +1 @@
1
+ �W�~k�#��V�����ѻ?en `��g�t\˦������̃b�!�;��m�+���:F���".A�v��ex�R��S�$�=�����u�!�-�)Ie�^������[h0˨}.Q���>���]#