remcached 0.3.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,268 @@
1
+ $: << File.dirname(__FILE__) + '/../lib'
2
+ require 'remcached'
3
+
4
+ describe Memcached do
5
+ def run(&block)
6
+ EM.run do
7
+ Memcached.servers = %w(127.0.0.2 localhost:11212 localhost localhost)
8
+
9
+ @timer = EM::PeriodicTimer.new(0.01) do
10
+ # at least localhost & localhost
11
+ if Memcached.usable_clients.length >= 2
12
+ @timer.cancel
13
+ block.call
14
+ end
15
+ end
16
+
17
+ end
18
+ end
19
+ def stop
20
+ Memcached.servers = []
21
+ EM.stop
22
+ end
23
+
24
+
25
+ context "when doing a simple operation" do
26
+ it "should add a value" do
27
+ run do
28
+ Memcached.add(:key => 'Hello',
29
+ :value => 'World') do |result|
30
+ result.should be_kind_of(Memcached::Response)
31
+ result[:status].should == Memcached::Errors::NO_ERROR
32
+ result[:cas].should_not == 0
33
+ stop
34
+ end
35
+ end
36
+ end
37
+
38
+ it "should get a value" do
39
+ run do
40
+ Memcached.get(:key => 'Hello') do |result|
41
+ result.should be_kind_of(Memcached::Response)
42
+ result[:status].should == Memcached::Errors::NO_ERROR
43
+ result[:value].should == 'World'
44
+ result[:cas].should_not == 0
45
+ @old_cas = result[:cas]
46
+ stop
47
+ end
48
+ end
49
+ end
50
+
51
+ it "should set a value" do
52
+ run do
53
+ Memcached.set(:key => 'Hello',
54
+ :value => 'Planet') do |result|
55
+ result.should be_kind_of(Memcached::Response)
56
+ result[:status].should == Memcached::Errors::NO_ERROR
57
+ result[:cas].should_not == 0
58
+ result[:cas].should_not == @old_cas
59
+ stop
60
+ end
61
+ end
62
+ end
63
+
64
+ it "should get a value" do
65
+ run do
66
+ Memcached.get(:key => 'Hello') do |result|
67
+ result.should be_kind_of(Memcached::Response)
68
+ result[:status].should == Memcached::Errors::NO_ERROR
69
+ result[:value].should == 'Planet'
70
+ result[:cas].should_not == @old_cas
71
+ stop
72
+ end
73
+ end
74
+ end
75
+
76
+ it "should delete a value" do
77
+ run do
78
+ Memcached.delete(:key => 'Hello') do |result|
79
+ result.should be_kind_of(Memcached::Response)
80
+ result[:status].should == Memcached::Errors::NO_ERROR
81
+ stop
82
+ end
83
+ end
84
+ end
85
+
86
+ it "should not get a value" do
87
+ run do
88
+ Memcached.get(:key => 'Hello') do |result|
89
+ result.should be_kind_of(Memcached::Response)
90
+ result[:status].should == Memcached::Errors::KEY_NOT_FOUND
91
+ stop
92
+ end
93
+ end
94
+ end
95
+
96
+ $n = 100
97
+ context "when incrementing a counter #{$n} times" do
98
+ it "should initialize the counter" do
99
+ run do
100
+ Memcached.set(:key => 'counter',
101
+ :value => '0') do |result|
102
+ stop
103
+ end
104
+ end
105
+ end
106
+
107
+ it "should count #{$n} times" do
108
+ @counted = 0
109
+ def count
110
+ Memcached.get(:key => 'counter') do |result|
111
+ result[:status].should == Memcached::Errors::NO_ERROR
112
+ value = result[:value].to_i
113
+ Memcached.set(:key => 'counter',
114
+ :value => (value + 1).to_s,
115
+ :cas => result[:cas]) do |result|
116
+ if result[:status] == Memcached::Errors::KEY_EXISTS
117
+ count # again
118
+ else
119
+ result[:status].should == Memcached::Errors::NO_ERROR
120
+ @counted += 1
121
+ stop if @counted >= $n
122
+ end
123
+ end
124
+ end
125
+ end
126
+ run do
127
+ $n.times { count }
128
+ end
129
+ end
130
+
131
+ it "should have counted up to #{$n}" do
132
+ run do
133
+ Memcached.get(:key => 'counter') do |result|
134
+ result[:status].should == Memcached::Errors::NO_ERROR
135
+ result[:value].to_i.should == $n
136
+ stop
137
+ end
138
+ end
139
+ end
140
+ end
141
+ end
142
+
143
+ context "when using multiple servers" do
144
+ it "should not return the same hash for the succeeding key" do
145
+ run do
146
+ Memcached.hash_key('0').should_not == Memcached.hash_key('1')
147
+ stop
148
+ end
149
+ end
150
+
151
+ it "should not return the same client for the succeeding key" do
152
+ run do
153
+ # wait for 2nd client to be connected
154
+ EM::Timer.new(0.1) do
155
+ Memcached.client_for_key('0').should_not == Memcached.client_for_key('1')
156
+ stop
157
+ end
158
+ end
159
+ end
160
+
161
+ it "should spread load (observe from outside :-)" do
162
+ run do
163
+
164
+ n = 10000
165
+ replies = 0
166
+ n.times do |i|
167
+ Memcached.set(:key => "#{i % 100}",
168
+ :value => rand(1 << 31).to_s) {
169
+ replies += 1
170
+ stop if replies >= n
171
+ }
172
+ end
173
+ end
174
+
175
+ end
176
+ end
177
+
178
+ context "when manipulating multiple records at once" do
179
+ before :all do
180
+ @n = 10
181
+ end
182
+
183
+ def key(n)
184
+ "test:item:#{n}"
185
+ end
186
+
187
+ it "should add some items" do
188
+ run do
189
+ items = []
190
+ @n.times { |i|
191
+ items << { :key => key(i),
192
+ :value => 'Foo',
193
+ :expiration => 20 } if i % 2 == 0
194
+ }
195
+ Memcached.multi_add(items) { |responses|
196
+ stop
197
+ @n.times { |i|
198
+ if i % 2 == 0 && (response_i = responses[key(i)])
199
+ response_i[:status].should == Memcached::Errors::NO_ERROR
200
+ end
201
+ }
202
+ }
203
+ end
204
+ end
205
+
206
+ it "should get all items" do
207
+ run do
208
+ items = []
209
+ @n.times { |i|
210
+ items << { :key => key(i) }
211
+ }
212
+ Memcached.multi_get(items) { |responses|
213
+ stop
214
+ @n.times { |i|
215
+ if i % 2 == 0
216
+ responses.should have_key(key(i))
217
+ responses[key(i)][:status].should == Memcached::Errors::NO_ERROR
218
+ responses[key(i)][:value].should == 'Foo'
219
+ else
220
+ # either no response because request was quiet, or not
221
+ # found in case of last response
222
+ if (response_i = responses[key(i)])
223
+ response_i[:status].should == Memcached::Errors::KEY_NOT_FOUND
224
+ end
225
+ end
226
+ }
227
+ }
228
+ end
229
+ end
230
+
231
+ it "should delete all items" do
232
+ run do
233
+ items = []
234
+ @n.times { |i|
235
+ items << { :key => key(i) }
236
+ }
237
+ Memcached.multi_delete(items) { |responses|
238
+ stop
239
+ @n.times { |i|
240
+ if i % 2 == 0
241
+ # either no response because request was quiet, or ok in
242
+ # case of last response
243
+ if (response_i = responses[key(i)])
244
+ response_i[:status].should == Memcached::Errors::NO_ERROR
245
+ end
246
+ else
247
+ responses[key(i)][:status].should == Memcached::Errors::KEY_NOT_FOUND
248
+ end
249
+ }
250
+ }
251
+ end
252
+ end
253
+
254
+ context "when the multi operation is empty" do
255
+ it "should return immediately" do
256
+ @results = []
257
+ @calls = 0
258
+ Memcached.multi_add([]) { |responses|
259
+ @results += responses
260
+ @calls += 1
261
+ }
262
+ @results.should be_empty
263
+ @calls.should == 1
264
+ end
265
+ end
266
+ end
267
+
268
+ end
@@ -0,0 +1,125 @@
1
+ $: << File.dirname(__FILE__) + '/../lib'
2
+ require 'remcached'
3
+
4
+ describe Memcached::Packet do
5
+
6
+ context "when generating a request" do
7
+ it "should set default values" do
8
+ pkt = Memcached::Request.new
9
+ pkt[:magic].should == 0x80
10
+ end
11
+
12
+ context "example 4.2.1" do
13
+ before :all do
14
+ pkt = Memcached::Request.new(:key => 'Hello')
15
+ @s = pkt.to_s
16
+ end
17
+
18
+ it "should serialize correctly" do
19
+ @s.should == "\x80\x00\x00\x05" +
20
+ "\x00\x00\x00\x00" +
21
+ "\x00\x00\x00\x05" +
22
+ "\x00\x00\x00\x00" +
23
+ "\x00\x00\x00\x00" +
24
+ "\x00\x00\x00\x00" +
25
+ "Hello"
26
+ end
27
+ end
28
+
29
+ context "example 4.3.1 (add)" do
30
+ before :all do
31
+ pkt = Memcached::Request::Add.new(:flags => 0xdeadbeef,
32
+ :expiration => 0xe10,
33
+ :key => "Hello",
34
+ :value => "World")
35
+ @s = pkt.to_s
36
+ end
37
+
38
+ it "should serialize correctly" do
39
+ @s.should == "\x80\x02\x00\x05" +
40
+ "\x08\x00\x00\x00" +
41
+ "\x00\x00\x00\x12" +
42
+ "\x00\x00\x00\x00" +
43
+ "\x00\x00\x00\x00" +
44
+ "\x00\x00\x00\x00" +
45
+ "\xde\xad\xbe\xef" +
46
+ "\x00\x00\x0e\x10" +
47
+ "Hello" +
48
+ "World"
49
+ end
50
+ end
51
+ end
52
+
53
+ context "when parsing a response" do
54
+ context "example 4.1.1" do
55
+ before :all do
56
+ s = "\x81\x00\x00\x00\x00\x00\x00\x01" +
57
+ "\x00\x00\x00\x09\x00\x00\x00\x00" +
58
+ "\x00\x00\x00\x00\x00\x00\x00\x00" +
59
+ "Not found"
60
+ @pkt = Memcached::Response.parse_header(s[0..23])
61
+ @pkt.parse_body(s[24..-1])
62
+ end
63
+
64
+ it "should return the right class according to magic & opcode" do
65
+ @pkt[:magic].should == 0x81
66
+ @pkt[:opcode].should == 0
67
+ @pkt.class.should == Memcached::Response
68
+ end
69
+ it "should return the right data type" do
70
+ @pkt[:data_type].should == 0
71
+ end
72
+ it "should return the right status" do
73
+ @pkt[:status].should == Memcached::Errors::KEY_NOT_FOUND
74
+ end
75
+ it "should return the right opaque" do
76
+ @pkt[:opaque].should == 0
77
+ end
78
+ it "should return the right CAS" do
79
+ @pkt[:cas].should == 0
80
+ end
81
+ it "should parse the body correctly" do
82
+ @pkt[:extras].should be_empty
83
+ @pkt[:key].should == ""
84
+ @pkt[:value].should == "Not found"
85
+ end
86
+ end
87
+
88
+ context "example 4.2.1" do
89
+ before :all do
90
+ s = "\x81\x00\x00\x00" +
91
+ "\x04\x00\x00\x00" +
92
+ "\x00\x00\x00\x09" +
93
+ "\x00\x00\x00\x00" +
94
+ "\x00\x00\x00\x00" +
95
+ "\x00\x00\x00\x01" +
96
+ "\xde\xad\xbe\xef" +
97
+ "World"
98
+ @pkt = Memcached::Response.parse_header(s[0..23])
99
+ @pkt.parse_body(s[24..-1])
100
+ end
101
+
102
+ it "should return the right class according to magic & opcode" do
103
+ @pkt[:magic].should == 0x81
104
+ @pkt[:opcode].should == 0
105
+ @pkt.class.should == Memcached::Response
106
+ end
107
+ it "should return the right data type" do
108
+ @pkt[:data_type].should == 0
109
+ end
110
+ it "should return the right status" do
111
+ @pkt[:status].should == Memcached::Errors::NO_ERROR
112
+ end
113
+ it "should return the right opaque" do
114
+ @pkt[:opaque].should == 0
115
+ end
116
+ it "should return the right CAS" do
117
+ @pkt[:cas].should == 1
118
+ end
119
+ it "should parse the body correctly" do
120
+ @pkt[:key].should == ""
121
+ @pkt[:value].should == "World"
122
+ end
123
+ end
124
+ end
125
+ end
metadata ADDED
@@ -0,0 +1,71 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: remcached
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.3.1
5
+ platform: ruby
6
+ authors:
7
+ - Stephan Maka
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+
12
+ date: 2009-10-12 00:00:00 +02:00
13
+ default_executable:
14
+ dependencies: []
15
+
16
+ description: Ruby EventMachine memcached client
17
+ email: astro@spaceboyz.net
18
+ executables: []
19
+
20
+ extensions: []
21
+
22
+ extra_rdoc_files:
23
+ - README.rst
24
+ files:
25
+ - .gitignore
26
+ - README.rst
27
+ - Rakefile
28
+ - VERSION.yml
29
+ - examples/fill.rb
30
+ - lib/remcached.rb
31
+ - lib/remcached/client.rb
32
+ - lib/remcached/const.rb
33
+ - lib/remcached/pack_array.rb
34
+ - lib/remcached/packet.rb
35
+ - remcached.gemspec
36
+ - spec/client_spec.rb
37
+ - spec/memcached_spec.rb
38
+ - spec/packet_spec.rb
39
+ has_rdoc: true
40
+ homepage: http://github.com/astro/remcached/
41
+ licenses: []
42
+
43
+ post_install_message:
44
+ rdoc_options:
45
+ - --charset=UTF-8
46
+ require_paths:
47
+ - lib
48
+ required_ruby_version: !ruby/object:Gem::Requirement
49
+ requirements:
50
+ - - ">="
51
+ - !ruby/object:Gem::Version
52
+ version: "0"
53
+ version:
54
+ required_rubygems_version: !ruby/object:Gem::Requirement
55
+ requirements:
56
+ - - ">="
57
+ - !ruby/object:Gem::Version
58
+ version: "0"
59
+ version:
60
+ requirements: []
61
+
62
+ rubyforge_project:
63
+ rubygems_version: 1.3.5
64
+ signing_key:
65
+ specification_version: 3
66
+ summary: Ruby EventMachine memcached client
67
+ test_files:
68
+ - spec/client_spec.rb
69
+ - spec/memcached_spec.rb
70
+ - spec/packet_spec.rb
71
+ - examples/fill.rb