appsignal 3.12.5 → 3.13.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,342 @@
1
+ describe Appsignal::Heartbeat do
2
+ let(:err_stream) { std_stream }
3
+
4
+ after do
5
+ Appsignal.instance_variable_set(:@heartbeat_constant_deprecation_warning_emitted, false)
6
+ end
7
+
8
+ it "returns the Cron constant calling the Heartbeat constant" do
9
+ silence { expect(Appsignal::Heartbeat).to be(Appsignal::CheckIn::Cron) }
10
+ end
11
+
12
+ it "prints a deprecation warning to STDERR" do
13
+ capture_std_streams(std_stream, err_stream) do
14
+ expect(Appsignal::Heartbeat).to be(Appsignal::CheckIn::Cron)
15
+ end
16
+
17
+ expect(err_stream.read)
18
+ .to include("appsignal WARNING: The constant Appsignal::Heartbeat has been deprecated.")
19
+ end
20
+
21
+ it "does not print a deprecation warning to STDERR more than once" do
22
+ capture_std_streams(std_stream, err_stream) do
23
+ expect(Appsignal::Heartbeat).to be(Appsignal::CheckIn::Cron)
24
+ end
25
+
26
+ expect(err_stream.read)
27
+ .to include("appsignal WARNING: The constant Appsignal::Heartbeat has been deprecated.")
28
+
29
+ err_stream.truncate(0)
30
+
31
+ capture_std_streams(std_stream, err_stream) do
32
+ expect(Appsignal::Heartbeat).to be(Appsignal::CheckIn::Cron)
33
+ end
34
+
35
+ expect(err_stream.read)
36
+ .not_to include("appsignal WARNING: The constant Appsignal::Heartbeat has been deprecated.")
37
+ end
38
+
39
+ it "logs a warning" do
40
+ logs =
41
+ capture_logs do
42
+ silence do
43
+ expect(Appsignal::Heartbeat).to be(Appsignal::CheckIn::Cron)
44
+ end
45
+ end
46
+
47
+ expect(logs).to contains_log(
48
+ :warn,
49
+ "The constant Appsignal::Heartbeat has been deprecated."
50
+ )
51
+ end
52
+
53
+ it "does not log a warning more than once" do
54
+ logs =
55
+ capture_logs do
56
+ silence do
57
+ expect(Appsignal::Heartbeat).to be(Appsignal::CheckIn::Cron)
58
+ end
59
+ end
60
+
61
+ expect(logs).to contains_log(
62
+ :warn,
63
+ "The constant Appsignal::Heartbeat has been deprecated."
64
+ )
65
+
66
+ logs =
67
+ capture_logs do
68
+ silence do
69
+ expect(Appsignal::Heartbeat).to be(Appsignal::CheckIn::Cron)
70
+ end
71
+ end
72
+
73
+ expect(logs).not_to contains_log(
74
+ :warn,
75
+ "The constant Appsignal::Heartbeat has been deprecated."
76
+ )
77
+ end
78
+ end
79
+
80
+ describe "Appsignal.heartbeat" do
81
+ let(:err_stream) { std_stream }
82
+
83
+ before do
84
+ Appsignal.instance_variable_set(:@heartbeat_helper_deprecation_warning_emitted, false)
85
+ end
86
+
87
+ it "should forward the call to Appsignal::CheckIn.cron" do
88
+ expect(Appsignal::CheckIn).to receive(:cron).with("heartbeat-name")
89
+ expect do
90
+ Appsignal.heartbeat("heartbeat-name")
91
+ end.not_to raise_error
92
+
93
+ block = proc { 42 }
94
+ expect(Appsignal::CheckIn).to receive(:cron).with("heartbeat-name") do |&given_block|
95
+ expect(given_block).to be(block)
96
+ end.and_return("output")
97
+ expect(Appsignal.heartbeat("heartbeat-name", &block)).to eq("output")
98
+ end
99
+
100
+ it "prints a deprecation warning to STDERR" do
101
+ capture_std_streams(std_stream, err_stream) do
102
+ Appsignal.heartbeat("heartbeat-name")
103
+ end
104
+
105
+ expect(err_stream.read)
106
+ .to include("appsignal WARNING: The helper Appsignal.heartbeat has been deprecated.")
107
+ end
108
+
109
+ it "does not print a deprecation warning to STDERR more than once" do
110
+ capture_std_streams(std_stream, err_stream) do
111
+ Appsignal.heartbeat("heartbeat-name")
112
+ end
113
+
114
+ expect(err_stream.read)
115
+ .to include("appsignal WARNING: The helper Appsignal.heartbeat has been deprecated.")
116
+
117
+ err_stream.truncate(0)
118
+
119
+ capture_std_streams(std_stream, err_stream) do
120
+ Appsignal.heartbeat("heartbeat-name")
121
+ end
122
+
123
+ expect(err_stream.read)
124
+ .not_to include("appsignal WARNING: The helper Appsignal.heartbeat has been deprecated.")
125
+ end
126
+
127
+ it "logs a warning" do
128
+ logs =
129
+ capture_logs do
130
+ silence do
131
+ Appsignal.heartbeat("heartbeat-name")
132
+ end
133
+ end
134
+
135
+ expect(logs).to contains_log(
136
+ :warn,
137
+ "The helper Appsignal.heartbeat has been deprecated."
138
+ )
139
+ end
140
+
141
+ it "does not log a warning more than once" do
142
+ logs =
143
+ capture_logs do
144
+ silence do
145
+ Appsignal.heartbeat("heartbeat-name")
146
+ end
147
+ end
148
+
149
+ expect(logs).to contains_log(
150
+ :warn,
151
+ "The helper Appsignal.heartbeat has been deprecated."
152
+ )
153
+
154
+ logs =
155
+ capture_logs do
156
+ silence do
157
+ Appsignal.heartbeat("heartbeat-name")
158
+ end
159
+ end
160
+
161
+ expect(logs).not_to contains_log(
162
+ :warn,
163
+ "The helper Appsignal.heartbeat has been deprecated."
164
+ )
165
+ end
166
+ end
167
+
168
+ describe Appsignal::CheckIn::Cron do
169
+ let(:config) { project_fixture_config }
170
+ let(:cron_checkin) { described_class.new(:name => "cron-checkin-name") }
171
+ let(:transmitter) { Appsignal::Transmitter.new("http://cron_checkins/", config) }
172
+
173
+ before(:each) do
174
+ allow(Appsignal).to receive(:active?).and_return(true)
175
+ config.logger = Logger.new(StringIO.new)
176
+ allow(Appsignal::CheckIn::Cron).to receive(:transmitter).and_return(transmitter)
177
+ end
178
+
179
+ describe "when Appsignal is not active" do
180
+ it "should not transmit any events" do
181
+ allow(Appsignal).to receive(:active?).and_return(false)
182
+ expect(transmitter).not_to receive(:transmit)
183
+
184
+ cron_checkin.start
185
+ cron_checkin.finish
186
+ end
187
+ end
188
+
189
+ describe "#start" do
190
+ it "should send a cron check-in start" do
191
+ expect(transmitter).to receive(:transmit).with(hash_including(
192
+ :identifier => "cron-checkin-name",
193
+ :kind => "start",
194
+ :check_in_type => "cron"
195
+ )).and_return(Net::HTTPResponse.new(nil, "200", nil))
196
+
197
+ expect(Appsignal.internal_logger).to receive(:debug).with(
198
+ "Transmitted cron check-in `cron-checkin-name` (#{cron_checkin.digest}) start event"
199
+ )
200
+ expect(Appsignal.internal_logger).not_to receive(:error)
201
+
202
+ cron_checkin.start
203
+ end
204
+
205
+ it "should log an error if it fails" do
206
+ expect(transmitter).to receive(:transmit).with(hash_including(
207
+ :identifier => "cron-checkin-name",
208
+ :kind => "start",
209
+ :check_in_type => "cron"
210
+ )).and_return(Net::HTTPResponse.new(nil, "499", nil))
211
+
212
+ expect(Appsignal.internal_logger).not_to receive(:debug)
213
+ expect(Appsignal.internal_logger).to receive(:error).with(
214
+ "Failed to transmit cron check-in start event: status code was 499"
215
+ )
216
+
217
+ cron_checkin.start
218
+ end
219
+ end
220
+
221
+ describe "#finish" do
222
+ it "should send a cron check-in finish" do
223
+ expect(transmitter).to receive(:transmit).with(hash_including(
224
+ :identifier => "cron-checkin-name",
225
+ :kind => "finish",
226
+ :check_in_type => "cron"
227
+ )).and_return(Net::HTTPResponse.new(nil, "200", nil))
228
+
229
+ expect(Appsignal.internal_logger).to receive(:debug).with(
230
+ "Transmitted cron check-in `cron-checkin-name` (#{cron_checkin.digest}) finish event"
231
+ )
232
+ expect(Appsignal.internal_logger).not_to receive(:error)
233
+
234
+ cron_checkin.finish
235
+ end
236
+
237
+ it "should log an error if it fails" do
238
+ expect(transmitter).to receive(:transmit).with(hash_including(
239
+ :identifier => "cron-checkin-name",
240
+ :kind => "finish",
241
+ :check_in_type => "cron"
242
+ )).and_return(Net::HTTPResponse.new(nil, "499", nil))
243
+
244
+ expect(Appsignal.internal_logger).not_to receive(:debug)
245
+ expect(Appsignal.internal_logger).to receive(:error).with(
246
+ "Failed to transmit cron check-in finish event: status code was 499"
247
+ )
248
+
249
+ cron_checkin.finish
250
+ end
251
+ end
252
+
253
+ describe ".cron" do
254
+ describe "when a block is given" do
255
+ it "should send a cron check-in start and finish and return the block output" do
256
+ expect(transmitter).to receive(:transmit).with(hash_including(
257
+ :kind => "start",
258
+ :identifier => "cron-checkin-with-block",
259
+ :check_in_type => "cron"
260
+ )).and_return(nil)
261
+
262
+ expect(transmitter).to receive(:transmit).with(hash_including(
263
+ :kind => "finish",
264
+ :identifier => "cron-checkin-with-block",
265
+ :check_in_type => "cron"
266
+ )).and_return(nil)
267
+
268
+ output = Appsignal::CheckIn.cron("cron-checkin-with-block") { "output" }
269
+ expect(output).to eq("output")
270
+ end
271
+
272
+ it "should not send a cron check-in finish event when an error is raised" do
273
+ expect(transmitter).to receive(:transmit).with(hash_including(
274
+ :kind => "start",
275
+ :identifier => "cron-checkin-with-block",
276
+ :check_in_type => "cron"
277
+ )).and_return(nil)
278
+
279
+ expect(transmitter).not_to receive(:transmit).with(hash_including(
280
+ :kind => "finish",
281
+ :identifier => "cron-checkin-with-block",
282
+ :check_in_type => "cron"
283
+ ))
284
+
285
+ expect do
286
+ Appsignal::CheckIn.cron("cron-checkin-with-block") { raise "error" }
287
+ end.to raise_error(RuntimeError, "error")
288
+ end
289
+ end
290
+
291
+ describe "when no block is given" do
292
+ it "should only send a cron check-in finish event" do
293
+ expect(transmitter).to receive(:transmit).with(hash_including(
294
+ :kind => "finish",
295
+ :identifier => "cron-checkin-without-block",
296
+ :check_in_type => "cron"
297
+ )).and_return(nil)
298
+
299
+ Appsignal::CheckIn.cron("cron-checkin-without-block")
300
+ end
301
+ end
302
+ end
303
+
304
+ describe "#initialize" do
305
+ describe "when initialised with deprecated heartbeat keyword names" do
306
+ let(:err_stream) { std_stream }
307
+
308
+ after do
309
+ described_class.instance_variable_set(:@initializer_deprecation_warning_emitted, false)
310
+ end
311
+
312
+ it "can be initialised" do
313
+ cron_checkin = described_class.new(:name => "cron-checkin-name")
314
+ expect(cron_checkin.identifier).to eq("cron-checkin-name")
315
+ end
316
+
317
+ it "logs a deprecation warning" do
318
+ capture_std_streams(std_stream, err_stream) do
319
+ expect(described_class.new(:name => "cron-checkin-name"))
320
+ .to be_a(Appsignal::CheckIn::Cron)
321
+ end
322
+
323
+ expect(err_stream.read)
324
+ .to include(
325
+ "appsignal WARNING: Passing a `name` keyword argument to " \
326
+ "`Appsignal::CheckIn::Cron.new` is deprecated."
327
+ )
328
+ end
329
+ end
330
+
331
+ it "can be initialised with cron check-in keyword names" do
332
+ cron_checkin = described_class.new(:identifier => "cron-checkin-name")
333
+ expect(cron_checkin.identifier).to eq("cron-checkin-name")
334
+ end
335
+
336
+ it "raises an error when no identifier is given" do
337
+ expect do
338
+ described_class.new
339
+ end.to raise_error(ArgumentError, "missing keyword: :identifier")
340
+ end
341
+ end
342
+ end
@@ -30,7 +30,7 @@ describe Appsignal::CLI::Install do
30
30
 
