dispatch-rider 1.5.3 → 1.6.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (53) hide show
  1. checksums.yaml +4 -4
  2. data/Gemfile +2 -2
  3. data/lib/dispatch-rider.rb +1 -0
  4. data/lib/dispatch-rider/configuration.rb +12 -5
  5. data/lib/dispatch-rider/demultiplexer.rb +3 -27
  6. data/lib/dispatch-rider/logging.rb +10 -0
  7. data/lib/dispatch-rider/logging/base_formatter.rb +30 -0
  8. data/lib/dispatch-rider/logging/json_formatter.rb +75 -0
  9. data/lib/dispatch-rider/logging/lifecycle_logger.rb +53 -0
  10. data/lib/dispatch-rider/logging/text_formatter.rb +48 -0
  11. data/lib/dispatch-rider/queue_services/file_system/queue.rb +13 -2
  12. data/lib/dispatch-rider/version.rb +1 -1
  13. data/spec/lib/dispatch-rider/airbrake_error_handler_spec.rb +10 -3
  14. data/spec/lib/dispatch-rider/callbacks/access_spec.rb +16 -18
  15. data/spec/lib/dispatch-rider/callbacks/storage_spec.rb +4 -9
  16. data/spec/lib/dispatch-rider/configuration_spec.rb +3 -3
  17. data/spec/lib/dispatch-rider/default_error_handler_spec.rb +2 -2
  18. data/spec/lib/dispatch-rider/demultiplexer_spec.rb +14 -14
  19. data/spec/lib/dispatch-rider/dispatcher_spec.rb +10 -8
  20. data/spec/lib/dispatch-rider/handlers/base_spec.rb +27 -22
  21. data/spec/lib/dispatch-rider/handlers/inheritance_tracking_spec.rb +6 -6
  22. data/spec/lib/dispatch-rider/logging/json_formatter_spec.rb +72 -0
  23. data/spec/lib/dispatch-rider/logging/lifecycle_logger_spec.rb +73 -0
  24. data/spec/lib/dispatch-rider/logging/text_formatter_spec.rb +61 -0
  25. data/spec/lib/dispatch-rider/message_spec.rb +11 -11
  26. data/spec/lib/dispatch-rider/notification_services/aws_sns_spec.rb +14 -13
  27. data/spec/lib/dispatch-rider/notification_services/base_spec.rb +18 -13
  28. data/spec/lib/dispatch-rider/notification_services/file_system/channel_spec.rb +2 -3
  29. data/spec/lib/dispatch-rider/notification_services/file_system/notifier_spec.rb +1 -3
  30. data/spec/lib/dispatch-rider/notification_services/file_system_spec.rb +3 -4
  31. data/spec/lib/dispatch-rider/publisher/configuration/destination_spec.rb +30 -21
  32. data/spec/lib/dispatch-rider/publisher/configuration/notification_service_spec.rb +22 -16
  33. data/spec/lib/dispatch-rider/publisher/configuration_reader_spec.rb +11 -10
  34. data/spec/lib/dispatch-rider/publisher/configuration_spec.rb +12 -12
  35. data/spec/lib/dispatch-rider/publisher/configuration_support_spec.rb +11 -11
  36. data/spec/lib/dispatch-rider/publisher_spec.rb +22 -15
  37. data/spec/lib/dispatch-rider/queue_services/aws_sqs_spec.rb +44 -36
  38. data/spec/lib/dispatch-rider/queue_services/base_spec.rb +41 -28
  39. data/spec/lib/dispatch-rider/queue_services/file_system_spec.rb +15 -14
  40. data/spec/lib/dispatch-rider/queue_services/received_message_spec.rb +3 -3
  41. data/spec/lib/dispatch-rider/queue_services/simple_spec.rb +9 -9
  42. data/spec/lib/dispatch-rider/registrars/base_spec.rb +5 -5
  43. data/spec/lib/dispatch-rider/registrars/file_system_channel_spec.rb +3 -3
  44. data/spec/lib/dispatch-rider/registrars/handler_spec.rb +1 -1
  45. data/spec/lib/dispatch-rider/registrars/notification_service_spec.rb +1 -1
  46. data/spec/lib/dispatch-rider/registrars/publishing_destination_spec.rb +2 -2
  47. data/spec/lib/dispatch-rider/registrars/queue_service_spec.rb +1 -1
  48. data/spec/lib/dispatch-rider/registrars/sns_channel_spec.rb +5 -5
  49. data/spec/lib/dispatch-rider/runner_spec.rb +1 -1
  50. data/spec/lib/dispatch-rider/subscriber_spec.rb +45 -29
  51. data/spec/lib/dispatch-rider_spec.rb +3 -3
  52. data/spec/spec_helper.rb +3 -1
  53. metadata +13 -2
