airbrake 9.2.1 → 9.2.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (43) hide show
  1. checksums.yaml +4 -4
  2. data/lib/airbrake/rack/middleware.rb +21 -13
  3. data/lib/airbrake/rails/action_controller_performance_breakdown_subscriber.rb +20 -2
  4. data/lib/airbrake/version.rb +1 -1
  5. metadata +5 -81
  6. data/spec/apps/rack/dummy_app.rb +0 -17
  7. data/spec/apps/rails/dummy_app.rb +0 -258
  8. data/spec/apps/rails/dummy_task.rake +0 -15
  9. data/spec/apps/rails/logs/32.log +0 -34094
  10. data/spec/apps/rails/logs/42.log +0 -1488
  11. data/spec/apps/rails/logs/52.log +0 -6321
  12. data/spec/apps/sinatra/sinatra_test_app.rb +0 -12
  13. data/spec/integration/rack/rack_spec.rb +0 -19
  14. data/spec/integration/rails/rails_spec.rb +0 -430
  15. data/spec/integration/rails/rake_spec.rb +0 -97
  16. data/spec/integration/shared_examples/rack_examples.rb +0 -110
  17. data/spec/integration/sinatra/sinatra_spec.rb +0 -30
  18. data/spec/spec_helper.rb +0 -105
  19. data/spec/support/matchers/a_notice_with.rb +0 -29
  20. data/spec/unit/logger_spec.rb +0 -125
  21. data/spec/unit/rack/context_filter_spec.rb +0 -90
  22. data/spec/unit/rack/http_headers_filter_spec.rb +0 -44
  23. data/spec/unit/rack/http_params_filter_spec.rb +0 -58
  24. data/spec/unit/rack/instrumentable_spec.rb +0 -105
  25. data/spec/unit/rack/middleware_spec.rb +0 -98
  26. data/spec/unit/rack/rack_spec.rb +0 -46
  27. data/spec/unit/rack/request_body_filter_spec.rb +0 -44
  28. data/spec/unit/rack/request_store_spec.rb +0 -36
  29. data/spec/unit/rack/route_filter_spec.rb +0 -52
  30. data/spec/unit/rack/session_filter_spec.rb +0 -44
  31. data/spec/unit/rack/user_filter_spec.rb +0 -30
  32. data/spec/unit/rack/user_spec.rb +0 -218
  33. data/spec/unit/rails/action_cable/notify_callback_spec.rb +0 -26
  34. data/spec/unit/rails/action_controller_notify_subscriber_spec.rb +0 -43
  35. data/spec/unit/rails/action_controller_performance_breakdown_subscriber_spec.rb +0 -63
  36. data/spec/unit/rails/action_controller_route_subscriber_spec.rb +0 -84
  37. data/spec/unit/rails/active_record_subscriber_spec.rb +0 -70
  38. data/spec/unit/rails/excon_spec.rb +0 -46
  39. data/spec/unit/rake/tasks_spec.rb +0 -70
  40. data/spec/unit/shoryuken_spec.rb +0 -55
  41. data/spec/unit/sidekiq/retryable_jobs_filter_spec.rb +0 -36
  42. data/spec/unit/sidekiq_spec.rb +0 -33
  43. data/spec/unit/sneakers_spec.rb +0 -83
