appsignal 3.9.3-java → 3.11.0-java
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.github/workflows/ci.yml +22 -19
- data/.rubocop.yml +1 -1
- data/CHANGELOG.md +180 -0
- data/Gemfile +1 -0
- data/README.md +0 -1
- data/Rakefile +1 -1
- data/benchmark.rake +99 -42
- data/build_matrix.yml +10 -12
- data/gemfiles/webmachine1.gemfile +5 -4
- data/lib/appsignal/cli/demo.rb +0 -1
- data/lib/appsignal/config.rb +57 -97
- data/lib/appsignal/demo.rb +15 -20
- data/lib/appsignal/environment.rb +6 -1
- data/lib/appsignal/event_formatter/rom/sql_formatter.rb +1 -0
- data/lib/appsignal/event_formatter.rb +3 -2
- data/lib/appsignal/helpers/instrumentation.rb +490 -16
- data/lib/appsignal/hooks/action_cable.rb +21 -16
- data/lib/appsignal/hooks/active_job.rb +15 -14
- data/lib/appsignal/hooks/delayed_job.rb +1 -1
- data/lib/appsignal/hooks/shoryuken.rb +3 -63
- data/lib/appsignal/integrations/action_cable.rb +5 -7
- data/lib/appsignal/integrations/active_support_notifications.rb +1 -0
- data/lib/appsignal/integrations/capistrano/capistrano_2_tasks.rb +36 -35
- data/lib/appsignal/integrations/data_mapper.rb +1 -0
- data/lib/appsignal/integrations/delayed_job_plugin.rb +27 -33
- data/lib/appsignal/integrations/dry_monitor.rb +1 -0
- data/lib/appsignal/integrations/excon.rb +1 -0
- data/lib/appsignal/integrations/http.rb +1 -0
- data/lib/appsignal/integrations/net_http.rb +1 -0
- data/lib/appsignal/integrations/object.rb +6 -0
- data/lib/appsignal/integrations/padrino.rb +21 -25
- data/lib/appsignal/integrations/que.rb +13 -20
- data/lib/appsignal/integrations/railtie.rb +1 -1
- data/lib/appsignal/integrations/rake.rb +45 -15
- data/lib/appsignal/integrations/redis.rb +1 -0
- data/lib/appsignal/integrations/redis_client.rb +1 -0
- data/lib/appsignal/integrations/resque.rb +2 -5
- data/lib/appsignal/integrations/shoryuken.rb +75 -0
- data/lib/appsignal/integrations/sidekiq.rb +7 -25
- data/lib/appsignal/integrations/unicorn.rb +1 -0
- data/lib/appsignal/integrations/webmachine.rb +12 -9
- data/lib/appsignal/logger.rb +7 -3
- data/lib/appsignal/probes/helpers.rb +1 -0
- data/lib/appsignal/probes/mri.rb +1 -0
- data/lib/appsignal/probes/sidekiq.rb +1 -0
- data/lib/appsignal/probes.rb +3 -0
- data/lib/appsignal/rack/abstract_middleware.rb +67 -24
- data/lib/appsignal/rack/body_wrapper.rb +143 -0
- data/lib/appsignal/rack/event_handler.rb +39 -8
- data/lib/appsignal/rack/generic_instrumentation.rb +6 -4
- data/lib/appsignal/rack/grape_middleware.rb +3 -2
- data/lib/appsignal/rack/hanami_middleware.rb +1 -1
- data/lib/appsignal/rack/instrumentation_middleware.rb +62 -0
- data/lib/appsignal/rack/rails_instrumentation.rb +1 -3
- data/lib/appsignal/rack/sinatra_instrumentation.rb +1 -3
- data/lib/appsignal/rack/streaming_listener.rb +14 -59
- data/lib/appsignal/rack.rb +60 -0
- data/lib/appsignal/span.rb +1 -0
- data/lib/appsignal/transaction.rb +353 -104
- data/lib/appsignal/utils/data.rb +0 -1
- data/lib/appsignal/utils/hash_sanitizer.rb +0 -1
- data/lib/appsignal/utils/integration_logger.rb +0 -13
- data/lib/appsignal/utils/integration_memory_logger.rb +0 -13
- data/lib/appsignal/utils/json.rb +0 -1
- data/lib/appsignal/utils/query_params_sanitizer.rb +0 -1
- data/lib/appsignal/utils/stdout_and_logger_message.rb +0 -1
- data/lib/appsignal/utils.rb +6 -0
- data/lib/appsignal/version.rb +1 -1
- data/lib/appsignal.rb +9 -6
- data/spec/lib/appsignal/capistrano2_spec.rb +1 -1
- data/spec/lib/appsignal/config_spec.rb +139 -43
- data/spec/lib/appsignal/hooks/action_cable_spec.rb +43 -74
- data/spec/lib/appsignal/hooks/activejob_spec.rb +9 -0
- data/spec/lib/appsignal/hooks/delayed_job_spec.rb +2 -443
- data/spec/lib/appsignal/hooks/rake_spec.rb +100 -17
- data/spec/lib/appsignal/hooks/shoryuken_spec.rb +0 -171
- data/spec/lib/appsignal/integrations/delayed_job_plugin_spec.rb +459 -0
- data/spec/lib/appsignal/integrations/padrino_spec.rb +181 -131
- data/spec/lib/appsignal/integrations/que_spec.rb +3 -4
- data/spec/lib/appsignal/integrations/shoryuken_spec.rb +167 -0
- data/spec/lib/appsignal/integrations/sidekiq_spec.rb +4 -4
- data/spec/lib/appsignal/integrations/sinatra_spec.rb +10 -2
- data/spec/lib/appsignal/integrations/webmachine_spec.rb +77 -17
- data/spec/lib/appsignal/rack/abstract_middleware_spec.rb +144 -11
- data/spec/lib/appsignal/rack/body_wrapper_spec.rb +263 -0
- data/spec/lib/appsignal/rack/event_handler_spec.rb +81 -10
- data/spec/lib/appsignal/rack/generic_instrumentation_spec.rb +70 -17
- data/spec/lib/appsignal/rack/grape_middleware_spec.rb +1 -1
- data/spec/lib/appsignal/rack/instrumentation_middleware_spec.rb +38 -0
- data/spec/lib/appsignal/rack/rails_instrumentation_spec.rb +4 -2
- data/spec/lib/appsignal/rack/streaming_listener_spec.rb +43 -120
- data/spec/lib/appsignal/rack_spec.rb +63 -0
- data/spec/lib/appsignal/transaction_spec.rb +1675 -953
- data/spec/lib/appsignal/utils/integration_logger_spec.rb +12 -16
- data/spec/lib/appsignal/utils/integration_memory_logger_spec.rb +0 -10
- data/spec/lib/appsignal_spec.rb +517 -13
- data/spec/support/helpers/transaction_helpers.rb +44 -20
- data/spec/support/matchers/transaction.rb +15 -1
- data/spec/support/mocks/dummy_app.rb +1 -1
- data/spec/support/testing.rb +1 -1
- metadata +12 -4
- data/support/check_versions +0 -22
|
@@ -15,9 +15,7 @@ describe Appsignal::Hooks::DelayedJobHook do
|
|
|
15
15
|
end
|
|
16
16
|
end
|
|
17
17
|
after(:context) { Object.send(:remove_const, :Delayed) }
|
|
18
|
-
before
|
|
19
|
-
start_agent
|
|
20
|
-
end
|
|
18
|
+
before { start_agent }
|
|
21
19
|
|
|
22
20
|
describe "#dependencies_present?" do
|
|
23
21
|
subject { described_class.new.dependencies_present? }
|
|
@@ -26,446 +24,7 @@ describe Appsignal::Hooks::DelayedJobHook do
|
|
|
26
24
|
end
|
|
27
25
|
|
|
28
26
|
it "adds the plugin" do
|
|
29
|
-
expect(::Delayed::Worker.plugins).to include
|
|
30
|
-
end
|
|
31
|
-
|
|
32
|
-
# We haven't found a way to test the hooks, we'll have to do that manually
|
|
33
|
-
|
|
34
|
-
describe ".invoke_with_instrumentation" do
|
|
35
|
-
let(:plugin) { Appsignal::Hooks::DelayedJobPlugin }
|
|
36
|
-
let(:time) { Time.parse("01-01-2001 10:01:00UTC") }
|
|
37
|
-
let(:created_at) { time - 3600 }
|
|
38
|
-
let(:run_at) { time - 3600 }
|
|
39
|
-
let(:payload_object) { double(:args => args) }
|
|
40
|
-
let(:job_data) do
|
|
41
|
-
{
|
|
42
|
-
:id => 123,
|
|
43
|
-
:name => "TestClass#perform",
|
|
44
|
-
:priority => 1,
|
|
45
|
-
:attempts => 1,
|
|
46
|
-
:queue => "default",
|
|
47
|
-
:created_at => created_at,
|
|
48
|
-
:run_at => run_at,
|
|
49
|
-
:payload_object => payload_object
|
|
50
|
-
}
|
|
51
|
-
end
|
|
52
|
-
let(:args) { ["argument"] }
|
|
53
|
-
let(:job) { double(job_data) }
|
|
54
|
-
let(:invoked_block) { proc {} }
|
|
55
|
-
|
|
56
|
-
def perform
|
|
57
|
-
Timecop.freeze(time) do
|
|
58
|
-
keep_transactions do
|
|
59
|
-
plugin.invoke_with_instrumentation(job, invoked_block)
|
|
60
|
-
end
|
|
61
|
-
end
|
|
62
|
-
end
|
|
63
|
-
|
|
64
|
-
context "with a normal call" do
|
|
65
|
-
it "wraps it in a transaction" do
|
|
66
|
-
perform
|
|
67
|
-
transaction = last_transaction
|
|
68
|
-
expect(transaction).to have_action("TestClass#perform")
|
|
69
|
-
expect(transaction).to have_namespace("background_job")
|
|
70
|
-
expect(transaction).to_not have_error
|
|
71
|
-
expect(transaction).to include_event(:name => "perform_job.delayed_job")
|
|
72
|
-
expect(transaction).to include_sample_metadata(
|
|
73
|
-
"priority" => 1,
|
|
74
|
-
"attempts" => 1,
|
|
75
|
-
"queue" => "default",
|
|
76
|
-
"id" => "123"
|
|
77
|
-
)
|
|
78
|
-
expect(transaction).to include_params(["argument"])
|
|
79
|
-
end
|
|
80
|
-
|
|
81
|
-
context "with more complex params" do
|
|
82
|
-
let(:args) do
|
|
83
|
-
{
|
|
84
|
-
:foo => "Foo",
|
|
85
|
-
:bar => "Bar"
|
|
86
|
-
}
|
|
87
|
-
end
|
|
88
|
-
|
|
89
|
-
it "adds the more complex arguments" do
|
|
90
|
-
perform
|
|
91
|
-
|
|
92
|
-
expect(last_transaction).to include_params("foo" => "Foo", "bar" => "Bar")
|
|
93
|
-
end
|
|
94
|
-
|
|
95
|
-
context "with parameter filtering" do
|
|
96
|
-
before do
|
|
97
|
-
Appsignal.config = project_fixture_config("production")
|
|
98
|
-
Appsignal.config[:filter_parameters] = ["foo"]
|
|
99
|
-
end
|
|
100
|
-
|
|
101
|
-
it "filters selected arguments" do
|
|
102
|
-
perform
|
|
103
|
-
|
|
104
|
-
expect(last_transaction).to include_params("foo" => "[FILTERED]", "bar" => "Bar")
|
|
105
|
-
end
|
|
106
|
-
end
|
|
107
|
-
end
|
|
108
|
-
|
|
109
|
-
context "with run_at in the future" do
|
|
110
|
-
let(:run_at) { Time.parse("2017-01-01 10:01:00UTC") }
|
|
111
|
-
|
|
112
|
-
it "reports queue_start with run_at time" do
|
|
113
|
-
perform
|
|
114
|
-
|
|
115
|
-
expect(last_transaction).to have_queue_start(run_at.to_i * 1000)
|
|
116
|
-
end
|
|
117
|
-
end
|
|
118
|
-
|
|
119
|
-
context "with class method job" do
|
|
120
|
-
let(:job_data) do
|
|
121
|
-
{ :name => "CustomClassMethod.perform", :payload_object => payload_object }
|
|
122
|
-
end
|
|
123
|
-
|
|
124
|
-
it "wraps it in a transaction using the class method job name" do
|
|
125
|
-
perform
|
|
126
|
-
expect(last_transaction).to have_action("CustomClassMethod.perform")
|
|
127
|
-
end
|
|
128
|
-
end
|
|
129
|
-
|
|
130
|
-
context "with custom name call" do
|
|
131
|
-
before { perform }
|
|
132
|
-
|
|
133
|
-
context "with appsignal_name defined" do
|
|
134
|
-
context "with payload_object being an object" do
|
|
135
|
-
context "with value" do
|
|
136
|
-
let(:payload_object) { double(:appsignal_name => "CustomClass#perform") }
|
|
137
|
-
|
|
138
|
-
it "wraps it in a transaction using the custom name" do
|
|
139
|
-
expect(last_transaction).to have_action("CustomClass#perform")
|
|
140
|
-
end
|
|
141
|
-
end
|
|
142
|
-
|
|
143
|
-
context "with non-String value" do
|
|
144
|
-
let(:payload_object) { double(:appsignal_name => Object.new) }
|
|
145
|
-
|
|
146
|
-
it "wraps it in a transaction using the original job name" do
|
|
147
|
-
expect(last_transaction).to have_action("TestClass#perform")
|
|
148
|
-
end
|
|
149
|
-
end
|
|
150
|
-
|
|
151
|
-
context "with class method name as job" do
|
|
152
|
-
let(:payload_object) { double(:appsignal_name => "CustomClassMethod.perform") }
|
|
153
|
-
|
|
154
|
-
it "wraps it in a transaction using the custom name" do
|
|
155
|
-
perform
|
|
156
|
-
expect(last_transaction).to have_action("CustomClassMethod.perform")
|
|
157
|
-
end
|
|
158
|
-
end
|
|
159
|
-
end
|
|
160
|
-
|
|
161
|
-
context "with payload_object being a Hash" do
|
|
162
|
-
context "with value" do
|
|
163
|
-
let(:payload_object) { double(:appsignal_name => "CustomClassHash#perform") }
|
|
164
|
-
|
|
165
|
-
it "wraps it in a transaction using the custom name" do
|
|
166
|
-
expect(last_transaction).to have_action("CustomClassHash#perform")
|
|
167
|
-
end
|
|
168
|
-
end
|
|
169
|
-
|
|
170
|
-
context "with non-String value" do
|
|
171
|
-
let(:payload_object) { double(:appsignal_name => Object.new) }
|
|
172
|
-
|
|
173
|
-
it "wraps it in a transaction using the original job name" do
|
|
174
|
-
expect(last_transaction).to have_action("TestClass#perform")
|
|
175
|
-
end
|
|
176
|
-
end
|
|
177
|
-
|
|
178
|
-
context "with class method name as job" do
|
|
179
|
-
let(:payload_object) { { :appsignal_name => "CustomClassMethod.perform" } }
|
|
180
|
-
|
|
181
|
-
it "wraps it in a transaction using the custom name" do
|
|
182
|
-
perform
|
|
183
|
-
expect(last_transaction).to have_action("CustomClassMethod.perform")
|
|
184
|
-
end
|
|
185
|
-
end
|
|
186
|
-
end
|
|
187
|
-
|
|
188
|
-
context "with payload_object acting like a Hash and returning a non-String value" do
|
|
189
|
-
class ClassActingAsHash
|
|
190
|
-
def self.[](_key)
|
|
191
|
-
Object.new
|
|
192
|
-
end
|
|
193
|
-
|
|
194
|
-
def self.appsignal_name
|
|
195
|
-
"ClassActingAsHash#perform"
|
|
196
|
-
end
|
|
197
|
-
end
|
|
198
|
-
let(:payload_object) { ClassActingAsHash }
|
|
199
|
-
|
|
200
|
-
# We check for hash values before object values
|
|
201
|
-
# this means ClassActingAsHash returns `Object.new` instead
|
|
202
|
-
# of `self.appsignal_name`. Since this isn't a valid `String`
|
|
203
|
-
# we return the default job name as action name.
|
|
204
|
-
it "wraps it in a transaction using the original job name" do
|
|
205
|
-
expect(last_transaction).to have_action("TestClass#perform")
|
|
206
|
-
end
|
|
207
|
-
end
|
|
208
|
-
end
|
|
209
|
-
end
|
|
210
|
-
|
|
211
|
-
context "with only job class name" do
|
|
212
|
-
let(:job_data) do
|
|
213
|
-
{ :name => "Banana", :payload_object => payload_object }
|
|
214
|
-
end
|
|
215
|
-
|
|
216
|
-
it "appends #perform to the class name" do
|
|
217
|
-
perform
|
|
218
|
-
expect(last_transaction).to have_action("Banana#perform")
|
|
219
|
-
end
|
|
220
|
-
end
|
|
221
|
-
|
|
222
|
-
if active_job_present?
|
|
223
|
-
require "active_job"
|
|
224
|
-
|
|
225
|
-
context "when wrapped by ActiveJob" do
|
|
226
|
-
let(:payload_object) do
|
|
227
|
-
ActiveJob::QueueAdapters::DelayedJobAdapter::JobWrapper.new(
|
|
228
|
-
"arguments" => args,
|
|
229
|
-
"job_class" => "TestClass",
|
|
230
|
-
"job_id" => 123,
|
|
231
|
-
"locale" => :en,
|
|
232
|
-
"queue_name" => "default"
|
|
233
|
-
)
|
|
234
|
-
end
|
|
235
|
-
let(:job) do
|
|
236
|
-
double(
|
|
237
|
-
:id => 123,
|
|
238
|
-
:name => "ActiveJob::QueueAdapters::DelayedJobAdapter::JobWrapper",
|
|
239
|
-
:priority => 1,
|
|
240
|
-
:attempts => 1,
|
|
241
|
-
:queue => "default",
|
|
242
|
-
:created_at => created_at,
|
|
243
|
-
:run_at => run_at,
|
|
244
|
-
:payload_object => payload_object
|
|
245
|
-
)
|
|
246
|
-
end
|
|
247
|
-
let(:args) { ["activejob_argument"] }
|
|
248
|
-
|
|
249
|
-
it "wraps it in a transaction with the correct params" do
|
|
250
|
-
perform
|
|
251
|
-
|
|
252
|
-
transaction = last_transaction
|
|
253
|
-
expect(transaction).to have_namespace("background_job")
|
|
254
|
-
expect(transaction).to have_action("TestClass#perform")
|
|
255
|
-
expect(transaction).to_not have_error
|
|
256
|
-
expect(transaction).to include_event("name" => "perform_job.delayed_job")
|
|
257
|
-
expect(transaction).to include_sample_metadata(
|
|
258
|
-
"priority" => 1,
|
|
259
|
-
"attempts" => 1,
|
|
260
|
-
"queue" => "default",
|
|
261
|
-
"id" => "123"
|
|
262
|
-
)
|
|
263
|
-
expect(transaction).to include_params(["activejob_argument"])
|
|
264
|
-
end
|
|
265
|
-
|
|
266
|
-
context "with more complex params" do
|
|
267
|
-
let(:args) do
|
|
268
|
-
{
|
|
269
|
-
:foo => "Foo",
|
|
270
|
-
:bar => "Bar"
|
|
271
|
-
}
|
|
272
|
-
end
|
|
273
|
-
|
|
274
|
-
it "adds the more complex arguments" do
|
|
275
|
-
perform
|
|
276
|
-
transaction = last_transaction
|
|
277
|
-
expect(transaction).to have_action("TestClass#perform")
|
|
278
|
-
expect(transaction).to include_params(
|
|
279
|
-
"foo" => "Foo",
|
|
280
|
-
"bar" => "Bar"
|
|
281
|
-
)
|
|
282
|
-
end
|
|
283
|
-
|
|
284
|
-
context "with parameter filtering" do
|
|
285
|
-
before do
|
|
286
|
-
Appsignal.config = project_fixture_config("production")
|
|
287
|
-
Appsignal.config[:filter_parameters] = ["foo"]
|
|
288
|
-
end
|
|
289
|
-
|
|
290
|
-
it "filters selected arguments" do
|
|
291
|
-
perform
|
|
292
|
-
transaction = last_transaction
|
|
293
|
-
expect(transaction).to have_action("TestClass#perform")
|
|
294
|
-
expect(transaction).to include_params(
|
|
295
|
-
"foo" => "[FILTERED]",
|
|
296
|
-
"bar" => "Bar"
|
|
297
|
-
)
|
|
298
|
-
end
|
|
299
|
-
end
|
|
300
|
-
end
|
|
301
|
-
|
|
302
|
-
context "with run_at in the future" do
|
|
303
|
-
let(:run_at) { Time.parse("2017-01-01 10:01:00UTC") }
|
|
304
|
-
|
|
305
|
-
it "reports queue_start with run_at time" do
|
|
306
|
-
perform
|
|
307
|
-
|
|
308
|
-
expect(last_transaction).to have_queue_start(run_at.to_i * 1000)
|
|
309
|
-
end
|
|
310
|
-
end
|
|
311
|
-
end
|
|
312
|
-
end
|
|
313
|
-
end
|
|
314
|
-
|
|
315
|
-
context "with an erroring call" do
|
|
316
|
-
let(:error) { ExampleException.new("uh oh") }
|
|
317
|
-
before do
|
|
318
|
-
expect(invoked_block).to receive(:call).and_raise(error)
|
|
319
|
-
end
|
|
320
|
-
|
|
321
|
-
it "adds the error to the transaction" do
|
|
322
|
-
expect do
|
|
323
|
-
perform
|
|
324
|
-
end.to raise_error(error)
|
|
325
|
-
|
|
326
|
-
transaction = last_transaction
|
|
327
|
-
expect(transaction).to have_namespace("background_job")
|
|
328
|
-
expect(transaction).to have_action("TestClass#perform")
|
|
329
|
-
expect(transaction).to have_error("ExampleException", "uh oh")
|
|
330
|
-
end
|
|
331
|
-
end
|
|
332
|
-
end
|
|
333
|
-
|
|
334
|
-
describe ".extract_value" do
|
|
335
|
-
let(:plugin) { Appsignal::Hooks::DelayedJobPlugin }
|
|
336
|
-
|
|
337
|
-
context "for a hash" do
|
|
338
|
-
let(:hash) { { :key => "value", :bool_false => false } }
|
|
339
|
-
|
|
340
|
-
context "when the key exists" do
|
|
341
|
-
subject { plugin.extract_value(hash, :key) }
|
|
342
|
-
|
|
343
|
-
it { is_expected.to eq "value" }
|
|
344
|
-
|
|
345
|
-
context "when the value is false" do
|
|
346
|
-
subject { plugin.extract_value(hash, :bool_false) }
|
|
347
|
-
|
|
348
|
-
it { is_expected.to be false }
|
|
349
|
-
end
|
|
350
|
-
end
|
|
351
|
-
|
|
352
|
-
context "when the key does not exist" do
|
|
353
|
-
subject { plugin.extract_value(hash, :nonexistent_key) }
|
|
354
|
-
|
|
355
|
-
it { is_expected.to be_nil }
|
|
356
|
-
|
|
357
|
-
context "with a default value" do
|
|
358
|
-
subject { plugin.extract_value(hash, :nonexistent_key, 1) }
|
|
359
|
-
|
|
360
|
-
it { is_expected.to eq 1 }
|
|
361
|
-
end
|
|
362
|
-
end
|
|
363
|
-
end
|
|
364
|
-
|
|
365
|
-
context "for a struct" do
|
|
366
|
-
before :context do
|
|
367
|
-
TestStruct = Struct.new(:key)
|
|
368
|
-
end
|
|
369
|
-
let(:struct) { TestStruct.new("value") }
|
|
370
|
-
|
|
371
|
-
context "when the key exists" do
|
|
372
|
-
subject { plugin.extract_value(struct, :key) }
|
|
373
|
-
|
|
374
|
-
it { is_expected.to eq "value" }
|
|
375
|
-
end
|
|
376
|
-
|
|
377
|
-
context "when the key does not exist" do
|
|
378
|
-
subject { plugin.extract_value(struct, :nonexistent_key) }
|
|
379
|
-
|
|
380
|
-
it { is_expected.to be_nil }
|
|
381
|
-
|
|
382
|
-
context "with a default value" do
|
|
383
|
-
subject { plugin.extract_value(struct, :nonexistent_key, 1) }
|
|
384
|
-
|
|
385
|
-
it { is_expected.to eq 1 }
|
|
386
|
-
end
|
|
387
|
-
end
|
|
388
|
-
end
|
|
389
|
-
|
|
390
|
-
context "for a struct with a method" do
|
|
391
|
-
before :context do
|
|
392
|
-
class TestStructClass < Struct.new(:id) # rubocop:disable Style/StructInheritance
|
|
393
|
-
def appsignal_name
|
|
394
|
-
"TestStruct#perform"
|
|
395
|
-
end
|
|
396
|
-
|
|
397
|
-
def bool_false
|
|
398
|
-
false
|
|
399
|
-
end
|
|
400
|
-
end
|
|
401
|
-
end
|
|
402
|
-
let(:struct) { TestStructClass.new("id") }
|
|
403
|
-
|
|
404
|
-
context "when the Struct responds to a method" do
|
|
405
|
-
subject { plugin.extract_value(struct, :appsignal_name) }
|
|
406
|
-
|
|
407
|
-
it "returns the method value" do
|
|
408
|
-
is_expected.to eq "TestStruct#perform"
|
|
409
|
-
end
|
|
410
|
-
|
|
411
|
-
context "when the value is false" do
|
|
412
|
-
subject { plugin.extract_value(struct, :bool_false) }
|
|
413
|
-
|
|
414
|
-
it "returns the method value" do
|
|
415
|
-
is_expected.to be false
|
|
416
|
-
end
|
|
417
|
-
end
|
|
418
|
-
end
|
|
419
|
-
|
|
420
|
-
context "when the key does not exist" do
|
|
421
|
-
subject { plugin.extract_value(struct, :nonexistent_key) }
|
|
422
|
-
|
|
423
|
-
context "without a method with the same name" do
|
|
424
|
-
it "returns nil" do
|
|
425
|
-
is_expected.to be_nil
|
|
426
|
-
end
|
|
427
|
-
end
|
|
428
|
-
|
|
429
|
-
context "with a default value" do
|
|
430
|
-
let(:default_value) { :my_default_value }
|
|
431
|
-
subject { plugin.extract_value(struct, :nonexistent_key, default_value) }
|
|
432
|
-
|
|
433
|
-
it "returns the default value" do
|
|
434
|
-
is_expected.to eq default_value
|
|
435
|
-
end
|
|
436
|
-
end
|
|
437
|
-
end
|
|
438
|
-
end
|
|
439
|
-
|
|
440
|
-
context "for an object" do
|
|
441
|
-
let(:object) { double(:existing_method => "value") }
|
|
442
|
-
|
|
443
|
-
context "when the method exists" do
|
|
444
|
-
subject { plugin.extract_value(object, :existing_method) }
|
|
445
|
-
|
|
446
|
-
it { is_expected.to eq "value" }
|
|
447
|
-
end
|
|
448
|
-
|
|
449
|
-
context "when the method does not exist" do
|
|
450
|
-
subject { plugin.extract_value(object, :nonexistent_method) }
|
|
451
|
-
|
|
452
|
-
it { is_expected.to be_nil }
|
|
453
|
-
|
|
454
|
-
context "and there is a default value" do
|
|
455
|
-
subject { plugin.extract_value(object, :nonexistent_method, 1) }
|
|
456
|
-
|
|
457
|
-
it { is_expected.to eq 1 }
|
|
458
|
-
end
|
|
459
|
-
end
|
|
460
|
-
end
|
|
461
|
-
|
|
462
|
-
context "when we need to call to_s on the value" do
|
|
463
|
-
let(:object) { double(:existing_method => 1) }
|
|
464
|
-
|
|
465
|
-
subject { plugin.extract_value(object, :existing_method, nil, true) }
|
|
466
|
-
|
|
467
|
-
it { is_expected.to eq "1" }
|
|
468
|
-
end
|
|
27
|
+
expect(::Delayed::Worker.plugins).to include(Appsignal::Integrations::DelayedJobPlugin)
|
|
469
28
|
end
|
|
470
29
|
end
|
|
471
30
|
|
|
@@ -1,41 +1,89 @@
|
|
|
1
1
|
require "rake"
|
|
2
2
|
|
|
3
3
|
describe Appsignal::Hooks::RakeHook do
|
|
4
|
+
let(:helper) { Appsignal::Integrations::RakeIntegrationHelper }
|
|
4
5
|
let(:task) { Rake::Task.new("task:name", Rake::Application.new) }
|
|
5
6
|
let(:arguments) { Rake::TaskArguments.new(["foo"], ["bar"]) }
|
|
6
|
-
|
|
7
|
-
|
|
7
|
+
before do
|
|
8
|
+
start_agent
|
|
9
|
+
allow(Kernel).to receive(:at_exit)
|
|
10
|
+
end
|
|
11
|
+
around { |example| keep_transactions { example.run } }
|
|
12
|
+
after do
|
|
13
|
+
if helper.instance_variable_defined?(:@register_at_exit_hook)
|
|
14
|
+
helper.remove_instance_variable(:@register_at_exit_hook)
|
|
15
|
+
end
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
def expect_to_not_have_registered_at_exit_hook
|
|
19
|
+
expect(Kernel).to_not have_received(:at_exit)
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
def expect_to_have_registered_at_exit_hook
|
|
23
|
+
expect(Kernel).to have_received(:at_exit)
|
|
24
|
+
end
|
|
8
25
|
|
|
9
26
|
describe "#execute" do
|
|
10
27
|
context "without error" do
|
|
11
|
-
before { expect(Appsignal).to_not receive(:stop) }
|
|
12
|
-
|
|
13
28
|
def perform
|
|
14
29
|
task.execute(arguments)
|
|
15
30
|
end
|
|
16
31
|
|
|
17
|
-
|
|
18
|
-
|
|
32
|
+
context "with :enable_rake_performance_instrumentation == false" do
|
|
33
|
+
before do
|
|
34
|
+
Appsignal.config[:enable_rake_performance_instrumentation] = false
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
it "creates no transaction" do
|
|
38
|
+
expect { perform }.to_not(change { created_transactions.count })
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
it "calls the original task" do
|
|
42
|
+
expect(perform).to eq([])
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
it "does not register an at_exit hook" do
|
|
46
|
+
perform
|
|
47
|
+
expect_to_not_have_registered_at_exit_hook
|
|
48
|
+
end
|
|
19
49
|
end
|
|
20
50
|
|
|
21
|
-
|
|
22
|
-
|
|
51
|
+
context "with :enable_rake_performance_instrumentation == true" do
|
|
52
|
+
before do
|
|
53
|
+
Appsignal.config[:enable_rake_performance_instrumentation] = true
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
it "creates a transaction" do
|
|
57
|
+
expect { perform }.to(change { created_transactions.count }.by(1))
|
|
58
|
+
|
|
59
|
+
transaction = last_transaction
|
|
60
|
+
expect(transaction).to have_id
|
|
61
|
+
expect(transaction).to have_namespace(Appsignal::Transaction::BACKGROUND_JOB)
|
|
62
|
+
expect(transaction).to have_action("task:name")
|
|
63
|
+
expect(transaction).to_not have_error
|
|
64
|
+
expect(transaction).to include_params("foo" => "bar")
|
|
65
|
+
expect(transaction).to include_event("name" => "task.rake")
|
|
66
|
+
expect(transaction).to be_completed
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
it "calls the original task" do
|
|
70
|
+
expect(perform).to eq([])
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
it "registers an at_exit hook" do
|
|
74
|
+
perform
|
|
75
|
+
expect_to_have_registered_at_exit_hook
|
|
76
|
+
end
|
|
23
77
|
end
|
|
24
78
|
end
|
|
25
79
|
|
|
26
80
|
context "with error" do
|
|
27
|
-
let(:error) { ExampleException }
|
|
28
81
|
before do
|
|
29
|
-
task.enhance { raise
|
|
30
|
-
# We don't call `and_call_original` here as we don't want AppSignal to
|
|
31
|
-
# stop and start for every spec.
|
|
32
|
-
expect(Appsignal).to receive(:stop).with("rake")
|
|
82
|
+
task.enhance { raise ExampleException, "error message" }
|
|
33
83
|
end
|
|
34
84
|
|
|
35
85
|
def perform
|
|
36
|
-
|
|
37
|
-
expect { task.execute(arguments) }.to raise_error(error)
|
|
38
|
-
end
|
|
86
|
+
expect { task.execute(arguments) }.to raise_error(ExampleException, "error message")
|
|
39
87
|
end
|
|
40
88
|
|
|
41
89
|
it "creates a background job transaction" do
|
|
@@ -45,11 +93,16 @@ describe Appsignal::Hooks::RakeHook do
|
|
|
45
93
|
expect(transaction).to have_id
|
|
46
94
|
expect(transaction).to have_namespace(Appsignal::Transaction::BACKGROUND_JOB)
|
|
47
95
|
expect(transaction).to have_action("task:name")
|
|
48
|
-
expect(transaction).to have_error("ExampleException", "
|
|
96
|
+
expect(transaction).to have_error("ExampleException", "error message")
|
|
49
97
|
expect(transaction).to include_params("foo" => "bar")
|
|
50
98
|
expect(transaction).to be_completed
|
|
51
99
|
end
|
|
52
100
|
|
|
101
|
+
it "registers an at_exit hook" do
|
|
102
|
+
perform
|
|
103
|
+
expect_to_have_registered_at_exit_hook
|
|
104
|
+
end
|
|
105
|
+
|
|
53
106
|
context "when first argument is not a `Rake::TaskArguments`" do
|
|
54
107
|
let(:arguments) { nil }
|
|
55
108
|
|
|
@@ -62,3 +115,33 @@ describe Appsignal::Hooks::RakeHook do
|
|
|
62
115
|
end
|
|
63
116
|
end
|
|
64
117
|
end
|
|
118
|
+
|
|
119
|
+
describe "Appsignal::Integrations::RakeIntegrationHelper" do
|
|
120
|
+
let(:helper) { Appsignal::Integrations::RakeIntegrationHelper }
|
|
121
|
+
describe ".register_at_exit_hook" do
|
|
122
|
+
before do
|
|
123
|
+
start_agent
|
|
124
|
+
allow(Appsignal).to receive(:stop)
|
|
125
|
+
end
|
|
126
|
+
|
|
127
|
+
it "registers the at_exit hook only once" do
|
|
128
|
+
allow(Kernel).to receive(:at_exit)
|
|
129
|
+
helper.register_at_exit_hook
|
|
130
|
+
helper.register_at_exit_hook
|
|
131
|
+
expect(Kernel).to have_received(:at_exit).once
|
|
132
|
+
end
|
|
133
|
+
end
|
|
134
|
+
|
|
135
|
+
describe ".at_exit_hook" do
|
|
136
|
+
let(:helper) { Appsignal::Integrations::RakeIntegrationHelper }
|
|
137
|
+
before do
|
|
138
|
+
start_agent
|
|
139
|
+
allow(Appsignal).to receive(:stop)
|
|
140
|
+
end
|
|
141
|
+
|
|
142
|
+
it "calls Appsignal.stop" do
|
|
143
|
+
helper.at_exit_hook
|
|
144
|
+
expect(Appsignal).to have_received(:stop).with("rake")
|
|
145
|
+
end
|
|
146
|
+
end
|
|
147
|
+
end
|