airbrake-ruby 5.2.0-java → 6.0.2-java

Sign up to get free protection for your applications and to get access to all the features.
Files changed (72) hide show
  1. checksums.yaml +4 -4
  2. data/lib/airbrake-ruby/async_sender.rb +3 -1
  3. data/lib/airbrake-ruby/config.rb +3 -3
  4. data/lib/airbrake-ruby/context.rb +51 -0
  5. data/lib/airbrake-ruby/filter_chain.rb +2 -0
  6. data/lib/airbrake-ruby/filters/context_filter.rb +4 -5
  7. data/lib/airbrake-ruby/filters/exception_attributes_filter.rb +1 -1
  8. data/lib/airbrake-ruby/filters/git_last_checkout_filter.rb +2 -2
  9. data/lib/airbrake-ruby/filters/git_repository_filter.rb +1 -1
  10. data/lib/airbrake-ruby/filters/git_revision_filter.rb +1 -1
  11. data/lib/airbrake-ruby/filters/keys_filter.rb +2 -2
  12. data/lib/airbrake-ruby/filters/sql_filter.rb +8 -8
  13. data/lib/airbrake-ruby/filters/thread_filter.rb +1 -1
  14. data/lib/airbrake-ruby/ignorable.rb +0 -2
  15. data/lib/airbrake-ruby/monotonic_time.rb +1 -1
  16. data/lib/airbrake-ruby/notice_notifier.rb +3 -4
  17. data/lib/airbrake-ruby/performance_notifier.rb +39 -40
  18. data/lib/airbrake-ruby/remote_settings/settings_data.rb +1 -1
  19. data/lib/airbrake-ruby/remote_settings.rb +26 -3
  20. data/lib/airbrake-ruby/stat.rb +1 -1
  21. data/lib/airbrake-ruby/tdigest.rb +10 -9
  22. data/lib/airbrake-ruby/thread_pool.rb +8 -6
  23. data/lib/airbrake-ruby/time_truncate.rb +2 -2
  24. data/lib/airbrake-ruby/timed_trace.rb +1 -3
  25. data/lib/airbrake-ruby/version.rb +1 -1
  26. data/lib/airbrake-ruby.rb +24 -23
  27. data/spec/airbrake_spec.rb +139 -76
  28. data/spec/async_sender_spec.rb +10 -8
  29. data/spec/backtrace_spec.rb +13 -10
  30. data/spec/benchmark_spec.rb +5 -3
  31. data/spec/code_hunk_spec.rb +24 -15
  32. data/spec/config/processor_spec.rb +12 -4
  33. data/spec/config/validator_spec.rb +5 -2
  34. data/spec/config_spec.rb +28 -20
  35. data/spec/context_spec.rb +54 -0
  36. data/spec/deploy_notifier_spec.rb +6 -4
  37. data/spec/file_cache_spec.rb +1 -0
  38. data/spec/filter_chain_spec.rb +29 -24
  39. data/spec/filters/context_filter_spec.rb +14 -5
  40. data/spec/filters/dependency_filter_spec.rb +3 -1
  41. data/spec/filters/exception_attributes_filter_spec.rb +5 -3
  42. data/spec/filters/gem_root_filter_spec.rb +5 -2
  43. data/spec/filters/git_last_checkout_filter_spec.rb +10 -12
  44. data/spec/filters/git_repository_filter.rb +9 -9
  45. data/spec/filters/git_revision_filter_spec.rb +20 -20
  46. data/spec/filters/keys_allowlist_spec.rb +25 -16
  47. data/spec/filters/keys_blocklist_spec.rb +25 -18
  48. data/spec/filters/root_directory_filter_spec.rb +3 -3
  49. data/spec/filters/sql_filter_spec.rb +26 -26
  50. data/spec/filters/system_exit_filter_spec.rb +4 -2
  51. data/spec/filters/thread_filter_spec.rb +15 -13
  52. data/spec/loggable_spec.rb +2 -2
  53. data/spec/monotonic_time_spec.rb +8 -6
  54. data/spec/nested_exception_spec.rb +46 -46
  55. data/spec/notice_notifier/options_spec.rb +23 -13
  56. data/spec/notice_notifier_spec.rb +52 -47
  57. data/spec/notice_spec.rb +6 -2
  58. data/spec/performance_notifier_spec.rb +69 -62
  59. data/spec/promise_spec.rb +38 -32
  60. data/spec/remote_settings/callback_spec.rb +27 -8
  61. data/spec/remote_settings/settings_data_spec.rb +4 -4
  62. data/spec/remote_settings_spec.rb +23 -9
  63. data/spec/response_spec.rb +34 -12
  64. data/spec/stashable_spec.rb +5 -5
  65. data/spec/stat_spec.rb +7 -5
  66. data/spec/sync_sender_spec.rb +49 -16
  67. data/spec/tdigest_spec.rb +60 -55
  68. data/spec/thread_pool_spec.rb +65 -56
  69. data/spec/time_truncate_spec.rb +23 -6
  70. data/spec/timed_trace_spec.rb +32 -30
  71. data/spec/truncator_spec.rb +72 -43
  72. metadata +54 -50
