tuber 0.0.1 → 0.6.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,342 @@
1
+ # frozen_string_literal: true
2
+
3
+ # test/tubes_test.rb
4
+
5
+ require File.expand_path('../test_helper', __FILE__)
6
+
7
+ describe Tuber::Tubes do
8
+ describe "for #find" do
9
+ before do
10
+ @beanstalk = stub
11
+ @tubes = Tuber::Tubes.new(@beanstalk)
12
+ end
13
+
14
+ it("should return Tube obj") { assert_kind_of Tuber::Tube, @tubes.find(:foo) }
15
+ it("should return Tube name") { assert_equal "foo", @tubes.find(:foo).name }
16
+ it("should support hash syntax") { assert_equal "bar", @tubes["bar"].name }
17
+ end # find
18
+
19
+ describe "for #use" do
20
+ before do
21
+ @beanstalk = Tuber.new(tuber_address)
22
+ end
23
+
24
+ it "should switch to used tube for valid name" do
25
+ Tuber::Tube.new(@beanstalk, 'some_name')
26
+ @beanstalk.tubes.use('some_name')
27
+ assert_equal 'some_name', @beanstalk.tubes.used.name
28
+ end
29
+
30
+ it "should raise for invalid tube name" do
31
+ assert_raises(Tuber::InvalidTubeName) { @beanstalk.tubes.use('; ') }
32
+ end
33
+ end # use
34
+
35
+ describe "for #watch & #watched" do
36
+ before do
37
+ @beanstalk = Tuber.new(tuber_address)
38
+ end
39
+
40
+ it 'should watch specified tubes' do
41
+ @beanstalk.tubes.watch('foo')
42
+ @beanstalk.tubes.watch('bar')
43
+ assert_equal ['default', 'foo', 'bar'].sort, @beanstalk.tubes.watched.map(&:name).sort
44
+ end
45
+
46
+ it 'should raise invalid name for bad tube' do
47
+ assert_raises(Tuber::InvalidTubeName) { @beanstalk.tubes.watch('; ') }
48
+ end
49
+ end # watch! & watched
50
+
51
+ describe "for #all" do
52
+ before do
53
+ @beanstalk = Tuber.new(tuber_address)
54
+ @beanstalk.tubes.find('foo').put 'bar'
55
+ @beanstalk.tubes.find('bar').put 'foo'
56
+ end
57
+
58
+ it 'should retrieve all tubes' do
59
+ ['default', 'foo', 'bar'].each do |t|
60
+ assert @beanstalk.tubes.all.map(&:name).include?(t)
61
+ end
62
+ end
63
+ end # all
64
+
65
+ describe "for Enumerable" do
66
+ before do
67
+ @beanstalk = Tuber.new(tuber_address)
68
+ @beanstalk.tubes.find('foo').put 'bar'
69
+ @beanstalk.tubes.find('bar').put 'foo'
70
+ end
71
+
72
+ it 'should map tubes' do
73
+ ['default', 'foo', 'bar'].each do |t|
74
+ assert @beanstalk.tubes.map(&:name).include?(t)
75
+ end
76
+ end
77
+ end
78
+
79
+ describe "for #used" do
80
+ before do
81
+ @beanstalk = Tuber.new(tuber_address)
82
+ @beanstalk.tubes.find('foo').put 'bar'
83
+ @beanstalk.tubes.find('bar').put 'foo'
84
+ end
85
+
86
+ it 'should retrieve used tube' do
87
+ assert_equal 'bar', @beanstalk.tubes.used.name
88
+ end
89
+
90
+ it 'should support dashed tubes' do
91
+ @beanstalk.tubes.find('der-bam').put 'foo'
92
+ assert_equal 'der-bam', @beanstalk.tubes.used.name
93
+ end
94
+ end # used
95
+
96
+ describe "for #watch!" do
97
+ before do
98
+ @beanstalk = Tuber.new(tuber_address)
99
+ end
100
+
101
+ it 'should watch specified tubes' do
102
+ @beanstalk.tubes.watch!(:foo)
103
+ @beanstalk.tubes.watch!('bar')
104
+ assert_equal ['bar'].sort, @beanstalk.tubes.watched.map(&:name).sort
105
+ end
106
+ end # watch!
107
+
108
+ describe "for #ignore" do
109
+ before do
110
+ @beanstalk = Tuber.new(tuber_address)
111
+ end
112
+
113
+ it 'should ignore specified tubes' do
114
+ @beanstalk.tubes.watch('foo')
115
+ @beanstalk.tubes.watch('bar')
116
+ @beanstalk.tubes.ignore('foo')
117
+ assert_equal ['default', 'bar'].sort, @beanstalk.tubes.watched.map(&:name).sort
118
+ end
119
+ end # ignore
120
+
121
+ describe "for #watch with weight" do
122
+ before do
123
+ @beanstalk = stub
124
+ @connection = stub(tubes_watched: ['default'])
125
+ @beanstalk.stubs(:connection).returns(@connection)
126
+ @tubes = Tuber::Tubes.new(@beanstalk)
127
+ end
128
+
129
+ it 'should send watch command with weight' do
130
+ @connection.expects(:transmit).with("watch foo 4").returns({status: "WATCHING", id: "2"})
131
+ @connection.expects(:add_to_watched).with("foo", 4)
132
+ @tubes.watch('foo', weight: 4)
133
+ end
134
+
135
+ it 'should send watch command without weight by default' do
136
+ @connection.expects(:transmit).with("watch foo").returns({status: "WATCHING", id: "2"})
137
+ @connection.expects(:add_to_watched).with("foo", nil)
138
+ @tubes.watch('foo')
139
+ end
140
+ end # watch with weight
141
+
142
+ describe "for #reserve_mode" do
143
+ before do
144
+ @beanstalk = stub
145
+ @connection = stub
146
+ @beanstalk.stubs(:connection).returns(@connection)
147
+ @tubes = Tuber::Tubes.new(@beanstalk)
148
+ end
149
+
150
+ it 'should send reserve-mode weighted command' do
151
+ @connection.expects(:transmit).with("reserve-mode weighted").returns({status: "USING", id: "weighted"})
152
+ @connection.expects(:reserve_mode=).with(:weighted)
153
+ @tubes.reserve_mode(:weighted)
154
+ end
155
+
156
+ it 'should send reserve-mode fifo command' do
157
+ @connection.expects(:transmit).with("reserve-mode fifo").returns({status: "USING", id: "fifo"})
158
+ @connection.expects(:reserve_mode=).with(:fifo)
159
+ @tubes.reserve_mode(:fifo)
160
+ end
161
+
162
+ it 'should record the mode on the connection so a reconnect can replay it' do
163
+ require_tuber!
164
+ client = Tuber.new(tuber_address)
165
+ begin
166
+ client.tubes.reserve_mode(:weighted)
167
+ assert_equal :weighted, client.connection.reserve_mode
168
+ ensure
169
+ client.close
170
+ end
171
+ end
172
+ end # reserve_mode
173
+
174
+ describe "for #reserve" do
175
+ before do
176
+ @beanstalk = Tuber.new(tuber_address)
177
+ @tube = @beanstalk.tubes.find 'tube'
178
+ @time = Time.now.to_i
179
+ @tube.put "foo reserve #{@time}"
180
+ end
181
+
182
+ it("should reserve job") do
183
+ @beanstalk.tubes.watch 'tube'
184
+ job = @beanstalk.tubes.reserve
185
+ assert_equal "foo reserve #{@time}", job.body
186
+ job.delete
187
+ end
188
+
189
+ it("should reserve job with block") do
190
+ @beanstalk.tubes.watch 'tube'
191
+ job = nil
192
+ @beanstalk.tubes.reserve { |j| job = j; job.delete }
193
+ assert_equal "foo reserve #{@time}", job.body
194
+ end
195
+
196
+ it("should reserve job with block and timeout") do
197
+ @beanstalk.tubes.watch 'tube'
198
+ job = nil
199
+ @beanstalk.tubes.reserve(0) { |j| job = j; job.delete }
200
+ assert_equal "foo reserve #{@time}", job.body
201
+ end
202
+
203
+ it "should raise TimedOutError with timeout" do
204
+ @beanstalk.tubes.watch 'tube'
205
+ @beanstalk.tubes.reserve(0) { |j| job = j; job.delete }
206
+ assert_raises(Tuber::TimedOutError) { @beanstalk.tubes.reserve(0) }
207
+ end
208
+
209
+ it "should raise DeadlineSoonError with ttr 1" do
210
+ @tube.reserve.delete
211
+ @tube.put "foo reserve #{@time}", :ttr => 1
212
+ @beanstalk.tubes.watch 'tube'
213
+ @beanstalk.tubes.reserve
214
+ assert_raises(Tuber::DeadlineSoonError) { @beanstalk.tubes.reserve(0) }
215
+ end
216
+
217
+ end # reserve
218
+
219
+ describe "for #reserve_batch" do
220
+ before do
221
+ require_tuber!
222
+ @beanstalk = Tuber.new(tuber_address)
223
+ @tube = @beanstalk.tubes.find 'batch_tube'
224
+ end
225
+
226
+ it "should return empty array on empty queue" do
227
+ @beanstalk.tubes.watch! 'batch_tube'
228
+ jobs = @beanstalk.tubes.reserve_batch(5)
229
+ assert_equal 0, jobs.size
230
+ end
231
+
232
+ it "should reserve 1 job" do
233
+ @tube.put "batch job 1"
234
+ @beanstalk.tubes.watch! 'batch_tube'
235
+ jobs = @beanstalk.tubes.reserve_batch(1)
236
+ assert_equal 1, jobs.size
237
+ assert_kind_of Tuber::Job, jobs.first
238
+ assert_equal "batch job 1", jobs.first.body
239
+ jobs.each(&:delete)
240
+ end
241
+
242
+ it "should reserve N jobs" do
243
+ 3.times { |i| @tube.put "batch job #{i}" }
244
+ @beanstalk.tubes.watch! 'batch_tube'
245
+ jobs = @beanstalk.tubes.reserve_batch(3)
246
+ assert_equal 3, jobs.size
247
+ jobs.each do |job|
248
+ assert_kind_of Tuber::Job, job
249
+ job.delete
250
+ end
251
+ end
252
+
253
+ it "should return partial results when fewer available than requested" do
254
+ 2.times { |i| @tube.put "partial job #{i}" }
255
+ @beanstalk.tubes.watch! 'batch_tube'
256
+ jobs = @beanstalk.tubes.reserve_batch(10)
257
+ assert_equal 2, jobs.size
258
+ jobs.each(&:delete)
259
+ end
260
+
261
+ it "should return deletable jobs" do
262
+ @tube.put "deletable job"
263
+ @beanstalk.tubes.watch! 'batch_tube'
264
+ jobs = @beanstalk.tubes.reserve_batch(1)
265
+ assert_equal 1, jobs.size
266
+ jobs.first.delete
267
+ assert_raises(Tuber::NotFoundError) { jobs.first.stats }
268
+ end
269
+
270
+ it "should return empty array when long-poll times out" do
271
+ @beanstalk.tubes.watch! 'batch_tube'
272
+ jobs = @beanstalk.tubes.reserve_batch(5, 1)
273
+ assert_equal 0, jobs.size
274
+ end
275
+
276
+ it "should drain ready jobs with a positive timeout" do
277
+ 2.times { |i| @tube.put "timeout job #{i}" }
278
+ @beanstalk.tubes.watch! 'batch_tube'
279
+ jobs = @beanstalk.tubes.reserve_batch(10, 1)
280
+ assert_equal 2, jobs.size
281
+ jobs.each(&:delete)
282
+ end
283
+
284
+ it "should block until a job arrives within the timeout" do
285
+ @beanstalk.tubes.watch! 'batch_tube'
286
+ Thread.new do
287
+ sleep 0.2
288
+ producer = Tuber.new(tuber_address)
289
+ producer.tubes.find('batch_tube').put "delayed job"
290
+ producer.close
291
+ end
292
+ jobs = @beanstalk.tubes.reserve_batch(5, 3)
293
+ assert_equal 1, jobs.size
294
+ assert_equal "delayed job", jobs.first.body
295
+ jobs.each(&:delete)
296
+ end
297
+ end # reserve_batch
298
+ describe "for #reserve_job" do
299
+ before do
300
+ @beanstalk = Tuber.new(tuber_address)
301
+ @tube = @beanstalk.tubes.find 'reserve_job_tube'
302
+ @time = Time.now.to_i
303
+ @tube.put "reserve_job test #{@time}"
304
+ end
305
+
306
+ it "should reserve a specific job by id" do
307
+ job_id = @tube.peek(:ready).id
308
+ job = @beanstalk.tubes.reserve_job(job_id)
309
+ assert_kind_of Tuber::Job, job
310
+ assert_equal job_id, job.id
311
+ assert_equal "reserve_job test #{@time}", job.body
312
+ job.delete
313
+ end
314
+
315
+ it "should return nil for non-existent job" do
316
+ result = @beanstalk.tubes.reserve_job(999999999)
317
+ assert_nil result
318
+ end
319
+ end # reserve_job
320
+
321
+ describe "for #stats_group" do
322
+ before do
323
+ require_tuber!
324
+ @beanstalk = Tuber.new(tuber_address)
325
+ @tube = @beanstalk.tubes.find 'stats_group_tube'
326
+ @group_name = "test_group_#{Time.now.to_i}"
327
+ 2.times { @tube.put "group job", grp: @group_name }
328
+ end
329
+
330
+ it "should return stats for a group" do
331
+ stats = @beanstalk.tubes.stats_group(@group_name)
332
+ assert_equal @group_name, stats.name
333
+ assert_equal 2, stats.ready
334
+ assert_equal 0, stats.reserved
335
+ assert_equal 0, stats.buried
336
+ end
337
+
338
+ it "should raise NotFoundError for non-existent group" do
339
+ assert_raises(Tuber::NotFoundError) { @beanstalk.tubes.stats_group("nonexistent_group_xyz") }
340
+ end
341
+ end # stats_group
342
+ end # Tuber::Tubes
data/tuber.gemspec ADDED
@@ -0,0 +1,33 @@
1
+ # frozen_string_literal: true
2
+ # -*- encoding: utf-8 -*-
3
+ lib = File.expand_path('../lib', __FILE__)
4
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
5
+ require 'tuber/version'
6
+
7
+ Gem::Specification.new do |gem|
8
+ gem.name = "tuber"
9
+ gem.version = Tuber::VERSION
10
+ gem.authors = ["Dan Milne", "Nico Taing"]
11
+ gem.email = ["d@nmilne.com"]
12
+ gem.description = %q{The Ruby client for the Tuber job queue server: unique jobs, concurrency keys, job group pipelines, batch operations and weighted tubes. Also fully compatible with beanstalkd.}
13
+ gem.summary = %q{Ruby client for the Tuber job queue server.}
14
+ gem.homepage = "https://github.com/tuberq/tuber-gem"
15
+ gem.license = 'MIT'
16
+
17
+ gem.required_ruby_version = '>= 2.7.0'
18
+
19
+ gem.metadata = {
20
+ 'source_code_uri' => gem.homepage,
21
+ 'changelog_uri' => "#{gem.homepage}/blob/main/CHANGELOG.md",
22
+ 'bug_tracker_uri' => "#{gem.homepage}/issues",
23
+ }
24
+
25
+ gem.files = `git ls-files`.split($/)
26
+ gem.executables = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
27
+ gem.require_paths = ["lib"]
28
+ gem.add_development_dependency 'minitest', "~> 4.1.0"
29
+ gem.add_development_dependency 'rake'
30
+ gem.add_development_dependency 'mocha'
31
+ gem.add_development_dependency 'term-ansicolor'
32
+ gem.add_development_dependency 'json'
33
+ end
metadata CHANGED
@@ -1,30 +1,135 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: tuber
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.1
4
+ version: 0.6.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Dan Milne
8
+ - Nico Taing
8
9
  bindir: bin