31
31
  define :include_complete_install do
32
32
  match do |actual|
33
- actual.include?("AppSignal installation complete")
33
+ actual.include?("Please return to your browser and follow the instructions.")
34
34
  end
35
35
  end
36
36
 
@@ -105,7 +105,7 @@ describe Appsignal::CLI::Install do
105
105
  run
106
106
 
107
107
  expect(output).to include "Problem encountered:",
108
- "No push API key entered"
108
+ "No Push API key entered"
109
109
  end
110
110
  end
111
111
 
@@ -120,7 +120,7 @@ describe Appsignal::CLI::Install do
120
120
  choose_environment_config
121
121
  run
122
122
 
123
- expect(output).to include("Validating API key...", "API key valid")
123
+ expect(output).to include("Validating Push API key...", "Push API key valid")
124
124
  end
125
125
  end
126
126
 
@@ -129,7 +129,7 @@ describe Appsignal::CLI::Install do
129
129
 
130
130
  it "prints an error" do
131
131
  run
132
- expect(output).to include "API key 'my_key' is not valid"
132
+ expect(output).to include "Push API key 'my_key' is not valid"
133
133
  end
134
134
  end
135
135
 
@@ -140,7 +140,7 @@ describe Appsignal::CLI::Install do
140
140
 
141
141
  it "prints an error" do
