stalk_climber 0.0.6 → 0.1.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.
- data/.rdoc_options +7 -0
- data/.travis.yml +8 -10
- data/Gemfile +1 -0
- data/lib/stalk_climber.rb +5 -0
- data/lib/stalk_climber/climber.rb +42 -54
- data/lib/stalk_climber/climber_enumerable.rb +110 -0
- data/lib/stalk_climber/climber_enumerables.rb +7 -0
- data/lib/stalk_climber/connection.rb +49 -37
- data/lib/stalk_climber/connection_pool.rb +37 -7
- data/lib/stalk_climber/job.rb +270 -67
- data/lib/stalk_climber/lazy_enumerable.rb +1 -0
- data/lib/stalk_climber/tube.rb +182 -0
- data/lib/stalk_climber/tubes.rb +37 -0
- data/lib/stalk_climber/version.rb +2 -1
- data/test/test_helper.rb +4 -2
- data/test/unit/beaneater_job_test.rb +260 -0
- data/test/unit/climber_enumerable.rb +18 -0
- data/test/unit/climber_test.rb +31 -100
- data/test/unit/connection_pool_test.rb +48 -33
- data/test/unit/connection_test.rb +200 -149
- data/test/unit/job_test.rb +240 -147
- data/test/unit/jobs_test.rb +106 -0
- data/test/unit/tube_test.rb +89 -0
- data/test/unit/tubes_test.rb +52 -0
- metadata +17 -2
data/test/unit/job_test.rb
CHANGED
@@ -1,196 +1,289 @@
|
|
1
1
|
require 'test_helper'
|
2
|
-
require 'json'
|
3
2
|
|
4
|
-
class Job <
|
3
|
+
class Job < StalkClimber::TestCase
|
5
4
|
|
6
|
-
|
5
|
+
setup do
|
7
6
|
@connection = StalkClimber::Connection.new('localhost:11300')
|
8
7
|
@job = seed_jobs(1).first
|
9
8
|
end
|
10
9
|
|
11
10
|
|
12
|
-
|
13
|
-
body = {'test' => true}.to_json
|
11
|
+
context 'beaneater integration' do
|
14
12
|
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
assert_equal body, @job.body
|
13
|
+
should 'derive from Beaneater::Job' do
|
14
|
+
assert_kind_of Beaneater::Job, @job
|
15
|
+
end
|
19
16
|
|
20
|
-
@job.connection.expects(:transmit).never
|
21
|
-
assert_equal body, @job.body
|
22
17
|
end
|
23
18
|
|
24
19
|
|
25
|
-
|
26
|
-
assert @job.instance_variable_get(:@connection)
|
27
|
-
assert @job.connection
|
28
|
-
end
|
20
|
+
context '#body' do
|
29
21
|
|
22
|
+
should 'perform peek and set/return body' do
|
23
|
+
body = "test #{Time.now.to_i}"
|
30
24
|
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
25
|
+
@job.connection.expects(:transmit).returns({
|
26
|
+
:body => body,
|
27
|
+
})
|
28
|
+
assert_equal body, @job.body
|
29
|
+
|
30
|
+
@job.connection.expects(:transmit).never
|
31
|
+
assert_equal body, @job.body
|
35
32
|
end
|
36
|
-
|
37
|
-
refute @job.instance_variable_get(:@stats)
|
38
|
-
assert_equal 'DELETED', @job.instance_variable_get(:@status)
|
33
|
+
|
39
34
|
end
|
40
35
|
|
41
36
|
|
42
|
-
|
43
|
-
|
37
|
+
context '#connection' do
|
38
|
+
|
39
|
+
should 'set connection instance variable to connection' do
|
40
|
+
assert @job.instance_variable_get(:@connection)
|
41
|
+
assert @job.connection
|
42
|
+
end
|
44
43
|
|
45
|
-
@job.delete
|
46
|
-
refute @job.exists?
|
47
44
|
end
|
48
45
|
|
49
46
|
|
50
|
-
|
51
|
-
job = StalkClimber::Job.new(@connection.transmit("peek #{@job.id}"))
|
52
|
-
@connection.expects(:transmit).never
|
53
|
-
assert_equal @connection, job.connection
|
54
|
-
assert_equal @job.id, job.id
|
55
|
-
assert_equal 'FOUND', job.instance_variable_get(:@status)
|
56
|
-
assert_equal('{}', job.body)
|
57
|
-
refute job.instance_variable_get(:@stats)
|
58
|
-
end
|
47
|
+
context '#delete' do
|
59
48
|
|
49
|
+
should 'delete the job' do
|
50
|
+
assert_equal 'DELETED', @job.delete[:status]
|
51
|
+
assert_raises Beaneater::NotFoundError do
|
52
|
+
@connection.transmit("peek #{@job.id}")
|
53
|
+
end
|
54
|
+
refute @job.instance_variable_get(:@body)
|
55
|
+
refute @job.instance_variable_get(:@stats)
|
56
|
+
assert_equal 'DELETED', @job.instance_variable_get(:@status)
|
57
|
+
end
|
58
|
+
|
59
|
+
|
60
|
+
should 'not clear job instance variables if delete fails' do
|
61
|
+
client = Beaneater::Connection.new('localhost:11300')
|
62
|
+
tube_name = SecureRandom.uuid
|
63
|
+
client.transmit("use #{tube_name}")
|
64
|
+
client.transmit("watch #{tube_name}")
|
65
|
+
client.transmit('ignore default')
|
66
|
+
job = client.transmit(StalkClimber::Connection::PROBE_TRANSMISSION)
|
67
|
+
@job = StalkClimber::Job.new(@connection.transmit("stats-job #{job[:id]}"))
|
68
|
+
client.transmit('reserve')
|
69
|
+
assert_raises Beaneater::NotFoundError do
|
70
|
+
@job.delete
|
71
|
+
end
|
72
|
+
assert @job.instance_variable_get(:@stats), 'Expected stats instance variable to still exist after failed deletion'
|
73
|
+
client.transmit("delete #{job[:id]}")
|
74
|
+
end
|
60
75
|
|
61
|
-
def test_initialize_with_put_response
|
62
|
-
@connection.expects(:transmit).never
|
63
|
-
assert @job.id
|
64
|
-
assert_equal @connection, @job.connection
|
65
|
-
assert_equal 'INSERTED', @job.instance_variable_get(:@status)
|
66
|
-
refute @job.instance_variable_get(:@body)
|
67
|
-
refute @job.instance_variable_get(:@stats)
|
68
76
|
end
|
69
77
|
|
70
78
|
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
refute job.instance_variable_get(:@body)
|
80
|
-
StalkClimber::Job::STATS_ATTRIBUTES.each do |method_name|
|
81
|
-
assert job.send(method_name)
|
79
|
+
context '#exists?' do
|
80
|
+
|
81
|
+
|
82
|
+
should 'verify the job exists' do
|
83
|
+
assert @job.exists?
|
84
|
+
|
85
|
+
@job.delete
|
86
|
+
refute @job.exists?
|
82
87
|
end
|
88
|
+
|
83
89
|
end
|
84
90
|
|
85
91
|
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
'
|
94
|
-
'
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
92
|
+
context '#initialize' do
|
93
|
+
|
94
|
+
should 'support initialization with peek response' do
|
95
|
+
job = StalkClimber::Job.new(@connection.transmit("peek #{@job.id}"))
|
96
|
+
@connection.expects(:transmit).never
|
97
|
+
assert_equal @connection, job.connection
|
98
|
+
assert_equal @job.id, job.id
|
99
|
+
assert_equal 'FOUND', job.instance_variable_get(:@status)
|
100
|
+
assert_equal('{}', job.body)
|
101
|
+
refute job.instance_variable_get(:@stats)
|
102
|
+
end
|
103
|
+
|
104
|
+
|
105
|
+
should 'support initialization with put response' do
|
106
|
+
@connection.expects(:transmit).never
|
107
|
+
assert @job.id
|
108
|
+
assert_equal @connection, @job.connection
|
109
|
+
assert_equal 'INSERTED', @job.instance_variable_get(:@status)
|
110
|
+
refute @job.instance_variable_get(:@body)
|
111
|
+
refute @job.instance_variable_get(:@stats)
|
112
|
+
end
|
113
|
+
|
114
|
+
|
115
|
+
should 'support initialization with stats response' do
|
116
|
+
job = StalkClimber::Job.new(@connection.transmit("stats-job #{@job.id}"))
|
117
|
+
@connection.expects(:transmit).never
|
118
|
+
assert_equal @job.id, job.id
|
119
|
+
assert_equal @connection, job.connection
|
120
|
+
assert_equal 'OK', job.instance_variable_get(:@status)
|
121
|
+
assert job.stats(false)
|
122
|
+
assert job.instance_variable_get(:@stats)
|
123
|
+
refute job.instance_variable_get(:@body)
|
124
|
+
StalkClimber::Job::CACHED_ATTRIBUTES.each do |method_name|
|
125
|
+
assert job.send(method_name)
|
126
|
+
end
|
127
|
+
end
|
128
|
+
|
129
|
+
|
130
|
+
should 'support initialization with reserve response' do
|
131
|
+
job = StalkClimber::Job.new(@connection.transmit('reserve'))
|
132
|
+
@connection.expects(:transmit).never
|
133
|
+
assert_equal @connection, job.connection
|
134
|
+
assert job.id
|
135
|
+
assert_equal 'RESERVED', job.instance_variable_get(:@status)
|
136
|
+
assert_equal('{}', job.body)
|
137
|
+
refute job.instance_variable_get(:@stats)
|
111
138
|
end
|
139
|
+
|
140
|
+
|
141
|
+
should 'raise error if initialized with unknown response type' do
|
142
|
+
assert_raises RuntimeError do
|
143
|
+
StalkClimber::Job.new({:status => 'DELETED'})
|
144
|
+
end
|
145
|
+
end
|
146
|
+
|
112
147
|
end
|
113
148
|
|
114
149
|
|
115
|
-
|
116
|
-
|
117
|
-
|
150
|
+
context 'stats methods' do
|
151
|
+
|
152
|
+
should 'initialize stats attributes and attribute methods should return correct values' do
|
153
|
+
stats_body = {
|
154
|
+
'age' => 3,
|
155
|
+
'buries' => 0,
|
156
|
+
'delay' => 0,
|
157
|
+
'id' => 4412,
|
158
|
+
'kicks' => 0,
|
159
|
+
'pri' => 4294967295,
|
160
|
+
'releases' => 0,
|
161
|
+
'reserves' => 0,
|
162
|
+
'state' => 'ready',
|
163
|
+
'time-left' => 0,
|
164
|
+
'timeouts' => 0,
|
165
|
+
'ttr' => 300,
|
166
|
+
'tube' => 'default',
|
167
|
+
}
|
168
|
+
stats_response = {
|
169
|
+
:body => stats_body,
|
170
|
+
:connection => @connection,
|
171
|
+
:id => 149,
|
172
|
+
:status => 'OK',
|
173
|
+
}
|
174
|
+
job = StalkClimber::Job.new(stats_response)
|
175
|
+
StalkClimber::Job::CACHED_ATTRIBUTES.each do |method_name|
|
176
|
+
assert_equal stats_body[method_name], job.send(method_name), "Expected #{stats_body[method_name]} for #{method_name}, got #{job.send(method_name)}"
|
177
|
+
end
|
178
|
+
end
|
179
|
+
|
180
|
+
|
181
|
+
should 'be able to force refresh of stats' do
|
182
|
+
initial_value = @job.age
|
183
|
+
@connection.expects(:transmit).returns({:body => {'age' => initial_value + 100}})
|
184
|
+
assert_equal initial_value + 100, @job.age(true)
|
185
|
+
end
|
186
|
+
|
187
|
+
|
188
|
+
should 'allow for not refreshing stats' do
|
189
|
+
initial_value = @job.age
|
190
|
+
@connection.expects(:transmit).never
|
191
|
+
assert_equal initial_value, @job.age(false)
|
118
192
|
end
|
193
|
+
|
119
194
|
end
|
120
195
|
|
121
196
|
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
197
|
+
context '#stats' do
|
198
|
+
|
199
|
+
should 'be able to force refresh' do
|
200
|
+
body = {
|
201
|
+
'age'=>3,
|
202
|
+
'buries'=>0,
|
203
|
+
'delay'=>0,
|
204
|
+
'kicks'=>0,
|
205
|
+
'id' => 4412,
|
206
|
+
'pri'=>4294967295,
|
207
|
+
'releases'=>0,
|
208
|
+
'reserves'=>0,
|
209
|
+
'state'=>'ready',
|
210
|
+
'time-left'=>0,
|
211
|
+
'timeouts'=>0,
|
212
|
+
'ttr'=>300,
|
213
|
+
'tube'=>'default',
|
214
|
+
}
|
215
|
+
stats_1 = {
|
216
|
+
:body => {},
|
217
|
+
:connection => @connection,
|
218
|
+
:id => 149,
|
219
|
+
:status => 'OK',
|
220
|
+
}
|
221
|
+
stats_2 = {
|
222
|
+
:body => body,
|
223
|
+
:connection => @connection,
|
224
|
+
:id => 149,
|
225
|
+
:status => 'OK',
|
226
|
+
}
|
227
|
+
@connection.expects(:transmit).twice.returns(stats_1, stats_2)
|
228
|
+
job = StalkClimber::Job.new(@connection.transmit("stats-job #{@job.id}"))
|
229
|
+
job.stats
|
230
|
+
StalkClimber::Job::CACHED_ATTRIBUTES.each do |method_name|
|
231
|
+
assert_equal body[method_name], job.send(method_name), "Expected #{body[method_name.to_sym]} for #{method_name}, got #{job.send(method_name)}"
|
232
|
+
end
|
233
|
+
end
|
234
|
+
|
235
|
+
|
236
|
+
should 'allow for not refreshing stats' do
|
237
|
+
stat = @job.stats
|
238
|
+
@job.connection.expects(:transmit).never
|
239
|
+
assert_equal stat, @job.stats(false)
|
240
|
+
end
|
241
|
+
|
126
242
|
end
|
127
243
|
|
128
244
|
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
|
150
|
-
|
151
|
-
|
152
|
-
|
153
|
-
|
154
|
-
|
155
|
-
|
156
|
-
|
157
|
-
|
158
|
-
|
159
|
-
|
160
|
-
StalkClimber::Job::STATS_ATTRIBUTES.each do |method_name|
|
161
|
-
assert_equal body[method_name], job.send(method_name), "Expected #{body[method_name.to_sym]} for #{method_name}, got #{job.send(method_name)}"
|
245
|
+
context '#to_h' do
|
246
|
+
|
247
|
+
should 'return the expected hash' do
|
248
|
+
job_body = "test #{Time.now.to_i}"
|
249
|
+
stats_body = {
|
250
|
+
'age' => 3,
|
251
|
+
'body' => job_body, # Will be ignored during job init
|
252
|
+
'buries' => 0,
|
253
|
+
'connection' => @connection, # Will be ignored during job init
|
254
|
+
'delay' => 0,
|
255
|
+
'id' => 4412,
|
256
|
+
'kicks' => 0,
|
257
|
+
'pri' => 4294967295,
|
258
|
+
'releases' => 0,
|
259
|
+
'reserves' => 0,
|
260
|
+
'state' => 'ready',
|
261
|
+
'time-left' => 0,
|
262
|
+
'timeouts' => 0,
|
263
|
+
'ttr' => 300,
|
264
|
+
'tube' => 'default',
|
265
|
+
}
|
266
|
+
stats_response = {
|
267
|
+
:body => stats_body,
|
268
|
+
:connection => @connection,
|
269
|
+
:id => 149,
|
270
|
+
:status => 'OK',
|
271
|
+
}
|
272
|
+
job = StalkClimber::Job.new(stats_response)
|
273
|
+
job.instance_variable_set(:@body, job_body)
|
274
|
+
job.connection.expects(:transmit).once.returns(stats_response)
|
275
|
+
assert_equal stats_body, job.to_h
|
162
276
|
end
|
277
|
+
|
163
278
|
end
|
164
279
|
|
165
|
-
|
166
|
-
|
167
|
-
|
168
|
-
|
169
|
-
|
170
|
-
|
171
|
-
|
172
|
-
'delay' => 0,
|
173
|
-
'id' => 4412,
|
174
|
-
'kicks' => 0,
|
175
|
-
'pri' => 4294967295,
|
176
|
-
'releases' => 0,
|
177
|
-
'reserves' => 0,
|
178
|
-
'state' => 'ready',
|
179
|
-
'time-left' => 0,
|
180
|
-
'timeouts' => 0,
|
181
|
-
'ttr' => 300,
|
182
|
-
'tube' => 'default',
|
183
|
-
}
|
184
|
-
stats_response = {
|
185
|
-
:body => stats_body,
|
186
|
-
:connection => @connection,
|
187
|
-
:id => 149,
|
188
|
-
:status => 'OK',
|
189
|
-
}
|
190
|
-
job = StalkClimber::Job.new(stats_response)
|
191
|
-
job.instance_variable_set(:@body, job_body)
|
192
|
-
expected_hash = Hash[stats_body.map { |k, v| [k.to_sym, v] }]
|
193
|
-
assert_equal expected_hash, job.to_h
|
280
|
+
|
281
|
+
context '#to_s' do
|
282
|
+
|
283
|
+
should 'return expected string representation of job' do
|
284
|
+
assert_equal "#<StalkClimber::Job id=#{@job.id} body=#{@job.body.inspect}>", @job.to_s
|
285
|
+
end
|
286
|
+
|
194
287
|
end
|
195
288
|
|
196
289
|
end
|
@@ -0,0 +1,106 @@
|
|
1
|
+
require 'test_helper'
|
2
|
+
|
3
|
+
class JobsTest < StalkClimber::TestCase
|
4
|
+
|
5
|
+
context '#each' do
|
6
|
+
|
7
|
+
setup do
|
8
|
+
@climber = StalkClimber::Climber.new(BEANSTALK_ADDRESSES)
|
9
|
+
|
10
|
+
@test_jobs = {}
|
11
|
+
@climber.connection_pool.connections.each do |connection|
|
12
|
+
@test_jobs[connection.address] = []
|
13
|
+
5.times.to_a.map! do
|
14
|
+
@test_jobs[connection.address] << StalkClimber::Job.new(connection.transmit(StalkClimber::Connection::PROBE_TRANSMISSION))
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
|
20
|
+
should 'cache jobs for later use' do
|
21
|
+
jobs = {}
|
22
|
+
@climber.jobs.each do |job|
|
23
|
+
jobs[job.connection.address] ||= {}
|
24
|
+
jobs[job.connection.address][job.id] = job
|
25
|
+
end
|
26
|
+
|
27
|
+
@climber.expects(:with_job).never
|
28
|
+
@climber.jobs.each do |job|
|
29
|
+
assert_equal jobs[job.connection.address][job.id], job
|
30
|
+
end
|
31
|
+
|
32
|
+
@climber.connection_pool.connections.each do |connection|
|
33
|
+
@test_jobs[connection.address].map(&:delete)
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
|
38
|
+
should 'allow breaking from enumeration' do
|
39
|
+
begin
|
40
|
+
count = 0
|
41
|
+
@climber.jobs.each do |job|
|
42
|
+
break if 2 == count += 1
|
43
|
+
assert(false, "Jobs#each did not break when expected") if count >= 3
|
44
|
+
end
|
45
|
+
rescue => e
|
46
|
+
assert(false, "Breaking from Jobs#each raised #{e.inspect}")
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
end
|
51
|
+
|
52
|
+
|
53
|
+
context '#each_threaded' do
|
54
|
+
|
55
|
+
should 'work correctly in non-break situations' do
|
56
|
+
climber = StalkClimber::Climber.new(BEANSTALK_ADDRESSES)
|
57
|
+
test_jobs = {}
|
58
|
+
climber.connection_pool.connections.each do |connection|
|
59
|
+
test_jobs[connection.address] = []
|
60
|
+
5.times.to_a.map! do
|
61
|
+
test_jobs[connection.address] << StalkClimber::Job.new(connection.transmit(StalkClimber::Connection::PROBE_TRANSMISSION))
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
climber.jobs.each_threaded do |job|
|
66
|
+
job
|
67
|
+
end
|
68
|
+
|
69
|
+
climber.connection_pool.connections.each do |connection|
|
70
|
+
test_jobs[connection.address].map(&:delete)
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
end
|
75
|
+
|
76
|
+
|
77
|
+
context 'enumberable contract' do
|
78
|
+
|
79
|
+
should 'function correctly as an enumerable' do
|
80
|
+
climber = StalkClimber::Climber.new(BEANSTALK_ADDRESSES)
|
81
|
+
test_jobs = {}
|
82
|
+
climber.connection_pool.connections.each do |connection|
|
83
|
+
test_jobs[connection.address] = []
|
84
|
+
5.times.to_a.map! do
|
85
|
+
test_jobs[connection.address] << StalkClimber::Job.new(connection.transmit(StalkClimber::Connection::PROBE_TRANSMISSION))
|
86
|
+
end
|
87
|
+
end
|
88
|
+
|
89
|
+
# verify enumeration can be short circuited
|
90
|
+
climber.jobs.any? do |job|
|
91
|
+
true
|
92
|
+
end
|
93
|
+
|
94
|
+
# test normal enumeration
|
95
|
+
climber.jobs.all? do |job|
|
96
|
+
job
|
97
|
+
end
|
98
|
+
|
99
|
+
climber.connection_pool.connections.each do |connection|
|
100
|
+
test_jobs[connection.address].map(&:delete)
|
101
|
+
end
|
102
|
+
end
|
103
|
+
|
104
|
+
end
|
105
|
+
|
106
|
+
end
|