9
10
  cert_chain: []
10
11
  date: 1980-01-02 00:00:00.000000000 Z
11
- dependencies: []
12
- description: Ruby client for Tuber, a fast beanstalkd-compatible job queue server.
13
- This release reserves the gem name; use the russet gem for a full-featured client
14
- in the meantime.
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: minitest
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: 4.1.0
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: 4.1.0
27
+ - !ruby/object:Gem::Dependency
28
+ name: rake
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: '0'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ">="
39
+ - !ruby/object:Gem::Version
40
+ version: '0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: mocha
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ">="
46
+ - !ruby/object:Gem::Version
47
+ version: '0'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ">="
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: term-ansicolor
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - ">="
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - ">="
67
+ - !ruby/object:Gem::Version
68
+ version: '0'
69
+ - !ruby/object:Gem::Dependency
70
+ name: json
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - ">="
74
+ - !ruby/object:Gem::Version
75
+ version: '0'
76
+ type: :development
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - ">="
81
+ - !ruby/object:Gem::Version
82
+ version: '0'
83
+ description: 'The Ruby client for the Tuber job queue server: unique jobs, concurrency
84
+ keys, job group pipelines, batch operations and weighted tubes. Also fully compatible
85
+ with beanstalkd.'
15
86
  email:
16
87
  - d@nmilne.com
