airbrake 9.0.2 → 9.1.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -262,7 +262,7 @@ RSpec.describe "Rails integration specs" do
262
262
  hash_including(
263
263
  route: '/crash(.:format)',
264
264
  method: 'GET',
265
- func: 'tap',
265
+ func: 'call',
266
266
  file: 'lib/airbrake/rails/active_record_subscriber.rb',
267
267
  line: anything
268
268
  )
@@ -305,5 +305,34 @@ RSpec.describe "Rails integration specs" do
305
305
 
306
306
  get '/breakdown'
307
307
  end
308
+
309
+ context "when response format is */*" do
310
+ it "normalizes it to :html" do
311
+ expect(Airbrake).to receive(:notify_performance_breakdown)
312
+ .with(hash_including(response_type: :html))
313
+ get '/breakdown', {}, 'HTTP_ACCEPT' => '*/*'
314
+ end
315
+ end
316
+
317
+ context "when db_runtime is nil" do
318
+ it "omits the db group" do
319
+ expect(Airbrake).to receive(:notify_performance_breakdown)
320
+ .with(hash_including(groups: { view: be > 0 }))
321
+ get '/breakdown_view_only'
322
+ end
323
+ end
324
+
325
+ context "when an action performs a HTTP request" do
326
+ let!(:example_request) do
327
+ stub_request(:get, 'http://example.com').to_return(body: '')
328
+ end
329
+
330
+ it "includes the http breakdown" do
331
+ expect(Airbrake).to receive(:notify_performance_breakdown)
332
+ .with(hash_including(groups: { view: be > 0, http: be > 0 }))
333
+ get '/breakdown_http'
334
+ expect(example_request).to have_been_made
335
+ end
336
+ end
308
337
  end
309
338
  end
@@ -0,0 +1,43 @@
1
+ require 'airbrake/rails/action_controller_notify_subscriber'
2
+
3
+ RSpec.describe Airbrake::Rails::ActionControllerNotifySubscriber do
4
+ after { Airbrake::Rack::RequestStore.clear }
5
+
6
+ describe "#call" do
7
+ let(:event) { double(Airbrake::Rails::Event) }
8
+
9
+ before do
10
+ allow(Airbrake::Rails::Event).to receive(:new).and_return(event)
11
+ end
12
+
13
+ context "when there are no routes in the request store" do
14
+ it "doesn't notify requests" do
15
+ expect(Airbrake).not_to receive(:notify_request)
16
+ subject.call([])
17
+ end
18
+ end
19
+
20
+ context "when there's a route in the request store" do
21
+ before do
22
+ Airbrake::Rack::RequestStore[:routes] = {
23
+ '/test-route' => { method: 'GET', response_type: :html }
24
+ }
25
+
26
+ expect(event).to receive(:method).and_return('GET')
27
+ expect(event).to receive(:status_code).and_return(200)
28
+ expect(event).to receive(:time).and_return(Time.now)
29
+ end
30
+
31
+ it "sends request info to Airbrake" do
32
+ expect(Airbrake).to receive(:notify_request).with(
33
+ hash_including(
34
+ method: 'GET',
35
+ route: '/test-route',
36
+ status_code: 200
37
+ )
38
+ )
39
+ subject.call([])
40
+ end
41
+ end
42
+ end
43
+ end
@@ -1,6 +1,13 @@
1
1
  require 'airbrake/rails/action_controller_performance_breakdown_subscriber'
2
2
 
3
3
  RSpec.describe Airbrake::Rails::ActionControllerPerformanceBreakdownSubscriber do
4
+ let(:app) { double(Airbrake::Rails::App) }
5
+ let(:event) { double(Airbrake::Rails::Event) }
6
+
7
+ before do
8
+ allow(Airbrake::Rails::Event).to receive(:new).and_return(event)
9
+ end
10
+
4
11
  after { Airbrake::Rack::RequestStore.clear }
5
12
 
6
13
  context "when routes are not set in the request store" do
@@ -13,7 +20,7 @@ RSpec.describe Airbrake::Rails::ActionControllerPerformanceBreakdownSubscriber d
13
20
  end
14
21
 
15
22
  context "when there are no routes in the request store" do
16
- before { Airbrake::Rack::RequestStore[:routes] = [] }
23
+ before { Airbrake::Rack::RequestStore[:routes] = {} }
17
24
 
