appsignal 3.11.0 → 3.12.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (75) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +109 -0
  3. data/Rakefile +1 -1
  4. data/lib/appsignal/cli/diagnose.rb +1 -1
  5. data/lib/appsignal/config.rb +150 -32
  6. data/lib/appsignal/demo.rb +1 -6
  7. data/lib/appsignal/integrations/grape.rb +7 -0
  8. data/lib/appsignal/integrations/hanami.rb +8 -43
  9. data/lib/appsignal/integrations/padrino.rb +8 -73
  10. data/lib/appsignal/integrations/railtie.rb +35 -13
  11. data/lib/appsignal/integrations/sinatra.rb +8 -19
  12. data/lib/appsignal/loaders/grape.rb +13 -0
  13. data/lib/appsignal/loaders/hanami.rb +40 -0
  14. data/lib/appsignal/loaders/padrino.rb +68 -0
  15. data/lib/appsignal/loaders/sinatra.rb +24 -0
  16. data/lib/appsignal/loaders.rb +92 -0
  17. data/lib/appsignal/rack/abstract_middleware.rb +2 -1
  18. data/lib/appsignal/rack/event_handler.rb +5 -5
  19. data/lib/appsignal/rack.rb +6 -0
  20. data/lib/appsignal/version.rb +1 -1
  21. data/lib/appsignal.rb +163 -9
  22. data/spec/lib/appsignal/cli/demo_spec.rb +0 -1
  23. data/spec/lib/appsignal/cli/diagnose/paths_spec.rb +1 -1
  24. data/spec/lib/appsignal/cli/diagnose_spec.rb +0 -1
  25. data/spec/lib/appsignal/config_spec.rb +153 -1
  26. data/spec/lib/appsignal/demo_spec.rb +1 -2
  27. data/spec/lib/appsignal/environment_spec.rb +4 -2
  28. data/spec/lib/appsignal/hooks/active_support_notifications_spec.rb +3 -6
  29. data/spec/lib/appsignal/hooks/activejob_spec.rb +3 -3
  30. data/spec/lib/appsignal/hooks/dry_monitor_spec.rb +4 -7
  31. data/spec/lib/appsignal/hooks/excon_spec.rb +3 -6
  32. data/spec/lib/appsignal/hooks/gvl_spec.rb +2 -2
  33. data/spec/lib/appsignal/hooks/http_spec.rb +1 -3
  34. data/spec/lib/appsignal/hooks/net_http_spec.rb +1 -1
  35. data/spec/lib/appsignal/hooks/redis_client_spec.rb +5 -8
  36. data/spec/lib/appsignal/hooks/redis_spec.rb +3 -6
  37. data/spec/lib/appsignal/hooks/resque_spec.rb +1 -1
  38. data/spec/lib/appsignal/hooks/sequel_spec.rb +3 -5
  39. data/spec/lib/appsignal/hooks/sidekiq_spec.rb +1 -1
  40. data/spec/lib/appsignal/hooks/webmachine_spec.rb +1 -1
  41. data/spec/lib/appsignal/integrations/delayed_job_plugin_spec.rb +2 -2
  42. data/spec/lib/appsignal/integrations/grape_spec.rb +36 -0
  43. data/spec/lib/appsignal/integrations/hanami_spec.rb +9 -178
  44. data/spec/lib/appsignal/integrations/http_spec.rb +1 -5
  45. data/spec/lib/appsignal/integrations/mongo_ruby_driver_spec.rb +4 -2
  46. data/spec/lib/appsignal/integrations/net_http_spec.rb +1 -1
  47. data/spec/lib/appsignal/integrations/object_spec.rb +1 -3
  48. data/spec/lib/appsignal/integrations/padrino_spec.rb +8 -330
  49. data/spec/lib/appsignal/integrations/railtie_spec.rb +275 -191
  50. data/spec/lib/appsignal/integrations/shoryuken_spec.rb +1 -1
  51. data/spec/lib/appsignal/integrations/sidekiq_spec.rb +11 -9
  52. data/spec/lib/appsignal/integrations/sinatra_spec.rb +9 -104
  53. data/spec/lib/appsignal/loaders/grape_spec.rb +12 -0
  54. data/spec/lib/appsignal/loaders/hanami_spec.rb +95 -0
  55. data/spec/lib/appsignal/loaders/padrino_spec.rb +277 -0
  56. data/spec/lib/appsignal/loaders/sinatra_spec.rb +47 -0
  57. data/spec/lib/appsignal/loaders_spec.rb +137 -0
  58. data/spec/lib/appsignal/probes/sidekiq_spec.rb +1 -1
  59. data/spec/lib/appsignal/probes_spec.rb +6 -5
  60. data/spec/lib/appsignal/rack/abstract_middleware_spec.rb +3 -2
  61. data/spec/lib/appsignal/rack/event_handler_spec.rb +33 -0
  62. data/spec/lib/appsignal/rack/generic_instrumentation_spec.rb +1 -1
  63. data/spec/lib/appsignal/rack/grape_middleware_spec.rb +2 -35
  64. data/spec/lib/appsignal/rack/hanami_middleware_spec.rb +1 -1
  65. data/spec/lib/appsignal/rack/sinatra_instrumentation_spec.rb +3 -3
  66. data/spec/lib/appsignal/span_spec.rb +1 -3
  67. data/spec/lib/appsignal/transaction_spec.rb +4 -2
  68. data/spec/lib/appsignal_spec.rb +278 -26
  69. data/spec/lib/puma/appsignal_spec.rb +0 -3
  70. data/spec/spec_helper.rb +5 -4
  71. data/spec/support/helpers/config_helpers.rb +2 -1
  72. data/spec/support/helpers/loader_helper.rb +21 -0
  73. data/spec/support/stubs/appsignal/loaders/loader_stub.rb +7 -0
  74. data/spec/support/testing.rb +46 -0
  75. metadata +15 -2
