appsignal 4.0.4-java → 4.0.6-java

Sign up to get free protection for your applications and to get access to all the features.
Files changed (39) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/ci.yml +151 -16
  3. data/CHANGELOG.md +42 -0
  4. data/build_matrix.yml +2 -1
  5. data/ext/agent.rb +27 -27
  6. data/gemfiles/que-1.gemfile +5 -0
  7. data/gemfiles/que-2.gemfile +5 -0
  8. data/lib/appsignal/check_in/scheduler.rb +3 -4
  9. data/lib/appsignal/config.rb +7 -0
  10. data/lib/appsignal/hooks/at_exit.rb +1 -0
  11. data/lib/appsignal/hooks/puma.rb +5 -1
  12. data/lib/appsignal/integrations/puma.rb +45 -0
  13. data/lib/appsignal/integrations/que.rb +8 -2
  14. data/lib/appsignal/rack/abstract_middleware.rb +3 -47
  15. data/lib/appsignal/rack/event_handler.rb +2 -0
  16. data/lib/appsignal/rack/hanami_middleware.rb +5 -1
  17. data/lib/appsignal/rack.rb +68 -0
  18. data/lib/appsignal/version.rb +1 -1
  19. data/spec/lib/appsignal/check_in/cron_spec.rb +134 -134
  20. data/spec/lib/appsignal/check_in/scheduler_spec.rb +297 -224
  21. data/spec/lib/appsignal/config_spec.rb +13 -0
  22. data/spec/lib/appsignal/hooks/at_exit_spec.rb +11 -0
  23. data/spec/lib/appsignal/hooks/puma_spec.rb +31 -23
  24. data/spec/lib/appsignal/integrations/puma_spec.rb +150 -0
  25. data/spec/lib/appsignal/integrations/que_spec.rb +56 -21
  26. data/spec/lib/appsignal/probes_spec.rb +4 -6
  27. data/spec/lib/appsignal/rack/abstract_middleware_spec.rb +41 -122
  28. data/spec/lib/appsignal/rack_spec.rb +180 -0
  29. data/spec/lib/appsignal/transaction_spec.rb +96 -92
  30. data/spec/spec_helper.rb +6 -7
  31. data/spec/support/helpers/api_request_helper.rb +40 -0
  32. data/spec/support/helpers/config_helpers.rb +2 -1
  33. data/spec/support/helpers/dependency_helper.rb +5 -0
  34. data/spec/support/matchers/contains_log.rb +10 -3
  35. data/spec/support/mocks/hash_like.rb +10 -0
  36. data/spec/support/mocks/puma_mock.rb +43 -0
  37. data/spec/support/testing.rb +9 -0
  38. metadata +8 -3
  39. data/gemfiles/que.gemfile +0 -5
@@ -61,3 +61,183 @@ describe Appsignal::Rack::Utils do
61
61
  end
62
62
  end
63
63
  end