@@ -13,18 +13,20 @@ RSpec.describe Airbrake::AsyncSender do
13
13
  end
14
14
 
15
15
  describe "#send" do
16
+ subject(:async_sender) { described_class.new }
17
+
16
18
  context "when sender has the capacity to send" do
17
19
  it "sends notices to Airbrake" do
18
- 2.times { subject.send(notice, Airbrake::Promise.new) }
19
- subject.close
20
+ 2.times { async_sender.send(notice, Airbrake::Promise.new) }
21
+ async_sender.close
20
22
 
21
23
  expect(a_request(:post, endpoint)).to have_been_made.twice
22
24
  end
23
25
 
24
26
  it "returns a resolved promise" do
25
27
  promise = Airbrake::Promise.new
26
- subject.send(notice, promise)
27
- subject.close
28
+ async_sender.send(notice, promise)
29
+ async_sender.close
28
30
 
29
31
  expect(promise).to be_resolved
30
32
  end
@@ -40,8 +42,8 @@ RSpec.describe Airbrake::AsyncSender do
40
42
  end
41
43
 
42
44
  it "doesn't send the exceeded notices to Airbrake" do
43
- 15.times { subject.send(notice, Airbrake::Promise.new) }
44
- subject.close
45
+ 15.times { async_sender.send(notice, Airbrake::Promise.new) }
46
+ async_sender.close
45
47
 
46
48
  expect(a_request(:post, endpoint)).not_to have_been_made
47
49
  end
@@ -49,9 +51,9 @@ RSpec.describe Airbrake::AsyncSender do
49
51
  it "returns a rejected promise" do
50
52
  promise = nil
51
53
  15.times do
52
- promise = subject.send(notice, Airbrake::Promise.new)
54
+ promise = async_sender.send(notice, Airbrake::Promise.new)
53
55
  end
54
- subject.close
56
+ async_sender.close
55
57
 
56
58
  expect(promise).to be_rejected