@@ -1,90 +0,0 @@
1
- RSpec.describe Airbrake::Rack::ContextFilter do
2
- def env_for(url, opts = {})
3
- Rack::MockRequest.env_for(url, opts)
4
- end
5
-
6
- let(:notice) do
7
- Airbrake.build_notice('oops').tap do |notice|
8
- notice.stash[:rack_request] = Rack::Request.new(env_for(uri, opts))
9
- end
10
- end
11
-
12
- let(:uri) { '/' }
13
- let(:opts) { {} }
14
-
15
- it "adds framework version to the context" do
16
- subject.call(notice)
17
- expect(notice[:context][:versions]).to include(
18
- 'rack_version' => a_string_matching(/\d.\d/),
19
- 'rack_release' => a_string_matching(/\d.\d\.\d/)
20
- )
21
- end
22
-
23
- context "when URL is present" do
24
- let(:uri) { '/bingo' }
25
- let(:opts) { {} }
26
-
27
- it "adds URL to the context" do
28
- subject.call(notice)
29
- expect(notice[:context][:url]).to eq('http://example.org/bingo')
30
- end
31
- end
32
-
33
- context "when User-Agent is present" do
34
- let(:uri) { '/' }
35
- let(:opts) do
36
- { 'HTTP_USER_AGENT' => 'Bingo Agent' }
37
- end
38
-
39
- it "adds User-Agent to the context" do
40
- subject.call(notice)
41
- expect(notice[:context][:userAgent]).to eq('Bingo Agent')
42
- end
43
- end
44
-
45
- context "when visitor address is present" do
46
- let(:opts) do
47
- { 'REMOTE_ADDR' => '1.2.3.4' }
48
- end
49
-
50
- it "adds userAddr to the context" do
51
- subject.call(notice)
52
- expect(notice[:context][:userAddr]).to eq('1.2.3.4')
53
- end
54
- end
55
-
56
- context "when visitor is behind a proxy or load balancer" do
57
- let(:opts) do
58
- { 'HTTP_X_FORWARDED_FOR' => '8.8.8.8, 9.9.9.9' }
59
- end
60
-
61
- it "adds userAddr to the context" do
62
- subject.call(notice)
63
- expect(notice[:context][:userAddr]).to eq('9.9.9.9')
64
- end
65
- end
66
-
67
- context "when controller is present" do
68
- let(:controller) do
69
- double.tap do |ctrl|
70
- allow(ctrl).to receive(:controller_name).and_return('BingoController')
71
- allow(ctrl).to receive(:action_name).and_return('bango_name')
72
- end
73
- end
74
-
75
- let(:uri) { '/' }
76
- let(:opts) do
77
- { 'action_controller.instance' => controller }
78
- end
79
-
80
- it "adds controller name as component" do
81
- subject.call(notice)
82
- expect(notice[:context][:component]).to eq('BingoController')
83
- end
84
-
85
- it "adds action name as action" do
86
- subject.call(notice)
87
- expect(notice[:context][:action]).to eq('bango_name')
88
- end
89
- end
90
- end
@@ -1,44 +0,0 @@
1
- RSpec.describe Airbrake::Rack::HttpHeadersFilter do
2
- def env_for(url, opts = {})
3
- Rack::MockRequest.env_for(url, opts)
4
- end
5
-
6
- let(:notice) do
7
- Airbrake.build_notice('oops').tap do |notice|
8
- notice.stash[:rack_request] = Rack::Request.new(env_for(uri, opts))
9
- end
10
- end
11
-
12
- let(:headers) do
13
- {
14
- 'HTTP_HOST' => 'example.com',
15
- 'CONTENT_TYPE' => 'text/html',
16
- 'CONTENT_LENGTH' => 100500
17
- }
18
- end
19
-
20
- let(:uri) { '/' }
21
- let(:opts) { headers.dup }
22
-
23
- it "preserves data that already has been added to the context" do
24
- notice[:context]['SOME_KEY'] = 'SOME_VALUE'
25
- subject.call(notice)
26
- expect(notice[:context]['SOME_KEY']).to eq('SOME_VALUE')
27
- end
28
-
29
- context "when CONTENT_TYPE, CONTENT_LENGTH and HTTP_* headers are present" do
30
- it "adds them to the context hash" do
31
- subject.call(notice)
32
- expect(notice[:context][:headers]).to eq(headers)
33
- end
34
- end
35
-
36
- context "when unexpected headers are present" do
37
- let(:opts) { headers.dup.merge('X-SOME-HEADER' => 'value') }
38
-
39
- it "adds them to the context hash" do
40
- subject.call(notice)
41
- expect(notice[:context][:headers]).to eq(headers)
42
- end
43
- end
44
- end
@@ -1,58 +0,0 @@
1
- RSpec.describe Airbrake::Rack::HttpParamsFilter do
2
- def env_for(url, opts = {})
3
- Rack::MockRequest.env_for(url, opts)
4
- end
5
-
6
- let(:notice) do
7
- Airbrake.build_notice('oops').tap do |notice|
8
- notice.stash[:rack_request] = Rack::Request.new(env_for(uri, opts))
9
- end
10
- end
11
-
12
- context "when rack params is nil" do
13
- let(:uri) { '/' }
14
- let(:opts) { {} }
15
-
16
- it "doesn't overwrite the params key with nil" do
17
- subject.call(notice)
18
- expect(notice[:params]).to eq({})
19
- end
20
- end
21
-
22
- context "when form params are present" do
23
- let(:params) do
24
- { a: 1, b: 2 }
25
- end
26
-
27
- let(:input) { StringIO.new }
28
- let(:uri) { '/' }
29
- let(:opts) do
30
- {
31
- 'rack.request.form_hash' => params,
32
- 'rack.request.form_input' => input,
33
- 'rack.input' => input
34
- }
35
- end
36
-
37
- it "sets the params hash" do
38
- subject.call(notice)
39
- expect(notice[:params]).to eq(params)
40
- end
41
-
42
- it "merges given params with existing params" do
43
- notice[:params] = { bingo: :bango }
44
- subject.call(notice)
45
- expect(notice[:params]).to eq(bingo: :bango, a: 1, b: 2)
46
- end
47
- end
48
-
49
- context "when query string params are present" do
50
- let(:uri) { '/?bingo=bango&bongo=bish' }
51
- let(:opts) { {} }
52
-
53
- it "sets the params hash" do
54
- subject.call(notice)
55
- expect(notice[:params]).to eq('bingo' => 'bango', 'bongo' => 'bish')
56
- end
57
- end
58
- end
@@ -1,105 +0,0 @@
1
- RSpec.describe Airbrake::Rack::Instrumentable do
2
- after { Airbrake::Rack::RequestStore.clear }
3
-
4
- describe ".airbrake_capture_timing" do
5
- let(:routes) { Airbrake::Rack::RequestStore[:routes] }
6
-
7
- let(:klass) do
8
- Class.new do
9
- extend Airbrake::Rack::Instrumentable
10
-
11
- def method; end
12
- airbrake_capture_timing :method
13
-
14
- def method_with_arg(a); end
15
- airbrake_capture_timing :method_with_arg
16
-
17
- def method_with_args(a, b); end
18
- airbrake_capture_timing :method_with_args
19
-
20
- def method_with_vla(*args); end
21
- airbrake_capture_timing :method_with_vla
22
-
23
- def method_with_args_and_vla(*args); end
24
- airbrake_capture_timing :method_with_args_and_vla
25
-
26
- def method_with_kwargs(foo:, bar:); end
27
- airbrake_capture_timing :method_with_kwargs
28
- end
29
- end
30
-
31
- context "when request store doesn't have any routes" do
32
- before { Airbrake::Rack::RequestStore.clear }
33
-
34
- it "doesn't store timing of the tracked method" do
35
- klass.new.method
36
- expect(Airbrake::Rack::RequestStore.store).to be_empty
37
- end
38
- end
39
-
40
- context "when request store has a route" do
41
- let(:groups) { routes['/about'][:groups] }
42
-
43
- before do
44
- Airbrake::Rack::RequestStore[:routes] = {
45
- '/about' => {
46
- method: 'GET',
47
- response_type: :html,
48
- groups: {}
49
- }
50
- }
51
- end
52
-
53
- it "attaches timing for a method without an argument" do
54
- klass.new.method
55
- expect(groups).to match('method' => be > 0)
56
- end
57
-
58
- it "attaches timing for a method with an argument" do
59
- klass.new.method_with_arg(1)
60
- expect(groups).to match('method_with_arg' => be > 0)
61
- end
62
-
63
- it "attaches timing for a variable-length argument method" do
64
- klass.new.method_with_vla(1, 2, 3)
65
- expect(groups).to match('method_with_vla' => be > 0)
66
- end
67
-
68
- it "attaches timing for a method with args and a variable-length array" do
69
- klass.new.method_with_args_and_vla(1, 2, 3)
70
- expect(groups).to match('method_with_args_and_vla' => be > 0)
71
- end
72
-
73
- it "attaches timing for a method with kwargs" do
74
- klass.new.method_with_kwargs(foo: 1, bar: 2)
75
- expect(groups).to match('method_with_kwargs' => be > 0)
76
- end
77
-
78
- it "attaches all timings for multiple methods to the request store" do
79
- klass.new.method
80
- klass.new.method_with_arg(1)
81
-
82
- expect(groups).to match(
83
- 'method' => be > 0,
84
- 'method_with_arg' => be > 0
85
- )
86
- end
87
-
88
- context "and when a custom label was provided" do
89
- let(:klass) do
90
- Class.new do
91
- extend Airbrake::Rack::Instrumentable
92
-
93
- def method; end
94
- airbrake_capture_timing :method, label: 'custom label'
95
- end
96
- end
97
-
98
- it "attaches timing under the provided label" do
99
- klass.new.method
100
- expect(groups).to match('custom label' => be > 0)
101
- end
102
- end
103
- end
104
- end
105
- end
@@ -1,98 +0,0 @@
1
- RSpec.describe Airbrake::Rack::Middleware do
2
- # The list of Rack filters that read Rack request information and append it to
3
- # notices.
4
- [
5
- Airbrake::Rack::ContextFilter,
6
- Airbrake::Rack::UserFilter,
7
- Airbrake::Rack::SessionFilter,
8
- Airbrake::Rack::HttpParamsFilter,
9
- Airbrake::Rack::HttpHeadersFilter,
10
- Airbrake::Rack::RouteFilter,
11
-
12
- # Optional filters (must be included by users):
13
- # Airbrake::Rack::RequestBodyFilter
14
- ].each do |filter|
15
- Airbrake.add_filter(filter.new)
16
- end
17
-
18
- let(:app) { proc { |env| [200, env, 'Bingo bango content'] } }
19
- let(:faulty_app) { proc { raise AirbrakeTestError } }
20
- let(:endpoint) { 'https://api.airbrake.io/api/v3/projects/113743/notices' }
21
- let(:middleware) { described_class.new(app) }
22
-
23
- def env_for(url, opts = {})
24
- Rack::MockRequest.env_for(url, opts)
25
- end
26
-
27
- def wait_for_a_request_with_body(body)
28
- wait_for(a_request(:post, endpoint).with(body: body)).to have_been_made.once
29
- end
30
-
31
- before do
32
- stub_request(:post, endpoint).to_return(status: 201, body: '{}')
33
- end
34
-
35
- describe "#call" do
36
- context "when app raises an exception" do
37
- it "rescues the exception, notifies Airbrake & re-raises it" do
38
- expect { described_class.new(faulty_app).call(env_for('/')) }
39
- .to raise_error(AirbrakeTestError)
40
-
41
- wait_for_a_request_with_body(/"errors":\[{"type":"AirbrakeTestError"/)
42
- end
43
-
44
- it "sends framework version and name" do
45
- expect { described_class.new(faulty_app).call(env_for('/bingo/bango')) }
46
- .to raise_error(AirbrakeTestError)
47
-
48
- wait_for_a_request_with_body(
49
- /"context":{.*"versions":{"(rails|sinatra|rack_version)"/
50
- )
51
- end
52
- end
53
-
54
- context "when app doesn't raise" do
55
- context "and previous middleware stored an exception in env" do
56
- shared_examples 'stored exception' do |type|
57
- it "notifies on #{type}, but doesn't raise" do
58
- env = env_for('/').merge(type => AirbrakeTestError.new)
59
- described_class.new(app).call(env)
60
-
61
- wait_for_a_request_with_body(/"errors":\[{"type":"AirbrakeTestError"/)
62
- end
63
- end
64
-
65
- ['rack.exception', 'action_dispatch.exception', 'sinatra.error'].each do |type|
66
- include_examples 'stored exception', type
67
- end
68
- end
69
-
70
- it "doesn't notify Airbrake" do
71
- described_class.new(app).call(env_for('/'))
72
- sleep 1
73
- expect(a_request(:post, endpoint)).not_to have_been_made
74
- end
75
- end
76
-
77
- it "returns a response" do
78
- response = described_class.new(app).call(env_for('/'))
79
-
80
- expect(response[0]).to eq(200)
81
- expect(response[1]).to be_a(Hash)
82
- expect(response[2]).to eq('Bingo bango content')
83
- end
84
- end
85
-
86
- context "when Airbrake is not configured" do
87
- it "returns nil" do
88
- allow(Airbrake).to receive(:build_notice).and_return(nil)
89
- allow(Airbrake).to receive(:notify)
90
-
91
- expect { described_class.new(faulty_app).call(env_for('/')) }
92
- .to raise_error(AirbrakeTestError)
93
-
94
- expect(Airbrake).to have_received(:build_notice)
95
- expect(Airbrake).not_to have_received(:notify)
96
- end
97
- end
98
- end
@@ -1,46 +0,0 @@
1
- RSpec.describe Airbrake::Rack do
2
- after { Airbrake::Rack::RequestStore.clear }
3
-
4
- describe ".timing" do
5
- let(:routes) { Airbrake::Rack::RequestStore[:routes] }
6
-
7
- context "when request store doesn't have any routes" do
8
- it "doesn't store timing" do
9
- described_class.capture_timing('operation') {}
10
- expect(Airbrake::Rack::RequestStore.store).to be_empty
11
- end
12
-
13
- it "returns the value of the block" do
14
- expect(described_class.capture_timing('operation') { 1 }).to eq(1)
15
- end
16
- end
17
-
18
- context "when request store has a route" do
19
- before do
20
- Airbrake::Rack::RequestStore[:routes] = {
21
- '/about' => {
22
- method: 'GET',
23
- response_type: :html,
24
- groups: {}
25
- }
26
- }
27
- end
28
-
29
- it "attaches all timings for different operations to the request store" do
30
- described_class.capture_timing('operation 1') {}
31
- described_class.capture_timing('operation 2') {}
32
- described_class.capture_timing('operation 3') {}
33
-
34
- expect(routes['/about'][:groups]).to match(
35
- 'operation 1' => be > 0,
36
- 'operation 2' => be > 0,
37
- 'operation 3' => be > 0
38
- )
39
- end
40
-
41
- it "returns the value of the block" do
42
- expect(described_class.capture_timing('operation') { 1 }).to eq(1)
43
- end
44
- end
45
- end
46
- end
@@ -1,44 +0,0 @@
1
- RSpec.describe Airbrake::Rack::RequestBodyFilter do
2
- def env_for(url, opts = {})
3
- Rack::MockRequest.env_for(url, opts)
4
- end
5
-
6
- let(:notice) do
7
- Airbrake.build_notice('oops').tap do |notice|
8
- notice.stash[:rack_request] = Rack::Request.new(env_for(uri, opts))
9
- end
10
- end
11
-
12
- let(:uri) { '/' }
13
- let(:opts) do
14
- { 'rack.input' => body }
15
- end
16
-
17
- context "when a request has a body" do
18
- let(:body) { StringIO.new('<bingo>bongo</bango>') }
19
-
20
- it "reads the body" do
21
- subject.call(notice)
22
- expect(notice[:environment][:body]).to eq(body.string)
23
- end
24
- end
25
-
26
- context "when body was read" do
27
- let(:body) { StringIO.new('<bingo>bongo</bango>' * 512) }
28
-
29
- it "rewinds rack.input" do
30
- subject.call(notice)
31
- expect(body.pos).to be_zero
32
- end
33
- end
34
-
35
- context "when body is bigger than the limit" do
36
- let(:len) { 4097 }
37
- let(:body) { StringIO.new('a' * len) }
38
-
39
- it "reads only first 4096 bytes" do
40
- subject.call(notice)
41
- expect(notice[:environment][:body]).to eq(body.string[0...len - 1])
42
- end
43
- end
44
- end