appsignal 3.7.0 → 3.7.2

Sign up to get free protection for your applications and to get access to all the features.
data/lib/appsignal.rb CHANGED
@@ -5,7 +5,7 @@ require "securerandom"
5
5
  require "stringio"
6
6
 
7
7
  require "appsignal/logger"
8
- require "appsignal/utils/deprecation_message"
8
+ require "appsignal/utils/stdout_and_logger_message"
9
9
  require "appsignal/helpers/instrumentation"
10
10
  require "appsignal/helpers/metrics"
11
11
 
@@ -120,7 +120,7 @@ module Appsignal
120
120
  Appsignal::Environment.report_enabled("allocation_tracking")
121
121
  end
122
122
 
123
- Appsignal::Minutely.start if config[:enable_minutely_probes]
123
+ Appsignal::Probes.start if config[:enable_minutely_probes]
124
124
 
125
125
  collect_environment_metadata
126
126
  else
@@ -152,6 +152,7 @@ module Appsignal
152
152
  internal_logger.debug("Stopping appsignal")
153
153
  end
154
154
  Appsignal::Extension.stop
155
+ Appsignal::Probes.stop
155
156
  end
156
157
 
157
158
  def forked
@@ -218,7 +219,10 @@ module Appsignal
218
219
  else
219
220
  Appsignal::Config::DEFAULT_LOG_LEVEL
220
221
  end
221
- internal_logger << @in_memory_log.string if @in_memory_log
222
+ return unless @in_memory_log
223
+
224
+ internal_logger << @in_memory_log.string
225
+ @in_memory_log = nil
222
226
  end
223
227
 
224
228
  # Returns if the C-extension was loaded properly.
@@ -287,6 +291,22 @@ module Appsignal
287
291
  end
288
292
  Appsignal::Environment.report_supported_gems
289
293
  end
294
+
295
+ # Alias constants that have moved with a warning message that points to the
296
+ # place to update the reference.
297
+ def const_missing(name)
298
+ case name
299
+ when :Minutely
300
+ callers = caller
301
+ Appsignal::Utils::StdoutAndLoggerMessage.warning \
302
+ "The constant Appsignal::Minutely has been deprecated. " \
303
+ "Please update the constant name to Appsignal::Probes " \
304
+ "in the following file to remove this message.\n#{callers.first}"
305
+ Appsignal::Probes
306
+ else
307
+ super
308
+ end
309
+ end
290
310
  end
291
311
  end
292
312
 
@@ -300,7 +320,6 @@ require "appsignal/event_formatter"
300
320
  require "appsignal/hooks"
301
321
  require "appsignal/probes"
302
322
  require "appsignal/marker"
303
- require "appsignal/minutely"
304
323
  require "appsignal/garbage_collection"
305
324
  require "appsignal/integrations/railtie" if defined?(::Rails)
306
325
  require "appsignal/transaction"
@@ -757,7 +757,10 @@ describe Appsignal::Config do
757
757
  let(:out_stream) { std_stream }
758
758
  let(:output) { out_stream.read }
759
759
  let(:config) { project_fixture_config("production", :log_path => log_path) }
760
- subject { capture_stdout(out_stream) { config.log_file_path } }
760
+
761
+ def log_file_path
762
+ capture_stdout(out_stream) { config.log_file_path }
763
+ end
761
764
 
762
765
  context "when path is writable" do
763
766
  let(:log_path) { File.join(tmp_dir, "writable-path") }
@@ -765,11 +768,11 @@ describe Appsignal::Config do
765
768
  after { FileUtils.rm_rf(log_path) }
766
769
 
767
770
  it "returns log file path" do
768
- expect(subject).to eq File.join(log_path, "appsignal.log")
771
+ expect(log_file_path).to eq File.join(log_path, "appsignal.log")
769
772
  end
770
773
 
771
774
  it "prints no warning" do
772
- subject
775
+ log_file_path
773
776
  expect(output).to be_empty
774
777
  end
775
778
  end
@@ -783,28 +786,47 @@ describe Appsignal::Config do
783
786
  before { FileUtils.chmod(0o777, system_tmp_dir) }
784
787
 
785
788
  it "returns returns the tmp location" do
