appsignal 4.0.3-java → 4.0.5-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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +51 -0
- data/ext/agent.rb +27 -27
- data/lib/appsignal/check_in/cron.rb +2 -34
- data/lib/appsignal/check_in/scheduler.rb +192 -0
- data/lib/appsignal/check_in.rb +18 -0
- data/lib/appsignal/cli/diagnose.rb +1 -1
- data/lib/appsignal/config.rb +7 -0
- data/lib/appsignal/hooks/at_exit.rb +3 -1
- data/lib/appsignal/hooks/puma.rb +5 -1
- data/lib/appsignal/integrations/puma.rb +45 -0
- data/lib/appsignal/rack/abstract_middleware.rb +3 -47
- data/lib/appsignal/rack/body_wrapper.rb +15 -0
- data/lib/appsignal/rack/event_handler.rb +2 -0
- data/lib/appsignal/rack/hanami_middleware.rb +5 -1
- data/lib/appsignal/rack.rb +68 -0
- data/lib/appsignal/transmitter.rb +30 -7
- data/lib/appsignal/utils/ndjson.rb +15 -0
- data/lib/appsignal/utils.rb +1 -0
- data/lib/appsignal/version.rb +1 -1
- data/lib/appsignal.rb +1 -0
- data/spec/lib/appsignal/check_in/cron_spec.rb +202 -0
- data/spec/lib/appsignal/check_in/scheduler_spec.rb +443 -0
- data/spec/lib/appsignal/config_spec.rb +13 -0
- data/spec/lib/appsignal/environment_spec.rb +1 -1
- data/spec/lib/appsignal/hooks/at_exit_spec.rb +22 -0
- data/spec/lib/appsignal/hooks/puma_spec.rb +31 -23
- data/spec/lib/appsignal/integrations/puma_spec.rb +150 -0
- data/spec/lib/appsignal/probes_spec.rb +1 -6
- data/spec/lib/appsignal/rack/abstract_middleware_spec.rb +41 -122
- data/spec/lib/appsignal/rack/body_wrapper_spec.rb +29 -21
- data/spec/lib/appsignal/rack_spec.rb +180 -0
- data/spec/lib/appsignal/transmitter_spec.rb +48 -2
- data/spec/lib/appsignal_spec.rb +5 -0
- data/spec/spec_helper.rb +0 -7
- data/spec/support/helpers/config_helpers.rb +2 -1
- data/spec/support/helpers/take_at_most_helper.rb +21 -0
- data/spec/support/matchers/contains_log.rb +10 -3
- data/spec/support/mocks/hash_like.rb +10 -0
- data/spec/support/mocks/puma_mock.rb +43 -0
- metadata +11 -3
- data/spec/lib/appsignal/check_in_spec.rb +0 -136
@@ -0,0 +1,443 @@
|
|
1
|
+
describe Appsignal::CheckIn::Scheduler do
|
2
|
+
include WaitForHelper
|
3
|
+
include TakeAtMostHelper
|
4
|
+
|
5
|
+
let(:log_stream) { std_stream }
|
6
|
+
let(:logs) { log_contents(log_stream) }
|
7
|
+
let(:appsignal_options) { {} }
|
8
|
+
let(:transmitter) { Appsignal::Transmitter.new("http://checkin-endpoint.invalid") }
|
9
|
+
|
10
|
+
before do
|
11
|
+
start_agent(:options => appsignal_options, :internal_logger => test_logger(log_stream))
|
12
|
+
allow(transmitter).to receive(:transmit).and_return(Net::HTTPSuccess.new("1.1", 200, "OK"))
|
13
|
+
allow(Appsignal::CheckIn).to receive(:transmitter).and_return(transmitter)
|
14
|
+
allow(Appsignal::CheckIn).to receive(:scheduler).and_return(subject)
|
15
|
+
# Shorten debounce intervals to make the tests run faster.
|
16
|
+
stub_const("Appsignal::CheckIn::Scheduler::INITIAL_DEBOUNCE_SECONDS", 0.1)
|
17
|
+
stub_const("Appsignal::CheckIn::Scheduler::BETWEEN_TRANSMISSIONS_DEBOUNCE_SECONDS", 0.1)
|
18
|
+
end
|
19
|
+
|
20
|
+
after do
|
21
|
+
subject.stop
|
22
|
+
end
|
23
|
+
|
24
|
+
describe "when no event is sent" do
|
25
|
+
it "does not start a thread" do
|
26
|
+
expect(subject.thread).to be_nil
|
27
|
+
end
|
28
|
+
|
29
|
+
it "does not schedule a debounce" do
|
30
|
+
expect(subject.waker).to be_nil
|
31
|
+
end
|
32
|
+
|
33
|
+
it "can be stopped" do
|
34
|
+
# Set all debounce intervals to 10 seconds, to make the assertion
|
35
|
+
# fail if it waits for the debounce -- this ensures that what is being
|
36
|
+
# tested is that no debounces are awaited when stopping the scheduler.
|
37
|
+
stub_const("Appsignal::CheckIn::Scheduler::INITIAL_DEBOUNCE_SECONDS", 10)
|
38
|
+
stub_const("Appsignal::CheckIn::Scheduler::BETWEEN_TRANSMISSIONS_DEBOUNCE_SECONDS", 10)
|
39
|
+
|
40
|
+
take_at_most(0.1) do
|
41
|
+
expect { subject.stop }.not_to raise_error
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
it "can be stopped more than once" do
|
46
|
+
# Set all debounce intervals to 10 seconds, to make the assertion
|
47
|
+
# fail if it waits for the debounce -- this ensures that what is being
|
48
|
+
# tested is that no debounces are awaited when stopping the scheduler.
|
49
|
+
stub_const("Appsignal::CheckIn::Scheduler::INITIAL_DEBOUNCE_SECONDS", 10)
|
50
|
+
stub_const("Appsignal::CheckIn::Scheduler::BETWEEN_TRANSMISSIONS_DEBOUNCE_SECONDS", 10)
|
51
|
+
|
52
|
+
take_at_most(0.1) do
|
53
|
+
expect { subject.stop }.not_to raise_error
|
54
|
+
expect { subject.stop }.not_to raise_error
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
it "closes the queue when stopped" do
|
59
|
+
subject.stop
|
60
|
+
expect(subject.queue.closed?).to be(true)
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
describe "when an event is sent" do
|
65
|
+
it "starts a thread" do
|
66
|
+
Appsignal::CheckIn.cron("test")
|
67
|
+
expect(subject.thread).to be_a(Thread)
|
68
|
+
end
|
69
|
+
|
70
|
+
it "schedules a debounce" do
|
71
|
+
Appsignal::CheckIn.cron("test")
|
72
|
+
expect(subject.waker).to be_a(Thread)
|
73
|
+
end
|
74
|
+
|
75
|
+
it "schedules the event to be transmitted" do
|
76
|
+
expect(transmitter).to receive(:transmit).with([hash_including(
|
77
|
+
:identifier => "test",
|
78
|
+
:check_in_type => "cron",
|
79
|
+
:kind => "finish"
|
80
|
+
)], :format => :ndjson)
|
81
|
+
|
82
|
+
expect(subject.events).to be_empty
|
83
|
+
|
84
|
+
Appsignal::CheckIn.cron("test")
|
85
|
+
|
86
|
+
expect(subject.events).not_to be_empty
|
87
|
+
|
88
|
+
wait_for("the event to be transmitted") { subject.transmitted == 1 }
|
89
|
+
|
90
|
+
expect(subject.events).to be_empty
|
91
|
+
|
92
|
+
expect(logs).to contains_log(:debug, "Scheduling cron check-in `test` finish event")
|
93
|
+
expect(logs).to contains_log(:debug, "Transmitted cron check-in `test` finish event")
|
94
|
+
end
|
95
|
+
|
96
|
+
it "waits for the event to be transmitted when stopped" do
|
97
|
+
# Set all debounce intervals to 10 seconds, to make the test
|
98
|
+
# fail if it waits for the debounce -- this ensures that what is being
|
99
|
+
# tested is that the events are transmitted immediately when the
|
100
|
+
# scheduler is stopped, without waiting for any debounce.
|
101
|
+
stub_const("Appsignal::CheckIn::Scheduler::INITIAL_DEBOUNCE_SECONDS", 10)
|
102
|
+
stub_const("Appsignal::CheckIn::Scheduler::BETWEEN_TRANSMISSIONS_DEBOUNCE_SECONDS", 10)
|
103
|
+
|
104
|
+
expect(transmitter).to receive(:transmit).with([hash_including(
|
105
|
+
:identifier => "test",
|
106
|
+
:check_in_type => "cron",
|
107
|
+
:kind => "finish"
|
108
|
+
)], :format => :ndjson)
|
109
|
+
|
110
|
+
Appsignal::CheckIn.cron("test")
|
111
|
+
|
112
|
+
expect(subject.events).not_to be_empty
|
113
|
+
|
114
|
+
take_at_most(0.1) do
|
115
|
+
expect { subject.stop }.not_to raise_error
|
116
|
+
end
|
117
|
+
|
118
|
+
# Check that the thread wasn't killed before the transmission was
|
119
|
+
# completed.
|
120
|
+
expect(subject.transmitted).to eq(1)
|
121
|
+
|
122
|
+
expect(subject.events).to be_empty
|
123
|
+
|
124
|
+
expect(logs).to contains_log(:debug, "Scheduling cron check-in `test` finish event")
|
125
|
+
expect(logs).to contains_log(:debug, "Transmitted cron check-in `test` finish event")
|
126
|
+
end
|
127
|
+
|
128
|
+
it "can be stopped more than once" do
|
129
|
+
# Set all debounce intervals to 10 seconds, to make the test
|
130
|
+
# fail if it waits for the debounce -- this ensures that what is being
|
131
|
+
# tested is that the events are transmitted immediately when the
|
132
|
+
# scheduler is stopped, without waiting for the debounce interval.
|
133
|
+
stub_const("Appsignal::CheckIn::Scheduler::INITIAL_DEBOUNCE_SECONDS", 10)
|
134
|
+
stub_const("Appsignal::CheckIn::Scheduler::BETWEEN_TRANSMISSIONS_DEBOUNCE_SECONDS", 10)
|
135
|
+
|
136
|
+
Appsignal::CheckIn.cron("test")
|
137
|
+
take_at_most(0.1) do
|
138
|
+
expect { subject.stop }.not_to raise_error
|
139
|
+
end
|
140
|
+
|
141
|
+
# Check that the thread wasn't killed before the transmission was
|
142
|
+
# completed.
|
143
|
+
expect(subject.transmitted).to eq(1)
|
144
|
+
|
145
|
+
take_at_most(0.1) do
|
146
|
+
expect { subject.stop }.not_to raise_error
|
147
|
+
end
|
148
|
+
end
|
149
|
+
|
150
|
+
it "closes the queue when stopped" do
|
151
|
+
Appsignal::CheckIn.cron("test")
|
152
|
+
subject.stop
|
153
|
+
expect(subject.queue.closed?).to be(true)
|
154
|
+
end
|
155
|
+
|
156
|
+
it "kills the thread when stopped" do
|
157
|
+
Appsignal::CheckIn.cron("test")
|
158
|
+
subject.stop
|
159
|
+
expect(subject.thread.alive?).to be(false)
|
160
|
+
end
|
161
|
+
|
162
|
+
it "unschedules the debounce when stopped" do
|
163
|
+
Appsignal::CheckIn.cron("test")
|
164
|
+
waker = subject.waker
|
165
|
+
subject.stop
|
166
|
+
expect(waker.alive?).to be(false)
|
167
|
+
expect(subject.waker).to be_nil
|
168
|
+
end
|
169
|
+
end
|
170
|
+
|
171
|
+
describe "when many events are sent" do
|
172
|
+
describe "within the short debounce interval" do
|
173
|
+
it "transmits all events at once" do
|
174
|
+
expect(transmitter).to receive(:transmit).with(
|
175
|
+
["first", "second", "third"].map do |identifier|
|
176
|
+
hash_including(
|
177
|
+
:identifier => identifier,
|
178
|
+
:check_in_type => "cron",
|
179
|
+
:kind => "finish"
|
180
|
+
)
|
181
|
+
end, :format => :ndjson
|
182
|
+
)
|
183
|
+
|
184
|
+
Appsignal::CheckIn.cron("first")
|
185
|
+
Appsignal::CheckIn.cron("second")
|
186
|
+
Appsignal::CheckIn.cron("third")
|
187
|
+
|
188
|
+
wait_for("the events to be transmitted") { subject.transmitted == 1 }
|
189
|
+
end
|
190
|
+
|
191
|
+
it "transmits all events at once when stopped" do
|
192
|
+
# Set a short debounce interval of 10 seconds, to make the final wait
|
193
|
+
# fail if it waits for the debounce -- this ensures that what is being
|
194
|
+
# tested is that the events are transmitted when the scheduler is
|
195
|
+
# stopped.
|
196
|
+
stub_const("Appsignal::CheckIn::Scheduler::INITIAL_DEBOUNCE_SECONDS", 10)
|
197
|
+
|
198
|
+
expect(transmitter).to receive(:transmit).with(
|
199
|
+
["first", "second", "third"].map do |identifier|
|
200
|
+
hash_including(
|
201
|
+
:identifier => identifier,
|
202
|
+
:check_in_type => "cron",
|
203
|
+
:kind => "finish"
|
204
|
+
)
|
205
|
+
end, :format => :ndjson
|
206
|
+
)
|
207
|
+
|
208
|
+
Appsignal::CheckIn.cron("first")
|
209
|
+
Appsignal::CheckIn.cron("second")
|
210
|
+
Appsignal::CheckIn.cron("third")
|
211
|
+
|
212
|
+
subject.stop
|
213
|
+
|
214
|
+
wait_for("the events to be transmitted") { subject.transmitted == 1 }
|
215
|
+
end
|
216
|
+
end
|
217
|
+
|
218
|
+
describe "further apart than the short debounce interval" do
|
219
|
+
it "transmits the first event and enqueues future events" do
|
220
|
+
expect(transmitter).to receive(:transmit).with([hash_including(
|
221
|
+
:identifier => "first",
|
222
|
+
:check_in_type => "cron",
|
223
|
+
:kind => "finish"
|
224
|
+
)], :format => :ndjson)
|
225
|
+
|
226
|
+
Appsignal::CheckIn.cron("first")
|
227
|
+
|
228
|
+
wait_for("the first event to be transmitted") { subject.transmitted == 1 }
|
229
|
+
|
230
|
+
Appsignal::CheckIn.cron("second")
|
231
|
+
Appsignal::CheckIn.cron("third")
|
232
|
+
|
233
|
+
expect(subject.events).to match(["second", "third"].map do |identifier|
|
234
|
+
hash_including({
|
235
|
+
:identifier => identifier,
|
236
|
+
:check_in_type => "cron",
|
237
|
+
:kind => "finish"
|
238
|
+
})
|
239
|
+
end)
|
240
|
+
end
|
241
|
+
|
242
|
+
it "transmits the other events after the debounce interval" do
|
243
|
+
expect(transmitter).to receive(:transmit)
|
244
|
+
|
245
|
+
Appsignal::CheckIn.cron("first")
|
246
|
+
|
247
|
+
wait_for("the first event to be transmitted") { subject.transmitted == 1 }
|
248
|
+
|
249
|
+
expect(transmitter).to receive(:transmit).with(
|
250
|
+
["second", "third"].map do |identifier|
|
251
|
+
hash_including(
|
252
|
+
:identifier => identifier,
|
253
|
+
:check_in_type => "cron",
|
254
|
+
:kind => "finish"
|
255
|
+
)
|
256
|
+
end, :format => :ndjson
|
257
|
+
)
|
258
|
+
|
259
|
+
Appsignal::CheckIn.cron("second")
|
260
|
+
Appsignal::CheckIn.cron("third")
|
261
|
+
|
262
|
+
expect(subject.events).to_not be_empty
|
263
|
+
|
264
|
+
wait_for("the other events to be transmitted") { subject.transmitted == 2 }
|
265
|
+
|
266
|
+
expect(subject.events).to be_empty
|
267
|
+
|
268
|
+
expect(logs).to contains_log(:debug, "Scheduling cron check-in `first` finish event")
|
269
|
+
expect(logs).to contains_log(:debug, "Transmitted cron check-in `first` finish event")
|
270
|
+
expect(logs).to contains_log(:debug, "Scheduling cron check-in `second` finish event")
|
271
|
+
expect(logs).to contains_log(:debug, "Scheduling cron check-in `third` finish event")
|
272
|
+
expect(logs).to contains_log(:debug, "Transmitted 2 check-in events")
|
273
|
+
end
|
274
|
+
|
275
|
+
it "transmits the other events when stopped" do
|
276
|
+
# Restore the original long debounce interval of 10 seconds, to make
|
277
|
+
# the final wait fail if it waits for the debounce -- this ensures
|
278
|
+
# that what is being tested is that the events are transmitted
|
279
|
+
# immediately when the scheduler is stopped.
|
280
|
+
stub_const("Appsignal::CheckIn::Scheduler::BETWEEN_TRANSMISSIONS_DEBOUNCE_SECONDS", 10)
|
281
|
+
|
282
|
+
expect(transmitter).to receive(:transmit)
|
283
|
+
|
284
|
+
Appsignal::CheckIn.cron("first")
|
285
|
+
|
286
|
+
wait_for("the event to be transmitted") { subject.transmitted == 1 }
|
287
|
+
|
288
|
+
expect(transmitter).to receive(:transmit).with(
|
289
|
+
["second", "third"].map do |identifier|
|
290
|
+
hash_including(
|
291
|
+
:identifier => identifier,
|
292
|
+
:check_in_type => "cron",
|
293
|
+
:kind => "finish"
|
294
|
+
)
|
295
|
+
end, :format => :ndjson
|
296
|
+
)
|
297
|
+
|
298
|
+
Appsignal::CheckIn.cron("second")
|
299
|
+
Appsignal::CheckIn.cron("third")
|
300
|
+
|
301
|
+
expect(subject.events).to_not be_empty
|
302
|
+
|
303
|
+
subject.stop
|
304
|
+
|
305
|
+
wait_for("the other events to be transmitted") { subject.transmitted == 2 }
|
306
|
+
|
307
|
+
expect(subject.events).to be_empty
|
308
|
+
|
309
|
+
expect(logs).to contains_log(:debug, "Scheduling cron check-in `first` finish event")
|
310
|
+
expect(logs).to contains_log(:debug, "Transmitted cron check-in `first` finish event")
|
311
|
+
expect(logs).to contains_log(:debug, "Scheduling cron check-in `second` finish event")
|
312
|
+
expect(logs).to contains_log(:debug, "Scheduling cron check-in `third` finish event")
|
313
|
+
expect(logs).to contains_log(:debug, "Transmitted 2 check-in events")
|
314
|
+
end
|
315
|
+
end
|
316
|
+
end
|
317
|
+
|
318
|
+
describe "when a similar event is sent more than once" do
|
319
|
+
it "only transmits one of the similar events" do
|
320
|
+
# We must instantiate `Appsignal::CheckIn::Cron` directly, as the
|
321
|
+
# `.cron` helper would use a different digest for each invocation.
|
322
|
+
cron = Appsignal::CheckIn::Cron.new(:identifier => "test")
|
323
|
+
|
324
|
+
expect(transmitter).to receive(:transmit).with([hash_including(
|
325
|
+
:identifier => "test",
|
326
|
+
:check_in_type => "cron",
|
327
|
+
:kind => "start"
|
328
|
+
)], :format => :ndjson)
|
329
|
+
|
330
|
+
cron.start
|
331
|
+
cron.start
|
332
|
+
|
333
|
+
wait_for("the event to be transmitted") { subject.transmitted == 1 }
|
334
|
+
|
335
|
+
expect(logs).to contains_log(
|
336
|
+
:debug,
|
337
|
+
"Scheduling cron check-in `test` start event (digest #{cron.digest}) to be transmitted"
|
338
|
+
)
|
339
|
+
expect(logs).to contains_log(
|
340
|
+
:debug,
|
341
|
+
"Scheduling cron check-in `test` start event (digest #{cron.digest}) to be transmitted"
|
342
|
+
)
|
343
|
+
expect(logs).to contains_log(
|
344
|
+
:debug,
|
345
|
+
"Replacing previously scheduled cron check-in `test` start event (digest #{cron.digest})"
|
346
|
+
)
|
347
|
+
expect(logs).to contains_log(
|
348
|
+
:debug,
|
349
|
+
"Transmitted cron check-in `test` start event (digest #{cron.digest})"
|
350
|
+
)
|
351
|
+
end
|
352
|
+
end
|
353
|
+
|
354
|
+
describe "when the scheduler is stopped" do
|
355
|
+
it "does not schedule any events to be transmitted" do
|
356
|
+
expect(transmitter).not_to receive(:transmit)
|
357
|
+
|
358
|
+
subject.stop
|
359
|
+
|
360
|
+
Appsignal::CheckIn.cron("test")
|
361
|
+
|
362
|
+
expect(subject.events).to be_empty
|
363
|
+
|
364
|
+
expect(logs).to contains_log(
|
365
|
+
:debug,
|
366
|
+
/Cannot transmit cron check-in `test` finish event .+: AppSignal is stopped/
|
367
|
+
)
|
368
|
+
end
|
369
|
+
end
|
370
|
+
|
371
|
+
describe "when AppSignal is not active" do
|
372
|
+
let(:appsignal_options) { { :active => false } }
|
373
|
+
|
374
|
+
it "does not schedule any events to be transmitted" do
|
375
|
+
subject.stop
|
376
|
+
|
377
|
+
Appsignal::CheckIn.cron("test")
|
378
|
+
|
379
|
+
expect(subject.events).to be_empty
|
380
|
+
|
381
|
+
expect(logs).to contains_log(
|
382
|
+
:debug,
|
383
|
+
/Cannot transmit cron check-in `test` finish event .+: AppSignal is not active/
|
384
|
+
)
|
385
|
+
end
|
386
|
+
end
|
387
|
+
|
388
|
+
describe "when transmitting returns a non-success response code" do
|
389
|
+
it "logs the error and continues" do
|
390
|
+
expect(transmitter).to receive(:transmit).and_return(
|
391
|
+
Net::HTTPNotFound.new("1.1", 404, "Not Found")
|
392
|
+
)
|
393
|
+
|
394
|
+
Appsignal::CheckIn.cron("first")
|
395
|
+
|
396
|
+
wait_for("the first event to be transmitted") { subject.transmitted == 1 }
|
397
|
+
|
398
|
+
expect(transmitter).to receive(:transmit).and_return(
|
399
|
+
Net::HTTPSuccess.new("1.1", 200, "OK")
|
400
|
+
)
|
401
|
+
|
402
|
+
Appsignal::CheckIn.cron("second")
|
403
|
+
|
404
|
+
wait_for("the second event to be transmitted") { subject.transmitted == 2 }
|
405
|
+
|
406
|
+
expect(logs).to contains_log(
|
407
|
+
:error,
|
408
|
+
/Failed to transmit cron check-in `first` finish event .+: 404 status code/
|
409
|
+
)
|
410
|
+
expect(logs).to contains_log(
|
411
|
+
:debug,
|
412
|
+
"Transmitted cron check-in `second` finish event"
|
413
|
+
)
|
414
|
+
end
|
415
|
+
end
|
416
|
+
|
417
|
+
describe "when transmitting throws an error" do
|
418
|
+
it "logs the error and continues" do
|
419
|
+
expect(transmitter).to receive(:transmit).and_raise("Something went wrong")
|
420
|
+
|
421
|
+
Appsignal::CheckIn.cron("first")
|
422
|
+
|
423
|
+
wait_for("the first event to be transmitted") { subject.transmitted == 1 }
|
424
|
+
|
425
|
+
expect(transmitter).to receive(:transmit).and_return(
|
426
|
+
Net::HTTPSuccess.new("1.1", 200, "OK")
|
427
|
+
)
|
428
|
+
|
429
|
+
Appsignal::CheckIn.cron("second")
|
430
|
+
|
431
|
+
wait_for("the second event to be transmitted") { subject.transmitted == 2 }
|
432
|
+
|
433
|
+
expect(logs).to contains_log(
|
434
|
+
:error,
|
435
|
+
/Failed to transmit cron check-in `first` finish event .+: Something went wrong/
|
436
|
+
)
|
437
|
+
expect(logs).to contains_log(
|
438
|
+
:debug,
|
439
|
+
"Transmitted cron check-in `second` finish event"
|
440
|
+
)
|
441
|
+
end
|
442
|
+
end
|
443
|
+
end
|
@@ -1,5 +1,18 @@
|
|
1
1
|
describe Appsignal::Config do
|
2
2
|
describe ".add_loader_defaults" do
|
3
|
+
context "when the config is initialized" do
|
4
|
+
before { Appsignal.configure(:test) }
|
5
|
+
|
6
|
+
it "logs a warning" do
|
7
|
+
logs = capture_logs { described_class.add_loader_defaults(:loader1) }
|
8
|
+
|
9
|
+
expect(logs).to contains_log(
|
10
|
+
:warn,
|
11
|
+
"The config defaults from the 'loader1' loader are ignored"
|
12
|
+
)
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
3
16
|
it "adds loader defaults to the list" do
|
4
17
|
described_class.add_loader_defaults(:loader1)
|
5
18
|
|
@@ -120,7 +120,7 @@ describe Appsignal::Environment do
|
|
120
120
|
|
121
121
|
expect(logs).to be_empty
|
122
122
|
|
123
|
-
|
123
|
+
unless Bundler.rubygems.respond_to?(:all_specs)
|
124
124
|
skip "Using new Bundler version without `all_specs` method"
|
125
125
|
end
|
126
126
|
bundle_gem_specs = silence { ::Bundler.rubygems.all_specs }
|
@@ -40,6 +40,17 @@ describe Appsignal::Hooks::AtExit::AtExitCallback do
|
|
40
40
|
Appsignal::Hooks::AtExit::AtExitCallback.call
|
41
41
|
end
|
42
42
|
|
43
|
+
it "reports no transaction if the process didn't exit with an error" do
|
44
|
+
logs =
|
45
|
+
capture_logs do
|
46
|
+
expect do
|
47
|
+
call_callback
|
48
|
+
end.to_not(change { created_transactions.count })
|
49
|
+
end
|
50
|
+
|
51
|
+
expect(logs).to_not contains_log(:error, "Appsignal.report_error: Cannot add error.")
|
52
|
+
end
|
53
|
+
|
43
54
|
it "reports an error if there's an unhandled error" do
|
44
55
|
expect do
|
45
56
|
with_error(ExampleException, "error message") do
|
@@ -80,4 +91,15 @@ describe Appsignal::Hooks::AtExit::AtExitCallback do
|
|
80
91
|
end.to_not change { created_transactions.count }.from(1)
|
81
92
|
end
|
82
93
|
end
|
94
|
+
|
95
|
+
it "doesn't report the error if it is a SignalException exception" do
|
96
|
+
with_error(SignalException, "TERM") do |error|
|
97
|
+
Appsignal.report_error(error)
|
98
|
+
expect(created_transactions.count).to eq(1)
|
99
|
+
|
100
|
+
expect do
|
101
|
+
call_callback
|
102
|
+
end.to_not change { created_transactions.count }.from(1)
|
103
|
+
end
|
104
|
+
end
|
83
105
|
end
|
@@ -1,34 +1,45 @@
|
|
1
1
|
describe Appsignal::Hooks::PumaHook do
|
2
2
|
context "with puma" do
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
3
|
+
let(:puma_version) { "6.0.0" }
|
4
|
+
before do
|
5
|
+
stub_const("Puma", PumaMock)
|
6
|
+
stub_const("Puma::Const::VERSION", puma_version)
|
7
|
+
end
|
8
|
+
|
9
|
+
describe "#dependencies_present?" do
|
10
|
+
subject { described_class.new.dependencies_present? }
|
11
|
+
|
12
|
+
context "when Puma present" do
|
13
|
+
context "when Puma is newer than version 3.0.0" do
|
14
|
+
let(:puma_version) { "3.0.0" }
|
7
15
|
|
8
|
-
|
9
|
-
@cli_config ||= CliConfig.new
|
16
|
+
it { is_expected.to be_truthy }
|
10
17
|
end
|
11
|
-
end
|
12
18
|
|
13
|
-
|
14
|
-
|
19
|
+
context "when Puma is older than version 3.0.0" do
|
20
|
+
let(:puma_version) { "2.9.9" }
|
15
21
|
|
16
|
-
|
17
|
-
@options = {}
|
22
|
+
it { is_expected.to be_falsey }
|
18
23
|
end
|
19
24
|
end
|
20
|
-
end
|
21
|
-
after(:context) { Object.send(:remove_const, :Puma) }
|
22
25
|
|
23
|
-
|
24
|
-
|
26
|
+
context "when Puma is not present" do
|
27
|
+
before do
|
28
|
+
hide_const("Puma")
|
29
|
+
end
|
25
30
|
|
26
|
-
|
31
|
+
it { is_expected.to be_falsey }
|
32
|
+
end
|
27
33
|
end
|
28
34
|
|
29
35
|
describe "installation" do
|
30
36
|
before { Appsignal::Probes.probes.clear }
|
31
37
|
|
38
|
+
it "adds the Puma::Server patch" do
|
39
|
+
Appsignal::Hooks::PumaHook.new.install
|
40
|
+
expect(::Puma::Server.included_modules).to include(Appsignal::Integrations::PumaServer)
|
41
|
+
end
|
42
|
+
|
32
43
|
context "when not clustered mode" do
|
33
44
|
it "does not add AppSignal stop behavior Puma::Cluster" do
|
34
45
|
expect(defined?(::Puma::Cluster)).to be_falsy
|
@@ -39,15 +50,12 @@ describe Appsignal::Hooks::PumaHook do
|
|
39
50
|
|
40
51
|
context "when in clustered mode" do
|
41
52
|
before do
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
@called = true
|
46
|
-
end
|
53
|
+
stub_const("Puma::Cluster", Class.new do
|
54
|
+
def stop_workers
|
55
|
+
@called = true
|
47
56
|
end
|
48
|
-
end
|
57
|
+
end)
|
49
58
|
end
|
50
|
-
after { Puma.send(:remove_const, :Cluster) }
|
51
59
|
|
52
60
|
it "adds behavior to Puma::Cluster.stop_workers" do
|
53
61
|
Appsignal::Hooks::PumaHook.new.install
|