airbrake-ruby 5.2.0-java → 5.2.1-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 (66) hide show
  1. checksums.yaml +4 -4
  2. data/lib/airbrake-ruby.rb +3 -2
  3. data/lib/airbrake-ruby/async_sender.rb +3 -1
  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 +1 -1
  9. data/lib/airbrake-ruby/filters/git_revision_filter.rb +1 -1
  10. data/lib/airbrake-ruby/filters/keys_filter.rb +2 -2
  11. data/lib/airbrake-ruby/filters/sql_filter.rb +2 -2
  12. data/lib/airbrake-ruby/filters/thread_filter.rb +1 -1
  13. data/lib/airbrake-ruby/ignorable.rb +0 -2
  14. data/lib/airbrake-ruby/notice_notifier.rb +3 -4
  15. data/lib/airbrake-ruby/performance_notifier.rb +1 -2
  16. data/lib/airbrake-ruby/remote_settings/settings_data.rb +1 -1
  17. data/lib/airbrake-ruby/tdigest.rb +7 -6
  18. data/lib/airbrake-ruby/thread_pool.rb +5 -3
  19. data/lib/airbrake-ruby/timed_trace.rb +1 -3
  20. data/lib/airbrake-ruby/version.rb +1 -1
  21. data/spec/airbrake_spec.rb +139 -76
  22. data/spec/async_sender_spec.rb +10 -8
  23. data/spec/backtrace_spec.rb +13 -10
  24. data/spec/benchmark_spec.rb +5 -3
  25. data/spec/code_hunk_spec.rb +24 -15
  26. data/spec/config/processor_spec.rb +12 -4
  27. data/spec/config/validator_spec.rb +5 -2
  28. data/spec/config_spec.rb +24 -16
  29. data/spec/context_spec.rb +54 -0
  30. data/spec/deploy_notifier_spec.rb +6 -4
  31. data/spec/file_cache_spec.rb +1 -0
  32. data/spec/filter_chain_spec.rb +29 -24
  33. data/spec/filters/context_filter_spec.rb +14 -5
  34. data/spec/filters/dependency_filter_spec.rb +3 -1
  35. data/spec/filters/exception_attributes_filter_spec.rb +5 -3
  36. data/spec/filters/gem_root_filter_spec.rb +5 -2
  37. data/spec/filters/git_last_checkout_filter_spec.rb +10 -12
  38. data/spec/filters/git_repository_filter.rb +9 -9
  39. data/spec/filters/git_revision_filter_spec.rb +19 -19
  40. data/spec/filters/keys_allowlist_spec.rb +25 -16
  41. data/spec/filters/keys_blocklist_spec.rb +25 -18
  42. data/spec/filters/root_directory_filter_spec.rb +3 -3
  43. data/spec/filters/sql_filter_spec.rb +26 -26
  44. data/spec/filters/system_exit_filter_spec.rb +4 -2
  45. data/spec/filters/thread_filter_spec.rb +15 -13
  46. data/spec/loggable_spec.rb +2 -2
  47. data/spec/monotonic_time_spec.rb +8 -6
  48. data/spec/nested_exception_spec.rb +46 -46
  49. data/spec/notice_notifier/options_spec.rb +23 -13
  50. data/spec/notice_notifier_spec.rb +52 -47
  51. data/spec/notice_spec.rb +6 -2
  52. data/spec/performance_notifier_spec.rb +67 -60
  53. data/spec/promise_spec.rb +38 -32
  54. data/spec/remote_settings/callback_spec.rb +27 -8
  55. data/spec/remote_settings/settings_data_spec.rb +4 -4
  56. data/spec/remote_settings_spec.rb +18 -8
  57. data/spec/response_spec.rb +34 -12
  58. data/spec/stashable_spec.rb +5 -5
  59. data/spec/stat_spec.rb +7 -5
  60. data/spec/sync_sender_spec.rb +49 -16
  61. data/spec/tdigest_spec.rb +60 -55
  62. data/spec/thread_pool_spec.rb +65 -55
  63. data/spec/time_truncate_spec.rb +4 -2
  64. data/spec/timed_trace_spec.rb +32 -30
  65. data/spec/truncator_spec.rb +72 -43
  66. metadata +51 -48
data/spec/promise_spec.rb CHANGED
@@ -1,15 +1,17 @@
1
1
  RSpec.describe Airbrake::Promise do
2
+ subject(:promise) { described_class.new }
3
+
2
4
  describe ".then" do
