airbrake-ruby 3.2.2-java

Sign up to get free protection for your applications and to get access to all the features.
Files changed (82) hide show
  1. checksums.yaml +7 -0
  2. data/lib/airbrake-ruby.rb +554 -0
  3. data/lib/airbrake-ruby/async_sender.rb +119 -0
  4. data/lib/airbrake-ruby/backtrace.rb +194 -0
  5. data/lib/airbrake-ruby/code_hunk.rb +53 -0
  6. data/lib/airbrake-ruby/config.rb +238 -0
  7. data/lib/airbrake-ruby/config/validator.rb +63 -0
  8. data/lib/airbrake-ruby/deploy_notifier.rb +47 -0
  9. data/lib/airbrake-ruby/file_cache.rb +48 -0
  10. data/lib/airbrake-ruby/filter_chain.rb +95 -0
  11. data/lib/airbrake-ruby/filters/context_filter.rb +29 -0
  12. data/lib/airbrake-ruby/filters/dependency_filter.rb +31 -0
  13. data/lib/airbrake-ruby/filters/exception_attributes_filter.rb +45 -0
  14. data/lib/airbrake-ruby/filters/gem_root_filter.rb +33 -0
  15. data/lib/airbrake-ruby/filters/git_last_checkout_filter.rb +90 -0
  16. data/lib/airbrake-ruby/filters/git_repository_filter.rb +42 -0
  17. data/lib/airbrake-ruby/filters/git_revision_filter.rb +66 -0
  18. data/lib/airbrake-ruby/filters/keys_blacklist.rb +50 -0
  19. data/lib/airbrake-ruby/filters/keys_filter.rb +140 -0
  20. data/lib/airbrake-ruby/filters/keys_whitelist.rb +49 -0
  21. data/lib/airbrake-ruby/filters/root_directory_filter.rb +28 -0
  22. data/lib/airbrake-ruby/filters/sql_filter.rb +104 -0
  23. data/lib/airbrake-ruby/filters/system_exit_filter.rb +23 -0
  24. data/lib/airbrake-ruby/filters/thread_filter.rb +92 -0
  25. data/lib/airbrake-ruby/hash_keyable.rb +37 -0
  26. data/lib/airbrake-ruby/ignorable.rb +44 -0
  27. data/lib/airbrake-ruby/nested_exception.rb +39 -0
  28. data/lib/airbrake-ruby/notice.rb +165 -0
  29. data/lib/airbrake-ruby/notice_notifier.rb +228 -0
  30. data/lib/airbrake-ruby/performance_notifier.rb +161 -0
  31. data/lib/airbrake-ruby/promise.rb +99 -0
  32. data/lib/airbrake-ruby/response.rb +71 -0
  33. data/lib/airbrake-ruby/stat.rb +56 -0
  34. data/lib/airbrake-ruby/sync_sender.rb +111 -0
  35. data/lib/airbrake-ruby/tdigest.rb +393 -0
  36. data/lib/airbrake-ruby/time_truncate.rb +17 -0
  37. data/lib/airbrake-ruby/truncator.rb +115 -0
  38. data/lib/airbrake-ruby/version.rb +6 -0
  39. data/spec/airbrake_spec.rb +171 -0
  40. data/spec/async_sender_spec.rb +154 -0
  41. data/spec/backtrace_spec.rb +438 -0
  42. data/spec/code_hunk_spec.rb +118 -0
  43. data/spec/config/validator_spec.rb +189 -0
  44. data/spec/config_spec.rb +281 -0
  45. data/spec/deploy_notifier_spec.rb +41 -0
  46. data/spec/file_cache.rb +36 -0
  47. data/spec/filter_chain_spec.rb +83 -0
  48. data/spec/filters/context_filter_spec.rb +25 -0
  49. data/spec/filters/dependency_filter_spec.rb +14 -0
  50. data/spec/filters/exception_attributes_filter_spec.rb +63 -0
  51. data/spec/filters/gem_root_filter_spec.rb +44 -0
  52. data/spec/filters/git_last_checkout_filter_spec.rb +48 -0
  53. data/spec/filters/git_repository_filter.rb +53 -0
  54. data/spec/filters/git_revision_filter_spec.rb +126 -0
  55. data/spec/filters/keys_blacklist_spec.rb +236 -0
  56. data/spec/filters/keys_whitelist_spec.rb +205 -0
  57. data/spec/filters/root_directory_filter_spec.rb +42 -0
  58. data/spec/filters/sql_filter_spec.rb +219 -0
  59. data/spec/filters/system_exit_filter_spec.rb +14 -0
  60. data/spec/filters/thread_filter_spec.rb +279 -0
  61. data/spec/fixtures/notroot.txt +7 -0
  62. data/spec/fixtures/project_root/code.rb +221 -0
  63. data/spec/fixtures/project_root/empty_file.rb +0 -0
  64. data/spec/fixtures/project_root/long_line.txt +1 -0
  65. data/spec/fixtures/project_root/short_file.rb +3 -0
  66. data/spec/fixtures/project_root/vendor/bundle/ignored_file.rb +5 -0
  67. data/spec/helpers.rb +9 -0
  68. data/spec/ignorable_spec.rb +14 -0
  69. data/spec/nested_exception_spec.rb +75 -0
  70. data/spec/notice_notifier_spec.rb +436 -0
  71. data/spec/notice_notifier_spec/options_spec.rb +266 -0
  72. data/spec/notice_spec.rb +297 -0
  73. data/spec/performance_notifier_spec.rb +287 -0
  74. data/spec/promise_spec.rb +165 -0
  75. data/spec/response_spec.rb +82 -0
  76. data/spec/spec_helper.rb +102 -0
  77. data/spec/stat_spec.rb +35 -0
  78. data/spec/sync_sender_spec.rb +140 -0
  79. data/spec/tdigest_spec.rb +230 -0
  80. data/spec/time_truncate_spec.rb +13 -0
  81. data/spec/truncator_spec.rb +238 -0
  82. metadata +278 -0
