sidejob 4.0.2 → 4.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.
@@ -119,8 +119,8 @@ describe SideJob::Port do
119
119
 
120
120
  it 'can return null default value' do
121
121
  @port1.default = nil
122
- expect(@port1.default).to be nil
123
- expect(@port1.default?).to be true
122
+ expect(@port1.default).to eq nil
123
+ expect(@port1.default?).to eq true
124
124
  end
125
125
  end
126
126
 
@@ -150,22 +150,65 @@ describe SideJob::Port do
150
150
  end
151
151
  end
152
152
 
153
+ describe '#channels, #channels=' do
154
+ before do
155
+ @channels = ['abc123', 'def456']
156
+ end
157
+
158
+ it 'can set and return channels for inport' do
159
+ expect(@port1.channels).to eq []
160
+ @channels.each do |ch|
161
+ expect(SideJob.redis.smembers("channel:#{ch}")).to eq []
162
+ end
163
+ @port1.channels = @channels
164
+ expect(@port1.channels).to match_array(@channels)
165
+ @channels.each do |ch|
166
+ expect(SideJob.redis.smembers("channel:#{ch}")).to eq [@port1.job.id.to_s]
167
+ end
168
+ @port1.channels = []
169
+ expect(@port1.channels).to eq []
170
+ @channels.each do |ch|
171
+ # We don't remove old jobs until we publish to the channel
172
+ expect(SideJob.redis.smembers("channel:#{ch}")).to eq [@port1.job.id.to_s]
173
+ end
174
+ end
175
+
176
+ it 'can set and return channels for outport' do
177
+ expect(@out1.channels).to eq []
178
+ @out1.channels = @channels
179
+ @channels.each do |ch|
180
+ expect(SideJob.redis.smembers("channel:#{ch}")).to eq []
181
+ end
182
+ expect(@out1.channels).to match_array(@channels)
183
+ @channels.each do |ch|
184
+ expect(SideJob.redis.smembers("channel:#{ch}")).to eq []
185
+ end
186
+ @out1.channels = []
187
+ expect(@out1.channels).to eq []
188
+ end
189
+ end
190
+
153
191
  describe '#write' do
154
192
  it 'can write different types of data to a port' do
155
- ['abc', 123, true, false, nil, {abc: 123}, [1, {foo: true}]].each {|x| @port1.write x}
156
- data = SideJob.redis.lrange(@port1.redis_key, 0, -1)
157
- expect(data).to eq(['"abc"', '123', 'true', 'false', 'null', '{"abc":123}', '[1,{"foo":true}]'])
193
+ data = ['abc', 123, true, false, nil, {'abc' => 123}, [1, {'foo' => true}]]
194
+ data.each {|x| @port1.write x}
195
+ expect(@port1.entries).to eq(data)
158
196
  end
159
197
 
160
198
  it 'logs writes' do
161
- now = Time.now
162
- allow(Time).to receive(:now) { now }
163
- SideJob::Port.log_group do
199
+ expect(SideJob).to receive(:log).with({read: [], write: [{job: @port1.job.id, inport: :port1, data: ['abc', 123]}]})
200
+ SideJob::Port.group do
164
201
  @port1.write 'abc'
165
202
  @port1.write 123
166
203
  end
167
- expect(SideJob.logs).to eq [{'timestamp' => SideJob.timestamp, 'read' => [],
168
- 'write' => ['job' => @job.id, 'inport' => 'port1', 'data' => ['abc', 123]]}]
204
+ end
205
+
206
+ it 'can disable logging for both reading and writing' do
207
+ expect(SideJob).not_to receive(:log)
208
+ SideJob::Port.group(log: false) do
209
+ @port1.write 'abc'
210
+ end
211
+ expect(@port1.read).to eq 'abc'
169
212
  end
170
213
 
171
214
  it 'raises error if port does not exist' do
@@ -191,6 +234,34 @@ describe SideJob::Port do
191
234
  expect(@job.status).to eq 'completed'
192
235
  expect(parent.status).to eq 'queued'
193
236
  end