3
5
  let(:resolved_with) { [] }
4
6
  let(:rejected_with) { [] }
5
7
 
6
8
  context "when it is not resolved" do
7
9
  it "returns self" do
8
- expect(subject.then {}).to eq(subject)
10
+ expect(promise.then { anything }).to eq(promise)
9
11
  end
10
12
 
11
13
  it "doesn't call the resolve callbacks yet" do
12
- subject.then { resolved_with << 1 }.then { resolved_with << 2 }
14
+ promise.then { resolved_with << 1 }.then { resolved_with << 2 }
13
15
  expect(resolved_with).to be_empty
14
16
  end
15
17
  end
@@ -17,12 +19,12 @@ RSpec.describe Airbrake::Promise do
17
19
  context "when it is resolved" do
18
20
  shared_examples "then specs" do
19
21
  it "returns self" do
20
- expect(subject.then {}).to eq(subject)
22
+ expect(promise.then { anything }).to eq(promise)
21
23
  end
22
24
 
23
25
  it "yields the resolved value" do
24
26
  yielded = nil
25
- subject.then { |value| yielded = value }
27
+ promise.then { |value| yielded = value }
26
28
  expect(yielded).to eq('id' => '123')
27
29
  end
28
30
 
@@ -37,29 +39,29 @@ RSpec.describe Airbrake::Promise do
37
39
 
38
40
  context "and there are some resolve and reject callbacks in place" do
39
41
  before do
40
- subject.then { resolved_with << 1 }.then { resolved_with << 2 }
41
- subject.rescue { rejected_with << 1 }.rescue { rejected_with << 2 }
42
- subject.resolve('id' => '123')
42
+ promise.then { resolved_with << 1 }.then { resolved_with << 2 }
43
+ promise.rescue { rejected_with << 1 }.rescue { rejected_with << 2 }
44
+ promise.resolve('id' => '123')
43
45
  end
44
46
 
45
47
  include_examples "then specs"
46
48
 
47
49
  it "registers the resolve callbacks" do
48
- subject.resolve('id' => '456')
50
+ promise.resolve('id' => '456')
49
51
  expect(resolved_with).to match_array([1, 2, 1, 2])
50
52
  end
51
53
  end
52
54
 
53
55
  context "and additional then callbacks are added" do
54
56
  before do
55
- subject.resolve('id' => '123')
56
- subject.then { resolved_with << 1 }.then { resolved_with << 2 }
57
+ promise.resolve('id' => '123')
58
+ promise.then { resolved_with << 1 }.then { resolved_with << 2 }
57
59
  end
58
60
 
59
61
  include_examples "then specs"
60
62
 
61
63
  it "doesn't register new resolve callbacks" do
62
- subject.resolve('id' => '456')
64
+ promise.resolve('id' => '456')
63
65
  expect(resolved_with).to match_array([1, 2])
64
66
  end
65
67
  end
@@ -72,11 +74,11 @@ RSpec.describe Airbrake::Promise do
72
74
 
73
75
  context "when it is not rejected" do
74
76
  it "returns self" do
75
- expect(subject.then {}).to eq(subject)
77
+ expect(promise.then { anything }).to eq(promise)
76
78
  end
77
79
 
78
80
  it "doesn't call the reject callbacks yet" do
79
- subject.rescue { rejected_with << 1 }.rescue { rejected_with << 2 }
81
+ promise.rescue { rejected_with << 1 }.rescue { rejected_with << 2 }
80
82
  expect(rejected_with).to be_empty
81
83
  end
82
84
  end
@@ -84,12 +86,12 @@ RSpec.describe Airbrake::Promise do
84
86
  context "when it is rejected" do
85
87
  shared_examples "rescue specs" do
86
88
  it "returns self" do
87
- expect(subject.rescue {}).to eq(subject)
89
+ expect(promise.rescue { anything }).to eq(promise)
88
90
  end
89
91
 
90
92
  it "yields the rejected value" do
91
93
  yielded = nil
92
- subject.rescue { |value| yielded = value }
94
+ promise.rescue { |value| yielded = value }
93
95
  expect(yielded).to eq('bingo')
94
96
  end
95
97
 
@@ -104,29 +106,29 @@ RSpec.describe Airbrake::Promise do
104
106
 
105
107
  context "and there are some resolve and reject callbacks in place" do
106
108
  before do