18
25
  it "doesn't send performance breakdown info" do
19
26
  expect(Airbrake).not_to receive(:notify_performance_breakdown)
@@ -22,121 +29,35 @@ RSpec.describe Airbrake::Rails::ActionControllerPerformanceBreakdownSubscriber d
22
29
  end
23
30
 
24
31
  context "when there's a route in the request store" do
25
- let(:event) do
26
- OpenStruct.new(
27
- payload: {
28
- format: :html,
29
- view_runtime: 0.5,
30
- db_runtime: 0.5
31
- }
32
- )
33
- end
34
-
35
32
  before do
36
- Airbrake::Rack::RequestStore[:routes] = [['/test-route', 'GET']]
37
-
38
- event_dbl = double
39
- expect(event_dbl).to receive(:new).and_return(event)
40
- stub_const('ActiveSupport::Notifications::Event', event_dbl)
41
- end
42
-
43
- it "sends performance info to Airbrake" do
44
- expect(Airbrake).to receive(:notify_performance_breakdown).with(
45
- hash_including(
46
- route: '/test-route',
47
- method: 'GET',
48
- response_type: :html,
49
- groups: { db: 0.5, view: 0.5 }
50
- )
51
- )
52
- subject.call([])
53
- end
54
-
55
- context "and when view_runtime is nil" do
56
- before { event.payload[:view_runtime] = nil }
57
-
58
- it "omits view_runtime" do
59
- expect(Airbrake).to receive(:notify_performance_breakdown).with(
60
- hash_including(
61
- route: '/test-route',
62
- method: 'GET',
63
- response_type: :html,
64
- groups: { db: 0.5 }
65
- )
66
- )
67
- subject.call([])
68
- end
69
- end
70
-
71
- context "and when db_runtime is nil" do
72
- before { event.payload[:db_runtime] = nil }
73
-
74
- it "omits db_runtime" do
75
- expect(Airbrake).to receive(:notify_performance_breakdown).with(
76
- hash_including(
77
- route: '/test-route',
78
- method: 'GET',
79
- response_type: :html,
80
- groups: { view: 0.5 }
81
- )
82
- )
83
- subject.call([])
84
- end
33
+ expect(event).to receive(:groups).and_return(db: 0.5, view: 0.5)
34
+ expect(event).to receive(:method).and_return('GET')
35
+ expect(event).to receive(:response_type).and_return(:html)
36
+ expect(event).to receive(:time).and_return(Time.new)
85
37
  end
86
38
 
87
- context "when db_runtime is zero" do
88
- before { event.payload[:db_runtime] = 0 }
89
-
90
- it "omits db_runtime" do
91
- expect(Airbrake).to receive(:notify_performance_breakdown).with(
92
- hash_including(
93
- route: '/test-route',
39
+ context "when request store routes have extra groups" do
40
+ before do
41
+ Airbrake::Rack::RequestStore[:routes] = {
42
+ '/test-route' => {
94
43
  method: 'GET',
95
44
  response_type: :html,
96
- groups: { view: 0.5 }
97
- )
98
- )
99
- subject.call([])
45
+ groups: { http: 0.5 }
46
+ }
47
+ }
100
48
  end
101
- end
102
49
 
103
- context "when view_runtime is zero" do
104
- before { event.payload[:view_runtime] = 0 }
105
-
106
- it "omits view_runtime" do
50
+ it "sends performance info to Airbrake with extra groups" do
107
51
  expect(Airbrake).to receive(:notify_performance_breakdown).with(
108
52
  hash_including(
109
53
  route: '/test-route',
110
54
  method: 'GET',
111
55
  response_type: :html,
112
- groups: { db: 0.5 }
56
+ groups: { db: 0.5, view: 0.5, http: 0.5 }
113
57
  )
114
58
  )
115
59
  subject.call([])
116
60
  end
117
61
  end
118
-
119
- context "when db_runtime and view_runtime are both zero" do
120
- before do
121
- event.payload[:db_runtime] = 0
122
- event.payload[:view_runtime] = 0
123
- end
124
-
125
- it "doesn't notify Airbrake" do
126
- expect(Airbrake).not_to receive(:notify_performance_breakdown)
127
- subject.call([])
128
- end
129
- end
130
-
131
- context "when response format is */*" do
132
- before { event.payload[:format] = "*/*" }
133
-
134
- it "normalizes it to :html" do
135
- expect(Airbrake).to receive(:notify_performance_breakdown).with(
136
- hash_including(response_type: :html)
137
- )
138
- subject.call([])
139
- end
140
- end
141
62
  end