237
+
238
+ it 'can disable running job' do
239
+ parent = SideJob.queue('testq', 'TestWorker')
240
+ parent.adopt(@job, 'child')
241
+ parent.status = 'completed'
242
+ @job.status = 'completed'
243
+ SideJob::Port.group(notify: false) do
244
+ @port1.write 3
245
+ @out1.write 3
246
+ end
247
+ expect(@job.status).to eq 'completed'
248
+ expect(parent.status).to eq 'completed'
249
+ end
250
+
251
+ it 'publishes writes to associated output port channel' do
252
+ data = {'abc' => [1,2]}
253
+ @out1.channels = ['mychannel']
254
+ expect(SideJob).to receive(:publish).with('mychannel', data)
255
+ expect(SideJob).to receive(:publish)
256
+ @out1.write data
257
+ end
258
+
259
+ it 'does not publish writes to associated input port channel' do
260
+ data = {'abc' => [1,2]}
261
+ @port1.channels = ['mychannel']
262
+ expect(SideJob).not_to receive(:publish).with('mychannel', data)
263
+ @port1.write data
264
+ end
194
265
  end
195
266
 
196
267
  describe '#read' do
@@ -225,21 +296,25 @@ describe SideJob::Port do
225
296
 
226
297
  it 'can use false default value' do
227
298
  port = @job.input(:default_false)
228
- expect(port.read).to be false
299
+ expect(port.read).to eq false
229
300
  end
230
301
 
231
302
  it 'logs reads' do
232
- now = Time.now
233
- allow(Time).to receive(:now) { now }
234
303
  ['abc', 123].each {|x| @port1.write x}
235
- SideJob.logs
236
- SideJob::Port.log_group do
304
+ expect(SideJob).to receive(:log).with({read: [{job: @port1.job.id, inport: :port1, data: ['abc', 123]}], write: []})
305
+ SideJob::Port.group do
306
+ expect(@port1.read).to eq('abc')
307
+ expect(@port1.read).to eq(123)
308
+ end
309
+ end
310
+
311
+ it 'can disable read logging' do
312
+ ['abc', 123].each {|x| @port1.write x}
313
+ expect(SideJob).not_to receive(:log)
314
+ SideJob::Port.group(log: false) do
237
315
  expect(@port1.read).to eq('abc')
238
316
  expect(@port1.read).to eq(123)
239
317
  end
240
- expect(SideJob.logs).to eq [{'timestamp' => SideJob.timestamp,
241
- 'read' => ['job' => @job.id, 'inport' => 'port1', 'data' => ['abc', 123]],
242
- 'write' => []}]
243
318
  end
244
319
  end
245
320
 
@@ -320,34 +395,29 @@ describe SideJob::Port do
320
395
  end
321
396
 
322
397
  it 'logs data' do
323
- now = Time.now
324
- allow(Time).to receive(:now) { now }
325
398
  @out1.write 1
326
399
  @out1.write [2,3]
327
- SideJob.logs(clear: true)
400
+ expect(SideJob).to receive(:log).with({read: [{job: @out1.job.id, outport: :out1, data: [1,[2,3]]}], write: [{job: @out1.job.id, inport: :port1, data: [1,[2,3]]}]})
328
401
  @out1.connect_to(@port1)
329
- expect(SideJob.logs).to eq([{'timestamp' => SideJob.timestamp,
330
- 'read' => [{'job' => @job.id, 'outport' => 'out1', 'data' => [1,[2,3]]}],
331
- 'write' => [{'job' => @job.id, 'inport' => 'port1', 'data' => [1,[2,3]]}] }])
332
- end
333
-
334
- it 'can use SideJob.log_context to specify additional metadata' do
335
- now = Time.now
336
- allow(Time).to receive(:now) { now }
337
- @out1.write 1
338
- @out1.write [2,3]
339
- SideJob.logs(clear: true)
340
- SideJob.log_context(user: 'test') do
341
- @out1.connect_to(@port1)
342
- end
343
- expect(SideJob.logs).to eq([{'timestamp' => SideJob.timestamp, 'user' => 'test',
344
- 'read' => [{'job' => @job.id, 'outport' => 'out1', 'data' => [1,[2,3]]}],
345
- 'write' => [{'job' => @job.id, 'inport' => 'port1', 'data' => [1,[2,3]]}] }])
346
402
  end
347
403
 
348
404
  it 'does not log if no data on port' do