107
- subject.then { resolved_with << 1 }.then { resolved_with << 2 }
108
- subject.rescue { rejected_with << 1 }.rescue { rejected_with << 2 }
109
- subject.reject('bingo')
109
+ promise.then { resolved_with << 1 }.then { resolved_with << 2 }
110
+ promise.rescue { rejected_with << 1 }.rescue { rejected_with << 2 }
111
+ promise.reject('bingo')
110
112
  end
111
113
 
112
114
  include_examples "rescue specs"
113
115
 
114
116
  it "registers the reject callbacks" do
115
- subject.reject('bingo again')
117
+ promise.reject('bingo again')
116
118
  expect(rejected_with).to match_array([1, 2, 1, 2])
117
119
  end
118
120
  end
119
121
 
120
122
  context "and additional reject callbacks are added" do
121
123
  before do
122
- subject.reject('bingo')
123
- subject.rescue { rejected_with << 1 }.rescue { rejected_with << 2 }
124
+ promise.reject('bingo')
125
+ promise.rescue { rejected_with << 1 }.rescue { rejected_with << 2 }
124
126
  end
125
127
 
126
128
  include_examples "rescue specs"
127
129
 
128
130
  it "doesn't register new reject callbacks" do
129
- subject.reject('bingo again')
131
+ promise.reject('bingo again')
130
132
  expect(rejected_with).to match_array([1, 2])
131
133
  end
132
134
  end
@@ -135,37 +137,38 @@ RSpec.describe Airbrake::Promise do
135
137
 
136
138
  describe ".resolve" do
137
139
  it "returns self" do
138
- expect(subject.resolve(1)).to eq(subject)
140
+ expect(promise.resolve(1)).to eq(promise)
139
141
  end
140
142
 
141
143
  it "executes callbacks attached with .then" do
142
144
  array = []
143
- subject.then { |notice_id| array << notice_id }.rescue { array << 999 }
145
+ promise.then { |notice_id| array << notice_id }.rescue { array << 999 }
144
146
 
145
147
  expect(array.size).to be_zero
146
- subject.resolve(1)
148
+ promise.resolve(1)
147
149
  expect(array).to match_array([1])
148
150
  end
149
151
  end
150
152
 
151
153
  describe ".reject" do
152
154
  it "returns self" do
153
- expect(subject.reject(1)).to eq(subject)
155
+ expect(promise.reject(1)).to eq(promise)
154
156
  end
155
157
 
156
158
  it "executes callbacks attached with .rescue" do
157
159
  array = []
158
- subject.then { array << 1 }.rescue { |error| array << error }
160
+ promise.then { array << 1 }.rescue { |error| array << error }
159
161
 
160
162
  expect(array.size).to be_zero
161
- subject.reject(999)
163
+ promise.reject(999)
162
164
  expect(array).to match_array([999])
163
165
  end
164
166
  end
165
167
 
166
168
  describe "#rejected?" do
167
169
  context "when it was rejected" do
168
- before { subject.reject(1) }
170
+ before { promise.reject(1) }
171
+
169
172
  it { is_expected.to be_rejected }
170
173
  end
171
174
 
@@ -174,14 +177,16 @@ RSpec.describe Airbrake::Promise do
174
177
  end
175
178
 
176
179
  context "when it was resolved" do
177
- before { subject.resolve }
180
+ before { promise.resolve }
181
+
178
182
  it { is_expected.not_to be_rejected }
179
183
  end
180
184
  end
181
185
 
182
186
  describe "#resolved?" do
183
187
  context "when it was resolved" do
184
- before { subject.resolve }
188
+ before { promise.resolve }
189
+
185
190
  it { is_expected.to be_resolved }
186
191
  end
187
192
 
@@ -190,7 +195,8 @@ RSpec.describe Airbrake::Promise do
190
195
  end
191
196
 
192
197
  context "when it was rejected" do
193
- before { subject.reject(1) }
198
+ before { promise.reject(1) }
199
+
194
200
  it { is_expected.not_to be_resolved }
195
201
  end
196
202
  end
@@ -22,10 +22,13 @@ RSpec.describe Airbrake::RemoteSettings::Callback do
22
22
  end
23
23
 
24
24
  it "logs given data" do
25
- expect(logger).to receive(:debug) do |&block|
25
+ allow(logger).to receive(:debug)
26
+
27
+ described_class.new(config).call(data)
28
+
29
+ expect(logger).to have_received(:debug) do |&block|
26
30
  expect(block.call).to match(/applying remote settings/)
27
31
  end
28
- described_class.new(config).call(data)
29
32
  end