142
63
  end
@@ -0,0 +1,84 @@
1
+ require 'ostruct'
2
+ require 'airbrake/rails/action_controller_route_subscriber'
3
+
4
+ RSpec.describe Airbrake::Rails::ActionControllerRouteSubscriber do
5
+ describe "#call" do
6
+ let(:app) { double(Airbrake::Rails::App) }
7
+ let(:event) { double(Airbrake::Rails::Event) }
8
+
9
+ let(:event_params) do
10
+ [
11
+ 'start_processing.action_controller',
12
+ Time.new,
13
+ Time.new,
14
+ '123',
15
+ { method: 'HEAD', path: '/crash' }
16
+ ]
17
+ end
18
+
19
+ before do
20
+ allow(Airbrake::Rails::App).to receive(:new).and_return(app)
21
+ allow(Airbrake::Rails::Event).to receive(:new).and_return(event)
22
+ end
23
+
24
+ context "when request store has the :routes key" do
25
+ let(:routes) do
26
+ [Airbrake::Rails::App::Route.new('/crash', 'DummyController', 'crash')]
27
+ end
28
+
29
+ before do
30
+ allow(app).to receive(:routes).and_return(routes)
31
+ allow(event).to receive(:params).and_return(params)
32
+ allow(event).to receive(:method).and_return('HEAD')
33
+ allow(event).to receive(:response_type).and_return(:html)
34
+
35
+ Airbrake::Rack::RequestStore[:routes] = {}
36
+ end
37
+
38
+ after { Airbrake::Rack::RequestStore.clear }
39
+
40
+ context "and when the route can be found" do
41
+ let(:params) do
42
+ OpenStruct.new(controller: 'DummyController', action: 'crash')
43
+ end
44
+
45
+ it "stores a route in the request store under :routes" do
46
+ subject.call(event_params)
47
+ expect(Airbrake::Rack::RequestStore[:routes])
48
+ .to eq('/crash' => { method: 'HEAD', response_type: :html, groups: {} })
49
+ end
50
+ end
51
+
52
+ context "and when the event controller can't be found" do
53
+ let(:params) do
54
+ OpenStruct.new(controller: 'BananaController', action: 'crash')
55
+ end
56
+
57
+ it "doesn't store any routes in the request store under :routes" do
58
+ subject.call(event_params)
59
+ expect(Airbrake::Rack::RequestStore[:routes]).to be_empty
60
+ end
61
+ end
62
+
63
+ context "and when the event action can't be found" do
64
+ let(:params) do
65
+ OpenStruct.new(controller: 'DummyController', action: 'banana')
66
+ end
67
+
68
+ it "doesn't store any routes in the request store under :routes" do
69
+ subject.call(event_params)
70
+ expect(Airbrake::Rack::RequestStore[:routes]).to be_empty
71
+ end
72
+ end
73
+ end
74
+
75
+ context "when request store doesn't have the :routes key" do
76
+ before { Airbrake::Rack::RequestStore.clear }
77
+
78
+ it "doesn't store any routes in the request store" do
79
+ subject.call(event_params)
80
+ expect(Airbrake::Rack::RequestStore[:routes]).to be_nil
81
+ end
82
+ end
83
+ end
84
+ end
@@ -0,0 +1,70 @@
1
+ require 'airbrake/rails/active_record_subscriber'
2
+
3
+ RSpec.describe Airbrake::Rails::ActiveRecordSubscriber do
4
+ after { Airbrake::Rack::RequestStore.clear }
5
+
6
+ describe "#call" do
7
+ let(:event) { double(Airbrake::Rails::Event) }
8
+
9
+ before do
10
+ allow(Airbrake::Rails::Event).to receive(:new).and_return(event)
11
+ end
12
+
13
+ context "when there are no routes in the request store" do
14
+ it "doesn't notify requests" do
15
+ expect(Airbrake).not_to receive(:notify_query)
16
+ subject.call([])
17
+ end
18
+ end
19
+
20
+ context "when there's a route in the request store" do
21
+ before do
22
+ Airbrake::Rack::RequestStore[:routes] = {
23
+ '/test-route' => { method: 'GET', response_type: :html }
24
+ }
25
+
26
+ allow(event).to receive(:sql).and_return('SELECT * FROM bananas')
27
+ allow(event).to receive(:time).and_return(Time.now)
28
+ allow(event).to receive(:end).and_return(Time.now)
29
+ allow(Airbrake::Rails::BacktraceCleaner).to receive(:clean).and_return(
30
+ "/lib/pry/cli.rb:117:in `start'"
31
+ )
32
+ end
33
+
34
+ it "sends query info to Airbrake" do
35
+ expect(Airbrake).to receive(:notify_query).with(
36
+ hash_including(
37
+ method: 'GET',
38
+ route: '/test-route',
39
+ query: 'SELECT * FROM bananas',
40
+ func: 'start',
41
+ line: 117,
42
+ file: '/lib/pry/cli.rb'
43
+ )
44
+ )
45
+ subject.call([])
46
+ end
47
+
48
+ context "and when backtrace couldn't be parsed" do
49
+ before do
50
+ allow(Airbrake::Rails::BacktraceCleaner)
51
+ .to receive(:clean).and_return([])
52
+ end
53
+
54
+ it "sends empty func/file/line to Airbrake" do
55
+ expect(Airbrake).to receive(:notify_query).with(
56
+ hash_including(
57
+ method: 'GET',
58
+ route: '/test-route',
59
+ query: 'SELECT * FROM bananas',
60
+ func: nil,
61
+ line: nil,
62
+ file: nil
63
+ )
64
+ )
65
+ subject.call([])
66
+ end
67
+ end
68
+ end
69
+ end
70
+ end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: airbrake
3
3
  version: !ruby/object:Gem::Version