@@ -0,0 +1,118 @@
1
+ RSpec.describe Airbrake::CodeHunk do
2
+ let(:config) { Airbrake::Config.new }
3
+
4
+ after do
5
+ %w[empty_file.rb code.rb banana.rb short_file.rb long_line.txt].each do |f|
6
+ Airbrake::FileCache[project_root_path(f)] = nil
7
+ end
8
+ end
9
+
10
+ describe "#to_h" do
11
+ context "when file is empty" do
12
+ subject do
13
+ described_class.new(config).get(project_root_path('empty_file.rb'), 1)
14
+ end
15
+
16
+ it { is_expected.to eq(1 => '') }
17
+ end
18
+
19
+ context "when line is nil" do
20
+ subject { described_class.new(config).get(project_root_path('code.rb'), nil) }
21
+
22
+ it { is_expected.to be_nil }
23
+ end
24
+
25
+ context "when a file doesn't exist" do
26
+ subject { described_class.new(config).get(project_root_path('banana.rb'), 1) }
27
+
28
+ it { is_expected.to be_nil }
29
+ end
30
+
31
+ context "when a file has less than NLINES lines before start line" do
32
+ subject { described_class.new(config).get(project_root_path('code.rb'), 1) }
33
+
34
+ it do
35
+ is_expected.to(
36
+ eq(
37
+ 1 => 'module Airbrake',
38
+ 2 => ' ##',
39
+ # rubocop:disable Metrics/LineLength
40
+ 3 => ' # Represents a chunk of information that is meant to be either sent to',
41
+ # rubocop:enable Metrics/LineLength
42
+ )
43
+ )
44
+ end
45
+ end
46
+
47
+ context "when a file has less than NLINES lines after end line" do
48
+ subject { described_class.new(config).get(project_root_path('code.rb'), 222) }
49
+
50
+ it do
51
+ is_expected.to(
52
+ eq(
53
+ 220 => ' end',
54
+ 221 => 'end'
55
+ )
56
+ )
57
+ end
58
+ end
59
+
60
+ context "when a file has less than NLINES lines before and after" do
61
+ subject do
62
+ described_class.new(config).get(project_root_path('short_file.rb'), 2)
63
+ end
64
+
65
+ it do
66
+ is_expected.to(
67
+ eq(
68
+ 1 => 'module Banana',
69
+ 2 => ' attr_reader :bingo',
70
+ 3 => 'end'
71
+ )
72
+ )
73
+ end
74
+ end
75
+
76
+ context "when a file has enough lines before and after" do
77
+ subject { described_class.new(config).get(project_root_path('code.rb'), 100) }
78
+
79
+ it do
80
+ is_expected.to(
81
+ eq(
82
+ 98 => ' return json if json && json.bytesize <= MAX_NOTICE_SIZE',
83
+ 99 => ' end',
84
+ 100 => '',
85
+ 101 => ' break if truncate == 0',
86
+ 102 => ' end'
87
+ )
88
+ )
89
+ end
90
+ end
91
+
92
+ context "when a line exceeds the length limit" do
93
+ subject do
94
+ described_class.new(config).get(project_root_path('long_line.txt'), 1)
95
+ end
96
+
97
+ it "strips the line" do
98
+ expect(subject[1]).to eq('l' + 'o' * 196 + 'ng')
99
+ end
100
+ end
101
+
102
+ context "when an error occurrs while fetching code" do
103
+ before do
104
+ expect(Airbrake::FileCache).to receive(:[]).and_raise(Errno::EACCES)
105
+ end
106
+
107
+ it "logs error and returns nil" do
108
+ out = StringIO.new
109
+ config = Airbrake::Config.new
110
+ config.logger = Logger.new(out)
111
+ expect(described_class.new(config).get(project_root_path('code.rb'), 1)).to(
112
+ eq(1 => '')
113
+ )
114
+ expect(out.string).to match(/can't read code hunk.+Permission denied/)
115
+ end
116
+ end
117
+ end
118
+ end
@@ -0,0 +1,189 @@
1
+ RSpec.describe Airbrake::Config::Validator do
2
+ subject { described_class.new(config) }
3
+
4
+ describe "#valid_project_id?" do
5
+ context "when project id is zero" do
6
+ let(:config) { Airbrake::Config.new(project_id: 0) }
7
+
8
+ it "returns false" do
9
+ expect(subject.valid_project_id?).to be false
10
+ end
11
+
12
+ it "sets correct error message" do
13
+ expect { subject.valid_project_id? }.to(
14
+ change { subject.error_message }.to(/:project_id is required/)
15
+ )
16
+ end
17
+ end
18
+
19
+ context "when project_id is a String" do
20
+ let(:config) { Airbrake::Config.new(project_id: '000') }
21
+
22
+ context "and when it's zero" do
23
+ it "returns false" do
24
+ expect(subject.valid_project_id?).to be false
25
+ end
26
+
27
+ it "sets correct error message" do
28
+ expect { subject.valid_project_id? }.
29
+ to(
30
+ change { subject.error_message }.to(/:project_id is required/)
31
+ )
32
+ end
33
+ end
34
+
35
+ context "and when it consists of letters" do
36
+ let(:config) { Airbrake::Config.new(project_id: 'bingo') }
37
+
38
+ it "returns false" do
39
+ expect(subject.valid_project_id?).to be false
40
+ end
41
+
42
+ it "sets correct error message" do
43
+ expect { subject.valid_project_id? }.to(
44
+ change { subject.error_message }.to(/:project_id is required/)
45
+ )
46
+ end
47
+ end
48
+
49
+ context "and when it's numerical" do
50
+ let(:config) { Airbrake::Config.new(project_id: '123') }
51
+
52
+ it "returns true" do
53
+ expect(subject.valid_project_id?).to be true
54
+ end
55
+
56
+ it "doesn't set the error message" do
57
+ expect { subject.valid_project_id? }.not_to(change { subject.error_message })
58
+ end
59
+ end
60
+ end
61
+
62
+ context "when project id is non-zero" do
63
+ let(:config) { Airbrake::Config.new(project_id: 123) }
64
+
65
+ it "returns true" do
66
+ expect(subject.valid_project_id?).to be true
67
+ end
68
+
69
+ it "doesn't set the error message" do
70
+ expect { subject.valid_project_id? }.not_to(change { subject.error_message })
71
+ end
72
+ end
73
+ end
74
+
75
+ describe "#valid_project_key?" do
76
+ context "when it's a String" do
77
+ context "and when it's empty" do
78
+ let(:config) { Airbrake::Config.new(project_key: '') }
79
+
80
+ it "returns false" do
81
+ expect(subject.valid_project_key?).to be false
82
+ end
83
+
84
+ it "sets correct error message" do
85
+ expect { subject.valid_project_key? }.
86
+ to change { subject.error_message }.
87
+ to(/:project_key is required/)
88
+ end
89
+ end
90
+
91
+ context "and when it's non-empty" do
92
+ let(:config) { Airbrake::Config.new(project_key: '123abc') }
93
+
94
+ it "returns true" do
95
+ expect(subject.valid_project_key?).to be true
96
+ end
97
+
98
+ it "doesn't set the error message" do
99
+ expect { subject.valid_project_key? }.not_to(change { subject.error_message })
100
+ end
101
+ end
102
+ end
103
+
104
+ context "when it's not a String" do
105
+ let(:config) { Airbrake::Config.new(project_key: 123) }
106
+
107
+ it "returns false" do
108
+ expect(subject.valid_project_key?).to be false
109
+ end
110
+
111
+ it "sets correct error message" do
112
+ expect { subject.valid_project_key? }.to(
113
+ change { subject.error_message }.to(/:project_key is required/)
114
+ )
115
+ end
116
+ end
117
+ end
118
+
119
+ describe "#valid_environment?" do
120
+ context "when config.environment is not set" do
121
+ let(:config) { Airbrake::Config.new }
122
+
123
+ it "returns true" do
124
+ expect(subject.valid_environment?).to be true
125
+ end
126
+
127
+ it "doesn't set the error message" do
128
+ expect { subject.valid_environment? }.not_to(change { subject.error_message })
129
+ end
130
+ end
131
+
132
+ context "when config.environment is set" do
133
+ context "and when it is not a Symbol or String" do
134
+ let(:config) { Airbrake::Config.new(environment: 123) }
135
+
136
+ it "returns false" do
137
+ expect(subject.valid_environment?).to be false
138
+ end
139
+
140
+ it "sets the error message" do
141
+ expect { subject.valid_environment? }.to(
142
+ change { subject.error_message }.
143
+ to(/the 'environment' option must be configured with a Symbol/)
144
+ )
145
+ end
146
+ end
147
+
148
+ context "and when it is a Symbol" do
149
+ let(:config) { Airbrake::Config.new(environment: :bingo) }
150
+
151
+ it "returns true" do
152
+ expect(subject.valid_environment?).to be true
153
+ end
154
+
155
+ it "doesn't set the error message" do
156
+ expect { subject.valid_environment? }.not_to(change { subject.error_message })
157
+ end
158
+ end
159
+
160
+ context "and when it is a String" do
161
+ let(:config) { Airbrake::Config.new(environment: 'bingo') }
162
+
163
+ it "returns true" do
164
+ expect(subject.valid_environment?).to be true
165
+ end
166
+
167
+ it "doesn't set the error message" do
168
+ expect { subject.valid_environment? }.not_to(change { subject.error_message })
169
+ end
170
+ end
171
+
172
+ context "and when it is kind of a String" do
173
+ let(:string_inquirer) { Class.new(String) }
174
+
175
+ let(:config) do
176
+ Airbrake::Config.new(environment: string_inquirer.new('bingo'))
177
+ end
178
+
179
+ it "returns true" do
180
+ expect(subject.valid_environment?).to be true
181
+ end
182
+
183
+ it "doesn't set the error message" do
184
+ expect { subject.valid_environment? }.not_to(change { subject.error_message })
185
+ end
186
+ end
187
+ end
188
+ end
189
+ end
@@ -0,0 +1,281 @@
1
+ RSpec.describe Airbrake::Config do
2
+ let(:config) { described_class.new }
3
+
4
+ describe "#new" do
5
+ describe "options" do
6
+ it "doesn't set the default project_id" do
7
+ expect(config.project_id).to be_nil
8
+ end
9
+
10
+ it "doesn't set the default project_key" do
11
+ expect(config.project_key).to be_nil
12
+ end
13
+
14
+ it "doesn't set the default proxy" do
15
+ expect(config.proxy).to be_empty
16
+ end
17
+
18
+ it "sets the default logger" do
19
+ expect(config.logger).to be_a Logger
20
+ end
21
+
22
+ it "doesn't set the default app_version" do
23
+ expect(config.app_version).to be_nil
24
+ end
25
+
26
+ it "sets the default versions" do
27
+ expect(config.versions).to be_empty
28
+ end
29
+
30
+ it "sets the default host" do
31
+ expect(config.host).to eq('https://api.airbrake.io')
32
+ end
33
+
34
+ it "sets the default endpoint" do
35
+ expect(config.endpoint).not_to be_nil
36
+ end
37
+
38
+ it "creates a new Config and merges it with the user config" do
39
+ cfg = described_class.new(logger: StringIO.new)
40
+ expect(cfg.logger).to be_a StringIO
41
+ end
42
+
43
+ it "raises error on unknown config options" do
44
+ expect { described_class.new(unknown_option: true) }.
45
+ to raise_error(Airbrake::Error, /unknown option/)
46
+ end
47
+
48
+ it "sets the default number of workers" do
49
+ expect(config.workers).to eq(1)
50
+ end
51
+
52
+ it "sets the default number of queue size" do
53
+ expect(config.queue_size).to eq(100)
54
+ end
55
+
56
+ it "sets the default root_directory" do
57
+ expect(config.root_directory).to eq Bundler.root.realpath.to_s
58
+ end
59
+
60
+ it "doesn't set the default environment" do
61
+ expect(config.environment).to be_nil
62
+ end
63
+
64
+ it "doesn't set default notify_environments" do
65
+ expect(config.ignore_environments).to be_empty
66
+ end
67
+
68
+ it "doesn't set default timeout" do
69
+ expect(config.timeout).to be_nil
70
+ end
71
+
72
+ it "doesn't set default blacklist" do
73
+ expect(config.blacklist_keys).to be_empty
74
+ end
75
+
76
+ it "doesn't set default whitelist" do
77
+ expect(config.whitelist_keys).to be_empty
78
+ end
79
+
80
+ it "disables route stats by default (deprecated)" do
81
+ out = StringIO.new
82
+ config.logger = Logger.new(out)
83
+ expect(config.route_stats).to be_falsey
84
+ expect(out.string).to match(/'route_stats'.+is deprecated/)
85
+ end
86
+
87
+ it "disables performance stats by default" do
88
+ expect(config.performance_stats).to be_falsey
89
+ end
90
+
91
+ it "sets the default route_stats_flush_period (deprecated)" do
92
+ out = StringIO.new
93
+ config.logger = Logger.new(out)
94
+ expect(config.route_stats_flush_period).to eq(15)
95
+ expect(out.string).to match(/'route_stats_flush_period'.+is deprecated/)
96
+ end
97
+
98
+ it "sets the default performance_stats_flush_period" do
99
+ expect(config.performance_stats_flush_period).to eq(15)
100
+ end
101
+ end
102
+ end
103
+
104
+ describe "#valid?" do
105
+ context "when project_id is nil" do
106
+ it "returns false" do
107
+ config.project_id = nil
108
+ config.project_key = '123'
109
+
110
+ expect(config).not_to be_valid
111
+ end
112
+ end
113
+
114
+ context "when project_key is nil" do
115
+ it "returns false" do
116
+ config.project_id = 123
117
+ config.project_key = nil
118
+
119
+ expect(config).not_to be_valid
120
+ end
121
+ end
122
+
123
+ context "when the current environment is ignored" do
124
+ context "and when the notifier misconfigures configure project_key & project_id" do
125
+ it "returns true" do
126
+ config.project_id = Object.new
127
+ config.project_key = Object.new
128
+ config.environment = :bingo
129
+ config.ignore_environments = [:bingo]
130
+
131
+ expect(config).to be_valid
132
+ end
133
+ end
134
+
135
+ context "and when the notifier configures project_key & project_id" do
136
+ it "returns true" do
137
+ config.project_id = 123
138
+ config.project_key = '321'
139
+ config.environment = :bingo
140
+ config.ignore_environments = [:bingo]
141
+
142
+ expect(config).to be_valid
143
+ end
144
+ end
145
+ end
146
+
147
+ context "when the project_id value is not a number" do
148
+ it "returns false" do
149
+ config.project_id = 'bingo'
150
+ config.project_key = '321'
151
+
152
+ expect(config).not_to be_valid
153
+ end
154
+ end
155
+
156
+ context "when the project_id value is a String number" do
157
+ it "returns true" do
158
+ config.project_id = '123'
159
+ config.project_key = '321'
160
+
161
+ expect(config).to be_valid
162
+ end
163
+ end
164
+
165
+ context "when the project_key value is not a String" do
166
+ it "returns false" do
167
+ config.project_id = 123
168
+ config.project_key = 321
169
+
170
+ expect(config).not_to be_valid
171
+ end
172
+ end
173
+
174
+ context "when the project_key value is an empty String" do
175
+ it "returns false" do
176
+ config.project_id = 123
177
+ config.project_key = ''
178
+
179
+ expect(config).not_to be_valid
180
+ end
181
+ end
182
+
183
+ context "when the environment value is not a String" do
184
+ let(:out) { StringIO.new }
185
+ let(:config) { described_class.new(logger: Logger.new(out)) }
186
+
187
+ before do
188
+ config.project_id = 123
189
+ config.project_key = '321'
190
+
191
+ config.environment = ['bingo']
192
+ end
193
+
194
+ it "returns false" do
195
+ expect(config).not_to be_valid
196
+ end
197
+ end
198
+ end
199
+
200
+ describe "#ignored_environment?" do
201
+ describe "warnings" do
202
+ let(:out) { StringIO.new }
203
+ let(:config) { described_class.new(logger: Logger.new(out)) }
204
+
205
+ context "when 'ignore_environments' is set and 'environment' isn't" do
206
+ it "prints a warning" do
207
+ config.ignore_environments = [:bingo]
208
+
209
+ expect(config.ignored_environment?).to be_falsey
210
+ expect(out.string).to match(/ignore_environments' has no effect/)
211
+ end
212
+ end
213
+
214
+ context "when 'ignore_environments' is set along with 'environment'" do
215
+ it "doesn't print a warning" do
216
+ config.environment = :bango
217
+ config.ignore_environments = [:bingo]
218
+
219
+ expect(config.ignored_environment?).to be_falsey
220
+ expect(out.string).to be_empty
221
+ end
222
+ end
223
+
224
+ context "when 'ignore_environments' isn't set and 'environment' isn't set too" do
225
+ it "doesn't print a warning" do
226
+ expect(config.ignored_environment?).to be_falsey
227
+ expect(out.string).to be_empty
228
+ end
229
+ end
230
+ end
231
+
232
+ describe "environment value types" do
233
+ context "when 'environment' is a String" do
234
+ context "and when 'ignore_environments' contains Symbols" do
235
+ it "returns true" do
236
+ config.environment = 'bango'
237
+ config.ignore_environments = [:bango]
238
+
239
+ expect(config.ignored_environment?).to be_truthy
240
+ end
241
+ end
242
+ end
243
+
244
+ context "when 'environment' is a Symbol" do
245
+ context "and when 'ignore_environments' contains Strings" do
246
+ it "returns true" do
247
+ config.environment = :bango
248
+ config.ignore_environments = %w[bango]
249
+
250
+ expect(config.ignored_environment?).to be_truthy
251
+ end
252
+ end
253
+ end
254
+ end
255
+ end
256
+
257
+ describe "#endpoint" do
258
+ context "when host is configured with a URL with a slug" do
259
+ before do
260
+ config.project_id = 1
261
+ config.project_key = '2'
262
+ end
263
+
264
+ context "and with a trailing slash" do
265
+ it "sets the endpoint with the slug" do
266
+ config.host = 'https://localhost/bingo/'
267
+ expect(config.endpoint.to_s).
268
+ to eq('https://localhost/bingo/api/v3/projects/1/notices')
269
+ end
270
+ end
271
+
272
+ context "and without a trailing slash" do
273
+ it "sets the endpoint without the slug" do
274
+ config.host = 'https://localhost/bingo'
275
+ expect(config.endpoint.to_s).
276
+ to eq('https://localhost/api/v3/projects/1/notices')
277
+ end
278
+ end
279
+ end
280
+ end
281
+ end