appsignal 2.9.12.beta.0 → 2.9.18.beta.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -732,6 +732,19 @@ describe Appsignal::Hooks::SidekiqProbe do
732
732
  probe.call
733
733
  end
734
734
 
735
+ context "when `redis_info` is not defined" do
736
+ before do
737
+ allow(Sidekiq).to receive(:respond_to?).with(:redis_info).and_return(false)
738
+ end
739
+
740
+ it "does not collect redis metrics" do
741
+ expect_gauge("connection_count", 2).never
742
+ expect_gauge("memory_usage", 1024).never
743
+ expect_gauge("memory_usage_rss", 512).never
744
+ probe.call
745
+ end
746
+ end
747
+
735
748
  context "when hostname is configured for probe" do
736
749
  let(:redis_hostname) { "my_redis_server" }
737
750
  let(:probe) { described_class.new(:hostname => redis_hostname) }
@@ -1,4 +1,6 @@
1
1
  describe Appsignal::Minutely do
2
+ include WaitForHelper
3
+
2
4
  before { Appsignal::Minutely.probes.clear }
3
5
 
4
6
  it "returns a ProbeCollection" do
@@ -7,38 +9,26 @@ describe Appsignal::Minutely do
7
9
  end
8
10
 
9
11
  describe ".start" do
10
- class Probe
11
- attr_reader :calls
12
-
13
- def initialize
14
- @calls = 0
15
- end
16
-
17
- def call
18
- @calls += 1
19
- end
20
- end
21
-
22
- class ProbeWithoutDependency < Probe
12
+ class ProbeWithoutDependency < MockProbe
23
13
  def self.dependencies_present?
24
14
  true
25
15
  end
26
16
  end
27
17
 
28
- class ProbeWithMissingDependency < Probe
18
+ class ProbeWithMissingDependency < MockProbe
29
19
  def self.dependencies_present?
30
20
  false
31
21
  end
32
22
  end
33
23
 
34
- class BrokenProbe < Probe
24
+ class BrokenProbe < MockProbe
35
25
  def call
36
26
  super
37
27
  raise "oh no!"
38
28
  end
39
29
  end
40
30
 
41
- class BrokenProbeOnInitialize < Probe
31
+ class BrokenProbeOnInitialize < MockProbe
42
32
  def initialize
43
33
  super
44
34
  raise "oh no initialize!"
@@ -60,7 +50,7 @@ describe Appsignal::Minutely do
60
50
 
61
51
  context "with an instance of a class" do
62
52
  it "calls the probe every <wait_time>" do
63
- probe = Probe.new
53
+ probe = MockProbe.new
64
54
  Appsignal::Minutely.probes.register :my_probe, probe
65
55
  Appsignal::Minutely.start
66
56
 
@@ -90,8 +80,8 @@ describe Appsignal::Minutely do
90
80
 
91
81
  context "with probe class" do
92
82
  it "creates an instance of the class and call that every <wait time>" do
93
- probe = Probe
94
- probe_instance = Probe.new
83
+ probe = MockProbe
84
+ probe_instance = MockProbe.new
95
85
  expect(probe).to receive(:new).and_return(probe_instance)
96
86
  Appsignal::Minutely.probes.register :my_probe, probe
97
87
  Appsignal::Minutely.start
@@ -163,7 +153,7 @@ describe Appsignal::Minutely do
163
153
 
164
154
  context "with a broken probe" do
165
155
  it "logs the error and continues calling the probes every <wait_time>" do
166
- probe = Probe.new
156
+ probe = MockProbe.new
167
157
  broken_probe = BrokenProbe.new
168
158
  Appsignal::Minutely.probes.register :my_probe, probe
169
159
  Appsignal::Minutely.probes.register :broken_probe, broken_probe
@@ -183,7 +173,7 @@ describe Appsignal::Minutely do
183
173
 
184
174
  it "ensures only one minutely probes thread is active at a time" do
185
175
  alive_thread_counter = proc { Thread.list.reject { |t| t.status == "dead" }.length }
