myobie-memcache-client 1.5.0.3
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/History.txt +85 -0
- data/README.txt +54 -0
- data/Rakefile +24 -0
- data/ext/crc32/crc32.c +28 -0
- data/ext/crc32/extconf.rb +5 -0
- data/lib/memcache.rb +791 -0
- data/lib/memcache_util.rb +90 -0
- data/test/test_mem_cache.rb +744 -0
- metadata +61 -0
@@ -0,0 +1,90 @@
|
|
1
|
+
##
|
2
|
+
# A utility wrapper around the MemCache client to simplify cache access. All
|
3
|
+
# methods silently ignore MemCache errors.
|
4
|
+
|
5
|
+
module Cache
|
6
|
+
|
7
|
+
##
|
8
|
+
# Returns the object at +key+ from the cache if successful, or nil if either
|
9
|
+
# the object is not in the cache or if there was an error attermpting to
|
10
|
+
# access the cache.
|
11
|
+
#
|
12
|
+
# If there is a cache miss and a block is given the result of the block will
|
13
|
+
# be stored in the cache with optional +expiry+, using the +add+ method rather
|
14
|
+
# than +set+.
|
15
|
+
|
16
|
+
def self.get(key, expiry = 0)
|
17
|
+
start_time = Time.now
|
18
|
+
value = CACHE.get key
|
19
|
+
elapsed = Time.now - start_time
|
20
|
+
ActiveRecord::Base.logger.debug('MemCache Get (%0.6f) %s' % [elapsed, key])
|
21
|
+
if value.nil? and block_given? then
|
22
|
+
value = yield
|
23
|
+
add key, value, expiry
|
24
|
+
end
|
25
|
+
value
|
26
|
+
rescue MemCache::MemCacheError => err
|
27
|
+
ActiveRecord::Base.logger.debug "MemCache Error: #{err.message}"
|
28
|
+
if block_given? then
|
29
|
+
value = yield
|
30
|
+
put key, value, expiry
|
31
|
+
end
|
32
|
+
value
|
33
|
+
end
|
34
|
+
|
35
|
+
##
|
36
|
+
# Sets +value+ in the cache at +key+, with an optional +expiry+ time in
|
37
|
+
# seconds.
|
38
|
+
|
39
|
+
def self.put(key, value, expiry = 0)
|
40
|
+
start_time = Time.now
|
41
|
+
CACHE.set key, value, expiry
|
42
|
+
elapsed = Time.now - start_time
|
43
|
+
ActiveRecord::Base.logger.debug('MemCache Set (%0.6f) %s' % [elapsed, key])
|
44
|
+
value
|
45
|
+
rescue MemCache::MemCacheError => err
|
46
|
+
ActiveRecord::Base.logger.debug "MemCache Error: #{err.message}"
|
47
|
+
nil
|
48
|
+
end
|
49
|
+
|
50
|
+
##
|
51
|
+
# Sets +value+ in the cache at +key+, with an optional +expiry+ time in
|
52
|
+
# seconds. If +key+ already exists in cache, returns nil.
|
53
|
+
|
54
|
+
def self.add(key, value, expiry = 0)
|
55
|
+
start_time = Time.now
|
56
|
+
response = CACHE.add key, value, expiry
|
57
|
+
elapsed = Time.now - start_time
|
58
|
+
ActiveRecord::Base.logger.debug('MemCache Add (%0.6f) %s' % [elapsed, key])
|
59
|
+
(response == "STORED\r\n") ? value : nil
|
60
|
+
rescue MemCache::MemCacheError => err
|
61
|
+
ActiveRecord::Base.logger.debug "MemCache Error: #{err.message}"
|
62
|
+
nil
|
63
|
+
end
|
64
|
+
|
65
|
+
##
|
66
|
+
# Deletes +key+ from the cache in +delay+ seconds.
|
67
|
+
|
68
|
+
def self.delete(key, delay = nil)
|
69
|
+
start_time = Time.now
|
70
|
+
CACHE.delete key, delay
|
71
|
+
elapsed = Time.now - start_time
|
72
|
+
ActiveRecord::Base.logger.debug('MemCache Delete (%0.6f) %s' %
|
73
|
+
[elapsed, key])
|
74
|
+
nil
|
75
|
+
rescue MemCache::MemCacheError => err
|
76
|
+
ActiveRecord::Base.logger.debug "MemCache Error: #{err.message}"
|
77
|
+
nil
|
78
|
+
end
|
79
|
+
|
80
|
+
##
|
81
|
+
# Resets all connections to MemCache servers.
|
82
|
+
|
83
|
+
def self.reset
|
84
|
+
CACHE.reset
|
85
|
+
ActiveRecord::Base.logger.debug 'MemCache Connections Reset'
|
86
|
+
nil
|
87
|
+
end
|
88
|
+
|
89
|
+
end
|
90
|
+
|
@@ -0,0 +1,744 @@
|
|
1
|
+
require 'stringio'
|
2
|
+
require 'test/unit'
|
3
|
+
require 'rubygems'
|
4
|
+
require 'test/zentest_assertions'
|
5
|
+
|
6
|
+
$TESTING = true
|
7
|
+
|
8
|
+
require 'memcache'
|
9
|
+
|
10
|
+
class MemCache
|
11
|
+
|
12
|
+
attr_writer :namespace
|
13
|
+
|
14
|
+
end
|
15
|
+
|
16
|
+
class FakeSocket
|
17
|
+
|
18
|
+
attr_reader :written, :data
|
19
|
+
|
20
|
+
def initialize
|
21
|
+
@written = StringIO.new
|
22
|
+
@data = StringIO.new
|
23
|
+
end
|
24
|
+
|
25
|
+
def write(data)
|
26
|
+
@written.write data
|
27
|
+
end
|
28
|
+
|
29
|
+
def gets
|
30
|
+
@data.gets
|
31
|
+
end
|
32
|
+
|
33
|
+
def read(arg)
|
34
|
+
@data.read arg
|
35
|
+
end
|
36
|
+
|
37
|
+
end
|
38
|
+
|
39
|
+
class FakeServer
|
40
|
+
|
41
|
+
attr_reader :host, :port, :socket
|
42
|
+
|
43
|
+
def initialize(socket = nil)
|
44
|
+
@closed = false
|
45
|
+
@host = 'example.com'
|
46
|
+
@port = 11211
|
47
|
+
@socket = socket || FakeSocket.new
|
48
|
+
end
|
49
|
+
|
50
|
+
def close
|
51
|
+
@closed = true
|
52
|
+
end
|
53
|
+
|
54
|
+
def alive?
|
55
|
+
!@closed
|
56
|
+
end
|
57
|
+
|
58
|
+
end
|
59
|
+
|
60
|
+
class TestMemCache < Test::Unit::TestCase
|
61
|
+
|
62
|
+
def setup
|
63
|
+
@cache = MemCache.new 'localhost:1', :namespace => 'my_namespace'
|
64
|
+
end
|
65
|
+
|
66
|
+
def test_cache_get
|
67
|
+
server = util_setup_fake_server
|
68
|
+
|
69
|
+
assert_equal "\004\b\"\0170123456789",
|
70
|
+
@cache.cache_get(server, 'my_namespace:key')
|
71
|
+
|
72
|
+
assert_equal "get my_namespace:key\r\n",
|
73
|
+
server.socket.written.string
|
74
|
+
end
|
75
|
+
|
76
|
+
def test_cache_get_EOF
|
77
|
+
server = util_setup_fake_server
|
78
|
+
server.socket.data.string = ''
|
79
|
+
|
80
|
+
e = assert_raise MemCache::MemCacheError do
|
81
|
+
@cache.cache_get server, 'my_namespace:key'
|
82
|
+
end
|
83
|
+
|
84
|
+
assert_equal "lost connection to example.com:11211", e.message
|
85
|
+
end
|
86
|
+
|
87
|
+
def test_cache_get_bad_state
|
88
|
+
server = FakeServer.new
|
89
|
+
server.socket.data.write "bogus response\r\n"
|
90
|
+
server.socket.data.rewind
|
91
|
+
|
92
|
+
@cache.servers = []
|
93
|
+
@cache.servers << server
|
94
|
+
|
95
|
+
e = assert_raise MemCache::MemCacheError do
|
96
|
+
@cache.cache_get(server, 'my_namespace:key')
|
97
|
+
end
|
98
|
+
|
99
|
+
assert_equal "unexpected response \"bogus response\\r\\n\"", e.message
|
100
|
+
|
101
|
+
deny server.alive?
|
102
|
+
|
103
|
+
assert_equal "get my_namespace:key\r\n",
|
104
|
+
server.socket.written.string
|
105
|
+
end
|
106
|
+
|
107
|
+
def test_cache_get_miss
|
108
|
+
socket = FakeSocket.new
|
109
|
+
socket.data.write "END\r\n"
|
110
|
+
socket.data.rewind
|
111
|
+
server = FakeServer.new socket
|
112
|
+
|
113
|
+
assert_equal nil, @cache.cache_get(server, 'my_namespace:key')
|
114
|
+
|
115
|
+
assert_equal "get my_namespace:key\r\n",
|
116
|
+
socket.written.string
|
117
|
+
end
|
118
|
+
|
119
|
+
def test_cache_get_multi
|
120
|
+
server = util_setup_fake_server
|
121
|
+
server.socket.data.write "VALUE foo 0 7\r\n"
|
122
|
+
server.socket.data.write "\004\b\"\bfoo\r\n"
|
123
|
+
server.socket.data.write "VALUE bar 0 7\r\n"
|
124
|
+
server.socket.data.write "\004\b\"\bbar\r\n"
|
125
|
+
server.socket.data.write "END\r\n"
|
126
|
+
server.socket.data.rewind
|
127
|
+
|
128
|
+
result = @cache.cache_get_multi server, 'foo bar baz'
|
129
|
+
|
130
|
+
assert_equal 2, result.length
|
131
|
+
assert_equal "\004\b\"\bfoo", result['foo']
|
132
|
+
assert_equal "\004\b\"\bbar", result['bar']
|
133
|
+
end
|
134
|
+
|
135
|
+
def test_cache_get_multi_EOF
|
136
|
+
server = util_setup_fake_server
|
137
|
+
server.socket.data.string = ''
|
138
|
+
|
139
|
+
e = assert_raise MemCache::MemCacheError do
|
140
|
+
@cache.cache_get_multi server, 'my_namespace:key'
|
141
|
+
end
|
142
|
+
|
143
|
+
assert_equal "lost connection to example.com:11211", e.message
|
144
|
+
end
|
145
|
+
|
146
|
+
def test_cache_get_multi_bad_state
|
147
|
+
server = FakeServer.new
|
148
|
+
server.socket.data.write "bogus response\r\n"
|
149
|
+
server.socket.data.rewind
|
150
|
+
|
151
|
+
@cache.servers = []
|
152
|
+
@cache.servers << server
|
153
|
+
|
154
|
+
e = assert_raise MemCache::MemCacheError do
|
155
|
+
@cache.cache_get_multi server, 'my_namespace:key'
|
156
|
+
end
|
157
|
+
|
158
|
+
assert_equal "unexpected response \"bogus response\\r\\n\"", e.message
|
159
|
+
|
160
|
+
deny server.alive?
|
161
|
+
|
162
|
+
assert_equal "get my_namespace:key\r\n",
|
163
|
+
server.socket.written.string
|
164
|
+
end
|
165
|
+
|
166
|
+
def test_crc32_ITU_T
|
167
|
+
assert_equal 0, ''.crc32_ITU_T
|
168
|
+
assert_equal 1260851911, 'my_namespace:key'.crc32_ITU_T
|
169
|
+
end
|
170
|
+
|
171
|
+
def test_initialize
|
172
|
+
cache = MemCache.new :namespace => 'my_namespace', :readonly => true
|
173
|
+
|
174
|
+
assert_equal 'my_namespace', cache.namespace
|
175
|
+
assert_equal true, cache.readonly?
|
176
|
+
assert_equal true, cache.servers.empty?
|
177
|
+
end
|
178
|
+
|
179
|
+
def test_initialize_compatible
|
180
|
+
cache = MemCache.new ['localhost:11211', 'localhost:11212'],
|
181
|
+
:namespace => 'my_namespace', :readonly => true
|
182
|
+
|
183
|
+
assert_equal 'my_namespace', cache.namespace
|
184
|
+
assert_equal true, cache.readonly?
|
185
|
+
assert_equal false, cache.servers.empty?
|
186
|
+
end
|
187
|
+
|
188
|
+
def test_initialize_compatible_no_hash
|
189
|
+
cache = MemCache.new ['localhost:11211', 'localhost:11212']
|
190
|
+
|
191
|
+
assert_equal nil, cache.namespace
|
192
|
+
assert_equal false, cache.readonly?
|
193
|
+
assert_equal false, cache.servers.empty?
|
194
|
+
end
|
195
|
+
|
196
|
+
def test_initialize_compatible_one_server
|
197
|
+
cache = MemCache.new 'localhost:11211'
|
198
|
+
|
199
|
+
assert_equal nil, cache.namespace
|
200
|
+
assert_equal false, cache.readonly?
|
201
|
+
assert_equal false, cache.servers.empty?
|
202
|
+
end
|
203
|
+
|
204
|
+
def test_initialize_compatible_bad_arg
|
205
|
+
e = assert_raise ArgumentError do
|
206
|
+
cache = MemCache.new Object.new
|
207
|
+
end
|
208
|
+
|
209
|
+
assert_equal 'first argument must be Array, Hash or String', e.message
|
210
|
+
end
|
211
|
+
|
212
|
+
def test_initialize_multiple_servers
|
213
|
+
cache = MemCache.new %w[localhost:11211 localhost:11212],
|
214
|
+
:namespace => 'my_namespace', :readonly => true
|
215
|
+
|
216
|
+
assert_equal 'my_namespace', cache.namespace
|
217
|
+
assert_equal true, cache.readonly?
|
218
|
+
assert_equal false, cache.servers.empty?
|
219
|
+
deny_empty cache.instance_variable_get(:@buckets)
|
220
|
+
end
|
221
|
+
|
222
|
+
def test_initialize_too_many_args
|
223
|
+
assert_raises ArgumentError do
|
224
|
+
MemCache.new 1, 2, 3
|
225
|
+
end
|
226
|
+
end
|
227
|
+
|
228
|
+
def test_decr
|
229
|
+
server = FakeServer.new
|
230
|
+
server.socket.data.write "5\r\n"
|
231
|
+
server.socket.data.rewind
|
232
|
+
|
233
|
+
@cache.servers = []
|
234
|
+
@cache.servers << server
|
235
|
+
|
236
|
+
value = @cache.decr 'key'
|
237
|
+
|
238
|
+
assert_equal "decr my_namespace:key 1\r\n",
|
239
|
+
@cache.servers.first.socket.written.string
|
240
|
+
|
241
|
+
assert_equal 5, value
|
242
|
+
end
|
243
|
+
|
244
|
+
def test_decr_not_found
|
245
|
+
server = FakeServer.new
|
246
|
+
server.socket.data.write "NOT_FOUND\r\n"
|
247
|
+
server.socket.data.rewind
|
248
|
+
|
249
|
+
@cache.servers = []
|
250
|
+
@cache.servers << server
|
251
|
+
|
252
|
+
value = @cache.decr 'key'
|
253
|
+
|
254
|
+
assert_equal "decr my_namespace:key 1\r\n",
|
255
|
+
@cache.servers.first.socket.written.string
|
256
|
+
|
257
|
+
assert_equal nil, value
|
258
|
+
end
|
259
|
+
|
260
|
+
def test_decr_space_padding
|
261
|
+
server = FakeServer.new
|
262
|
+
server.socket.data.write "5 \r\n"
|
263
|
+
server.socket.data.rewind
|
264
|
+
|
265
|
+
@cache.servers = []
|
266
|
+
@cache.servers << server
|
267
|
+
|
268
|
+
value = @cache.decr 'key'
|
269
|
+
|
270
|
+
assert_equal "decr my_namespace:key 1\r\n",
|
271
|
+
@cache.servers.first.socket.written.string
|
272
|
+
|
273
|
+
assert_equal 5, value
|
274
|
+
end
|
275
|
+
|
276
|
+
def test_get
|
277
|
+
util_setup_fake_server
|
278
|
+
|
279
|
+
value = @cache.get 'key'
|
280
|
+
|
281
|
+
assert_equal "get my_namespace:key\r\n",
|
282
|
+
@cache.servers.first.socket.written.string
|
283
|
+
|
284
|
+
assert_equal '0123456789', value
|
285
|
+
end
|
286
|
+
|
287
|
+
def test_get_bad_key
|
288
|
+
util_setup_fake_server
|
289
|
+
assert_raise ArgumentError do @cache.get 'k y' end
|
290
|
+
|
291
|
+
util_setup_fake_server
|
292
|
+
assert_raise ArgumentError do @cache.get 'k' * 250 end
|
293
|
+
end
|
294
|
+
|
295
|
+
def test_get_cache_get_IOError
|
296
|
+
socket = Object.new
|
297
|
+
def socket.write(arg) raise IOError, 'some io error'; end
|
298
|
+
server = FakeServer.new socket
|
299
|
+
|
300
|
+
@cache.servers = []
|
301
|
+
@cache.servers << server
|
302
|
+
|
303
|
+
e = assert_raise MemCache::MemCacheError do
|
304
|
+
@cache.get 'my_namespace:key'
|
305
|
+
end
|
306
|
+
|
307
|
+
assert_equal 'some io error', e.message
|
308
|
+
end
|
309
|
+
|
310
|
+
def test_get_cache_get_SystemCallError
|
311
|
+
socket = Object.new
|
312
|
+
def socket.write(arg) raise SystemCallError, 'some syscall error'; end
|
313
|
+
server = FakeServer.new socket
|
314
|
+
|
315
|
+
@cache.servers = []
|
316
|
+
@cache.servers << server
|
317
|
+
|
318
|
+
e = assert_raise MemCache::MemCacheError do
|
319
|
+
@cache.get 'my_namespace:key'
|
320
|
+
end
|
321
|
+
|
322
|
+
assert_equal 'unknown error - some syscall error', e.message
|
323
|
+
end
|
324
|
+
|
325
|
+
def test_get_no_connection
|
326
|
+
@cache.servers = 'localhost:1'
|
327
|
+
e = assert_raise MemCache::MemCacheError do
|
328
|
+
@cache.get 'key'
|
329
|
+
end
|
330
|
+
|
331
|
+
assert_match /^No connection to server/, e.message
|
332
|
+
end
|
333
|
+
|
334
|
+
def test_get_no_servers
|
335
|
+
@cache.servers = []
|
336
|
+
e = assert_raise MemCache::MemCacheError do
|
337
|
+
@cache.get 'key'
|
338
|
+
end
|
339
|
+
|
340
|
+
assert_equal 'No active servers', e.message
|
341
|
+
end
|
342
|
+
|
343
|
+
def test_get_multi
|
344
|
+
server = FakeServer.new
|
345
|
+
server.socket.data.write "VALUE my_namespace:key 0 14\r\n"
|
346
|
+
server.socket.data.write "\004\b\"\0170123456789\r\n"
|
347
|
+
server.socket.data.write "VALUE my_namespace:keyb 0 14\r\n"
|
348
|
+
server.socket.data.write "\004\b\"\0179876543210\r\n"
|
349
|
+
server.socket.data.write "END\r\n"
|
350
|
+
server.socket.data.rewind
|
351
|
+
|
352
|
+
@cache.servers = []
|
353
|
+
@cache.servers << server
|
354
|
+
|
355
|
+
values = @cache.get_multi 'key', 'keyb'
|
356
|
+
|
357
|
+
assert_equal "get my_namespace:key my_namespace:keyb\r\n",
|
358
|
+
server.socket.written.string
|
359
|
+
|
360
|
+
expected = { 'key' => '0123456789', 'keyb' => '9876543210' }
|
361
|
+
|
362
|
+
assert_equal expected.sort, values.sort
|
363
|
+
end
|
364
|
+
|
365
|
+
def test_get_raw
|
366
|
+
server = FakeServer.new
|
367
|
+
server.socket.data.write "VALUE my_namespace:key 0 10\r\n"
|
368
|
+
server.socket.data.write "0123456789\r\n"
|
369
|
+
server.socket.data.write "END\r\n"
|
370
|
+
server.socket.data.rewind
|
371
|
+
|
372
|
+
@cache.servers = []
|
373
|
+
@cache.servers << server
|
374
|
+
|
375
|
+
|
376
|
+
value = @cache.get 'key', true
|
377
|
+
|
378
|
+
assert_equal "get my_namespace:key\r\n",
|
379
|
+
@cache.servers.first.socket.written.string
|
380
|
+
|
381
|
+
assert_equal '0123456789', value
|
382
|
+
end
|
383
|
+
|
384
|
+
def test_get_server_for_key
|
385
|
+
server = @cache.get_server_for_key 'key'
|
386
|
+
assert_equal 'localhost', server.host
|
387
|
+
assert_equal 1, server.port
|
388
|
+
end
|
389
|
+
|
390
|
+
def test_get_server_for_key_multiple
|
391
|
+
s1 = util_setup_server @cache, 'one.example.com', ''
|
392
|
+
s2 = util_setup_server @cache, 'two.example.com', ''
|
393
|
+
@cache.instance_variable_set :@servers, [s1, s2]
|
394
|
+
@cache.instance_variable_set :@buckets, [s1, s2]
|
395
|
+
|
396
|
+
server = @cache.get_server_for_key 'keya'
|
397
|
+
assert_equal 'two.example.com', server.host
|
398
|
+
server = @cache.get_server_for_key 'keyb'
|
399
|
+
assert_equal 'one.example.com', server.host
|
400
|
+
end
|
401
|
+
|
402
|
+
def test_get_server_for_key_no_servers
|
403
|
+
@cache.servers = []
|
404
|
+
|
405
|
+
e = assert_raise MemCache::MemCacheError do
|
406
|
+
@cache.get_server_for_key 'key'
|
407
|
+
end
|
408
|
+
|
409
|
+
assert_equal 'No servers available', e.message
|
410
|
+
end
|
411
|
+
|
412
|
+
def test_get_server_for_key_spaces
|
413
|
+
e = assert_raise ArgumentError do
|
414
|
+
@cache.get_server_for_key 'space key'
|
415
|
+
end
|
416
|
+
assert_equal 'illegal character in key "space key"', e.message
|
417
|
+
end
|
418
|
+
|
419
|
+
def test_get_server_for_key_length
|
420
|
+
@cache.get_server_for_key 'x' * 250
|
421
|
+
long_key = 'x' * 251
|
422
|
+
e = assert_raise ArgumentError do
|
423
|
+
@cache.get_server_for_key long_key
|
424
|
+
end
|
425
|
+
assert_equal "key too long #{long_key.inspect}", e.message
|
426
|
+
end
|
427
|
+
|
428
|
+
def test_incr
|
429
|
+
server = FakeServer.new
|
430
|
+
server.socket.data.write "5\r\n"
|
431
|
+
server.socket.data.rewind
|
432
|
+
|
433
|
+
@cache.servers = []
|
434
|
+
@cache.servers << server
|
435
|
+
|
436
|
+
value = @cache.incr 'key'
|
437
|
+
|
438
|
+
assert_equal "incr my_namespace:key 1\r\n",
|
439
|
+
@cache.servers.first.socket.written.string
|
440
|
+
|
441
|
+
assert_equal 5, value
|
442
|
+
end
|
443
|
+
|
444
|
+
def test_incr_not_found
|
445
|
+
server = FakeServer.new
|
446
|
+
server.socket.data.write "NOT_FOUND\r\n"
|
447
|
+
server.socket.data.rewind
|
448
|
+
|
449
|
+
@cache.servers = []
|
450
|
+
@cache.servers << server
|
451
|
+
|
452
|
+
value = @cache.incr 'key'
|
453
|
+
|
454
|
+
assert_equal "incr my_namespace:key 1\r\n",
|
455
|
+
@cache.servers.first.socket.written.string
|
456
|
+
|
457
|
+
assert_equal nil, value
|
458
|
+
end
|
459
|
+
|
460
|
+
def test_incr_space_padding
|
461
|
+
server = FakeServer.new
|
462
|
+
server.socket.data.write "5 \r\n"
|
463
|
+
server.socket.data.rewind
|
464
|
+
|
465
|
+
@cache.servers = []
|
466
|
+
@cache.servers << server
|
467
|
+
|
468
|
+
value = @cache.incr 'key'
|
469
|
+
|
470
|
+
assert_equal "incr my_namespace:key 1\r\n",
|
471
|
+
@cache.servers.first.socket.written.string
|
472
|
+
|
473
|
+
assert_equal 5, value
|
474
|
+
end
|
475
|
+
|
476
|
+
def test_make_cache_key
|
477
|
+
assert_equal 'my_namespace:key', @cache.make_cache_key('key')
|
478
|
+
@cache.namespace = nil
|
479
|
+
assert_equal 'key', @cache.make_cache_key('key')
|
480
|
+
end
|
481
|
+
|
482
|
+
def test_servers
|
483
|
+
server = FakeServer.new
|
484
|
+
@cache.servers = []
|
485
|
+
@cache.servers << server
|
486
|
+
assert_equal [server], @cache.servers
|
487
|
+
end
|
488
|
+
|
489
|
+
def test_servers_equals_type_error
|
490
|
+
e = assert_raise TypeError do
|
491
|
+
@cache.servers = [Object.new]
|
492
|
+
end
|
493
|
+
|
494
|
+
assert_equal 'cannot convert Object into MemCache::Server', e.message
|
495
|
+
end
|
496
|
+
|
497
|
+
def test_set
|
498
|
+
server = FakeServer.new
|
499
|
+
server.socket.data.write "STORED\r\n"
|
500
|
+
server.socket.data.rewind
|
501
|
+
@cache.servers = []
|
502
|
+
@cache.servers << server
|
503
|
+
|
504
|
+
@cache.set 'key', 'value'
|
505
|
+
|
506
|
+
expected = "set my_namespace:key 0 0 9\r\n\004\b\"\nvalue\r\n"
|
507
|
+
assert_equal expected, server.socket.written.string
|
508
|
+
end
|
509
|
+
|
510
|
+
def test_set_expiry
|
511
|
+
server = FakeServer.new
|
512
|
+
server.socket.data.write "STORED\r\n"
|
513
|
+
server.socket.data.rewind
|
514
|
+
@cache.servers = []
|
515
|
+
@cache.servers << server
|
516
|
+
|
517
|
+
@cache.set 'key', 'value', 5
|
518
|
+
|
519
|
+
expected = "set my_namespace:key 0 5 9\r\n\004\b\"\nvalue\r\n"
|
520
|
+
assert_equal expected, server.socket.written.string
|
521
|
+
end
|
522
|
+
|
523
|
+
def test_set_raw
|
524
|
+
server = FakeServer.new
|
525
|
+
server.socket.data.write "STORED\r\n"
|
526
|
+
server.socket.data.rewind
|
527
|
+
@cache.servers = []
|
528
|
+
@cache.servers << server
|
529
|
+
|
530
|
+
@cache.set 'key', 'value', 0, true
|
531
|
+
|
532
|
+
expected = "set my_namespace:key 0 0 5\r\nvalue\r\n"
|
533
|
+
assert_equal expected, server.socket.written.string
|
534
|
+
end
|
535
|
+
|
536
|
+
def test_set_readonly
|
537
|
+
cache = MemCache.new :readonly => true
|
538
|
+
|
539
|
+
e = assert_raise MemCache::MemCacheError do
|
540
|
+
cache.set 'key', 'value'
|
541
|
+
end
|
542
|
+
|
543
|
+
assert_equal 'Update of readonly cache', e.message
|
544
|
+
end
|
545
|
+
|
546
|
+
def test_set_too_big
|
547
|
+
server = FakeServer.new
|
548
|
+
server.socket.data.write "SERVER_ERROR object too large for cache\r\n"
|
549
|
+
server.socket.data.rewind
|
550
|
+
@cache.servers = []
|
551
|
+
@cache.servers << server
|
552
|
+
|
553
|
+
e = assert_raise MemCache::MemCacheError do
|
554
|
+
@cache.set 'key', 'v'
|
555
|
+
end
|
556
|
+
|
557
|
+
assert_equal 'object too large for cache', e.message
|
558
|
+
end
|
559
|
+
|
560
|
+
def test_add
|
561
|
+
server = FakeServer.new
|
562
|
+
server.socket.data.write "STORED\r\n"
|
563
|
+
server.socket.data.rewind
|
564
|
+
@cache.servers = []
|
565
|
+
@cache.servers << server
|
566
|
+
|
567
|
+
@cache.add 'key', 'value'
|
568
|
+
|
569
|
+
expected = "add my_namespace:key 0 0 9\r\n\004\b\"\nvalue\r\n"
|
570
|
+
assert_equal expected, server.socket.written.string
|
571
|
+
end
|
572
|
+
|
573
|
+
def test_add_exists
|
574
|
+
server = FakeServer.new
|
575
|
+
server.socket.data.write "NOT_STORED\r\n"
|
576
|
+
server.socket.data.rewind
|
577
|
+
@cache.servers = []
|
578
|
+
@cache.servers << server
|
579
|
+
|
580
|
+
@cache.add 'key', 'value'
|
581
|
+
|
582
|
+
expected = "add my_namespace:key 0 0 9\r\n\004\b\"\nvalue\r\n"
|
583
|
+
assert_equal expected, server.socket.written.string
|
584
|
+
end
|
585
|
+
|
586
|
+
def test_add_expiry
|
587
|
+
server = FakeServer.new
|
588
|
+
server.socket.data.write "STORED\r\n"
|
589
|
+
server.socket.data.rewind
|
590
|
+
@cache.servers = []
|
591
|
+
@cache.servers << server
|
592
|
+
|
593
|
+
@cache.add 'key', 'value', 5
|
594
|
+
|
595
|
+
expected = "add my_namespace:key 0 5 9\r\n\004\b\"\nvalue\r\n"
|
596
|
+
assert_equal expected, server.socket.written.string
|
597
|
+
end
|
598
|
+
|
599
|
+
def test_add_raw
|
600
|
+
server = FakeServer.new
|
601
|
+
server.socket.data.write "STORED\r\n"
|
602
|
+
server.socket.data.rewind
|
603
|
+
@cache.servers = []
|
604
|
+
@cache.servers << server
|
605
|
+
|
606
|
+
@cache.add 'key', 'value', 0, true
|
607
|
+
|
608
|
+
expected = "add my_namespace:key 0 0 5\r\nvalue\r\n"
|
609
|
+
assert_equal expected, server.socket.written.string
|
610
|
+
end
|
611
|
+
|
612
|
+
def test_add_readonly
|
613
|
+
cache = MemCache.new :readonly => true
|
614
|
+
|
615
|
+
e = assert_raise MemCache::MemCacheError do
|
616
|
+
cache.add 'key', 'value'
|
617
|
+
end
|
618
|
+
|
619
|
+
assert_equal 'Update of readonly cache', e.message
|
620
|
+
end
|
621
|
+
|
622
|
+
def test_delete
|
623
|
+
server = FakeServer.new
|
624
|
+
@cache.servers = []
|
625
|
+
@cache.servers << server
|
626
|
+
|
627
|
+
@cache.delete 'key'
|
628
|
+
|
629
|
+
expected = "delete my_namespace:key 0\r\n"
|
630
|
+
assert_equal expected, server.socket.written.string
|
631
|
+
end
|
632
|
+
|
633
|
+
def test_delete_with_expiry
|
634
|
+
server = FakeServer.new
|
635
|
+
@cache.servers = []
|
636
|
+
@cache.servers << server
|
637
|
+
|
638
|
+
@cache.delete 'key', 300
|
639
|
+
|
640
|
+
expected = "delete my_namespace:key 300\r\n"
|
641
|
+
assert_equal expected, server.socket.written.string
|
642
|
+
end
|
643
|
+
|
644
|
+
def test_flush_all
|
645
|
+
@cache.servers = []
|
646
|
+
3.times { @cache.servers << FakeServer.new }
|
647
|
+
|
648
|
+
@cache.flush_all
|
649
|
+
|
650
|
+
expected = "flush_all\r\n"
|
651
|
+
@cache.servers.each do |server|
|
652
|
+
assert_equal expected, server.socket.written.string
|
653
|
+
end
|
654
|
+
end
|
655
|
+
|
656
|
+
def test_flush_all_failure
|
657
|
+
socket = FakeSocket.new
|
658
|
+
socket.data.write "ERROR\r\n"
|
659
|
+
socket.data.rewind
|
660
|
+
server = FakeServer.new socket
|
661
|
+
def server.host() "localhost"; end
|
662
|
+
def server.port() 11211; end
|
663
|
+
|
664
|
+
@cache.servers = []
|
665
|
+
@cache.servers << server
|
666
|
+
|
667
|
+
assert_raise MemCache::MemCacheError do
|
668
|
+
@cache.flush_all
|
669
|
+
end
|
670
|
+
|
671
|
+
assert_equal "flush_all\r\n", socket.written.string
|
672
|
+
end
|
673
|
+
|
674
|
+
def test_stats
|
675
|
+
socket = FakeSocket.new
|
676
|
+
socket.data.write "STAT pid 20188\r\nSTAT total_items 32\r\nSTAT version 1.2.3\r\nSTAT rusage_user 1:300\r\nSTAT dummy ok\r\nEND\r\n"
|
677
|
+
socket.data.rewind
|
678
|
+
server = FakeServer.new socket
|
679
|
+
def server.host() 'localhost'; end
|
680
|
+
def server.port() 11211; end
|
681
|
+
|
682
|
+
@cache.servers = []
|
683
|
+
@cache.servers << server
|
684
|
+
|
685
|
+
expected = {
|
686
|
+
'localhost:11211' => {
|
687
|
+
'pid' => 20188, 'total_items' => 32, 'version' => '1.2.3',
|
688
|
+
'rusage_user' => 1.0003, 'dummy' => 'ok'
|
689
|
+
}
|
690
|
+
}
|
691
|
+
assert_equal expected, @cache.stats
|
692
|
+
|
693
|
+
assert_equal "stats\r\n", socket.written.string
|
694
|
+
end
|
695
|
+
|
696
|
+
def test_basic_threaded_operations_should_work
|
697
|
+
cache = MemCache.new :multithread => true,
|
698
|
+
:namespace => 'my_namespace',
|
699
|
+
:readonly => false
|
700
|
+
server = util_setup_server cache, 'example.com', "OK\r\n"
|
701
|
+
cache.instance_variable_set :@servers, [server]
|
702
|
+
|
703
|
+
assert_nothing_raised do
|
704
|
+
cache.set "test", "test value"
|
705
|
+
end
|
706
|
+
end
|
707
|
+
|
708
|
+
def test_basic_unthreaded_operations_should_work
|
709
|
+
cache = MemCache.new :multithread => false,
|
710
|
+
:namespace => 'my_namespace',
|
711
|
+
:readonly => false
|
712
|
+
server = util_setup_server cache, 'example.com', "OK\r\n"
|
713
|
+
cache.instance_variable_set :@servers, [server]
|
714
|
+
|
715
|
+
assert_nothing_raised do
|
716
|
+
cache.set "test", "test value"
|
717
|
+
end
|
718
|
+
end
|
719
|
+
|
720
|
+
def util_setup_fake_server
|
721
|
+
server = FakeServer.new
|
722
|
+
server.socket.data.write "VALUE my_namespace:key 0 14\r\n"
|
723
|
+
server.socket.data.write "\004\b\"\0170123456789\r\n"
|
724
|
+
server.socket.data.write "END\r\n"
|
725
|
+
server.socket.data.rewind
|
726
|
+
|
727
|
+
@cache.servers = []
|
728
|
+
@cache.servers << server
|
729
|
+
|
730
|
+
return server
|
731
|
+
end
|
732
|
+
|
733
|
+
def util_setup_server(memcache, host, responses)
|
734
|
+
server = MemCache::Server.new memcache, host
|
735
|
+
server.instance_variable_set :@sock, StringIO.new(responses)
|
736
|
+
|
737
|
+
@cache.servers = []
|
738
|
+
@cache.servers << server
|
739
|
+
|
740
|
+
return server
|
741
|
+
end
|
742
|
+
|
743
|
+
end
|
744
|
+
|