airbrake-ruby 6.0.1 → 6.1.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (73) hide show
  1. checksums.yaml +4 -4
  2. data/lib/airbrake-ruby/config/processor.rb +6 -0
  3. data/lib/airbrake-ruby/config.rb +3 -3
  4. data/lib/airbrake-ruby/filters/git_last_checkout_filter.rb +1 -1
  5. data/lib/airbrake-ruby/filters/git_repository_filter.rb +7 -1
  6. data/lib/airbrake-ruby/filters/sql_filter.rb +6 -6
  7. data/lib/airbrake-ruby/nested_exception.rb +10 -1
  8. data/lib/airbrake-ruby/notice.rb +5 -3
  9. data/lib/airbrake-ruby/performance_notifier.rb +38 -38
  10. data/lib/airbrake-ruby/stat.rb +1 -1
  11. data/lib/airbrake-ruby/time_truncate.rb +2 -2
  12. data/lib/airbrake-ruby/version.rb +1 -1
  13. data/lib/airbrake-ruby.rb +21 -21
  14. metadata +6 -123
  15. data/spec/airbrake_spec.rb +0 -522
  16. data/spec/async_sender_spec.rb +0 -65
  17. data/spec/backtrace_spec.rb +0 -430
  18. data/spec/benchmark_spec.rb +0 -35
  19. data/spec/code_hunk_spec.rb +0 -124
  20. data/spec/config/processor_spec.rb +0 -151
  21. data/spec/config/validator_spec.rb +0 -204
  22. data/spec/config_spec.rb +0 -188
  23. data/spec/context_spec.rb +0 -54
  24. data/spec/deploy_notifier_spec.rb +0 -50
  25. data/spec/file_cache_spec.rb +0 -35
  26. data/spec/filter_chain_spec.rb +0 -124
  27. data/spec/filters/context_filter_spec.rb +0 -32
  28. data/spec/filters/dependency_filter_spec.rb +0 -14
  29. data/spec/filters/exception_attributes_filter_spec.rb +0 -52
  30. data/spec/filters/gem_root_filter_spec.rb +0 -44
  31. data/spec/filters/git_last_checkout_filter_spec.rb +0 -61
  32. data/spec/filters/git_repository_filter.rb +0 -61
  33. data/spec/filters/git_revision_filter_spec.rb +0 -126
  34. data/spec/filters/keys_allowlist_spec.rb +0 -204
  35. data/spec/filters/keys_blocklist_spec.rb +0 -242
  36. data/spec/filters/root_directory_filter_spec.rb +0 -39
  37. data/spec/filters/sql_filter_spec.rb +0 -274
  38. data/spec/filters/system_exit_filter_spec.rb +0 -16
  39. data/spec/filters/thread_filter_spec.rb +0 -281
  40. data/spec/fixtures/notroot.txt +0 -7
  41. data/spec/fixtures/project_root/code.rb +0 -221
  42. data/spec/fixtures/project_root/empty_file.rb +0 -0
  43. data/spec/fixtures/project_root/long_line.txt +0 -1
  44. data/spec/fixtures/project_root/short_file.rb +0 -3
  45. data/spec/fixtures/project_root/vendor/bundle/ignored_file.rb +0 -5
  46. data/spec/helpers.rb +0 -9
  47. data/spec/ignorable_spec.rb +0 -14
  48. data/spec/inspectable_spec.rb +0 -45
  49. data/spec/loggable_spec.rb +0 -17
  50. data/spec/monotonic_time_spec.rb +0 -25
  51. data/spec/nested_exception_spec.rb +0 -73
  52. data/spec/notice_notifier/options_spec.rb +0 -269
  53. data/spec/notice_notifier_spec.rb +0 -361
  54. data/spec/notice_spec.rb +0 -300
  55. data/spec/performance_breakdown_spec.rb +0 -11
  56. data/spec/performance_notifier_spec.rb +0 -645
  57. data/spec/promise_spec.rb +0 -203
  58. data/spec/query_spec.rb +0 -11
  59. data/spec/queue_spec.rb +0 -18
  60. data/spec/remote_settings/callback_spec.rb +0 -162
  61. data/spec/remote_settings/settings_data_spec.rb +0 -348
  62. data/spec/remote_settings_spec.rb +0 -201
  63. data/spec/request_spec.rb +0 -9
  64. data/spec/response_spec.rb +0 -110
  65. data/spec/spec_helper.rb +0 -100
  66. data/spec/stashable_spec.rb +0 -23
  67. data/spec/stat_spec.rb +0 -39
  68. data/spec/sync_sender_spec.rb +0 -168
  69. data/spec/tdigest_spec.rb +0 -235
  70. data/spec/thread_pool_spec.rb +0 -196
  71. data/spec/time_truncate_spec.rb +0 -15
  72. data/spec/timed_trace_spec.rb +0 -127
  73. data/spec/truncator_spec.rb +0 -267