@@ -1,11 +1,9 @@
1
1
  require 'spec_helper'
2
2
 
3
3
  describe DispatchRider::Callbacks::Storage do
4
-
5
- subject{ described_class.new }
4
+ subject { described_class.new }
6
5
 
7
6
  describe "adding callbacks" do
8
-
9
7
  let!(:log) { [] }
10
8
  let(:actual) { proc { log << :actual } }
11
9
 
@@ -17,7 +15,7 @@ describe DispatchRider::Callbacks::Storage do
17
15
  log << :aafter
18
16
  end
19
17
  subject.for(:initialize).first[actual]
20
- log.should == [:abefore, :actual, :aafter]
18
+ expect(log).to eq [:abefore, :actual, :aafter]
21
19
  end
22
20
  end
23
21
 
@@ -25,7 +23,7 @@ describe DispatchRider::Callbacks::Storage do
25
23
  example do
26
24
  subject.before(:initialize) { log << :before }
27
25
  subject.for(:initialize).first[actual]
28
- log.should == [:before, :actual]
26
+ expect(log).to eq [:before, :actual]
29
27
  end
30
28
  end
31
29
 
@@ -33,11 +31,8 @@ describe DispatchRider::Callbacks::Storage do
33
31
  example do
34
32
  subject.after(:initialize) { log << :after }
35
33
  subject.for(:initialize).first[actual]
36
- log.should == [:actual, :after]
34
+ expect(log).to eq [:actual, :after]
37
35
  end
38
36
  end
39
-
40
37
  end
41
-
42
-
43
38
  end
@@ -2,14 +2,14 @@ require 'spec_helper'
2
2
 
3
3
  describe DispatchRider::Configuration do
4
4
 
5
- subject{ described_class.new }
5
+ subject { described_class.new }
6
6
 
7
7
  describe "defaults" do
8
8
  example do
9
9
  expect(subject.handler_path).to match_regex(/\/app\/handlers/)
10
10
  expect(subject.error_handler).to eq DispatchRider::DefaultErrorHandler
11
11
  expect(subject.queue_kind).to eq :file_system
12
- expect(subject.queue_info).to eq({ path: "tmp/dispatch-rider-queue" })
12
+ expect(subject.queue_info).to eq(path: "tmp/dispatch-rider-queue")
13
13
  expect(subject.subscriber).to eq DispatchRider::Subscriber
14
14
  end
15
15
  end
@@ -47,7 +47,7 @@ describe DispatchRider::Configuration do
47
47
  subject.default_retry_timeout = 60
48
48
  expect(TestHandler.instance_methods).to include(:retry_timeout)
49
49
  #Need to do this so that all the other tests don't have this as default!
50
- DispatchRider::Handlers::Base.send(:remove_method,:retry_timeout)
50
+ DispatchRider::Handlers::Base.send(:remove_method, :retry_timeout)
51
51
  end
52
52
  end
53
53
 
@@ -3,9 +3,9 @@ require "spec_helper"
3
3
  describe DispatchRider::DefaultErrorHandler do
4
4
 
5
5
  describe ".call" do
6
- let(:exception){ Exception.new("Something went terribly wrong") }
6
+ let(:exception) { Exception.new("Something went terribly wrong") }
7
7
  example do