786
- expect(subject).to eq(File.join(system_tmp_dir, "appsignal.log"))
789
+ expect(log_file_path).to eq(File.join(system_tmp_dir, "appsignal.log"))
787
790
  end
788
791
 
789
792
  it "prints a warning" do
790
- subject
793
+ log_file_path
791
794
  expect(output).to include "appsignal: Unable to log to '#{log_path}'. " \
792
795
  "Logging to '#{system_tmp_dir}' instead."
793
796
  end
797
+
798
+ it "prints a warning once" do
799
+ capture_stdout(out_stream) do
800
+ log_file_path
801
+ log_file_path
802
+ end
803
+ message = "appsignal: Unable to log to '#{log_path}'. " \
804
+ "Logging to '#{system_tmp_dir}' instead."
805
+ expect(output.scan(message).count).to eq(1)
806
+ end
794
807
  end
795
808
 
796
809
  context "when the /tmp fallback path is not writable" do
797
810
  before { FileUtils.chmod(0o555, system_tmp_dir) }
798
811
 
799
812
  it "returns nil" do
800
- expect(subject).to be_nil
813
+ expect(log_file_path).to be_nil
801
814
  end
802
815
 
803
816
  it "prints a warning" do
804
- subject
817
+ log_file_path
805
818
  expect(output).to include "appsignal: Unable to log to '#{log_path}' " \
806
819
  "or the '#{system_tmp_dir}' fallback."
807
820
  end
821
+
822
+ it "prints a warning once" do
823
+ capture_stdout(out_stream) do
824
+ log_file_path
825
+ log_file_path
826
+ end
827
+ message = "appsignal: Unable to log to '#{log_path}' or the '#{system_tmp_dir}' fallback."
828
+ expect(output.scan(message).count).to eq(1)
829
+ end
808
830
  end
809
831
  end
810
832
 
@@ -819,11 +841,11 @@ describe Appsignal::Config do
819
841
 
820
842
  context "when root_path is set" do
821
843
  it "returns returns the project log location" do
822
- expect(subject).to eq File.join(config.root_path, "log/appsignal.log")
844
+ expect(log_file_path).to eq File.join(config.root_path, "log/appsignal.log")
823
845
  end
824
846
 
825
847
  it "prints no warning" do
826
- subject
848
+ log_file_path
827
849
  expect(output).to be_empty
828
850
  end
829
851
  end
@@ -883,7 +905,7 @@ describe Appsignal::Config do
883
905
  end
884
906
 
885
907
  it "returns real path of log path" do
886
- expect(subject).to eq(File.join(real_path, "appsignal.log"))
908
+ expect(log_file_path).to eq(File.join(real_path, "appsignal.log"))
887
909
  end
888
910
  end
889
911
  end
@@ -93,7 +93,7 @@ describe Appsignal::Hooks::GvlHook do
93
93
  it "is added to minutely probes" do
94
94
  Appsignal::Hooks.load_hooks
95
95
 
96
- expect(Appsignal::Minutely.probes[:gvl]).to be Appsignal::Probes::GvlProbe
96
+ expect(Appsignal::Probes.probes[:gvl]).to be Appsignal::Probes::GvlProbe
97
97
  end
98
98
  end
99
99
  end
@@ -16,7 +16,7 @@ describe Appsignal::Hooks::MriHook do
16
16
  end
17
17
 
18
18
  it "should be added to minutely probes" do
19
- expect(Appsignal::Minutely.probes[:mri]).to be Appsignal::Probes::MriProbe
19
+ expect(Appsignal::Probes.probes[:mri]).to be Appsignal::Probes::MriProbe
20
20
  end
21
21
  end
22
22
  end
@@ -27,7 +27,7 @@ describe Appsignal::Hooks::PumaHook do
27
27
  end
28
28
 
29
29
  describe "installation" do
30
- before { Appsignal::Minutely.probes.clear }
30
+ before { Appsignal::Probes.probes.clear }
31
31
 
32
32
  context "when not clustered mode" do
33
33
  it "does not add AppSignal stop behavior Puma::Cluster" do
@@ -1,11 +1,40 @@
1
- describe Appsignal::Minutely do
1
+ describe Appsignal::Probes do
2
2
  include WaitForHelper