186
- probe = Probe.new
176
+ probe = MockProbe.new
187
177
  Appsignal::Minutely.probes.register :my_probe, probe
188
178
  expect do
189
179
  Appsignal::Minutely.start
@@ -349,31 +339,4 @@ describe Appsignal::Minutely do
349
339
  end
350
340
  end
351
341
  end
352
-
353
- # Wait for a condition to be met
354
- #
355
- # @example
356
- # # Perform threaded operation
357
- # wait_for("enough probe calls") { probe.calls >= 2 }
358
- # # Assert on result
359
- #
360
- # @param name [String] The name of the condition to check. Used in the
361
- # error when it fails.
362
- # @yield Assertion to check.
363
- # @yieldreturn [Boolean] True/False value that indicates if the condition
364
- # is met.
365
- # @raise [StandardError] Raises error if the condition is not met after 5
366
- # seconds, 5_000 tries.
367
- def wait_for(name)
368
- max_wait = 5_000
369
- i = 0
370
- while i <= max_wait
371
- break if yield
372
- i += 1
373
- sleep 0.001
374
- end
375
-
376
- return unless i == max_wait
377
- raise "Waited 5 seconds for #{name} condition, but was not met."
378
- end
379
342
  end
@@ -630,7 +630,11 @@ describe Appsignal::Transaction do
630
630
 
631
631
  describe "#set_error" do
632
632
  let(:env) { http_request_env_with_data }
633
- let(:error) { double(:error, :message => "test message", :backtrace => ["line 1"]) }
633
+ let(:error) do
634
+ e = ExampleStandardError.new("test message")
635
+ allow(e).to receive(:backtrace).and_return(["line 1"])
636
+ e
637
+ end
634
638
 
635
639
  it "should also respond to add_exception for backwords compatibility" do
636
640
  expect(transaction).to respond_to(:add_exception)
@@ -643,10 +647,24 @@ describe Appsignal::Transaction do
643
647
  transaction.set_error(error)
644
648
  end
645
649
 
650
+ context "when error is not an error" do
651
+ let(:error) { Object.new }
652
+
653
+ it "does not add the error" do
654
+ expect(Appsignal.logger).to receive(:error).with(
655
+ "Appsignal::Transaction#set_error: Cannot set error. " \
656
+ "The given value is not an exception: #{error.inspect}"
657
+ )
658
+ expect(transaction.ext).to_not receive(:set_error)
659
+
660
+ transaction.set_error(error)
661
+ end
662
+ end
663
+
646
664
  context "for a http request" do
647
665
  it "should set an error in the extension" do
648
666
  expect(transaction.ext).to receive(:set_error).with(
649
- "RSpec::Mocks::Double",
667
+ "ExampleStandardError",
650
668
  "test message",
651
669
  Appsignal::Utils::Data.generate(["line 1"])
652
670
  )
@@ -656,7 +674,12 @@ describe Appsignal::Transaction do
656
674
  end
657
675
 
658
676
  context "when error message is nil" do
659
- let(:error) { double(:error, :message => nil, :backtrace => ["line 1"]) }
677
+ let(:error) do
678
+ e = ExampleStandardError.new
679
+ allow(e).to receive(:message).and_return(nil)
680
+ allow(e).to receive(:backtrace).and_return(["line 1"])
681
+ e
682
+ end
660
683
 
661
684
  it "should not raise an error" do
662
685
  expect { transaction.set_error(error) }.to_not raise_error
@@ -664,7 +687,7 @@ describe Appsignal::Transaction do
664
687
 
665
688
  it "should set an error in the extension" do
666
689
  expect(transaction.ext).to receive(:set_error).with(
667
- "RSpec::Mocks::Double",
690
+ "ExampleStandardError",
668
691
  "",
669
692
  Appsignal::Utils::Data.generate(["line 1"])
670
693
  )
@@ -657,8 +657,10 @@ describe Appsignal do
657
657
  let(:error) { double }