142
142
  run
143
- expect(output).to include "There was an error validating your API key"
143
+ expect(output).to include "There was an error validating your Push API key"
144
144
  end
145
145
  end
146
146
  end
@@ -419,14 +419,16 @@ describe Appsignal::CLI::Install do
419
419
  expect(File.exist?(File.join(config_dir, "application.rb"))).to eql(false)
420
420
  end
421
421
 
422
- it "fails the installation" do
422
+ it "falls back on the unknown framework installation" do
423
+ enter_app_name app_name
424
+ choose_environment_config
423
425
  run
424
426
 
425
- expect(output).to include("We could not detect which framework you are using.")
427
+ expect(output)
428
+ .to include("\e[31mWarning: We could not detect which framework you are using\e[0m")
426
429
  expect(output).to_not include("Installing for Ruby on Rails")
430
+ expect(output).to include_env_push_api_key(push_api_key)
427
431
  expect(output).to include_complete_install
428
-
429
- expect(File.exist?(config_file_path)).to be(false)
430
432
  end
431
433
  end
432
434
 
@@ -465,8 +467,10 @@ describe Appsignal::CLI::Install do
465
467
  let(:installation_instructions) do
466
468
  [
467
469
  "Installing for Sinatra",
468
- "Sinatra requires some manual configuration.",
469
- "require 'appsignal/integrations/sinatra'",
470
+ "Sinatra apps requires some manual setup.",
471
+ %(require "appsignal"),
472
+ "Appsignal.load(:sinatra)",
473
+ "Appsignal.start",
470
474
  "https://docs.appsignal.com/ruby/integrations/sinatra.html"
471
475
  ]
