torquebox-cache 2.0.0.beta1-java
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.
- data/lib/active_support/cache/torque_box_store.rb +124 -0
- data/lib/cache.rb +420 -0
- data/lib/cache_listener.rb +46 -0
- data/lib/datamapper/dm-infinispan-adapter.rb +128 -0
- data/lib/datamapper/model.rb +185 -0
- data/lib/datamapper/search.rb +145 -0
- data/lib/dm-infinispan-adapter.rb +1 -0
- data/lib/gem_hook.rb +22 -0
- data/lib/torquebox-cache.jar +0 -0
- data/lib/torquebox-cache.rb +13 -0
- data/licenses/lgpl-2.1.txt +502 -0
- data/spec/cache_listener_spec.rb +93 -0
- data/spec/cache_spec.rb +361 -0
- data/spec/dm-infinispan-adapter_spec.rb +375 -0
- data/spec/spec.opts +5 -0
- data/spec/spec_helper.rb +29 -0
- data/spec/torque_box_store_spec.rb +220 -0
- metadata +161 -0
@@ -0,0 +1,375 @@
|
|
1
|
+
#
|
2
|
+
# Copyright 2011 Red Hat, Inc.
|
3
|
+
#
|
4
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
5
|
+
# you may not use this file except in compliance with the License.
|
6
|
+
# You may obtain a copy of the License at
|
7
|
+
#
|
8
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
9
|
+
#
|
10
|
+
# Unless required by applicable law or agreed to in writing, software
|
11
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
12
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
13
|
+
# See the License for the specific language governing permissions and
|
14
|
+
# limitations under the License.
|
15
|
+
#
|
16
|
+
|
17
|
+
require File.dirname(__FILE__) + '/spec_helper'
|
18
|
+
require 'dm-core'
|
19
|
+
require 'datamapper/model'
|
20
|
+
|
21
|
+
describe DataMapper::Adapters::InfinispanAdapter do
|
22
|
+
|
23
|
+
before :all do
|
24
|
+
@adapter = DataMapper.setup(:default, :adapter => 'infinispan')
|
25
|
+
@heffalump_index = File.join( File.dirname(__FILE__), '..', 'rubyobj.Heffalump' )
|
26
|
+
class ::Heffalump
|
27
|
+
include DataMapper::Resource
|
28
|
+
|
29
|
+
property :id, Serial
|
30
|
+
property :color, String
|
31
|
+
property :num_spots, Integer
|
32
|
+
property :striped, Boolean
|
33
|
+
end
|
34
|
+
|
35
|
+
DataMapper.finalize
|
36
|
+
Heffalump.auto_migrate!
|
37
|
+
end
|
38
|
+
|
39
|
+
it "should use the infinispan search manager" do
|
40
|
+
@adapter.search_manager.should_not be_nil
|
41
|
+
end
|
42
|
+
|
43
|
+
after :all do
|
44
|
+
@adapter.stop
|
45
|
+
FileUtils.rm_rf @heffalump_index
|
46
|
+
end
|
47
|
+
|
48
|
+
describe '#auto_migrate!' do
|
49
|
+
it 'should clear the cache' do
|
50
|
+
Heffalump.create(:color => 'magenta')
|
51
|
+
Heffalump.all.size.should == 1
|
52
|
+
Heffalump.auto_migrate!
|
53
|
+
Heffalump.all.size.should == 0
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
describe '#auto_upgrade!' do
|
58
|
+
it 'should not clear the cache' do
|
59
|
+
Heffalump.create(:color => 'magenta')
|
60
|
+
Heffalump.all.size.should == 1
|
61
|
+
Heffalump.auto_upgrade!
|
62
|
+
Heffalump.all.size.should == 1
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
describe '#create' do
|
67
|
+
it 'should not raise any errors' do
|
68
|
+
lambda {
|
69
|
+
Heffalump.create(:color => 'peach')
|
70
|
+
}.should_not raise_error
|
71
|
+
end
|
72
|
+
|
73
|
+
it 'should set the identity field for the resource' do
|
74
|
+
heffalump = Heffalump.new(:color => 'peach')
|
75
|
+
heffalump.id.should be_nil
|
76
|
+
heffalump.save
|
77
|
+
heffalump.id.should_not be_nil
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
81
|
+
describe '#read' do
|
82
|
+
before :all do
|
83
|
+
@heffalump = Heffalump.create(:color => 'brownish hue')
|
84
|
+
end
|
85
|
+
|
86
|
+
it 'should not raise any errors' do
|
87
|
+
lambda {
|
88
|
+
Heffalump.all()
|
89
|
+
}.should_not raise_error
|
90
|
+
end
|
91
|
+
|
92
|
+
it 'should return stuff' do
|
93
|
+
Heffalump.all.should be_include(@heffalump)
|
94
|
+
end
|
95
|
+
end
|
96
|
+
|
97
|
+
describe '#update' do
|
98
|
+
before do
|
99
|
+
@heffalump = Heffalump.create(:color => 'indigo')
|
100
|
+
end
|
101
|
+
|
102
|
+
it 'should not raise any errors' do
|
103
|
+
lambda {
|
104
|
+
@heffalump.color = 'violet'
|
105
|
+
@heffalump.save
|
106
|
+
}.should_not raise_error
|
107
|
+
end
|
108
|
+
|
109
|
+
it 'should not alter the identity field' do
|
110
|
+
id = @heffalump.id
|
111
|
+
@heffalump.color = 'violet'
|
112
|
+
@heffalump.save
|
113
|
+
@heffalump.id.should == id
|
114
|
+
end
|
115
|
+
|
116
|
+
it 'should update altered fields' do
|
117
|
+
@heffalump.color = 'violet'
|
118
|
+
@heffalump.save
|
119
|
+
Heffalump.get(*@heffalump.key).color.should == 'violet'
|
120
|
+
end
|
121
|
+
|
122
|
+
it 'should not alter other fields' do
|
123
|
+
color = @heffalump.color
|
124
|
+
@heffalump.num_spots = 3
|
125
|
+
@heffalump.save
|
126
|
+
Heffalump.get(*@heffalump.key).color.should == color
|
127
|
+
end
|
128
|
+
end
|
129
|
+
|
130
|
+
describe '#delete' do
|
131
|
+
before do
|
132
|
+
@heffalump = Heffalump.create(:color => 'forest green')
|
133
|
+
end
|
134
|
+
|
135
|
+
it 'should not raise any errors' do
|
136
|
+
lambda {
|
137
|
+
@heffalump.destroy
|
138
|
+
}.should_not raise_error
|
139
|
+
end
|
140
|
+
|
141
|
+
it 'should delete the requested resource' do
|
142
|
+
id = @heffalump.id
|
143
|
+
@heffalump.destroy
|
144
|
+
Heffalump.get(id).should be_nil
|
145
|
+
end
|
146
|
+
end
|
147
|
+
|
148
|
+
describe 'query matching' do
|
149
|
+
before :all do
|
150
|
+
Heffalump.auto_migrate!
|
151
|
+
@red = Heffalump.create(:color => 'red')
|
152
|
+
@two = Heffalump.create(:num_spots => 2)
|
153
|
+
@five = Heffalump.create(:num_spots => 5)
|
154
|
+
end
|
155
|
+
|
156
|
+
describe 'conditions' do
|
157
|
+
describe 'eql' do
|
158
|
+
it 'should be able to search for objects included in an inclusive range of values' do
|
159
|
+
Heffalump.all(:num_spots => 1..5).should be_include(@five)
|
160
|
+
end
|
161
|
+
|
162
|
+
it 'should be able to search for objects included in an exclusive range of values' do
|
163
|
+
Heffalump.all(:num_spots => 1...6).should be_include(@five)
|
164
|
+
end
|
165
|
+
|
166
|
+
it 'should not be able to search for values not included in an inclusive range of values' do
|
167
|
+
Heffalump.all(:num_spots => 1..4).should_not be_include(@five)
|
168
|
+
end
|
169
|
+
|
170
|
+
it 'should not be able to search for values not included in an exclusive range of values' do
|
171
|
+
Heffalump.all(:num_spots => 1...5).should_not be_include(@five)
|
172
|
+
end
|
173
|
+
end
|
174
|
+
|
175
|
+
describe 'not' do
|
176
|
+
it 'should be able to search for objects with not equal value' do
|
177
|
+
Heffalump.all(:color.not => 'red').should_not be_include(@red)
|
178
|
+
end
|
179
|
+
|
180
|
+
it 'should include objects that are not like the value' do
|
181
|
+
Heffalump.all(:color.not => 'black').should be_include(@red)
|
182
|
+
end
|
183
|
+
|
184
|
+
it 'should be able to search for objects with not nil value' do
|
185
|
+
Heffalump.all(:color.not => nil).should be_include(@red)
|
186
|
+
end
|
187
|
+
|
188
|
+
it 'should not include objects with a nil value' do
|
189
|
+
Heffalump.all(:color.not => nil).should_not be_include(@two)
|
190
|
+
end
|
191
|
+
|
192
|
+
it 'should be able to search for object with a nil value using required properties' do
|
193
|
+
Heffalump.all(:id.not => nil).should == [ @red, @two, @five ]
|
194
|
+
end
|
195
|
+
|
196
|
+
it 'should be able to search for objects not in an empty list (match all)' do
|
197
|
+
Heffalump.all(:color.not => []).should == [ @red, @two, @five ]
|
198
|
+
end
|
199
|
+
|
200
|
+
it 'should be able to search for objects in an empty list and another OR condition (match none on the empty list)' do
|
201
|
+
Heffalump.all(
|
202
|
+
:conditions => DataMapper::Query::Conditions::Operation.new(
|
203
|
+
:or,
|
204
|
+
DataMapper::Query::Conditions::Comparison.new(:in, Heffalump.properties[:color], []),
|
205
|
+
DataMapper::Query::Conditions::Comparison.new(:in, Heffalump.properties[:num_spots], [5])
|
206
|
+
)
|
207
|
+
).should == [ @five ]
|
208
|
+
end
|
209
|
+
|
210
|
+
it 'should be able to search for objects not included in an array of values' do
|
211
|
+
Heffalump.all(:num_spots.not => [ 1, 3, 5, 7 ]).should be_include(@two)
|
212
|
+
end
|
213
|
+
|
214
|
+
it 'should be able to search for objects not included in an array of values' do
|
215
|
+
Heffalump.all(:num_spots.not => [ 1, 3, 5, 7 ]).should_not be_include(@five)
|
216
|
+
end
|
217
|
+
|
218
|
+
it 'should be able to search for objects not included in an inclusive range of values' do
|
219
|
+
Heffalump.all(:num_spots.not => 1..4).should be_include(@five)
|
220
|
+
end
|
221
|
+
|
222
|
+
it 'should be able to search for objects not included in an exclusive range of values' do
|
223
|
+
Heffalump.all(:num_spots.not => 1...5).should be_include(@five)
|
224
|
+
end
|
225
|
+
|
226
|
+
it 'should not be able to search for values not included in an inclusive range of values' do
|
227
|
+
Heffalump.all(:num_spots.not => 1..5).should_not be_include(@five)
|
228
|
+
end
|
229
|
+
|
230
|
+
it 'should not be able to search for values not included in an exclusive range of values' do
|
231
|
+
Heffalump.all(:num_spots.not => 1...6).should_not be_include(@five)
|
232
|
+
end
|
233
|
+
end
|
234
|
+
|
235
|
+
describe 'like' do
|
236
|
+
it 'should be able to search for objects that match value' do
|
237
|
+
Heffalump.all(:color.like => '%ed').should be_include(@red)
|
238
|
+
end
|
239
|
+
|
240
|
+
it 'should not search for objects that do not match the value' do
|
241
|
+
Heffalump.all(:color.like => '%blak%').should_not be_include(@red)
|
242
|
+
end
|
243
|
+
end
|
244
|
+
|
245
|
+
describe 'regexp' do
|
246
|
+
before do
|
247
|
+
if (defined?(DataMapper::Adapters::SqliteAdapter) && @adapter.kind_of?(DataMapper::Adapters::SqliteAdapter) ||
|
248
|
+
defined?(DataMapper::Adapters::SqlserverAdapter) && @adapter.kind_of?(DataMapper::Adapters::SqlserverAdapter))
|
249
|
+
pending 'delegate regexp matches to same system that the InMemory and YAML adapters use'
|
250
|
+
end
|
251
|
+
end
|
252
|
+
|
253
|
+
it 'should be able to search for objects that match value' do
|
254
|
+
Heffalump.all(:color => /ed/).should be_include(@red)
|
255
|
+
end
|
256
|
+
|
257
|
+
it 'should not be able to search for objects that do not match the value' do
|
258
|
+
Heffalump.all(:color => /blak/).should_not be_include(@red)
|
259
|
+
end
|
260
|
+
|
261
|
+
it 'should be able to do a negated search for objects that match value' do
|
262
|
+
Heffalump.all(:color.not => /blak/).should be_include(@red)
|
263
|
+
end
|
264
|
+
|
265
|
+
it 'should not be able to do a negated search for objects that do not match value' do
|
266
|
+
Heffalump.all(:color.not => /ed/).should_not be_include(@red)
|
267
|
+
end
|
268
|
+
|
269
|
+
end
|
270
|
+
|
271
|
+
describe 'gt' do
|
272
|
+
it 'should be able to search for objects with value greater than' do
|
273
|
+
Heffalump.all(:num_spots.gt => 1).should be_include(@two)
|
274
|
+
end
|
275
|
+
|
276
|
+
it 'should not find objects with a value less than' do
|
277
|
+
Heffalump.all(:num_spots.gt => 3).should_not be_include(@two)
|
278
|
+
end
|
279
|
+
end
|
280
|
+
|
281
|
+
describe 'gte' do
|
282
|
+
it 'should be able to search for objects with value greater than' do
|
283
|
+
Heffalump.all(:num_spots.gte => 1).should be_include(@two)
|
284
|
+
end
|
285
|
+
|
286
|
+
it 'should be able to search for objects with values equal to' do
|
287
|
+
Heffalump.all(:num_spots.gte => 2).should be_include(@two)
|
288
|
+
end
|
289
|
+
|
290
|
+
it 'should not find objects with a value less than' do
|
291
|
+
Heffalump.all(:num_spots.gte => 3).should_not be_include(@two)
|
292
|
+
end
|
293
|
+
end
|
294
|
+
|
295
|
+
describe 'lt' do
|
296
|
+
it 'should be able to search for objects with value less than' do
|
297
|
+
Heffalump.all(:num_spots.lt => 3).should be_include(@two)
|
298
|
+
end
|
299
|
+
|
300
|
+
it 'should not find objects with a value less than' do
|
301
|
+
Heffalump.all(:num_spots.gt => 2).should_not be_include(@two)
|
302
|
+
end
|
303
|
+
end
|
304
|
+
|
305
|
+
describe 'lte' do
|
306
|
+
it 'should be able to search for objects with value less than' do
|
307
|
+
Heffalump.all(:num_spots.lte => 3).should be_include(@two)
|
308
|
+
end
|
309
|
+
|
310
|
+
it 'should be able to search for objects with values equal to' do
|
311
|
+
Heffalump.all(:num_spots.lte => 2).should be_include(@two)
|
312
|
+
end
|
313
|
+
|
314
|
+
it 'should not find objects with a value less than' do
|
315
|
+
Heffalump.all(:num_spots.lte => 1).should_not be_include(@two)
|
316
|
+
end
|
317
|
+
end
|
318
|
+
end
|
319
|
+
|
320
|
+
describe 'limits' do
|
321
|
+
it 'should be able to limit the objects' do
|
322
|
+
Heffalump.all(:limit => 2).length.should == 2
|
323
|
+
end
|
324
|
+
end
|
325
|
+
end
|
326
|
+
|
327
|
+
describe "with persistence" do
|
328
|
+
before :all do
|
329
|
+
@configured_dir = File.join( File.dirname(__FILE__), '..', random_string + "-dm-infinispan-adapter.cache" )
|
330
|
+
@default_dir = File.join(File.dirname(__FILE__), '..', 'Infinispan-FileCacheStore')
|
331
|
+
@snuffy = File.join( File.dirname(__FILE__), '..', 'rubyobj.Snuffleupagus' )
|
332
|
+
FileUtils.mkdir( @configured_dir )
|
333
|
+
class Snuffleupagus
|
334
|
+
include DataMapper::Resource
|
335
|
+
property :id, Serial
|
336
|
+
property :birthday, Date
|
337
|
+
end
|
338
|
+
Snuffleupagus.configure_index!
|
339
|
+
end
|
340
|
+
|
341
|
+
after :all do
|
342
|
+
#FileUtils.rm_rf( @configured_dir )
|
343
|
+
#FileUtils.rm_rf( @default_dir )
|
344
|
+
FileUtils.rm_rf( @snuffy )
|
345
|
+
end
|
346
|
+
|
347
|
+
it "should store data in a configured directory" do
|
348
|
+
adapter = DataMapper.setup(:dminfinispanadapterconfigured, :adapter => 'infinispan', :persist => @configured_dir.to_s)
|
349
|
+
snuffy = Snuffleupagus.create(:birthday=>Date.today)
|
350
|
+
File.exist?("#{@configured_dir.to_s}/dminfinispanadapterconfigured").should be_true
|
351
|
+
snuffy.should_not be_nil
|
352
|
+
adapter.stop
|
353
|
+
end
|
354
|
+
|
355
|
+
it "should store data in a default directory" do
|
356
|
+
adapter = DataMapper.setup(:dminfinispanadapterdefault, :adapter => 'infinispan', :persist=>true)
|
357
|
+
snuffy = Snuffleupagus.create(:birthday=>Date.today)
|
358
|
+
File.exist?( @default_dir ).should be_true
|
359
|
+
snuffy.should_not be_nil
|
360
|
+
snuffy.id.should_not be_nil
|
361
|
+
adapter.stop
|
362
|
+
end
|
363
|
+
|
364
|
+
it "should store dates" do
|
365
|
+
adapter = DataMapper.setup(:default, :adapter => 'infinispan', :persist=>true)
|
366
|
+
snuffy = Snuffleupagus.create(:birthday => Date.today)
|
367
|
+
snuffy.should_not be_nil
|
368
|
+
snuffy.getBirthday.should_not be_nil
|
369
|
+
adapter.stop
|
370
|
+
end
|
371
|
+
|
372
|
+
end
|
373
|
+
end
|
374
|
+
|
375
|
+
|
data/spec/spec.opts
ADDED
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,29 @@
|
|
1
|
+
#
|
2
|
+
# Copyright 2011 Red Hat, Inc.
|
3
|
+
#
|
4
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
5
|
+
# you may not use this file except in compliance with the License.
|
6
|
+
# You may obtain a copy of the License at
|
7
|
+
#
|
8
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
9
|
+
#
|
10
|
+
# Unless required by applicable law or agreed to in writing, software
|
11
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
12
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
13
|
+
# See the License for the specific language governing permissions and
|
14
|
+
# limitations under the License.
|
15
|
+
#
|
16
|
+
|
17
|
+
require 'dm-core/spec/shared/adapter_spec'
|
18
|
+
require 'dm-core/spec/lib/pending_helpers'
|
19
|
+
require 'datamapper/dm-infinispan-adapter'
|
20
|
+
require 'cache'
|
21
|
+
|
22
|
+
Spec::Runner.configure do |config|
|
23
|
+
config.include(DataMapper::Spec::PendingHelpers)
|
24
|
+
end
|
25
|
+
|
26
|
+
def random_string( length = 20 )
|
27
|
+
chars = ('a'..'z').to_a + ('A'..'Z').to_a
|
28
|
+
dir_string = (0...length).collect { chars[Kernel.rand(chars.length)] }.join
|
29
|
+
end
|
@@ -0,0 +1,220 @@
|
|
1
|
+
require 'active_support/cache/torque_box_store'
|
2
|
+
require 'logger'
|
3
|
+
|
4
|
+
java_import org.infinispan.config.Configuration::CacheMode
|
5
|
+
include ActiveSupport::Cache
|
6
|
+
|
7
|
+
TORQUEBOX_APP_NAME = 'active-support-unit-test'
|
8
|
+
|
9
|
+
describe ActiveSupport::Cache::TorqueBoxStore do
|
10
|
+
|
11
|
+
before(:each) do
|
12
|
+
TorqueBox::ServiceRegistry.service_registry = nil
|
13
|
+
@cache = ActiveSupport::Cache::TorqueBoxStore.new()
|
14
|
+
end
|
15
|
+
|
16
|
+
describe "basics" do
|
17
|
+
|
18
|
+
it "should write and read a string" do
|
19
|
+
@cache.write("key", "value").should be_true
|
20
|
+
@cache.read("key").should == "value"
|
21
|
+
end
|
22
|
+
|
23
|
+
it "should write and read a number" do
|
24
|
+
@cache.write("key", 42).should be_true
|
25
|
+
@cache.read("key").should == 42
|
26
|
+
end
|
27
|
+
|
28
|
+
it "should exist after writing" do
|
29
|
+
@cache.write("key", 42).should be_true
|
30
|
+
@cache.exist?("key").should be_true
|
31
|
+
end
|
32
|
+
|
33
|
+
it "should be gone after deleting" do
|
34
|
+
@cache.write("key", 42).should be_true
|
35
|
+
@cache.read("key").should == 42
|
36
|
+
@cache.delete("key").should be_true
|
37
|
+
@cache.read("key").should be_nil
|
38
|
+
end
|
39
|
+
|
40
|
+
it "should overwrite an existing key" do
|
41
|
+
@cache.write("key", 42).should be_true
|
42
|
+
@cache.read("key").should == 42
|
43
|
+
@cache.write("key", 44).should be_true
|
44
|
+
@cache.read("key").should == 44
|
45
|
+
end
|
46
|
+
|
47
|
+
end
|
48
|
+
|
49
|
+
describe "options" do
|
50
|
+
|
51
|
+
it "should be expirable" do
|
52
|
+
@cache.write("key", 42, :expires_in => 1.second).should be_true
|
53
|
+
@cache.read("key").should == 42
|
54
|
+
sleep(1.1)
|
55
|
+
@cache.read("key").should be_nil
|
56
|
+
end
|
57
|
+
|
58
|
+
it "should optionally not overwrite an existing key" do
|
59
|
+
@cache.write("key", 42).should be_true
|
60
|
+
@cache.read("key").should == 42
|
61
|
+
@cache.write("key", 44, :unless_exist => true).should be_true
|
62
|
+
@cache.read("key").should == 42
|
63
|
+
end
|
64
|
+
|
65
|
+
it "should merge initialized options" do
|
66
|
+
@cache = ActiveSupport::Cache::TorqueBoxStore.new(:expires_in => 1.second)
|
67
|
+
@cache.write("key", 42).should be_true
|
68
|
+
@cache.read("key").should == 42
|
69
|
+
sleep(1.1)
|
70
|
+
@cache.read("key").should be_nil
|
71
|
+
end
|
72
|
+
|
73
|
+
end
|
74
|
+
|
75
|
+
describe "fetching" do
|
76
|
+
|
77
|
+
it "should fetch existing keys" do
|
78
|
+
@cache.write("today", "Monday")
|
79
|
+
@cache.fetch("today").should == "Monday"
|
80
|
+
end
|
81
|
+
|
82
|
+
it "should fetch block values for missing keys" do
|
83
|
+
@cache.fetch("city").should be_nil
|
84
|
+
@cache.fetch("city") {
|
85
|
+
"Duckburgh"
|
86
|
+
}.should == "Duckburgh"
|
87
|
+
@cache.fetch("city").should == "Duckburgh"
|
88
|
+
end
|
89
|
+
|
90
|
+
it "should fetch block values when forced" do
|
91
|
+
@cache.write("today", "Monday")
|
92
|
+
@cache.fetch("today").should == "Monday"
|
93
|
+
@cache.fetch("today", :force => true) { "Tuesday" }.should == "Tuesday"
|
94
|
+
end
|
95
|
+
|
96
|
+
it "should support :race_condition_ttl" do
|
97
|
+
database = mock('database')
|
98
|
+
fetch_options = { :expires_in => 0.1.seconds, :race_condition_ttl => 30.seconds }
|
99
|
+
# First fetch looks up from database and populates
|
100
|
+
database.should_receive(:town).and_return("Pantsville")
|
101
|
+
@cache.fetch("town", fetch_options) {
|
102
|
+
database.town
|
103
|
+
}.should == "Pantsville"
|
104
|
+
# Sleep until the entry is expired
|
105
|
+
sleep(0.2)
|
106
|
+
# Create a set of CountDownLatches to test :race_condition_ttl
|
107
|
+
# without relying on sleep calls
|
108
|
+
read_latch = java.util.concurrent.CountDownLatch.new(1)
|
109
|
+
write_latch = java.util.concurrent.CountDownLatch.new(1)
|
110
|
+
# Read the cache from two threads but only one should hit our database
|
111
|
+
database.should_receive(:town).once.and_return {
|
112
|
+
# Trigger the read latch so the other thread can read the cached value
|
113
|
+
read_latch.count_down
|
114
|
+
write_latch.await(15, java.util.concurrent.TimeUnit::SECONDS)
|
115
|
+
"NoPantsville"
|
116
|
+
}
|
117
|
+
other_thread = Thread.new {
|
118
|
+
read_latch.await(15, java.util.concurrent.TimeUnit::SECONDS)
|
119
|
+
@cache.fetch("town", fetch_options) {
|
120
|
+
database.town
|
121
|
+
}.should == "Pantsville"
|
122
|
+
# Trigger the write latch to update the cached value
|
123
|
+
write_latch.count_down
|
124
|
+
}
|
125
|
+
@cache.fetch("town", fetch_options) {
|
126
|
+
database.town
|
127
|
+
}.should == "NoPantsville"
|
128
|
+
other_thread.join
|
129
|
+
@cache.read("town").should == "NoPantsville"
|
130
|
+
end
|
131
|
+
|
132
|
+
end
|
133
|
+
|
134
|
+
describe "multiples" do
|
135
|
+
|
136
|
+
before(:each) do
|
137
|
+
@cache.write("john", "guitar")
|
138
|
+
@cache.write("paul", "bass")
|
139
|
+
@cache.write("george", "lead")
|
140
|
+
@cache.write("ringo", "drums")
|
141
|
+
end
|
142
|
+
|
143
|
+
it "should delete by regexp" do
|
144
|
+
@cache.delete_matched /g/
|
145
|
+
@cache.read("george").should be_nil
|
146
|
+
@cache.read("ringo").should be_nil
|
147
|
+
@cache.read("john").should == "guitar"
|
148
|
+
@cache.read("paul").should == "bass"
|
149
|
+
end
|
150
|
+
|
151
|
+
it "should clear all entries" do
|
152
|
+
@cache.clear
|
153
|
+
@cache.read("george").should be_nil
|
154
|
+
@cache.read("ringo").should be_nil
|
155
|
+
@cache.read("john").should be_nil
|
156
|
+
@cache.read("paul").should be_nil
|
157
|
+
end
|
158
|
+
|
159
|
+
it "should cleanup expired entries" do
|
160
|
+
@cache.write("jimi", "guitar", :expires_in => 1.second)
|
161
|
+
@cache.exist?("jimi").should be_true
|
162
|
+
sleep(1.1)
|
163
|
+
@cache.cleanup
|
164
|
+
@cache.exist?("jimi").should be_false
|
165
|
+
@cache.exist?("ringo").should be_true
|
166
|
+
end
|
167
|
+
|
168
|
+
it "should read multiple values" do
|
169
|
+
@cache.read_multi("john", "paul").should == {"john" => "guitar", "paul" => "bass"}
|
170
|
+
end
|
171
|
+
|
172
|
+
end
|
173
|
+
|
174
|
+
describe "advanced" do
|
175
|
+
|
176
|
+
it "should support incrementation" do
|
177
|
+
@cache.write("key", 42).should be_true
|
178
|
+
@cache.read("key").should == 42
|
179
|
+
@cache.increment("key").should == 43
|
180
|
+
@cache.read("key").should == 43
|
181
|
+
end
|
182
|
+
|
183
|
+
it "should support decrementation" do
|
184
|
+
@cache.write("key", 42).should be_true
|
185
|
+
@cache.read("key").should == 42
|
186
|
+
@cache.decrement("key").should == 41
|
187
|
+
@cache.read("key").should == 41
|
188
|
+
end
|
189
|
+
|
190
|
+
end
|
191
|
+
|
192
|
+
describe "clustering" do
|
193
|
+
|
194
|
+
it "should default to invalidation mode" do
|
195
|
+
@cache.clustering_mode.should == CacheMode::INVALIDATION_ASYNC
|
196
|
+
TorqueBoxStore.new(:mode => :unknown).clustering_mode.should == CacheMode::INVALIDATION_ASYNC
|
197
|
+
end
|
198
|
+
|
199
|
+
[:repl, :dist, :invalidation].each do |mode|
|
200
|
+
it "should be configurable in #{mode} mode" do
|
201
|
+
TorqueBoxStore.new(:mode => mode).clustering_mode.to_s.should == "#{mode.to_s.upcase}_ASYNC"
|
202
|
+
TorqueBoxStore.new(:mode => mode, :sync => true).clustering_mode.to_s.should == "#{mode.to_s.upcase}_SYNC"
|
203
|
+
end
|
204
|
+
end
|
205
|
+
|
206
|
+
it "should support replicated mode" do
|
207
|
+
[:r, :repl, :replicated, :replication].each do |mode|
|
208
|
+
TorqueBoxStore.new(:mode => mode).clustering_mode.should be_replicated
|
209
|
+
end
|
210
|
+
end
|
211
|
+
|
212
|
+
it "should support distributed mode" do
|
213
|
+
[:d, :dist, :distributed, :distribution].each do |mode|
|
214
|
+
TorqueBoxStore.new(:mode => mode).clustering_mode.should be_distributed
|
215
|
+
end
|
216
|
+
end
|
217
|
+
|
218
|
+
end
|
219
|
+
|
220
|
+
end
|