airbrake 4.3.8 → 5.0.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.
Files changed (134) hide show
  1. checksums.yaml +4 -4
  2. data/lib/airbrake/capistrano/tasks.rb +64 -0
  3. data/lib/airbrake/delayed_job/plugin.rb +48 -0
  4. data/lib/airbrake/rack/middleware.rb +45 -0
  5. data/lib/airbrake/rack/notice_builder.rb +80 -0
  6. data/lib/airbrake/rack/user.rb +51 -0
  7. data/lib/airbrake/rails/action_controller.rb +35 -0
  8. data/lib/airbrake/rails/active_job.rb +23 -0
  9. data/lib/airbrake/rails/active_record.rb +40 -0
  10. data/lib/airbrake/rails/railtie.rb +61 -0
  11. data/lib/airbrake/rake/task_ext.rb +61 -0
  12. data/lib/airbrake/rake/tasks.rb +93 -0
  13. data/lib/airbrake/resque/failure.rb +19 -0
  14. data/lib/airbrake/sidekiq/error_handler.rb +35 -0
  15. data/lib/airbrake/version.rb +4 -1
  16. data/lib/airbrake.rb +16 -185
  17. data/lib/generators/airbrake_generator.rb +25 -0
  18. data/lib/generators/airbrake_initializer.rb.erb +55 -0
  19. data/spec/airbrake_spec.rb +0 -0
  20. data/spec/apps/rack/dummy_app.rb +17 -0
  21. data/spec/apps/rails/dummy_app.rb +150 -0
  22. data/spec/apps/rails/dummy_task.rake +20 -0
  23. data/spec/apps/rails/logs/32.log +13358 -0
  24. data/spec/apps/rails/logs/40.log +6854 -0
  25. data/spec/apps/rails/logs/41.log +3170 -0
  26. data/spec/apps/rails/logs/42.log +23919 -0
  27. data/spec/apps/rails/logs/50.log +10976 -0
  28. data/spec/apps/sinatra/dummy_app.rb +12 -0
  29. data/spec/integration/rack/rack_spec.rb +17 -0
  30. data/spec/integration/rails/rails_spec.rb +135 -0
  31. data/spec/integration/rails/rake_spec.rb +160 -0
  32. data/spec/integration/shared_examples/rack_examples.rb +106 -0
  33. data/spec/integration/sinatra/sinatra_spec.rb +15 -0
  34. data/spec/spec_helper.rb +127 -0
  35. data/spec/unit/rack/middleware_spec.rb +80 -0
  36. data/spec/unit/rack/notice_builder_spec.rb +35 -0
  37. data/spec/unit/rack/user_spec.rb +78 -0
  38. data/spec/unit/rake/tasks_spec.rb +40 -0
  39. data/spec/unit/sidekiq/error_handler_spec.rb +29 -0
  40. metadata +108 -323
  41. data/CHANGELOG +0 -1716
  42. data/Gemfile +0 -3
  43. data/Guardfile +0 -6
  44. data/INSTALL +0 -20
  45. data/LICENSE +0 -61
  46. data/README.md +0 -148
  47. data/README_FOR_HEROKU_ADDON.md +0 -102
  48. data/Rakefile +0 -179
  49. data/TESTED_AGAINST +0 -7
  50. data/airbrake.gemspec +0 -41
  51. data/bin/airbrake +0 -12
  52. data/features/metal.feature +0 -34
  53. data/features/rack.feature +0 -60
  54. data/features/rails.feature +0 -324
  55. data/features/rake.feature +0 -33
  56. data/features/sinatra.feature +0 -126
  57. data/features/step_definitions/file_steps.rb +0 -14
  58. data/features/step_definitions/rack_steps.rb +0 -27
  59. data/features/step_definitions/rails_application_steps.rb +0 -267
  60. data/features/step_definitions/rake_steps.rb +0 -22
  61. data/features/support/airbrake_shim.rb.template +0 -11
  62. data/features/support/aruba.rb +0 -5
  63. data/features/support/env.rb +0 -39
  64. data/features/support/matchers.rb +0 -35
  65. data/features/support/rails.rb +0 -156
  66. data/features/support/rake/Rakefile +0 -77
  67. data/features/user_informer.feature +0 -57
  68. data/generators/airbrake/airbrake_generator.rb +0 -94
  69. data/generators/airbrake/lib/insert_commands.rb +0 -34
  70. data/generators/airbrake/lib/rake_commands.rb +0 -24
  71. data/generators/airbrake/templates/airbrake_tasks.rake +0 -25
  72. data/generators/airbrake/templates/capistrano_hook.rb +0 -6
  73. data/generators/airbrake/templates/initializer.rb +0 -4
  74. data/install.rb +0 -1
  75. data/lib/airbrake/backtrace.rb +0 -103
  76. data/lib/airbrake/capistrano.rb +0 -103
  77. data/lib/airbrake/capistrano3.rb +0 -3
  78. data/lib/airbrake/cli/client.rb +0 -76
  79. data/lib/airbrake/cli/options.rb +0 -45
  80. data/lib/airbrake/cli/printer.rb +0 -33
  81. data/lib/airbrake/cli/project.rb +0 -17
  82. data/lib/airbrake/cli/project_factory.rb +0 -33
  83. data/lib/airbrake/cli/runner.rb +0 -49
  84. data/lib/airbrake/cli/validator.rb +0 -8
  85. data/lib/airbrake/configuration.rb +0 -366
  86. data/lib/airbrake/jobs/send_job.rb +0 -7
  87. data/lib/airbrake/notice.rb +0 -411
  88. data/lib/airbrake/rack.rb +0 -64
  89. data/lib/airbrake/rails/action_controller_catcher.rb +0 -32
  90. data/lib/airbrake/rails/controller_methods.rb +0 -146
  91. data/lib/airbrake/rails/error_lookup.rb +0 -35
  92. data/lib/airbrake/rails/middleware.rb +0 -63
  93. data/lib/airbrake/rails.rb +0 -45
  94. data/lib/airbrake/rails3_tasks.rb +0 -126
  95. data/lib/airbrake/railtie.rb +0 -46
  96. data/lib/airbrake/rake_handler.rb +0 -75
  97. data/lib/airbrake/response.rb +0 -29
  98. data/lib/airbrake/sender.rb +0 -213
  99. data/lib/airbrake/shared_tasks.rb +0 -59
  100. data/lib/airbrake/sidekiq.rb +0 -8
  101. data/lib/airbrake/sinatra.rb +0 -40
  102. data/lib/airbrake/tasks/airbrake.cap +0 -28
  103. data/lib/airbrake/tasks.rb +0 -81
  104. data/lib/airbrake/user_informer.rb +0 -36
  105. data/lib/airbrake/utils/params_cleaner.rb +0 -141
  106. data/lib/airbrake/utils/rack_filters.rb +0 -45
  107. data/lib/airbrake_tasks.rb +0 -62
  108. data/lib/rails/generators/airbrake/airbrake_generator.rb +0 -155
  109. data/lib/templates/rescue.erb +0 -91
  110. data/rails/init.rb +0 -1
  111. data/resources/README.md +0 -34
  112. data/resources/airbrake_2_4.xsd +0 -89
  113. data/resources/airbrake_3_0.json +0 -52
  114. data/resources/ca-bundle.crt +0 -3376
  115. data/script/integration_test.rb +0 -35
  116. data/test/airbrake_tasks_test.rb +0 -161
  117. data/test/backtrace_test.rb +0 -215
  118. data/test/capistrano_test.rb +0 -44
  119. data/test/configuration_test.rb +0 -303
  120. data/test/controller_methods_test.rb +0 -230
  121. data/test/helper.rb +0 -233
  122. data/test/integration/catcher_test.rb +0 -371
  123. data/test/integration.rb +0 -13
  124. data/test/logger_test.rb +0 -79
  125. data/test/notice_test.rb +0 -494
  126. data/test/notifier_test.rb +0 -288
  127. data/test/params_cleaner_test.rb +0 -204
  128. data/test/rack_test.rb +0 -62
  129. data/test/rails_initializer_test.rb +0 -36
  130. data/test/recursion_test.rb +0 -10
  131. data/test/response_test.rb +0 -18
  132. data/test/sender_test.rb +0 -335
  133. data/test/support/response_shim.xml +0 -4
  134. data/test/user_informer_test.rb +0 -29
