airbrake-ruby 5.0.1-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 (73) hide show
  1. checksums.yaml +4 -4
  2. data/lib/airbrake-ruby.rb +4 -2
  3. data/lib/airbrake-ruby/async_sender.rb +3 -1
  4. data/lib/airbrake-ruby/config.rb +15 -6
  5. data/lib/airbrake-ruby/config/processor.rb +7 -20
  6. data/lib/airbrake-ruby/context.rb +51 -0
  7. data/lib/airbrake-ruby/file_cache.rb +1 -1
  8. data/lib/airbrake-ruby/filter_chain.rb +2 -0
  9. data/lib/airbrake-ruby/filters/context_filter.rb +4 -5
  10. data/lib/airbrake-ruby/filters/exception_attributes_filter.rb +1 -1
  11. data/lib/airbrake-ruby/filters/git_last_checkout_filter.rb +1 -1
  12. data/lib/airbrake-ruby/filters/git_revision_filter.rb +1 -1
  13. data/lib/airbrake-ruby/filters/keys_filter.rb +2 -2
  14. data/lib/airbrake-ruby/filters/sql_filter.rb +2 -2
  15. data/lib/airbrake-ruby/filters/thread_filter.rb +2 -3
  16. data/lib/airbrake-ruby/grouppable.rb +1 -1
  17. data/lib/airbrake-ruby/ignorable.rb +0 -2
  18. data/lib/airbrake-ruby/mergeable.rb +1 -1
  19. data/lib/airbrake-ruby/notice_notifier.rb +3 -4
  20. data/lib/airbrake-ruby/performance_notifier.rb +1 -2
  21. data/lib/airbrake-ruby/remote_settings.rb +10 -50
  22. data/lib/airbrake-ruby/remote_settings/callback.rb +44 -0
  23. data/lib/airbrake-ruby/remote_settings/settings_data.rb +3 -8
  24. data/lib/airbrake-ruby/tdigest.rb +7 -6
  25. data/lib/airbrake-ruby/thread_pool.rb +5 -3
  26. data/lib/airbrake-ruby/timed_trace.rb +1 -3
  27. data/lib/airbrake-ruby/version.rb +2 -2
  28. data/spec/airbrake_spec.rb +139 -76
  29. data/spec/async_sender_spec.rb +10 -8
  30. data/spec/backtrace_spec.rb +13 -10
  31. data/spec/benchmark_spec.rb +5 -3
  32. data/spec/code_hunk_spec.rb +24 -15
  33. data/spec/config/processor_spec.rb +29 -87
  34. data/spec/config/validator_spec.rb +5 -2
  35. data/spec/config_spec.rb +26 -17
  36. data/spec/context_spec.rb +54 -0
  37. data/spec/deploy_notifier_spec.rb +6 -4
  38. data/spec/file_cache_spec.rb +1 -0
  39. data/spec/filter_chain_spec.rb +29 -24
  40. data/spec/filters/context_filter_spec.rb +14 -5
  41. data/spec/filters/dependency_filter_spec.rb +3 -1
  42. data/spec/filters/exception_attributes_filter_spec.rb +5 -3
  43. data/spec/filters/gem_root_filter_spec.rb +5 -2
  44. data/spec/filters/git_last_checkout_filter_spec.rb +10 -12
  45. data/spec/filters/git_repository_filter.rb +9 -9
  46. data/spec/filters/git_revision_filter_spec.rb +19 -19
  47. data/spec/filters/keys_allowlist_spec.rb +25 -16
  48. data/spec/filters/keys_blocklist_spec.rb +25 -18
  49. data/spec/filters/root_directory_filter_spec.rb +3 -3
  50. data/spec/filters/sql_filter_spec.rb +26 -26
  51. data/spec/filters/system_exit_filter_spec.rb +4 -2
  52. data/spec/filters/thread_filter_spec.rb +16 -14
  53. data/spec/loggable_spec.rb +2 -2
  54. data/spec/monotonic_time_spec.rb +8 -6
  55. data/spec/nested_exception_spec.rb +46 -46
  56. data/spec/notice_notifier/options_spec.rb +23 -13
  57. data/spec/notice_notifier_spec.rb +52 -47
  58. data/spec/notice_spec.rb +6 -2
  59. data/spec/performance_notifier_spec.rb +67 -60
  60. data/spec/promise_spec.rb +38 -32
  61. data/spec/remote_settings/callback_spec.rb +162 -0
  62. data/spec/remote_settings/settings_data_spec.rb +23 -53
  63. data/spec/remote_settings_spec.rb +42 -75
  64. data/spec/response_spec.rb +34 -12
  65. data/spec/stashable_spec.rb +5 -5
  66. data/spec/stat_spec.rb +7 -5
  67. data/spec/sync_sender_spec.rb +49 -16
  68. data/spec/tdigest_spec.rb +61 -56
  69. data/spec/thread_pool_spec.rb +65 -55
  70. data/spec/time_truncate_spec.rb +4 -2
  71. data/spec/timed_trace_spec.rb +32 -30
  72. data/spec/truncator_spec.rb +72 -43
  73. metadata +53 -47