@@ -1,110 +1,15 @@
1
- if DependencyHelper.sinatra_present?
2
- require "appsignal/integrations/sinatra"
3
-
4
- def install_sinatra_integration
5
- load File.expand_path("lib/appsignal/integrations/sinatra.rb", project_dir)
6
- end
7
-
8
- # "Uninstall" the AppSignal integration
9
- def uninstall_sinatra_integration
10
- expected_middleware = [
11
- Rack::Events,
12
- Appsignal::Rack::SinatraBaseInstrumentation
13
- ]
14
- Sinatra::Base.instance_variable_get(:@middleware).delete_if do |middleware|
15
- expected_middleware.include?(middleware.first)
16
- end
17
- end
18
-
1
+ if DependencyHelper.padrino_present?
19
2
  describe "Sinatra integration" do
20
- before do
21
- Appsignal.config = nil
22
- end
23
- after { uninstall_sinatra_integration }
24
-
25
- context "when active" do
26
- before { allow(Appsignal).to receive(:active?).and_return(true) }
27
-
28
- it "does not start AppSignal again" do
29
- expect(Appsignal::Config).to_not receive(:new)
30
- expect(Appsignal).to_not receive(:start)
31
- install_sinatra_integration
32
- end
33
-
34
- it "adds the instrumentation middleware to Sinatra::Base" do
35
- install_sinatra_integration
36
- middlewares = Sinatra::Base.middleware.to_a
37
- expect(middlewares).to include(
38
- [Rack::Events, [[instance_of(Appsignal::Rack::EventHandler)]], nil]
39
- )
40
- expect(middlewares).to include(
41
- [Appsignal::Rack::SinatraBaseInstrumentation, [], nil]
42
- )
43
- end
44
- end
45
-
46
- context "when not active" do
47
- context "Appsignal.internal_logger" do
48
- subject { Appsignal.internal_logger }
49
-
50
- it "sets a logger" do
51
- install_sinatra_integration
52
- is_expected.to be_a Logger
53
- end
54
- end
55
-
56
- describe "middleware" do
57
- context "when AppSignal is not active" do
58
- it "does not add the instrumentation middleware to Sinatra::Base" do
59
- install_sinatra_integration
60
- middlewares = Sinatra::Base.middleware.to_a
61
- expect(middlewares).to_not include(
62
- [Appsignal::Rack::SinatraBaseInstrumentation, [], nil]
63
- )
64
- expect(middlewares).to_not include(
65
- [Rack::Events, [Appsignal::Rack::EventHandler], nil]
66
- )
67
- end
68
- end
69
-
70
- context "when the new AppSignal config is active" do
71
- it "adds the instrumentation middleware to Sinatra::Base" do
72
- ENV["APPSIGNAL_APP_NAME"] = "My Sinatra app name"
73
- ENV["APPSIGNAL_APP_ENV"] = "test"
74
- ENV["APPSIGNAL_PUSH_API_KEY"] = "my-key"
75
-
76
- install_sinatra_integration
77
- middlewares = Sinatra::Base.middleware.to_a
78
- expect(middlewares).to include(
79
- [Rack::Events, [[Appsignal::Rack::EventHandler]], nil],
80
- [Appsignal::Rack::SinatraBaseInstrumentation, [], nil]
81
- )
82
- end
83
- end
84
- end
85
-
86
- describe "environment" do
87
- subject { Appsignal.config.env }
88
-
89
- context "without APPSIGNAL_APP_ENV" do
90
- before { install_sinatra_integration }
91
-
92
- it "uses the app environment" do
93
- expect(subject).to eq("test")
94
- end
95
- end
3
+ it "loads the Sinatra loader" do
4
+ ENV["APPSIGNAL_APP_NAME"] = "test/sinatra"
5
+ ENV["APPSIGNAL_PUSH_API_KEY"] = "test-key"
96
6
 