3
3
 
4
- before { Appsignal::Minutely.probes.clear }
4
+ before { Appsignal::Probes.probes.clear }
5
+
6
+ context "Minutely constant" do
7
+ let(:err_stream) { std_stream }
8
+ let(:stderr) { err_stream.read }
9
+
10
+ it "returns the Probes constant calling the Minutely constant" do
11
+ silence { expect(Appsignal::Minutely).to be(Appsignal::Probes) }
12
+ end
13
+
14
+ it "prints a deprecation warning to STDERR" do
15
+ capture_std_streams(std_stream, err_stream) do
16
+ expect(Appsignal::Minutely).to be(Appsignal::Probes)
17
+ end
18
+
19
+ expect(stderr)
20
+ .to include("appsignal WARNING: The constant Appsignal::Minutely has been deprecated.")
21
+ end
22
+
23
+ it "logs a warning to STDERR" do
24
+ logs =
25
+ capture_logs do
26
+ silence do
27
+ expect(Appsignal::Minutely).to be(Appsignal::Probes)
28
+ end
29
+ end
30
+
31
+ expect(logs).to include("The constant Appsignal::Minutely has been deprecated.")
32
+ end
33
+ end
5
34
 
6
35
  it "returns a ProbeCollection" do
7
- expect(Appsignal::Minutely.probes)
8
- .to be_instance_of(Appsignal::Minutely::ProbeCollection)
36
+ expect(Appsignal::Probes.probes)
37
+ .to be_instance_of(Appsignal::Probes::ProbeCollection)
9
38
  end
10
39
 
11
40
  describe ".start" do
@@ -43,16 +72,31 @@ describe Appsignal::Minutely do
43
72
  let(:log) { log_contents(log_stream) }
44
73
  before do
45
74
  Appsignal.internal_logger = test_logger(log_stream)
46
- # Speed up test time
47
- allow(Appsignal::Minutely).to receive(:initial_wait_time).and_return(0.001)
48
- allow(Appsignal::Minutely).to receive(:wait_time).and_return(0.001)
75
+ speed_up_tests!
76
+ end
77
+
78
+ describe ".started?" do
79
+ it "returns true when the probes thread has been started" do
80
+ expect(Appsignal::Probes.started?).to be_falsy
81
+ Appsignal::Probes.register :my_probe, (lambda {})
82
+ Appsignal::Probes.start
83
+ expect(Appsignal::Probes.started?).to be_truthy
84
+ end
85
+
86
+ it "returns false when the probes thread has been stopped" do
87
+ Appsignal::Probes.register :my_probe, lambda {}
88
+ Appsignal::Probes.start
89
+ expect(Appsignal::Probes.started?).to be_truthy
90
+ Appsignal::Probes.stop
91
+ expect(Appsignal::Probes.started?).to be_falsy
92
+ end
49
93
  end
50
94
 
51
95
  context "with an instance of a class" do
52
96
  it "calls the probe every <wait_time>" do
53
97
  probe = MockProbe.new
54
- Appsignal::Minutely.probes.register :my_probe, probe
55
- Appsignal::Minutely.start
98
+ Appsignal::Probes.register :my_probe, probe
99
+ Appsignal::Probes.start
56
100
 
57
101
  wait_for("enough probe calls") { probe.calls >= 2 }
58
102
  expect(log).to contains_log(:debug, "Gathering minutely metrics with 1 probe")
@@ -63,11 +107,11 @@ describe Appsignal::Minutely do
63
107
  it "does not initialize the probe" do
64
108
  # Working probe which we can use to wait for X ticks
65
109
  working_probe = ProbeWithoutDependency.new
66
- Appsignal::Minutely.probes.register :probe_without_dep, working_probe
110
+ Appsignal::Probes.register :probe_without_dep, working_probe
67
111
 
68
112
  probe = ProbeWithMissingDependency.new
69
- Appsignal::Minutely.probes.register :probe_with_missing_dep, probe
70
- Appsignal::Minutely.start
113
+ Appsignal::Probes.register :probe_with_missing_dep, probe
114
+ Appsignal::Probes.start
71
115
 
72
116
  wait_for("enough probe calls") { working_probe.calls >= 2 }