@@ -0,0 +1,12 @@
1
+ class DummyApp < Sinatra::Base
2
+ use Airbrake::Rack::Middleware
3
+ use Warden::Manager
4
+
5
+ get '/' do
6
+ 'Hello from index'
7
+ end
8
+
9
+ get '/crash' do
10
+ raise AirbrakeTestError
11
+ end
12
+ end
@@ -0,0 +1,17 @@
1
+ require 'spec_helper'
2
+ require 'integration/shared_examples/rack_examples'
3
+
4
+ RSpec.describe "Rack integration specs" do
5
+ let(:app) { DummyApp }
6
+
7
+ include_examples 'rack examples'
8
+
9
+ describe "context payload" do
10
+ it "includes version" do
11
+ get '/crash'
12
+ wait_for_a_request_with_body(
13
+ /"context":{.*"version":"1.2.3 Rack\.version.+Rack\.release/
14
+ )
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,135 @@
1
+ require 'spec_helper'
2
+ require 'integration/shared_examples/rack_examples'
3
+
4
+ RSpec.describe "Rails integration specs" do
5
+ include Warden::Test::Helpers
6
+
7
+ let(:app) { Rails.application }
8
+
9
+ include_examples 'rack examples'
10
+
11
+ it "inserts the Airbrake Rack middleware after DebugExceptions" do
12
+ middlewares = Rails.configuration.middleware.middlewares.map(&:inspect)
13
+ own_idx = middlewares.index('Airbrake::Rack::Middleware')
14
+
15
+ expect(middlewares[own_idx - 1]).to eq('ActionDispatch::DebugExceptions')
16
+ end
17
+
18
+ shared_examples 'context payload content' do |route|
19
+ before do
20
+ login_as(OpenStruct.new(id: 1, email: 'qa@example.com', username: 'qa-dept'))
21
+ get(route, foo: :bar)
22
+ end
23
+
24
+ it "includes component information" do
25
+ wait_for_a_request_with_body(/"context":{.*"component":"dummy".*}/)
26
+ end
27
+
28
+ it "includes action information" do
29
+ case route
30
+ when '/crash'
31
+ wait_for_a_request_with_body(/"context":{.*"action":"crash".*}/)
32
+ when '/notify_airbrake_helper'
33
+ wait_for_a_request_with_body(
34
+ /"context":{.*"action":"notify_airbrake_helper".*}/
35
+ )
36
+ when '/notify_airbrake_sync_helper'
37
+ wait_for_a_request_with_body(
38
+ /"context":{.*"action":"notify_airbrake_sync_helper".*}/
39
+ )
40
+ else
41
+ raise 'Unknown route'
42
+ end
43
+ end
44
+
45
+ it "includes version" do
46
+ wait_for_a_request_with_body(/"context":{.*"version":"1.2.3 Rails/)
47
+ end
48
+
49
+ it "includes session" do
50
+ wait_for_a_request_with_body(
51
+ /"context":{.*"session":{.*"session_id":"\w+".*}/
52
+ )
53
+ end
54
+
55
+ it "includes params" do
56
+ action = route[1..-1]
57
+ wait_for_a_request_with_body(
58
+ /"context":{.*"params":{.*"controller":"dummy","action":"#{action}".*}/
59
+ )
60
+ end
61
+ end
62
+
63
+ describe "context payload" do
64
+ context "when exception reported through middleware" do
65
+ include_examples('context payload content', '/crash')
66
+ end
67
+
68
+ context "when exception reported through the notify_airbrake helper" do
69
+ include_examples('context payload content', '/notify_airbrake_helper')
70
+ end
71
+
72
+ context "when exception reported through the notify_airbrake_sync helper" do
73
+ include_examples('context payload content', '/notify_airbrake_sync_helper')
74
+ end
75
+ end
76
+
77
+ describe "Active Record callbacks" do
78
+ it "reports exceptions in after_commit callbacks" do
79
+ get '/active_record_after_commit'
80
+ wait_for_a_request_with_body(
81
+ /"type":"AirbrakeTestError","message":"after_commit"/
82
+ )
83
+ end
84
+
85
+ it "reports exceptions in after_rollback callbacks" do
86
+ get '/active_record_after_rollback'
87
+ wait_for_a_request_with_body(
88
+ /"type":"AirbrakeTestError","message":"after_rollback"/
89
+ )
90
+ end
91
+ end
92
+
93
+ if Gem::Version.new(Rails.version) >= Gem::Version.new('4.2')
94
+ describe "ActiveJob jobs" do
95
+ it "reports exceptions occurring in ActiveJob workers" do
96
+ get '/active_job'
97
+ sleep 2
98
+
99
+ wait_for(
100
+ a_request(:post, endpoint).
101
+ with(body: /"message":"active_job error"/)
102
+ ).to have_been_made.twice
103
+ end
104
+ end
105
+ end
106
+
107
+ describe "Resque workers" do
108
+ it "reports exceptions occurring in Resque workers" do
109
+ with_resque { get '/resque' }
110
+
111
+ wait_for_a_request_with_body(
112
+ /"message":"resque\serror".*"params":{.*
113
+ "class":"BingoWorker","args":\["bango","bongo"\].*}/x
114
+ )
115
+ end
116
+ end
117
+
118
+ describe "DelayedJob jobs" do
119
+ it "reports exceptions occurring in DelayedJob jobs" do
120
+ get '/delayed_job'
121
+ sleep 2
122
+
123
+ wait_for_a_request_with_body(
124
+ %r("message":"delayed_job\serror".*"params":{.*
125
+ "handler":"---\s!ruby/struct:BangoJob\\nbingo:\s
126
+ bingo\\nbongo:\sbongo\\n".*})x
127
+ )
128
+
129
+ # Two requests are performed during this example. We care only about one.
130
+ # Sleep guarantees that we let the unimportant request occur here and not
131
+ # elsewhere.
132
+ sleep 2
133
+ end
134
+ end
135
+ end
@@ -0,0 +1,160 @@
1
+ require 'spec_helper'
2
+
3
+ RSpec.describe "Rake integration" do
4
+ let(:endpoint) do
5
+ 'https://airbrake.io/api/v3/projects/113743/notices?key=fd04e13d806a90f96614ad8e529b2822'
6
+ end
7
+
8
+ def wait_for_a_request_with_body(body)
9
+ wait_for(a_request(:post, endpoint).with(body: body)).to have_been_made.once
10
+ end
11
+
12
+ def expect_no_requests_with_body(body)
13
+ sleep 1
14
+ expect(a_request(:post, endpoint).with(body: body)).not_to have_been_made
15
+ end
16
+
17
+ before do
18
+ Rails.application.load_tasks
19
+ stub_request(:post, endpoint).to_return(status: 201, body: '{}')
20
+ expect { faulty_task.invoke }.to raise_error(AirbrakeTestError)
21
+ end
22
+
23
+ after do
24
+ # Rake ensures that each task is executed only once per session. For testing
25
+ # purposes, we run the task multiple times.
26
+ faulty_task.reenable
27
+ end
28
+
29
+ describe "a task with maximum information, which raises an exception" do
30
+ let(:faulty_task) { Rake::Task['bingo:bango'] }
31
+
32
+ it "sends the exception to Airbrake" do
33
+ wait_for_a_request_with_body(/"errors":\[{"type":"AirbrakeTestError"/)
34
+ end
35
+
36
+ describe "contains the context payload, which" do
37
+ it "includes correct component" do
38
+ wait_for_a_request_with_body(/"context":{.*"component":"rake".*}/)
39
+ end
40
+
41
+ it "includes correct action" do
42
+ wait_for_a_request_with_body(
43
+ /"context":{.*"action":"bingo:bango".*/
44
+ )
45
+ end
46
+ end
47
+
48
+ describe "contains the params payload, which" do
49
+ it "includes a task name" do
50
+ wait_for_a_request_with_body(
51
+ /"params":{.*"rake_task":{.*"name":"bingo:bango".*}.*}/
52
+ )
53
+ end
54
+
55
+ it "includes a timestamp" do
56
+ wait_for_a_request_with_body(
57
+ /"params":{.*"rake_task":{.*"timestamp":"201\d\-\d\d-\d\d.+".*}.*}/
58
+ )
59
+ end
60
+
61
+ it "includes investigation" do
62
+ # rubocop:disable Metrics/LineLength
63
+ wait_for_a_request_with_body(
64
+ /"params":{.*"rake_task":{.*"investigation":".+Investigating bingo:bango.+".*}.*}/
65
+ )
66
+ # rubocop:enable Metrics/LineLength
67
+ end
68
+
69
+ it "includes full comment" do
70
+ wait_for_a_request_with_body(
71
+ /"params":{.*"rake_task":{.*"full_comment":"Dummy description".*}.*}/
72
+ )
73
+ end
74
+
75
+ it "includes arg names" do
76
+ wait_for_a_request_with_body(
77
+ /"params":{.*"rake_task":{.*"arg_names":\["dummy_arg"\].*}.*}/
78
+ )
79
+ end
80
+
81
+ it "includes arg description" do
82
+ wait_for_a_request_with_body(
83
+ /"params":{.*"rake_task":{.*"arg_description":"\[dummy_arg\]".*}.*}/
84
+ )
85
+ end
86
+
87
+ it "includes locations" do
88
+ # rubocop:disable Metrics/LineLength
89
+ wait_for_a_request_with_body(
90
+ %r("params":{.*"rake_task":{.*"locations":\[".+spec/apps/rails/dummy_task.rake:\d+:in.+"\].*}.*})
91
+ )
92
+ # rubocop:enable Metrics/LineLength
93
+ end
94
+
95
+ it "includes sources" do
96
+ wait_for_a_request_with_body(
97
+ /"params":{.*"rake_task":{.*"sources":\["environment"\].*}.*}/
98
+ )
99
+ end
100
+
101
+ it "includes prerequisite tasks" do
102
+ # rubocop:disable Metrics/LineLength
103
+ wait_for_a_request_with_body(
104
+ /"params":{.*"rake_task":{.*"prerequisite_tasks":\[{"name":"bingo:environment".+\].*}.*}/
105
+ )
106
+ # rubocop:enable Metrics/LineLength
107
+ end
108
+
109
+ it "includes argv info" do
110
+ wait_for_a_request_with_body(
111
+ %r("params":{.*"argv":"--pattern spec/integration/rails/\*_spec.rb".*})
112
+ )
113
+ end
114
+
115
+ it "includes #execute args" do
116
+ wait_for_a_request_with_body(
117
+ /"params":{.*"execute_args":\[\].*}/
118
+ )
119
+ end
120
+ end
121
+ end
122
+
123
+ describe "a task with minimum information, which raises an exception" do
124
+ let(:faulty_task) { Rake::Task['bingo:bongo'] }
125
+
126
+ describe "doesn't contain in the params payload" do
127
+ it "full comment" do
128
+ expect_no_requests_with_body(
129
+ /"params":{.*"rake_task":{.*"full_comment":"Dummy description".*}.*}/
130
+ )
131
+ end
132
+
133
+ it "arg names" do
134
+ expect_no_requests_with_body(
135
+ /"params":{.*"rake_task":{.*"arg_names":\["dummy_arg"\].*}.*}/
136
+ )
137
+ end
138
+
139
+ it "arg description" do
140
+ expect_no_requests_with_body(
141
+ /"params":{.*"rake_task":{.*"arg_description":"\[dummy_arg\]".*}.*}/
142
+ )
143
+ end
144
+
145
+ it "sources" do
146
+ expect_no_requests_with_body(
147
+ /"params":{.*"rake_task":{.*"sources":\["environment"\].*}.*}/
148
+ )
149
+ end
150
+
151
+ it "prerequisite tasks" do
152
+ # rubocop:disable Metrics/LineLength
153
+ expect_no_requests_with_body(
154
+ /"params":{.*"rake_task":{.*"prerequisite_tasks":\[{"name":"bingo:environment".+\].*}.*}/
155
+ )
156
+ # rubocop:enable Metrics/LineLength
157
+ end
158
+ end
159
+ end
160
+ end
@@ -0,0 +1,106 @@
1
+ RSpec.shared_examples 'rack examples' do
2
+ include Warden::Test::Helpers
3
+
4
+ after { Warden.test_reset! }
5
+
6
+ let(:endpoint) do
7
+ 'https://airbrake.io/api/v3/projects/113743/notices?key=fd04e13d806a90f96614ad8e529b2822'
8
+ end
9
+
10
+ def wait_for_a_request_with_body(body)
11
+ wait_for(a_request(:post, endpoint).with(body: body)).to have_been_made.once
12
+ end
13
+
14
+ before do
15
+ stub_request(:post, endpoint).to_return(status: 201, body: '{}')
16
+ end
17
+
18
+ describe "application routes" do
19
+ describe "/index" do
20
+ it "successfully returns 200 and body" do
21
+ get '/'
22
+
23
+ expect(last_response.status).to eq(200)
24
+ expect(last_response.body).to eq('Hello from index')
25
+
26
+ wait_for(a_request(:post, endpoint)).not_to have_been_made
27
+ end
28
+ end
29
+
30
+ describe "/crash" do
31
+ it "returns 500 and sends a notice to Airbrake" do
32
+ get '/crash'
33
+
34
+ expect(last_response.status).to eq(500)
35
+ wait_for_a_request_with_body(/"errors":\[{"type":"AirbrakeTestError"/)
36
+ end
37
+ end
38
+ end
39
+
40
+ describe "context payload" do
41
+ context "when the user is present" do
42
+ let(:common_user_params) do
43
+ { id: 1, email: 'qa@example.com', username: 'qa-dept' }
44
+ end
45
+
46
+ before do
47
+ login_as(OpenStruct.new(user_params))
48
+ get '/crash'
49
+ end
50
+
51
+ context "when the user has first and last names" do
52
+ let(:user_params) do
53
+ common_user_params.merge(first_name: 'Bingo', last_name: 'Bongo')
54
+ end
55
+
56
+ it "reports the user's first and last names" do
57
+ wait_for_a_request_with_body(/
58
+ "context":{.*
59
+ "user":{
60
+ "id":"1",
61
+ "name":"Bingo\sBongo",
62
+ "username":"qa-dept",
63
+ "email":"qa@example.com"}
64
+ /x)
65
+ end
66
+ end
67
+
68
+ context "when the user has only name" do
69
+ let(:user_params) do
70
+ common_user_params.merge(name: 'Bingo')
71
+ end
72
+
73
+ it "reports the user's name" do
74
+ wait_for_a_request_with_body(/
75
+ "context":{.*
76
+ "user":{
77
+ "id":"1",
78
+ "name":"Bingo",
79
+ "username":"qa-dept",
80
+ "email":"qa@example.com"}
81
+ /x)
82
+ end
83
+ end
84
+ end
85
+
86
+ context "when additional parameters present" do
87
+ before do
88
+ get '/crash', nil, 'HTTP_USER_AGENT' => 'Bot'
89
+ end
90
+
91
+ it "features url" do
92
+ wait_for_a_request_with_body(
93
+ %r("context":{.*"url":"http://example\.org/crash".*})
94
+ )
95
+ end
96
+
97
+ it "features hostname" do
98
+ wait_for_a_request_with_body(/"context":{.*"hostname":".+".*}/)
99
+ end
100
+
101
+ it "features userAgent" do
102
+ wait_for_a_request_with_body(/"context":{.*"userAgent":"Bot".*}/)
103
+ end
104
+ end
105
+ end
106
+ end
@@ -0,0 +1,15 @@
1
+ require 'spec_helper'
2
+ require 'integration/shared_examples/rack_examples'
3
+
4
+ RSpec.describe "Sinatra integration specs" do
5
+ let(:app) { DummyApp }
6
+
7
+ include_examples 'rack examples'
8
+
9
+ describe "context payload" do
10
+ it "includes version" do
11
+ get '/crash'
12
+ wait_for_a_request_with_body(/"context":{.*"version":"1.2.3 Sinatra/)
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,127 @@
1
+ # Gems from the gemspec.
2
+ require 'webmock'
3
+ require 'webmock/rspec'
4
+ require 'rspec/wait'
5
+ require 'pry'
6
+ require 'rack'
7
+ require 'rack/test'
8
+ require 'rake'
9
+
10
+ if Gem::Version.new(RUBY_VERSION) >= Gem::Version.new('2.0')
11
+ require 'sidekiq'
12
+ require 'sidekiq/cli'
13
+ end
14
+
15
+ require 'airbrake'
16
+ require 'airbrake/rake/tasks'
17
+
18
+ # Load integration tests only when they're run through appraisals.
19
+ if ENV['APPRAISAL_INITIALIZED']
20
+ # Gems from appraisals that every application uses.
21
+ require 'warden'
22
+
23
+ # Load a Rails app or skip.
24
+ begin
25
+ ENV['RAILS_ENV'] = 'test'
26
+
27
+ if RUBY_ENGINE == 'jruby'
28
+ require 'activerecord-jdbcsqlite3-adapter'
29
+ else
30
+ require 'sqlite3'
31
+ end
32
+
33
+ require 'rails'
34
+
35
+ rails_vsn = Gem::Version.new(Rails.version)
36
+
37
+ if rails_vsn <= Gem::Version.new('4.2')
38
+ ENV['DATABASE_URL'] = 'sqlite3:///:memory:'
39
+ else
40
+ ENV['DATABASE_URL'] = 'sqlite3::memory:'
41
+ end
42
+
43
+ require 'action_controller'
44
+ require 'action_view'
45
+ require 'action_view/testing/resolvers'
46
+ require 'active_record/railtie'
47
+ if rails_vsn >= Gem::Version.new('4.2')
48
+ require 'active_job'
49
+
50
+ # Silence logger.
51
+ ActiveJob::Base.logger.level = 99
52
+ end
53
+
54
+ require 'resque'
55
+ require 'resque_spec'
56
+ require 'airbrake/resque/failure'
57
+ Resque::Failure.backend = Resque::Failure::Airbrake
58
+
59
+ require 'delayed_job'
60
+ require 'delayed_job_active_record'
61
+ require 'airbrake/delayed_job/plugin'
62
+ Delayed::Worker.delay_jobs = false
63
+
64
+ require 'airbrake/rails/railtie'
65
+
66
+ load 'apps/rails/dummy_task.rake'
67
+ require 'apps/rails/dummy_app'
68
+ rescue LoadError
69
+ puts '** Skipped Rails specs'
70
+ end
71
+
72
+ # Load a Sinatra app or skip.
73
+ begin
74
+ # Resque depends on Sinatra, so when we launch Rails specs, we also
75
+ # accidentally load Sinatra.
76
+ raise LoadError if defined?(Resque)
77
+
78
+ require 'sinatra'
79
+ require 'apps/sinatra/dummy_app'
80
+ rescue LoadError
81
+ puts '** Skipped Sinatra specs'
82
+ end
83
+
84
+ # Load a Rack app or skip.
85
+ begin
86
+ require 'apps/rack/dummy_app'
87
+ rescue LoadError
88
+ puts '** Skipped Rack specs'
89
+ end
90
+ end
91
+
92
+ RSpec.configure do |c|
93
+ c.order = 'random'
94
+ c.color = true
95
+ c.disable_monkey_patching!
96
+ c.wait_timeout = 3
97
+
98
+ c.include Rack::Test::Methods
99
+ end
100
+
101
+ Airbrake.configure do |c|
102
+ c.project_id = 113743
103
+ c.project_key = 'fd04e13d806a90f96614ad8e529b2822'
104
+ c.logger = Logger.new('/dev/null')
105
+ c.app_version = '1.2.3'
106
+ c.workers = 5
107
+ end
108
+
109
+ # Make sure tests that use async requests fail.
110
+ Thread.abort_on_exception = true
111
+
112
+ AirbrakeTestError = Class.new(StandardError)
113
+
114
+ # Print header with versions information. This simplifies debugging of build
115
+ # failures on CircleCI.
116
+ versions = <<EOS
117
+ #{'#' * 80}
118
+ # RUBY_VERSION: #{RUBY_VERSION}
119
+ # RUBY_ENGINE: #{RUBY_ENGINE}
120
+ EOS
121
+ versions << "# JRUBY_VERSION #{JRUBY_VERSION}\n" if defined?(JRUBY_VERSION)
122
+ versions << "# Rails version: #{Rails.version}\n" if defined?(Rails)
123
+ versions << "# Sinatra version: #{Sinatra::VERSION}\n" if defined?(Sinatra)
124
+ versions << "# Rack release: #{Rack.release}\n"
125
+ versions << '#' * 80
126
+
127
+ puts versions
@@ -0,0 +1,80 @@
1
+ require 'spec_helper'
2
+
3
+ RSpec.describe Airbrake::Rack::Middleware do
4
+ let(:app) do
5
+ proc { |env| [200, env, 'Bingo bango content'] }
6
+ end
7
+
8
+ let(:faulty_app) do
9
+ proc { raise AirbrakeTestError }
10
+ end
11
+
12
+ let(:endpoint) do
13
+ 'https://airbrake.io/api/v3/projects/113743/notices?key=fd04e13d806a90f96614ad8e529b2822'
14
+ end
15
+
16
+ let(:middleware) { described_class.new(app) }
17
+
18
+ def env_for(url, opts = {})
19
+ Rack::MockRequest.env_for(url, opts)
20
+ end
21
+
22
+ def wait_for_a_request_with_body(body)
23
+ wait_for(a_request(:post, endpoint).with(body: body)).to have_been_made.once
24
+ end
25
+
26
+ before do
27
+ stub_request(:post, endpoint).to_return(status: 201, body: '{}')
28
+ end
29
+
30
+ describe "#call" do
31
+ context "when app raises an exception" do
32
+ it "rescues the exception, notifies Airbrake & re-raises it" do
33
+ expect { described_class.new(faulty_app).call(env_for('/')) }.
34
+ to raise_error(AirbrakeTestError)
35
+
36
+ wait_for_a_request_with_body(/"errors":\[{"type":"AirbrakeTestError"/)
37
+ end
38
+
39
+ it "sends framework version and name" do
40
+ expect { described_class.new(faulty_app).call(env_for('/bingo/bango')) }.
41
+ to raise_error(AirbrakeTestError)
42
+
43
+ wait_for_a_request_with_body(
44
+ %r("context":{.*"version":"1.2.3 (Rails|Sinatra|Rack\.version)/.+".+})
45
+ )
46
+ end
47
+ end
48
+
49
+ context "when app doesn't raise" do
50
+ context "and previous middleware stored an exception in env" do
51
+ shared_examples 'stored exception' do |type|
52
+ it "notifies on #{type}, but doesn't raise" do
53
+ env = env_for('/').merge(type => AirbrakeTestError.new)
54
+ described_class.new(app).call(env)
55
+
56
+ wait_for_a_request_with_body(/"errors":\[{"type":"AirbrakeTestError"/)
57
+ end
58
+ end
59
+
60
+ ['action_dispatch.exception', 'sinatra.error'].each do |type|
61
+ include_examples 'stored exception', type
62
+ end
63
+ end
64
+
65
+ it "doesn't notify Airbrake" do
66
+ described_class.new(app).call(env_for('/'))
67
+ sleep 1
68
+ expect(a_request(:post, endpoint)).not_to have_been_made
69
+ end
70
+ end
71
+
72
+ it "returns a response" do
73
+ response = described_class.new(app).call(env_for('/'))
74
+
75
+ expect(response[0]).to eq(200)
76
+ expect(response[1]).to be_a(Hash)
77
+ expect(response[2]).to eq('Bingo bango content')
78
+ end
79
+ end
80
+ end
@@ -0,0 +1,35 @@
1
+ require 'spec_helper'
2
+
3
+ RSpec.describe Airbrake::Rack::NoticeBuilder do
4
+ describe "#build_notice" do
5
+ it "doesn't overwrite session with nil" do
6
+ notice_builder = described_class.new('rack.session' => nil)
7
+ notice = notice_builder.build_notice(AirbrakeTestError.new)
8
+
9
+ expect(notice[:session]).to eq({})
10
+ end
11
+
12
+ it "sets session if it is present" do
13
+ session = { a: 1, b: 2 }
14
+ notice_builder = described_class.new('rack.session' => session)
15
+ notice = notice_builder.build_notice(AirbrakeTestError.new)
16
+
17
+ expect(notice[:session]).to eq(session)
18
+ end
19
+
20
+ it "doesn't overwrite params with nil" do
21
+ notice_builder = described_class.new('action_dispatch.request.parameters' => nil)
22
+ notice = notice_builder.build_notice(AirbrakeTestError.new)
23
+
24
+ expect(notice[:session]).to eq({})
25
+ end
26
+
27
+ it "sets params if they're present" do
28
+ params = { a: 1, b: 2 }
29
+ notice_builder = described_class.new('action_dispatch.request.parameters' => params)
30
+ notice = notice_builder.build_notice(AirbrakeTestError.new)
31
+
32
+ expect(notice[:params]).to eq(params)
33
+ end
34
+ end
35
+ end