airbrake 9.2.1 → 9.2.2

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 (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