8
- expect{
8
+ expect {
9
9
  described_class.call("Error", exception)
10
10
  }.to raise_exception exception
11
11
  end
@@ -1,6 +1,6 @@
1
1
  require 'spec_helper'
2
2
 
3
- describe DispatchRider::Demultiplexer, :nodb => true do
3
+ describe DispatchRider::Demultiplexer, nodb: true do
4
4
  class TestHandler < DispatchRider::Handlers::Base
5
5
  def process(options)
6
6
  raise "OMG!!!" if options["raise_exception"]
@@ -17,7 +17,7 @@ describe DispatchRider::Demultiplexer, :nodb => true do
17
17
  DispatchRider::QueueServices::Simple.new
18
18
  end
19
19
 
20
- let(:message){ DispatchRider::Message.new(:subject => "test_handler", :body => {}) }
20
+ let(:message) { DispatchRider::Message.new(subject: "test_handler", body: {}) }
21
21
 
22
22
  let(:demultiplexer_thread) do
23
23
  demultiplexer
@@ -28,17 +28,17 @@ describe DispatchRider::Demultiplexer, :nodb => true do
28
28
  thread
29
29
  end
30
30
 
31
- let(:error_handler){ ->(message, exception){ raise exception }}
31
+ let(:error_handler) { ->(_message, exception) { raise exception } }
32
32
 
33
33
  subject(:demultiplexer) { DispatchRider::Demultiplexer.new(queue, dispatcher, error_handler) }
34
34
 
35
35
  describe "#initialize" do
36
36
  it "should assign the queue" do
37
- demultiplexer.queue.should be_empty
37
+ expect(demultiplexer.queue).to be_empty
38
38
  end
39
39
 
40
40
  it "should assign the dispatcher" do
41
- demultiplexer.dispatcher.fetch(:test_handler).should eq(TestHandler)
41
+ expect(demultiplexer.dispatcher.fetch(:test_handler)).to eq(TestHandler)
42
42
  end
43
43
  end
44
44
 
@@ -55,7 +55,7 @@ describe DispatchRider::Demultiplexer, :nodb => true do
55
55
  end
56
56
 
57
57
  it "should be sending the message to the dispatcher" do
58
- demultiplexer.should_receive(:dispatch_message).with(message).at_least(:once)
58
+ expect(demultiplexer).to receive(:dispatch_message).with(message).at_least(:once)
59
59
  demultiplexer_thread.run
60
60
  sleep 0.01 # give it a chance to process the job async before killing the demux
61
61
  end
@@ -63,7 +63,7 @@ describe DispatchRider::Demultiplexer, :nodb => true do
63
63
  # THIS ALSO TESTS THAT THE JOB IS NOT RUN MULTIPLE TIMES
64
64
  # IF THIS FAILS, BE CAREFUL NOT TO INTRODUCE BUGS
65
65
  it "should call the correct handler" do
66
- TestHandler.any_instance.should_receive(:process).with(message.body).at_least(1).times
66
+ expect_any_instance_of(TestHandler).to receive(:process).with(message.body).at_least(1).times
67
67
  demultiplexer_thread.run
68
68
  sleep 0.01 # give it a chance to process the job async before killing the demux
69
69
  end
@@ -71,7 +71,7 @@ describe DispatchRider::Demultiplexer, :nodb => true do
71
71
 
72
72
  context "when the queue is empty" do
73
73
  it "should not be sending any message to the dispatcher" do
74
- demultiplexer.should_receive(:dispatch_message).exactly(0).times
74
+ expect(demultiplexer).to receive(:dispatch_message).exactly(0).times
75
75
  demultiplexer_thread.run
76
76
  end
77
77
  end
@@ -83,8 +83,8 @@ describe DispatchRider::Demultiplexer, :nodb => true do
83
83
  end
84
84
 
85
85
  it "should call the error handler" do
86
- error_handler.should_receive(:call).at_least(:once).and_return(true)
87
- queue.should_not_receive(:delete)
86
+ expect(error_handler).to receive(:call).at_least(:once).and_return(true)
87
+ expect(queue).not_to receive(:delete)
88
88
  demultiplexer_thread.run
89
89
  sleep 0.01 # give it a chance to process the job async before killing the demux
90
90
  end
@@ -92,11 +92,11 @@ describe DispatchRider::Demultiplexer, :nodb => true do
92
92
 
93
93
  context "when the queue crashes" do
94
94
  before do
95
- queue.stub(:pop){ raise "OMG!!!"}
95
+ allow(queue).to receive(:pop) { raise "OMG!!!" }
96
96
  end
97
97
 
98
98
  it "should call the error handler" do
99
- error_handler.should_receive(:call).once
99
+ expect(error_handler).to receive(:call).once
100
100
  demultiplexer_thread.run
101
101
 
102
102
  sleep 0.01 # give it a chance to process the job async before killing the demux
@@ -107,10 +107,10 @@ describe DispatchRider::Demultiplexer, :nodb => true do
107
107
  describe ".stop" do
108
108
  it "should stop the demultiplexer" do
109
109
  demultiplexer_thread.run
110
- demultiplexer_thread.should be_alive # looper should be looping
110
+ expect(demultiplexer_thread).to be_alive # looper should be looping
111
111
  demultiplexer_thread[:demultiplexer].stop
112
112
  demultiplexer_thread.join
113
- demultiplexer_thread.should_not be_alive # looper should close the loop
113
+ expect(demultiplexer_thread).not_to be_alive # looper should close the loop
114
114
  end
115
115
  end
116
116
 
@@ -8,21 +8,21 @@ describe DispatchRider::Dispatcher, :nodb => true do
8
8
  end
9
9
 
10
10
  class HandlerThatReturnsFalse < DispatchRider::Handlers::Base
11
- def process(params)
11
+ def process(_params)
12
12
  false
13
13
  end
14
14
  end
15
15
 
16
16
  describe "#dispatch" do
17
- let(:message){ DispatchRider::Message.new(:subject => "handle_something", :body => { :do_throw_something => true }) }
17
+ let(:message) { DispatchRider::Message.new(subject: "handle_something", body: { do_throw_something: true }) }
18
18
 
19
19
  describe "callbacks" do
20
20
  let(:dummy) { double(:dummy) }
21
21
  let(:storage) { DispatchRider::Callbacks::Storage.new }
22
- let(:message){ DispatchRider::Message.new(:subject => "handle_something", :body => { :do_throw_something => true }) }
22
+ let(:message) { DispatchRider::Message.new(subject: "handle_something", body: { do_throw_something: true }) }
23
23
 
24
24
  before do
25
- DispatchRider.config.stub(:callbacks) { storage }
25
+ allow(DispatchRider.config).to receive(:callbacks) { storage }
26
26
  storage.around(:dispatch_message) do |block, message|
27
27
  begin
28
28
  dummy.before
@@ -35,9 +35,9 @@ describe DispatchRider::Dispatcher, :nodb => true do
35
35
  subject.register('handle_something')
36
36
  end
37
37
  example do
38
- dummy.should_receive(:before).once
39
- dummy.should_receive(:after).once
40
- dummy.should_receive(:log).with(message).once
38
+ expect(dummy).to receive(:before).once
39
+ expect(dummy).to receive(:after).once
40
+ expect(dummy).to receive(:log).with(message).once
41
41
  catch(:something) do
42
42
  subject.dispatch(message)
43
43
  end
@@ -55,7 +55,9 @@ describe DispatchRider::Dispatcher, :nodb => true do
55
55
  end
56
56
 
57
57
  context "when the handler returns false" do
58
- let(:message){ DispatchRider::Message.new(:subject => "handler_that_returns_false", :body => { :do_throw_something => true }) }
58
+ let(:message) do
59
+ DispatchRider::Message.new(subject: "handler_that_returns_false", body: { do_throw_something: true })
60
+ end
59
61
 
60
62
  before :each do
61
63
  subject.register('handler_that_returns_false')
@@ -5,32 +5,38 @@ describe DispatchRider::Handlers::Base do
5
5
  end
6
6
 
7
7
  class ProcessImplemented < DispatchRider::Handlers::Base
8
- def process(options)
8
+ def process(_options)
9
9
  "good job"
10
10
  end
11
11
  end
12
-
12
+
13
13
  class ProcessWithImmediateRetry < DispatchRider::Handlers::Base
14
- def process(options)
14
+ def process(_options)
15
15
  raise "I have failed!"
16
16
  end
17
-
18
- def retry_timeout; :immediate; end
17
+
18
+ def retry_timeout
19
+ :immediate
20
+ end
19
21
  end
20
-
22
+
21
23
  class ProcessWithTenSecondRetry < DispatchRider::Handlers::Base
22
- def process(options)
24
+ def process(_options)
23
25
  raise "I have failed!"
24
26
  end
25
-
26
- def retry_timeout; 10*60; end
27
+
28
+ def retry_timeout
29
+ 10 * 60
30
+ end
27
31
  end
28
32
 
29
33
  describe "#do_process" do
30
- let(:message){ double(:message, subject: 'some_message', body: { 'guid' => DispatchRider::Debug::PUBLISHER_MESSAGE_GUID }) }
34
+ let(:message) do
35
+ double(:message, subject: 'some_message', body: { 'guid' => DispatchRider::Debug::PUBLISHER_MESSAGE_GUID })
36
+ end
31
37
 
32
38
  context "when class doesn't implement process" do
33
- let(:handler){ NoProcessImplemented.new }
39
+ let(:handler) { NoProcessImplemented.new }
34
40
 
35
41
  example do
36
42
  expect {
@@ -40,7 +46,7 @@ describe DispatchRider::Handlers::Base do
40
46
  end
41
47
 
42
48
  context "when the class does implement process" do
43
- let(:handler){ ProcessImplemented.new }
49
+ let(:handler) { ProcessImplemented.new }
44
50
 
45
51
  example do
46
52
  expect {
@@ -49,33 +55,32 @@ describe DispatchRider::Handlers::Base do
49
55
  end
50
56
 
51
57
  example do
52
- handler.do_process(message).should == "good job"
58
+ expect(handler.do_process(message)).to eq("good job")
53
59
  end
54
60
  end
55
-
61
+
56
62
  context "when the class wants to immediately retry" do
57
63
  let(:handler) { ProcessWithImmediateRetry.new }
58
-
64
+
59
65
  example do
60
- message.should_receive(:return_to_queue)
61
-
66
+ expect(message).to receive(:return_to_queue)
67
+
62
68
  expect {
63
69
  handler.do_process(message)
64
70
  }.to raise_exception "I have failed!"
65
71
  end
66
72
  end
67
-
73
+
68
74
  context "when the class wants to retry in 10 seconds" do
69
75
  let(:handler) { ProcessWithTenSecondRetry.new }
70
-
76
+
71
77
  example do
72
- message.should_receive(:extend_timeout).with(10*60)
73
-
78
+ expect(message).to receive(:extend_timeout).with(10 * 60)
79
+
74
80
  expect {
75
81
  handler.do_process(message)
76
82
  }.to raise_exception "I have failed!"
77
83
  end
78
84
  end
79
85
  end
80
-
81
86
  end
@@ -1,27 +1,27 @@
1
1
  require 'spec_helper'
2
2
 
3
3
  describe DispatchRider::Handlers::InheritanceTracking do
4
-
5
4
  class InheritanceDummyClass
6
5
  extend DispatchRider::Handlers::InheritanceTracking
7
6
  end
8
7
 
9
8
  describe ".subclasses" do
10
9
  context "when a class inherits from the dummy class" do
11
- class Blah < InheritanceDummyClass; end
10
+ class Blah < InheritanceDummyClass
11
+ end
12
12
 
13
13
  example do
14
- InheritanceDummyClass.subclasses.should include(Blah)
14
+ expect(InheritanceDummyClass.subclasses).to include(Blah)
15
15
  end
16
16
 
17
17
  context "and another class inherits from the dummy class" do
18
- class Foo < InheritanceDummyClass; end
18
+ class Foo < InheritanceDummyClass
19
+ end
19
20
 
20
21
  example do
21
- InheritanceDummyClass.subclasses.should include(Blah, Foo)
22
+ expect(InheritanceDummyClass.subclasses).to include(Blah, Foo)
22
23
  end
23
24
  end
24
25
  end
25
26
  end
26
-
27
27
  end
@@ -0,0 +1,72 @@
1
+ require 'spec_helper'
2
+
3
+ describe DispatchRider::Logging::JsonFormatter do
4
+ let(:fs_message) { DispatchRider::Message.new(subject: 'test', body: { 'key' => 'value', 'guid' => 123 }) }
5
+ let(:item) { double :item }
6
+ let(:queue) { double :queue }
7
+ let(:message) { DispatchRider::QueueServices::FileSystem::FsReceivedMessage.new(fs_message, item, queue) }
8
+ let(:exception) { StandardError.new }
9
+ let(:reason) { "Stop reason" }
10
+
11
+ let(:result_object) do
12
+ {
13
+ "subject" => "test",
14
+ "guid" => "123",
15
+ "body" => {
16
+ "key" => "value"
17
+ },
18
+ }
19
+ end
20
+ let(:result_exception) do
21
+ {
22
+ "expection" => {
23
+ "class" => "StandardError",
24
+ "message" => "StandardError"
25
+ }
26
+ }
27
+ end
28
+
29
+ context "format_error_handler_fail" do
30
+ let(:formatted_message) { result_object.merge("phase" => "failed").merge(result_exception) }
31
+ let(:result_message) { JSON.parse subject.format_error_handler_fail(message, exception) }
32
+
33
+ example { expect(result_message).to eq(formatted_message) }
34
+ end
35
+
36
+ context "format_got_stop" do
37
+ let(:formatted_message) { result_object.merge("phase" => "stop", "reason" => reason) }
38
+ let(:result_message) { JSON.parse subject.format_got_stop(message, reason) }
39
+
40
+ example { expect(result_message).to eq(formatted_message) }
41
+ end
42
+
43
+ context "format_handling" do
44
+ context "start" do
45
+ let(:formatted_message) { result_object.merge("phase" => "start") }
46
+ let(:result_message) { JSON.parse subject.format_handling(:start, message) }
47
+
48
+ example { expect(result_message).to eq(formatted_message) }
49
+ end
50
+
51
+ context "success" do
52
+ let(:formatted_message) { result_object.merge("phase" => "success") }
53
+ let(:result_message) { JSON.parse subject.format_handling(:success, message) }
54
+
55
+ example { expect(result_message).to eq(formatted_message) }
56
+ end
57
+
58
+ context "complete" do
59
+ let(:formatted_message) { result_object.merge("phase" => "complete", "duration" => "2.00") }
60
+ let(:result_message) { JSON.parse subject.format_handling(:complete, message, duration: 2.0) }
61
+
62
+ example { expect(result_message).to eq(formatted_message) }
63
+ end
64
+
65
+ context "fail" do
66
+ let(:formatted_message) { result_object.merge("phase" => "fail").merge(result_exception) }
67
+ let(:result_message) { JSON.parse subject.format_handling(:fail, message, exception: exception) }
68
+
69
+ example { expect(formatted_message).to eq(formatted_message) }
70
+ end
71
+ end
72
+ end
@@ -0,0 +1,73 @@
1
+ require 'spec_helper'
2
+
3
+ describe DispatchRider::Logging::LifecycleLogger do
4
+ subject { DispatchRider::Logging::LifecycleLogger }
5
+
6
+ let(:message) { DispatchRider::Message.new(subject: 'test', body: 'test_handler') }
7
+ let(:string_to_log) { "string to log" }
8
+ let(:exception) { StandardError.new }
9
+ let(:reason) { "Stop reason" }
10
+
11
+ let(:formatter) { DispatchRider.config.log_formatter }
12
+ let(:logger) { DispatchRider.config.logger }
13
+
14
+ before do
15
+ allow(formatter).to receive(:format_got_stop).and_return(string_to_log)
16
+ allow(formatter).to receive(:format_error_handler_fail).and_return(string_to_log)
17
+ allow(formatter).to receive(:format_handling).and_return(string_to_log)
18
+ end
19
+
20
+ context "log_error_handler_fail" do
21
+ after { subject.log_error_handler_fail message, exception }
22
+
23
+ it "calls logger with error" do
24
+ expect(logger).to receive(:error).with(string_to_log)
25
+ end
26
+ end
27
+
28
+ context "log_got_stop" do
29
+ after { subject.log_got_stop reason, message }
30
+
31
+ it "calls logger with info" do
32
+ expect(logger).to receive(:info).with(string_to_log)
33
+ end
34
+ end
35
+
36
+ context "wrap_handling" do
37
+ context "block runs successfully" do
38
+ let(:block) { Proc.new { true } }
39
+ after { subject.wrap_handling(message, &block) }
40
+
41
+ it "logs start" do
42
+ expect(subject).to receive(:log_start).with(message)
43
+ end
44
+
45
+ it "logs success" do
46
+ expect(subject).to receive(:log_success).with(message)
47
+ end
48
+
49
+ it "logs complete" do
50
+ expect(subject).to receive(:log_complete).with(message, an_instance_of(Float))
51
+ end
52
+ end
53
+
54
+ context "block fails" do
55
+ let(:block) { Proc.new { raise exception } }
56
+ after do
57
+ expect { subject.wrap_handling(message, &block) }.to raise_error(exception)
58
+ end
59
+
60
+ it "logs start" do
61
+ expect(subject).to receive(:log_start).with(message)
62
+ end
63
+
64
+ it "logs fail" do
65
+ expect(subject).to receive(:log_fail).with(message, exception)
66
+ end
67
+
68
+ it "logs complete" do
69
+ expect(subject).to receive(:log_complete).with(message, an_instance_of(Float))
70
+ end
71
+ end
72
+ end
73
+ end