execute_with_rescue_with_airbrake 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
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
@@ -0,0 +1,18 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ .yardoc
6
+ Gemfile.lock
7
+ InstalledFiles
8
+ _yardoc
9
+ coverage
10
+ doc/
11
+ lib/bundler/man
12
+ pkg
13
+ rdoc
14
+ spec/reports
15
+ test/tmp
16
+ test/version_tmp
17
+ tmp
18
+ *.lock
data/.rspec ADDED
@@ -0,0 +1 @@
1
+ --color
data/.travis.yml ADDED
@@ -0,0 +1,12 @@
1
+ language: ruby
2
+ cache:
3
+ - bundler
4
+ rvm:
5
+ - 1.9.3
6
+ - 2.0.0
7
+ - 2.1.0
8
+ - 2.1.1
9
+ gemfile:
10
+ - gemfiles/rails_3_2.gemfile
11
+ - gemfiles/rails_4_0.gemfile
12
+ - gemfiles/rails_4_1.gemfile
data/Appraisals ADDED
@@ -0,0 +1,11 @@
1
+ appraise "rails-3-2" do
2
+ gem "activesupport", "3.2.17"
3
+ end
4
+
5
+ appraise "rails-4-0" do
6
+ gem "activesupport", "4.0.4"
7
+ end
8
+
9
+ appraise "rails-4-1" do
10
+ gem "activesupport", "4.1.0.rc1"
11
+ end
data/CHANGELOG.md ADDED
@@ -0,0 +1,5 @@
1
+ ### Changelog
2
+
3
+
4
+ - **0.0.1**
5
+ - Initial Release
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in execute_with_rescue_with_airbrake.gemspec
4
+ gemspec
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
+ [![Build Status](http://img.shields.io/travis/PikachuEXE/execute_with_rescue_with_airbrake.svg)](https://travis-ci.org/PikachuEXE/execute_with_rescue_with_airbrake)
14
+ [![Gem Version](http://img.shields.io/gem/v/execute_with_rescue_with_airbrake.svg)](http://badge.fury.io/rb/execute_with_rescue_with_airbrake)
15
+ [![Dependency Status](http://img.shields.io/gemnasium/PikachuEXE/execute_with_rescue_with_airbrake.svg)](https://gemnasium.com/PikachuEXE/execute_with_rescue_with_airbrake)
16
+ [![Coverage Status](http://img.shields.io/coveralls/PikachuEXE/execute_with_rescue_with_airbrake.svg)](https://coveralls.io/r/PikachuEXE/execute_with_rescue_with_airbrake)
17
+ [![Code Climate](http://img.shields.io/codeclimate/github/PikachuEXE/execute_with_rescue_with_airbrake.svg)](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,7 @@
1
+ # This file was generated by Appraisal
2
+
3
+ source "https://rubygems.org"
4
+
5
+ gem "activesupport", "3.2.17"
6
+
7
+ gemspec :path=>"../"
@@ -0,0 +1,7 @@
1
+ # This file was generated by Appraisal
2
+
3
+ source "https://rubygems.org"
4
+
5
+ gem "activesupport", "4.0.4"
6
+
7
+ gemspec :path=>"../"
@@ -0,0 +1,7 @@
1
+ # This file was generated by Appraisal
2
+
3
+ source "https://rubygems.org"
4
+
5
+ gem "activesupport", "4.1.0.rc1"
6
+
7
+ gemspec :path=>"../"
@@ -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,7 @@
1
+ require 'execute_with_rescue_with_airbrake/version'
2
+ require 'execute_with_rescue'
3
+ require 'execute_with_rescue/mixins/with_airbrake'
4
+
5
+
6
+ module ExecuteWithRescueWithAirbrake
7
+ 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,3 @@
1
+ module ExecuteWithRescueWithAirbrake
2
+ VERSION = "0.0.1"
3
+ 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
@@ -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: