siberite-client 0.8.0

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,40 @@
1
+ require 'spec_helper'
2
+
3
+ describe Siberite::Client::Json do
4
+ describe "Instance Methods" do
5
+ before do
6
+ @raw_client = Siberite::Client.new(*Siberite::Config.default)
7
+ @client = Siberite::Client::Json.new(@raw_client)
8
+ end
9
+
10
+ describe "#get" do
11
+ it "parses json" do
12
+ mock(@raw_client).get('a_queue') { '{"a": 1, "b": [{"c": 2}]}' }
13
+ @client.get('a_queue').should == {"a" => 1, "b" => ["c" => 2]}
14
+ end
15
+
16
+ # wtf is up with this test?
17
+ it "uses a HashWithIndifferentAccess" do
18
+ mock(@raw_client).get('a_queue') { '{"a": 1, "b": [{"c": 2}]}' }
19
+ @client.get('a_queue').class.should == HashWithIndifferentAccess
20
+ end
21
+
22
+ it "passes through non-strings" do
23
+ mock(@raw_client).get('a_queue') { {:key => "value"} }
24
+ @client.get('a_queue').should == {:key => "value"}
25
+ end
26
+
27
+ it "passes through strings that are not json" do
28
+ mock(@raw_client).get('a_queue') { "I am not JSON" }
29
+ @client.get('a_queue').should == "I am not JSON"
30
+ end
31
+ end
32
+ end
33
+ end
34
+
35
+ class HashWithIndifferentAccess < Hash
36
+ def initialize(hash = {})
37
+ super()
38
+ merge!(hash)
39
+ end
40
+ end
@@ -0,0 +1,54 @@
1
+ require 'spec_helper'
2
+
3
+ describe Siberite::Client::Namespace do
4
+ describe "Instance Methods" do
5
+ before do
6
+ @raw_client = Siberite::Client.new(*Siberite::Config.default)
7
+ @client = Siberite::Client::Namespace.new('some_namespace', @raw_client)
8
+ end
9
+
10
+ describe "#set" do
11
+ it "prepends a namespace to the key" do
12
+ mock(@raw_client).set('some_namespace:a_queue', :mcguffin)
13
+ @client.set('a_queue', :mcguffin)
14
+ end
15
+ end
16
+
17
+ describe "#get" do
18
+ it "prepends a namespace to the key" do
19
+ mock(@raw_client).get('some_namespace:a_queue')
20
+ @client.get('a_queue')
21
+ end
22
+ end
23
+
24
+ describe "#delete" do
25
+ it "prepends a namespace to the key" do
26
+ mock(@raw_client).delete('some_namespace:a_queue')
27
+ @client.delete('a_queue')
28
+ end
29
+ end
30
+
31
+ describe "#flush" do
32
+ it "prepends a namespace to the key" do
33
+ mock(@raw_client).flush('some_namespace:a_queue')
34
+ @client.flush('a_queue')
35
+ end
36
+ end
37
+
38
+ describe "#stat" do
39
+ it "prepends a namespace to the key" do
40
+ mock(@raw_client).stat('some_namespace:a_queue')
41
+ @client.stat('a_queue')
42
+ end
43
+ end
44
+
45
+ describe "#available_queues" do
46
+ it "only returns namespaced queues" do
47
+ @raw_client.set('some_namespace:namespaced_queue', 'foo')
48
+ @raw_client.set('unnamespaced_queue', 'foo')
49
+
50
+ @client.available_queues.should == ['namespaced_queue']
51
+ end
52
+ end
53
+ end
54
+ end
@@ -0,0 +1,33 @@
1
+ require 'spec_helper'
2
+
3
+ describe Siberite::Client::Partitioning do
4
+ before do
5
+ @client_1 = Siberite::Client.new(*Siberite::Config.default)
6
+ @client_2 = Siberite::Client.new(*Siberite::Config.default)
7
+ @default_client = Siberite::Client.new(*Siberite::Config.default)
8
+
9
+ @client = Siberite::Client::Partitioning.new(
10
+ 'queue1' => @client_1,
11
+ ['queue2', 'queue3'] => @client_2,
12
+ default: @default_client
13
+ )
14
+ end
15
+
16
+ %w(set get delete flush stat).each do |method|
17
+ describe "##{method}" do
18
+ it "routes to the correct client" do
19
+ mock(@client_1).__send__(method, 'queue1')
20
+ @client.send(method, 'queue1')
21
+
22
+ mock(@client_2).__send__(method, 'queue2')
23
+ @client.send(method, 'queue2')
24
+
25
+ mock(@client_2).__send__(method, 'queue3/queue_arg')
26
+ @client.send(method, 'queue3/queue_arg')
27
+
28
+ mock(@default_client).__send__(method, 'queue4')
29
+ @client.send(method, 'queue4')
30
+ end
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,273 @@
1
+ require 'spec_helper'
2
+
3
+ describe "Siberite::Client::Transactional" do
4
+ before do
5
+ @raw_client = Siberite::Client.new(*Siberite::Config.default)
6
+ @client = Siberite::Client::Transactional.new(@raw_client)
7
+ @queue = "some_queue"
8
+ end
9
+
10
+ describe "integration" do
11
+ def get_job
12
+ job = nil
13
+ job = @client.get(@queue) until job
14
+ job
15
+ end
16
+
17
+ it "processes normal jobs" do
18
+ returns = [:mcguffin]
19
+ stub(@raw_client).get(@queue, anything) { returns.shift }
20
+ stub(@raw_client).get_from_last(@queue + "_errors", anything)
21
+
22
+ mock(@raw_client).get_from_last(@queue, :close => true)
23
+
24
+ get_job.should == :mcguffin
25
+ @client.current_try.should == 1
26
+ @client.get(@queue) # simulate next get run
27
+ end
28
+
29
+ it "processes successful retries" do
30
+ returns = [Siberite::Client::Transactional::RetryableJob.new(1, :mcguffin)]
31
+ stub(@raw_client).get_from_last(@queue + "_errors", anything) { returns.shift }
32
+ stub(@raw_client).get(@queue, anything)
33
+
34
+ mock(@raw_client).get_from_last(@queue + "_errors", :close => true)
35
+
36
+ get_job.should == :mcguffin
37
+ @client.current_try.should == 2
38
+ @client.get(@queue) # simulate next get run
39
+ end
40
+
41
+ it "processes normal jobs that should retry" do
42
+ returns = [:mcguffin]
43
+ stub(@raw_client).get(@queue, anything) { returns.shift }
44
+ stub(@raw_client).get_from_last(@queue + "_errors", anything)
45
+
46
+ mock(@raw_client).set(@queue + "_errors", anything) do |q,j|
47
+ j.retries.should == 1
48
+ j.job.should == :mcguffin
49
+ end
50
+ mock(@raw_client).get_from_last(@queue, :close => true)
51
+
52
+ get_job.should == :mcguffin
53
+ @client.current_try.should == 1
54
+
55
+ @client.retry
56
+ @client.get(@queue) # simulate next get run
57
+ end
58
+
59
+ it "processes retries that should retry" do
60
+ returns = [Siberite::Client::Transactional::RetryableJob.new(1, :mcguffin)]
61
+ stub(@raw_client).get_from_last(@queue + "_errors", :open => true) { returns.shift }
62
+ stub(@raw_client).get(@queue, anything)
63
+ mock(@raw_client).set(@queue + "_errors", anything) do |q,j|
64
+ j.retries.should == 2
65
+ j.job.should == :mcguffin
66
+ end
67
+ mock(@raw_client).get_from_last(@queue + "_errors", :close => true)
68
+
69
+ get_job.should == :mcguffin
70
+ @client.current_try.should == 2
71
+
72
+ @client.retry
73
+ @client.get(@queue) # simulate next get run
74
+ end
75
+
76
+ it "processes retries that should give up" do
77
+ returns = [Siberite::Client::Transactional::RetryableJob.new(Siberite::Client::Transactional::DEFAULT_RETRIES - 1, :mcguffin)]
78
+ stub(@raw_client).get_from_last(@queue + "_errors", :open => true) { returns.shift }
79
+ stub(@raw_client).get(@queue, anything)
80
+ mock(@raw_client).set.never
81
+ mock(@raw_client).get_from_last(@queue + "_errors", :close => true)
82
+
83
+ get_job.should == :mcguffin
84
+ @client.current_try.should == Siberite::Client::Transactional::DEFAULT_RETRIES
85
+
86
+ lambda { @client.retry }.should raise_error(Siberite::Client::Transactional::RetriesExceeded)
87
+ @client.get(@queue) # simulate next get run
88
+ end
89
+ end
90
+
91
+ describe "Instance Methods" do
92
+ before do
93
+ stub(@client).rand { 1 }
94
+ end
95
+
96
+ describe "#get" do
97
+ it "asks for a transaction" do
98
+ mock(@raw_client).get(@queue, :open => true) { :mcguffin }
99
+ @client.get(@queue).should == :mcguffin
100
+ end
101
+
102
+ it "is nil when the primary queue is empty and selected" do
103
+ mock(@client).rand { Siberite::Client::Transactional::ERROR_PROCESSING_RATE + 0.05 }
104
+ mock(@raw_client).get(@queue, anything) { nil }
105
+ mock(@raw_client).get(@queue + "_errors", :open => true).never
106
+ @client.get(@queue).should be_nil
107
+ end
108
+
109
+ it "is nil when the error queue is empty and selected" do
110
+ mock(@client).rand { Siberite::Client::Transactional::ERROR_PROCESSING_RATE - 0.05 }
111
+ mock(@raw_client).get(@queue, anything).never
112
+ mock(@raw_client).get_from_last(@queue + "_errors", :open => true) { nil }
113
+ @client.get(@queue).should be_nil
114
+ end
115
+
116
+ it "returns the payload of a RetryableJob" do
117
+ stub(@client).rand { 0 }
118
+ mock(@raw_client).get_from_last(@queue + "_errors", anything) do
119
+ Siberite::Client::Transactional::RetryableJob.new(1, :mcmuffin)
120
+ end
121
+
122
+ @client.get(@queue).should == :mcmuffin
123
+ end
124
+
125
+ it "closes an open transaction with no retries" do
126
+ stub(@raw_client).get(@queue, anything) { :mcguffin }
127
+ @client.get(@queue)
128
+
129
+ mock(@raw_client).get_from_last(@queue, :close => true)
130
+ @client.get(@queue)
131
+ end
132
+
133
+ it "closes an open transaction with retries" do
134
+ stub(@client).rand { 0 }
135
+ stub(@raw_client).get_from_last(@queue + "_errors", :open => true) do
136
+ Siberite::Client::Transactional::RetryableJob.new(1, :mcmuffin)
137
+ end
138
+ @client.get(@queue)
139
+
140
+ mock(@raw_client).get_from_last(@queue + "_errors", :close => true)
141
+ @client.get(@queue)
142
+ end
143
+
144
+ it "prevents transactional gets across multiple queues" do
145
+ stub(@raw_client).get(@queue, anything) { :mcguffin }
146
+ @client.get(@queue)
147
+
148
+ lambda do
149
+ @client.get("transaction_fail")
150
+ end.should raise_error(Siberite::Client::Transactional::MultipleQueueException)
151
+ end
152
+ end
153
+
154
+ describe "#retry" do
155
+ before do
156
+ stub(@raw_client).get(@queue, anything) { :mcmuffin }
157
+ stub(@raw_client).get_from_last
158
+ @client.get(@queue)
159
+ end
160
+
161
+ it "raises an exception if called when there is no open transaction" do
162
+ @client.close_last_transaction
163
+ lambda { @client.retry }.should raise_error(Siberite::Client::Transactional::NoOpenTransaction)
164
+ end
165
+
166
+ it "raises an exception if retry has already been called" do
167
+ @client.retry
168
+ lambda { @client.retry }.should raise_error(Siberite::Client::Transactional::NoOpenTransaction)
169
+ end
170
+
171
+ it "enqueues a fresh failed job to the errors queue with a retry count" do
172
+ mock(@raw_client).set(@queue + "_errors", anything) do |queue, job|
173
+ job.retries.should == 1
174
+ job.job.should == :mcmuffin
175
+ end
176
+ @client.retry.should be_truthy
177
+ end
178
+
179
+ it "allows specification of the job to retry" do
180
+ mock(@raw_client).set(@queue + "_errors", anything) do |queue, job|
181
+ job.retries.should == 1
182
+ job.job.should == :revised_mcmuffin
183
+ end
184
+ @client.retry(:revised_mcmuffin).should be_truthy
185
+ end
186
+
187
+ it "increments the retry count and re-enqueues the retried job" do
188
+ stub(@client).rand { 0 }
189
+ stub(@raw_client).get_from_last(@queue + "_errors", anything) do
190
+ Siberite::Client::Transactional::RetryableJob.new(1, :mcmuffin)
191
+ end
192
+
193
+ mock(@raw_client).set(@queue + "_errors", anything) do |queue, job|
194
+ job.retries.should == 2
195
+ job.job.should == :mcmuffin
196
+ end
197
+
198
+ @client.get(@queue)
199
+ @client.retry.should be_truthy
200
+ end
201
+
202
+ it "does not enqueue the retried job after too many tries" do
203
+ stub(@client).rand { 0 }
204
+ stub(@raw_client).get_from_last(@queue + "_errors", :open => true) do
205
+ Siberite::Client::Transactional::RetryableJob.new(Siberite::Client::Transactional::DEFAULT_RETRIES - 1, :mcmuffin)
206
+ end
207
+ mock(@raw_client).set(@queue + "_errors", anything).never
208
+ mock(@raw_client).get_from_last(@queue + "_errors", :close => true)
209
+ @client.get(@queue)
210
+ lambda { @client.retry }.should raise_error(Siberite::Client::Transactional::RetriesExceeded)
211
+ end
212
+
213
+ it "closes an open transaction with no retries" do
214
+ stub(@raw_client).get(@queue, anything) { :mcguffin }
215
+ @client.get(@queue)
216
+
217
+ mock(@raw_client).get_from_last(@queue, :close => true)
218
+ @client.retry
219
+ end
220
+
221
+ it "closes an open transaction with retries" do
222
+ stub(@client).rand { 0 }
223
+ stub(@raw_client).get_from_last(@queue + "_errors", :open => true) do
224
+ Siberite::Client::Transactional::RetryableJob.new(1, :mcmuffin)
225
+ end
226
+ @client.get(@queue)
227
+
228
+ mock(@raw_client).get_from_last(@queue + "_errors", :close => true)
229
+ @client.retry
230
+ end
231
+ end
232
+
233
+ describe "#read_from_error_queue?" do
234
+ it "returns the error queue ERROR_PROCESSING_RATE pct. of the time" do
235
+ mock(@client).rand { Siberite::Client::Transactional::ERROR_PROCESSING_RATE - 0.05 }
236
+ @client.send(:read_from_error_queue?).should == true
237
+ end
238
+
239
+ it "returns the normal queue most of the time" do
240
+ mock(@client).rand { Siberite::Client::Transactional::ERROR_PROCESSING_RATE + 0.05 }
241
+ @client.send(:read_from_error_queue?).should == false
242
+ end
243
+ end
244
+
245
+ describe "#close_last_transaction" do
246
+ it "does nothing if there is no last transaction" do
247
+ mock(@raw_client).get_from_last(@queue, :close => true).never
248
+ mock(@raw_client).get_from_last(@queue + "_errors", :close => true).never
249
+ @client.send(:close_last_transaction)
250
+ end
251
+
252
+ it "closes the normal queue if the job was pulled off of the normal queue" do
253
+ mock(@client).read_from_error_queue? { false }
254
+ mock(@raw_client).get(@queue, :open => true) { :mcguffin }
255
+ mock(@raw_client).get_from_last(@queue, :close => true)
256
+ mock(@raw_client).get_from_last(@queue + "_errors", :close => true).never
257
+
258
+ @client.get(@queue).should == :mcguffin
259
+ @client.send(:close_last_transaction)
260
+ end
261
+
262
+ it "closes the error queue if the job was pulled off of the error queue" do
263
+ mock(@client).read_from_error_queue? { true }
264
+ mock(@raw_client).get_from_last(@queue + "_errors", :open => true) { Siberite::Client::Transactional::RetryableJob.new 1, :mcguffin }
265
+ mock(@raw_client).get_from_last(@queue, :close => true).never
266
+ mock(@raw_client).get_from_last(@queue + "_errors", :close => true)
267
+
268
+ @client.get(@queue).should == :mcguffin
269
+ @client.send(:close_last_transaction)
270
+ end
271
+ end
272
+ end
273
+ end
@@ -0,0 +1,68 @@
1
+ require 'spec_helper'
2
+
3
+ describe Siberite::Client::Unmarshal do
4
+ describe "Instance Methods" do
5
+ before do
6
+ @raw_client = Siberite::Client.new(*Siberite::Config.default)
7
+ @client = Siberite::Client::Unmarshal.new(@raw_client)
8
+ end
9
+
10
+ describe "#get" do
11
+ it "integrates" do
12
+ @client.set('a_queue', "foo")
13
+ @client.get('a_queue').should == 'foo'
14
+ end
15
+
16
+ it "unmarshals marshaled objects" do
17
+ test_object = {:a => 1, :b => [1, 2, 3]}
18
+ mock(@raw_client).get('a_queue', :raw => true) { Marshal.dump(test_object) }
19
+ @client.get('a_queue').should == test_object
20
+ end
21
+
22
+ it "does not unmarshal when raw is true" do
23
+ test_object = {:a => 1, :b => [1, 2, 3]}
24
+ mock(@raw_client).get('a_queue', :raw => true) { Marshal.dump(test_object) }
25
+ @client.get('a_queue', :raw => true).should == Marshal.dump(test_object)
26
+ end
27
+
28
+ it "passes through objects" do
29
+ test_object = Object.new
30
+ mock(@raw_client).get('a_queue', :raw => true) { test_object }
31
+ @client.get('a_queue').should == test_object
32
+ end
33
+
34
+ it "passes through strings" do
35
+ mock(@raw_client).get('a_queue', :raw => true) { "I am not marshaled" }
36
+ @client.get('a_queue').should == "I am not marshaled"
37
+ end
38
+ end
39
+
40
+ describe "#isMarshaled" do
41
+ it "should foo" do
42
+ @client.is_marshaled?("foo").should be_falsey
43
+ @client.is_marshaled?(Marshal.dump("foo")).should be_truthy
44
+ @client.is_marshaled?(Marshal.dump("foo")).should be_truthy
45
+
46
+ @client.is_marshaled?({}).should be_falsey
47
+ @client.is_marshaled?(Marshal.dump({})).should be_truthy
48
+ @client.is_marshaled?(Marshal.dump({})).should be_truthy
49
+
50
+ @client.is_marshaled?(BadObject.new).should be_falsey
51
+ @client.is_marshaled?(Marshal.dump(BadObject.new)).should be_truthy
52
+ @client.is_marshaled?(Marshal.dump(BadObject.new)).should be_truthy
53
+ end
54
+ end
55
+ end
56
+ end
57
+
58
+ class BadObject
59
+ def to_s
60
+ raise Exception
61
+ end
62
+ end
63
+
64
+ module Marshal
65
+ def self.load_with_constantize(source, loaded_constants = [])
66
+ self.load(source)
67
+ end
68
+ end