73
117
  # Only counts initialized probes
@@ -83,8 +127,8 @@ describe Appsignal::Minutely do
83
127
  probe = MockProbe
84
128
  probe_instance = MockProbe.new
85
129
  expect(probe).to receive(:new).and_return(probe_instance)
86
- Appsignal::Minutely.probes.register :my_probe, probe
87
- Appsignal::Minutely.start
130
+ Appsignal::Probes.register :my_probe, probe
131
+ Appsignal::Probes.start
88
132
 
89
133
  wait_for("enough probe calls") { probe_instance.calls >= 2 }
90
134
  expect(log).to contains_log(:debug, "Gathering minutely metrics with 1 probe")
@@ -97,11 +141,11 @@ describe Appsignal::Minutely do
97
141
  working_probe = ProbeWithoutDependency
98
142
  working_probe_instance = working_probe.new
99
143
  expect(working_probe).to receive(:new).and_return(working_probe_instance)
100
- Appsignal::Minutely.probes.register :probe_without_dep, working_probe
144
+ Appsignal::Probes.register :probe_without_dep, working_probe
101
145
 
102
146
  probe = ProbeWithMissingDependency
103
- Appsignal::Minutely.probes.register :probe_with_missing_dep, probe
104
- Appsignal::Minutely.start
147
+ Appsignal::Probes.register :probe_with_missing_dep, probe
148
+ Appsignal::Probes.start
105
149
 
106
150
  wait_for("enough probe calls") { working_probe_instance.calls >= 2 }
107
151
  # Only counts initialized probes
@@ -117,11 +161,11 @@ describe Appsignal::Minutely do
117
161
  working_probe = ProbeWithoutDependency
118
162
  working_probe_instance = working_probe.new
119
163
  expect(working_probe).to receive(:new).and_return(working_probe_instance)
120
- Appsignal::Minutely.probes.register :probe_without_dep, working_probe
164
+ Appsignal::Probes.register :probe_without_dep, working_probe
121
165
 
122
166
  probe = BrokenProbeOnInitialize
123
- Appsignal::Minutely.probes.register :broken_probe_on_initialize, probe
124
- Appsignal::Minutely.start
167
+ Appsignal::Probes.register :broken_probe_on_initialize, probe
168
+ Appsignal::Probes.start
125
169
 
126
170
  wait_for("enough probe calls") { working_probe_instance.calls >= 2 }
127
171
  # Only counts initialized probes
@@ -142,8 +186,8 @@ describe Appsignal::Minutely do
142
186
  it "calls the lambda every <wait time>" do
143
187
  calls = 0
144
188
  probe = lambda { calls += 1 }
145
- Appsignal::Minutely.probes.register :my_probe, probe
146
- Appsignal::Minutely.start
189
+ Appsignal::Probes.register :my_probe, probe
190
+ Appsignal::Probes.start
147
191
 
148
192
  wait_for("enough probe calls") { calls >= 2 }
149
193
  expect(log).to contains_log(:debug, "Gathering minutely metrics with 1 probe")
@@ -155,9 +199,9 @@ describe Appsignal::Minutely do
155
199
  it "logs the error and continues calling the probes every <wait_time>" do
156
200
  probe = MockProbe.new
157
201
  broken_probe = BrokenProbe.new
158
- Appsignal::Minutely.probes.register :my_probe, probe
159
- Appsignal::Minutely.probes.register :broken_probe, broken_probe
160
- Appsignal::Minutely.start
202
+ Appsignal::Probes.register :my_probe, probe
203
+ Appsignal::Probes.register :broken_probe, broken_probe
204
+ Appsignal::Probes.start
161
205
 
162
206
  wait_for("enough probe calls") { probe.calls >= 2 }
163
207
  wait_for("enough broken_probe calls") { broken_probe.calls >= 2 }
@@ -174,53 +218,101 @@ describe Appsignal::Minutely do
174
218
  it "ensures only one minutely probes thread is active at a time" do
175
219
  alive_thread_counter = proc { Thread.list.reject { |t| t.status == "dead" }.length }
176
220
  probe = MockProbe.new