64
+
65
+ describe Appsignal::Rack::ApplyRackRequest do
66
+ describe "#apply_to" do
67
+ let(:merged_env) do
68
+ Rack::MockRequest.env_for(
69
+ "/some/path",
70
+ {
71
+ "REQUEST_METHOD" => "GET",
72
+ :params => { "page" => 2, "query" => "lorem" },
73
+ "rack.session" => { "session" => "data", "user_id" => 123 }
74
+ }.merge(env)
75
+ )
76
+ end
77
+ let(:env) { {} }
78
+ let(:request) { ::Rack::Request.new(merged_env) }
79
+ let(:options) { {} }
80
+ let(:helper) { described_class.new(request, options) }
81
+ let(:transaction) { http_request_transaction }
82
+ before { start_agent }
83
+
84
+ def apply_to(transaction)
85
+ helper.apply_to(transaction)
86
+ transaction._sample
87
+ end
88
+
89
+ it "sets request metadata" do
90
+ apply_to(transaction)
91
+
92
+ expect(transaction).to include_metadata(
93
+ "method" => "GET",
94
+ "path" => "/some/path"
95
+ )
96
+ expect(transaction).to include_environment(
97
+ "REQUEST_METHOD" => "GET",
98
+ "PATH_INFO" => "/some/path"
99
+ # and more, but we don't need to test Rack mock defaults
100
+ )
101
+ end
102
+
103
+ context "with an invalid HTTP request method" do
104
+ let(:env) { { "REQUEST_METHOD" => "FOO" } }
105
+
106
+ it "stores the invalid HTTP request method" do
107
+ apply_to(transaction)
108
+
109
+ expect(transaction).to include_metadata("method" => "FOO")
110
+ end
111
+ end
112
+
113
+ context "when fetching the request method raises an error" do
114
+ class BrokenRequestMethodRequest < Rack::Request
115
+ def request_method
116
+ raise "uh oh!"
117
+ end
118
+ end
119
+
120
+ let(:env) { { "REQUEST_METHOD" => "FOO" } }
121
+ let(:request) { BrokenRequestMethodRequest.new(merged_env) }
122
+
123
+ it "does not store the invalid HTTP request method" do
124
+ logs = capture_logs { apply_to(transaction) }
125
+
126
+ expect(transaction).to_not include_metadata("method" => anything)
127
+ expect(logs).to contains_log(
128
+ :error,
129
+ "Exception while fetching the HTTP request method: RuntimeError: uh oh"
130
+ )
131
+ end
132
+ end
133
+
134
+ it "sets request parameters" do
135
+ apply_to(transaction)
136
+
137
+ expect(transaction).to include_params(
138
+ "page" => "2",
139
+ "query" => "lorem"
140
+ )
141
+ end
142
+
143
+ context "when params_method isn't set" do
144
+ let(:options) { { :params_method => nil } }
145
+
146
+ it "reports no params" do
147
+ apply_to(transaction)
148
+
149
+ expect(transaction).to_not include_params
150
+ end
151
+ end
152
+
153
+ context "when fetching the request method raises an error" do
154
+ class BrokenRequestParamsRequest < Rack::Request
155
+ def params
156
+ raise "uh oh!"
157
+ end
158
+ end
159
+
160
+ let(:request) { BrokenRequestParamsRequest.new(merged_env) }
161
+ let(:options) { { :params_method => :params } }
162
+
163
+ it "does not store the invalid HTTP request method" do
164
+ logs = capture_logs { apply_to(transaction) }
165
+
166
+ expect(transaction).to_not include_params
167
+ expect(logs).to contains_log(
168
+ :error,
169
+ "Exception while fetching params " \
170
+ "from 'BrokenRequestParamsRequest#params': RuntimeError uh oh!"
171
+ )
172
+ end
173
+ end
174
+
175
+ it "sets session data" do
176
+ apply_to(transaction)
177
+
178
+ expect(transaction).to include_session_data("session" => "data", "user_id" => 123)
179
+ end
180
+
181
+ context "with Hash-like session data" do
182
+ let(:env) { { "rack.session" => HashLike.new("hash-like" => "value", "user_id" => 123) } }
183
+
184
+ it "sets session data" do
185
+ apply_to(transaction)
186
+
187
+ expect(transaction).to include_session_data("hash-like" => "value", "user_id" => 123)
188
+ end
189
+ end
190
+
191
+ context "with queue start header" do
192
+ let(:queue_start_time) { fixed_time * 1_000 }
193
+ let(:env) { { "HTTP_X_REQUEST_START" => "t=#{queue_start_time.to_i}" } } # in milliseconds
194
+
195
+ it "sets the queue start" do
196
+ apply_to(transaction)
197
+
198
+ expect(transaction).to have_queue_start(queue_start_time)
199
+ end
200
+ end
201
+
202
+ class RackFilteredRequest
203
+ attr_reader :env
204
+
205
+ def initialize(env)
206
+ @env = env
207
+ end
208
+
209
+ def path
210
+ "/static/path"
211
+ end
212
+
213
+ def request_method
214
+ "GET"
215
+ end
216
+
217
+ def filtered_params
218
+ { "abc" => "123" }
219
+ end
220
+
221
+ def session
222
+ { "data" => "value" }
223
+ end
224
+ end
225
+
226
+ context "with overridden request class and params method" do
227
+ let(:request) { RackFilteredRequest.new(env) }
228
+ let(:options) { { :params_method => :filtered_params } }
229
+
230
+ it "uses the overridden request class and params method to fetch params" do
231
+ apply_to(transaction)
232
+
233
+ expect(transaction).to include_params("abc" => "123")
234
+ end
235
+
236
+ it "uses the overridden request class to fetch session data" do
237
+ apply_to(transaction)
238
+
239
+ expect(transaction).to include_session_data("data" => "value")
240
+ end
241
+ end
242
+ end
243
+ end
@@ -211,15 +211,15 @@ describe Appsignal::Transaction do
211
211
 