658
658
 
659
659
  it "logs an error message" do
660
- expect(Appsignal.logger).to receive(:error)
661
- .with("Can't send error, given value is not an exception")
660
+ expect(Appsignal.logger).to receive(:error).with(
661
+ "Appsignal.send_error: Cannot send error. " \
662
+ "The given value is not an exception: #{error.inspect}"
663
+ )
662
664
  end
663
665
 
664
666
  it "does not send the error" do
@@ -778,13 +780,19 @@ describe Appsignal do
778
780
  Appsignal.set_error(error)
779
781
  end
780
782
 
781
- context "when the error is nil" do
782
- it "does nothing" do
783
+ context "when the error is not an Exception" do
784
+ let(:error) { Object.new }
785
+
786
+ it "logs an error" do
787
+ expect(Appsignal.logger).to receive(:error).with(
788
+ "Appsignal.set_error: Cannot set error. " \
789
+ "The given value is not an exception: #{error.inspect}"
790
+ )
783
791
  expect(transaction).to_not receive(:set_error)
784
792
  expect(transaction).to_not receive(:set_tags)
785
793
  expect(transaction).to_not receive(:set_namespace)
786
794
 
787
- Appsignal.set_error(nil)
795
+ Appsignal.set_error(error)
788
796
  end
789
797
  end
790
798
 
@@ -0,0 +1,91 @@
1
+ RSpec.describe "Puma plugin" do
2
+ include WaitForHelper
3
+
4
+ class MockPumaLauncher
5
+ def events
6
+ return @events if defined?(@events)
7
+
8
+ @events = MockPumaEvents.new
9
+ end
10
+ end
11
+
12
+ class MockPumaEvents
13
+ def on_booted(&block)
14
+ @on_booted = block if block_given?
15
+ @on_booted if defined?(@on_booted)
16
+ end
17
+ end
18
+
19
+ let(:probe) { MockProbe.new }
20
+ let(:launcher) { MockPumaLauncher.new }
21
+ before do
22
+ module Puma
23
+ def self.stats
24
+ end
25
+
26
+ class Plugin
27
+ class << self
28
+ attr_reader :plugin
29
+
30
+ def create(&block)
31
+ @plugin = Class.new(::Puma::Plugin)
32
+ @plugin.class_eval(&block)
33
+ end
34
+ end
35
+ end
36
+ end
37
+
38
+ Appsignal::Minutely.probes.clear
39
+ ENV["APPSIGNAL_ENABLE_MINUTELY_PROBES"] = "true"
40
+ Appsignal.config = project_fixture_config
41
+ # Speed up test time
42
+ allow(Appsignal::Minutely).to receive(:initial_wait_time).and_return(0.001)
43
+ allow(Appsignal::Minutely).to receive(:wait_time).and_return(0.001)
44
+
45
+ Appsignal::Minutely.probes.register :my_probe, probe
46
+ load File.expand_path("../lib/puma/plugin/appsignal.rb", APPSIGNAL_SPEC_DIR)
47
+ end
48
+ after do
49
+ Appsignal.config = nil
50
+ Object.send :remove_const, :Puma
51
+ Object.send :remove_const, :APPSIGNAL_PUMA_PLUGIN_LOADED
52
+ end
53
+
54
+ it "registers the PumaProbe" do
55
+ expect(Appsignal::Minutely.probes[:my_probe]).to eql(probe)
56
+ expect(Appsignal::Minutely.probes[:puma]).to be_nil
57
+ plugin = Puma::Plugin.plugin.new
58
+ expect(launcher.events.on_booted).to be_nil
59
+
60
+ plugin.start(launcher)
61
+ expect(Appsignal::Minutely.probes[:puma]).to be_nil
62
+ expect(launcher.events.on_booted).to_not be_nil
63
+
64
+ launcher.events.on_booted.call
65
+ expect(Appsignal::Minutely.probes[:puma]).to eql(Appsignal::Hooks::PumaProbe)
66
+
67
+ # Minutely probes started and called
68
+ wait_for("enough probe calls") { probe.calls >= 2 }
69
+ end
70
+
71
+ context "without Puma.stats" do
72
+ before { Puma.singleton_class.send(:remove_method, :stats) }
73
+
74
+ it "does not register the PumaProbe" do
75
+ expect(Appsignal::Minutely.probes[:my_probe]).to eql(probe)
76
+ expect(Appsignal::Minutely.probes[:puma]).to be_nil
77
+ plugin = Puma::Plugin.plugin.new
78
+ expect(launcher.events.on_booted).to be_nil
79
+
80
+ plugin.start(launcher)
81
+ expect(Appsignal::Minutely.probes[:puma]).to be_nil
82
+ expect(launcher.events.on_booted).to_not be_nil
83
+
84
+ launcher.events.on_booted.call
85
+ expect(Appsignal::Minutely.probes[:puma]).to be_nil
86
+
87
+ # Minutely probes started and called
88
+ wait_for("enough probe calls") { probe.calls >= 2 }
89
+ end
90
+ end
91
+ end
@@ -0,0 +1,28 @@
1
+ module WaitForHelper
2
+ # Wait for a condition to be met
3
+ #
4
+ # @example
5
+ # # Perform threaded operation
6
+ # wait_for("enough probe calls") { probe.calls >= 2 }
7
+ # # Assert on result
8
+ #
9
+ # @param name [String] The name of the condition to check. Used in the
10
+ # error when it fails.
11
+ # @yield Assertion to check.
12
+ # @yieldreturn [Boolean] True/False value that indicates if the condition
13
+ # is met.
14
+ # @raise [StandardError] Raises error if the condition is not met after 5
15
+ # seconds, 5_000 tries.
16
+ def wait_for(name)
17
+ max_wait = 5_000
18
+ i = 0
19
+ while i <= max_wait
20
+ break if yield
21
+ i += 1
22
+ sleep 0.001
23
+ end
24
+
25
+ return unless i == max_wait
26
+ raise "Waited 5 seconds for #{name} condition, but was not met."
27
+ end
28
+ end
@@ -0,0 +1,11 @@
1
+ class MockProbe
2
+ attr_reader :calls
3
+
4
+ def initialize
5
+ @calls = 0
6
+ end
7
+
8
+ def call
9
+ @calls += 1
10
+ end
11
+ end
metadata CHANGED
@@ -1,15 +1,16 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: appsignal
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.9.12.beta.0
4
+ version: 2.9.18.beta.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Robert Beekman
8
8
  - Thijs Cadier