405
+ expect(SideJob).not_to receive(:publish)
349
406
  @out1.connect_to(@port1)
350
- expect(SideJob.logs).to eq([])
407
+ end
408
+
409
+ it 'publishes to associated outport channels' do
410
+ dest = [@port1, @out1]
411
+ @out1.channels = ['channel1']
412
+ @port1.channels = ['channel2']
413
+ @default.channels = ['channel3']
414
+ @default.write 1
415
+ @default.write [2,3]
416
+
417
+ allow(SideJob).to receive(:publish)
418
+ expect(SideJob).to receive(:publish).with('channel1', 1)
419
+ expect(SideJob).to receive(:publish).with('channel1', [2,3])
420
+ @default.connect_to dest
351
421
  end
352
422
  end
353
423
 
@@ -400,67 +470,137 @@ describe SideJob::Port do
400
470
  end
401
471
  end
402
472
 
403
- describe '.log_group' do
404
- before do
405
- now = Time.now
406
- allow(Time).to receive(:now) { now }
407
- end
408
-
473
+ describe '.group' do
409
474
  it 'does not log anything if no port operations occur within the block' do
410
- SideJob::Port.log_group {}
411
- expect(SideJob.logs.length).to eq 0
475
+ expect(SideJob).not_to receive(:log)
476
+ SideJob::Port.group {}
412
477
  end
413
478
 
414
479
  it 'groups all port logs within the block' do
415
- SideJob::Port.log_group do
480
+ expect(SideJob).to receive(:log).with({
481
+ read: [{job: @port1.job.id, inport: :port1, data: ['abc']}],
482
+ write: [{job: @port1.job.id, inport: :port1, data: ['abc', 'def']},
483
+ {job: @out1.job.id, outport: :out1, data: ['xyz']}],
484
+ })
485
+ SideJob::Port.group do
416
486
  @port1.write 'abc'
417
487
  @port1.read
418
488
  @port1.write 'def'
419
489
  @out1.write 'xyz'
420
490
  end
421
- expect(SideJob.logs).to eq [{'timestamp' => SideJob.timestamp,
422
- 'read' => [{'job' => @port1.job.id, 'inport' => 'port1', 'data' => ['abc']}],
423
- 'write' => [{'job' => @port1.job.id, 'inport' => 'port1', 'data' => ['abc', 'def']}, {'job' => @out1.job.id, 'outport' => 'out1', 'data' => ['xyz']} ]}]
424
491
  end
425
492
 
426
493
  it 'does not write out log until the end of outermost group' do
427
- SideJob::Port.log_group do
494
+ expect(SideJob).to receive(:log).with({
495
+ read: [],
496
+ write: [{job: @port1.job.id, inport: :port1, data: ['hello', 2]}],
497
+ })
498
+ SideJob::Port.group do
428
499
  @port1.write 'hello'
429
- SideJob::Port.log_group do
500
+ SideJob::Port.group do
430
501
  @port1.write 2
431
502
  end
432
- expect(SideJob.logs.length).to eq 0
433
503
  end
434
- expect(SideJob.logs).to eq [{'timestamp' => SideJob.timestamp,
435
- 'read' => [],
436
- 'write' => [{'job' => @port1.job.id, 'inport' => 'port1', 'data' => ['hello', 2]}]}]
437
504
  end
438
505
 
439
- it 'works with SideJob.log_context' do
440
- SideJob.log_context(user: 'foo') do
441
- SideJob::Port.log_group do
506
+ it 'works with SideJob.context' do
507
+ now = Time.now
508
+ allow(Time).to receive(:now) { now }
509
+ allow(SideJob).to receive(:publish)
510
+ expect(SideJob).to receive(:publish).with('/sidejob/log', {
511
+ user: 'foo',
512
+ read: [{job: @port1.job.id, inport: :port1, data: ['abc']}],
513
+ write: [{job: @port1.job.id, inport: :port1, data: ['abc']}],
514
+ timestamp: SideJob.timestamp})
515
+ SideJob.context(user: 'foo') do
516
+ SideJob::Port.group do
442
517
  @port1.write 'abc'
443
518
  @port1.read
444
519
  end
445
520
  end