177
- Appsignal::Minutely.probes.register :my_probe, probe
221
+ Appsignal::Probes.register :my_probe, probe
178
222
  expect do
179
- Appsignal::Minutely.start
223
+ Appsignal::Probes.start
180
224
  end.to change { alive_thread_counter.call }.by(1)
181
225
 
182
226
  wait_for("enough probe calls") { probe.calls >= 2 }
183
- expect(Appsignal::Minutely).to have_received(:initial_wait_time).once
184
- expect(Appsignal::Minutely).to have_received(:wait_time).at_least(:once)
227
+ expect(Appsignal::Probes).to have_received(:initial_wait_time).once
228
+ expect(Appsignal::Probes).to have_received(:wait_time).at_least(:once)
185
229
  expect(log).to contains_log(:debug, "Gathering minutely metrics with 1 probe")
186
230
  expect(log).to contains_log(:debug, "Gathering minutely metrics with 'my_probe' probe")
187
231
 
188
232
  # Starting twice in this spec, so expecting it more than once
189
- expect(Appsignal::Minutely).to have_received(:initial_wait_time).once
233
+ expect(Appsignal::Probes).to have_received(:initial_wait_time).once
190
234
  expect do
191
235
  # Fetch old thread
192
- thread = Appsignal::Minutely.instance_variable_get(:@thread)
193
- Appsignal::Minutely.start
236
+ thread = Appsignal::Probes.instance_variable_get(:@thread)
237
+ Appsignal::Probes.start
194
238
  thread&.join # Wait for old thread to exit
195
239
  end.to_not(change { alive_thread_counter.call })
196
240
  end
241
+
242
+ context "with thread already started" do
243
+ before do
244
+ allow(Appsignal::Probes).to receive(:initial_wait_time).and_return(0.00001)
245
+ end
246
+
247
+ it "auto starts probes added after the thread is started" do
248
+ Appsignal::Probes.start
249
+ wait_for("Probes thread to start") { Appsignal::Probes.started? }
250
+
251
+ calls = 0
252
+ probe = lambda { calls += 1 }
253
+ Appsignal::Probes.register :late_probe, probe
254
+
255
+ wait_for("enough probe calls") { calls >= 2 }
256
+ expect(log).to contains_log(:debug, "Gathering minutely metrics with 1 probe")
257
+ expect(log).to contains_log(:debug, "Gathering minutely metrics with 'late_probe' probe")
258
+ end
259
+ end
260
+ end
261
+
262
+ describe ".unregister" do
263
+ let(:log_stream) { StringIO.new }
264
+ let(:log) { log_contents(log_stream) }
265
+ before do
266
+ Appsignal.internal_logger = test_logger(log_stream)
267
+ speed_up_tests!
268
+ end
269
+
270
+ it "does not call the initialized probe after unregistering" do
271
+ probe1_calls = 0
272
+ probe2_calls = 0
273
+ probe1 = lambda { probe1_calls += 1 }
274
+ probe2 = lambda { probe2_calls += 1 }
275
+ Appsignal::Probes.register :probe1, probe1
276
+ Appsignal::Probes.register :probe2, probe2
277
+ Appsignal::Probes.start
278
+ wait_for("enough probe1 calls") { probe1_calls >= 2 }
279
+ wait_for("enough probe2 calls") { probe2_calls >= 2 }
280
+
281
+ Appsignal::Probes.unregister :probe2
282
+ probe1_calls = 0
283
+ probe2_calls = 0
284
+ # Check the probe 1 calls to make sure the probes have been called before
285
+ # testing if the unregistered probe has not been called
286
+ wait_for("enough probe1 calls") { probe1_calls >= 2 }
287
+ expect(probe2_calls).to eq(0)
288
+ end
197
289
  end
198
290
 
199
291
  describe ".stop" do
200
292
  before do
201
- allow(Appsignal::Minutely).to receive(:initial_wait_time).and_return(0.001)
293
+ allow(Appsignal::Probes).to receive(:initial_wait_time).and_return(0.001)
202
294
  end
203
295
 
204
296
  it "stops the minutely thread" do
205
- Appsignal::Minutely.start
206
- thread = Appsignal::Minutely.instance_variable_get(:@thread)
297
+ Appsignal::Probes.start
298
+ thread = Appsignal::Probes.instance_variable_get(:@thread)
207
299
  expect(%w[sleep run]).to include(thread.status)