472
476
  end
@@ -533,7 +537,10 @@ describe Appsignal::CLI::Install do
533
537
  let(:installation_instructions) do
534
538
  [
535
539
  "Installing for Padrino",
536
- "Padrino requires some manual configuration.",
540
+ "Padrino apps requires some manual setup.",
541
+ %(require "appsignal"),
542
+ "Appsignal.load(:padrino)",
543
+ "Appsignal.start",
537
544
  "https://docs.appsignal.com/ruby/integrations/padrino.html"
538
545
  ]
539
546
  end
@@ -600,7 +607,7 @@ describe Appsignal::CLI::Install do
600
607
  let(:installation_instructions) do
601
608
  [
602
609
  "Installing for Grape",
603
- "Manual Grape configuration needed",
610
+ "Grape apps require some manual setup.",
604
611
  "https://docs.appsignal.com/ruby/integrations/grape.html"
605
612
  ]
606
613
  end
@@ -624,6 +631,7 @@ describe Appsignal::CLI::Install do
624
631
  it "completes the installation" do
625
632
  run
626
633
 
634
+ puts output
627
635
  expect(output).to include(*installation_instructions)
628
636
  expect(output).to include_complete_install
629
637
  end
@@ -667,7 +675,10 @@ describe Appsignal::CLI::Install do
667
675
  let(:installation_instructions) do
