identity_cache 0.1.0 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -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���>���]#