57
59
  expect(promise.value).to eq(
@@ -177,10 +177,13 @@ RSpec.describe Airbrake::Backtrace do
177
177
  end
178
178
 
179
179
  it "logs frames that cannot be parsed" do
180
- expect(Airbrake::Loggable.instance).to receive(:error).with(
180
+ allow(Airbrake::Loggable.instance).to receive(:error)
181
+
182
+ described_class.parse(ex)
183
+
184
+ expect(Airbrake::Loggable.instance).to have_received(:error).with(
181
185
  /can't parse 'a b c 1 23 321 .rb'/,
182
186
  )
183
- described_class.parse(ex)
184
187
  end
185
188
  end
186
189
 
@@ -298,9 +301,9 @@ RSpec.describe Airbrake::Backtrace do
298
301
  it "attaches code to those frames files of which match root_directory" do
299
302
  ex = RuntimeError.new
300
303
  backtrace = [
301
- project_root_path('code.rb') + ":94:in `to_json'",
302
- fixture_path('notroot.txt' + ":3:in `pineapple'"),
303
- project_root_path('vendor/bundle/ignored_file.rb') + ":2:in `ignore_me'",
304
+ "#{project_root_path('code.rb')}:94:in `to_json'",
305
+ fixture_path("notroot.txt:3:in `pineapple'"),
306
+ "#{project_root_path('vendor/bundle/ignored_file.rb')}:2:in `ignore_me'",
304
307
  ]
305
308
  ex.set_backtrace(backtrace)
306
309
  expect(described_class.parse(ex)).to eq(parsed_backtrace)
@@ -335,7 +338,7 @@ RSpec.describe Airbrake::Backtrace do
335
338
 
336
339
  it "attaches code to those frames files of which match root_directory" do
337
340
  ex = RuntimeError.new
338
- ex.set_backtrace([project_root_path('code.rb') + ":94:in `to_json'"])
341
+ ex.set_backtrace(["#{project_root_path('code.rb')}:94:in `to_json'"])
339
342
  expect(described_class.parse(ex)).to eq(parsed_backtrace)
340
343
  end
341
344
  end
@@ -387,9 +390,9 @@ RSpec.describe Airbrake::Backtrace do
387
390
  it "attaches code to first N frames" do
388
391
  ex = RuntimeError.new
389
392
  backtrace = [
390
- project_root_path('code.rb') + ":94:in `to_json'",
391
- project_root_path('code.rb') + ":95:in `to_json'",
392
- project_root_path('code.rb') + ":96:in `to_json'",
393
+ "#{project_root_path('code.rb')}:94:in `to_json'",
394
+ "#{project_root_path('code.rb')}:95:in `to_json'",
395
+ "#{project_root_path('code.rb')}:96:in `to_json'",
393
396
  ]
394
397
  ex.set_backtrace(backtrace)
395
398
  expect(described_class.parse(ex)).to eq(parsed_backtrace)
@@ -417,7 +420,7 @@ RSpec.describe Airbrake::Backtrace do
417
420
 
418
421
  it "doesn't attach code to frames" do
419
422
  ex = RuntimeError.new
420
- backtrace = [project_root_path('code.rb') + ":94:in `to_json'"]
423
+ backtrace = ["#{project_root_path('code.rb')}:94:in `to_json'"]
421
424
  ex.set_backtrace(backtrace)
422
425
  expect(described_class.parse(ex)).to eq(parsed_backtrace)
423
426
  end
@@ -1,4 +1,6 @@
1
1
  RSpec.describe Airbrake::Benchmark do
2
+ subject(:benchmark) { described_class.new }
3
+
2
4
  describe ".measure" do
3
5
  it "returns measured performance time" do
4
6
  expect(described_class.measure { '10' * 10 }).to be_kind_of(Numeric)
@@ -6,14 +8,14 @@ RSpec.describe Airbrake::Benchmark do
6
8
  end
7
9
 
8
10
  describe "#stop" do
9
- before { subject }
11
+ before { benchmark }
10
12
 
11
13
  context "when called one time" do
12
14
  its(:stop) { is_expected.to eq(true) }
13
15
  end
14
16
 
15
17
  context "when called twice or more" do
16
- before { subject.stop }
18
+ before { benchmark.stop }
17
19
 
18
20
  its(:stop) { is_expected.to eq(false) }
19
21
  end
@@ -25,7 +27,7 @@ RSpec.describe Airbrake::Benchmark do
25
27
  end
26
28
 
27
29
  context "when #stop was called" do
28
- before { subject.stop }
30
+ before { benchmark.stop }
29
31
 
30
32
  its(:duration) { is_expected.to be > 0 }
31
33
  end
@@ -1,4 +1,6 @@
1
1
  RSpec.describe Airbrake::CodeHunk do
2
+ subject(:code_hunk) { described_class.new }
3
+
2
4
  after do
3
5
  %w[empty_file.rb code.rb banana.rb short_file.rb long_line.txt].each do |f|
4
6
  Airbrake::FileCache[project_root_path(f)] = nil
@@ -27,10 +29,12 @@ RSpec.describe Airbrake::CodeHunk do
27
29
  end
28
30
 
29
31
  context "when a file has less than NLINES lines before start line" do
30
- subject { described_class.new.get(project_root_path('code.rb'), 1) }
32
+ subject(:code_hunk) do
33
+ described_class.new.get(project_root_path('code.rb'), 1)
34
+ end
31
35
 
32
36
  it do
33
- is_expected.to(
37
+ expect(code_hunk).to(
34
38
  eq(
35
39
  1 => 'module Airbrake',
36
40
  2 => ' ##',
@@ -43,10 +47,12 @@ RSpec.describe Airbrake::CodeHunk do
43
47
  end
44
48
 
45
49
  context "when a file has less than NLINES lines after end line" do
46
- subject { described_class.new.get(project_root_path('code.rb'), 222) }
50
+ subject(:code_hunk) do
51
+ described_class.new.get(project_root_path('code.rb'), 222)
52
+ end
47
53
 
48
54
  it do
49
- is_expected.to(
55
+ expect(code_hunk).to(
50
56
  eq(
51
57
  220 => ' end',
52
58
  221 => 'end',
@@ -56,12 +62,12 @@ RSpec.describe Airbrake::CodeHunk do
56
62
  end
57
63
 
58
64
  context "when a file has less than NLINES lines before and after" do
59
- subject do
65
+ subject(:code_hunk) do
60
66
  described_class.new.get(project_root_path('short_file.rb'), 2)
61
67
  end
62
68
 
63
69
  it do
64
- is_expected.to(
70
+ expect(code_hunk).to(
65
71
  eq(
66
72
  1 => 'module Banana',
67
73
  2 => ' attr_reader :bingo',
@@ -72,10 +78,12 @@ RSpec.describe Airbrake::CodeHunk do
72
78
  end
73
79
 
74
80
  context "when a file has enough lines before and after" do
75
- subject { described_class.new.get(project_root_path('code.rb'), 100) }
81
+ subject(:code_hunk) do
82
+ described_class.new.get(project_root_path('code.rb'), 100)
83
+ end
76
84
 
77
85
  it do
78
- is_expected.to(
86
+ expect(code_hunk).to(
79
87
  eq(
80
88
  98 => ' return json if json && json.bytesize <= MAX_NOTICE_SIZE',
81
89
  99 => ' end',
@@ -88,27 +96,28 @@ RSpec.describe Airbrake::CodeHunk do
88
96
  end
89
97
 
90
98
  context "when a line exceeds the length limit" do
91
- subject do
99
+ subject(:code_hunk) do
92
100
  described_class.new.get(project_root_path('long_line.txt'), 1)
93
101
  end
94
102
 
95
103
  it "strips the line" do
96
- expect(subject[1]).to eq('l' + 'o' * 196 + 'ng')
104
+ expect(code_hunk[1]).to eq("l#{'o' * 196}ng")
97
105
  end
98
106
  end
99
107
 
100
108
  context "when an error occurrs while fetching code" do
101
109
  before do
102
- expect(Airbrake::FileCache).to receive(:[]).and_raise(Errno::EACCES)
110
+ allow(Airbrake::Loggable.instance).to receive(:error)
111
+ allow(Airbrake::FileCache).to receive(:[]).and_raise(Errno::EACCES)
103
112
  end
104
113
 
105
114
  it "logs error and returns nil" do
106
- expect(Airbrake::Loggable.instance).to receive(:error).with(
107
- /can't read code hunk.+Permission denied/,
108
- )
109
- expect(subject.get(project_root_path('code.rb'), 1)).to(
115
+ expect(code_hunk.get(project_root_path('code.rb'), 1)).to(
110
116
  eq(1 => ''),
111
117
  )
118
+ expect(Airbrake::Loggable.instance).to have_received(:error).with(
119
+ /can't read code hunk.+Permission denied/,
120
+ )
112
121
  end
113
122
  end
114
123
  end
@@ -44,12 +44,17 @@ RSpec.describe Airbrake::Config::Processor do
44
44
  end
45
45
 
46
46
  describe "#process_remote_configuration" do
47
+ before do
48
+ allow(Airbrake::RemoteSettings).to receive(:poll)
49
+ end
50
+
47
51
  context "when the config doesn't define a project_id" do
48
52
  let(:config) { Airbrake::Config.new(project_id: nil) }
49
53
 
50
54
  it "doesn't set remote settings" do
51
- expect(Airbrake::RemoteSettings).not_to receive(:poll)
52
55
  described_class.new(config).process_remote_configuration
56
+
57
+ expect(Airbrake::RemoteSettings).not_to have_received(:poll)
53
58
  end
54
59
  end
55
60
 
@@ -57,8 +62,9 @@ RSpec.describe Airbrake::Config::Processor do
57
62
  let(:config) { Airbrake::Config.new(project_id: 123, environment: 'test') }
58
63
 
59
64
  it "doesn't set remote settings" do
60
- expect(Airbrake::RemoteSettings).not_to receive(:poll)
61
65
  described_class.new(config).process_remote_configuration
66
+
67
+ expect(Airbrake::RemoteSettings).not_to have_received(:poll)
62
68
  end
63
69
  end
64
70
 
@@ -68,8 +74,9 @@ RSpec.describe Airbrake::Config::Processor do
68
74
  end
69
75
 
70
76
  it "sets remote settings" do
71
- expect(Airbrake::RemoteSettings).to receive(:poll)
72
77
  described_class.new(config).process_remote_configuration
78
+
79
+ expect(Airbrake::RemoteSettings).to have_received(:poll)
73
80
  end
74
81
  end
75
82
 
@@ -77,8 +84,9 @@ RSpec.describe Airbrake::Config::Processor do
77
84
  let(:config) { Airbrake::Config.new(project_id: 123, remote_config: false) }
78
85
 
79
86
  it "doesn't set remote settings" do
80
- expect(Airbrake::RemoteSettings).not_to receive(:poll)
81
87
  described_class.new(config).process_remote_configuration
88
+
89
+ expect(Airbrake::RemoteSettings).not_to have_received(:poll)
82
90
  end
83
91
  end
84
92
  end
@@ -175,9 +175,12 @@ RSpec.describe Airbrake::Config::Validator do
175
175
  end
176
176
 
177
177
  it "warns about 'no effect'" do
178
- expect(config.logger).to receive(:warn)
179
- .with(/'ignore_environments' has no effect/)
178
+ allow(config.logger).to receive(:warn)
179
+
180
180
  described_class.check_notify_ability(config)
181
+
182
+ expect(config.logger).to have_received(:warn)
183
+ .with(/'ignore_environments' has no effect/)
181
184
  end
182
185
  end
183
186
 
data/spec/config_spec.rb CHANGED
@@ -1,4 +1,6 @@
1
1
  RSpec.describe Airbrake::Config do
2
+ subject(:config) { described_class.new }
3
+
2
4
  let(:resolved_promise) { Airbrake::Promise.new.resolve }
3
5
  let(:rejected_promise) { Airbrake::Promise.new.reject }
4
6
 
@@ -35,18 +37,22 @@ RSpec.describe Airbrake::Config do
35
37
  describe "#new" do
36
38
  context "when user config is passed" do
37
39
  subject { described_class.new(logger: StringIO.new) }
40
+
38
41
  its(:logger) { is_expected.to be_a(StringIO) }
39
42
  end
40
43
  end
41
44
 
42
45
  describe "#valid?" do
43
- context "when #validate returns a resolved promise" do
44
- before { expect(subject).to receive(:validate).and_return(resolved_promise) }
46
+ context "when the config is valid" do
47
+ before do
48
+ config.project_id = 123
49
+ config.project_key = 'abc'
50
+ end
51
+
45
52
  it { is_expected.to be_valid }
46
53
  end
47
54
 
48
- context "when #validate returns a rejected promise" do
49
- before { expect(subject).to receive(:validate).and_return(rejected_promise) }
55
+ context "when the config is invalid" do
50
56
  it { is_expected.not_to be_valid }
51
57
  end
52
58
  end
@@ -54,7 +60,7 @@ RSpec.describe Airbrake::Config do
54
60
  describe "#ignored_environment?" do
55
61
  context "when Validator returns a resolved promise" do
56
62
  before do
57
- expect(Airbrake::Config::Validator).to receive(:check_notify_ability)
63
+ allow(Airbrake::Config::Validator).to receive(:check_notify_ability)
58
64
  .and_return(resolved_promise)
59
65
  end
60
66
 
@@ -63,7 +69,7 @@ RSpec.describe Airbrake::Config do
63
69
 
64
70
  context "when Validator returns a rejected promise" do
65
71
  before do
66
- expect(Airbrake::Config::Validator).to receive(:check_notify_ability)
72
+ allow(Airbrake::Config::Validator).to receive(:check_notify_ability)
67
73
  .and_return(rejected_promise)
68
74
  end
69
75
 
@@ -96,19 +102,21 @@ RSpec.describe Airbrake::Config do
96
102
  end
97
103
 
98
104
  describe "#check_configuration" do
99
- let(:user_config) { {} }
100
-
101
105
  subject { described_class.new(valid_params.merge(user_config)) }
102
106
 
107
+ let(:user_config) { {} }
108
+
103
109
  its(:check_configuration) { is_expected.to be_an(Airbrake::Promise) }
104
110
 
105
111
  context "when config is invalid" do
106
112
  let(:user_config) { { project_id: nil } }
113
+
107
114
  its(:check_configuration) { is_expected.to be_rejected }
108
115
  end
109
116
 
110
117
  context "when current environment is ignored" do
111
118
  let(:user_config) { { environment: 'test', ignore_environments: ['test'] } }
119
+
112
120
  its(:check_configuration) { is_expected.to be_rejected }
113
121
  end
114
122
 
@@ -119,22 +127,22 @@ RSpec.describe Airbrake::Config do
119
127
 
120
128
  describe "#check_performance_options" do
121
129
  it "returns a promise" do
122
- resource = Airbrake::Query.new(method: '', route: '', query: '', timing: 1)
123
- expect(subject.check_performance_options(resource))
130
+ metric = Airbrake::Query.new(method: '', route: '', query: '', timing: 1)
131
+ expect(config.check_performance_options(metric))
124
132
  .to be_an(Airbrake::Promise)
125
133
  end
126
134
 
127
135
  context "when performance stats are disabled" do
128
- before { subject.performance_stats = false }
136
+ before { config.performance_stats = false }
129
137
 
130
- let(:resource) do
138
+ let(:metric) do
131
139
  Airbrake::Request.new(
132
140
  method: 'GET', route: '/foo', status_code: 200, timing: 1,
133
141
  )
134
142
  end
135
143
 
136
144
  it "returns a rejected promise" do
137
- promise = subject.check_performance_options(resource)
145
+ promise = config.check_performance_options(metric)
138
146
  expect(promise.value).to eq(
139
147
  'error' => "The Performance Stats feature is disabled",
140
148
  )
@@ -142,14 +150,14 @@ RSpec.describe Airbrake::Config do
142
150
  end
143
151
 
144
152
  context "when query stats are disabled" do
145
- before { subject.query_stats = false }
153
+ before { config.query_stats = false }
146
154
 
147
- let(:resource) do
155
+ let(:metric) do
148
156
  Airbrake::Query.new(method: 'GET', route: '/foo', query: '', timing: 1)
149
157
  end
150
158
 
151
159
  it "returns a rejected promise" do
152
- promise = subject.check_performance_options(resource)
160
+ promise = config.check_performance_options(metric)
153
161
  expect(promise.value).to eq(
154
162
  'error' => "The Query Stats feature is disabled",
155
163
  )
@@ -157,14 +165,14 @@ RSpec.describe Airbrake::Config do
157
165
  end
158
166
 
159
167
  context "when job stats are disabled" do
160
- before { subject.job_stats = false }
168
+ before { config.job_stats = false }
161
169
 
162
- let(:resource) do
170
+ let(:metric) do
163
171
  Airbrake::Queue.new(queue: 'foo_queue', error_count: 0, timing: 1)
164
172
  end
165
173
 
166
174
  it "returns a rejected promise" do
167
- promise = subject.check_performance_options(resource)
175
+ promise = config.check_performance_options(metric)
168
176
  expect(promise.value).to eq(
169
177
  'error' => "The Job Stats feature is disabled",
170
178
  )
@@ -174,7 +182,7 @@ RSpec.describe Airbrake::Config do
174
182
 
175
183
  describe "#logger" do
176
184
  it "sets logger level to Logger::WARN" do
177
- expect(subject.logger.level).to eq(Logger::WARN)
185
+ expect(config.logger.level).to eq(Logger::WARN)
178
186
  end
179
187
  end
180
188
  end
@@ -0,0 +1,54 @@
1
+ RSpec.describe Airbrake::Context do
2
+ subject(:context) { described_class.current }
3
+
4
+ before { described_class.current.clear }
5
+
6
+ after { described_class.current.clear }
7
+
8
+ describe "#merge!" do
9
+ it "merges the given context with the current one" do
10
+ context.merge!(apples: 'oranges')
11
+ expect(context.to_h).to match(apples: 'oranges')
12
+ end
13
+ end
14
+
15
+ describe "#clear" do
16
+ it "clears the context" do
17
+ context.merge!(apples: 'oranges')
18
+ context.clear
19
+ expect(context.to_h).to be_empty
20
+ end
21
+ end
22
+
23
+ describe "#to_h" do
24
+ it "returns a hash representation of the context" do
25
+ expect(context.to_h).to be_a(Hash)
26
+ end
27
+ end
28
+
29
+ describe "#empty?" do
30
+ context "when the context has data" do
31
+ it "returns true" do
32
+ context.merge!(apples: 'oranges')
33
+ expect(context).not_to be_empty
34
+ end
35
+ end
36
+
37
+ context "when the context has NO data" do
38
+ it "returns false" do
39
+ expect(context).to be_empty
40
+ end
41
+ end
42
+ end
43
+
44
+ context "when another thread is spawned" do
45
+ it "doesn't clash with other threads' contexts" do
46
+ described_class.current.merge!(apples: 'oranges')
47
+ th = Thread.new do
48
+ described_class.current.merge!(foos: 'bars')
49
+ end
50
+ th.join
51
+ expect(described_class.current.to_h).to match(apples: 'oranges')
52
+ end
53
+ end
54
+ end
@@ -4,17 +4,19 @@ RSpec.describe Airbrake::DeployNotifier do
4
4
  end
5
5
 
6
6
  describe "#notify" do
7
+ subject(:deploy_notifier) { described_class.new }
8
+
7
9
  it "returns a promise" do
8
10
  stub_request(:post, 'https://api.airbrake.io/api/v4/projects/1/deploys')
9
11
  .to_return(status: 201, body: '{}')
10
- expect(subject.notify({})).to be_an(Airbrake::Promise)
12
+ expect(deploy_notifier.notify({})).to be_an(Airbrake::Promise)
11
13
  end
12
14
 
13
15
  context "when config is invalid" do
14
16
  before { Airbrake::Config.instance.merge(project_id: nil) }
15
17
 
16
18
  it "returns a rejected promise" do
17
- promise = subject.notify({})
19
+ promise = deploy_notifier.notify({})
18
20
  expect(promise).to be_rejected
19
21
  end
20
22
  end
@@ -28,7 +30,7 @@ RSpec.describe Airbrake::DeployNotifier do
28
30
  instance_of(Airbrake::Promise),
29
31
  URI('https://api.airbrake.io/api/v4/projects/1/deploys'),
30
32
  )
31
- subject.notify(environment: 'barenv')
33
+ deploy_notifier.notify(environment: 'barenv')
32
34
  end
33
35
  end
34
36
 
@@ -41,7 +43,7 @@ RSpec.describe Airbrake::DeployNotifier do
41
43
  instance_of(Airbrake::Promise),
42
44
  URI('https://api.airbrake.io/api/v4/projects/1/deploys'),
43
45
  )
44
- subject.notify({})
46
+ deploy_notifier.notify({})
45
47
  end
46
48
  end
47
49
  end
@@ -1,5 +1,6 @@
1
1
  RSpec.describe Airbrake::FileCache do
2
2
  before { described_class.reset }
3
+
3
4
  after { described_class.reset }
4
5
 
5
6
  describe ".[]=" do
@@ -1,4 +1,6 @@
1
1
  RSpec.describe Airbrake::FilterChain do
2
+ subject(:filter_chain) { described_class.new }
3
+
2
4
  let(:notice) { Airbrake::Notice.new(AirbrakeTestError.new) }
3
5
 
4
6
  describe "#refine" do
@@ -19,24 +21,27 @@ RSpec.describe Airbrake::FilterChain do
19
21
  it "executes filters from heaviest to lightest" do
20
22
  notice[:params][:bingo] = []
21
23
 
22
- (0...3).reverse_each { |i| subject.add_filter(filter.new(i)) }
23
- subject.refine(notice)
24
+ (0...3).reverse_each { |i| filter_chain.add_filter(filter.new(i)) }
25
+ filter_chain.refine(notice)
24
26
 
25
27
  expect(notice[:params][:bingo]).to eq([2, 1, 0])
26
28
  end
27
29
 
28
30
  it "stops execution once a notice was ignored" do
29
31
  f2 = filter.new(2)
30
- expect(f2).to receive(:call)
32
+ allow(f2).to receive(:call)
31
33
 
32
34
  f1 = proc { |notice| notice.ignore! }
33
35
 
34
36
  f0 = filter.new(-1)
35
- expect(f0).not_to receive(:call)
37
+ allow(f0).to receive(:call)
38
+
39
+ [f2, f1, f0].each { |f| filter_chain.add_filter(f) }
36
40
 
37
- [f2, f1, f0].each { |f| subject.add_filter(f) }
41
+ filter_chain.refine(notice)
38
42
 
39
- subject.refine(notice)
43
+ expect(f2).to have_received(:call)
44
+ expect(f0).not_to have_received(:call)
40
45
  end
41
46
  end
42
47
 
@@ -63,56 +68,56 @@ RSpec.describe Airbrake::FilterChain do
63
68
  notice[:params][:foo] = []
64
69
 
65
70
  f1 = filter.new(1)
66
- subject.add_filter(f1)
71
+ filter_chain.add_filter(f1)
67
72
 
68
73
  foo_filter_mock = double
69
- expect(foo_filter_mock).to(
70
- receive(:name).at_least(:once).and_return('FooFilter'),
71
- )
72
- subject.delete_filter(foo_filter_mock)
74
+ allow(foo_filter_mock).to receive(:name).at_least(:once).and_return('FooFilter')
75
+ filter_chain.delete_filter(foo_filter_mock)
76
+
77
+ expect(foo_filter_mock).to have_received(:name)
73
78
 
74
79
  f2 = filter.new(2)
75
- subject.add_filter(f2)
80
+ filter_chain.add_filter(f2)
76
81
 
77
- subject.refine(notice)
82
+ filter_chain.refine(notice)
78
83
  expect(notice[:params][:foo]).to eq([2])
79
84
  end
80
85
  end
81
86
 
82
87
  describe "#inspect" do
83
88
  it "returns a string representation of an empty FilterChain" do
84
- expect(subject.inspect).to eq('[]')
89
+ expect(filter_chain.inspect).to eq('[]')
85
90
  end
86
91
 
87
92
  it "returns a string representation of a non-empty FilterChain" do
88
- subject.add_filter(proc {})
89
- expect(subject.inspect).to eq('[Proc]')
93
+ filter_chain.add_filter(proc {})
94
+ expect(filter_chain.inspect).to eq('[Proc]')
90
95
  end
91
96
  end
92
97
 
93
98
  describe "#includes?" do
94
99
  context "when a custom filter class is included in the filter chain" do
95
100
  it "returns true" do
96
- klass = Class.new {}
101
+ klass = Class.new
97
102
 
98
- subject.add_filter(klass.new)
99
- expect(subject.includes?(klass)).to eq(true)
103
+ filter_chain.add_filter(klass.new)
104
+ expect(filter_chain.includes?(klass)).to eq(true)
100
105
  end
101
106
  end
102
107
 
103
108
  context "when Proc filter class is included in the filter chain" do
104
109
  it "returns true" do
105
- subject.add_filter(proc {})
106
- expect(subject.includes?(Proc)).to eq(true)
110
+ filter_chain.add_filter(proc {})
111
+ expect(filter_chain.includes?(Proc)).to eq(true)
107
112
  end
108
113
  end
109
114
 
110
115
  context "when filter class is NOT included in the filter chain" do
111
116
  it "returns false" do
112
- klass = Class.new {}
117
+ klass = Class.new
113
118
 
114
- subject.add_filter(proc {})
115
- expect(subject.includes?(klass)).to eq(false)
119
+ filter_chain.add_filter(proc {})
120
+ expect(filter_chain.includes?(klass)).to eq(false)
116
121
  end
117
122
  end
118
123
  end