208
- Appsignal::Minutely.stop
300
+ Appsignal::Probes.stop
209
301
  thread.join
210
302
  expect(thread.status).to eql(false)
211
303
  end
212
304
 
213
305
  it "clears the probe instances array" do
214
- Appsignal::Minutely.probes.register :my_probe, lambda {}
215
- Appsignal::Minutely.start
216
- thread = Appsignal::Minutely.instance_variable_get(:@thread)
306
+ Appsignal::Probes.register :my_probe, lambda {}
307
+ Appsignal::Probes.start
308
+ thread = Appsignal::Probes.instance_variable_get(:@thread)
217
309
  wait_for("probes initialized") do
218
- !Appsignal::Minutely.send(:probe_instances).empty?
310
+ !Appsignal::Probes.send(:probe_instances).empty?
219
311
  end
220
- expect(Appsignal::Minutely.send(:probe_instances)).to_not be_empty
221
- Appsignal::Minutely.stop
312
+ expect(Appsignal::Probes.send(:probe_instances)).to_not be_empty
313
+ Appsignal::Probes.stop
222
314
  thread.join
223
- expect(Appsignal::Minutely.send(:probe_instances)).to be_empty
315
+ expect(Appsignal::Probes.send(:probe_instances)).to be_empty
224
316
  end
225
317
  end
226
318
 
@@ -228,7 +320,7 @@ describe Appsignal::Minutely do
228
320
  it "gets the time to the next minute" do
229
321
  time = Time.new(2019, 4, 9, 12, 0, 20)
230
322
  Timecop.freeze time do
231
- expect(Appsignal::Minutely.wait_time).to eq 40
323
+ expect(Appsignal::Probes.wait_time).to eq 40
232
324
  end
233
325
  end
234
326
  end
@@ -238,7 +330,7 @@ describe Appsignal::Minutely do
238
330
  it "waits for the number of seconds + 60" do
239
331
  time = Time.new(2019, 4, 9, 12, 0, 31)
240
332
  Timecop.freeze time do
241
- expect(Appsignal::Minutely.send(:initial_wait_time)).to eql(29 + 60)
333
+ expect(Appsignal::Probes.send(:initial_wait_time)).to eql(29 + 60)
242
334
  end
243
335
  end
244
336
  end
@@ -247,29 +339,29 @@ describe Appsignal::Minutely do
247
339
  it "waits the remaining seconds in the minute" do
248
340
  time = Time.new(2019, 4, 9, 12, 0, 29)
249
341
  Timecop.freeze time do
250
- expect(Appsignal::Minutely.send(:initial_wait_time)).to eql(31)
342
+ expect(Appsignal::Probes.send(:initial_wait_time)).to eql(31)
251
343
  end
252
344
  end
253
345
  end
254
346
  end
255
347
 
256
- describe Appsignal::Minutely::ProbeCollection do
348
+ describe Appsignal::Probes::ProbeCollection do
257
349
  let(:collection) { described_class.new }
258
350
 
259
351
  describe "#count" do
260
352
  it "returns how many probes are registered" do
261
353
  expect(collection.count).to eql(0)
262
- collection.register :my_probe_1, lambda {}
354
+ collection.internal_register :my_probe_1, lambda {}
263
355
  expect(collection.count).to eql(1)
264
- collection.register :my_probe_2, lambda {}
356
+ collection.internal_register :my_probe_2, lambda {}
265
357
  expect(collection.count).to eql(2)
266
358
  end
267
359
  end
268
360
 
269
361
  describe "#clear" do
270
362
  it "clears the list of probes" do
271
- collection.register :my_probe_1, lambda {}
272
- collection.register :my_probe_2, lambda {}
363
+ collection.internal_register :my_probe_1, lambda {}
364
+ collection.internal_register :my_probe_2, lambda {}
273
365
  expect(collection.count).to eql(2)
274
366
  collection.clear
275
367
  expect(collection.count).to eql(0)
@@ -279,27 +371,65 @@ describe Appsignal::Minutely do
279
371
  describe "#[]" do