@@ -22,72 +22,35 @@ RSpec.describe Airbrake::RemoteSettings do
22
22
  }
23
23
  end
24
24
 
25
- let(:config_path) { described_class::CONFIG_DUMP_PATH }
26
- let(:config_dir) { File.dirname(config_path) }
27
-
28
25
  let!(:stub) do
29
26
  stub_request(:get, Regexp.new(endpoint))
30
27
  .to_return(status: 200, body: body.to_json)
31
28
  end
32
29
 
33
- before do
34
- # Do not create config dumps on disk.
35
- allow(Dir).to receive(:mkdir).with(config_dir)
36
- allow(File).to receive(:write).with(config_path, anything)
37
- end
38
-
39
30
  describe ".poll" do
40
31
  describe "config loading" do
41
32
  let(:settings_data) { described_class::SettingsData.new(project_id, body) }
42
33
 
43
34
  before do
44
- allow(File).to receive(:exist?).with(config_path).and_return(true)
45
- allow(File).to receive(:read).with(config_path).and_return(body.to_json)
46
-
47
35
  allow(described_class::SettingsData).to receive(:new).and_return(settings_data)
48
36
  end
49
37
 
50
- it "loads the config from disk" do
51
- expect(File).to receive(:read).with(config_path)
52
- expect(settings_data).to receive(:merge!).with(body).twice
53
-
54
- remote_settings = described_class.poll(project_id, host) {}
55
- sleep(0.2)
56
- remote_settings.stop_polling
57
-
58
- expect(stub).to have_been_requested.once
59
- end
60
-
61
38
  it "yields the config to the block twice" do
62
39
  block = proc {}
63
- expect(block).to receive(:call).twice
40
+ allow(block).to receive(:call)
64
41
 
65
42
  remote_settings = described_class.poll(project_id, host, &block)
66
43
  sleep(0.2)
67
44
  remote_settings.stop_polling
68
45
 
69
46
  expect(stub).to have_been_requested.once
70
- end
71
-
72
- context "when config loading fails" do
73
- it "logs an error" do
74
- expect(File).to receive(:read).and_raise(StandardError)
75
- expect(Airbrake::Loggable.instance).to receive(:error).with(
76
- '**Airbrake: config loading failed: StandardError',
77
- )
78
-
79
- remote_settings = described_class.poll(project_id, host) {}
80
- sleep(0.2)
81
- remote_settings.stop_polling
82
-
83
- expect(stub).to have_been_requested.once
84
- end
47
+ expect(block).to have_received(:call).twice
85
48
  end
86
49
  end
87
50
 
88
51
  context "when no errors are raised" do
