memcachedb-client 0.0.1

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.
@@ -0,0 +1,143 @@
1
+ == 1.5.0, 1.8.6 (default in Rails 2.2 and lower)
2
+
3
+ user system total real
4
+ set:plain:memcache-client 41.550000 0.590000 42.140000 ( 43.740685)
5
+ set:ruby:memcache-client 41.540000 0.590000 42.130000 ( 43.733796)
6
+ get:plain:memcache-client 41.920000 0.610000 42.530000 ( 44.031005)
7
+ get:ruby:memcache-client 41.940000 0.600000 42.540000 ( 44.082447)
8
+ multiget:ruby:memcache-client 46.120000 0.440000 46.560000 ( 47.354041)
9
+ missing:ruby:memcache-client 41.490000 0.580000 42.070000 ( 43.610837)
10
+ mixed:ruby:memcache-client 83.820000 1.190000 85.010000 ( 88.117077)
11
+
12
+
13
+ == 1.7.0, timeout, 1.8.6 (closest to default in Rails 2.3)
14
+ user system total real
15
+ set:plain:memcache-client 4.320000 2.280000 6.600000 ( 7.102900)
16
+ set:ruby:memcache-client 4.400000 2.300000 6.700000 ( 6.856992)
17
+ get:plain:memcache-client 9.890000 6.830000 16.720000 ( 16.984208)
18
+ get:ruby:memcache-client 10.040000 6.890000 16.930000 ( 17.141128)
19
+ multiget:ruby:memcache-client 5.350000 4.110000 9.460000 ( 9.542898)
20
+ missing:ruby:memcache-client 4.710000 3.180000 7.890000 ( 8.030969)
21
+ mixed:ruby:memcache-client 14.540000 9.200000 23.740000 ( 24.121824)
22
+
23
+ == 1.7.0, timeout, system_timer, 1.8.6
24
+ user system total real
25
+ set:plain:memcache-client 3.840000 0.640000 4.480000 ( 4.643790)
26
+ set:ruby:memcache-client 3.930000 0.650000 4.580000 ( 4.731868)
27
+ get:plain:memcache-client 8.320000 1.290000 9.610000 ( 9.903877)
28
+ get:ruby:memcache-client 8.460000 1.310000 9.770000 ( 9.986694)
29
+ multiget:ruby:memcache-client 4.250000 0.560000 4.810000 ( 4.935326)
30
+ missing:ruby:memcache-client 3.840000 0.640000 4.480000 ( 4.569696)
31
+ mixed:ruby:memcache-client 12.400000 1.960000 14.360000 ( 14.857924)
32
+
33
+ == 1.7.0, timeout, 1.9.1
34
+ user system total real
35
+ set:plain:memcache-client 2.130000 2.150000 4.280000 ( 3.774238)
36
+ set:ruby:memcache-client 2.230000 2.230000 4.460000 ( 3.883686)
37
+ get:plain:memcache-client 4.030000 4.250000 8.280000 ( 6.702740)
38
+ get:ruby:memcache-client 4.090000 4.220000 8.310000 ( 6.749134)
39
+ multiget:ruby:memcache-client 1.960000 1.840000 3.800000 ( 3.089448)
40
+ missing:ruby:memcache-client 2.110000 2.210000 4.320000 ( 3.659019)
41
+ mixed:ruby:memcache-client 6.400000 6.560000 12.960000 ( 11.116317)
42
+
43
+ == 1.7.0, no timeout, 1.9.1
44
+ user system total real
45
+ set:plain:memcache-client 0.560000 0.320000 0.880000 ( 1.849380)
46
+ set:ruby:memcache-client 0.630000 0.320000 0.950000 ( 1.968208)
47
+ get:plain:memcache-client 0.640000 0.330000 0.970000 ( 1.962473)
48
+ get:ruby:memcache-client 0.690000 0.320000 1.010000 ( 2.002295)
49
+ multiget:ruby:memcache-client 0.460000 0.110000 0.570000 ( 0.885827)
50
+ missing:ruby:memcache-client 0.530000 0.320000 0.850000 ( 1.721371)
51
+ mixed:ruby:memcache-client 1.340000 0.660000 2.000000 ( 3.973213)
52
+
53
+ == 1.7.0, no timeout, 1.8.6
54
+ user system total real
55
+ set:plain:memcache-client 1.220000 0.310000 1.530000 ( 2.763310)
56
+ set:ruby:memcache-client 1.270000 0.300000 1.570000 ( 2.806251)
57
+ get:plain:memcache-client 1.400000 0.300000 1.700000 ( 2.944343)
58
+ get:ruby:memcache-client 1.450000 0.310000 1.760000 ( 2.997234)
59
+ multiget:ruby:memcache-client 1.120000 0.110000 1.230000 ( 1.665716)
60
+ missing:ruby:memcache-client 1.160000 0.300000 1.460000 ( 2.683376)
61
+ mixed:ruby:memcache-client 2.760000 0.610000 3.370000 ( 5.851047)
62
+
63
+ == 1.7.1, timeout, 1.8.6, raw + gets SystemTimer
64
+ user system total real
65
+ set:plain:memcache-client 2.670000 0.510000 3.180000 ( 3.489509)
66
+ set:ruby:memcache-client 2.810000 0.530000 3.340000 ( 3.675955)
67
+ get:plain:memcache-client 4.380000 0.720000 5.100000 ( 5.400587)
68
+ get:ruby:memcache-client 4.490000 0.730000 5.220000 ( 5.477543)
69
+ multiget:ruby:memcache-client 2.570000 0.310000 2.880000 ( 3.034944)
70
+ missing:ruby:memcache-client 2.800000 0.530000 3.330000 ( 3.547073)
71
+ mixed:ruby:memcache-client 7.460000 1.250000 8.710000 ( 9.272177)
72
+
73
+ == 1.7.1, timeout, 1.9.1, raw + gets Timeout
74
+ user system total real
75
+ set:plain:memcache-client 1.370000 1.300000 2.670000 ( 2.708669)
76
+ set:ruby:memcache-client 1.400000 1.240000 2.640000 ( 2.713737)
77
+ get:plain:memcache-client 2.070000 2.020000 4.090000 ( 3.950879)
78
+ get:ruby:memcache-client 2.160000 2.090000 4.250000 ( 3.924613)
79
+ multiget:ruby:memcache-client 1.080000 0.820000 1.900000 ( 1.744107)
80
+ missing:ruby:memcache-client 1.330000 1.270000 2.600000 ( 2.547597)
81
+ mixed:ruby:memcache-client 3.540000 3.270000 6.810000 ( 6.735349)
82
+
83
+ == 1.7.1, timeout, 1.8.6, raw + gets SystemTimer, native binary search
84
+ user system total real
85
+ set:plain:memcache-client 1.840000 0.450000 2.290000 ( 2.651285)
86
+ set:ruby:memcache-client 1.960000 0.460000 2.420000 ( 2.712650)
87
+ get:plain:memcache-client 3.180000 0.630000 3.810000 ( 4.079930)
88
+ get:ruby:memcache-client 3.290000 0.640000 3.930000 ( 4.242648)
89
+ multiget:ruby:memcache-client 1.640000 0.250000 1.890000 ( 2.003687)
90
+ missing:ruby:memcache-client 1.940000 0.450000 2.390000 ( 2.619675)
91
+ mixed:ruby:memcache-client 5.360000 1.100000 6.460000 ( 7.040998)
92
+
93
+ == 1.7.2, timeout, 1.8.6, SystemTimer, native binary search
94
+ user system total real
95
+ set:plain:memcache-client 3.260000 0.590000 3.850000 ( 4.067382)
96
+ set:ruby:memcache-client 3.370000 0.590000 3.960000 ( 4.364004)
97
+ get:plain:memcache-client 6.740000 1.240000 7.980000 ( 8.586676)
98
+ get:ruby:memcache-client 6.780000 1.210000 7.990000 ( 8.423400)
99
+ multiget:ruby:memcache-client 3.480000 0.540000 4.020000 ( 4.288633)
100
+ missing:ruby:memcache-client 3.250000 0.590000 3.840000 ( 4.043602)
101
+ mixed:ruby:memcache-client 10.150000 1.810000 11.960000 ( 12.372054)
102
+
103
+ == 1.7.4, 1.8.6, buffered and non-blocking IO
104
+ user system total real
105
+ set:plain:memcache-client 2.450000 0.790000 3.240000 ( 3.397091)
106
+ set:ruby:memcache-client 2.490000 0.790000 3.280000 ( 3.555436)
107
+ get:plain:memcache-client 2.840000 0.810000 3.650000 ( 3.759695)
108
+ get:ruby:memcache-client 2.890000 0.790000 3.680000 ( 3.778011)
109
+ multiget:ruby:memcache-client 1.380000 0.280000 1.660000 ( 1.695290)
110
+ missing:ruby:memcache-client 2.380000 0.780000 3.160000 ( 3.251136)
111
+ mixed:ruby:memcache-client 5.360000 1.600000 6.960000 ( 7.189314)
112
+
113
+ == memcached 0.13 + libmemcached 0.25.4 versus memcache-client 1.7.4
114
+
115
+ user system total real
116
+ set:plain:noblock:memcached 0.090000 0.030000 0.120000 ( 0.277929)
117
+ set:plain:memcached 0.220000 0.270000 0.490000 ( 1.251547)
118
+ set:plain:memcache-client 0.610000 0.270000 0.880000 ( 1.670718)
119
+ set:ruby:noblock:memcached 0.150000 0.020000 0.170000 ( 0.309201)
120
+ set:ruby:memcached 0.300000 0.290000 0.590000 ( 1.390354)
121
+ set:ruby:memcache-client 0.670000 0.270000 0.940000 ( 1.713558)
122
+ get:plain:memcached 0.240000 0.270000 0.510000 ( 1.169909)
123
+ get:plain:memcache-client 0.850000 0.270000 1.120000 ( 1.885270)
124
+ get:ruby:memcached 0.270000 0.280000 0.550000 ( 1.229705)
125
+ get:ruby:memcache-client 0.890000 0.260000 1.150000 ( 1.861660)
126
+ multiget:ruby:memcached 0.190000 0.090000 0.280000 ( 0.396264)
127
+ multiget:ruby:memcache-client 0.530000 0.100000 0.630000 ( 0.901016)
128
+ missing:ruby:memcached 0.280000 0.290000 0.570000 ( 1.254400)
129
+ missing:ruby:memcached:inline 0.300000 0.290000 0.590000 ( 1.235122)
130
+ missing:ruby:memcache-client 0.570000 0.250000 0.820000 ( 1.461293)
131
+ mixed:ruby:noblock:memcached 0.540000 0.620000 1.160000 ( 2.429200)
132
+ mixed:ruby:memcached 0.580000 0.570000 1.150000 ( 2.610819)
133
+ mixed:ruby:memcache-client 1.580000 0.540000 2.120000 ( 3.632775)
134
+
135
+ == 1.7.6, 1.8.7 64-bit (Snow Leopard), SystemTimer
136
+ user system total real
137
+ set:plain:memcache-client 3.070000 0.380000 3.450000 ( 3.643275)
138
+ set:ruby:memcache-client 3.140000 0.370000 3.510000 ( 3.698602)
139
+ get:plain:memcache-client 3.480000 0.360000 3.840000 ( 3.983941)
140
+ get:ruby:memcache-client 3.540000 0.360000 3.900000 ( 4.034308)
141
+ multiget:ruby:memcache-client 1.690000 0.140000 1.830000 ( 1.889290)
142
+ missing:ruby:memcache-client 3.070000 0.360000 3.430000 ( 3.571754)
143
+ mixed:ruby:memcache-client 6.720000 0.750000 7.470000 ( 7.838771)
@@ -0,0 +1,134 @@
1
+ HERE = File.dirname(__FILE__)
2
+ $LOAD_PATH.unshift "#{HERE}/../lib"
3
+ #$LOAD_PATH << "/Library/Ruby/Gems/1.8/gems/activesupport-2.2.2/lib/active_support/vendor/memcache-client-1.5.1"
4
+
5
+ require 'benchmark'
6
+ require 'rubygems'
7
+ require 'test/unit'
8
+
9
+ $TESTING = true
10
+ require 'memcachedb' if not defined?(MemCacheDb)
11
+
12
+ class TestBenchmark < Test::Unit::TestCase
13
+
14
+ def setup
15
+ puts "Testing #{MemCacheDb::VERSION}"
16
+ # We'll use a simple @value to try to avoid spending time in Marshal,
17
+ # which is a constant penalty that both clients have to pay
18
+ @value = []
19
+ @marshalled = Marshal.dump(@value)
20
+
21
+ @opts = [
22
+ [{:servers=>['127.0.0.1:11211', '127.0.0.1:11212']}],
23
+ {
24
+ :namespace => "namespace",
25
+ # :no_reply => true,
26
+ # :timeout => nil,
27
+ }
28
+ ]
29
+ @key1 = "Short"
30
+ @key2 = "Sym1-2-3::45"*8
31
+ @key3 = "Long"*40
32
+ @key4 = "Medium"*8
33
+ # 5 and 6 are only used for multiget miss test
34
+ @key5 = "Medium2"*8
35
+ @key6 = "Long3"*40
36
+ end
37
+
38
+ def test_benchmark
39
+ Benchmark.bm(31) do |x|
40
+
41
+ n = 2500
42
+ # n = 1000
43
+
44
+ @m = MemCacheDb.new(*@opts)
45
+ x.report("set:plain:memcache-client") do
46
+ n.times do
47
+ @m.set @key1, @marshalled, 0, true
48
+ @m.set @key2, @marshalled, 0, true
49
+ @m.set @key3, @marshalled, 0, true
50
+ @m.set @key1, @marshalled, 0, true
51
+ @m.set @key2, @marshalled, 0, true
52
+ @m.set @key3, @marshalled, 0, true
53
+ end
54
+ end
55
+
56
+ @m = MemCacheDb.new(*@opts)
57
+ x.report("set:ruby:memcache-client") do
58
+ n.times do
59
+ @m.set @key1, @value
60
+ @m.set @key2, @value
61
+ @m.set @key3, @value
62
+ @m.set @key1, @value
63
+ @m.set @key2, @value
64
+ @m.set @key3, @value
65
+ end
66
+ end
67
+
68
+ @m = MemCacheDb.new(*@opts)
69
+ x.report("get:plain:memcache-client") do
70
+ n.times do
71
+ @m.get @key1, true
72
+ @m.get @key2, true
73
+ @m.get @key3, true
74
+ @m.get @key1, true
75
+ @m.get @key2, true
76
+ @m.get @key3, true
77
+ end
78
+ end
79
+
80
+ @m = MemCacheDb.new(*@opts)
81
+ x.report("get:ruby:memcache-client") do
82
+ n.times do
83
+ @m.get @key1
84
+ @m.get @key2
85
+ @m.get @key3
86
+ @m.get @key1
87
+ @m.get @key2
88
+ @m.get @key3
89
+ end
90
+ end
91
+
92
+ @m = MemCacheDb.new(*@opts)
93
+ x.report("multiget:ruby:memcache-client") do
94
+ n.times do
95
+ # We don't use the keys array because splat is slow
96
+ @m.get_multi @key1, @key2, @key3, @key4, @key5, @key6
97
+ end
98
+ end
99
+
100
+ @m = MemCacheDb.new(*@opts)
101
+ x.report("missing:ruby:memcache-client") do
102
+ n.times do
103
+ begin @m.delete @key1; rescue; end
104
+ begin @m.get @key1; rescue; end
105
+ begin @m.delete @key2; rescue; end
106
+ begin @m.get @key2; rescue; end
107
+ begin @m.delete @key3; rescue; end
108
+ begin @m.get @key3; rescue; end
109
+ end
110
+ end
111
+
112
+ @m = MemCacheDb.new(*@opts)
113
+ x.report("mixed:ruby:memcache-client") do
114
+ n.times do
115
+ @m.set @key1, @value
116
+ @m.set @key2, @value
117
+ @m.set @key3, @value
118
+ @m.get @key1
119
+ @m.get @key2
120
+ @m.get @key3
121
+ @m.set @key1, @value
122
+ @m.get @key1
123
+ @m.set @key2, @value
124
+ @m.get @key2
125
+ @m.set @key3, @value
126
+ @m.get @key3
127
+ end
128
+ end
129
+
130
+ assert true
131
+ end
132
+
133
+ end
134
+ end
@@ -0,0 +1,1220 @@
1
+ # encoding: utf-8
2
+ require 'logger'
3
+ require 'stringio'
4
+ require 'test/unit'
5
+ require 'rubygems'
6
+ begin
7
+ gem 'flexmock'
8
+ require 'flexmock/test_unit'
9
+ rescue LoadError => e
10
+ puts "Some tests require flexmock, please run `gem install flexmock`"
11
+ end
12
+
13
+ Thread.abort_on_exception = true
14
+ $TESTING = true
15
+
16
+ require File.dirname(__FILE__) + '/../lib/memcachedb' if not defined?(MemCacheDb)
17
+
18
+ class MemCacheDb
19
+
20
+ attr_writer :namespace
21
+ attr_writer :autofix_keys
22
+
23
+ end
24
+
25
+ class FakeSocket
26
+
27
+ attr_reader :written, :data
28
+
29
+ def initialize
30
+ @written = StringIO.new
31
+ @data = StringIO.new
32
+ end
33
+
34
+ def write(data)
35
+ @written.write data
36
+ end
37
+
38
+ def gets
39
+ @data.gets || 'STORED\n\r'
40
+ end
41
+
42
+ def read(arg)
43
+ @data.read arg
44
+ end
45
+
46
+ end
47
+
48
+ class Test::Unit::TestCase
49
+ def requirement(bool, msg)
50
+ if bool
51
+ yield
52
+ else
53
+ puts msg
54
+ assert true
55
+ end
56
+ end
57
+
58
+ def memcached_running?
59
+ TCPSocket.new('localhost', 11211) rescue false
60
+ end
61
+
62
+ def xprofile(name, &block)
63
+ a = Time.now
64
+ block.call
65
+ Time.now - a
66
+ end
67
+
68
+ def profile(name, &block)
69
+ require 'ruby-prof'
70
+ a = Time.now
71
+ result = RubyProf.profile(&block)
72
+ time = Time.now - a
73
+ printer = RubyProf::GraphHtmlPrinter.new(result)
74
+ File.open("#{name}.html", 'w') do |f|
75
+ printer.print(f, :min_percent=>1)
76
+ end
77
+ time
78
+ end
79
+
80
+ end
81
+
82
+ class FakeGroup
83
+ attr_reader :weight
84
+ attr_reader :servers
85
+ attr_reader :name
86
+
87
+ def initialize(server = FakeServer.new, name = nil)
88
+ @server = server
89
+ @servers = []
90
+ @servers << server
91
+ @weight = 1
92
+ @name = name || (server.host.to_s + server.port.to_s)
93
+ end
94
+
95
+ def alive?
96
+ master.alive?
97
+ end
98
+
99
+ def master
100
+ @server
101
+ end
102
+
103
+ def next_slave
104
+ @server
105
+ end
106
+ end
107
+
108
+ class FakeServer
109
+
110
+ attr_accessor :host, :port, :socket, :weight, :multithread, :status
111
+
112
+ def initialize(socket = nil)
113
+ @closed = false
114
+ @host = 'example.com'
115
+ @port = 11211
116
+ @socket = socket || FakeSocket.new
117
+ @weight = 1
118
+ @multithread = true
119
+ @status = "CONNECTED"
120
+ end
121
+
122
+ def close
123
+ # begin
124
+ # raise "Already closed"
125
+ # rescue => e
126
+ # puts e.backtrace.join("\n")
127
+ # end
128
+ @closed = true
129
+ @socket = nil
130
+ @status = "NOT CONNECTED"
131
+ end
132
+
133
+ def alive?
134
+ # puts "I'm #{@closed ? 'dead' : 'alive'}"
135
+ !@closed
136
+ end
137
+
138
+ end
139
+
140
+ class TestMemCache < Test::Unit::TestCase
141
+
142
+ def setup
143
+ @cache = MemCacheDb.new( {}, {:namespace => 'my_namespace'})
144
+ end
145
+
146
+ def util_setup_fake_server
147
+ server = FakeServer.new
148
+ server.socket.data.write "VALUE my_namespace:key 0 14\r\n"
149
+ server.socket.data.write "\004\b\"\0170123456789\r\n"
150
+ server.socket.data.write "END\r\n"
151
+ server.socket.data.rewind
152
+
153
+ group = FakeGroup.new(server)
154
+ @cache.groups = []
155
+ @cache.groups << group
156
+
157
+ return server
158
+ end
159
+
160
+
161
+ def test_add
162
+ server = FakeServer.new
163
+ server.socket.data.write "STORED\r\n"
164
+ server.socket.data.rewind
165
+
166
+ group = FakeGroup.new(server)
167
+ @cache.groups = []
168
+ @cache.groups << group
169
+
170
+ @cache.add 'key', 'value'
171
+
172
+ dumped = Marshal.dump('value')
173
+
174
+ expected = "add my_namespace:key 0 0 #{dumped.length}\r\n#{dumped}\r\n"
175
+ assert_equal expected, server.socket.written.string
176
+ end
177
+
178
+
179
+ def test_performance
180
+ requirement(memcached_running?, 'A real memcached server must be running for performance testing') do
181
+
182
+ cache = MemCacheDb.new({:servers=>['localhost:11211',"localhost:11212"]})
183
+ cache.add('a', 1, 120)
184
+ with = xprofile 'get' do
185
+ 1000.times do
186
+ cache.get('a')
187
+ end
188
+ end
189
+ puts ''
190
+ puts "1000 gets with socket timeout: #{with} sec"
191
+
192
+ cache = MemCacheDb.new([{:servers=>['localhost:11211',"localhost:11212"]}], :timeout => nil)
193
+ cache.add('a', 1, 120)
194
+ without = xprofile 'get' do
195
+ 1000.times do
196
+ cache.get('a')
197
+ end
198
+ end
199
+ puts "1000 gets without socket timeout: #{without} sec"
200
+ end
201
+ end
202
+
203
+
204
+ def test_get_multi_with_server_failure
205
+ @cache = MemCacheDb.new({:server=>'localhost:1'}, {:namespace => 'my_namespace', :logger=>nil})
206
+ s1 = FakeServer.new
207
+ s2 = FakeServer.new
208
+
209
+ g1 = FakeGroup.new(s1, "1")
210
+ g2 = FakeGroup.new(s2, "2")
211
+
212
+ # Write two messages to the socket to test failover
213
+ s1.socket.data.write "VALUE my_namespace:a 0 14\r\n\004\b\"\0170123456789\r\nEND\r\n"
214
+ s1.socket.data.rewind
215
+ s2.socket.data.write "bogus response\r\nbogus response\r\n"
216
+ s2.socket.data.rewind
217
+
218
+ @cache.groups = [g1, g2]
219
+
220
+ assert s1.alive?
221
+ assert s2.alive?
222
+ # a maps to s1, the rest map to s2
223
+ value = @cache.get_multi(['foo', 'bar', 'a', 'b', 'c'])
224
+ assert_equal({'a'=>'0123456789'}, value)
225
+ assert s1.alive?
226
+ assert !s2.alive?
227
+ end
228
+
229
+
230
+ def test_consistent_hashing
231
+ requirement(self.respond_to?(:flexmock), 'Flexmock is required to run this test') do
232
+
233
+ flexmock(MemCacheDb::Server).new_instances.should_receive(:alive?).and_return(true)
234
+
235
+ # Setup a continuum of two servers
236
+ @cache.groups = [FakeGroup.new(FakeServer.new, "1"), FakeGroup.new(FakeServer.new, "2"), FakeGroup.new(FakeServer.new, "3")]
237
+
238
+ keys = []
239
+ 1000.times do |idx|
240
+ keys << idx.to_s
241
+ end
242
+
243
+ before_continuum = keys.map {|key| @cache.get_group_for_key(key) }
244
+
245
+ @cache.groups = [FakeGroup.new(FakeServer.new, "1"), FakeGroup.new(FakeServer.new, "2"), FakeGroup.new(FakeServer.new, "3"), FakeGroup.new(FakeServer.new, "4")]
246
+
247
+ after_continuum = keys.map {|key| @cache.get_group_for_key(key) }
248
+
249
+ same_count = before_continuum.zip(after_continuum).find_all {|a| a[0].name == a[1].name }.size
250
+
251
+ # With continuum, we should see about 75% of the keys map to the same server
252
+ # With modulo, we would see about 25%.
253
+ assert same_count > 700
254
+ end
255
+ end
256
+
257
+ def test_cache_get_with_failover
258
+ @cache = MemCacheDb.new 'localhost:1', :namespace => 'my_namespace', :logger => nil#Logger.new(STDOUT)
259
+ s1 = FakeServer.new
260
+ s2 = FakeServer.new
261
+
262
+ g1 = FakeGroup.new(s1)
263
+ g2 = FakeGroup.new(s2)
264
+
265
+ # Write two messages to the socket to test failover
266
+ s1.socket.data.write "VALUE foo 0 14\r\n\004\b\"\0170123456789\r\n"
267
+ s1.socket.data.rewind
268
+ s2.socket.data.write "bogus response\r\nbogus response\r\n"
269
+ s2.socket.data.rewind
270
+
271
+ @cache.instance_variable_set(:@failover, true)
272
+ @cache.groups = [g1, g2]
273
+
274
+ assert s1.alive?
275
+ assert s2.alive?
276
+ @cache.get('foo')
277
+ assert s1.alive?
278
+ assert !s2.alive?
279
+ end
280
+
281
+ def test_cache_get_without_failover
282
+ s1 = FakeServer.new
283
+ s2 = FakeServer.new
284
+
285
+ g1 = FakeGroup.new(s1)
286
+ g2 = FakeGroup.new(s2)
287
+
288
+ s1.socket.data.write "VALUE foo 0 14\r\n\004\b\"\0170123456789\r\n"
289
+ s1.socket.data.rewind
290
+ s2.socket.data.write "bogus response\r\nbogus response\r\n"
291
+ s2.socket.data.rewind
292
+
293
+ @cache.instance_variable_set(:@failover, false)
294
+ @cache.groups = [g1, g2]
295
+
296
+ assert s1.alive?
297
+ assert s2.alive?
298
+ e = assert_raise MemCacheDb::MemCacheDbError do
299
+ @cache.get('foo')
300
+ end
301
+ assert s1.alive?
302
+ assert !s2.alive?
303
+
304
+ assert_equal "No servers available", e.message
305
+ end
306
+
307
+ def test_cache_get
308
+ server = util_setup_fake_server
309
+
310
+ assert_equal "\004\b\"\0170123456789",
311
+ @cache.cache_get(server, 'my_namespace:key')
312
+
313
+ assert_equal "get my_namespace:key\r\n",
314
+ server.socket.written.string
315
+ end
316
+
317
+ def test_cache_get_EOF
318
+ server = util_setup_fake_server
319
+ server.socket.data.string = ''
320
+
321
+ e = assert_raise IndexError do
322
+ @cache.cache_get server, 'my_namespace:key'
323
+ end
324
+
325
+ assert_equal "No connection to server (NOT CONNECTED)", e.message
326
+ end
327
+
328
+ def test_cache_get_bad_state
329
+ server = FakeServer.new
330
+
331
+ # Write two messages to the socket to test failover
332
+ server.socket.data.write "bogus response\r\nbogus response\r\n"
333
+ server.socket.data.rewind
334
+
335
+ group = FakeGroup.new(server)
336
+ @cache.groups = []
337
+ @cache.groups << group
338
+
339
+ e = assert_raise IndexError do
340
+ @cache.cache_get(server, 'my_namespace:key')
341
+ end
342
+
343
+ assert_match(/#{Regexp.quote 'No connection to server (NOT CONNECTED)'}/, e.message)
344
+
345
+ assert !server.alive?
346
+ end
347
+
348
+ def test_cache_get_miss
349
+ socket = FakeSocket.new
350
+ socket.data.write "END\r\n"
351
+ socket.data.rewind
352
+ server = FakeServer.new socket
353
+
354
+ assert_equal nil, @cache.cache_get(server, 'my_namespace:key')
355
+
356
+ assert_equal "get my_namespace:key\r\n",
357
+ socket.written.string
358
+ end
359
+
360
+ def test_cache_get_multi
361
+ server = util_setup_fake_server
362
+ server.socket.data.write "VALUE foo 0 7\r\n"
363
+ server.socket.data.write "\004\b\"\bfoo\r\n"
364
+ server.socket.data.write "VALUE bar 0 7\r\n"
365
+ server.socket.data.write "\004\b\"\bbar\r\n"
366
+ server.socket.data.write "END\r\n"
367
+ server.socket.data.rewind
368
+
369
+ result = @cache.cache_get_multi server, 'foo bar baz'
370
+
371
+ assert_equal 2, result.length
372
+ assert_equal "\004\b\"\bfoo", result['foo']
373
+ assert_equal "\004\b\"\bbar", result['bar']
374
+ end
375
+
376
+ def test_cache_get_multi_EOF
377
+ server = util_setup_fake_server
378
+ server.socket.data.string = ''
379
+
380
+ e = assert_raise IndexError do
381
+ @cache.cache_get_multi server, 'my_namespace:key'
382
+ end
383
+
384
+ assert_equal "No connection to server (NOT CONNECTED)", e.message
385
+ end
386
+
387
+ def test_cache_get_multi_bad_state
388
+ server = FakeServer.new
389
+
390
+ # Write two messages to the socket to test failover
391
+ server.socket.data.write "bogus response\r\nbogus response\r\n"
392
+ server.socket.data.rewind
393
+
394
+ group = FakeGroup.new(server)
395
+ @cache.groups = []
396
+ @cache.groups << group
397
+
398
+ e = assert_raise IndexError do
399
+ @cache.cache_get_multi server, 'my_namespace:key'
400
+ end
401
+
402
+ assert_match(/#{Regexp.quote 'No connection to server (NOT CONNECTED)'}/, e.message)
403
+
404
+ assert !server.alive?
405
+ end
406
+
407
+ def test_multithread_error
408
+ server = FakeServer.new
409
+ server.multithread = false
410
+
411
+ @cache = MemCacheDb.new(['localhost:1'], :multithread => false)
412
+
413
+ server.socket.data.write "bogus response\r\nbogus response\r\n"
414
+ server.socket.data.rewind
415
+
416
+ group = FakeGroup.new(server)
417
+ @cache.groups = []
418
+ @cache.groups << group
419
+
420
+ assert_nothing_raised do
421
+ @cache.set 'a', 1
422
+ end
423
+
424
+ passed = true
425
+ Thread.new do
426
+ begin
427
+ @cache.set 'b', 2
428
+ passed = false
429
+ rescue MemCacheDb::MemCacheDbError => me
430
+ passed = me.message =~ /multiple threads/
431
+ end
432
+ end
433
+ assert passed
434
+ end
435
+
436
+ def test_initialize
437
+ cache = MemCacheDb.new ([], {:namespace => 'my_namespace', :readonly => true})
438
+
439
+ assert_equal 'my_namespace', cache.namespace
440
+ assert_equal true, cache.readonly?
441
+ assert_equal true, cache.groups.empty?
442
+ end
443
+
444
+ def test_initialize_compatible
445
+ cache = MemCacheDb.new ([:servers=>['localhost:11211', 'localhost:11212']],
446
+ :namespace => 'my_namespace', :readonly => true)
447
+
448
+ assert_equal 'my_namespace', cache.namespace
449
+ assert_equal true, cache.readonly?
450
+ assert_equal false, cache.groups.empty?
451
+ end
452
+
453
+ def test_initialize_compatible_no_hash
454
+ cache = MemCacheDb.new (:servers=>['localhost:11211', 'localhost:11212'])
455
+
456
+ assert_equal nil, cache.namespace
457
+ assert_equal false, cache.readonly?
458
+ assert_equal false, cache.groups.empty?
459
+ end
460
+
461
+ def test_initialize_compatible_bad_arg
462
+ e = assert_raise ArgumentError do
463
+ cache = MemCacheDb.new Object.new
464
+ end
465
+
466
+ assert_equal 'first argument must be Array, Hash', e.message
467
+ end
468
+
469
+ def test_initialize_too_many_args
470
+ assert_raises ArgumentError do
471
+ MemCacheDb.new 1, 2, 3
472
+ end
473
+ end
474
+
475
+
476
+ def test_initialize_multiple_servers
477
+ cache = MemCacheDb.new([{:servers=>['localhost:11211', 'localhost:11212']}, {:servers=>['localhost:11211', 'localhost:11212']}],
478
+ {:namespace => 'my_namespace', :readonly => true})
479
+
480
+ assert_equal 'my_namespace', cache.namespace
481
+ assert_equal true, cache.readonly?
482
+ assert_equal false, cache.groups.empty?
483
+ assert !cache.instance_variable_get(:@continuum).empty?
484
+ end
485
+
486
+ def test_decr
487
+ server = FakeServer.new
488
+ server.socket.data.write "5\r\n"
489
+ server.socket.data.rewind
490
+
491
+ group = FakeGroup.new(server)
492
+ @cache.groups = []
493
+ @cache.groups << group
494
+
495
+ value = @cache.decr 'key'
496
+
497
+ assert_equal "decr my_namespace:key 1\r\n",
498
+ @cache.groups.first.servers.first.socket.written.string
499
+
500
+ assert_equal 5, value
501
+ end
502
+
503
+ def test_decr_not_found
504
+ server = FakeServer.new
505
+ server.socket.data.write "NOT_FOUND\r\n"
506
+ server.socket.data.rewind
507
+
508
+ group = FakeGroup.new(server)
509
+ @cache.groups = []
510
+ @cache.groups << group
511
+
512
+ value = @cache.decr 'key'
513
+
514
+ assert_equal "decr my_namespace:key 1\r\n",
515
+ @cache.groups.first.servers.first.socket.written.string
516
+
517
+ assert_equal nil, value
518
+ end
519
+
520
+ def test_decr_space_padding
521
+ server = FakeServer.new
522
+ server.socket.data.write "5 \r\n"
523
+ server.socket.data.rewind
524
+
525
+ group = FakeGroup.new(server)
526
+ @cache.groups = []
527
+ @cache.groups << group
528
+
529
+ value = @cache.decr 'key'
530
+
531
+ assert_equal "decr my_namespace:key 1\r\n",
532
+ @cache.groups.first.servers.first.socket.written.string
533
+
534
+ assert_equal 5, value
535
+ end
536
+
537
+ def test_get
538
+ util_setup_fake_server
539
+
540
+ value = @cache.get 'key'
541
+
542
+ assert_equal "get my_namespace:key\r\n",
543
+ @cache.groups.first.servers.first.socket.written.string
544
+
545
+ assert_equal '0123456789', value
546
+ end
547
+
548
+
549
+ def test_fetch_without_a_block
550
+ server = FakeServer.new
551
+ server.socket.data.write "END\r\n"
552
+ server.socket.data.rewind
553
+
554
+ group = FakeGroup.new(server)
555
+ @cache.groups = [group]
556
+
557
+ flexmock(@cache).should_receive(:get).with('key', false).and_return(nil)
558
+
559
+ value = @cache.fetch('key', 1)
560
+ assert_equal nil, value
561
+ end
562
+
563
+ def test_fetch_miss
564
+ server = FakeServer.new
565
+ server.socket.data.write "END\r\n"
566
+ server.socket.data.rewind
567
+
568
+ group = FakeGroup.new(server)
569
+ @cache.groups = [group]
570
+
571
+ flexmock(@cache).should_receive(:get).with('key', false).and_return(nil)
572
+ flexmock(@cache).should_receive(:add).with('key', 'value', 1, false)
573
+
574
+ value = @cache.fetch('key', 1) { 'value' }
575
+
576
+ assert_equal 'value', value
577
+ end
578
+
579
+ def test_fetch_hit
580
+ server = FakeServer.new
581
+ server.socket.data.write "END\r\n"
582
+ server.socket.data.rewind
583
+
584
+ group = FakeGroup.new(server)
585
+ @cache.groups = [group]
586
+
587
+ flexmock(@cache).should_receive(:get).with('key', false).and_return('value')
588
+ flexmock(@cache).should_receive(:add).never
589
+
590
+ value = @cache.fetch('key', 1) { raise 'Should not be called.' }
591
+
592
+ assert_equal 'value', value
593
+ end
594
+
595
+ def test_get_bad_key
596
+ util_setup_fake_server
597
+ assert_raise ArgumentError do @cache.get 'k y' end
598
+
599
+ util_setup_fake_server
600
+ assert_raise ArgumentError do @cache.get 'k' * 250 end
601
+ end
602
+
603
+ def test_get_cache_get_IOError
604
+ socket = Object.new
605
+ def socket.write(arg) raise IOError, 'some io error'; end
606
+ server = FakeServer.new socket
607
+
608
+ group = FakeGroup.new(server)
609
+ @cache.groups = []
610
+ @cache.groups << group
611
+
612
+ e = assert_raise MemCacheDb::MemCacheDbError do
613
+ @cache.get 'my_namespace:key'
614
+ end
615
+
616
+ assert_equal 'some io error', e.message
617
+ end
618
+
619
+
620
+ def test_get_cache_get_SystemCallError
621
+ socket = Object.new
622
+ def socket.write(arg) raise SystemCallError, 'some syscall error'; end
623
+ server = FakeServer.new socket
624
+
625
+ group = FakeGroup.new(server)
626
+ @cache.groups = []
627
+ @cache.groups << group
628
+
629
+ e = assert_raise MemCacheDb::MemCacheDbError do
630
+ @cache.get 'my_namespace:key'
631
+ end
632
+
633
+ assert_equal 'unknown error - some syscall error', e.message
634
+ end
635
+
636
+ def test_get_no_connection
637
+ e = assert_raise MemCacheDb::MemCacheDbError do
638
+ @cache.groups = [:servers=>'localhost:1']
639
+ end
640
+
641
+ assert_match(/^No Master Server found/, e.message)
642
+ end
643
+
644
+ def test_get_no_servers
645
+ @cache.groups = []
646
+ e = assert_raise MemCacheDb::MemCacheDbError do
647
+ @cache.get 'key'
648
+ end
649
+
650
+ assert_equal 'No active servers', e.message
651
+ end
652
+
653
+ def test_get_multi
654
+ server = FakeServer.new
655
+ server.socket.data.write "VALUE my_namespace:key 0 14\r\n"
656
+ server.socket.data.write "\004\b\"\0170123456789\r\n"
657
+ server.socket.data.write "VALUE my_namespace:keyb 0 14\r\n"
658
+ server.socket.data.write "\004\b\"\0179876543210\r\n"
659
+ server.socket.data.write "END\r\n"
660
+ server.socket.data.rewind
661
+
662
+ group = FakeGroup.new(server)
663
+ @cache.groups = []
664
+ @cache.groups << group
665
+
666
+ values = @cache.get_multi 'key', 'keyb'
667
+
668
+ assert_equal "get my_namespace:key my_namespace:keyb\r\n",
669
+ server.socket.written.string
670
+
671
+ expected = { 'key' => '0123456789', 'keyb' => '9876543210' }
672
+
673
+ assert_equal expected.sort, values.sort
674
+ end
675
+
676
+ def test_get_raw
677
+ server = FakeServer.new
678
+ server.socket.data.write "VALUE my_namespace:key 0 10\r\n"
679
+ server.socket.data.write "0123456789\r\n"
680
+ server.socket.data.write "END\r\n"
681
+ server.socket.data.rewind
682
+
683
+ group = FakeGroup.new(server)
684
+ @cache.groups = []
685
+ @cache.groups << group
686
+
687
+
688
+ value = @cache.get 'key', true
689
+
690
+ assert_equal "get my_namespace:key\r\n",
691
+ @cache.groups.first.servers.first.socket.written.string
692
+
693
+ assert_equal '0123456789', value
694
+ end
695
+
696
+ def test_get_server_for_key_no_servers
697
+ @cache.groups = []
698
+
699
+ e = assert_raise MemCacheDb::MemCacheDbError do
700
+ @cache.get_group_for_key 'key'
701
+ end
702
+
703
+ assert_equal 'No servers available', e.message
704
+ end
705
+
706
+ def test_get_server_for_key_spaces
707
+ e = assert_raise ArgumentError do
708
+ @cache.get_group_for_key 'space key'
709
+ end
710
+ assert_equal 'illegal character in key "space key"', e.message
711
+ end
712
+
713
+
714
+ def test_get_server_for_key_length
715
+ @cache.groups = [FakeGroup.new]
716
+ @cache.get_group_for_key 'x' * 250
717
+ long_key = 'x' * 251
718
+ e = assert_raise ArgumentError do
719
+ @cache.get_group_for_key long_key
720
+ end
721
+ assert_equal "key too long #{long_key.inspect}", e.message
722
+ end
723
+
724
+ def test_incr
725
+ server = FakeServer.new
726
+ server.socket.data.write "5\r\n"
727
+ server.socket.data.rewind
728
+
729
+ group = FakeGroup.new(server)
730
+ @cache.groups = []
731
+ @cache.groups << group
732
+
733
+ value = @cache.incr 'key'
734
+
735
+ assert_equal "incr my_namespace:key 1\r\n",
736
+ @cache.groups.first.servers.first.socket.written.string
737
+
738
+ assert_equal 5, value
739
+ end
740
+
741
+ def test_incr_not_found
742
+ server = FakeServer.new
743
+ server.socket.data.write "NOT_FOUND\r\n"
744
+ server.socket.data.rewind
745
+
746
+ group = FakeGroup.new(server)
747
+ @cache.groups = []
748
+ @cache.groups << group
749
+
750
+ value = @cache.incr 'key'
751
+
752
+ assert_equal "incr my_namespace:key 1\r\n",
753
+ @cache.groups.first.servers.first.socket.written.string
754
+
755
+ assert_equal nil, value
756
+ end
757
+
758
+ def test_incr_space_padding
759
+ server = FakeServer.new
760
+ server.socket.data.write "5 \r\n"
761
+ server.socket.data.rewind
762
+
763
+ group = FakeGroup.new(server)
764
+ @cache.groups = []
765
+ @cache.groups << group
766
+
767
+ value = @cache.incr 'key'
768
+
769
+ assert_equal "incr my_namespace:key 1\r\n",
770
+ @cache.groups.first.servers.first.socket.written.string
771
+
772
+ assert_equal 5, value
773
+ end
774
+
775
+ def test_make_cache_key
776
+ assert_equal 'my_namespace:key', @cache.make_cache_key('key')
777
+ @cache.namespace = nil
778
+ assert_equal 'key', @cache.make_cache_key('key')
779
+ end
780
+
781
+ def test_make_cache_key_without_autofix
782
+ @cache.autofix_keys = false
783
+
784
+ key = "keys with more than two hundred and fifty characters can cause problems, because they get truncated and start colliding with each other. It's not a common occurrence, but when it happens is very hard to debug. the autofix option takes care of that for you"
785
+ hash = Digest::SHA1.hexdigest(key)
786
+ @cache.namespace = nil
787
+ assert_equal key, @cache.make_cache_key(key)
788
+ end
789
+
790
+ def test_make_cache_key_with_autofix
791
+ @cache.autofix_keys = true
792
+
793
+ @cache.namespace = "my_namespace"
794
+ assert_equal 'my_namespace:key', @cache.make_cache_key('key')
795
+ @cache.namespace = nil
796
+ assert_equal 'key', @cache.make_cache_key('key')
797
+
798
+ key = "keys with more than two hundred and fifty characters can cause problems, because they get truncated and start colliding with each other. It's not a common occurrence, but when it happens is very hard to debug. the autofix option takes care of that for you"
799
+ hash = Digest::SHA1.hexdigest(key)
800
+ @cache.namespace = "my_namespace"
801
+ assert_equal "my_namespace:#{hash}-autofixed", @cache.make_cache_key(key)
802
+ @cache.namespace = nil
803
+ assert_equal "#{hash}-autofixed", @cache.make_cache_key(key)
804
+
805
+ key = "a short key with spaces"
806
+ hash = Digest::SHA1.hexdigest(key)
807
+ @cache.namespace = "my_namespace"
808
+ assert_equal "my_namespace:#{hash}-autofixed", @cache.make_cache_key(key)
809
+ @cache.namespace = nil
810
+ assert_equal "#{hash}-autofixed", @cache.make_cache_key(key)
811
+
812
+ # namespace + separator + key > 250
813
+ key = 'k' * 240
814
+ hash = Digest::SHA1.hexdigest(key)
815
+ @cache.namespace = 'n' * 10
816
+ assert_equal "#{@cache.namespace}:#{hash}-autofixed", @cache.make_cache_key(key)
817
+ end
818
+
819
+ def test_servers
820
+ server = FakeServer.new
821
+ group = FakeGroup.new(server)
822
+ @cache.groups = []
823
+ @cache.groups << group
824
+ assert_equal [group], @cache.groups
825
+ end
826
+
827
+ def test_set
828
+ server = FakeServer.new
829
+ server.socket.data.write "STORED\r\n"
830
+ server.socket.data.rewind
831
+ group = FakeGroup.new(server)
832
+ @cache.groups = []
833
+ @cache.groups << group
834
+
835
+ @cache.set 'key', 'value'
836
+
837
+ dumped = Marshal.dump('value')
838
+ expected = "set my_namespace:key 0 0 #{dumped.length}\r\n#{dumped}\r\n"
839
+ # expected = "set my_namespace:key 0 0 9\r\n\004\b\"\nvalue\r\n"
840
+ assert_equal expected, server.socket.written.string
841
+ end
842
+
843
+ def test_set_expiry
844
+ server = FakeServer.new
845
+ server.socket.data.write "STORED\r\n"
846
+ server.socket.data.rewind
847
+ group = FakeGroup.new(server)
848
+ @cache.groups = []
849
+ @cache.groups << group
850
+
851
+ @cache.set 'key', 'value', 5
852
+
853
+ dumped = Marshal.dump('value')
854
+ expected = "set my_namespace:key 0 5 #{dumped.length}\r\n#{dumped}\r\n"
855
+ assert_equal expected, server.socket.written.string
856
+ end
857
+
858
+ def test_set_raw
859
+ server = FakeServer.new
860
+ server.socket.data.write "STORED\r\n"
861
+ server.socket.data.rewind
862
+ group = FakeGroup.new(server)
863
+ @cache.groups = []
864
+ @cache.groups << group
865
+
866
+ @cache.set 'key', 'value', 0, true
867
+
868
+ expected = "set my_namespace:key 0 0 5\r\nvalue\r\n"
869
+ assert_equal expected, server.socket.written.string
870
+ end
871
+
872
+ def test_set_readonly
873
+ cache = MemCacheDb.new( [FakeGroup.new], :readonly => true)
874
+
875
+ e = assert_raise MemCacheDb::MemCacheDbError do
876
+ cache.set 'key', 'value'
877
+ end
878
+
879
+ assert_equal 'Update of readonly cache', e.message
880
+ end
881
+
882
+ def test_check_size_on
883
+ cache = MemCacheDb.new( [FakeGroup.new], :check_size => true)
884
+
885
+ server = FakeServer.new
886
+ server.socket.data.write "STORED\r\n"
887
+ server.socket.data.rewind
888
+
889
+ group = FakeGroup.new(server)
890
+ cache.groups = []
891
+ cache.groups << group
892
+
893
+ e = assert_raise MemCacheDb::MemCacheDbError do
894
+ cache.set 'key', 'v' * 1048577
895
+ end
896
+
897
+ assert_equal 'Value too large, MemCacheDbd can only store 1MB of data per key', e.message
898
+ end
899
+
900
+ def test_check_size_off
901
+ cache = MemCacheDb.new([FakeGroup.new], :check_size => false)
902
+
903
+ server = FakeServer.new
904
+ server.socket.data.write "STORED\r\n"
905
+ server.socket.data.rewind
906
+
907
+ group = FakeGroup.new(server)
908
+ cache.groups = []
909
+ cache.groups << group
910
+
911
+ assert_nothing_raised do
912
+ cache.set 'key', 'v' * 1048577
913
+ end
914
+ end
915
+
916
+ def test_set_too_big
917
+ server = FakeServer.new
918
+
919
+ # Write two messages to the socket to test failover
920
+ server.socket.data.write "SERVER_ERROR\r\nSERVER_ERROR object too large for cache\r\n"
921
+ server.socket.data.rewind
922
+
923
+ group = FakeGroup.new(server)
924
+ @cache.groups = []
925
+ @cache.groups << group
926
+
927
+ e = assert_raise MemCacheDb::MemCacheDbError do
928
+ @cache.set 'key', 'v'
929
+ end
930
+
931
+ assert_match(/object too large for cache/, e.message)
932
+ end
933
+
934
+ def test_prepend
935
+ server = FakeServer.new
936
+ server.socket.data.write "STORED\r\n"
937
+ server.socket.data.rewind
938
+ group = FakeGroup.new(server)
939
+ @cache.groups = []
940
+ @cache.groups << group
941
+
942
+ @cache.prepend 'key', 'value'
943
+
944
+ dumped = Marshal.dump('value')
945
+
946
+ expected = "prepend my_namespace:key 0 0 5\r\nvalue\r\n"
947
+ assert_equal expected, server.socket.written.string
948
+ end
949
+
950
+ def test_append
951
+ server = FakeServer.new
952
+ server.socket.data.write "STORED\r\n"
953
+ server.socket.data.rewind
954
+ group = FakeGroup.new(server)
955
+ @cache.groups = []
956
+ @cache.groups << group
957
+
958
+ @cache.append 'key', 'value'
959
+
960
+ expected = "append my_namespace:key 0 0 5\r\nvalue\r\n"
961
+ assert_equal expected, server.socket.written.string
962
+ end
963
+
964
+ def test_replace
965
+ server = FakeServer.new
966
+ server.socket.data.write "STORED\r\n"
967
+ server.socket.data.rewind
968
+ group = FakeGroup.new(server)
969
+ @cache.groups = []
970
+ @cache.groups << group
971
+
972
+ @cache.replace 'key', 'value', 150
973
+
974
+ dumped = Marshal.dump('value')
975
+
976
+ expected = "replace my_namespace:key 0 150 #{dumped.length}\r\n#{dumped}\r\n"
977
+ assert_equal expected, server.socket.written.string
978
+ end
979
+
980
+ def test_add_exists
981
+ server = FakeServer.new
982
+ server.socket.data.write "NOT_STORED\r\n"
983
+ server.socket.data.rewind
984
+ group = FakeGroup.new(server)
985
+ @cache.groups = []
986
+ @cache.groups << group
987
+
988
+ @cache.add 'key', 'value'
989
+
990
+ dumped = Marshal.dump('value')
991
+ expected = "add my_namespace:key 0 0 #{dumped.length}\r\n#{dumped}\r\n"
992
+ assert_equal expected, server.socket.written.string
993
+ end
994
+
995
+ def test_add_expiry
996
+ server = FakeServer.new
997
+ server.socket.data.write "STORED\r\n"
998
+ server.socket.data.rewind
999
+ group = FakeGroup.new(server)
1000
+ @cache.groups = []
1001
+ @cache.groups << group
1002
+
1003
+ @cache.add 'key', 'value', 5
1004
+
1005
+ dumped = Marshal.dump('value')
1006
+ expected = "add my_namespace:key 0 5 #{dumped.length}\r\n#{dumped}\r\n"
1007
+ assert_equal expected, server.socket.written.string
1008
+ end
1009
+
1010
+ def test_add_raw
1011
+ server = FakeServer.new
1012
+ server.socket.data.write "STORED\r\n"
1013
+ server.socket.data.rewind
1014
+ group = FakeGroup.new(server)
1015
+ @cache.groups = []
1016
+ @cache.groups << group
1017
+
1018
+ @cache.add 'key', 'value', 0, true
1019
+
1020
+ expected = "add my_namespace:key 0 0 5\r\nvalue\r\n"
1021
+ assert_equal expected, server.socket.written.string
1022
+ end
1023
+
1024
+ def test_add_raw_int
1025
+ server = FakeServer.new
1026
+ server.socket.data.write "STORED\r\n"
1027
+ server.socket.data.rewind
1028
+ group = FakeGroup.new(server)
1029
+ @cache.groups = []
1030
+ @cache.groups << group
1031
+
1032
+ @cache.add 'key', 12, 0, true
1033
+
1034
+ expected = "add my_namespace:key 0 0 2\r\n12\r\n"
1035
+ assert_equal expected, server.socket.written.string
1036
+ end
1037
+
1038
+ def test_add_readonly
1039
+ cache = MemCacheDb.new ([FakeGroup.new],:readonly => true)
1040
+
1041
+ e = assert_raise MemCacheDb::MemCacheDbError do
1042
+ cache.add 'key', 'value'
1043
+ end
1044
+
1045
+ assert_equal 'Update of readonly cache', e.message
1046
+ end
1047
+
1048
+ def test_delete
1049
+ server = FakeServer.new
1050
+ group = FakeGroup.new(server)
1051
+ @cache.groups = []
1052
+ @cache.groups << group
1053
+
1054
+ @cache.delete 'key'
1055
+
1056
+ expected = "delete my_namespace:key\r\n"
1057
+ assert_equal expected, group.master.socket.written.string
1058
+ end
1059
+
1060
+ def test_delete_with_expiry
1061
+ server = FakeServer.new
1062
+ group = FakeGroup.new(server)
1063
+ @cache.groups = []
1064
+ @cache.groups << group
1065
+
1066
+ @cache.delete 'key', 300
1067
+
1068
+ expected = "delete my_namespace:key\r\n"
1069
+ assert_equal expected, group.master.socket.written.string
1070
+ end
1071
+
1072
+
1073
+
1074
+
1075
+ def test_basic_threaded_operations_should_work
1076
+ cache = MemCacheDb.new ([FakeGroup.new], :multithread => true,
1077
+ :namespace => 'my_namespace',
1078
+ :readonly => false)
1079
+
1080
+ server = FakeServer.new
1081
+ server.socket.data.write "STORED\r\n"
1082
+ server.socket.data.rewind
1083
+
1084
+ group = FakeGroup.new(server)
1085
+ cache.groups = []
1086
+ cache.groups << group
1087
+
1088
+ assert cache.multithread
1089
+
1090
+ assert_nothing_raised do
1091
+ cache.set "test", "test value"
1092
+ end
1093
+
1094
+ output = server.socket.written.string
1095
+ assert_match(/set my_namespace:test/, output)
1096
+ assert_match(/test value/, output)
1097
+ end
1098
+
1099
+ def test_namespace_separator
1100
+ cache = MemCacheDb.new ( [FakeGroup.new], :namespace => 'ns', :namespace_separator => '')
1101
+
1102
+ server = FakeServer.new
1103
+ server.socket.data.write "STORED\r\n"
1104
+ server.socket.data.rewind
1105
+
1106
+ group = FakeGroup.new(server)
1107
+ cache.groups = []
1108
+ cache.groups << group
1109
+
1110
+ assert_nothing_raised do
1111
+ cache.set "test", "test value"
1112
+ end
1113
+
1114
+ output = server.socket.written.string
1115
+ assert_match(/set nstest/, output)
1116
+ assert_match(/test value/, output)
1117
+ end
1118
+
1119
+ def test_basic_unthreaded_operations_should_work
1120
+ cache = MemCacheDb.new ( [FakeGroup.new], :multithread => false,
1121
+ :namespace => 'my_namespace',
1122
+ :readonly => false)
1123
+
1124
+ server = FakeServer.new
1125
+ server.socket.data.write "STORED\r\n"
1126
+ server.socket.data.rewind
1127
+
1128
+ group = FakeGroup.new(server)
1129
+ cache.groups = []
1130
+ cache.groups << group
1131
+
1132
+ assert !cache.multithread
1133
+
1134
+ assert_nothing_raised do
1135
+ cache.set "test", "test value"
1136
+ end
1137
+
1138
+ output = server.socket.written.string
1139
+ assert_match(/set my_namespace:test/, output)
1140
+ assert_match(/test value/, output)
1141
+ end
1142
+
1143
+
1144
+
1145
+ def util_setup_server(memcache, host, responses)
1146
+ server = MemCacheDb::Server.new memcache, host
1147
+ server.instance_variable_set :@sock, StringIO.new(responses)
1148
+
1149
+ group = FakeGroup.new(server)
1150
+ @cache.groups = []
1151
+ @cache.groups << group
1152
+
1153
+ return server
1154
+ end
1155
+
1156
+ def test_crazy_multithreaded_access
1157
+ requirement(memcached_running?, 'A real memcached server must be running for performance testing') do
1158
+
1159
+ # Use a null logger to verify logging doesn't blow up at runtime
1160
+ cache = MemCacheDb.new([{:servers=>['localhost:11211', 'localhost:11212']}], :logger => Logger.new('/dev/null'))
1161
+ workers = []
1162
+
1163
+
1164
+
1165
+ # Have a bunch of threads perform a bunch of operations at the same time.
1166
+ # Verify the result of each operation to ensure the request and response
1167
+ # are not intermingled between threads.
1168
+ 10.times do
1169
+ workers << Thread.new do
1170
+ 100.times do
1171
+ cache.set('a', 9)
1172
+ cache.set('b', 11)
1173
+ cache.add('c', 10, 0, true)
1174
+ cache.set('d', 'a', 100, true)
1175
+ cache.set('e', 'x', 100, true)
1176
+ cache.set('f', 'zzz')
1177
+ cache.append('d', 'b')
1178
+ cache.prepend('e', 'y')
1179
+ assert_equal "NOT_STORED\r\n", cache.add('a', 11)
1180
+ assert_equal({ 'a' => 9, 'b' => 11 }, cache.get_multi(['a', 'b']))
1181
+ inc = cache.incr('c', 10)
1182
+ assert_equal 0, inc % 5
1183
+ assert inc > 14
1184
+ assert cache.decr('c', 5) > 14
1185
+ assert_equal 11, cache.get('b')
1186
+ d = cache.get('d', true)
1187
+ assert_match(/\Aab*\Z/, d)
1188
+ e = cache.get('e', true)
1189
+ assert_match(/\Ay*x\Z/, e)
1190
+ end
1191
+ end
1192
+ end
1193
+
1194
+ workers.each { |w| w.join }
1195
+ end
1196
+ end
1197
+ def test_stats
1198
+ socket = FakeSocket.new
1199
+ 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"
1200
+ socket.data.rewind
1201
+ server = FakeServer.new socket
1202
+ def server.host() 'localhost'; end
1203
+ def server.port() 11211; end
1204
+
1205
+ group = FakeGroup.new(server)
1206
+ @cache.groups = []
1207
+ @cache.groups << group
1208
+
1209
+ expected = {
1210
+ 'localhost:11211' => {
1211
+ 'pid' => 20188, 'total_items' => 32, 'version' => '1.2.3',
1212
+ 'rusage_user' => 1.0003, 'dummy' => 'ok'
1213
+ }
1214
+ }
1215
+ assert_equal expected, @cache.stats
1216
+
1217
+ assert_equal "stats\r\n", socket.written.string
1218
+ end
1219
+ end
1220
+