212
212
  context "when a transaction has errors" do
213
213
  let(:error) do
214
- e = ExampleStandardError.new("test message")
215
- allow(e).to receive(:backtrace).and_return(["line 1"])
216
- e
214
+ ExampleStandardError.new("test message").tap do |e|
215
+ e.set_backtrace(["line 1"])
216
+ end
217
217
  end
218
218
 
219
219
  let(:other_error) do
220
- e = ExampleStandardError.new("other test message")
221
- allow(e).to receive(:backtrace).and_return(["line 2"])
222
- e
220
+ ExampleStandardError.new("other test message").tap do |e|
221
+ e.set_backtrace(["line 2"])
222
+ end
223
223
  end
224
224
 
225
225
  context "when an error is already set on the transaction" do
@@ -1526,9 +1526,9 @@ describe Appsignal::Transaction do
1526
1526
  let(:transaction) { create_transaction }
1527
1527
 
1528
1528
  let(:error) do
1529
- e = ExampleStandardError.new("test message")
1530
- allow(e).to receive(:backtrace).and_return(["line 1"])
1531
- e
1529
+ ExampleStandardError.new("test message").tap do |e|
1530
+ e.set_backtrace(["line 1"])
1531
+ end
1532
1532
  end
1533
1533
 
1534
1534
  context "when error argument is not an error" do
@@ -1588,9 +1588,9 @@ describe Appsignal::Transaction do
1588
1588
 
1589
1589
  context "when an error is already set in the transaction" do
1590
1590
  let(:other_error) do
1591
- e = ExampleStandardError.new("other test message")
1592
- allow(e).to receive(:backtrace).and_return(["line 2"])
1593
- e
1591
+ ExampleStandardError.new("other test message").tap do |e|
1592
+ e.set_backtrace(["line 2"])
1593
+ end
1594
1594
  end
1595
1595
 
1596
1596
  before { transaction.set_error(other_error) }
@@ -1697,12 +1697,92 @@ describe Appsignal::Transaction do
1697
1697
  end
1698
1698
  end
1699
1699
  end
1700
+
1701
+ context "with a PG::UniqueViolation" do
1702
+ let(:error) do
1703
+ PG::UniqueViolation.new(
1704
+ "ERROR: duplicate key value violates unique constraint " \
1705
+ "\"index_users_on_email\" DETAIL: Key (email)=(test@test.com) already exists."
1706
+ )
1707
+ end
1708
+ before do
1709
+ stub_const("PG::UniqueViolation", Class.new(StandardError))
1710
+ transaction.add_error(error)
1711
+ end
1712
+
1713
+ it "returns a sanizited error message" do
1714
+ expect(transaction).to have_error(
1715
+ "PG::UniqueViolation",
1716
+ "ERROR: duplicate key value violates unique constraint " \
1717
+ "\"index_users_on_email\" DETAIL: Key (email)=(?) already exists."
1718
+ )
1719
+ end
1720
+ end
1721
+
1722
+ context "with a ActiveRecord::RecordNotUnique" do
1723
+ let(:error) do
1724
+ ActiveRecord::RecordNotUnique.new(
1725
+ "PG::UniqueViolation: ERROR: duplicate key value violates unique constraint " \
1726
+ "\"example_constraint\"\nDETAIL: Key (email)=(foo@example.com) already exists."
1727
+ )
1728
+ end
1729
+ before do
1730
+ stub_const("ActiveRecord::RecordNotUnique", Class.new(StandardError))
1731
+ transaction.add_error(error)
1732
+ end
1733
+
1734
+ it "returns a sanizited error message" do
1735
+ expect(transaction).to have_error(
1736
+ "ActiveRecord::RecordNotUnique",
1737
+ "PG::UniqueViolation: ERROR: duplicate key value violates unique constraint " \
1738
+ "\"example_constraint\"\nDETAIL: Key (email)=(?) already exists."
1739
+ )
1740
+ end
1741
+ end
1742
+
1743
+ context "with Rails module but without backtrace_cleaner method" do
1744
+ it "returns the backtrace uncleaned" do
1745
+ stub_const("Rails", Module.new)
1746
+ error = ExampleStandardError.new("error message")
1747
+ error.set_backtrace(["line 1", "line 2"])
1748
+ transaction.add_error(error)
1749
+
1750
+ expect(last_transaction).to have_error(
1751
+ "ExampleStandardError",
1752
+ "error message",
1753
+ ["line 1", "line 2"]
1754
+ )
1755
+ end
1756
+ end
1757
+
1758
+ if rails_present?
1759
+ context "with Rails" do
1760
+ it "cleans the backtrace with the Rails backtrace cleaner" do
1761
+ ::Rails.backtrace_cleaner.add_filter do |line|
1762
+ line.tr("2", "?")
1763
+ end
1764
+
1765
+ error = ExampleStandardError.new("error message")
1766
+ error.set_backtrace(["line 1", "line 2"])
1767
+ transaction.add_error(error)
1768
+ expect(last_transaction).to have_error(
1769
+ "ExampleStandardError",
1770
+ "error message",
1771
+ ["line 1", "line ?"]
1772
+ )
1773
+ end
1774
+ end
1775
+ end
1700
1776
  end