89
52
  it "makes a request to AWS S3" do
90
- remote_settings = described_class.poll(project_id, host) {}
53
+ remote_settings = described_class.poll(project_id, host) { anything }
91
54
  sleep(0.1)
92
55
  remote_settings.stop_polling
93
56
 
@@ -95,7 +58,7 @@ RSpec.describe Airbrake::RemoteSettings do
95
58
  end
96
59
 
97
60
  it "sends params about the environment with the request" do
98
- remote_settings = described_class.poll(project_id, host) {}
61
+ remote_settings = described_class.poll(project_id, host) { anything }
99
62
  sleep(0.1)
100
63
  remote_settings.stop_polling
101
64
 
@@ -105,6 +68,7 @@ RSpec.describe Airbrake::RemoteSettings do
105
68
  expect(stub_with_query_params).to have_been_requested.at_least_once
106
69
  end
107
70
 
71
+ # rubocop:disable RSpec/MultipleExpectations
108
72
  it "fetches remote settings" do
109
73
  settings = nil
110
74
  remote_settings = described_class.poll(project_id, host) do |data|
@@ -117,11 +81,12 @@ RSpec.describe Airbrake::RemoteSettings do
117
81
  expect(settings.performance_stats?).to eq(false)
118
82
  expect(settings.interval).to eq(1)
119
83
  end
84
+ # rubocop:enable RSpec/MultipleExpectations
120
85
  end
121
86
 
122
87
  context "when an error is raised while making a HTTP request" do
123
88
  before do
124
- allow(Net::HTTP).to receive(:get).and_raise(StandardError)
89
+ allow(Net::HTTP).to receive(:get_response).and_raise(StandardError)
125
90
  end
126
91
 
127
92
  it "doesn't fetch remote settings" do
@@ -155,10 +120,10 @@ RSpec.describe Airbrake::RemoteSettings do
155
120
  end
156
121
  end
157
122
 
158
- context "when API returns an XML response" do
123
+ context "when API returns a non-200 response" do
159
124
  let!(:stub) do
160
125
  stub_request(:get, Regexp.new(endpoint))
161
- .to_return(status: 200, body: '<?xml ...')
126
+ .to_return(status: 201, body: body.to_json)
162
127
  end
163
128
 
164
129
  it "doesn't update settings data" do
@@ -172,59 +137,61 @@ RSpec.describe Airbrake::RemoteSettings do
172
137
  expect(stub).to have_been_requested.once
173
138
  expect(settings.interval).to eq(600)
174
139
  end
175
- end
176
140
 
177
- context "when a config route is specified in the returned data" do
178
- let(:new_endpoint) do
179
- "http://example.com"
180
- end
141
+ it "logs error" do
142
+ allow(Airbrake::Loggable.instance).to receive(:error)
181
143
 
182
- let(:body) do
183
- { 'config_route' => new_endpoint, 'poll_sec' => 0.1 }
144
+ remote_settings = described_class.poll(project_id, host) { anything }
145
+ sleep(0.1)
146
+ remote_settings.stop_polling
147
+
148
+ expect(Airbrake::Loggable.instance).to have_received(:error).with(body.to_json)
184
149
  end
150
+ end
185
151
 
186
- let!(:new_stub) do
187
- stub_request(:get, Regexp.new(new_endpoint))
152
+ context "when API returns a 200 response" do
153
+ let!(:stub) do
154
+ stub_request(:get, Regexp.new(endpoint))
188
155
  .to_return(status: 200, body: body.to_json)
189
156
  end
190
157
 
191
- it "makes the next request to the specified config route" do
192
- remote_settings = described_class.poll(project_id, host) {}
193
- sleep(0.2)
158
+ it "doesn't log errors" do
159
+ allow(Airbrake::Loggable.instance).to receive(:error)
194
160
 
161
+ remote_settings = described_class.poll(project_id, host) { anything }
162
+ sleep(0.1)
195
163
  remote_settings.stop_polling