@@ -1,348 +0,0 @@
1
- RSpec.describe Airbrake::RemoteSettings::SettingsData do
2
- let(:project_id) { 123 }
3
-
4
- describe "#merge!" do
5
- it "returns self" do
6
- settings_data = described_class.new(project_id, {})
7
- expect(settings_data.merge!({})).to eql(settings_data)
8
- end
9
-
10
- it "merges the given hash with the data" do
11
- settings_data = described_class.new(project_id, {})
12
- settings_data.merge!('poll_sec' => 123, 'config_route' => 'abc')
13
-
14
- expect(settings_data.interval).to eq(123)
15
- expect(settings_data.config_route(''))
16
- .to eq('/abc')
17
- end
18
- end
19
-
20
- describe "#interval" do
21
- context "when given data has zero interval" do
22
- let(:data) do
23
- { 'poll_sec' => 0 }
24
- end
25
-
26
- it "returns the default interval" do
27
- expect(described_class.new(project_id, data).interval).to eq(600)
28
- end
29
- end
30
-
31
- context "when given data has negative interval" do
32
- let(:data) do
33
- { 'poll_sec' => -1 }
34
- end
35
-
36
- it "returns the default interval" do
37
- expect(described_class.new(project_id, data).interval).to eq(600)
38
- end
39
- end
40
-
41
- context "when given data has nil interval" do
42
- let(:data) do
43
- { 'poll_sec' => nil }
44
- end
45
-
46
- it "returns the default interval" do
47
- expect(described_class.new(project_id, data).interval).to eq(600)
48
- end
49
- end
50
-
51
- context "when given data has a positive interval" do
52
- let(:data) do
53
- { 'poll_sec' => 123 }
54
- end
55
-
56
- it "returns the interval from data" do
57
- expect(described_class.new(project_id, data).interval).to eq(123)
58
- end
59
- end
60
- end
61
-
62
- describe "#config_route" do
63
- let(:host) { 'http://example.com/' }
64
-
65
- context "when remote config specifies a config route" do
66
- let(:data) do
67
- { 'config_route' => '123/cfg/321/cfg.json' }
68
- end
69
-
70
- it "returns the config route with the provided location" do
71
- expect(described_class.new(project_id, data).config_route(host)).to eq(
72
- 'http://example.com/123/cfg/321/cfg.json',
73
- )
74
- end
75
- end
76
-
77
- context "when remote config DOES NOT specify a config route" do
78
- it "returns the config route with the default location" do
79
- expect(described_class.new(project_id, {}).config_route(host)).to eq(
80
- "http://example.com/2020-06-18/config/#{project_id}/config.json",
81
- )
82
- end
83
- end
84
-
85
- context "when a config route is specified but is set to nil" do
86
- let(:data) do
87
- { 'config_route' => nil }
88
- end
89
-
90
- it "returns the config route with the default location" do
91
- expect(described_class.new(project_id, data).config_route(host)).to eq(
92
- "http://example.com/2020-06-18/config/#{project_id}/config.json",
93
- )
94
- end
95
- end
96
-
97
- context "when a config route is specified but is set to an empty string" do
98
- let(:data) do
99
- { 'config_route' => '' }
100
- end
101
-
102
- it "returns the route with the default instead" do
103
- expect(described_class.new(project_id, data).config_route(host)).to eq(
104
- "http://example.com/2020-06-18/config/#{project_id}/config.json",
105
- )
106
- end
107
- end
108
- end
109
-
110
- describe "#error_notifications?" do
111
- context "when the 'errors' setting is present" do
112
- context "and when it is enabled" do
113
- let(:data) do
114
- {
115
- 'settings' => [
116
- {
117
- 'name' => 'errors',
118
- 'enabled' => true,
119
- },
120
- ],
121
- }
122
- end
123
-
124
- it "returns true" do
125
- expect(described_class.new(project_id, data).error_notifications?)
126
- .to eq(true)
127
- end
128
- end
129
-
130
- context "and when it is disabled" do
131
- let(:data) do
132
- {
133
- 'settings' => [
134
- {
135
- 'name' => 'errors',
136
- 'enabled' => false,
137
- },
138
- ],
139
- }
140
- end
141
-
142
- it "returns false" do
143
- expect(described_class.new(project_id, data).error_notifications?)
144
- .to eq(false)
145
- end
146
- end
147
- end
148
-
149
- context "when the 'errors' setting is missing" do
150
- let(:data) do
151
- { 'settings' => [] }
152
- end
153
-
154
- it "returns true" do
155
- expect(described_class.new(project_id, data).error_notifications?)
156
- .to eq(true)
157
- end
158
- end
159
- end
160
-
161
- describe "#performance_stats?" do
162
- context "when the 'apm' setting is present" do
163
- context "and when it is enabled" do
164
- let(:data) do
165
- {
166
- 'settings' => [
167
- {
168
- 'name' => 'apm',
169
- 'enabled' => true,
170
- },
171
- ],
172
- }
173
- end
174
-
175
- it "returns true" do
176
- expect(described_class.new(project_id, data).performance_stats?)
177
- .to eq(true)
178
- end
179
- end
180
-
181
- context "and when it is disabled" do
182
- let(:data) do
183
- {
184
- 'settings' => [
185
- {
186
- 'name' => 'apm',
187
- 'enabled' => false,
188
- },
189
- ],
190
- }
191
- end
192
-
193
- it "returns false" do
194
- expect(described_class.new(project_id, data).performance_stats?)
195
- .to eq(false)
196
- end
197
- end
198
- end
199
-
200
- context "when the 'apm' setting is missing" do
201
- let(:data) do
202
- { 'settings' => [] }
203
- end
204
-
205
- it "returns true" do
206
- expect(described_class.new(project_id, data).performance_stats?)
207
- .to eq(true)
208
- end
209
- end
210
- end
211
-
212
- describe "#error_host" do
213
- context "when the 'errors' setting is present" do
214
- context "and when 'endpoint' is specified" do
215
- let(:endpoint) { 'https://api.example.com/' }
216
-
217
- let(:data) do
218
- {
219
- 'settings' => [
220
- {
221
- 'name' => 'errors',
222
- 'enabled' => true,
223
- 'endpoint' => endpoint,
224
- },
225
- ],
226
- }
227
- end
228
-
229
- it "returns the endpoint" do
230
- expect(described_class.new(project_id, data).error_host).to eq(endpoint)
231
- end
232
- end
233
-
234
- context "and when an endpoint is NOT specified" do
235
- let(:data) do
236
- {
237
- 'settings' => [
238
- {
239
- 'name' => 'errors',
240
- 'enabled' => true,
241
- },
242
- ],
243
- }
244
- end
245
-
246
- it "returns nil" do
247
- expect(described_class.new(project_id, data).error_host).to be_nil
248
- end
249
- end
250
- end
251
-
252
- context "when the 'errors' setting is missing" do
253
- let(:data) do
254
- { 'settings' => [] }
255
- end
256
-
257
- it "returns nil" do
258
- expect(described_class.new(project_id, data).error_host).to be_nil
259
- end
260
- end
261
- end
262
-
263
- describe "#apm_host" do
264
- context "when the 'apm' setting is present" do
265
- context "and when 'endpoint' is specified" do
266
- let(:endpoint) { 'https://api.example.com/' }
267
-
268
- let(:data) do
269
- {
270
- 'settings' => [
271
- {
272
- 'name' => 'apm',
273
- 'enabled' => true,
274
- 'endpoint' => endpoint,
275
- },
276
- ],
277
- }
278
- end
279
-
280
- it "returns the endpoint" do
281
- expect(described_class.new(project_id, data).apm_host).to eq(endpoint)
282
- end
283
- end
284
-
285
- context "and when an endpoint is NOT specified" do
286
- let(:data) do
287
- {
288
- 'settings' => [
289
- {
290
- 'name' => 'apm',
291
- 'enabled' => true,
292
- },
293
- ],
294
- }
295
- end
296
-
297
- it "returns nil" do
298
- expect(described_class.new(project_id, data).apm_host).to be_nil
299
- end
300
- end
301
- end
302
-
303
- context "when the 'apm' setting is missing" do
304
- let(:data) do
305
- { 'settings' => [] }
306
- end
307
-
308
- it "returns nil" do
309
- expect(described_class.new(project_id, data).apm_host).to be_nil
310
- end
311
- end
312
- end
313
-
314
- describe "#to_h" do
315
- subject(:settings_data) { described_class.new(project_id, data) }
316
-
317
- let(:data) do
318
- {
319
- 'poll_sec' => 123,
320
- 'settings' => [
321
- {
322
- 'name' => 'apm',
323
- 'enabled' => false,
324
- },
325
- ],
326
- }
327
- end
328
-
329
- it "returns a hash representation of settings" do
330
- expect(described_class.new(project_id, data).to_h).to eq(data)
331
- end
332
-
333
- it "doesn't allow mutation of the original data object" do
334
- hash = settings_data.to_h
335
- hash['poll_sec'] = 0
336
-
337
- expect(settings_data.to_h).to eq(
338
- 'poll_sec' => 123,
339
- 'settings' => [
340
- {
341
- 'name' => 'apm',
342
- 'enabled' => false,
343
- },
344
- ],
345
- )
346
- end
347
- end
348
- end
@@ -1,201 +0,0 @@
1
- RSpec.describe Airbrake::RemoteSettings do
2
- let(:project_id) { 123 }
3
- let(:host) { 'https://v1-production-notifier-configs.s3.amazonaws.com' }
4
-
5
- let(:endpoint) do
6
- "#{host}/2020-06-18/config/#{project_id}/config.json"
7
- end
8
-
9
- let(:body) do
10
- {
11
- 'poll_sec' => 1,
12
- 'settings' => [
13
- {
14
- 'name' => 'apm',
15
- 'enabled' => false,
16
- },
17
- {
18
- 'name' => 'errors',
19
- 'enabled' => true,
20
- },
21
- ],
22
- }
23
- end
24
-
25
- let!(:stub) do
26
- stub_request(:get, Regexp.new(endpoint))
27
- .to_return(status: 200, body: body.to_json)
28
- end
29
-
30
- describe ".poll" do
31
- describe "config loading" do
32
- let(:settings_data) { described_class::SettingsData.new(project_id, body) }
33
-
34
- before do
35
- allow(described_class::SettingsData).to receive(:new).and_return(settings_data)
36
- end
37
-
38
- it "yields the config to the block twice" do
39
- block = proc {}
40
- allow(block).to receive(:call)
41
-
42
- remote_settings = described_class.poll(project_id, host, &block)
43
- sleep(0.2)
44
- remote_settings.stop_polling
45
-
46
- expect(stub).to have_been_requested.once
47
- expect(block).to have_received(:call).twice
48
- end
49
- end
50
-
51
- context "when no errors are raised" do
52
- it "makes a request to AWS S3" do
53
- remote_settings = described_class.poll(project_id, host) { anything }
54
- sleep(0.1)
55
- remote_settings.stop_polling
56
-
57
- expect(stub).to have_been_requested.at_least_once
58
- end
59
-
60
- it "sends params about the environment with the request" do
61
- remote_settings = described_class.poll(project_id, host) { anything }
62
- sleep(0.1)
63
- remote_settings.stop_polling
64
-
65
- stub_with_query_params = stub.with(
66
- query: URI.decode_www_form(described_class::QUERY_PARAMS).to_h,
67
- )
68
- expect(stub_with_query_params).to have_been_requested.at_least_once
69
- end
70
-
71
- # rubocop:disable RSpec/MultipleExpectations
72
- it "fetches remote settings" do
73
- settings = nil
74
- remote_settings = described_class.poll(project_id, host) do |data|
75
- settings = data
76
- end
77
- sleep(0.1)
78
- remote_settings.stop_polling
79
-
80
- expect(settings.error_notifications?).to eq(true)
81
- expect(settings.performance_stats?).to eq(false)
82
- expect(settings.interval).to eq(1)
83
- end
84
- # rubocop:enable RSpec/MultipleExpectations
85
- end
86
-
87
- context "when an error is raised while making a HTTP request" do
88
- let(:https) { instance_double(Net::HTTP) }
89
-
90
- before do
91
- allow(Net::HTTP).to receive(:new).and_return(https)
92
- allow(https).to receive(:use_ssl=).with(true)
93
- allow(https).to receive(:request).and_raise(StandardError)
94
- end
95
-
96
- it "doesn't fetch remote settings" do
97
- settings = nil
98
- remote_settings = described_class.poll(project_id, host) do |data|
99
- settings = data
100
- end
101
- sleep(0.1)
102
- remote_settings.stop_polling
103
-
104
- expect(stub).not_to have_been_requested
105
- expect(settings.interval).to eq(600)
106
- end
107
- end
108
-
109
- context "when an error is raised while parsing returned JSON" do
110
- before do
111
- allow(JSON).to receive(:parse).and_raise(JSON::ParserError)
112
- end
113
-
114
- it "doesn't update settings data" do
115
- settings = nil
116
- remote_settings = described_class.poll(project_id, host) do |data|
117
- settings = data
118
- end
119
- sleep(0.1)
120
- remote_settings.stop_polling
121
-
122
- expect(stub).to have_been_requested.once
123
- expect(settings.interval).to eq(600)
124
- end
125
- end
126
-
127
- context "when API returns a non-200 response" do
128
- let!(:stub) do
129
- stub_request(:get, Regexp.new(endpoint))
130
- .to_return(status: 201, body: body.to_json)
131
- end
132
-
133
- it "doesn't update settings data" do
134
- settings = nil
135
- remote_settings = described_class.poll(project_id, host) do |data|
136
- settings = data
137
- end
138
- sleep(0.1)
139
- remote_settings.stop_polling
140
-
141
- expect(stub).to have_been_requested.once
142
- expect(settings.interval).to eq(600)
143
- end
144
-
145
- it "logs error" do
146
- allow(Airbrake::Loggable.instance).to receive(:error)
147
-
148
- remote_settings = described_class.poll(project_id, host) { anything }
149
- sleep(0.1)
150
- remote_settings.stop_polling
151
-
152
- expect(Airbrake::Loggable.instance).to have_received(:error).with(body.to_json)
153
- end
154
- end
155
-
156
- context "when API returns a 200 response" do
157
- let!(:stub) do
158
- stub_request(:get, Regexp.new(endpoint))
159
- .to_return(status: 200, body: body.to_json)
160
- end
161
-
162
- it "doesn't log errors" do
163
- allow(Airbrake::Loggable.instance).to receive(:error)
164
-
165
- remote_settings = described_class.poll(project_id, host) { anything }
166
- sleep(0.1)
167
- remote_settings.stop_polling
168
-
169
- expect(Airbrake::Loggable.instance).not_to have_received(:error)
170
- expect(stub).to have_been_requested.once
171
- end
172
- end
173
-
174
- # rubocop:disable RSpec/MultipleMemoizedHelpers
175
- context "when a config route is specified in the returned data" do
176
- let(:new_config_route) do
177
- '213/config/111/config.json'
178
- end
179
-
180
- let(:body) do
181
- { 'config_route' => new_config_route, 'poll_sec' => 0.1 }
182
- end
183
-
184
- let!(:new_stub) do
185
- stub_request(:get, Regexp.new(new_config_route))
186
- .to_return(status: 200, body: body.to_json)
187
- end
188
-
189
- it "makes the next request to the specified config route" do
190
- remote_settings = described_class.poll(project_id, host) { anything }
191
- sleep(0.2)
192
-
193
- remote_settings.stop_polling
194
-
195
- expect(stub).to have_been_requested.once
196
- expect(new_stub).to have_been_requested.once
197
- end
198
- end
199
- # rubocop:enable RSpec/MultipleMemoizedHelpers
200
- end
201
- end
data/spec/request_spec.rb DELETED
@@ -1,9 +0,0 @@
1
- RSpec.describe Airbrake::Request do
2
- describe "#stash" do
3
- subject do
4
- described_class.new(method: 'GET', route: '/', status_code: 200)
5
- end
6
-
7
- it { is_expected.to respond_to(:stash) }
8
- end
9
- end
@@ -1,110 +0,0 @@
1
- RSpec.describe Airbrake::Response do
2
- describe ".parse" do
3
- [200, 201, 204].each do |code|
4
- context "when response code is #{code}" do
5
- before do
6
- allow(Airbrake::Loggable.instance).to receive(:debug)
7
- end
8
-
9
- it "logs response body" do
10
- described_class.parse(OpenStruct.new(code: code, body: '{}'))
11
-
12
- expect(Airbrake::Loggable.instance).to have_received(:debug).with(
13
- /Airbrake::Response \(#{code}\): {}/,
14
- )
15
- end
16
- end
17
- end
18
-
19
- [400, 401, 403, 420].each do |code|
20
- context "when response code is #{code}" do
21
- before do
22
- allow(Airbrake::Loggable.instance).to receive(:error)
23
- end
24
-
25
- it "logs response message" do
26
- described_class.parse(
27
- OpenStruct.new(code: code, body: '{"message":"foo"}'),
28
- )
29
-
30
- expect(Airbrake::Loggable.instance).to have_received(:error).with(
31
- /Airbrake: foo/,
32
- )
33
- end
34
- end
35
- end
36
-
37
- context "when response code is 429" do
38
- let(:response) { OpenStruct.new(code: 429, body: '{"message":"rate limited"}') }
39
-
40
- before do
41
- allow(Airbrake::Loggable.instance).to receive(:error)
42
- end
43
-
44
- it "logs response message" do
45
- described_class.parse(response)
46
- expect(Airbrake::Loggable.instance).to have_received(:error).with(
47
- /Airbrake: rate limited/,
48
- )
49
- end
50
-
51
- it "returns an error response" do
52
- time = Time.now
53
- allow(Time).to receive(:now).and_return(time)
54
-
55
- resp = described_class.parse(response)
56
- expect(resp).to include(
57
- 'error' => '**Airbrake: rate limited',
58
- 'rate_limit_reset' => time,
59
- )
60
- end
61
- end
62
-
63
- context "when response code is unhandled" do
64
- let(:response) { OpenStruct.new(code: 500, body: 'foo') }
65
-
66
- before do
67
- allow(Airbrake::Loggable.instance).to receive(:error)
68
- end
69
-
70
- it "logs response body" do
71
- described_class.parse(response)
72
- expect(Airbrake::Loggable.instance).to have_received(:error).with(
73
- /Airbrake: unexpected code \(500\)\. Body: foo/,
74
- )
75
- end
76
-
77
- it "returns an error response" do
78
- resp = described_class.parse(response)
79
- expect(resp).to eq('error' => 'foo')
80
- end
81
-
82
- it "truncates body" do
83
- response.body *= 1000
84
- resp = described_class.parse(response)
85
- expect(resp).to eq('error' => "#{'foo' * 33}fo...")
86
- end
87
- end
88
-
89
- context "when response body can't be parsed as JSON" do
90
- let(:response) { OpenStruct.new(code: 201, body: 'foo') }
91
-
92
- before do
93
- allow(Airbrake::Loggable.instance).to receive(:error)
94
- end
95
-
96
- it "logs response body" do
97
- described_class.parse(response)
98
- expect(Airbrake::Loggable.instance).to have_received(:error).with(
99
- /Airbrake: error while parsing body \(.*unexpected token.*\)\. Body: foo/,
100
- )
101
- end
102
-
103
- it "returns an error message" do
104
- expect(described_class.parse(response)['error']).to match(
105
- /\A#<JSON::ParserError.+>/,
106
- )
107
- end
108
- end
109
- end
110
- end