446
- expect(SideJob.logs).to eq [{'timestamp' => SideJob.timestamp, 'user' => 'foo',
447
- 'read' => [{'job' => @port1.job.id, 'inport' => 'port1', 'data' => ['abc']}],
448
- 'write' => [{'job' => @port1.job.id, 'inport' => 'port1', 'data' => ['abc']}]}]
449
521
  end
450
522
 
451
523
  it 'logs correctly even if data is changed' do
524
+ expect(SideJob).to receive(:log).with({
525
+ read: [{job: @port1.job.id, inport: :port1, data: [{'x' => [1,2]},{'x' => [1,2,3]}]}],
526
+ write: [{job: @port1.job.id, inport: :port1, data: [{'x' => [1,2]},{'x' => [1,2,3]}]}],
527
+ })
452
528
  data = {'x' => [1,2]}
453
- SideJob::Port.log_group do
529
+ SideJob::Port.group do
454
530
  @port1.write data
455
531
  expect(@port1.read).to eq data
456
532
  data['x'].push 3
457
533
  @port1.write data
458
534
  expect(@port1.read).to eq data
459
535
  end
460
- expect(SideJob.logs).to eq [{'timestamp' => SideJob.timestamp,
461
- 'read' => [{'job' => @port1.job.id, 'inport' => 'port1', 'data' => [{'x' => [1,2]},{'x' => [1,2,3]}]}],
462
- 'write' => [{'job' => @port1.job.id, 'inport' => 'port1', 'data' => [{'x' => [1,2]},{'x' => [1,2,3]}]}],
463
- }]
536
+ end
537
+
538
+ it 'can set options' do
539
+ SideJob::Port.group(log: true, notify: false, set_default: true) do
540
+ expect(Thread.current[:sidejob_port_group][:options]).to eq({log: true, notify: false, set_default: true})
541
+ end
542
+ expect(Thread.current[:sidejob_port_group]).to be nil
543
+ end
544
+
545
+ it 'can merge options in nested groups' do
546
+ SideJob::Port.group(log: false) do
547
+ expect(Thread.current[:sidejob_port_group][:options]).to eq({log: false})
548
+ SideJob::Port.group(notify: true) do
549
+ expect(Thread.current[:sidejob_port_group][:options]).to eq({log: false, notify: true})
550
+ end
551
+ expect(Thread.current[:sidejob_port_group][:options]).to eq({log: false})
552
+ end
553
+ expect(Thread.current[:sidejob_port_group]).to be nil
554
+ end
555
+ end
556
+
557
+ describe '.encode_data' do
558
+ it 'encodes data with no context' do
559
+ expect(JSON.parse(SideJob::Port.encode_data(5))).to eq({ 'data' => 5 })
560
+ end
561
+
562
+ it 'handles context' do
563
+ SideJob.context({xyz: 456}) do
564
+ expect(JSON.parse(SideJob::Port.encode_data([1,2]))).to eq({ 'context' => {'xyz' => 456}, 'data' => [1,2] })
565
+ end
566
+ end
567
+
568
+ it 'handles port group options' do
569
+ SideJob::Port.group(log: true, notify: false) do
570
+ expect(JSON.parse(SideJob::Port.encode_data([1,2]))).to eq({ 'options' => {'log' => true, 'notify' => false}, 'data' => [1,2] })
571
+ end
572
+ end
573
+ end
574
+
575
+ describe '.decode_data' do
576
+ it 'returns None if no data' do
577
+ expect(SideJob::Port.decode_data(nil)).to be SideJob::Port::None
578
+ end
579
+
580
+ it 'decodes object with no context' do
581
+ x = SideJob::Port.decode_data(SideJob::Port.encode_data(1.23))
582
+ expect(x.sidejob_context).to eq({})
583
+ end
584
+
585
+ it 'handles context' do
586
+ SideJob.context({abc: 'foo'}) do
587
+ SideJob.context({xyz: 456}) do
588
+ x = SideJob::Port.decode_data(SideJob::Port.encode_data(nil))
589
+ expect(x.sidejob_context).to eq({'abc' => 'foo', 'xyz' => 456})
590
+ end
591
+ end
592
+ end
593
+
594
+ it 'handles port group options' do
595
+ SideJob::Port.group(log: true, notify: false) do
596
+ expect(SideJob::Port.decode_data(SideJob::Port.encode_data([1,2])).sidejob_options).to eq({ 'log' => true, 'notify' => false})
597
+ end
598
+ end
599
+
600
+ it 'decoded data should equal original data' do
601
+ ['abc', [1,2], {'abc' => [1,2]}, 1, 1.23, true, false, nil].each do |x|
602
+ expect(SideJob::Port.decode_data(SideJob::Port.encode_data(x))).to eq x
603
+ end
464
604
  end