196
164
 
165
+ expect(Airbrake::Loggable.instance).not_to have_received(:error)
197
166
  expect(stub).to have_been_requested.once
198
- expect(new_stub).to have_been_requested.once
199
167
  end
200
168
  end
201
- end
202
169
 
203
- describe "#stop_polling" do
204
- it "dumps config data to disk" do
205
- expect(Dir).to receive(:mkdir).with(config_dir)
206
- expect(File).to receive(:write).with(config_path, body.to_json)
207
-
208
- remote_settings = described_class.poll(project_id, host) {}
209
- sleep(0.2)
210
- remote_settings.stop_polling
170
+ # rubocop:disable RSpec/MultipleMemoizedHelpers
171
+ context "when a config route is specified in the returned data" do
172
+ let(:new_config_route) do
173
+ '213/config/111/config.json'
174
+ end
211
175
 
212
- expect(stub).to have_been_requested.once
213
- end
176
+ let(:body) do
177
+ { 'config_route' => new_config_route, 'poll_sec' => 0.1 }
178
+ end
214
179
 
215
- context "when config dumping fails" do
216
- it "logs an error" do
217
- expect(File).to receive(:write).and_raise(StandardError)
218
- expect(Airbrake::Loggable.instance).to receive(:error).with(
219
- '**Airbrake: config dumping failed: StandardError',
220
- )
180
+ let!(:new_stub) do
181
+ stub_request(:get, Regexp.new(new_config_route))
182
+ .to_return(status: 200, body: body.to_json)
183
+ end
221
184
 
222
- remote_settings = described_class.poll(project_id, host) {}
185
+ it "makes the next request to the specified config route" do
186
+ remote_settings = described_class.poll(project_id, host) { anything }
223
187
  sleep(0.2)
188
+
224
189
  remote_settings.stop_polling
225
190
 
226
191
  expect(stub).to have_been_requested.once
192
+ expect(new_stub).to have_been_requested.once
227
193
  end
228
194
  end
195
+ # rubocop:enable RSpec/MultipleMemoizedHelpers
229
196
  end
230
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
@@ -5,19 +5,19 @@ RSpec.describe Airbrake::Stashable do
5
5
  end
6
6
 
7
7
  describe "#stash" do
8
- subject { klass.new }
8
+ subject(:instance) { klass.new }
9
9
 
10
10
  it "returns a hash" do
11
- expect(subject.stash).to be_a(Hash)
11
+ expect(instance.stash).to be_a(Hash)
12
12
  end
13
13
 
14
14
  it "returns an empty hash" do
15
- expect(subject.stash).to be_empty
15
+ expect(instance.stash).to be_empty
16
16
  end
17
17
 
18
18
  it "remembers what was put in the stash" do
19
- subject.stash[:foo] = 1
20
- expect(subject.stash[:foo]).to eq(1)
19
+ instance.stash[:foo] = 1
20
+ expect(instance.stash[:foo]).to eq(1)
21
21
  end
22
22
  end
23
23
  end
data/spec/stat_spec.rb CHANGED
@@ -1,7 +1,9 @@
1
1
  RSpec.describe Airbrake::Stat do
2
+ subject(:stat) { described_class.new }
3
+
2
4
  describe "#to_h" do
3
5
  it "converts to a hash" do