4
- version: 9.0.2
4
+ version: 9.1.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Airbrake Technologies, Inc.
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2019-04-08 00:00:00.000000000 Z
11
+ date: 2019-04-17 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: airbrake-ruby
@@ -283,6 +283,10 @@ files:
283
283
  - lib/airbrake/rails/active_job.rb
284
284
  - lib/airbrake/rails/active_record.rb
285
285
  - lib/airbrake/rails/active_record_subscriber.rb
286
+ - lib/airbrake/rails/app.rb
287
+ - lib/airbrake/rails/backtrace_cleaner.rb
288
+ - lib/airbrake/rails/event.rb
289
+ - lib/airbrake/rails/net_http.rb
286
290
  - lib/airbrake/rake.rb
287
291
  - lib/airbrake/rake/tasks.rb
288
292
  - lib/airbrake/resque.rb
@@ -319,7 +323,10 @@ files:
319
323
  - spec/unit/rack/user_filter_spec.rb
320
324
  - spec/unit/rack/user_spec.rb
321
325
  - spec/unit/rails/action_cable/notify_callback_spec.rb
326
+ - spec/unit/rails/action_controller_notify_subscriber_spec.rb
322
327
  - spec/unit/rails/action_controller_performance_breakdown_subscriber_spec.rb
328
+ - spec/unit/rails/action_controller_route_subscriber_spec.rb
329
+ - spec/unit/rails/active_record_subscriber_spec.rb
323
330
  - spec/unit/rake/tasks_spec.rb
324
331
  - spec/unit/shoryuken_spec.rb
325
332
  - spec/unit/sidekiq/retryable_jobs_filter_spec.rb
@@ -369,7 +376,10 @@ test_files:
369
376
  - spec/unit/rack/user_spec.rb
370
377
  - spec/unit/rack/route_filter_spec.rb
371
378
  - spec/unit/rails/action_controller_performance_breakdown_subscriber_spec.rb
379
+ - spec/unit/rails/active_record_subscriber_spec.rb
372
380
  - spec/unit/rails/action_cable/notify_callback_spec.rb
381
+ - spec/unit/rails/action_controller_notify_subscriber_spec.rb
382
+ - spec/unit/rails/action_controller_route_subscriber_spec.rb
373
383
  - spec/integration/sinatra/sinatra_spec.rb
374
384
  - spec/integration/rack/rack_spec.rb
375
385
  - spec/integration/shared_examples/rack_examples.rb