9
+ - Tom de Bruijn
9
10
  autorequire:
10
11
  bindir: bin
11
12
  cert_chain: []
12
- date: 2019-07-25 00:00:00.000000000 Z
13
+ date: 2019-11-18 00:00:00.000000000 Z
13
14
  dependencies:
14
15
  - !ruby/object:Gem::Dependency
15
16
  name: rack
@@ -45,14 +46,14 @@ dependencies:
45
46
  requirements:
46
47
  - - "~>"
47
48
  - !ruby/object:Gem::Version
48
- version: '3.7'
49
+ version: '3.8'
49
50
  type: :development
50
51
  prerelease: false
51
52
  version_requirements: !ruby/object:Gem::Requirement
52
53
  requirements:
53
54
  - - "~>"
54
55
  - !ruby/object:Gem::Version
55
- version: '3.7'
56
+ version: '3.8'
56
57
  - !ruby/object:Gem::Dependency
57
58
  name: pry
58
59
  requirement: !ruby/object:Gem::Requirement
@@ -115,14 +116,14 @@ dependencies:
115
116
  requirements:
116
117
  - - ">="
117
118
  - !ruby/object:Gem::Version
118
- version: '0'
119
+ version: 0.9.20
119
120
  type: :development
120
121
  prerelease: false
121
122
  version_requirements: !ruby/object:Gem::Requirement
122
123
  requirements:
123
124
  - - ">="