30
33
 
31
34
  context "when the config disables error notifications" do
@@ -34,6 +37,7 @@ RSpec.describe Airbrake::RemoteSettings::Callback do
34
37
  allow(data).to receive(:error_notifications?).and_return(true)
35
38
  end
36
39
 
40
+ # rubocop:disable RSpec/MultipleExpectations
37
41
  it "keeps the option disabled forever" do
38
42
  callback = described_class.new(config)
39
43
 
@@ -46,22 +50,29 @@ RSpec.describe Airbrake::RemoteSettings::Callback do
46
50
  callback.call(data)
47
51
  expect(config.error_notifications).to eq(false)
48
52
  end
53
+ # rubocop:enable RSpec/MultipleExpectations
49
54
  end
50
55
 
51
56
  context "when the config enables error notifications" do
52
57
  before { config.error_notifications = true }
53
58
 
59
+ # rubocop:disable RSpec/MultipleExpectations
54
60
  it "can disable and enable error notifications" do
55
- expect(data).to receive(:error_notifications?).and_return(false)
56
-
57
61
  callback = described_class.new(config)
62
+
63
+ allow(data).to receive(:error_notifications?).and_return(false)
64
+
58
65
  callback.call(data)
59
66
  expect(config.error_notifications).to eq(false)
60
67
 
61
- expect(data).to receive(:error_notifications?).and_return(true)
68
+ allow(data).to receive(:error_notifications?).and_return(true)
69
+
62
70
  callback.call(data)
63
71
  expect(config.error_notifications).to eq(true)
72
+
73
+ expect(data).to have_received(:error_notifications?).twice
64
74
  end
75
+ # rubocop:enable RSpec/MultipleExpectations
65
76
  end
66
77
 
67
78
  context "when the config disables performance_stats" do
@@ -70,6 +81,7 @@ RSpec.describe Airbrake::RemoteSettings::Callback do
70
81
  allow(data).to receive(:performance_stats?).and_return(true)
71
82
  end
72
83
 
84
+ # rubocop:disable RSpec/MultipleExpectations
73
85
  it "keeps the option disabled forever" do
74
86
  callback = described_class.new(config)
75
87
 
@@ -82,22 +94,29 @@ RSpec.describe Airbrake::RemoteSettings::Callback do
82
94
  callback.call(data)
83
95
  expect(config.performance_stats).to eq(false)
84
96
  end
97
+ # rubocop:enable RSpec/MultipleExpectations
85
98
  end
86
99
 
87
100
  context "when the config enables performance stats" do
88
101
  before { config.performance_stats = true }
89
102
 
103
+ # rubocop:disable RSpec/MultipleExpectations
90
104
  it "can disable and enable performance_stats" do
91
- expect(data).to receive(:performance_stats?).and_return(false)
92
-
93
105
  callback = described_class.new(config)
106
+
107
+ allow(data).to receive(:performance_stats?).and_return(false)
108
+
94
109
  callback.call(data)
95
110
  expect(config.performance_stats).to eq(false)
96
111
 
97
- expect(data).to receive(:performance_stats?).and_return(true)
112
+ allow(data).to receive(:performance_stats?).and_return(true)
113
+
98
114
  callback.call(data)
99
115
  expect(config.performance_stats).to eq(true)
116
+
117
+ expect(data).to have_received(:performance_stats?).twice
100
118
  end
119
+ # rubocop:enable RSpec/MultipleExpectations
101
120
  end
102
121
 
103
122
  context "when error_host returns a value" do
@@ -312,6 +312,8 @@ RSpec.describe Airbrake::RemoteSettings::SettingsData do
312
312
  end
313
313
 
314
314
  describe "#to_h" do
315
+ subject(:settings_data) { described_class.new(project_id, data) }
316
+
315
317
  let(:data) do
316
318
  {
317
319
  'poll_sec' => 123,
@@ -324,17 +326,15 @@ RSpec.describe Airbrake::RemoteSettings::SettingsData do
324
326
  }
325
327
  end
326
328
 
327
- subject { described_class.new(project_id, data) }
328
-
329
329
  it "returns a hash representation of settings" do
330
330
  expect(described_class.new(project_id, data).to_h).to eq(data)
331
331
  end
332
332
 
333
333
  it "doesn't allow mutation of the original data object" do
334
- hash = subject.to_h
334
+ hash = settings_data.to_h
335
335
  hash['poll_sec'] = 0
336
336
 
