execute_with_rescue_with_airbrake 0.0.1
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.
- checksums.yaml +7 -0
- data/.gitignore +18 -0
- data/.rspec +1 -0
- data/.travis.yml +12 -0
- data/Appraisals +11 -0
- data/CHANGELOG.md +5 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +22 -0
- data/README.md +101 -0
- data/Rakefile +16 -0
- data/execute_with_rescue_with_airbrake.gemspec +33 -0
- data/gemfiles/rails_3_2.gemfile +7 -0
- data/gemfiles/rails_4_0.gemfile +7 -0
- data/gemfiles/rails_4_1.gemfile +7 -0
- data/lib/execute_with_rescue/errors/no_airbrake_adapter.rb +13 -0
- data/lib/execute_with_rescue/mixins/with_airbrake.rb +66 -0
- data/lib/execute_with_rescue_with_airbrake.rb +7 -0
- data/lib/execute_with_rescue_with_airbrake/adapters/airbrake_adapter.rb +123 -0
- data/lib/execute_with_rescue_with_airbrake/version.rb +3 -0
- data/spec/execute_with_rescue/mixins/with_airbrake_spec.rb +127 -0
- data/spec/execute_with_rescue_with_airbrake/adapters/airbrake_adapter_spec.rb +211 -0
- data/spec/fixtures/test_service_classes.rb +51 -0
- data/spec/spec_helper.rb +20 -0
- metadata +192 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: a075f476d5e0d9f96a18858757b1f0f967162c8e
|
4
|
+
data.tar.gz: 57fe7504b06259d529e6a56cc4910ac91728ad25
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: da8223cb3c1484790c8d9a883faf00f705d572aef2f74c81886ff18e7914d0c0efeb912b2f42a40bda49684be01ea517c08fc7748a480bcf101c308a8648c5d2
|
7
|
+
data.tar.gz: 204f405743ecb2ae9e20d55b3482429383e0d0d443c1281a802325a96016a8c24f430f20bc3392ceb261b52e9ea63538dc0b24d6a0dba647e965c1fc6d8ee848
|
data/.gitignore
ADDED
data/.rspec
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
--color
|
data/.travis.yml
ADDED
data/Appraisals
ADDED
data/CHANGELOG.md
ADDED
data/Gemfile
ADDED
data/LICENSE.txt
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
Copyright (c) 2014 PikachuEXE
|
2
|
+
|
3
|
+
MIT License
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
6
|
+
a copy of this software and associated documentation files (the
|
7
|
+
"Software"), to deal in the Software without restriction, including
|
8
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
9
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
10
|
+
permit persons to whom the Software is furnished to do so, subject to
|
11
|
+
the following conditions:
|
12
|
+
|
13
|
+
The above copyright notice and this permission notice shall be
|
14
|
+
included in all copies or substantial portions of the Software.
|
15
|
+
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
17
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
18
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
19
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
20
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
21
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
22
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,101 @@
|
|
1
|
+
# ExecuteWithRescueWithAirbrake
|
2
|
+
|
3
|
+
TODO: Write a gem description
|
4
|
+
|
5
|
+
The Airbrake adapter plus mixin to be used with `execute_with_rescue`.
|
6
|
+
|
7
|
+
## Support
|
8
|
+
===========
|
9
|
+
Tested against:
|
10
|
+
- Active Support of version `3.2`, `4.0` and `4.1` (pre-3.2 got wrong dependency & I don't want to support)
|
11
|
+
- MRI `1.9.3`, `2.0.0`, `2.1.0`, `2.1.1`
|
12
|
+
|
13
|
+
[](https://travis-ci.org/PikachuEXE/execute_with_rescue_with_airbrake)
|
14
|
+
[](http://badge.fury.io/rb/execute_with_rescue_with_airbrake)
|
15
|
+
[](https://gemnasium.com/PikachuEXE/execute_with_rescue_with_airbrake)
|
16
|
+
[](https://coveralls.io/r/PikachuEXE/execute_with_rescue_with_airbrake)
|
17
|
+
[](https://codeclimate.com/github/PikachuEXE/execute_with_rescue_with_airbrake)
|
18
|
+
|
19
|
+
## Installation
|
20
|
+
|
21
|
+
Add this line to your application's Gemfile:
|
22
|
+
|
23
|
+
gem 'execute_with_rescue_with_airbrake'
|
24
|
+
|
25
|
+
And then execute:
|
26
|
+
|
27
|
+
$ bundle
|
28
|
+
|
29
|
+
Or install it yourself as:
|
30
|
+
|
31
|
+
$ gem install execute_with_rescue_with_airbrake
|
32
|
+
|
33
|
+
## Usage
|
34
|
+
|
35
|
+
TODO: Write usage instructions here
|
36
|
+
|
37
|
+
Note: You must configurate `airbrake` first or you won't be able to send anything (I have to do the same in `spec_helper`)
|
38
|
+
|
39
|
+
### `include ExecuteWithRescue::Mixins::WithAirbrake`
|
40
|
+
Once inlcuded, `rescue_from StandardError, with: :notify_by_airbrake_or_raise` will be called.
|
41
|
+
|
42
|
+
|
43
|
+
### `#set_default_airbrake_notice_error_class`, `#set_default_airbrake_notice_error_message`, `#add_default_airbrake_notice_parameters`
|
44
|
+
**Private** methods to be called within a block in `execute_with_rescue`
|
45
|
+
Every `execute_with_rescue` call will push a new airbrake adapater for the instance (with before hook),
|
46
|
+
so you can have different custom error class, message or/and parameters within the same service/worker class.
|
47
|
+
You should call these methods within the block passed to `execute_with_rescue`, as there is no adapter from the beginning.
|
48
|
+
|
49
|
+
Here is an example for getting a document from the network:
|
50
|
+
```ruby
|
51
|
+
class SomeServiceClass
|
52
|
+
|
53
|
+
BadNetworkConnectionError = Class.new(StandardError)
|
54
|
+
|
55
|
+
include ExecuteWithRescue::Mixins::WithAirbrake
|
56
|
+
|
57
|
+
# then run code with possible errors
|
58
|
+
def perform(url_of_webpage)
|
59
|
+
execute_with_rescue do
|
60
|
+
set_default_airbrake_notice_error_class(BadNetworkConnectionError)
|
61
|
+
set_default_airbrake_notice_error_message("We have a bad network today...")
|
62
|
+
add_default_airbrake_notice_parameters({url_of_webpage: url_of_webpage})
|
63
|
+
|
64
|
+
# Calling `add_default_airbrake_notice_parameters` with duplicated key(s) would raise error
|
65
|
+
# add_default_airbrake_notice_parameters({url_of_webpage: something_else}) =>
|
66
|
+
# ExecuteWithRescueWithAirbrake::Adapters::AirbrakeAdapter::Errors::ParameterKeyConflict
|
67
|
+
|
68
|
+
doc = Nokogiri::HTML(open(listing_url))
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
72
|
+
```
|
73
|
+
|
74
|
+
### `#notify_by_airbrake_or_raise`
|
75
|
+
**Private** method to be called automatically by `rescue_from StandardError` from the mixin.
|
76
|
+
Call this if you have some custom handling for some error classes
|
77
|
+
Override this if you have some additional operation like logging for all kinds of error inherited from `StandardError`
|
78
|
+
Note: It would re-raise the exception if `airbrake` would ignore all notify call in that environment (see `development_environments` in its config).
|
79
|
+
Example:
|
80
|
+
```ruby
|
81
|
+
class SomeWorker
|
82
|
+
rescue_from ActiveRecord::RecordInvalid,
|
83
|
+
with: :notify_by_airbrake_or_raise_ar_invalid_error
|
84
|
+
|
85
|
+
def notify_by_airbrake_or_raise_ar_invalid_error(ex)
|
86
|
+
add_default_airbrake_notice_parameters({
|
87
|
+
active_record_instance: ex.record.inspect,
|
88
|
+
active_record_instance_errors: ex.record.errors.inspect,
|
89
|
+
})
|
90
|
+
notify_by_airbrake_or_raise(ex)
|
91
|
+
end
|
92
|
+
end
|
93
|
+
```
|
94
|
+
|
95
|
+
## Contributing
|
96
|
+
|
97
|
+
1. Fork it ( http://github.com/PikachuEXE/execute_with_rescue_with_airbrake/fork )
|
98
|
+
2. Create your feature branch (`git checkout -b feature/my-new-feature`)
|
99
|
+
3. Commit your changes (`git commit -am 'Add some feature'`)
|
100
|
+
4. Push to the branch (`git push origin feature/my-new-feature`)
|
101
|
+
5. Create new Pull Request
|
data/Rakefile
ADDED
@@ -0,0 +1,16 @@
|
|
1
|
+
require "bundler/gem_tasks"
|
2
|
+
require "rubygems"
|
3
|
+
require "bundler/setup"
|
4
|
+
|
5
|
+
require "rspec/core/rake_task"
|
6
|
+
require "appraisal"
|
7
|
+
|
8
|
+
RSpec::Core::RakeTask.new(:spec)
|
9
|
+
|
10
|
+
if !ENV["APPRAISAL_INITIALIZED"] && !ENV["TRAVIS"]
|
11
|
+
task :default do
|
12
|
+
sh "rake appraisal:install && rake appraisal spec"
|
13
|
+
end
|
14
|
+
else
|
15
|
+
task :default => :spec
|
16
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require 'execute_with_rescue_with_airbrake/version'
|
5
|
+
|
6
|
+
Gem::Specification.new do |spec|
|
7
|
+
spec.name = "execute_with_rescue_with_airbrake"
|
8
|
+
spec.version = ExecuteWithRescueWithAirbrake::VERSION
|
9
|
+
spec.authors = ["PikachuEXE"]
|
10
|
+
spec.email = ["pikachuexe@gmail.com"]
|
11
|
+
spec.summary = %q{The Airbrake adapter plus mixin to be used with `execute_with_rescue`}
|
12
|
+
spec.homepage = "http://github.com/PikachuEXE/execute_with_rescue_with_airbrake"
|
13
|
+
spec.license = "MIT"
|
14
|
+
|
15
|
+
spec.files = `git ls-files -z`.split("\x0")
|
16
|
+
spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
|
17
|
+
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
18
|
+
spec.require_paths = ["lib"]
|
19
|
+
|
20
|
+
spec.add_dependency "execute_with_rescue", "~> 0.0", ">= 0.0.1"
|
21
|
+
spec.add_dependency "airbrake", "~> 3.1.0"
|
22
|
+
|
23
|
+
spec.add_development_dependency "bundler", "~> 1.5"
|
24
|
+
spec.add_development_dependency "rake"
|
25
|
+
spec.add_development_dependency "appraisal", ">= 0.5.2"
|
26
|
+
spec.add_development_dependency "rspec", "~> 2.14.0"
|
27
|
+
spec.add_development_dependency "coveralls", ">= 0.7"
|
28
|
+
spec.add_development_dependency "gem-release", ">= 0.7"
|
29
|
+
|
30
|
+
spec.required_ruby_version = ">= 1.9.3"
|
31
|
+
|
32
|
+
spec.required_rubygems_version = ">= 1.4.0"
|
33
|
+
end
|
@@ -0,0 +1,13 @@
|
|
1
|
+
module ExecuteWithRescue
|
2
|
+
module Errors
|
3
|
+
class NoAirbrakeAdapter < RuntimeError
|
4
|
+
def self.new(msg = nil)
|
5
|
+
msg ||= <<-ERR_MSG
|
6
|
+
There is no airbrake adapter available.
|
7
|
+
Maybe you forgot to use `execute_with_rescue`?
|
8
|
+
ERR_MSG
|
9
|
+
super(msg)
|
10
|
+
end
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
@@ -0,0 +1,66 @@
|
|
1
|
+
require 'airbrake'
|
2
|
+
require 'active_support/concern'
|
3
|
+
require 'active_support/core_ext/module/delegation'
|
4
|
+
|
5
|
+
require 'execute_with_rescue'
|
6
|
+
require 'execute_with_rescue/errors/no_airbrake_adapter'
|
7
|
+
require 'execute_with_rescue_with_airbrake/adapters/airbrake_adapter'
|
8
|
+
|
9
|
+
module ExecuteWithRescue
|
10
|
+
module Mixins
|
11
|
+
module WithAirbrake
|
12
|
+
extend ActiveSupport::Concern
|
13
|
+
|
14
|
+
included do
|
15
|
+
include ExecuteWithRescue::Mixins::Core
|
16
|
+
|
17
|
+
add_execute_with_rescue_before_hook do
|
18
|
+
_execute_with_rescue_airbrake_adapters
|
19
|
+
.push(ExecuteWithRescueWithAirbrake::Adapters::AirbrakeAdapter.new)
|
20
|
+
end
|
21
|
+
add_execute_with_rescue_after_hook do
|
22
|
+
_execute_with_rescue_airbrake_adapters.pop
|
23
|
+
end
|
24
|
+
|
25
|
+
rescue_from StandardError,
|
26
|
+
with: :notify_by_airbrake_or_raise
|
27
|
+
|
28
|
+
delegate :set_default_airbrake_notice_error_class,
|
29
|
+
:set_default_airbrake_notice_error_message,
|
30
|
+
:add_default_airbrake_notice_parameters,
|
31
|
+
to: :_execute_with_rescue_current_airbrake_adapter
|
32
|
+
end
|
33
|
+
|
34
|
+
# Call this if you have some custom handling for some classes
|
35
|
+
# Override this if you have some additional operation like logging
|
36
|
+
# for all kinds of error inherited from `StandardError`
|
37
|
+
#
|
38
|
+
# @example Add default parameters when rescuing AR Invalid Error
|
39
|
+
# class SomeWorker
|
40
|
+
# rescue_from ActiveRecord::RecordInvalid,
|
41
|
+
# with: :notify_by_airbrake_or_raise_ar_invalid_error
|
42
|
+
#
|
43
|
+
# def notify_by_airbrake_or_raise_ar_invalid_error(ex)
|
44
|
+
# add_default_airbrake_notice_parameters({
|
45
|
+
# active_record_instance: ex.record.inspect,
|
46
|
+
# active_record_instance_errors: ex.record.errors.inspect,
|
47
|
+
# })
|
48
|
+
# notify_by_airbrake_or_raise(ex)
|
49
|
+
# end
|
50
|
+
# end
|
51
|
+
def notify_by_airbrake_or_raise(ex)
|
52
|
+
_execute_with_rescue_current_airbrake_adapter
|
53
|
+
.notify_or_raise(ex)
|
54
|
+
end
|
55
|
+
|
56
|
+
# For pushing and popping the adapters
|
57
|
+
def _execute_with_rescue_airbrake_adapters
|
58
|
+
@_execute_with_rescue_airbrake_adapters ||= []
|
59
|
+
end
|
60
|
+
def _execute_with_rescue_current_airbrake_adapter
|
61
|
+
_execute_with_rescue_airbrake_adapters.last ||
|
62
|
+
(raise ExecuteWithRescue::Errors::NoAirbrakeAdapter)
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
@@ -0,0 +1,123 @@
|
|
1
|
+
require 'active_support/core_ext/hash/indifferent_access'
|
2
|
+
|
3
|
+
module ExecuteWithRescueWithAirbrake
|
4
|
+
module Adapters
|
5
|
+
class AirbrakeAdapter
|
6
|
+
module Errors
|
7
|
+
InvalidParameters = Class.new(ArgumentError)
|
8
|
+
ParameterKeyConflict = Class.new(ArgumentError)
|
9
|
+
end
|
10
|
+
|
11
|
+
# This should NOT be used directly, but used with rescue_from
|
12
|
+
# if you need custom options use Airbrake directly
|
13
|
+
#
|
14
|
+
# @param ex [Exception]
|
15
|
+
# The exception rescued
|
16
|
+
#
|
17
|
+
# @raise [Exception] the original exception
|
18
|
+
# when Airbrake detects the current environment is not public
|
19
|
+
# @see should_raise?
|
20
|
+
def notify_or_raise(ex)
|
21
|
+
if should_raise?
|
22
|
+
raise ex
|
23
|
+
else
|
24
|
+
notify_or_ignore_with_options(ex)
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
|
29
|
+
# set the default `error_class` option when notify by Airbrake
|
30
|
+
# It must can be init without argument, this method won't check it
|
31
|
+
# Pass nil to clear it
|
32
|
+
#
|
33
|
+
# @param message [NilClass, Class]
|
34
|
+
# the error message to be used in Airbrake notice
|
35
|
+
#
|
36
|
+
# @raise [ArgumentError] when class is not nil or symbol
|
37
|
+
def set_default_airbrake_notice_error_class(klass)
|
38
|
+
(klass.nil? || klass.is_a?(Class)) or raise ArgumentError
|
39
|
+
|
40
|
+
@default_airbrake_notice_error_class = klass
|
41
|
+
end
|
42
|
+
|
43
|
+
# set the default `error_message` option when notify by Airbrake
|
44
|
+
# Pass nil to clear it
|
45
|
+
#
|
46
|
+
# @param message [NilClass, String]
|
47
|
+
# the error message to be used in Airbrake notice
|
48
|
+
#
|
49
|
+
# @raise [ArgumentError] when message is not nil or string
|
50
|
+
def set_default_airbrake_notice_error_message(message)
|
51
|
+
(message.nil? || message.is_a?(String)) or raise ArgumentError
|
52
|
+
|
53
|
+
@default_airbrake_notice_error_message = message
|
54
|
+
end
|
55
|
+
|
56
|
+
# Push new default `parameters` option when notify by Airbrake
|
57
|
+
# Pass nil to clear it
|
58
|
+
#
|
59
|
+
# @param new_params [Hash]
|
60
|
+
# the additional parameters to be used in Airbrake notice
|
61
|
+
#
|
62
|
+
# @raise [InvalidParameters]
|
63
|
+
# when new_params is not hash
|
64
|
+
# @raise [ParameterKeyConflict]
|
65
|
+
# when new_params contains keys conflicting with existing keys
|
66
|
+
def add_default_airbrake_notice_parameters(new_params)
|
67
|
+
new_params.is_a?(Hash) or
|
68
|
+
(raise Errors::InvalidParameters)
|
69
|
+
new_params =
|
70
|
+
new_params.with_indifferent_access
|
71
|
+
|
72
|
+
# find out common element size (which should be 0)
|
73
|
+
common_keys =
|
74
|
+
default_airbrake_notice_parameters.keys &
|
75
|
+
new_params.keys
|
76
|
+
if common_keys.size > 0
|
77
|
+
raise Errors::ParameterKeyConflict,
|
78
|
+
"Conflicting keys: #{common_keys.inspect}"
|
79
|
+
end
|
80
|
+
|
81
|
+
default_airbrake_notice_parameters.merge!(new_params)
|
82
|
+
end
|
83
|
+
|
84
|
+
private
|
85
|
+
|
86
|
+
def notify_or_ignore_with_options(ex)
|
87
|
+
Airbrake.notify_or_ignore(ex, build_notice_options)
|
88
|
+
end
|
89
|
+
|
90
|
+
def build_notice_options
|
91
|
+
result_options_hash = Hash.new
|
92
|
+
|
93
|
+
if @default_airbrake_notice_error_class
|
94
|
+
result_options_hash[:error_class] =
|
95
|
+
@default_airbrake_notice_error_class
|
96
|
+
end
|
97
|
+
if @default_airbrake_notice_error_message
|
98
|
+
result_options_hash[:error_message] =
|
99
|
+
@default_airbrake_notice_error_message
|
100
|
+
end
|
101
|
+
unless default_airbrake_notice_parameters.empty?
|
102
|
+
result_options_hash[:parameters] =
|
103
|
+
default_airbrake_notice_parameters.symbolize_keys
|
104
|
+
end
|
105
|
+
|
106
|
+
result_options_hash
|
107
|
+
end
|
108
|
+
|
109
|
+
def default_airbrake_notice_parameters
|
110
|
+
@default_airbrake_notice_parameters ||= HashWithIndifferentAccess.new
|
111
|
+
end
|
112
|
+
|
113
|
+
# @return [Boolean]
|
114
|
+
# Whether the adapter should raise the error instead
|
115
|
+
# (like in development or test)
|
116
|
+
#
|
117
|
+
# @see Airbrake.configuration.development_environments
|
118
|
+
def should_raise?
|
119
|
+
!Airbrake.configuration.public?
|
120
|
+
end
|
121
|
+
end
|
122
|
+
end
|
123
|
+
end
|
@@ -0,0 +1,127 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
|
4
|
+
describe ExecuteWithRescue::Mixins::WithAirbrake do
|
5
|
+
let(:test_class) { TestServiceWithAirbrake }
|
6
|
+
let(:test_class_instance) { test_class.new }
|
7
|
+
let(:call_service) { test_class_instance.call }
|
8
|
+
|
9
|
+
shared_context 'when airbrake adapter assumed exists' do
|
10
|
+
let(:adapter_class) do
|
11
|
+
ExecuteWithRescueWithAirbrake::Adapters::AirbrakeAdapter
|
12
|
+
end
|
13
|
+
let!(:adapter_instance) { adapter_class.new }
|
14
|
+
before do
|
15
|
+
# Avoid Error
|
16
|
+
test_class_instance
|
17
|
+
.stub(:_execute_with_rescue_current_airbrake_adapter)
|
18
|
+
.and_return(adapter_instance)
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
describe 'included modules' do
|
23
|
+
subject { test_class.ancestors }
|
24
|
+
|
25
|
+
it {should include ExecuteWithRescue::Mixins::Core}
|
26
|
+
it {should include ExecuteWithRescue::Mixins::WithAirbrake}
|
27
|
+
end
|
28
|
+
|
29
|
+
describe 'call delegated methods' do
|
30
|
+
context 'without calling #execute_with_rescue' do
|
31
|
+
let(:test_class) { TestServiceWithAirbrakeWithoutExecuteWithRescueCall }
|
32
|
+
let(:expected_error_class) { ExecuteWithRescue::Errors::NoAirbrakeAdapter }
|
33
|
+
|
34
|
+
specify do
|
35
|
+
expect{ call_service }
|
36
|
+
.to raise_error(expected_error_class)
|
37
|
+
end
|
38
|
+
end
|
39
|
+
context 'without calling #execute_with_rescue' do
|
40
|
+
let(:test_class) { TestServiceWithAirbrakeWithExecuteWithRescueCall }
|
41
|
+
|
42
|
+
specify do
|
43
|
+
expect{ call_service }
|
44
|
+
.to_not raise_error
|
45
|
+
end
|
46
|
+
end
|
47
|
+
context 'with calling #execute_with_rescue'
|
48
|
+
end
|
49
|
+
|
50
|
+
describe 'delegation' do
|
51
|
+
include_context 'when airbrake adapter assumed exists'
|
52
|
+
|
53
|
+
before { adapter_instance.stub(method_name) }
|
54
|
+
|
55
|
+
let(:send_message) { test_class_instance.send(method_name) }
|
56
|
+
|
57
|
+
shared_examples_for 'delegation' do
|
58
|
+
specify do
|
59
|
+
expect(adapter_instance).to receive(method_name)
|
60
|
+
|
61
|
+
send_message
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
describe 'for #set_default_airbrake_notice_error_class' do
|
66
|
+
let(:method_name) { :set_default_airbrake_notice_error_class }
|
67
|
+
|
68
|
+
it_behaves_like 'delegation'
|
69
|
+
end
|
70
|
+
describe 'for #set_default_airbrake_notice_error_message' do
|
71
|
+
let(:method_name) { :set_default_airbrake_notice_error_message }
|
72
|
+
|
73
|
+
it_behaves_like 'delegation'
|
74
|
+
end
|
75
|
+
describe 'for #add_default_airbrake_notice_parameters' do
|
76
|
+
let(:method_name) { :add_default_airbrake_notice_parameters }
|
77
|
+
|
78
|
+
it_behaves_like 'delegation'
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
describe 'execution' do
|
83
|
+
include_context 'when airbrake adapter assumed exists'
|
84
|
+
|
85
|
+
before { Airbrake.configuration.stub(public?: true) }
|
86
|
+
|
87
|
+
describe 'when there is no error raised' do
|
88
|
+
specify do
|
89
|
+
expect(Airbrake)
|
90
|
+
.to_not receive(:notify_or_ignore)
|
91
|
+
|
92
|
+
call_service
|
93
|
+
end
|
94
|
+
end
|
95
|
+
describe 'when there is error raised' do
|
96
|
+
context 'and it is a standard error' do
|
97
|
+
let(:test_class) { TestServiceWithAirbrakeWithError }
|
98
|
+
|
99
|
+
specify do
|
100
|
+
expect(Airbrake)
|
101
|
+
.to(receive(:notify_or_ignore)
|
102
|
+
.with(kind_of(StandardError), {}))
|
103
|
+
|
104
|
+
call_service
|
105
|
+
end
|
106
|
+
end
|
107
|
+
|
108
|
+
describe 'setting custom airbrake options' do
|
109
|
+
let(:test_class) { TestServiceWithAirbrakeWithErrorAndAirbrakeOption }
|
110
|
+
|
111
|
+
specify do
|
112
|
+
expect(Airbrake)
|
113
|
+
.to(receive(:notify_or_ignore)
|
114
|
+
.with(kind_of(StandardError), {
|
115
|
+
error_class: test_class::CustomError,
|
116
|
+
error_message: 'hi',
|
117
|
+
parameters: {
|
118
|
+
foo: :bar
|
119
|
+
},
|
120
|
+
}))
|
121
|
+
|
122
|
+
call_service
|
123
|
+
end
|
124
|
+
end
|
125
|
+
end
|
126
|
+
end
|
127
|
+
end
|
@@ -0,0 +1,211 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
|
4
|
+
describe ExecuteWithRescueWithAirbrake::Adapters::AirbrakeAdapter do
|
5
|
+
let!(:instance) { described_class.new }
|
6
|
+
|
7
|
+
let!(:notice_options) do
|
8
|
+
{parameters: {}}
|
9
|
+
end
|
10
|
+
let!(:exception_rescued) { StandardError.new('hi I am test error') }
|
11
|
+
|
12
|
+
let(:notify_or_raise) { instance.notify_or_raise(exception_rescued) }
|
13
|
+
|
14
|
+
#before { }
|
15
|
+
|
16
|
+
context 'when exception should not be notified according to Airbrake' do
|
17
|
+
before { Airbrake.configuration.stub(public?: false) }
|
18
|
+
|
19
|
+
it 're-raise the rescue error' do
|
20
|
+
expect { notify_or_raise }.to raise_error(exception_rescued.class,
|
21
|
+
exception_rescued.message)
|
22
|
+
end
|
23
|
+
end
|
24
|
+
context 'when exception should be notified according to Airbrake' do
|
25
|
+
before { Airbrake.configuration.stub(public?: true) }
|
26
|
+
|
27
|
+
it 'does not re-raise the rescued error' do
|
28
|
+
expect { notify_or_raise }.to_not raise_error
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
context 'assuming Airbrake says it error should be notified' do
|
33
|
+
before { Airbrake.configuration.stub(public?: true) }
|
34
|
+
|
35
|
+
it 'calls Airbrake.notify_or_ignore' do
|
36
|
+
Airbrake.should_receive(:notify_or_ignore)
|
37
|
+
|
38
|
+
notify_or_raise
|
39
|
+
end
|
40
|
+
|
41
|
+
|
42
|
+
describe '#set_default_airbrake_notice_error_class' do
|
43
|
+
let(:set_error_class) do
|
44
|
+
instance.set_default_airbrake_notice_error_class(
|
45
|
+
default_error_class)
|
46
|
+
end
|
47
|
+
let(:default_error_class) { nil }
|
48
|
+
let(:option_key) { :error_class }
|
49
|
+
|
50
|
+
before do
|
51
|
+
# Return the options only
|
52
|
+
Airbrake.stub(:notify_or_ignore) {|*args| args.last }
|
53
|
+
end
|
54
|
+
let(:options_hash) { notify_or_raise }
|
55
|
+
subject { options_hash }
|
56
|
+
|
57
|
+
context 'when its not called' do
|
58
|
+
its(:keys) { should_not include(option_key) }
|
59
|
+
end
|
60
|
+
context 'when its called with nil' do
|
61
|
+
let(:default_error_class) { nil }
|
62
|
+
before { set_error_class }
|
63
|
+
|
64
|
+
its(:keys) { should_not include(option_key) }
|
65
|
+
end
|
66
|
+
context 'when its called with custom error' do
|
67
|
+
let(:default_error_class) { ArgumentError }
|
68
|
+
before { set_error_class }
|
69
|
+
|
70
|
+
it { should include({option_key => default_error_class}) }
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
describe '#set_default_airbrake_notice_error_message' do
|
75
|
+
let(:set_error_message) do
|
76
|
+
instance.set_default_airbrake_notice_error_message(
|
77
|
+
default_error_message)
|
78
|
+
end
|
79
|
+
let(:default_error_message) { nil }
|
80
|
+
let(:option_key) { :error_message }
|
81
|
+
|
82
|
+
before do
|
83
|
+
# Return the options only
|
84
|
+
Airbrake.stub(:notify_or_ignore) {|*args| args.last }
|
85
|
+
end
|
86
|
+
let(:options_hash) { notify_or_raise }
|
87
|
+
subject { options_hash }
|
88
|
+
|
89
|
+
context 'when its not called' do
|
90
|
+
its(:keys) { should_not include(option_key) }
|
91
|
+
end
|
92
|
+
context 'when its called with nil' do
|
93
|
+
let(:default_error_message) { nil }
|
94
|
+
before { set_error_message }
|
95
|
+
|
96
|
+
its(:keys) { should_not include(option_key) }
|
97
|
+
end
|
98
|
+
context 'when its called with custom error' do
|
99
|
+
let(:default_error_message) { 'hello' }
|
100
|
+
before { set_error_message }
|
101
|
+
|
102
|
+
it { should include({option_key => default_error_message}) }
|
103
|
+
end
|
104
|
+
end
|
105
|
+
|
106
|
+
describe '#add_default_airbrake_notice_parameters' do
|
107
|
+
# Must defined as method or it won't run twice
|
108
|
+
def add_parameters(params = new_parameters)
|
109
|
+
instance.add_default_airbrake_notice_parameters(
|
110
|
+
params)
|
111
|
+
end
|
112
|
+
let(:new_parameters) { Hash.new }
|
113
|
+
let(:option_key) { :parameters }
|
114
|
+
|
115
|
+
before do
|
116
|
+
# Return the options only
|
117
|
+
Airbrake.stub(:notify_or_ignore) {|*args| args.last }
|
118
|
+
end
|
119
|
+
let(:options_hash) { notify_or_raise }
|
120
|
+
let(:parameters_hash) { options_hash[option_key] }
|
121
|
+
|
122
|
+
subject { options_hash }
|
123
|
+
|
124
|
+
context 'when its not called' do
|
125
|
+
its(:keys) { should_not include(option_key) }
|
126
|
+
end
|
127
|
+
context 'when its called with non hash' do
|
128
|
+
let(:new_parameters) { Array.new }
|
129
|
+
let(:expected_error_class) do
|
130
|
+
described_class::Errors::InvalidParameters
|
131
|
+
end
|
132
|
+
|
133
|
+
specify do
|
134
|
+
expect { add_parameters }
|
135
|
+
.to raise_error(expected_error_class)
|
136
|
+
end
|
137
|
+
end
|
138
|
+
context 'when its called with empty hash' do
|
139
|
+
let(:new_parameters) { Hash.new }
|
140
|
+
before { add_parameters }
|
141
|
+
|
142
|
+
its(:keys) { should_not include(option_key) }
|
143
|
+
end
|
144
|
+
|
145
|
+
context 'when its called with non-empty hash' do
|
146
|
+
subject { parameters_hash }
|
147
|
+
|
148
|
+
let(:new_parameters) { {foo: :bar} }
|
149
|
+
|
150
|
+
context 'and there is no conflicting key' do
|
151
|
+
before { add_parameters }
|
152
|
+
|
153
|
+
it { should include(new_parameters) }
|
154
|
+
end
|
155
|
+
|
156
|
+
context 'and there is a conflicting key' do
|
157
|
+
before { add_parameters }
|
158
|
+
let(:expected_error_class) do
|
159
|
+
described_class::Errors::ParameterKeyConflict
|
160
|
+
end
|
161
|
+
|
162
|
+
context 'in symbol' do
|
163
|
+
specify do
|
164
|
+
expect { add_parameters }
|
165
|
+
.to raise_error(expected_error_class)
|
166
|
+
end
|
167
|
+
end
|
168
|
+
context 'in string' do
|
169
|
+
specify do
|
170
|
+
expect { add_parameters(new_parameters.stringify_keys) }
|
171
|
+
.to raise_error(expected_error_class)
|
172
|
+
end
|
173
|
+
end
|
174
|
+
end
|
175
|
+
end
|
176
|
+
end
|
177
|
+
|
178
|
+
|
179
|
+
describe 'options passed' do
|
180
|
+
context 'when nothing is set' do
|
181
|
+
specify do
|
182
|
+
expect(Airbrake)
|
183
|
+
.to(receive(:notify_or_ignore)
|
184
|
+
.with(kind_of(StandardError), {}))
|
185
|
+
|
186
|
+
notify_or_raise
|
187
|
+
end
|
188
|
+
end
|
189
|
+
context 'when all things are set' do
|
190
|
+
let!(:custom_error_class) { Class.new(StandardError) }
|
191
|
+
let!(:custom_error_message) { 'hi' }
|
192
|
+
let!(:custom_parameters) { {foo: :bar}.stringify_keys }
|
193
|
+
before { instance.set_default_airbrake_notice_error_class(custom_error_class) }
|
194
|
+
before { instance.set_default_airbrake_notice_error_message(custom_error_message) }
|
195
|
+
before { instance.add_default_airbrake_notice_parameters(custom_parameters) }
|
196
|
+
|
197
|
+
specify do
|
198
|
+
expect(Airbrake)
|
199
|
+
.to(receive(:notify_or_ignore)
|
200
|
+
.with(kind_of(StandardError), {
|
201
|
+
error_class: custom_error_class,
|
202
|
+
error_message: custom_error_message,
|
203
|
+
parameters: custom_parameters.symbolize_keys,
|
204
|
+
}))
|
205
|
+
|
206
|
+
notify_or_raise
|
207
|
+
end
|
208
|
+
end
|
209
|
+
end
|
210
|
+
end
|
211
|
+
end
|
@@ -0,0 +1,51 @@
|
|
1
|
+
|
2
|
+
class TestServiceWithAirbrake
|
3
|
+
include ExecuteWithRescue::Mixins::WithAirbrake
|
4
|
+
|
5
|
+
def call
|
6
|
+
execute_with_rescue do
|
7
|
+
do_something
|
8
|
+
end
|
9
|
+
end
|
10
|
+
|
11
|
+
private
|
12
|
+
|
13
|
+
def do_something
|
14
|
+
# do nothing
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
class TestServiceWithAirbrakeWithError < TestServiceWithAirbrake
|
19
|
+
def do_something
|
20
|
+
raise StandardError
|
21
|
+
end
|
22
|
+
end
|
23
|
+
class TestServiceWithAirbrakeWithErrorAndAirbrakeOption <
|
24
|
+
TestServiceWithAirbrakeWithError
|
25
|
+
|
26
|
+
CustomError = Class.new(StandardError)
|
27
|
+
|
28
|
+
def do_something
|
29
|
+
set_default_airbrake_notice_error_class(CustomError)
|
30
|
+
set_default_airbrake_notice_error_message('hi')
|
31
|
+
add_default_airbrake_notice_parameters({foo: :bar})
|
32
|
+
|
33
|
+
super
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
class TestServiceWithAirbrakeWithExecuteWithRescueCall <
|
38
|
+
TestServiceWithAirbrake
|
39
|
+
|
40
|
+
def do_something
|
41
|
+
set_default_airbrake_notice_error_message('test')
|
42
|
+
end
|
43
|
+
end
|
44
|
+
class TestServiceWithAirbrakeWithoutExecuteWithRescueCall <
|
45
|
+
TestServiceWithAirbrakeWithExecuteWithRescueCall
|
46
|
+
|
47
|
+
def call
|
48
|
+
# without `execute_with_rescue`
|
49
|
+
do_something
|
50
|
+
end
|
51
|
+
end
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
if ENV["TRAVIS"]
|
2
|
+
require 'coveralls'
|
3
|
+
Coveralls.wear!
|
4
|
+
end
|
5
|
+
|
6
|
+
require 'execute_with_rescue_with_airbrake'
|
7
|
+
require 'airbrake'
|
8
|
+
|
9
|
+
require 'fixtures/test_service_classes'
|
10
|
+
require 'rspec'
|
11
|
+
|
12
|
+
require 'logger'
|
13
|
+
|
14
|
+
# Need to configurate it before any `notify_or_ignore`
|
15
|
+
Airbrake.configure(true) do |config|
|
16
|
+
config.test_mode = true
|
17
|
+
end
|
18
|
+
|
19
|
+
RSpec.configure do |config|
|
20
|
+
end
|
metadata
ADDED
@@ -0,0 +1,192 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: execute_with_rescue_with_airbrake
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.1
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- PikachuEXE
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2014-03-27 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: execute_with_rescue
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - ~>
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '0.0'
|
20
|
+
- - '>='
|
21
|
+
- !ruby/object:Gem::Version
|
22
|
+
version: 0.0.1
|
23
|
+
type: :runtime
|
24
|
+
prerelease: false
|
25
|
+
version_requirements: !ruby/object:Gem::Requirement
|
26
|
+
requirements:
|
27
|
+
- - ~>
|
28
|
+
- !ruby/object:Gem::Version
|
29
|
+
version: '0.0'
|
30
|
+
- - '>='
|
31
|
+
- !ruby/object:Gem::Version
|
32
|
+
version: 0.0.1
|
33
|
+
- !ruby/object:Gem::Dependency
|
34
|
+
name: airbrake
|
35
|
+
requirement: !ruby/object:Gem::Requirement
|
36
|
+
requirements:
|
37
|
+
- - ~>
|
38
|
+
- !ruby/object:Gem::Version
|
39
|
+
version: 3.1.0
|
40
|
+
type: :runtime
|
41
|
+
prerelease: false
|
42
|
+
version_requirements: !ruby/object:Gem::Requirement
|
43
|
+
requirements:
|
44
|
+
- - ~>
|
45
|
+
- !ruby/object:Gem::Version
|
46
|
+
version: 3.1.0
|
47
|
+
- !ruby/object:Gem::Dependency
|
48
|
+
name: bundler
|
49
|
+
requirement: !ruby/object:Gem::Requirement
|
50
|
+
requirements:
|
51
|
+
- - ~>
|
52
|
+
- !ruby/object:Gem::Version
|
53
|
+
version: '1.5'
|
54
|
+
type: :development
|
55
|
+
prerelease: false
|
56
|
+
version_requirements: !ruby/object:Gem::Requirement
|
57
|
+
requirements:
|
58
|
+
- - ~>
|
59
|
+
- !ruby/object:Gem::Version
|
60
|
+
version: '1.5'
|
61
|
+
- !ruby/object:Gem::Dependency
|
62
|
+
name: rake
|
63
|
+
requirement: !ruby/object:Gem::Requirement
|
64
|
+
requirements:
|
65
|
+
- - '>='
|
66
|
+
- !ruby/object:Gem::Version
|
67
|
+
version: '0'
|
68
|
+
type: :development
|
69
|
+
prerelease: false
|
70
|
+
version_requirements: !ruby/object:Gem::Requirement
|
71
|
+
requirements:
|
72
|
+
- - '>='
|
73
|
+
- !ruby/object:Gem::Version
|
74
|
+
version: '0'
|
75
|
+
- !ruby/object:Gem::Dependency
|
76
|
+
name: appraisal
|
77
|
+
requirement: !ruby/object:Gem::Requirement
|
78
|
+
requirements:
|
79
|
+
- - '>='
|
80
|
+
- !ruby/object:Gem::Version
|
81
|
+
version: 0.5.2
|
82
|
+
type: :development
|
83
|
+
prerelease: false
|
84
|
+
version_requirements: !ruby/object:Gem::Requirement
|
85
|
+
requirements:
|
86
|
+
- - '>='
|
87
|
+
- !ruby/object:Gem::Version
|
88
|
+
version: 0.5.2
|
89
|
+
- !ruby/object:Gem::Dependency
|
90
|
+
name: rspec
|
91
|
+
requirement: !ruby/object:Gem::Requirement
|
92
|
+
requirements:
|
93
|
+
- - ~>
|
94
|
+
- !ruby/object:Gem::Version
|
95
|
+
version: 2.14.0
|
96
|
+
type: :development
|
97
|
+
prerelease: false
|
98
|
+
version_requirements: !ruby/object:Gem::Requirement
|
99
|
+
requirements:
|
100
|
+
- - ~>
|
101
|
+
- !ruby/object:Gem::Version
|
102
|
+
version: 2.14.0
|
103
|
+
- !ruby/object:Gem::Dependency
|
104
|
+
name: coveralls
|
105
|
+
requirement: !ruby/object:Gem::Requirement
|
106
|
+
requirements:
|
107
|
+
- - '>='
|
108
|
+
- !ruby/object:Gem::Version
|
109
|
+
version: '0.7'
|
110
|
+
type: :development
|
111
|
+
prerelease: false
|
112
|
+
version_requirements: !ruby/object:Gem::Requirement
|
113
|
+
requirements:
|
114
|
+
- - '>='
|
115
|
+
- !ruby/object:Gem::Version
|
116
|
+
version: '0.7'
|
117
|
+
- !ruby/object:Gem::Dependency
|
118
|
+
name: gem-release
|
119
|
+
requirement: !ruby/object:Gem::Requirement
|
120
|
+
requirements:
|
121
|
+
- - '>='
|
122
|
+
- !ruby/object:Gem::Version
|
123
|
+
version: '0.7'
|
124
|
+
type: :development
|
125
|
+
prerelease: false
|
126
|
+
version_requirements: !ruby/object:Gem::Requirement
|
127
|
+
requirements:
|
128
|
+
- - '>='
|
129
|
+
- !ruby/object:Gem::Version
|
130
|
+
version: '0.7'
|
131
|
+
description:
|
132
|
+
email:
|
133
|
+
- pikachuexe@gmail.com
|
134
|
+
executables: []
|
135
|
+
extensions: []
|
136
|
+
extra_rdoc_files: []
|
137
|
+
files:
|
138
|
+
- .gitignore
|
139
|
+
- .rspec
|
140
|
+
- .travis.yml
|
141
|
+
- Appraisals
|
142
|
+
- CHANGELOG.md
|
143
|
+
- Gemfile
|
144
|
+
- LICENSE.txt
|
145
|
+
- README.md
|
146
|
+
- Rakefile
|
147
|
+
- execute_with_rescue_with_airbrake.gemspec
|
148
|
+
- gemfiles/rails_3_2.gemfile
|
149
|
+
- gemfiles/rails_3_2.gemfile.lock
|
150
|
+
- gemfiles/rails_4_0.gemfile
|
151
|
+
- gemfiles/rails_4_0.gemfile.lock
|
152
|
+
- gemfiles/rails_4_1.gemfile
|
153
|
+
- gemfiles/rails_4_1.gemfile.lock
|
154
|
+
- lib/execute_with_rescue/errors/no_airbrake_adapter.rb
|
155
|
+
- lib/execute_with_rescue/mixins/with_airbrake.rb
|
156
|
+
- lib/execute_with_rescue_with_airbrake.rb
|
157
|
+
- lib/execute_with_rescue_with_airbrake/adapters/airbrake_adapter.rb
|
158
|
+
- lib/execute_with_rescue_with_airbrake/version.rb
|
159
|
+
- spec/execute_with_rescue/mixins/with_airbrake_spec.rb
|
160
|
+
- spec/execute_with_rescue_with_airbrake/adapters/airbrake_adapter_spec.rb
|
161
|
+
- spec/fixtures/test_service_classes.rb
|
162
|
+
- spec/spec_helper.rb
|
163
|
+
homepage: http://github.com/PikachuEXE/execute_with_rescue_with_airbrake
|
164
|
+
licenses:
|
165
|
+
- MIT
|
166
|
+
metadata: {}
|
167
|
+
post_install_message:
|
168
|
+
rdoc_options: []
|
169
|
+
require_paths:
|
170
|
+
- lib
|
171
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
172
|
+
requirements:
|
173
|
+
- - '>='
|
174
|
+
- !ruby/object:Gem::Version
|
175
|
+
version: 1.9.3
|
176
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
177
|
+
requirements:
|
178
|
+
- - '>='
|
179
|
+
- !ruby/object:Gem::Version
|
180
|
+
version: 1.4.0
|
181
|
+
requirements: []
|
182
|
+
rubyforge_project:
|
183
|
+
rubygems_version: 2.2.2
|
184
|
+
signing_key:
|
185
|
+
specification_version: 4
|
186
|
+
summary: The Airbrake adapter plus mixin to be used with `execute_with_rescue`
|
187
|
+
test_files:
|
188
|
+
- spec/execute_with_rescue/mixins/with_airbrake_spec.rb
|
189
|
+
- spec/execute_with_rescue_with_airbrake/adapters/airbrake_adapter_spec.rb
|
190
|
+
- spec/fixtures/test_service_classes.rb
|
191
|
+
- spec/spec_helper.rb
|
192
|
+
has_rdoc:
|