124
125
  - !ruby/object:Gem::Version
125
- version: '0'
126
+ version: 0.9.20
126
127
  description: The official appsignal.com gem
127
128
  email:
128
129
  - support@appsignal.com
@@ -162,6 +163,7 @@ files:
162
163
  - gemfiles/no_dependencies.gemfile
163
164
  - gemfiles/padrino.gemfile
164
165
  - gemfiles/que.gemfile
166
+ - gemfiles/que_beta.gemfile
165
167
  - gemfiles/rails-3.2.gemfile
166
168
  - gemfiles/rails-4.0.gemfile
167
169
  - gemfiles/rails-4.1.gemfile
@@ -253,6 +255,7 @@ files:
253
255
  - lib/appsignal/utils/query_params_sanitizer.rb
254
256
  - lib/appsignal/utils/rails_helper.rb
255
257
  - lib/appsignal/version.rb
258
+ - lib/puma/plugin/appsignal.rb
256
259
  - lib/sequel/extensions/appsignal_integration.rb
257
260
  - resources/appsignal.yml.erb
258
261
  - resources/cacert.pem
@@ -326,6 +329,7 @@ files:
326
329
  - spec/lib/appsignal/utils/json_spec.rb
327
330
  - spec/lib/appsignal/utils/query_params_sanitizer_spec.rb
328
331
  - spec/lib/appsignal_spec.rb
332
+ - spec/lib/puma/appsignal_spec.rb
329
333
  - spec/spec_helper.rb
330
334
  - spec/support/fixtures/generated_config.yml
331
335
  - spec/support/fixtures/projects/valid/config/application.rb
@@ -348,9 +352,11 @@ files:
348
352
  - spec/support/helpers/system_helpers.rb
349
353
  - spec/support/helpers/time_helpers.rb
350
354
  - spec/support/helpers/transaction_helpers.rb
355
+ - spec/support/helpers/wait_for_helper.rb
351
356
  - spec/support/matchers/contains_log.rb
352
357
  - spec/support/mocks/fake_gc_profiler.rb
353
358
  - spec/support/mocks/mock_extension.rb
359
+ - spec/support/mocks/mock_probe.rb
354
360
  - spec/support/rails/my_app.rb
355
361
  - spec/support/shared_examples/instrument.rb
356
362
  - spec/support/stubs/delayed_job.rb
@@ -382,8 +388,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
382
388
  - !ruby/object:Gem::Version
383
389
  version: 1.3.1
384
390
  requirements: []
385
- rubyforge_project:
386
- rubygems_version: 2.6.14.3
391
+ rubygems_version: 3.0.6
387
392
  signing_key:
388
393
  specification_version: 4
389
394
  summary: Logs performance and exception data from your app to appsignal.com
@@ -458,6 +463,7 @@ test_files:
458
463
  - spec/lib/appsignal/utils/json_spec.rb
459
464
  - spec/lib/appsignal/utils/query_params_sanitizer_spec.rb
460
465
  - spec/lib/appsignal_spec.rb
466
+ - spec/lib/puma/appsignal_spec.rb
461
467
  - spec/spec_helper.rb
462
468
  - spec/support/fixtures/generated_config.yml
463
469
  - spec/support/fixtures/projects/valid/config/application.rb
@@ -480,9 +486,11 @@ test_files:
480
486
  - spec/support/helpers/system_helpers.rb
481
487
  - spec/support/helpers/time_helpers.rb
482
488
  - spec/support/helpers/transaction_helpers.rb
489
+ - spec/support/helpers/wait_for_helper.rb
483
490
  - spec/support/matchers/contains_log.rb
484
491
  - spec/support/mocks/fake_gc_profiler.rb
485
492
  - spec/support/mocks/mock_extension.rb
493
+ - spec/support/mocks/mock_probe.rb
486
494
  - spec/support/rails/my_app.rb
487
495
  - spec/support/shared_examples/instrument.rb
488
496
  - spec/support/stubs/delayed_job.rb