97
- context "with APPSIGNAL_APP_ENV" do
98
- before do
99
- ENV["APPSIGNAL_APP_ENV"] = "env-staging"
100
- install_sinatra_integration
101
- end
7
+ require "appsignal/integrations/sinatra"
102
8
 
103
- it "uses the environment variable" do
104
- expect(subject).to eq("env-staging")
105
- end
106
- end
107
- end
9
+ expect(Appsignal::Loaders.instances).to include(
10
+ :sinatra => kind_of(Appsignal::Loaders::SinatraLoader)
11
+ )
12
+ expect(Appsignal.active?).to be(true)
108
13
  end
109
14
  end
110
15
  end
@@ -0,0 +1,12 @@
1
+ if DependencyHelper.grape_present?
2
+ describe "Appsignal::Loaders::PadrinoLoader" do
3
+ describe "#on_load" do
4
+ it "ensures the Grape middleware is loaded" do
5
+ load_loader(:grape)
6
+
7
+ # Calling this doesn't raise a NameError
8
+ Appsignal::Rack::GrapeMiddleware
9
+ end
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,95 @@
1
+ if DependencyHelper.hanami_present?
2
+ describe "Appsignal::Loaders::HanamiLoader" do
3
+ before { Appsignal.config = nil }
4
+
5
+ describe "#on_load" do
6
+ it "registers Hanami default config" do
7
+ load_loader(:hanami)
8
+
9
+ expect(Appsignal::Config.loader_defaults).to include([
10
+ :hanami,
11
+ {
12
+ :env => :test,
13
+ :root_path => Dir.pwd
14
+ }
15
+ ])
16
+ end
17
+ end
18
+
19
+ describe "#on_start" do
20
+ before do
21
+ allow(::Hanami::Action).to receive(:prepend)
22
+ load_loader(:hanami)
23
+ start_loader(:hanami)
24
+ end
25
+ after { uninstall_hanami_middleware }
26
+
27
+ def uninstall_hanami_middleware
28
+ middleware_stack = ::Hanami.app.config.middleware.stack[::Hanami::Router::DEFAULT_PREFIX]
29
+ middleware_stack.delete_if do |middleware|
30
+ middleware.first == Appsignal::Rack::HanamiMiddleware ||
31
+ middleware.first == Rack::Events
32
+ end
33
+ end
34
+
35
+ it "adds the instrumentation middleware to Sinatra::Base" do
36
+ expect(::Hanami.app.config.middleware.stack[::Hanami::Router::DEFAULT_PREFIX])
37
+ .to include(
38
+ [Rack::Events, [[kind_of(Appsignal::Rack::EventHandler)]], *hanami_middleware_options],
39
+ [Appsignal::Rack::HanamiMiddleware, [], *hanami_middleware_options]
40
+ )
41
+ end
42
+
43
+ it "prepends the integration to Hanami::Action" do
44
+ expect(::Hanami::Action)
45
+ .to have_received(:prepend).with(Appsignal::Loaders::HanamiLoader::HanamiIntegration)
46
+ end
47
+
48
+ def hanami_middleware_options
49
+ if DependencyHelper.hanami2_1_present?
50
+ [{}, nil]
51
+ else
52
+ [nil]
53
+ end
54
+ end
55
+ end
56
+
57
+ describe "Appsignal::Loaders::HanamiLoader::HanamiIntegration" do
58
+ let(:transaction) { http_request_transaction }
59
+ let(:app) { HanamiApp::Actions::Books::Index }
60
+ around { |example| keep_transactions { example.run } }
61
+ before do
62
+ expect(::Hanami.app.config).to receive(:root).and_return(project_fixture_path)
63
+ Appsignal.load(:hanami)
64
+ start_agent
65
+ end
66
+
67
+ def make_request(env)
68
+ action = app.new
69
+ action.call(env)
70
+ end
71
+
72
+ describe "#call" do
73
+ context "without an active transaction" do
74
+ let(:env) { {} }
75
+
76
+ it "does not set the action name" do
77
+ make_request(env)
78
+
79
+ expect(transaction).to_not have_action
80
+ end
81
+ end
82
+
83
+ context "with an active transaction" do
84
+ let(:env) { { Appsignal::Rack::APPSIGNAL_TRANSACTION => transaction } }
85
+
86
+ it "sets action name on the transaction" do
87
+ make_request(env)
88
+
89
+ expect(transaction).to have_action("HanamiApp::Actions::Books::Index")
90
+ end
91
+ end
92
+ end
93
+ end
94
+ end
95
+ end
@@ -0,0 +1,277 @@
1
+ if DependencyHelper.padrino_present?
2
+ describe "Appsignal::Loaders::PadrinoLoader" do
3
+ before { Appsignal.config = nil }
4
+
5
+ describe "#on_load" do
6
+ it "registers Padrino default config" do
7
+ load_loader(:padrino)
8
+
9
+ expect(Appsignal::Config.loader_defaults).to include([
10
+ :padrino,
11
+ {
12
+ :env => :test,
13
+ :root_path => Padrino.mounted_root
14
+ }
15
+ ])
16
+ end
17
+ end
18
+
19
+ describe "#on_start" do
20
+ let(:callbacks) { { :before_load => nil } }
21
+ before do
22
+ allow(Padrino).to receive(:before_load)
23
+ .and_wrap_original do |original_method, *args, &block|
24
+ callbacks[:before_load] = block
25
+ original_method.call(*args, &block)
26
+ end
27
+ end
28
+ after { uninstall_padrino_integration }
29
+
30
+ def uninstall_padrino_integration
31
+ expected_middleware = [
32
+ Rack::Events,
33
+ Appsignal::Rack::SinatraBaseInstrumentation
34
+ ]
35
+ Padrino.middleware.delete_if do |middleware|
36
+ expected_middleware.include?(middleware.first)
37
+ end
38
+ end
39
+
40
+ it "adds the instrumentation middleware to Padrino" do
41
+ load_loader(:padrino)
42
+ start_loader(:padrino)
43
+
44
+ callbacks[:before_load].call
45
+
46
+ middlewares = Padrino.middleware
47
+ expect(middlewares).to include(
48
+ [Rack::Events, [[instance_of(Appsignal::Rack::EventHandler)]], nil]
49
+ )
50
+ expect(middlewares).to include(
51
+ [
52
+ Appsignal::Rack::SinatraBaseInstrumentation,
53
+ [
54
+ :instrument_event_name => "process_action.padrino"
55
+ ],
56
+ nil
57
+ ]
58
+ )
59
+ end
60
+ end
61
+
62
+ describe "Padrino integration" do
63
+ class PadrinoClassWithRouter
64
+ include Padrino::Routing
65
+ end
66
+
67
+ let(:base) { double }
68
+ let(:router) { PadrinoClassWithRouter.new }
69
+ let(:env) { {} }
70
+ # TODO: use an instance double
71
+ let(:settings) { double(:name => "TestApp") }
72
+ around { |example| keep_transactions { example.run } }
73
+ before { Appsignal.config = nil }
74
+
75
+ describe "routes" do
76
+ let(:env) do
77
+ {
78
+ "REQUEST_METHOD" => "GET",
79
+ "PATH_INFO" => path,
80
+ "REQUEST_PATH" => path,
81
+ "rack.input" => StringIO.new
82
+ }
83
+ end
84
+ let(:app) do
85
+ Class.new(Padrino::Application) do
86
+ def self.name
87
+ "PadrinoTestApp"
88
+ end
89
+ end
90
+ end
91
+ let(:response) { app.call(env) }
92
+
93
+ def fetch_body(body)
94
+ if body.respond_to?(:response)
95
+ _, _, nested_body = body.response.to_a
96
+ fetch_body(nested_body)
97
+ elsif body.respond_to?(:to_ary)
98
+ body.to_ary
99
+ else
100
+ body
101
+ end
102
+ end
103
+
104
+ RSpec::Matchers.define :match_response do |expected_status, expected_body|
105
+ match do |response|
106
+ status, _headers, potential_body = response
107
+ body = fetch_body(potential_body)
108
+
109
+ matches_body =
110
+ if expected_body.is_a?(Regexp)
111
+ body.join =~ expected_body
112
+ else
113
+ body == [expected_body].compact
114
+ end
115
+ status == expected_status && matches_body
116
+ end
117
+ end
118
+
119
+ context "when AppSignal is not active" do
120
+ let(:path) { "/foo" }
121
+ before { app.controllers { get(:foo) { "content" } } }
122
+
123
+ it "does not instrument the request" do
124
+ expect do
125
+ expect(response).to match_response(200, "content")
126
+ end.to_not(change { created_transactions.count })
127
+ end
128
+ end
129
+
130
+ context "when AppSignal is active" do
131
+ let(:transaction) { http_request_transaction }
132
+ before do
133
+ start_agent
134
+ set_current_transaction(transaction)
135
+ end
136
+
137
+ context "with not existing route" do
138
+ let(:path) { "/404" }
139
+
140
+ it "instruments the request" do
141
+ expect(response).to match_response(404, /^GET /404/)
142
+ expect(last_transaction).to have_action("PadrinoTestApp#unknown")
143
+ end
144
+ end
145
+
146
+ context "when Sinatra tells us it's a static file" do
147
+ let(:path) { "/static" }
148
+ before do
149
+ env["sinatra.static_file"] = true
150
+ app.controllers { get(:static) { "Static!" } }
151
+ end
152
+
153
+ it "does not instrument the request" do
154
+ expect(response).to match_response(200, "Static!")
155
+ expect(last_transaction).to_not have_action
156
+ end
157
+ end
158
+
159
+ # Older Padrino versions don't support `action` (v11.0+)
160
+ context "without #action on Sinatra::Request" do
161
+ let(:path) { "/my_original_path/10" }
162
+ before do
163
+ allow_any_instance_of(Sinatra::Request).to receive(:action).and_return(nil)
164
+ app.controllers { get(:my_original_path, :with => :id) { "content" } }
165
+ end
166
+
167
+ it "falls back on Sinatra::Request#route_obj.original_path" do
168
+ expect(response).to match_response(200, "content")
169
+ expect(last_transaction).to have_action("PadrinoTestApp:/my_original_path/:id")
170
+ end
171
+ end
172
+
173
+ context "without Sinatra::Request#route_obj.original_path" do
174
+ let(:path) { "/my_original_path" }
175
+ before do
176
+ allow_any_instance_of(Sinatra::Request).to receive(:action).and_return(nil)
177
+ allow_any_instance_of(Sinatra::Request).to receive(:route_obj).and_return(nil)
178
+ app.controllers { get(:my_original_path) { "content" } }
179
+ end
180
+
181
+ it "falls back on app name" do
182
+ expect(response).to match_response(200, "content")
183
+ expect(last_transaction).to have_action("PadrinoTestApp#unknown")
184
+ end
185
+ end
186
+
187
+ context "with existing route" do
188
+ let(:path) { "/" }
189
+ def make_request
190
+ expect(response).to match_response(200, "content")
191
+ end
192
+
193
+ context "with action name as symbol" do
194
+ context "with :index helper" do
195
+ before do
196
+ # :index == "/"
197
+ app.controllers { get(:index) { "content" } }
198
+ end
199
+
200
+ it "sets the action with the app name and action name" do
201
+ make_request
202
+ expect(last_transaction).to have_action("PadrinoTestApp:#index")
203
+ end
204
+ end
205
+
206
+ context "with custom action name" do
207
+ let(:path) { "/foo" }
208
+ before do
209
+ app.controllers { get(:foo) { "content" } }
210
+ end
211
+
212
+ it "sets the action with the app name and action name" do
213
+ make_request
214
+ expect(last_transaction).to have_action("PadrinoTestApp:#foo")
215
+ end
216
+ end
217
+ end
218
+
219
+ context "with an action defined with a path" do
220
+ context "with root path" do
221
+ before do
222
+ # :index == "/"
223
+ app.controllers { get("/") { "content" } }
224
+ end
225
+
226
+ it "sets the action with the app name and action path" do
227
+ make_request
228
+ expect(last_transaction).to have_action("PadrinoTestApp:#/")
229
+ end
230
+ end
231
+
232
+ context "with custom path" do
233
+ let(:path) { "/foo" }
234
+ before do
235
+ app.controllers { get("/foo") { "content" } }
236
+ end
237
+
238
+ it "sets the action with the app name and action path" do
239
+ make_request
240
+ expect(last_transaction).to have_action("PadrinoTestApp:#/foo")
241
+ end
242
+ end
243
+ end
244
+
245
+ context "with controller" do
246
+ let(:path) { "/my_controller" }
247
+
248
+ context "with controller as name" do
249
+ before do
250
+ # :index == "/"
251
+ app.controllers(:my_controller) { get(:index) { "content" } }
252
+ end
253
+
254
+ it "sets the action with the app name, controller name and action name" do
255
+ make_request
256
+ expect(last_transaction).to have_action("PadrinoTestApp:my_controller#index")
257
+ end
258
+ end
259
+
260
+ context "with controller as path" do
261
+ before do
262
+ # :index == "/"
263
+ app.controllers("/my_controller") { get(:index) { "content" } }
264
+ end
265
+
266
+ it "sets the action with the app name, controller name and action path" do
267
+ make_request
268
+ expect(last_transaction).to have_action("PadrinoTestApp:/my_controller#index")
269
+ end
270
+ end
271
+ end
272
+ end
273
+ end
274
+ end
275
+ end
276
+ end
277
+ end
@@ -0,0 +1,47 @@
1
+ if DependencyHelper.sinatra_present?
2
+ describe "Appsignal::Loaders::SinatraLoader" do
3
+ before { Appsignal.config = nil }
4
+
5
+ describe "#on_load" do
6
+ it "registers Sinatra default config" do
7
+ ::Sinatra::Application.settings.root = "/some/path"
8
+ load_loader(:sinatra)
9
+
10
+ expect(Appsignal::Config.loader_defaults).to include([
11
+ :sinatra,
12
+ {
13
+ :env => :test,
14
+ :root_path => "/some/path"
15
+ }
16
+ ])
17
+ end
18
+ end
19
+
20
+ describe "#on_start" do
21
+ after { uninstall_sinatra_integration }
22
+
23
+ def uninstall_sinatra_integration
24
+ expected_middleware = [
25
+ Rack::Events,
26
+ Appsignal::Rack::SinatraBaseInstrumentation
27
+ ]
28
+ Sinatra::Base.instance_variable_get(:@middleware).delete_if do |middleware|
29
+ expected_middleware.include?(middleware.first)
30
+ end
31
+ end
32
+
33
+ it "adds the instrumentation middleware to Sinatra::Base" do
34
+ load_loader(:sinatra)
35
+ start_loader(:sinatra)
36
+
37
+ middlewares = Sinatra::Base.middleware.to_a
38
+ expect(middlewares).to include(
39
+ [Rack::Events, [[instance_of(Appsignal::Rack::EventHandler)]], nil]
40
+ )
41
+ expect(middlewares).to include(
42
+ [Appsignal::Rack::SinatraBaseInstrumentation, [], nil]
43
+ )
44
+ end
45
+ end
46
+ end
47
+ end
@@ -0,0 +1,137 @@
1
+ describe Appsignal::Loaders do
2
+ describe ".register" do
3
+ before do
4
+ define_loader(:test_loader) do
5
+ def on_load
6
+ puts "do something on_load"
7
+ register_config_defaults(
8
+ :root_path => "/some/path",
9
+ :env => "test env",
10
+ :active => false
11
+ )
12
+ end
13
+ end
14
+ end
15
+
16
+ it "registers a loader" do
17
+ define_loader(:test_loader)
18
+ expect(Appsignal::Loaders.loaders).to have_key(:test_loader)
19
+ end
20
+ end
21
+
22
+ describe ".unregister" do
23
+ it "unregisters a loader" do
24
+ define_loader(:test_loader)
25
+ expect(Appsignal::Loaders.loaders).to have_key(:test_loader)
26
+
27
+ Appsignal::Loaders.unregister(:test_loader)
28
+ expect(Appsignal::Loaders.loaders).to_not have_key(:test_loader)
29
+ end
30
+ end
31
+
32
+ describe ".load" do
33
+ it "calls the Loader's on_loader method" do
34
+ Appsignal::Testing.store[:loader_loaded] = 0
35
+ define_loader(:test_loader) do
36
+ def on_load
37
+ Appsignal::Testing.store[:loader_loaded] += 1
38
+ end
39
+ end
40
+ Appsignal::Loaders.load(:test_loader)
41
+
42
+ expect(Appsignal::Testing.store[:loader_loaded]).to eq(1)
43
+ end
44
+
45
+ it "registers config defaults" do
46
+ define_loader(:test_loader) do
47
+ def on_load
48
+ register_config_defaults(:my_option => true)
49
+ end
50
+ end
51
+ Appsignal::Loaders.load(:test_loader)
52
+
53
+ expect(Appsignal::Config.loader_defaults).to eq([[:test_loader, { :my_option => true }]])
54
+ end
55
+
56
+ it "does not load errors that aren't registered" do
57
+ logs =
58
+ capture_logs do
59
+ Appsignal::Loaders.load(:unknown_loader)
60
+ end
61
+
62
+ expect(logs).to contains_log(:warn, "No loader found with the name 'unknown_loader'.")
63
+ end
64
+
65
+ it "loads the loader file on load" do
66
+ expect(Appsignal::Loaders.registered?(:loader_stub)).to be_falsy
67
+ Appsignal::Loaders.load(:loader_stub)
68
+
69
+ expect(Appsignal::Loaders.registered?(:loader_stub)).to be_truthy
70
+ end
71
+
72
+ it "does not error when a loader has no on_load method" do
73
+ define_loader(:test_loader) do
74
+ # Do nothing
75
+ end
76
+ Appsignal::Loaders.load(:test_loader)
77
+ end
78
+
79
+ it "logs an error when an error occurs on load" do
80
+ define_loader(:test_loader) do
81
+ def on_load
82
+ raise ExampleStandardError, "uh oh"
83
+ end
84
+ end
85
+ logs =
86
+ capture_logs do
87
+ Appsignal::Loaders.load(:test_loader)
88
+ end
89
+
90
+ expect(logs).to contains_log(
91
+ :error,
92
+ "An error occurred while loading the 'test_loader' loader: ExampleStandardError: uh oh"
93
+ )
94
+ end
95
+ end
96
+
97
+ describe ".start" do
98
+ it "starts all loaded loaders" do
99
+ Appsignal::Testing.store[:loader_started] = 0
100
+ define_loader(:test_loader) do
101
+ def on_start
102
+ Appsignal::Testing.store[:loader_started] += 1
103
+ end
104
+ end
105
+ Appsignal::Loaders.load(:test_loader)
106
+ Appsignal::Loaders.start
107
+
108
+ expect(Appsignal::Testing.store[:loader_started]).to eq(1)
109
+ end
110
+
111
+ it "does not error when a loader has no on_start method" do
112
+ define_loader(:test_loader) do
113
+ # Do nothing
114
+ end
115
+ Appsignal::Loaders.load(:test_loader)
116
+ Appsignal::Loaders.start
117
+ end
118
+
119
+ it "logs an error when an error occurs on start" do
120
+ define_loader(:test_loader) do
121
+ def on_start
122
+ raise ExampleStandardError, "uh oh"
123
+ end
124
+ end
125
+ logs =
126
+ capture_logs do
127
+ Appsignal::Loaders.load(:test_loader)
128
+ Appsignal::Loaders.start
129
+ end
130
+
131
+ expect(logs).to contains_log(
132
+ :error,
133
+ "An error occurred while starting the 'test_loader' loader: ExampleStandardError: uh oh"
134
+ )
135
+ end
136
+ end
137
+ end
@@ -6,7 +6,7 @@ describe Appsignal::Probes::SidekiqProbe do
6
6
  let(:redis_hostname) { "localhost" }
7
7
  let(:expected_default_tags) { { :hostname => "localhost" } }
8
8
  before do
9
- Appsignal.config = project_fixture_config
9
+ start_agent
10
10
 
11
11
  class SidekiqStats
12
12
  class << self