memcache-auth 0.2

Sign up to get free protection for your applications and to get access to all the features.
data/test/setup.rb ADDED
@@ -0,0 +1,29 @@
1
+
2
+ unless defined? UNIX_SOCKET_NAME
3
+ HERE = File.dirname(__FILE__)
4
+ UNIX_SOCKET_NAME = File.join(ENV['TMPDIR']||'/tmp','memcached')
5
+
6
+ # Kill memcached
7
+ system("killall -9 memcached")
8
+
9
+ # Start memcached
10
+ verbosity = (ENV['DEBUG'] ? "-vv" : "")
11
+ log = "/tmp/memcached.log"
12
+ system ">#{log}"
13
+
14
+ # TCP memcached
15
+ (43042..43046).each do |port|
16
+ cmd = "memcached #{verbosity} -U 0 -p #{port} >> #{log} 2>&1 &"
17
+ raise "'#{cmd}' failed to start" unless system(cmd)
18
+ end
19
+ # UDP memcached
20
+ (43052..43053).each do |port|
21
+ cmd = "memcached #{verbosity} -U #{port} -p 0 >> #{log} 2>&1 &"
22
+ raise "'#{cmd}' failed to start" unless system(cmd)
23
+ end
24
+ # Domain socket memcached
25
+ (0..1).each do |i|
26
+ cmd = "memcached -M -s #{UNIX_SOCKET_NAME}#{i} #{verbosity} >> #{log} 2>&1 &"
27
+ raise "'#{cmd}' failed to start" unless system(cmd)
28
+ end
29
+ end
data/test/teardown.rb ADDED
File without changes
@@ -0,0 +1,18 @@
1
+
2
+ $LOAD_PATH << "#{File.dirname(__FILE__)}/../lib"
3
+
4
+ require 'rubygems'
5
+ require 'mocha'
6
+
7
+ if ENV['DEBUG']
8
+ require 'ruby-debug'
9
+ end
10
+
11
+ require 'memcached'
12
+ require 'test/unit'
13
+ require 'ostruct'
14
+
15
+ UNIX_SOCKET_NAME = File.join(ENV['TMPDIR']||'/tmp','memcached') unless defined? UNIX_SOCKET_NAME
16
+
17
+ class GenericClass
18
+ end
@@ -0,0 +1,8 @@
1
+
2
+ require "#{File.dirname(__FILE__)}/../test_helper"
3
+
4
+ class BindingTest < Test::Unit::TestCase
5
+ def test_libmemcached_loaded
6
+ assert_nothing_raised { Rlibmemcached }
7
+ end
8
+ end
@@ -0,0 +1,1029 @@
1
+
2
+ require "#{File.dirname(__FILE__)}/../test_helper"
3
+ require 'socket'
4
+ require 'mocha'
5
+ require 'benchmark'
6
+
7
+ class MemcachedTest < Test::Unit::TestCase
8
+
9
+ def setup
10
+ @servers = ['localhost:43042', 'localhost:43043', "#{UNIX_SOCKET_NAME}0"]
11
+ @udp_servers = ['localhost:43052', 'localhost:43053']
12
+
13
+ # Maximum allowed prefix key size for :hash_with_prefix_key_key => false
14
+ @prefix_key = 'prefix_key_'
15
+
16
+ @options = {
17
+ :prefix_key => @prefix_key,
18
+ :hash => :default,
19
+ :distribution => :modula}
20
+ @cache = Memcached.new(@servers, @options)
21
+
22
+ @binary_protocol_options = {
23
+ :prefix_key => @prefix_key,
24
+ :hash => :default,
25
+ :distribution => :modula,
26
+ :binary_protocol => true}
27
+ @binary_protocol_cache = Memcached.new(@servers, @binary_protocol_options)
28
+
29
+ @udp_options = {
30
+ :prefix_key => @prefix_key,
31
+ :hash => :default,
32
+ :use_udp => true,
33
+ :distribution => :modula}
34
+ @udp_cache = Memcached.new(@udp_servers, @udp_options)
35
+
36
+ @noblock_options = {
37
+ :prefix_key => @prefix_key,
38
+ :no_block => true,
39
+ :buffer_requests => true,
40
+ :hash => :default}
41
+ @noblock_cache = Memcached.new(@servers, @noblock_options)
42
+
43
+ @value = OpenStruct.new(:a => 1, :b => 2, :c => GenericClass)
44
+ @marshalled_value = Marshal.dump(@value)
45
+ end
46
+
47
+ # Initialize
48
+
49
+ def test_initialize
50
+ cache = Memcached.new @servers, :prefix_key => 'test'
51
+ assert_equal 'test', cache.options[:prefix_key]
52
+ assert_equal 3, cache.send(:server_structs).size
53
+ assert_equal 'localhost', cache.send(:server_structs).first.hostname
54
+ assert_equal 43042, cache.send(:server_structs).first.port
55
+ end
56
+
57
+ def test_initialize_with_ip_addresses
58
+ cache = Memcached.new ['127.0.0.1:43042', '127.0.0.1:43043']
59
+ assert_equal '127.0.0.1', cache.send(:server_structs).first.hostname
60
+ assert_equal '127.0.0.1', cache.send(:server_structs).last.hostname
61
+ end
62
+
63
+ def test_initialize_without_port
64
+ cache = Memcached.new ['localhost']
65
+ assert_equal 'localhost', cache.send(:server_structs).first.hostname
66
+ assert_equal 11211, cache.send(:server_structs).first.port
67
+ end
68
+
69
+ def test_initialize_with_ports_and_weights
70
+ cache = Memcached.new ['localhost:43042:2', 'localhost:43043:10']
71
+ assert_equal 2, cache.send(:server_structs).first.weight
72
+ assert_equal 43043, cache.send(:server_structs).last.port
73
+ assert_equal 10, cache.send(:server_structs).last.weight
74
+ end
75
+
76
+ def test_initialize_with_hostname_only
77
+ addresses = (1..8).map { |i| "app-cache-%02d" % i }
78
+ cache = Memcached.new(addresses)
79
+ addresses.each_with_index do |address, index|
80
+ assert_equal address, cache.send(:server_structs)[index].hostname
81
+ assert_equal 11211, cache.send(:server_structs)[index].port
82
+ end
83
+ end
84
+
85
+ def test_initialize_with_ip_address_and_options
86
+ cache = Memcached.new '127.0.0.1:43042', :ketama_weighted => false
87
+ assert_equal '127.0.0.1', cache.send(:server_structs).first.hostname
88
+ assert_equal false, cache.options[:ketama_weighted]
89
+ end
90
+
91
+ def test_options_are_set
92
+ Memcached::DEFAULTS.merge(@noblock_options).each do |key, expected|
93
+ value = @noblock_cache.options[key]
94
+ unless key == :rcv_timeout or key == :poll_timeout
95
+ assert(expected == value, "#{key} should be #{expected} but was #{value}")
96
+ end
97
+ end
98
+ end
99
+
100
+ def test_options_are_frozen
101
+ assert_raise(TypeError, RuntimeError) do
102
+ @cache.options[:no_block] = true
103
+ end
104
+ end
105
+
106
+ def test_behaviors_are_set
107
+ Memcached::BEHAVIORS.keys.each do |key, value|
108
+ assert_not_nil @cache.send(:get_behavior, key)
109
+ end
110
+ end
111
+
112
+ def test_initialize_with_invalid_server_strings
113
+ assert_raise(ArgumentError) { Memcached.new ":43042" }
114
+ assert_raise(ArgumentError) { Memcached.new "localhost:memcached" }
115
+ assert_raise(ArgumentError) { Memcached.new "local host:43043:1" }
116
+ end
117
+
118
+ def test_initialize_with_invalid_options
119
+ assert_raise(ArgumentError) do
120
+ Memcached.new @servers, :sort_hosts => true, :distribution => :consistent
121
+ end
122
+ end
123
+
124
+ def test_initialize_with_invalid_prefix_key
125
+ assert_raise(ArgumentError) do
126
+ Memcached.new @servers, :prefix_key => "x" * 128
127
+ end
128
+ end
129
+
130
+ def test_initialize_without_prefix_key
131
+ cache = Memcached.new @servers
132
+ assert_equal nil, cache.options[:prefix_key]
133
+ assert_equal 3, cache.send(:server_structs).size
134
+ end
135
+
136
+ def test_initialize_negative_behavior
137
+ cache = Memcached.new @servers,
138
+ :buffer_requests => false
139
+ assert_nothing_raised do
140
+ cache.set key, @value
141
+ end
142
+ end
143
+
144
+ def test_initialize_without_backtraces
145
+ cache = Memcached.new @servers,
146
+ :show_backtraces => false
147
+ cache.delete key rescue
148
+ begin
149
+ cache.get key
150
+ rescue Memcached::NotFound => e
151
+ assert e.backtrace.empty?
152
+ end
153
+ begin
154
+ cache.append key, @value
155
+ rescue Memcached::NotStored => e
156
+ assert e.backtrace.empty?
157
+ end
158
+ end
159
+
160
+ def test_initialize_with_backtraces
161
+ cache = Memcached.new @servers,
162
+ :show_backtraces => true
163
+ cache.delete key rescue
164
+ begin
165
+ cache.get key
166
+ rescue Memcached::NotFound => e
167
+ assert !e.backtrace.empty?
168
+ end
169
+ end
170
+
171
+ def test_initialize_sort_hosts
172
+ # Original
173
+ cache = Memcached.new(@servers.sort,
174
+ :sort_hosts => false,
175
+ :distribution => :modula
176
+ )
177
+ assert_equal @servers.sort,
178
+ cache.servers
179
+
180
+ # Original with sort_hosts
181
+ cache = Memcached.new(@servers.sort,
182
+ :sort_hosts => true,
183
+ :distribution => :modula
184
+ )
185
+ assert_equal @servers.sort,
186
+ cache.servers
187
+
188
+ # Reversed
189
+ cache = Memcached.new(@servers.sort.reverse,
190
+ :sort_hosts => false,
191
+ :distribution => :modula
192
+ )
193
+ assert_equal @servers.sort.reverse,
194
+ cache.servers
195
+
196
+ # Reversed with sort_hosts
197
+ cache = Memcached.new(@servers.sort.reverse,
198
+ :sort_hosts => true,
199
+ :distribution => :modula
200
+ )
201
+ assert_equal @servers.sort,
202
+ cache.servers
203
+ end
204
+
205
+ def test_initialize_single_server
206
+ cache = Memcached.new 'localhost:43042'
207
+ assert_equal nil, cache.options[:prefix_key]
208
+ assert_equal 1, cache.send(:server_structs).size
209
+ end
210
+
211
+ def test_initialize_strange_argument
212
+ assert_raise(ArgumentError) { Memcached.new 1 }
213
+ end
214
+
215
+ # Get
216
+
217
+ def test_get
218
+ @cache.set key, @value
219
+ result = @cache.get key
220
+ assert_equal @value, result
221
+
222
+ @binary_protocol_cache.set key, @value
223
+ result = @binary_protocol_cache.get key
224
+ assert_equal @value, result
225
+
226
+ @udp_cache.set(key, @value)
227
+ assert_raises(Memcached::ActionNotSupported) do
228
+ @udp_cache.get(key)
229
+ end
230
+ end
231
+
232
+ def test_get_nil
233
+ @cache.set key, nil, 0
234
+ result = @cache.get key
235
+ assert_equal nil, result
236
+ end
237
+
238
+ def test_get_missing
239
+ @cache.delete key rescue nil
240
+ assert_raise(Memcached::NotFound) do
241
+ result = @cache.get key
242
+ end
243
+ end
244
+
245
+ def test_get_with_server_timeout
246
+ socket = stub_server 43047
247
+ cache = Memcached.new("localhost:43047:1", :timeout => 0.5)
248
+ assert 0.49 < (Benchmark.measure do
249
+ assert_raise(Memcached::ATimeoutOccurred) do
250
+ result = cache.get key
251
+ end
252
+ end).real
253
+
254
+ cache = Memcached.new("localhost:43047:1", :poll_timeout => 0.001, :rcv_timeout => 0.5)
255
+ assert 0.49 < (Benchmark.measure do
256
+ assert_raise(Memcached::ATimeoutOccurred) do
257
+ result = cache.get key
258
+ end
259
+ end).real
260
+
261
+ cache = Memcached.new("localhost:43047:1", :poll_timeout => 0.25, :rcv_timeout => 0.25)
262
+ assert 0.51 > (Benchmark.measure do
263
+ assert_raise(Memcached::ATimeoutOccurred) do
264
+ result = cache.get key
265
+ end
266
+ end).real
267
+
268
+ socket.close
269
+ end
270
+
271
+ def test_get_with_no_block_server_timeout
272
+ socket = stub_server 43048
273
+ cache = Memcached.new("localhost:43048:1", :no_block => true, :timeout => 0.25)
274
+ assert 0.24 < (Benchmark.measure do
275
+ assert_raise(Memcached::ATimeoutOccurred) do
276
+ result = cache.get key
277
+ end
278
+ end).real
279
+
280
+ cache = Memcached.new("localhost:43048:1", :no_block => true, :poll_timeout => 0.25, :rcv_timeout => 0.001)
281
+ assert 0.24 < (Benchmark.measure do
282
+ assert_raise(Memcached::ATimeoutOccurred) do
283
+ result = cache.get key
284
+ end
285
+ end).real
286
+
287
+ cache = Memcached.new("localhost:43048:1", :no_block => true,
288
+ :poll_timeout => 0.001,
289
+ :rcv_timeout => 0.25 # No affect in no-block mode
290
+ )
291
+ assert 0.24 > (Benchmark.measure do
292
+ assert_raise(Memcached::ATimeoutOccurred) do
293
+ result = cache.get key
294
+ end
295
+ end).real
296
+
297
+ socket.close
298
+ end
299
+
300
+ def test_get_with_prefix_key
301
+ # Prefix_key
302
+ cache = Memcached.new(
303
+ # We can only use one server because the key is hashed separately from the prefix key
304
+ @servers.first,
305
+ :prefix_key => @prefix_key,
306
+ :hash => :default,
307
+ :distribution => :modula
308
+ )
309
+ cache.set key, @value
310
+ assert_equal @value, cache.get(key)
311
+
312
+ # No prefix_key specified
313
+ cache = Memcached.new(
314
+ @servers.first,
315
+ :hash => :default,
316
+ :distribution => :modula
317
+ )
318
+ assert_nothing_raised do
319
+ assert_equal @value, cache.get("#{@prefix_key}#{key}")
320
+ end
321
+ end
322
+
323
+ def test_values_with_null_characters_are_not_truncated
324
+ value = OpenStruct.new(:a => Object.new) # Marshals with a null \000
325
+ @cache.set key, value
326
+ result = @cache.get key, false
327
+ non_wrapped_result = Rlibmemcached.memcached_get(
328
+ @cache.instance_variable_get("@struct"),
329
+ key
330
+ ).first
331
+ assert result.size > non_wrapped_result.size
332
+ end
333
+
334
+ def test_get_multi
335
+ @cache.set "#{key}_1", 1
336
+ @cache.set "#{key}_2", 2
337
+ assert_equal({"#{key}_1" => 1, "#{key}_2" => 2},
338
+ @cache.get(["#{key}_1", "#{key}_2"]))
339
+ end
340
+
341
+ def test_get_multi_missing
342
+ @cache.set "#{key}_1", 1
343
+ @cache.delete "#{key}_2" rescue nil
344
+ @cache.set "#{key}_3", 3
345
+ @cache.delete "#{key}_4" rescue nil
346
+ assert_equal(
347
+ {"test_get_multi_missing_3"=>3, "test_get_multi_missing_1"=>1},
348
+ @cache.get(["#{key}_1", "#{key}_2", "#{key}_3", "#{key}_4"])
349
+ )
350
+ end
351
+
352
+ def test_get_multi_completely_missing
353
+ @cache.delete "#{key}_1" rescue nil
354
+ @cache.delete "#{key}_2" rescue nil
355
+ assert_equal(
356
+ {},
357
+ @cache.get(["#{key}_1", "#{key}_2"])
358
+ )
359
+ end
360
+
361
+ def test_get_multi_checks_types
362
+ assert_raises(TypeError, ArgumentError) do
363
+ @cache.get([nil])
364
+ end
365
+ end
366
+
367
+ def test_set_and_get_unmarshalled
368
+ @cache.set key, @value
369
+ result = @cache.get key, false
370
+ assert_equal @marshalled_value, result
371
+ end
372
+
373
+ def test_get_multi_unmarshalled
374
+ @cache.set "#{key}_1", 1, 0, false
375
+ @cache.set "#{key}_2", 2, 0, false
376
+ assert_equal(
377
+ {"#{key}_1" => "1", "#{key}_2" => "2"},
378
+ @cache.get(["#{key}_1", "#{key}_2"], false)
379
+ )
380
+ end
381
+
382
+ def test_get_multi_mixed_marshalling
383
+ @cache.set "#{key}_1", 1
384
+ @cache.set "#{key}_2", 2, 0, false
385
+ assert_nothing_raised do
386
+ @cache.get(["#{key}_1", "#{key}_2"], false)
387
+ end
388
+ assert_raise(ArgumentError) do
389
+ @cache.get(["#{key}_1", "#{key}_2"])
390
+ end
391
+ end
392
+
393
+ def test_random_distribution_is_statistically_random
394
+ cache = Memcached.new(@servers, :distribution => :random)
395
+ cache.flush
396
+ 20.times { |i| cache.set "#{key}#{i}", @value }
397
+
398
+ cache, hits = Memcached.new(@servers.first), 0
399
+ 20.times do |i|
400
+ begin
401
+ cache.get "#{key}#{i}"
402
+ hits += 1
403
+ rescue Memcached::NotFound
404
+ end
405
+ end
406
+
407
+ assert_not_equal 4, hits
408
+ end
409
+
410
+ # Set
411
+
412
+ def test_set
413
+ assert_nothing_raised do
414
+ @cache.set(key, @value)
415
+ end
416
+
417
+ assert_nothing_raised do
418
+ @binary_protocol_cache.set(key, @value)
419
+ end
420
+
421
+ assert_nothing_raised do
422
+ @udp_cache.set(key, @value)
423
+ end
424
+ end
425
+
426
+ def test_set_expiry
427
+ @cache.set key, @value, 1
428
+ assert_nothing_raised do
429
+ @cache.get key
430
+ end
431
+ sleep(2)
432
+ assert_raise(Memcached::NotFound) do
433
+ @cache.get key
434
+ end
435
+ end
436
+
437
+ def test_set_with_default_ttl
438
+ cache = Memcached.new(
439
+ @servers,
440
+ :default_ttl => 1
441
+ )
442
+ cache.set key, @value
443
+ assert_nothing_raised do
444
+ cache.get key
445
+ end
446
+ sleep(2)
447
+ assert_raise(Memcached::NotFound) do
448
+ cache.get key
449
+ end
450
+ end
451
+
452
+ def disabled_test_set_retry_on_client_error
453
+ # FIXME Test passes, but Mocha doesn't restore the original method properly
454
+ Rlibmemcached.stubs(:memcached_set).raises(Memcached::ClientError)
455
+ Rlibmemcached.stubs(:memcached_set).returns(0)
456
+
457
+ assert_nothing_raised do
458
+ @cache.set(key, @value)
459
+ end
460
+ end
461
+
462
+ # Delete
463
+
464
+ def test_delete
465
+ @cache.set key, @value
466
+ @cache.delete key
467
+ assert_raise(Memcached::NotFound) do
468
+ @cache.get key
469
+ end
470
+ end
471
+
472
+ def test_missing_delete
473
+ @cache.delete key rescue nil
474
+ assert_raise(Memcached::NotFound) do
475
+ @cache.delete key
476
+ end
477
+ end
478
+
479
+ # Flush
480
+
481
+ def test_flush
482
+ @cache.set key, @value
483
+ assert_equal @value,
484
+ @cache.get(key)
485
+ @cache.flush
486
+ assert_raise(Memcached::NotFound) do
487
+ @cache.get key
488
+ end
489
+ end
490
+
491
+ # Add
492
+
493
+ def test_add
494
+ @cache.delete key rescue nil
495
+ @cache.add key, @value
496
+ assert_equal @value, @cache.get(key)
497
+ end
498
+
499
+ def test_existing_add
500
+ @cache.set key, @value
501
+ assert_raise(Memcached::NotStored) do
502
+ @cache.add key, @value
503
+ end
504
+ end
505
+
506
+ def test_add_expiry
507
+ @cache.delete key rescue nil
508
+ @cache.set key, @value, 1
509
+ assert_nothing_raised do
510
+ @cache.get key
511
+ end
512
+ sleep(1)
513
+ assert_raise(Memcached::NotFound) do
514
+ @cache.get key
515
+ end
516
+ end
517
+
518
+ def test_unmarshalled_add
519
+ @cache.delete key rescue nil
520
+ @cache.add key, @marshalled_value, 0, false
521
+ assert_equal @marshalled_value, @cache.get(key, false)
522
+ assert_equal @value, @cache.get(key)
523
+ end
524
+
525
+ # Increment and decrement
526
+
527
+ def test_increment
528
+ @cache.set key, 10, 0, false
529
+ assert_equal 11, @cache.increment(key)
530
+ end
531
+
532
+ def test_increment_offset
533
+ @cache.set key, 10, 0, false
534
+ assert_equal 15, @cache.increment(key, 5)
535
+ end
536
+
537
+ def test_missing_increment
538
+ @cache.delete key rescue nil
539
+ assert_raise(Memcached::NotFound) do
540
+ @cache.increment key
541
+ end
542
+ end
543
+
544
+ def test_decrement
545
+ @cache.set key, 10, 0, false
546
+ assert_equal 9, @cache.decrement(key)
547
+ end
548
+
549
+ def test_decrement_offset
550
+ @cache.set key, 10, 0, false
551
+ assert_equal 5, @cache.decrement(key, 5)
552
+ end
553
+
554
+ def test_missing_decrement
555
+ @cache.delete key rescue nil
556
+ assert_raise(Memcached::NotFound) do
557
+ @cache.decrement key
558
+ end
559
+ end
560
+
561
+ # Replace
562
+
563
+ def test_replace
564
+ @cache.set key, nil
565
+ assert_nothing_raised do
566
+ @cache.replace key, @value
567
+ end
568
+ assert_equal @value, @cache.get(key)
569
+ end
570
+
571
+ def test_missing_replace
572
+ @cache.delete key rescue nil
573
+ assert_raise(Memcached::NotStored) do
574
+ @cache.replace key, @value
575
+ end
576
+ assert_raise(Memcached::NotFound) do
577
+ assert_equal @value, @cache.get(key)
578
+ end
579
+ end
580
+
581
+ # Append and prepend
582
+
583
+ def test_append
584
+ @cache.set key, "start", 0, false
585
+ assert_nothing_raised do
586
+ @cache.append key, "end"
587
+ end
588
+ assert_equal "startend", @cache.get(key, false)
589
+
590
+ @binary_protocol_cache.set key, "start", 0, false
591
+ assert_nothing_raised do
592
+ @binary_protocol_cache.append key, "end"
593
+ end
594
+ assert_equal "startend", @binary_protocol_cache.get(key, false)
595
+ end
596
+
597
+ def test_missing_append
598
+ @cache.delete key rescue nil
599
+ assert_raise(Memcached::NotStored) do
600
+ @cache.append key, "end"
601
+ end
602
+ assert_raise(Memcached::NotFound) do
603
+ assert_equal @value, @cache.get(key)
604
+ end
605
+
606
+ @binary_protocol_cache.delete key rescue nil
607
+ assert_raise(Memcached::NotStored) do
608
+ @binary_protocol_cache.append key, "end"
609
+ end
610
+ assert_raise(Memcached::NotFound) do
611
+ assert_equal @value, @binary_protocol_cache.get(key)
612
+ end
613
+ end
614
+
615
+ def test_prepend
616
+ @cache.set key, "end", 0, false
617
+ assert_nothing_raised do
618
+ @cache.prepend key, "start"
619
+ end
620
+ assert_equal "startend", @cache.get(key, false)
621
+ end
622
+
623
+ def test_missing_prepend
624
+ @cache.delete key rescue nil
625
+ assert_raise(Memcached::NotStored) do
626
+ @cache.prepend key, "end"
627
+ end
628
+ assert_raise(Memcached::NotFound) do
629
+ assert_equal @value, @cache.get(key)
630
+ end
631
+ end
632
+
633
+ def test_cas
634
+ cache = Memcached.new(
635
+ @servers,
636
+ :prefix_key => @prefix_key,
637
+ :support_cas => true
638
+ )
639
+ value2 = OpenStruct.new(:d => 3, :e => 4, :f => GenericClass)
640
+
641
+ # Existing set
642
+ cache.set key, @value
643
+ cache.cas(key) do |current|
644
+ assert_equal @value, current
645
+ value2
646
+ end
647
+ assert_equal value2, cache.get(key)
648
+
649
+ # Existing test without marshalling
650
+ cache.set(key, "foo", 0, false)
651
+ cache.cas(key, 0, false) do |current|
652
+ "#{current}bar"
653
+ end
654
+ assert_equal "foobar", cache.get(key, false)
655
+
656
+ # Missing set
657
+ cache.delete key
658
+ assert_raises(Memcached::NotFound) do
659
+ cache.cas(key) {}
660
+ end
661
+
662
+ # Conflicting set
663
+ cache.set key, @value
664
+ assert_raises(Memcached::ConnectionDataExists) do
665
+ cache.cas(key) do |current|
666
+ cache.set key, value2
667
+ current
668
+ end
669
+ end
670
+ end
671
+
672
+ # Error states
673
+
674
+ def test_key_with_spaces
675
+ key = "i have a space"
676
+ assert_raises(Memcached::ABadKeyWasProvidedOrCharactersOutOfRange) do
677
+ @cache.set key, @value
678
+ end
679
+ assert_raises(Memcached::ABadKeyWasProvidedOrCharactersOutOfRange) do
680
+ @cache.get(key)
681
+ end
682
+ end
683
+
684
+ def test_key_with_null
685
+ key = "with\000null"
686
+ assert_raises(Memcached::ABadKeyWasProvidedOrCharactersOutOfRange) do
687
+ @cache.set key, @value
688
+ end
689
+ assert_raises(Memcached::ABadKeyWasProvidedOrCharactersOutOfRange) do
690
+ @cache.get(key)
691
+ end
692
+
693
+ assert_raises(Memcached::ABadKeyWasProvidedOrCharactersOutOfRange) do
694
+ response = @cache.get([key])
695
+ end
696
+ end
697
+
698
+ def test_key_with_invalid_control_characters
699
+ key = "ch\303\242teau"
700
+ assert_raises(Memcached::ABadKeyWasProvidedOrCharactersOutOfRange) do
701
+ @cache.set key, @value
702
+ end
703
+ assert_raises(Memcached::ABadKeyWasProvidedOrCharactersOutOfRange) do
704
+ @cache.get(key)
705
+ end
706
+
707
+ assert_raises(Memcached::ABadKeyWasProvidedOrCharactersOutOfRange) do
708
+ response = @cache.get([key])
709
+ end
710
+ end
711
+
712
+ def test_key_too_long
713
+ key = "x"*251
714
+ assert_raises(Memcached::ABadKeyWasProvidedOrCharactersOutOfRange) do
715
+ @cache.set key, @value
716
+ end
717
+ assert_raises(Memcached::ABadKeyWasProvidedOrCharactersOutOfRange) do
718
+ @cache.get(key)
719
+ end
720
+
721
+ assert_raises(Memcached::ABadKeyWasProvidedOrCharactersOutOfRange) do
722
+ @cache.get([key])
723
+ end
724
+ end
725
+
726
+ def test_server_error_message
727
+ @cache.set key, "I'm big" * 1000000
728
+ assert false # Never reached
729
+ rescue Memcached::ServerError => e
730
+ assert_match /^"object too large for cache". Key/, e.message
731
+ end
732
+
733
+ def test_errno_message
734
+ Rlibmemcached::MemcachedServerSt.any_instance.stubs("cached_errno").returns(1)
735
+ @cache.send(:check_return_code, Rlibmemcached::MEMCACHED_ERRNO, key)
736
+ rescue Memcached::SystemError => e
737
+ assert_match /^Errno 1: "Operation not permitted". Key/, e.message
738
+ end
739
+
740
+ # Stats
741
+
742
+ def test_stats
743
+ stats = @cache.stats
744
+ assert_equal 3, stats[:pid].size
745
+ assert_instance_of Fixnum, stats[:pid].first
746
+ assert_instance_of String, stats[:version].first
747
+ end
748
+
749
+ def test_missing_stats
750
+ cache = Memcached.new('localhost:43041')
751
+ assert_raises(Memcached::SomeErrorsWereReported) { cache.stats }
752
+ end
753
+
754
+ # Clone
755
+
756
+ def test_clone
757
+ cache = @cache.clone
758
+ assert_equal cache.servers, @cache.servers
759
+ assert_not_equal cache, @cache
760
+
761
+ # Definitely check that the structs are unlinked
762
+ assert_not_equal @cache.instance_variable_get('@struct').object_id,
763
+ cache.instance_variable_get('@struct').object_id
764
+
765
+ assert_nothing_raised do
766
+ @cache.set key, @value
767
+ end
768
+ end
769
+
770
+ # Non-blocking IO
771
+
772
+ def test_buffered_requests_return_value
773
+ cache = Memcached.new @servers,
774
+ :buffer_requests => true
775
+ assert_nothing_raised do
776
+ cache.set key, @value
777
+ end
778
+ ret = Rlibmemcached.memcached_set(
779
+ cache.instance_variable_get("@struct"),
780
+ key,
781
+ @marshalled_value,
782
+ 0,
783
+ Memcached::FLAGS
784
+ )
785
+ assert_equal Rlibmemcached::MEMCACHED_BUFFERED, ret
786
+ end
787
+
788
+ def test_no_block_return_value
789
+ assert_nothing_raised do
790
+ @noblock_cache.set key, @value
791
+ end
792
+ ret = Rlibmemcached.memcached_set(
793
+ @noblock_cache.instance_variable_get("@struct"),
794
+ key,
795
+ @marshalled_value,
796
+ 0,
797
+ Memcached::FLAGS
798
+ )
799
+ assert_equal Rlibmemcached::MEMCACHED_BUFFERED, ret
800
+ end
801
+
802
+ def test_no_block_get
803
+ @noblock_cache.set key, @value
804
+ assert_equal @value,
805
+ @noblock_cache.get(key)
806
+ end
807
+
808
+ def test_no_block_missing_delete
809
+ @noblock_cache.delete key rescue nil
810
+ assert_nothing_raised do
811
+ @noblock_cache.delete key
812
+ end
813
+ end
814
+
815
+ def test_no_block_set_invalid_key
816
+ assert_raises(Memcached::ABadKeyWasProvidedOrCharactersOutOfRange) do
817
+ @noblock_cache.set "I'm so bad", @value
818
+ end
819
+ end
820
+
821
+ def test_no_block_set_object_too_large
822
+ assert_nothing_raised do
823
+ @noblock_cache.set key, "I'm big" * 1000000
824
+ end
825
+ end
826
+
827
+ def test_no_block_existing_add
828
+ # Should still raise
829
+ @noblock_cache.set key, @value
830
+ assert_raise(Memcached::NotStored) do
831
+ @noblock_cache.add key, @value
832
+ end
833
+ end
834
+
835
+ # Server removal and consistent hashing
836
+
837
+ def test_unresponsive_server
838
+ socket = stub_server 43041
839
+
840
+ cache = Memcached.new(
841
+ [@servers.last, 'localhost:43041'],
842
+ :prefix_key => @prefix_key,
843
+ :auto_eject_hosts => true,
844
+ :server_failure_limit => 2,
845
+ :retry_timeout => 1,
846
+ :hash_with_prefix_key => false,
847
+ :hash => :md5
848
+ )
849
+
850
+ # Hit second server up to the server_failure_limit
851
+ key2 = 'test_missing_server'
852
+ assert_raise(Memcached::ATimeoutOccurred) { cache.set(key2, @value) }
853
+ assert_raise(Memcached::ATimeoutOccurred) { cache.get(key2, @value) }
854
+
855
+ # Hit second server and pass the limit
856
+ key2 = 'test_missing_server'
857
+ begin
858
+ cache.get(key2)
859
+ rescue => e
860
+ assert_equal Memcached::ServerIsMarkedDead, e.class
861
+ assert_match /localhost:43041/, e.message
862
+ end
863
+
864
+ # Hit first server on retry
865
+ assert_nothing_raised do
866
+ cache.set(key2, @value)
867
+ assert_equal cache.get(key2), @value
868
+ end
869
+
870
+ sleep(2)
871
+
872
+ # Hit second server again after restore, expect same failure
873
+ key2 = 'test_missing_server'
874
+ assert_raise(Memcached::ATimeoutOccurred) do
875
+ cache.set(key2, @value)
876
+ end
877
+
878
+ socket.close
879
+ end
880
+
881
+ def test_missing_server
882
+ cache = Memcached.new(
883
+ [@servers.last, 'localhost:43041'],
884
+ :prefix_key => @prefix_key,
885
+ :auto_eject_hosts => true,
886
+ :server_failure_limit => 2,
887
+ :retry_timeout => 1,
888
+ :hash_with_prefix_key => false,
889
+ :hash => :md5
890
+ )
891
+
892
+ # Hit second server up to the server_failure_limit
893
+ key2 = 'test_missing_server'
894
+ assert_raise(Memcached::SystemError) { cache.set(key2, @value) }
895
+ assert_raise(Memcached::SystemError) { cache.get(key2, @value) }
896
+
897
+ # Hit second server and pass the limit
898
+ key2 = 'test_missing_server'
899
+ begin
900
+ cache.get(key2)
901
+ rescue => e
902
+ assert_equal Memcached::ServerIsMarkedDead, e.class
903
+ assert_match /localhost:43041/, e.message
904
+ end
905
+
906
+ # Hit first server on retry
907
+ assert_nothing_raised do
908
+ cache.set(key2, @value)
909
+ assert_equal cache.get(key2), @value
910
+ end
911
+
912
+ sleep(2)
913
+
914
+ # Hit second server again after restore, expect same failure
915
+ key2 = 'test_missing_server'
916
+ assert_raise(Memcached::SystemError) do
917
+ cache.set(key2, @value)
918
+ end
919
+ end
920
+
921
+ def test_unresponsive_with_random_distribution
922
+ socket = stub_server 43041
923
+ failures = [Memcached::ATimeoutOccurred, Memcached::ServerIsMarkedDead]
924
+
925
+ cache = Memcached.new(
926
+ [@servers.last, 'localhost:43041'],
927
+ :auto_eject_hosts => true,
928
+ :distribution => :random,
929
+ :server_failure_limit => 1,
930
+ :retry_timeout => 1
931
+ )
932
+
933
+ # Provoke the errors in 'failures'
934
+ exceptions = []
935
+ 100.times { begin; cache.set key, @value; rescue => e; exceptions << e; end }
936
+ assert_equal failures, exceptions.map { |x| x.class }
937
+
938
+ # Hit first server on retry
939
+ assert_nothing_raised { cache.set(key, @value) }
940
+
941
+ # Hit second server again after restore, expect same failures
942
+ sleep(2)
943
+ exceptions = []
944
+ 100.times { begin; cache.set key, @value; rescue => e; exceptions << e; end }
945
+ assert_equal failures, exceptions.map { |x| x.class }
946
+
947
+ socket.close
948
+ end
949
+
950
+ def test_consistent_hashing
951
+ keys = %w(EN6qtgMW n6Oz2W4I ss4A8Brr QShqFLZt Y3hgP9bs CokDD4OD Nd3iTSE1 24vBV4AU H9XBUQs5 E5j8vUq1 AzSh8fva PYBlK2Pi Ke3TgZ4I AyAIYanO oxj8Xhyd eBFnE6Bt yZyTikWQ pwGoU7Pw 2UNDkKRN qMJzkgo2 keFXbQXq pBl2QnIg ApRl3mWY wmalTJW1 TLueug8M wPQL4Qfg uACwus23 nmOk9R6w lwgZJrzJ v1UJtKdG RK629Cra U2UXFRqr d9OQLNl8 KAm1K3m5 Z13gKZ1v tNVai1nT LhpVXuVx pRib1Itj I1oLUob7 Z1nUsd5Q ZOwHehUa aXpFX29U ZsnqxlGz ivQRjOdb mB3iBEAj)
952
+
953
+ # Five servers
954
+ cache = Memcached.new(
955
+ @servers + ['localhost:43044', 'localhost:43045', 'localhost:43046'],
956
+ :prefix_key => @prefix_key
957
+ )
958
+
959
+ cache.flush
960
+ keys.each do |key|
961
+ cache.set(key, @value)
962
+ end
963
+
964
+ # Pull a server
965
+ cache = Memcached.new(
966
+ @servers + ['localhost:43044', 'localhost:43046'],
967
+ :prefix_key => @prefix_key
968
+ )
969
+
970
+ failed = 0
971
+ keys.each_with_index do |key, i|
972
+ begin
973
+ cache.get(key)
974
+ rescue Memcached::NotFound
975
+ failed += 1
976
+ end
977
+ end
978
+
979
+ assert(failed < keys.size / 3, "#{failed} failed out of #{keys.size}")
980
+ end
981
+
982
+ # Concurrency
983
+
984
+ def test_thread_contention
985
+ threads = []
986
+ 4.times do |index|
987
+ threads << Thread.new do
988
+ cache = @cache.clone
989
+ assert_nothing_raised do
990
+ cache.set("test_thread_contention_#{index}", index)
991
+ end
992
+ assert_equal index, cache.get("test_thread_contention_#{index}")
993
+ end
994
+ end
995
+ threads.each {|thread| thread.join}
996
+ end
997
+
998
+ # Hash
999
+
1000
+ def test_hash
1001
+ assert_equal 3157003241,
1002
+ Rlibmemcached.memcached_generate_hash_rvalue("test", Rlibmemcached::MEMCACHED_HASH_FNV1_32)
1003
+ end
1004
+
1005
+ # Memory cleanup
1006
+
1007
+ def test_reset
1008
+ original_struct = @cache.instance_variable_get("@struct")
1009
+ assert_nothing_raised do
1010
+ @cache.reset
1011
+ end
1012
+ assert_not_equal original_struct,
1013
+ @cache.instance_variable_get("@struct")
1014
+ end
1015
+
1016
+ private
1017
+
1018
+ def key
1019
+ caller.first[/.*[` ](.*)'/, 1] # '
1020
+ end
1021
+
1022
+ def stub_server(port)
1023
+ socket = TCPServer.new('127.0.0.1', port)
1024
+ Thread.new { socket.accept }
1025
+ socket
1026
+ end
1027
+
1028
+ end
1029
+