airbrake-ruby 3.2.2-java

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