airbrake-ruby 4.6.0 → 6.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.
- checksums.yaml +5 -5
- data/lib/airbrake-ruby/async_sender.rb +24 -109
- data/lib/airbrake-ruby/backlog.rb +123 -0
- data/lib/airbrake-ruby/backtrace.rb +8 -7
- data/lib/airbrake-ruby/benchmark.rb +1 -1
- data/lib/airbrake-ruby/code_hunk.rb +1 -1
- data/lib/airbrake-ruby/config/processor.rb +77 -0
- data/lib/airbrake-ruby/config/validator.rb +9 -3
- data/lib/airbrake-ruby/config.rb +78 -19
- data/lib/airbrake-ruby/context.rb +51 -0
- data/lib/airbrake-ruby/deploy_notifier.rb +1 -1
- data/lib/airbrake-ruby/file_cache.rb +6 -0
- data/lib/airbrake-ruby/filter_chain.rb +18 -1
- data/lib/airbrake-ruby/filters/context_filter.rb +4 -5
- data/lib/airbrake-ruby/filters/dependency_filter.rb +1 -0
- data/lib/airbrake-ruby/filters/exception_attributes_filter.rb +3 -3
- data/lib/airbrake-ruby/filters/gem_root_filter.rb +1 -0
- data/lib/airbrake-ruby/filters/git_last_checkout_filter.rb +7 -7
- data/lib/airbrake-ruby/filters/git_repository_filter.rb +11 -2
- data/lib/airbrake-ruby/filters/git_revision_filter.rb +3 -1
- data/lib/airbrake-ruby/filters/{keys_whitelist.rb → keys_allowlist.rb} +3 -3
- data/lib/airbrake-ruby/filters/{keys_blacklist.rb → keys_blocklist.rb} +3 -3
- data/lib/airbrake-ruby/filters/keys_filter.rb +41 -22
- data/lib/airbrake-ruby/filters/root_directory_filter.rb +1 -0
- data/lib/airbrake-ruby/filters/sql_filter.rb +35 -11
- data/lib/airbrake-ruby/filters/system_exit_filter.rb +1 -0
- data/lib/airbrake-ruby/filters/thread_filter.rb +6 -5
- data/lib/airbrake-ruby/grouppable.rb +12 -0
- data/lib/airbrake-ruby/ignorable.rb +1 -2
- data/lib/airbrake-ruby/inspectable.rb +2 -2
- data/lib/airbrake-ruby/loggable.rb +1 -1
- data/lib/airbrake-ruby/mergeable.rb +12 -0
- data/lib/airbrake-ruby/monotonic_time.rb +6 -1
- data/lib/airbrake-ruby/nested_exception.rb +22 -1
- data/lib/airbrake-ruby/notice.rb +12 -17
- data/lib/airbrake-ruby/notice_notifier.rb +15 -7
- data/lib/airbrake-ruby/performance_breakdown.rb +16 -9
- data/lib/airbrake-ruby/performance_notifier.rb +106 -54
- data/lib/airbrake-ruby/promise.rb +1 -0
- data/lib/airbrake-ruby/query.rb +20 -14
- data/lib/airbrake-ruby/queue.rb +65 -0
- data/lib/airbrake-ruby/remote_settings/callback.rb +44 -0
- data/lib/airbrake-ruby/remote_settings/settings_data.rb +116 -0
- data/lib/airbrake-ruby/remote_settings.rb +128 -0
- data/lib/airbrake-ruby/request.rb +14 -11
- data/lib/airbrake-ruby/response.rb +56 -5
- data/lib/airbrake-ruby/stat.rb +27 -34
- data/lib/airbrake-ruby/sync_sender.rb +43 -11
- data/lib/airbrake-ruby/tdigest.rb +52 -66
- data/lib/airbrake-ruby/thread_pool.rb +139 -0
- data/lib/airbrake-ruby/time_truncate.rb +2 -2
- data/lib/airbrake-ruby/timed_trace.rb +1 -3
- data/lib/airbrake-ruby/truncator.rb +10 -4
- data/lib/airbrake-ruby/version.rb +11 -1
- data/lib/airbrake-ruby.rb +157 -78
- metadata +122 -116
- data/spec/airbrake_spec.rb +0 -324
- data/spec/async_sender_spec.rb +0 -155
- data/spec/backtrace_spec.rb +0 -427
- data/spec/benchmark_spec.rb +0 -33
- data/spec/code_hunk_spec.rb +0 -115
- data/spec/config/validator_spec.rb +0 -184
- data/spec/config_spec.rb +0 -154
- data/spec/deploy_notifier_spec.rb +0 -48
- data/spec/file_cache.rb +0 -36
- data/spec/filter_chain_spec.rb +0 -92
- data/spec/filters/context_filter_spec.rb +0 -23
- data/spec/filters/dependency_filter_spec.rb +0 -12
- data/spec/filters/exception_attributes_filter_spec.rb +0 -50
- data/spec/filters/gem_root_filter_spec.rb +0 -41
- data/spec/filters/git_last_checkout_filter_spec.rb +0 -46
- data/spec/filters/git_repository_filter.rb +0 -61
- data/spec/filters/git_revision_filter_spec.rb +0 -126
- data/spec/filters/keys_blacklist_spec.rb +0 -225
- data/spec/filters/keys_whitelist_spec.rb +0 -194
- data/spec/filters/root_directory_filter_spec.rb +0 -39
- data/spec/filters/sql_filter_spec.rb +0 -219
- data/spec/filters/system_exit_filter_spec.rb +0 -14
- data/spec/filters/thread_filter_spec.rb +0 -277
- data/spec/fixtures/notroot.txt +0 -7
- data/spec/fixtures/project_root/code.rb +0 -221
- data/spec/fixtures/project_root/empty_file.rb +0 -0
- data/spec/fixtures/project_root/long_line.txt +0 -1
- data/spec/fixtures/project_root/short_file.rb +0 -3
- data/spec/fixtures/project_root/vendor/bundle/ignored_file.rb +0 -5
- data/spec/helpers.rb +0 -9
- data/spec/ignorable_spec.rb +0 -14
- data/spec/inspectable_spec.rb +0 -45
- data/spec/monotonic_time_spec.rb +0 -12
- data/spec/nested_exception_spec.rb +0 -73
- data/spec/notice_notifier_spec/options_spec.rb +0 -259
- data/spec/notice_notifier_spec.rb +0 -356
- data/spec/notice_spec.rb +0 -296
- data/spec/performance_breakdown_spec.rb +0 -12
- data/spec/performance_notifier_spec.rb +0 -435
- data/spec/promise_spec.rb +0 -197
- data/spec/query_spec.rb +0 -11
- data/spec/request_spec.rb +0 -11
- data/spec/response_spec.rb +0 -88
- data/spec/spec_helper.rb +0 -100
- data/spec/stashable_spec.rb +0 -23
- data/spec/stat_spec.rb +0 -47
- data/spec/sync_sender_spec.rb +0 -133
- data/spec/tdigest_spec.rb +0 -230
- data/spec/time_truncate_spec.rb +0 -13
- data/spec/timed_trace_spec.rb +0 -125
- data/spec/truncator_spec.rb +0 -238
|
@@ -1,259 +0,0 @@
|
|
|
1
|
-
RSpec.describe Airbrake::NoticeNotifier do
|
|
2
|
-
let(:project_id) { 105138 }
|
|
3
|
-
let(:project_key) { 'fd04e13d806a90f96614ad8e529b2822' }
|
|
4
|
-
let(:localhost) { 'http://localhost:8080' }
|
|
5
|
-
|
|
6
|
-
let(:endpoint) do
|
|
7
|
-
"https://api.airbrake.io/api/v3/projects/#{project_id}/notices"
|
|
8
|
-
end
|
|
9
|
-
|
|
10
|
-
let(:params) { {} }
|
|
11
|
-
let(:ex) { AirbrakeTestError.new }
|
|
12
|
-
|
|
13
|
-
before do
|
|
14
|
-
stub_request(:post, endpoint).to_return(status: 201, body: '{}')
|
|
15
|
-
|
|
16
|
-
Airbrake::Config.instance = Airbrake::Config.new(
|
|
17
|
-
project_id: project_id,
|
|
18
|
-
project_key: project_key
|
|
19
|
-
)
|
|
20
|
-
end
|
|
21
|
-
|
|
22
|
-
describe "options" do
|
|
23
|
-
describe ":host" do
|
|
24
|
-
context "when custom" do
|
|
25
|
-
shared_examples 'endpoint' do |host, endpoint, title|
|
|
26
|
-
before { Airbrake::Config.instance.merge(host: host) }
|
|
27
|
-
|
|
28
|
-
example(title) do
|
|
29
|
-
stub_request(:post, endpoint).to_return(status: 201, body: '{}')
|
|
30
|
-
subject.notify_sync(ex)
|
|
31
|
-
|
|
32
|
-
expect(a_request(:post, endpoint)).to have_been_made.once
|
|
33
|
-
end
|
|
34
|
-
end
|
|
35
|
-
|
|
36
|
-
path = '/api/v3/projects/105138/notices'
|
|
37
|
-
|
|
38
|
-
context "given a full host" do
|
|
39
|
-
include_examples('endpoint', localhost = 'http://localhost:8080',
|
|
40
|
-
URI.join(localhost, path),
|
|
41
|
-
"sends notices to the specified host's endpoint")
|
|
42
|
-
end
|
|
43
|
-
|
|
44
|
-
context "given a full host" do
|
|
45
|
-
include_examples('endpoint', localhost = 'http://localhost',
|
|
46
|
-
URI.join(localhost, path),
|
|
47
|
-
"assumes port 80 by default")
|
|
48
|
-
end
|
|
49
|
-
|
|
50
|
-
context "given a host without scheme" do
|
|
51
|
-
include_examples 'endpoint', localhost = 'localhost:8080',
|
|
52
|
-
URI.join("https://#{localhost}", path),
|
|
53
|
-
"assumes https by default"
|
|
54
|
-
end
|
|
55
|
-
|
|
56
|
-
context "given only hostname" do
|
|
57
|
-
include_examples 'endpoint', localhost = 'localhost',
|
|
58
|
-
URI.join("https://#{localhost}", path),
|
|
59
|
-
"assumes https and port 80 by default"
|
|
60
|
-
end
|
|
61
|
-
end
|
|
62
|
-
end
|
|
63
|
-
|
|
64
|
-
describe ":root_directory" do
|
|
65
|
-
before do
|
|
66
|
-
subject.add_filter(
|
|
67
|
-
Airbrake::Filters::RootDirectoryFilter.new('/home/kyrylo/code')
|
|
68
|
-
)
|
|
69
|
-
end
|
|
70
|
-
|
|
71
|
-
it "filters out frames" do
|
|
72
|
-
subject.notify_sync(ex)
|
|
73
|
-
|
|
74
|
-
expect(
|
|
75
|
-
a_request(:post, endpoint)
|
|
76
|
-
.with(body: %r|{"file":"/PROJECT_ROOT/airbrake/ruby/spec/airbrake_spec.+|)
|
|
77
|
-
).to have_been_made.once
|
|
78
|
-
end
|
|
79
|
-
|
|
80
|
-
context "when present and is a" do
|
|
81
|
-
shared_examples 'root directory' do |dir|
|
|
82
|
-
before { Airbrake::Config.instance.merge(root_directory: dir) }
|
|
83
|
-
|
|
84
|
-
it "being included into the notice's payload" do
|
|
85
|
-
subject.notify_sync(ex)
|
|
86
|
-
expect(
|
|
87
|
-
a_request(:post, endpoint)
|
|
88
|
-
.with(body: %r{"rootDirectory":"/bingo/bango"})
|
|
89
|
-
).to have_been_made.once
|
|
90
|
-
end
|
|
91
|
-
end
|
|
92
|
-
|
|
93
|
-
context "String" do
|
|
94
|
-
include_examples 'root directory', '/bingo/bango'
|
|
95
|
-
end
|
|
96
|
-
|
|
97
|
-
context "Pathname" do
|
|
98
|
-
include_examples 'root directory', Pathname.new('/bingo/bango')
|
|
99
|
-
end
|
|
100
|
-
end
|
|
101
|
-
end
|
|
102
|
-
|
|
103
|
-
describe ":proxy" do
|
|
104
|
-
let(:proxy) do
|
|
105
|
-
WEBrick::HTTPServer.new(
|
|
106
|
-
Port: 0,
|
|
107
|
-
Logger: WEBrick::Log.new('/dev/null'),
|
|
108
|
-
AccessLog: []
|
|
109
|
-
)
|
|
110
|
-
end
|
|
111
|
-
|
|
112
|
-
let(:requests) { Queue.new }
|
|
113
|
-
|
|
114
|
-
let(:proxy_params) do
|
|
115
|
-
{ host: 'localhost',
|
|
116
|
-
port: proxy.config[:Port],
|
|
117
|
-
user: 'user',
|
|
118
|
-
password: 'password' }
|
|
119
|
-
end
|
|
120
|
-
|
|
121
|
-
before do
|
|
122
|
-
Airbrake::Config.instance.merge(
|
|
123
|
-
proxy: proxy_params,
|
|
124
|
-
host: "http://localhost:#{proxy.config[:Port]}"
|
|
125
|
-
)
|
|
126
|
-
|
|
127
|
-
proxy.mount_proc '/' do |req, res|
|
|
128
|
-
requests << req
|
|
129
|
-
res.status = 201
|
|
130
|
-
res.body = "OK\n"
|
|
131
|
-
end
|
|
132
|
-
|
|
133
|
-
Thread.new { proxy.start }
|
|
134
|
-
end
|
|
135
|
-
|
|
136
|
-
after { proxy.stop }
|
|
137
|
-
|
|
138
|
-
it "is being used if configured" do
|
|
139
|
-
if Gem::Version.new(RUBY_VERSION) >= Gem::Version.new("2.6.0")
|
|
140
|
-
skip(
|
|
141
|
-
"We use Webmock 2, which doesn't support Ruby 2.6+. It's " \
|
|
142
|
-
"safe to run this test on 2.6+ once we upgrade to Webmock 3.5+"
|
|
143
|
-
)
|
|
144
|
-
end
|
|
145
|
-
subject.notify_sync(ex)
|
|
146
|
-
|
|
147
|
-
proxied_request = requests.pop(true)
|
|
148
|
-
|
|
149
|
-
expect(proxied_request.header['proxy-authorization'].first)
|
|
150
|
-
.to eq('Basic dXNlcjpwYXNzd29yZA==')
|
|
151
|
-
|
|
152
|
-
# rubocop:disable Metrics/LineLength
|
|
153
|
-
expect(proxied_request.request_line)
|
|
154
|
-
.to eq("POST http://localhost:#{proxy.config[:Port]}/api/v3/projects/105138/notices HTTP/1.1\r\n")
|
|
155
|
-
# rubocop:enable Metrics/LineLength
|
|
156
|
-
end
|
|
157
|
-
end
|
|
158
|
-
|
|
159
|
-
describe ":environment" do
|
|
160
|
-
context "when present" do
|
|
161
|
-
before { Airbrake::Config.instance.merge(environment: :production) }
|
|
162
|
-
|
|
163
|
-
it "being included into the notice's payload" do
|
|
164
|
-
subject.notify_sync(ex)
|
|
165
|
-
expect(
|
|
166
|
-
a_request(:post, endpoint)
|
|
167
|
-
.with(body: /"context":{.*"environment":"production".*}/)
|
|
168
|
-
).to have_been_made.once
|
|
169
|
-
end
|
|
170
|
-
end
|
|
171
|
-
end
|
|
172
|
-
|
|
173
|
-
describe ":ignore_environments" do
|
|
174
|
-
shared_examples 'sent notice' do |params|
|
|
175
|
-
before { Airbrake::Config.instance.merge(params) }
|
|
176
|
-
|
|
177
|
-
it "sends a notice" do
|
|
178
|
-
subject.notify_sync(ex)
|
|
179
|
-
expect(a_request(:post, endpoint)).to have_been_made
|
|
180
|
-
end
|
|
181
|
-
end
|
|
182
|
-
|
|
183
|
-
shared_examples 'ignored notice' do |params|
|
|
184
|
-
before { Airbrake::Config.instance.merge(params) }
|
|
185
|
-
|
|
186
|
-
it "ignores exceptions occurring in envs that were not configured" do
|
|
187
|
-
subject.notify_sync(ex)
|
|
188
|
-
expect(a_request(:post, endpoint)).not_to have_been_made
|
|
189
|
-
end
|
|
190
|
-
end
|
|
191
|
-
|
|
192
|
-
context "when env is set and ignore_environments doesn't mention it" do
|
|
193
|
-
params = {
|
|
194
|
-
environment: :development,
|
|
195
|
-
ignore_environments: [:production]
|
|
196
|
-
}
|
|
197
|
-
|
|
198
|
-
include_examples 'sent notice', params
|
|
199
|
-
end
|
|
200
|
-
|
|
201
|
-
context "when the current env and notify envs are the same" do
|
|
202
|
-
params = {
|
|
203
|
-
environment: :development,
|
|
204
|
-
ignore_environments: %i[production development]
|
|
205
|
-
}
|
|
206
|
-
|
|
207
|
-
include_examples 'ignored notice', params
|
|
208
|
-
|
|
209
|
-
it "returns early and doesn't try to parse the given exception" do
|
|
210
|
-
expect(Airbrake::Notice).not_to receive(:new)
|
|
211
|
-
expect(subject.notify_sync(ex))
|
|
212
|
-
.to eq('error' => "current environment 'development' is ignored")
|
|
213
|
-
expect(a_request(:post, endpoint)).not_to have_been_made
|
|
214
|
-
end
|
|
215
|
-
end
|
|
216
|
-
|
|
217
|
-
context "when the current env is not set and notify envs are present" do
|
|
218
|
-
params = { ignore_environments: %i[production development] }
|
|
219
|
-
|
|
220
|
-
include_examples 'sent notice', params
|
|
221
|
-
end
|
|
222
|
-
|
|
223
|
-
context "when the current env is set and notify envs aren't" do
|
|
224
|
-
include_examples 'sent notice', environment: :development
|
|
225
|
-
end
|
|
226
|
-
|
|
227
|
-
context "when ignore_environments specifies a Regexp pattern" do
|
|
228
|
-
params = {
|
|
229
|
-
environment: :testing,
|
|
230
|
-
ignore_environments: ['staging', /test.+/]
|
|
231
|
-
}
|
|
232
|
-
|
|
233
|
-
include_examples 'ignored notice', params
|
|
234
|
-
end
|
|
235
|
-
end
|
|
236
|
-
|
|
237
|
-
describe ":blacklist_keys" do
|
|
238
|
-
# Fixes https://github.com/airbrake/airbrake-ruby/issues/276
|
|
239
|
-
context "when specified along with :whitelist_keys" do
|
|
240
|
-
context "and when context payload is present" do
|
|
241
|
-
before do
|
|
242
|
-
Airbrake::Config.instance.merge(
|
|
243
|
-
blacklist_keys: %i[password password_confirmation],
|
|
244
|
-
whitelist_keys: [:email, /user/i, 'account_id']
|
|
245
|
-
)
|
|
246
|
-
end
|
|
247
|
-
|
|
248
|
-
it "sends a notice" do
|
|
249
|
-
notice = subject.build_notice(ex)
|
|
250
|
-
notice[:context][:headers] = 'banana'
|
|
251
|
-
subject.notify_sync(notice)
|
|
252
|
-
|
|
253
|
-
expect(a_request(:post, endpoint)).to have_been_made
|
|
254
|
-
end
|
|
255
|
-
end
|
|
256
|
-
end
|
|
257
|
-
end
|
|
258
|
-
end
|
|
259
|
-
end
|
|
@@ -1,356 +0,0 @@
|
|
|
1
|
-
RSpec.describe Airbrake::NoticeNotifier do
|
|
2
|
-
before do
|
|
3
|
-
Airbrake::Config.instance = Airbrake::Config.new(
|
|
4
|
-
project_id: 1,
|
|
5
|
-
project_key: 'abc',
|
|
6
|
-
logger: Logger.new('/dev/null'),
|
|
7
|
-
performance_stats: true
|
|
8
|
-
)
|
|
9
|
-
end
|
|
10
|
-
|
|
11
|
-
describe "#new" do
|
|
12
|
-
describe "default filter addition" do
|
|
13
|
-
before { allow_any_instance_of(Airbrake::FilterChain).to receive(:add_filter) }
|
|
14
|
-
|
|
15
|
-
it "appends the context filter" do
|
|
16
|
-
expect_any_instance_of(Airbrake::FilterChain).to receive(:add_filter)
|
|
17
|
-
.with(instance_of(Airbrake::Filters::ContextFilter))
|
|
18
|
-
subject
|
|
19
|
-
end
|
|
20
|
-
|
|
21
|
-
it "appends the exception attributes filter" do
|
|
22
|
-
expect_any_instance_of(Airbrake::FilterChain).to receive(:add_filter)
|
|
23
|
-
.with(instance_of(Airbrake::Filters::ExceptionAttributesFilter))
|
|
24
|
-
subject
|
|
25
|
-
end
|
|
26
|
-
end
|
|
27
|
-
end
|
|
28
|
-
|
|
29
|
-
describe "#notify" do
|
|
30
|
-
let(:endpoint) { 'https://api.airbrake.io/api/v3/projects/1/notices' }
|
|
31
|
-
|
|
32
|
-
let(:body) do
|
|
33
|
-
{
|
|
34
|
-
'id' => '00054414-b147-6ffa-85d6-1524d83362a6',
|
|
35
|
-
'url' => 'http://localhost/locate/00054414-b147-6ffa-85d6-1524d83362a6'
|
|
36
|
-
}.to_json
|
|
37
|
-
end
|
|
38
|
-
|
|
39
|
-
before { stub_request(:post, endpoint).to_return(status: 201, body: body) }
|
|
40
|
-
|
|
41
|
-
it "returns a promise" do
|
|
42
|
-
expect(subject.notify('ex')).to be_an(Airbrake::Promise)
|
|
43
|
-
sleep 1
|
|
44
|
-
end
|
|
45
|
-
|
|
46
|
-
it "refines the notice object" do
|
|
47
|
-
subject.add_filter { |n| n[:params] = { foo: 'bar' } }
|
|
48
|
-
notice = subject.build_notice('ex')
|
|
49
|
-
subject.notify(notice)
|
|
50
|
-
expect(notice[:params]).to eq(foo: 'bar')
|
|
51
|
-
sleep 1
|
|
52
|
-
end
|
|
53
|
-
|
|
54
|
-
context "when config is invalid" do
|
|
55
|
-
before { Airbrake::Config.instance.merge(project_id: nil) }
|
|
56
|
-
|
|
57
|
-
it "returns a rejected promise" do
|
|
58
|
-
promise = subject.notify({})
|
|
59
|
-
expect(promise).to be_rejected
|
|
60
|
-
end
|
|
61
|
-
end
|
|
62
|
-
|
|
63
|
-
context "when a notice is not ignored" do
|
|
64
|
-
it "yields the notice" do
|
|
65
|
-
expect { |b| subject.notify('ex', &b) }
|
|
66
|
-
.to yield_with_args(Airbrake::Notice)
|
|
67
|
-
sleep 1
|
|
68
|
-
end
|
|
69
|
-
end
|
|
70
|
-
|
|
71
|
-
context "when a notice is ignored via a filter" do
|
|
72
|
-
before { subject.add_filter(&:ignore!) }
|
|
73
|
-
|
|
74
|
-
it "yields the notice" do
|
|
75
|
-
expect { |b| subject.notify('ex', &b) }
|
|
76
|
-
.to yield_with_args(Airbrake::Notice)
|
|
77
|
-
end
|
|
78
|
-
|
|
79
|
-
it "returns a rejected promise" do
|
|
80
|
-
value = subject.notify('ex').value
|
|
81
|
-
expect(value['error']).to match(/was marked as ignored/)
|
|
82
|
-
end
|
|
83
|
-
end
|
|
84
|
-
|
|
85
|
-
context "when a notice is ignored via an inline filter" do
|
|
86
|
-
before { subject.add_filter { raise AirbrakeTestError } }
|
|
87
|
-
|
|
88
|
-
it "doesn't invoke regular filters" do
|
|
89
|
-
expect { subject.notify('ex', &:ignore!) }.not_to raise_error
|
|
90
|
-
end
|
|
91
|
-
end
|
|
92
|
-
|
|
93
|
-
context "when async sender has workers" do
|
|
94
|
-
it "sends an exception asynchronously" do
|
|
95
|
-
expect_any_instance_of(Airbrake::AsyncSender).to receive(:send)
|
|
96
|
-
subject.notify('foo', bingo: 'bango')
|
|
97
|
-
end
|
|
98
|
-
end
|
|
99
|
-
|
|
100
|
-
context "when async sender doesn't have workers" do
|
|
101
|
-
it "sends an exception synchronously" do
|
|
102
|
-
expect_any_instance_of(Airbrake::AsyncSender)
|
|
103
|
-
.to receive(:has_workers?).and_return(false)
|
|
104
|
-
expect_any_instance_of(Airbrake::SyncSender).to receive(:send)
|
|
105
|
-
subject.notify('foo', bingo: 'bango')
|
|
106
|
-
end
|
|
107
|
-
end
|
|
108
|
-
|
|
109
|
-
context "when the provided environment is ignored" do
|
|
110
|
-
before do
|
|
111
|
-
Airbrake::Config.instance.merge(
|
|
112
|
-
environment: 'test',
|
|
113
|
-
ignore_environments: %w[test]
|
|
114
|
-
)
|
|
115
|
-
end
|
|
116
|
-
|
|
117
|
-
it "doesn't send an notice" do
|
|
118
|
-
expect_any_instance_of(Airbrake::AsyncSender).not_to receive(:send)
|
|
119
|
-
subject.notify('foo', bingo: 'bango')
|
|
120
|
-
end
|
|
121
|
-
|
|
122
|
-
it "returns a rejected promise" do
|
|
123
|
-
promise = subject.notify('foo', bingo: 'bango')
|
|
124
|
-
expect(promise.value).to eq('error' => "current environment 'test' is ignored")
|
|
125
|
-
end
|
|
126
|
-
end
|
|
127
|
-
end
|
|
128
|
-
|
|
129
|
-
describe "#notify_sync" do
|
|
130
|
-
let(:endpoint) { 'https://api.airbrake.io/api/v3/projects/1/notices' }
|
|
131
|
-
|
|
132
|
-
let(:body) do
|
|
133
|
-
{
|
|
134
|
-
'id' => '00054414-b147-6ffa-85d6-1524d83362a6',
|
|
135
|
-
'url' => 'http://localhost/locate/00054414-b147-6ffa-85d6-1524d83362a6'
|
|
136
|
-
}
|
|
137
|
-
end
|
|
138
|
-
|
|
139
|
-
before { stub_request(:post, endpoint).to_return(status: 201, body: body.to_json) }
|
|
140
|
-
|
|
141
|
-
it "returns a reponse hash" do
|
|
142
|
-
expect(subject.notify_sync('ex')).to eq(body)
|
|
143
|
-
end
|
|
144
|
-
|
|
145
|
-
it "refines the notice object" do
|
|
146
|
-
subject.add_filter { |n| n[:params] = { foo: 'bar' } }
|
|
147
|
-
notice = subject.build_notice('ex')
|
|
148
|
-
subject.notify_sync(notice)
|
|
149
|
-
expect(notice[:params]).to eq(foo: 'bar')
|
|
150
|
-
end
|
|
151
|
-
|
|
152
|
-
it "sends an exception synchronously" do
|
|
153
|
-
subject.notify_sync('foo', bingo: 'bango')
|
|
154
|
-
expect(
|
|
155
|
-
a_request(:post, endpoint).with(
|
|
156
|
-
body: /"params":{.*"bingo":"bango".*}/
|
|
157
|
-
)
|
|
158
|
-
).to have_been_made.once
|
|
159
|
-
end
|
|
160
|
-
|
|
161
|
-
context "when a notice is not ignored" do
|
|
162
|
-
it "yields the notice" do
|
|
163
|
-
expect { |b| subject.notify_sync('ex', &b) }
|
|
164
|
-
.to yield_with_args(Airbrake::Notice)
|
|
165
|
-
end
|
|
166
|
-
end
|
|
167
|
-
|
|
168
|
-
context "when a notice is ignored via a filter" do
|
|
169
|
-
before { subject.add_filter(&:ignore!) }
|
|
170
|
-
|
|
171
|
-
it "yields the notice" do
|
|
172
|
-
expect { |b| subject.notify_sync('ex', &b) }
|
|
173
|
-
.to yield_with_args(Airbrake::Notice)
|
|
174
|
-
end
|
|
175
|
-
|
|
176
|
-
it "returns an error hash" do
|
|
177
|
-
response = subject.notify_sync('ex')
|
|
178
|
-
expect(response['error']).to match(/was marked as ignored/)
|
|
179
|
-
end
|
|
180
|
-
end
|
|
181
|
-
|
|
182
|
-
context "when a notice is ignored via an inline filter" do
|
|
183
|
-
before { subject.add_filter { raise AirbrakeTestError } }
|
|
184
|
-
|
|
185
|
-
it "doesn't invoke regular filters" do
|
|
186
|
-
expect { subject.notify('ex', &:ignore!) }.not_to raise_error
|
|
187
|
-
end
|
|
188
|
-
end
|
|
189
|
-
|
|
190
|
-
context "when the provided environment is ignored" do
|
|
191
|
-
before do
|
|
192
|
-
Airbrake::Config.instance.merge(
|
|
193
|
-
environment: 'test', ignore_environments: %w[test]
|
|
194
|
-
)
|
|
195
|
-
end
|
|
196
|
-
|
|
197
|
-
it "doesn't send an notice" do
|
|
198
|
-
expect_any_instance_of(Airbrake::SyncSender).not_to receive(:send)
|
|
199
|
-
subject.notify_sync('foo', bingo: 'bango')
|
|
200
|
-
end
|
|
201
|
-
|
|
202
|
-
it "returns an error hash" do
|
|
203
|
-
expect(subject.notify_sync('foo'))
|
|
204
|
-
.to eq('error' => "current environment 'test' is ignored")
|
|
205
|
-
end
|
|
206
|
-
end
|
|
207
|
-
end
|
|
208
|
-
|
|
209
|
-
describe "#add_filter" do
|
|
210
|
-
context "given a block" do
|
|
211
|
-
it "appends a new filter to the filter chain" do
|
|
212
|
-
notifier = subject
|
|
213
|
-
b = proc {}
|
|
214
|
-
expect_any_instance_of(Airbrake::FilterChain)
|
|
215
|
-
.to receive(:add_filter) { |*args| expect(args.last).to be(b) }
|
|
216
|
-
notifier.add_filter(&b)
|
|
217
|
-
end
|
|
218
|
-
end
|
|
219
|
-
|
|
220
|
-
context "given a class" do
|
|
221
|
-
it "appends a new filter to the filter chain" do
|
|
222
|
-
notifier = subject
|
|
223
|
-
klass = Class.new
|
|
224
|
-
expect_any_instance_of(Airbrake::FilterChain)
|
|
225
|
-
.to receive(:add_filter).with(klass)
|
|
226
|
-
notifier.add_filter(klass)
|
|
227
|
-
end
|
|
228
|
-
end
|
|
229
|
-
end
|
|
230
|
-
|
|
231
|
-
describe "#build_notice" do
|
|
232
|
-
context "when given exception is another notice" do
|
|
233
|
-
it "merges params with the notice" do
|
|
234
|
-
notice = subject.build_notice('ex')
|
|
235
|
-
other = subject.build_notice(notice, foo: 'bar')
|
|
236
|
-
expect(other[:params]).to eq(foo: 'bar')
|
|
237
|
-
end
|
|
238
|
-
|
|
239
|
-
it "it returns the provided notice" do
|
|
240
|
-
notice = subject.build_notice('ex')
|
|
241
|
-
other = subject.build_notice(notice, foo: 'bar')
|
|
242
|
-
expect(other).to eq(notice)
|
|
243
|
-
end
|
|
244
|
-
end
|
|
245
|
-
|
|
246
|
-
context "when given exception is an Exception" do
|
|
247
|
-
it "prevents mutation of passed-in params hash" do
|
|
248
|
-
params = { immutable: true }
|
|
249
|
-
notice = subject.build_notice('ex', params)
|
|
250
|
-
notice[:params][:mutable] = true
|
|
251
|
-
expect(params).to eq(immutable: true)
|
|
252
|
-
end
|
|
253
|
-
|
|
254
|
-
context "and also when it doesn't have own backtrace" do
|
|
255
|
-
context "and when the generated backtrace consists only of library frames" do
|
|
256
|
-
it "returns the full generated backtrace" do
|
|
257
|
-
backtrace = [
|
|
258
|
-
"/lib/airbrake-ruby/a.rb:84:in `build_notice'",
|
|
259
|
-
"/lib/airbrake-ruby/b.rb:124:in `send_notice'"
|
|
260
|
-
]
|
|
261
|
-
allow(Kernel).to receive(:caller).and_return(backtrace)
|
|
262
|
-
|
|
263
|
-
notice = subject.build_notice(Exception.new)
|
|
264
|
-
|
|
265
|
-
expect(notice[:errors].first[:backtrace]).to eq(
|
|
266
|
-
[
|
|
267
|
-
{ file: '/lib/airbrake-ruby/a.rb', line: 84, function: 'build_notice' },
|
|
268
|
-
{ file: '/lib/airbrake-ruby/b.rb', line: 124, function: 'send_notice' }
|
|
269
|
-
]
|
|
270
|
-
)
|
|
271
|
-
end
|
|
272
|
-
end
|
|
273
|
-
|
|
274
|
-
context "and when the generated backtrace consists of mixed frames" do
|
|
275
|
-
it "returns the filtered backtrace" do
|
|
276
|
-
backtrace = [
|
|
277
|
-
"/airbrake-ruby/lib/airbrake-ruby/a.rb:84:in `b'",
|
|
278
|
-
"/airbrake-ruby/lib/foo/b.rb:84:in `build'",
|
|
279
|
-
"/airbrake-ruby/lib/bar/c.rb:124:in `send'"
|
|
280
|
-
]
|
|
281
|
-
allow(Kernel).to receive(:caller).and_return(backtrace)
|
|
282
|
-
|
|
283
|
-
notice = subject.build_notice(Exception.new)
|
|
284
|
-
|
|
285
|
-
expect(notice[:errors].first[:backtrace]).to eq(
|
|
286
|
-
[
|
|
287
|
-
{ file: '/airbrake-ruby/lib/foo/b.rb', line: 84, function: 'build' },
|
|
288
|
-
{ file: '/airbrake-ruby/lib/bar/c.rb', line: 124, function: 'send' }
|
|
289
|
-
]
|
|
290
|
-
)
|
|
291
|
-
end
|
|
292
|
-
end
|
|
293
|
-
end
|
|
294
|
-
end
|
|
295
|
-
|
|
296
|
-
# TODO: this seems to be bugged. Fix later.
|
|
297
|
-
context "when given exception is a Java exception", skip: true do
|
|
298
|
-
before do
|
|
299
|
-
expect(Airbrake::Backtrace).to receive(:java_exception?).and_return(true)
|
|
300
|
-
end
|
|
301
|
-
|
|
302
|
-
it "automatically generates the backtrace" do
|
|
303
|
-
backtrace = [
|
|
304
|
-
"org/jruby/RubyKernel.java:998:in `eval'",
|
|
305
|
-
"/ruby/stdlib/irb/workspace.rb:87:in `evaluate'",
|
|
306
|
-
"/ruby/stdlib/irb.rb:489:in `block in eval_input'"
|
|
307
|
-
]
|
|
308
|
-
allow(Kernel).to receive(:caller).and_return(backtrace)
|
|
309
|
-
|
|
310
|
-
notice = subject.build_notice(Exception.new)
|
|
311
|
-
|
|
312
|
-
# rubocop:disable Metrics/LineLength
|
|
313
|
-
expect(notice[:errors].first[:backtrace]).to eq(
|
|
314
|
-
[
|
|
315
|
-
{ file: 'org/jruby/RubyKernel.java', line: 998, function: 'eval' },
|
|
316
|
-
{ file: '/ruby/stdlib/irb/workspace.rb', line: 87, function: 'evaluate' },
|
|
317
|
-
{ file: '/ruby/stdlib/irb.rb:489', line: 489, function: 'block in eval_input' }
|
|
318
|
-
]
|
|
319
|
-
)
|
|
320
|
-
# rubocop:enable Metrics/LineLength
|
|
321
|
-
end
|
|
322
|
-
end
|
|
323
|
-
|
|
324
|
-
context "when async sender is closed" do
|
|
325
|
-
before do
|
|
326
|
-
expect_any_instance_of(Airbrake::AsyncSender)
|
|
327
|
-
.to receive(:closed?).and_return(true)
|
|
328
|
-
end
|
|
329
|
-
|
|
330
|
-
it "raises error" do
|
|
331
|
-
expect { subject.build_notice(Exception.new) }.to raise_error(
|
|
332
|
-
Airbrake::Error,
|
|
333
|
-
'attempted to build Exception with closed Airbrake instance'
|
|
334
|
-
)
|
|
335
|
-
end
|
|
336
|
-
end
|
|
337
|
-
end
|
|
338
|
-
|
|
339
|
-
describe "#close" do
|
|
340
|
-
it "sends the close message to async sender" do
|
|
341
|
-
expect_any_instance_of(Airbrake::AsyncSender).to receive(:close)
|
|
342
|
-
subject.close
|
|
343
|
-
end
|
|
344
|
-
end
|
|
345
|
-
|
|
346
|
-
describe "#configured?" do
|
|
347
|
-
it { is_expected.to be_configured }
|
|
348
|
-
end
|
|
349
|
-
|
|
350
|
-
describe "#merge_context" do
|
|
351
|
-
it "merges the provided context with the notice object" do
|
|
352
|
-
expect_any_instance_of(Hash).to receive(:merge!).with(apples: 'oranges')
|
|
353
|
-
subject.merge_context(apples: 'oranges')
|
|
354
|
-
end
|
|
355
|
-
end
|
|
356
|
-
end
|