280
372
  it "returns the probe for that name" do
281
373
  probe = lambda {}
282
- collection.register :my_probe, probe
374
+ collection.internal_register :my_probe, probe
283
375
  expect(collection[:my_probe]).to eql(probe)
284
376
  end
285
377
  end
286
378
 
287
379
  describe "#register" do
380
+ it "adds the probe by key" do
381
+ expect(Appsignal::Probes).to receive(:probes).and_return(collection)
382
+
383
+ probe = lambda {}
384
+ silence { collection.register :my_probe, probe }
385
+ expect(collection[:my_probe]).to eql(probe)
386
+ end
387
+
388
+ context "logger" do
389
+ let(:log_stream) { std_stream }
390
+ let(:log) { log_contents(log_stream) }
391
+
392
+ around { |example| use_logger_with(log_stream) { example.run } }
393
+ it "logs a deprecation message" do
394
+ silence { collection.register :my_probe, lambda {} }
395
+ expect(log).to contains_log :warn,
396
+ "The method 'Appsignal::Probes.probes.register' is deprecated. " \
397
+ "Use 'Appsignal::Probes.register' instead."
398
+ end
399
+ end
400
+
401
+ context "stderr" do
402
+ let(:err_stream) { std_stream }
403
+ let(:stderr) { err_stream.read }
404
+
405
+ it "prints a deprecation warning" do
406
+ capture_std_streams(std_stream, err_stream) do
407
+ collection.register :my_probe, lambda {}
408
+ end
409
+ deprecation_message =
410
+ "The method 'Appsignal::Probes.probes.register' is deprecated. " \
411
+ "Use 'Appsignal::Probes.register' instead."
412
+ expect(stderr).to include("appsignal WARNING: #{deprecation_message}")
413
+ end
414
+ end
415
+ end
416
+
417
+ describe "#internal_register" do
288
418
  let(:log_stream) { std_stream }
289
419
  let(:log) { log_contents(log_stream) }
290
420
  before { Appsignal.internal_logger = test_logger(log_stream) }
291
421
 
292
- it "adds the by key probe" do
422
+ it "adds the probe by key" do
293
423
  probe = lambda {}
294
- collection.register :my_probe, probe
424
+ collection.internal_register :my_probe, probe
295
425
  expect(collection[:my_probe]).to eql(probe)
296
426
  end
297
427
 
298
428
  context "when a probe is already registered with the same key" do
299
429
  it "logs a debug message" do
300
430
  probe = lambda {}
301
- collection.register :my_probe, probe
302
- collection.register :my_probe, probe
431
+ collection.internal_register :my_probe, probe
432
+ collection.internal_register :my_probe, probe
303
433
  expect(log).to contains_log :debug, "A probe with the name " \
304
434
  "`my_probe` is already registered. Overwriting the entry " \
305
435
  "with the new probe."
@@ -308,10 +438,23 @@ describe Appsignal::Minutely do
308
438
  end
309
439
  end
310
440
 
441
+ describe "#unregister" do
442
+ it "removes the probe from the collection" do
443
+ expect(Appsignal::Probes).to receive(:probes).and_return(collection)
444
+
445
+ probe = lambda {}
446
+ silence { collection.register :my_probe, probe }
447
+ expect(collection[:my_probe]).to eql(probe)
448
+
449
+ silence { collection.unregister :my_probe }
450
+ expect(collection[:my_probe]).to be_nil
451
+ end
452
+ end
453
+
311
454
  describe "#each" do
312
455
  it "loops over the registered probes" do
313
456
  probe = lambda {}
314
- collection.register :my_probe, probe
457
+ collection.internal_register :my_probe, probe
315
458
  list = []
316
459
  collection.each do |name, p|
317
460
  list << [name, p]
@@ -320,4 +463,10 @@ describe Appsignal::Minutely do
320
463
  end
321
464
  end
322
465
  end
466
+
467
+ # Speed up test time by decreasing wait times in the probes mechanism
468
+ def speed_up_tests!
469
+ allow(Appsignal::Probes).to receive(:initial_wait_time).and_return(0.001)
470
+ allow(Appsignal::Probes).to receive(:wait_time).and_return(0.001)
471
+ end
323
472
  end