668
676
  [
669
677
  "Installing for Hanami",
670
- "Hanami requires some manual configuration.",
678
+ "Hanami apps requires some manual setup.",
679
+ %(require "appsignal"),
680
+ "Appsignal.load(:hanami)",
681
+ "Appsignal.start",
671
682
  "https://docs.appsignal.com/ruby/integrations/hanami.html"
672
683
  ]
673
684
  end
@@ -728,47 +739,109 @@ describe Appsignal::CLI::Install do
728
739
  !hanami2_present?
729
740
  context "with unknown framework" do
730
741
  let(:push_api_key) { "my_key" }
742
+ let(:app_name) { "Test app" }
731
743
 
732
- it_behaves_like "windows installation"
733
744
  it_behaves_like "push_api_key validation"
734
- it_behaves_like "demo data"
745
+ it_behaves_like "requires an application name"
746
+
747
+ describe "unknown framework specific tests" do
748
+ let(:installation_instructions) do
749
+ [
750
+ "Installing",
751
+ "\e[31mWarning: We could not detect which framework you are using\e[0m",
752
+ "Some manual installation is most likely required.",
753
+ "https://docs.appsignal.com/ruby/integrations.html"
754
+ ]
755
+ end
756
+ before { enter_app_name app_name }
735
757
 
736
- context "without color options" do
737
- let(:options) { {} }
758
+ describe "configuration with environment variables" do
759
+ before { choose_environment_config }
738
760
 
739
- it "prints the instructions in color" do
740
- run
741
- expect(output).to have_colorized_text(:green, "## Starting AppSignal Installer ##")
761
+ it_behaves_like "windows installation"
762
+ it_behaves_like "capistrano install"
763
+ it_behaves_like "demo data"
764
+
765
+ it "prints environment variables" do
766
+ run
767
+
768
+ expect(output).to include_env_push_api_key(push_api_key)
769
+ expect(output).to include_env_app_name(app_name)
770
+ end
771
+
772
+ it "completes the installation" do
773
+ run
774
+
775
+ expect(output).to include(*installation_instructions)
776
+ expect(output).to include_complete_install
777
+ end
742
778
  end
743
- end
744
779
 
745
- context "with --color option" do
746
- let(:options) { { "color" => nil } }
780
+ describe "configure with a configuration file" do
781
+ before { choose_config_file }
747
782
 
748
- it "prints the instructions in color" do
749
- run
750
- expect(output).to have_colorized_text(:green, "## Starting AppSignal Installer ##")
783
+ it_behaves_like "windows installation"
784
+ it_behaves_like "capistrano install"
785
+ it_behaves_like "demo data"
786
+
787
+ it "writes configuration to file" do
788
+ run
789
+ expect(output).to include_file_config
790
+ expect(config_file).to configure_app_name(app_name)
791
+ expect(config_file).to configure_push_api_key(push_api_key)
792
+ expect(config_file).to configure_environment("development")
793
+ expect(config_file).to configure_environment("staging")
794
+ expect(config_file).to configure_environment("production")
795
+ end
796
+
797
+ it "completes the installation" do
798
+ run
799
+
800
+ expect(output).to include(*installation_instructions)
801
+ expect(output).to include_complete_install
802
+ end
751
803
  end