4
- expect(subject.to_h).to eq(
6
+ expect(stat.to_h).to eq(
5
7
  'count' => 0,
6
8
  'sum' => 0.0,
7
9
  'sumsq' => 0.0,
@@ -11,19 +13,19 @@ RSpec.describe Airbrake::Stat do
11
13
  end
12
14
 
13
15
  describe "#increment_ms" do
14
- before { subject.increment_ms(1000) }
16
+ before { stat.increment_ms(1000) }
15
17
 
16
18
  its(:sum) { is_expected.to eq(1000) }
17
19
  its(:sumsq) { is_expected.to eq(1000000) }
18
20
 
19
21
  it "updates tdigest" do
20
- expect(subject.tdigest.size).to eq(1)
22
+ expect(stat.tdigest.size).to eq(1)
21
23
  end
22
24
  end
23
25
 
24
26
  describe "#inspect" do
25
27
  it "provides custom inspect output" do
26
- expect(subject.inspect).to eq(
28
+ expect(stat.inspect).to eq(
27
29
  '#<struct Airbrake::Stat count=0, sum=0.0, sumsq=0.0>',
28
30
  )
29
31
  end
@@ -31,7 +33,7 @@ RSpec.describe Airbrake::Stat do
31
33
 
32
34
  describe "#pretty_print" do
33
35
  it "is an alias of #inspect" do
34
- expect(subject.method(:pretty_print)).to eql(subject.method(:inspect))
36
+ expect(stat.method(:pretty_print)).to eql(stat.method(:inspect))
35
37
  end
36
38
  end
37
39
  end
@@ -1,4 +1,6 @@
1
1
  RSpec.describe Airbrake::SyncSender do
2
+ subject(:sync_sender) { described_class.new }
3
+
2
4
  before do
3
5
  Airbrake::Config.instance = Airbrake::Config.new(
4
6
  project_id: 1, project_key: 'banana',
@@ -14,7 +16,7 @@ RSpec.describe Airbrake::SyncSender do
14
16
  before { stub_request(:post, endpoint).to_return(body: '{}') }
15
17
 
16
18
  it "sets the Content-Type header to JSON" do
17
- subject.send({}, promise)
19
+ sync_sender.send({}, promise)
18
20
  expect(
19
21
  a_request(:post, endpoint).with(
20
22
  headers: { 'Content-Type' => 'application/json' },
@@ -23,7 +25,7 @@ RSpec.describe Airbrake::SyncSender do
23
25
  end
24
26
 
25
27
  it "sets the User-Agent header to the notifier slug" do
26
- subject.send({}, promise)
28
+ sync_sender.send({}, promise)
27
29
  expect(
28
30
  a_request(:post, endpoint).with(
29
31
  headers: {
@@ -36,7 +38,7 @@ RSpec.describe Airbrake::SyncSender do
36
38
  end
37
39
 
38
40
  it "sets the Authorization header to the project key" do
39
- subject.send({}, promise)
41
+ sync_sender.send({}, promise)
40
42
  expect(
41
43
  a_request(:post, endpoint).with(
42
44
  headers: { 'Authorization' => 'Bearer banana' },
@@ -45,19 +47,46 @@ RSpec.describe Airbrake::SyncSender do
45
47
  end
46
48
 
47
49
  it "catches exceptions raised while sending" do
50
+ # rubocop:disable RSpec/VerifiedDoubles
48
51
  https = double("foo")
49
- allow(subject).to receive(:build_https).and_return(https)
52
+ # rubocop:enable RSpec/VerifiedDoubles
53
+
54
+ # rubocop:disable RSpec/SubjectStub
55
+ allow(sync_sender).to receive(:build_https).and_return(https)
56
+ # rubocop:enable RSpec/SubjectStub
57
+
50
58
  allow(https).to receive(:request).and_raise(StandardError.new('foo'))
51
- expect(Airbrake::Loggable.instance).to receive(:error).with(
59
+
60
+ expect(sync_sender.send({}, promise)).to be_an(Airbrake::Promise)
61
+ expect(promise.value).to eq('error' => '**Airbrake: HTTP error: foo')
62
+ end
63
+
64
+ it "logs exceptions raised while sending" do
65
+ allow(Airbrake::Loggable.instance).to receive(:error)
66
+
67
+ # rubocop:disable RSpec/VerifiedDoubles
68
+ https = double("foo")
69
+ # rubocop:enable RSpec/VerifiedDoubles
70
+
71
+ # rubocop:disable RSpec/SubjectStub
72
+ allow(sync_sender).to receive(:build_https).and_return(https)
73
+ # rubocop:enable RSpec/SubjectStub
74
+
75
+ allow(https).to receive(:request).and_raise(StandardError.new('foo'))
76
+
77
+ sync_sender.send({}, promise)
78
+
79
+ expect(Airbrake::Loggable.instance).to have_received(:error).with(
52
80
  /HTTP error: foo/,
53
81
  )
54
- expect(subject.send({}, promise)).to be_an(Airbrake::Promise)
55
- expect(promise.value).to eq('error' => '**Airbrake: HTTP error: foo')
56
82
  end
57
83
 
58
84
  context "when request body is nil" do
85
+ # rubocop:disable RSpec/MultipleExpectations
59
86
  it "doesn't send data" do
60
- expect_any_instance_of(Airbrake::Truncator)
87
+ allow(Airbrake::Loggable.instance).to receive(:error)
88
+
89
+ allow_any_instance_of(Airbrake::Truncator)
61
90
  .to receive(:reduce_max_size).and_return(0)
62
91
 
63
92
  encoded = Base64.encode64("\xD3\xE6\xBC\x9D\xBA").encode!('ASCII-8BIT')
@@ -70,16 +99,18 @@ RSpec.describe Airbrake::SyncSender do
70
99
 
71
100
  notice = Airbrake::Notice.new(ex)
72
101
 
73
- expect(Airbrake::Loggable.instance).to receive(:error).with(
102
+ expect(sync_sender.send(notice, promise)).to be_an(Airbrake::Promise)
103
+ expect(promise.value)
104
+ .to match('error' => '**Airbrake: data was not sent because of missing body')
105
+
106
+ expect(Airbrake::Loggable.instance).to have_received(:error).with(
74
107
  /data was not sent/,
75
108
  )
76
- expect(Airbrake::Loggable.instance).to receive(:error).with(
109
+ expect(Airbrake::Loggable.instance).to have_received(:error).with(
77
110
  /truncation failed/,
78
111
  )
79
- expect(subject.send(notice, promise)).to be_an(Airbrake::Promise)
80
- expect(promise.value)
81
- .to match('error' => '**Airbrake: data was not sent because of missing body')
82
112
  end
113
+ # rubocop:enable RSpec/MultipleExpectations
83
114
  end
84
115
 
85
116
  context "when IP is rate limited" do
@@ -93,13 +124,14 @@ RSpec.describe Airbrake::SyncSender do
93
124
  )
94
125
  end
95
126
 
127
+ # rubocop:disable RSpec/MultipleExpectations
96
128
  it "returns error" do
97
129
  p1 = Airbrake::Promise.new
98
- subject.send({}, p1)
130
+ sync_sender.send({}, p1)
99
131
  expect(p1.value).to match('error' => '**Airbrake: IP is rate limited')
100
132
 
101
133
  p2 = Airbrake::Promise.new
102
- subject.send({}, p2)
134
+ sync_sender.send({}, p2)
103
135
  expect(p2.value).to match('error' => '**Airbrake: IP is rate limited')
104
136
 
105
137
  # Wait for X-RateLimit-Delay and then make a new request to make sure p2
@@ -107,11 +139,12 @@ RSpec.describe Airbrake::SyncSender do
107
139
  sleep 1
108
140
 
109
141
  p3 = Airbrake::Promise.new
110
- subject.send({}, p3)
142
+ sync_sender.send({}, p3)
111
143
  expect(p3.value).to match('error' => '**Airbrake: IP is rate limited')
112
144
 
113
145
  expect(a_request(:post, endpoint)).to have_been_made.twice
114
146
  end
147
+ # rubocop:enable RSpec/MultipleExpectations
115
148
  end
116
149
 
117
150
  context "when the provided method is :put" do