465
605
  end
466
606
  end
@@ -1,6 +1,17 @@
1
1
  require 'spec_helper'
2
2
 
3
3
  describe SideJob::ServerMiddleware do
4
+ class TestWorkerStartup
5
+ include SideJob::Worker
6
+ register
7
+ attr_accessor :startup_called
8
+ def startup
9
+ @startup_called = true
10
+ end
11
+ def perform
12
+ end
13
+ end
14
+
4
15
  class TestWorkerShutdown
5
16
  include SideJob::Worker
6
17
  register
@@ -73,7 +84,7 @@ describe SideJob::ServerMiddleware do
73
84
  it 'sets the ran_at time at the beginning of the run' do
74
85
  now = Time.now
75
86
  allow(Time).to receive(:now) { now }
76
- process(@job) { |worker| @ran_at = worker.get(:ran_at) }
87
+ process(@job) { |worker| @ran_at = worker.info[:ran_at] }
77
88
  expect(@ran_at).to eq SideJob.timestamp
78
89
  expect(@job.status).to eq 'completed'
79
90
  end
@@ -147,15 +158,11 @@ describe SideJob::ServerMiddleware do
147
158
  it 'sets status to failed on exception and logs error' do
148
159
  now = Time.now
149
160
  allow(Time).to receive(:now) { now }
150
- process(@job) { raise 'oops' }
161
+ SideJob::ServerMiddleware.raise_errors = false
162
+ exception = RuntimeError.new('oops')
163
+ expect(SideJob).to receive(:log).with(exception)
164
+ process(@job) { raise exception }
151
165
  expect(@job.status).to eq 'failed'
152
-
153
- log = SideJob.logs.select {|log| log['error'] }
154
- expect(log.size).to eq(1)
155
- expect(log[0]['job']).to eq @job.id
156
- expect(log[0]['error']).to eq('oops')
157
- # check that we trim down backtrace to remove sidekiq lines
158
- expect(log[0]['backtrace']).to_not match(/sidekiq/)
159
166
  end
160
167
 
161
168
  it 'does not set status to failed if status is terminating' do
@@ -190,13 +197,19 @@ describe SideJob::ServerMiddleware do
190
197
  end
191
198
  end
192
199
 
200
+ describe 'handles job startup' do
201
+ it 'calls worker startup method' do
202
+ @job = SideJob.queue(@queue, 'TestWorkerStartup')
203
+ worker = process(@job) { }
204
+ expect(worker.startup_called).to be true
205
+ end
206
+ end
207
+
193
208
  describe 'handles job termination' do
194
209
  it 'sets status to terminated upon run' do
195
210
  @job.status = 'terminating'
196
211
  process(@job) { raise 'should not be called' }
197
212
  expect(@job.status).to eq 'terminated'
198
- errors = SideJob.logs.select {|log| log['type'] == 'error'}
199
- expect(errors.size).to eq 0
200
213
  end
201
214
 
202
215
  it 'runs parent' do
@@ -217,11 +230,13 @@ describe SideJob::ServerMiddleware do
217
230
  it 'logs but ignores exceptions thrown during shutdown' do
218
231
  @job = SideJob.queue(@queue, 'TestWorkerShutdownError')
219
232
  @job.status = 'terminating'
233
+ logged = false
234
+ expect(SideJob).to receive(:log) do |exception|
235
+ expect(exception.message).to eq 'shutdown error'
236
+ logged = true
237
+ end
220
238
  worker = process(@job) { raise 'not reached' }
221
- logs = SideJob.logs.select {|log| log['error']}
222
- expect(logs.size).to eq 1
223
- expect(logs[0]['job']).to eq @job.id
224
- expect(logs[0]['error']).to eq 'shutdown error'
239
+ expect(logged).to be true
225
240
  end
226
241
  end
227
242
  end