752
804
  end
753
805
 
754
- context "with --no-color option" do
755
- let(:options) { { "no-color" => nil } }
806
+ describe "color flag" do
807
+ before do
808
+ enter_app_name "Test app"
809
+ choose_environment_config
810
+ end
756
811
 
757
- it "prints the instructions without special colors" do
758
- run
759
- expect(output).to include("Starting AppSignal Installer")
760
- expect(output).to_not have_color_markers
812
+ context "without color options" do
813
+ let(:options) { {} }
814
+
815
+ it "prints the instructions in color" do
816
+ run
817
+ expect(output).to have_colorized_text(
818
+ :green,
819
+ "## Starting AppSignal Installer ##"
820
+ )
821
+ end
761
822
  end
762
- end
763
823
 
764
- it "prints a message about unknown framework" do
765
- run
824
+ context "with --color option" do
825
+ let(:options) { { "color" => nil } }
766
826
 
767
- expect(output).to include \
768
- "\e[31mWarning:\e[0m We could not detect which framework you are using."
769
- expect(output).to_not include_env_push_api_key
770
- expect(output).to_not include_env_app_name
771
- expect(File.exist?(config_file_path)).to be_falsy
827
+ it "prints the instructions in color" do
828
+ run
829
+ expect(output).to have_colorized_text(
830
+ :green,
831
+ "## Starting AppSignal Installer ##"
832
+ )
833
+ end
834
+ end
835
+
836
+ context "with --no-color option" do
837
+ let(:options) { { "no-color" => nil } }
838
+
839
+ it "prints the instructions without special colors" do
840
+ run
841
+ expect(output).to include("## Starting AppSignal Installer ##")
842
+ expect(output).to_not have_color_markers
843
+ end
844
+ end
772
845
  end
773
846
  end
774
847
  end
@@ -1439,5 +1439,29 @@ describe Appsignal::Config do
1439
1439
 
1440
1440
  expect(dsl.cpu_count).to eq(1.0)
1441
1441
  end
1442
+
1443
+ describe "#app_path=" do
1444
+ it "prints a deprecation warning" do
1445
+ err_stream = std_stream
1446
+ capture_std_streams(std_stream, err_stream) do
1447
+ dsl.app_path = "foo"
1448
+ end
1449
+
1450
+ expect(err_stream.read).to include(
1451
+ "appsignal WARNING: The `Appsignal.configure`'s `app_path=` writer is deprecated"
1452
+ )
1453
+ end
1454
+
1455
+ it "logs a deprecation warning" do
1456
+ logs = capture_logs do
1457
+ silence { dsl.app_path = "foo" }
1458
+ end
1459
+
1460
+ expect(logs).to contains_log(
1461
+ :warn,
1462
+ "The `Appsignal.configure`'s `app_path=` writer is deprecated"
1463
+ )
1464
+ end
1465
+ end
1442
1466
  end
1443
1467
  end
@@ -67,27 +67,6 @@ if DependencyHelper.http_present?
67
67
  end
68
68
  end
69
69
 
70
- context "with an HTTP exception" do
71
- let(:error) { ExampleException.new("oh no!") }
72
-
73
- it "reports the exception and re-raises it" do
74
- stub_request(:get, "https://www.google.com").and_raise(error)
75
-
76
- expect do
77
- HTTP.get("https://www.google.com")
78
- end.to raise_error(ExampleException)
79
-
80
- expect(transaction).to have_namespace(Appsignal::Transaction::HTTP_REQUEST)
81
- expect(transaction).to include_event(
82
- "body" => "",
83
- "body_format" => Appsignal::EventFormatter::DEFAULT,
84
- "name" => "request.http_rb",
85
- "title" => "GET https://www.google.com"
86
- )
87
- expect(transaction).to have_error(error.class.name, error.message)
88
- end
89
- end
90
-
91
70
  context "with various URI objects" do
92
71
  it "parses an object responding to #to_s" do
93
72
  request_uri = Struct.new(:uri) do