1701
1777
 
1702
1778
  describe "#_set_error" do
1703
1779
  let(:transaction) { new_transaction }
1704
1780
  let(:env) { http_request_env_with_data }
1705
- let(:error) { ExampleStandardError.new("test message") }
1781
+ let(:error) do
1782
+ ExampleStandardError.new("test message").tap do |e|
1783
+ e.set_backtrace(["line 1"])
1784
+ end
1785
+ end
1706
1786
 
1707
1787
  it "responds to add_exception for backwards compatibility" do
1708
1788
  expect(transaction).to respond_to(:add_exception)
@@ -1716,7 +1796,6 @@ describe Appsignal::Transaction do
1716
1796
 
1717
1797
  context "for a http request" do
1718
1798
  it "sets an error on the transaction" do
1719
- allow(error).to receive(:backtrace).and_return(["line 1"])
1720
1799
  transaction.send(:_set_error, error)
1721
1800
 
1722
1801
  expect(transaction).to have_error(
@@ -1738,9 +1817,9 @@ describe Appsignal::Transaction do
1738
1817
  context "when the error has multiple causes" do
1739
1818
  let(:error) do
1740
1819
  e = ExampleStandardError.new("test message")
1820
+ e.set_backtrace(["line 1"])
1741
1821
  e2 = RuntimeError.new("cause message")
1742
1822
  e3 = StandardError.new("cause message 2")
1743
- allow(e).to receive(:backtrace).and_return(["line 1"])
1744
1823
  allow(e).to receive(:cause).and_return(e2)
1745
1824
  allow(e2).to receive(:cause).and_return(e3)
1746
1825
  e
@@ -1795,8 +1874,7 @@ describe Appsignal::Transaction do
1795
1874
  allow(next_e).to receive(:cause).and_return(e)
1796
1875
  e = next_e
1797
1876
  end
1798
-
1799
- allow(e).to receive(:backtrace).and_return(["line 1"])
1877
+ e.set_backtrace(["line 1"])
1800
1878
  e
1801
1879
  end
1802
1880
 
@@ -1831,7 +1909,7 @@ describe Appsignal::Transaction do
1831
1909
  let(:error) do
1832
1910
  e = ExampleStandardError.new
1833
1911
  allow(e).to receive(:message).and_return(nil)
1834
- allow(e).to receive(:backtrace).and_return(["line 1"])
1912
+ e.set_backtrace(["line 1"])
1835
1913
  e
1836
1914
  end
1837
1915
 
@@ -1985,80 +2063,6 @@ describe Appsignal::Transaction do
1985
2063
 
1986
2064
  # private
1987
2065
 
1988
- describe "#cleaned_backtrace" do
1989
- let(:transaction) { new_transaction }
1990
- subject { transaction.send(:cleaned_backtrace, ["line 1", "line 2"]) }
1991
-
1992
- it "returns the backtrace" do
1993
- expect(subject).to eq ["line 1", "line 2"]
1994
- end
1995
-
1996
- context "with Rails module but without backtrace_cleaner method" do
1997
- it "returns the backtrace uncleaned" do
1998
- stub_const("Rails", Module.new)
1999
- expect(subject).to eq ["line 1", "line 2"]
2000
- end
2001
- end
2002
-
2003
- if rails_present?
2004
- context "with rails" do
2005
- it "cleans the backtrace with the Rails backtrace cleaner" do
2006
- ::Rails.backtrace_cleaner.add_filter do |line|
2007
- line.tr("2", "?")
2008
- end
2009
- expect(subject).to eq ["line 1", "line ?"]
2010
- end
2011
- end
2012
- end
2013
- end
2014
-
2015
- describe "#cleaned_error_message" do
2016
- let(:transaction) { new_transaction }
2017
- let(:error) { StandardError.new("Error message") }
2018
- subject { transaction.send(:cleaned_error_message, error) }
2019
-
2020
- it "returns the error message" do
2021
- expect(subject).to eq "Error message"
2022
- end
2023
-
2024
- context "with a PG::UniqueViolation" do
2025
- before do
2026
- stub_const("PG::UniqueViolation", Class.new(StandardError))
2027
- end
2028
-
2029
- let(:error) do
2030
- PG::UniqueViolation.new(
2031
- "ERROR: duplicate key value violates unique constraint " \
2032
- "\"index_users_on_email\" DETAIL: Key (email)=(test@test.com) already exists."
2033
- )
2034
- end
2035
-
2036
- it "returns a sanizited error message" do
2037
- expect(subject).to eq "ERROR: duplicate key value violates unique constraint " \
2038
- "\"index_users_on_email\" DETAIL: Key (email)=(?) already exists."
2039
- end
2040
- end
2041
-
2042
- context "with a ActiveRecord::RecordNotUnique" do
2043
- before do
2044
- stub_const("ActiveRecord::RecordNotUnique", Class.new(StandardError))
2045
- end
2046
-
2047
- let(:error) do
2048
- ActiveRecord::RecordNotUnique.new(
2049
- "PG::UniqueViolation: ERROR: duplicate key value violates unique constraint " \
2050
- "\"example_constraint\"\nDETAIL: Key (email)=(foo@example.com) already exists."
2051
- )
2052
- end
2053
-
2054
- it "returns a sanizited error message" do
2055
- expect(subject).to eq \
2056
- "PG::UniqueViolation: ERROR: duplicate key value violates unique constraint " \
2057
- "\"example_constraint\"\nDETAIL: Key (email)=(?) already exists."
2058
- end
2059
- end
2060
- end
2061
-
2062
2066
  describe ".to_hash / .to_h" do
2063
2067
  let(:transaction) { new_transaction }
2064
2068
  subject { transaction.to_hash }
data/spec/spec_helper.rb CHANGED
@@ -85,6 +85,10 @@ RSpec.configure do |config|
85
85
  File.join(tmp_dir, "system-tmp")
86
86
  end
87
87
 
88
+ config.before :suite do
89
+ WebMock.disable_net_connect!
90
+ end
91
+
88
92
  config.before :context do
89
93
  FileUtils.rm_rf(tmp_dir)
90
94
  FileUtils.mkdir_p(spec_system_tmp_dir)
@@ -94,6 +98,8 @@ RSpec.configure do |config|
94
98
  Appsignal.clear!
95
99
  Appsignal::Testing.clear!
96
100
  Appsignal::Loaders.clear!
101
+ Appsignal::CheckIn.clear!
102
+
97
103
  clear_current_transaction!
98
104
  stop_minutely_probes
99
105
  ENV["RAILS_ENV"] ||= "test"
@@ -168,13 +174,6 @@ RSpec.configure do |config|
168
174
  end
169
175
 
170
176
  def stop_minutely_probes
171
- thread =
172
- begin
173
- Appsignal::Probes.class_variable_get(:@@thread) # Fetch old thread
174
- rescue NameError
175
- nil
176
- end
177
177
  Appsignal::Probes.stop
178
- thread&.join # Wait for old thread to exit
179
178
  end
180
179
  end
@@ -17,4 +17,44 @@ module ApiRequestHelper
17
17
  endpoint = config[:endpoint] || Appsignal::Config::DEFAULT_CONFIG[:endpoint]
18
18
  stub_request(:post, "#{endpoint}/1/#{path}").with(options)
19
19
  end
20
+
21
+ def stub_check_in_request(events:, response: { :status => 200 })
22
+ config = Appsignal.config
23
+ options = {
24
+ :query => {
25
+ :api_key => config[:push_api_key],
26
+ :name => config[:name],
27
+ :environment => config.respond_to?(:env) ? config.env : config[:environment],
28
+ :hostname => config[:hostname],
29
+ :gem_version => Appsignal::VERSION
30
+ },
31
+ :headers => { "Content-Type" => "application/x-ndjson; charset=UTF-8" }
32
+ }
33
+
34
+ request_stub =
35
+ stub_request(
36
+ :post,
37
+ "#{config[:logging_endpoint]}/check_ins/json"
38
+ ).with(options) do |request|
39
+ # Parse each line as JSON per the NDJSON format
40
+ payloads = request.body.split("\n").map { |line| JSON.parse(line) }
41
+ formatted_events =
42
+ events.map do |event|
43
+ {
44
+ "identifier" => nil,
45
+ "digest" => kind_of(String),
46
+ "kind" => "start",
47
+ "timestamp" => kind_of(Integer),
48
+ "check_in_type" => "cron"
49
+ }.merge(event)
50
+ end
51
+ expect(payloads).to include(*formatted_events)
52
+ end
53
+
54
+ if response.is_a?(Exception)
55
+ request_stub.to_raise(response)
56
+ else
57
+ request_stub.to_return(response)
58
+ end
59
+ end
20
60
  end
@@ -46,7 +46,7 @@ module ConfigHelpers
46
46
  end
47
47
  module_function :build_config
48
48
 
49
- def start_agent(env: "production", options: {})
49
+ def start_agent(env: "production", options: {}, internal_logger: nil)
50
50
  env = "production" if env == :default
51
51
  env ||= "production"
52
52
  Appsignal.configure(env, :root_path => project_fixture_path) do |config|
@@ -55,6 +55,7 @@ module ConfigHelpers
55
55
  end
56
56
  end
57
57
  Appsignal.start
58
+ Appsignal.internal_logger = internal_logger if internal_logger
58
59
  end
59
60
 
60
61
  def clear_integration_env_vars!
@@ -127,6 +127,11 @@ module DependencyHelper
127
127
  dependency_present? "que"
128
128
  end
129
129
 
130
+ def que2_present?
131
+ que_present? &&
132
+ Gem.loaded_specs["que"].version >= Gem::Version.new("2.0.0")
133
+ end
134
+
130
135
  def hanami_present?
131
136
  dependency_present? "hanami"
132
137
  end
@@ -1,14 +1,21 @@
1
1
  RSpec::Matchers.define :contains_log do |level, message|
2
- expected_log_line = "[#{level.upcase}] #{message}"
2
+ log_level_prefix = level.upcase
3
3
 
4
4
  match do |actual|
5
- actual.include?(expected_log_line)
5
+ case message
6
+ when Regexp
7
+ /\[#{log_level_prefix}\] #{message}/.match?(actual)
8
+ else
9
+ expected_log_line = "[#{log_level_prefix}] #{message}"
10
+ actual.include?(expected_log_line)
11
+ end
6
12
  end
7
13
 
8
14
  failure_message do |actual|
9
15
  <<~MESSAGE
10
16
  Did not contain log line:
11
- #{expected_log_line}
17
+ Log level: #{log_level_prefix}
18
+ Message: #{message}
12
19
 
13
20
  Received logs:
14
21
  #{actual}
@@ -0,0 +1,10 @@
1
+ class HashLike < Hash
2
+ def initialize(value)
3
+ super
4
+ @value = value
5
+ end
6
+
7
+ def to_h
8
+ @value
9
+ end
10
+ end
@@ -0,0 +1,43 @@
1
+ class PumaMock
2
+ module MiniSSL
3
+ class SSLError < StandardError
4
+ def self.to_s
5
+ "Puma::MiniSSL::SSLError"
6
+ end
7
+ end
8
+ end
9
+
10
+ class HttpParserError < StandardError
11
+ def self.to_s
12
+ "Puma::HttpParserError"
13
+ end
14
+ end
15
+
16
+ class HttpParserError501 < StandardError
17
+ def self.to_s
18
+ "Puma::HttpParserError501"
19
+ end
20
+ end
21
+
22
+ def self.stats
23
+ end
24
+
25
+ def self.cli_config
26
+ @cli_config ||= CliConfig.new
27
+ end
28
+
29
+ class Server
30
+ end
31
+
32
+ module Const
33
+ VERSION = "6.0.0".freeze
34
+ end
35
+
36
+ class CliConfig
37
+ attr_accessor :options
38
+
39
+ def initialize
40
+ @options = {}
41
+ end
42
+ end
43
+ end
@@ -47,6 +47,15 @@ module Appsignal
47
47
  end
48
48
  end
49
49
 
50
+ module CheckIn
51
+ class << self
52
+ def clear!
53
+ @transmitter = nil
54
+ @scheduler = nil
55
+ end
56
+ end
57
+ end
58
+
50
59
  # @api private
51
60
  module Testing
52
61
  class << self