17
88
  executables: []
18
89
  extensions: []
19
90
  extra_rdoc_files: []
20
91
  files:
92
+ - ".github/workflows/ruby.yml"
93
+ - ".gitignore"
94
+ - ".yardopts"
95
+ - CHANGELOG.md
96
+ - Gemfile
97
+ - LICENSE.txt
21
98
  - README.md
99
+ - Rakefile
100
+ - examples/demo.rb
22
101
  - lib/tuber.rb
102
+ - lib/tuber/configuration.rb
103
+ - lib/tuber/connection.rb
104
+ - lib/tuber/errors.rb
105
+ - lib/tuber/job.rb
106
+ - lib/tuber/job/collection.rb
107
+ - lib/tuber/job/record.rb
108
+ - lib/tuber/stats.rb
109
+ - lib/tuber/stats/fast_struct.rb
110
+ - lib/tuber/stats/stat_struct.rb
111
+ - lib/tuber/tube.rb
112
+ - lib/tuber/tube/collection.rb
113
+ - lib/tuber/tube/record.rb
114
+ - lib/tuber/version.rb
115
+ - test/connection_test.rb
116
+ - test/errors_test.rb
117
+ - test/job_test.rb
118
+ - test/jobs_test.rb
119
+ - test/prompt_regexp_test.rb
120
+ - test/stat_struct_test.rb
121
+ - test/stats_test.rb
122
+ - test/test_helper.rb
123
+ - test/tube_test.rb
124
+ - test/tuber_test.rb
125
+ - test/tubes_test.rb
126
+ - tuber.gemspec
23
127
  homepage: https://github.com/tuberq/tuber-gem
24
128
  licenses:
25
129
  - MIT
26
130
  metadata:
27
131
  source_code_uri: https://github.com/tuberq/tuber-gem
132
+ changelog_uri: https://github.com/tuberq/tuber-gem/blob/main/CHANGELOG.md
28
133
  bug_tracker_uri: https://github.com/tuberq/tuber-gem/issues
29
134
  rdoc_options: []
30
135
  require_paths:
@@ -42,5 +147,5 @@ required_rubygems_version: !ruby/object:Gem::Requirement
42
147
  requirements: []
43
148
  rubygems_version: 4.0.16
44
149
  specification_version: 4
45
- summary: Ruby client for the Tuber job queue server
150
+ summary: Ruby client for the Tuber job queue server.
46
151
  test_files: []