337
- expect(subject.to_h).to eq(
337
+ expect(settings_data.to_h).to eq(
338
338
  'poll_sec' => 123,
339
339
  'settings' => [
340
340
  {
@@ -37,19 +37,20 @@ RSpec.describe Airbrake::RemoteSettings do
37
37
 
38
38
  it "yields the config to the block twice" do
39
39
  block = proc {}
40
- expect(block).to receive(:call).twice
40
+ allow(block).to receive(:call)
41
41
 
42
42
  remote_settings = described_class.poll(project_id, host, &block)
43
43
  sleep(0.2)
44
44
  remote_settings.stop_polling
45
45
 
46
46
  expect(stub).to have_been_requested.once
47
+ expect(block).to have_received(:call).twice
47
48
  end
48
49
  end
49
50
 
50
51
  context "when no errors are raised" do
51
52
  it "makes a request to AWS S3" do
52
- remote_settings = described_class.poll(project_id, host) {}
53
+ remote_settings = described_class.poll(project_id, host) { anything }
53
54
  sleep(0.1)
54
55
  remote_settings.stop_polling
55
56
 
@@ -57,7 +58,7 @@ RSpec.describe Airbrake::RemoteSettings do
57
58
  end
58
59
 
59
60
  it "sends params about the environment with the request" do
60
- remote_settings = described_class.poll(project_id, host) {}
61
+ remote_settings = described_class.poll(project_id, host) { anything }
61
62
  sleep(0.1)
62
63
  remote_settings.stop_polling
63
64
 
@@ -67,6 +68,7 @@ RSpec.describe Airbrake::RemoteSettings do
67
68
  expect(stub_with_query_params).to have_been_requested.at_least_once
68
69
  end
69
70
 
71
+ # rubocop:disable RSpec/MultipleExpectations
70
72
  it "fetches remote settings" do
71
73
  settings = nil
72
74
  remote_settings = described_class.poll(project_id, host) do |data|
@@ -79,6 +81,7 @@ RSpec.describe Airbrake::RemoteSettings do
79
81
  expect(settings.performance_stats?).to eq(false)
80
82
  expect(settings.interval).to eq(1)
81
83
  end
84
+ # rubocop:enable RSpec/MultipleExpectations
82
85
  end
83
86
 
84
87
  context "when an error is raised while making a HTTP request" do
@@ -136,11 +139,13 @@ RSpec.describe Airbrake::RemoteSettings do
136
139
  end
137
140
 
138
141
  it "logs error" do
139
- expect(Airbrake::Loggable.instance).to receive(:error).with(body.to_json)
142
+ allow(Airbrake::Loggable.instance).to receive(:error)
140
143
 
141
- remote_settings = described_class.poll(project_id, host) {}
144
+ remote_settings = described_class.poll(project_id, host) { anything }
142
145
  sleep(0.1)
143
146
  remote_settings.stop_polling
147
+
148
+ expect(Airbrake::Loggable.instance).to have_received(:error).with(body.to_json)
144
149
  end
145
150
  end
146
151
 
@@ -151,14 +156,18 @@ RSpec.describe Airbrake::RemoteSettings do
151
156
  end
152
157
 
153
158
  it "doesn't log errors" do
154
- expect(Airbrake::Loggable.instance).not_to receive(:error)
159
+ allow(Airbrake::Loggable.instance).to receive(:error)
155
160
 
156
- remote_settings = described_class.poll(project_id, host) {}
161
+ remote_settings = described_class.poll(project_id, host) { anything }
157
162
  sleep(0.1)
158
163
  remote_settings.stop_polling
164
+
165
+ expect(Airbrake::Loggable.instance).not_to have_received(:error)
166
+ expect(stub).to have_been_requested.once
159
167
  end
160
168
  end
161
169
 
170
+ # rubocop:disable RSpec/MultipleMemoizedHelpers
162
171
  context "when a config route is specified in the returned data" do
163
172
  let(:new_config_route) do
164
173
  '213/config/111/config.json'
@@ -174,7 +183,7 @@ RSpec.describe Airbrake::RemoteSettings do
174
183
  end
175
184
 
176
185
  it "makes the next request to the specified config route" do
177
- remote_settings = described_class.poll(project_id, host) {}
186
+ remote_settings = described_class.poll(project_id, host) { anything }
178
187
  sleep(0.2)
179
188
 
180
189
  remote_settings.stop_polling
@@ -183,5 +192,6 @@ RSpec.describe Airbrake::RemoteSettings do
183
192
  expect(new_stub).to have_been_requested.once
184
193
  end
185
194
  end
195
+ # rubocop:enable RSpec/MultipleMemoizedHelpers
186
196
  end
187
197
  end
@@ -2,24 +2,34 @@ RSpec.describe Airbrake::Response do
2
2
  describe ".parse" do
3
3
  [200, 201, 204].each do |code|
4
4
  context "when response code is #{code}" do
5
+ before do
6
+ allow(Airbrake::Loggable.instance).to receive(:debug)
7
+ end
8
+
5
9
  it "logs response body" do
6
- expect(Airbrake::Loggable.instance).to receive(:debug).with(
10
+ described_class.parse(OpenStruct.new(code: code, body: '{}'))
11
+
12
+ expect(Airbrake::Loggable.instance).to have_received(:debug).with(
7
13
  /Airbrake::Response \(#{code}\): {}/,
8
14
  )
9
- described_class.parse(OpenStruct.new(code: code, body: '{}'))
10
15
  end
11
16
  end
12
17
  end
13
18
 
14
19
  [400, 401, 403, 420].each do |code|
15
20
  context "when response code is #{code}" do
21
+ before do
22
+ allow(Airbrake::Loggable.instance).to receive(:error)
23
+ end
24
+
16
25
  it "logs response message" do
17
- expect(Airbrake::Loggable.instance).to receive(:error).with(
18
- /Airbrake: foo/,
19
- )
20
26
  described_class.parse(
21
27
  OpenStruct.new(code: code, body: '{"message":"foo"}'),
22
28
  )
29
+
30
+ expect(Airbrake::Loggable.instance).to have_received(:error).with(
31
+ /Airbrake: foo/,
32
+ )
23
33
  end
24
34
  end
25
35
  end
@@ -27,11 +37,15 @@ RSpec.describe Airbrake::Response do
27
37
  context "when response code is 429" do
28
38
  let(:response) { OpenStruct.new(code: 429, body: '{"message":"rate limited"}') }
29
39
 
40
+ before do
41
+ allow(Airbrake::Loggable.instance).to receive(:error)
42
+ end
43
+
30
44
  it "logs response message" do
31
- expect(Airbrake::Loggable.instance).to receive(:error).with(
45
+ described_class.parse(response)
46
+ expect(Airbrake::Loggable.instance).to have_received(:error).with(
32
47
  /Airbrake: rate limited/,
33
48
  )
34
- described_class.parse(response)
35
49
  end
36
50
 
37
51
  it "returns an error response" do
@@ -49,11 +63,15 @@ RSpec.describe Airbrake::Response do
49
63
  context "when response code is unhandled" do
50
64
  let(:response) { OpenStruct.new(code: 500, body: 'foo') }
51
65
 
66
+ before do
67
+ allow(Airbrake::Loggable.instance).to receive(:error)
68
+ end
69
+
52
70
  it "logs response body" do
53
- expect(Airbrake::Loggable.instance).to receive(:error).with(
71
+ described_class.parse(response)
72
+ expect(Airbrake::Loggable.instance).to have_received(:error).with(
54
73
  /Airbrake: unexpected code \(500\)\. Body: foo/,
55
74
  )
56
- described_class.parse(response)
57
75
  end
58
76
 
59
77
  it "returns an error response" do
@@ -64,18 +82,22 @@ RSpec.describe Airbrake::Response do
64
82
  it "truncates body" do
65
83
  response.body *= 1000
66
84
  resp = described_class.parse(response)
67
- expect(resp).to eq('error' => ('foo' * 33) + 'fo...')
85
+ expect(resp).to eq('error' => "#{'foo' * 33}fo...")
68
86
  end
69
87
  end
70
88
 
71
89
  context "when response body can't be parsed as JSON" do
72
90
  let(:response) { OpenStruct.new(code: 201, body: 'foo') }
73
91
 
92
+ before do
93
+ allow(Airbrake::Loggable.instance).to receive(:error)
94
+ end
95
+
74
96
  it "logs response body" do
75
- expect(Airbrake::Loggable.instance).to receive(:error).with(
97
+ described_class.parse(response)
98
+ expect(Airbrake::Loggable.instance).to have_received(:error).with(
76
99
  /Airbrake: error while parsing body \(.*unexpected token.*\)\. Body: foo/,
77
100
  )
78
- described_class.parse(response)
79
101
  end
80
102
 
81
103
  it "returns an error message" do