appsignal 2.11.8-java → 3.0.1-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/.rubocop.yml +4 -1
- data/.rubocop_todo.yml +1 -1
- data/.semaphore/semaphore.yml +88 -111
- data/CHANGELOG.md +24 -0
- data/appsignal.gemspec +1 -1
- data/build_matrix.yml +11 -15
- data/lib/appsignal.rb +2 -29
- data/lib/appsignal/auth_check.rb +2 -8
- data/lib/appsignal/cli.rb +1 -23
- data/lib/appsignal/config.rb +1 -25
- data/lib/appsignal/event_formatter.rb +0 -25
- data/lib/appsignal/helpers/instrumentation.rb +69 -5
- data/lib/appsignal/hooks.rb +6 -13
- data/lib/appsignal/hooks/action_cable.rb +3 -34
- data/lib/appsignal/hooks/active_support_notifications.rb +7 -86
- data/lib/appsignal/hooks/celluloid.rb +5 -9
- data/lib/appsignal/hooks/net_http.rb +2 -12
- data/lib/appsignal/hooks/puma.rb +3 -5
- data/lib/appsignal/hooks/que.rb +1 -1
- data/lib/appsignal/hooks/rake.rb +2 -24
- data/lib/appsignal/hooks/redis.rb +2 -13
- data/lib/appsignal/hooks/resque.rb +2 -43
- data/lib/appsignal/hooks/sidekiq.rb +6 -143
- data/lib/appsignal/hooks/unicorn.rb +3 -24
- data/lib/appsignal/hooks/webmachine.rb +1 -7
- data/lib/appsignal/integrations/action_cable.rb +34 -0
- data/lib/appsignal/integrations/active_support_notifications.rb +77 -0
- data/lib/appsignal/integrations/net_http.rb +16 -0
- data/lib/appsignal/integrations/object.rb +39 -4
- data/lib/appsignal/integrations/padrino.rb +5 -7
- data/lib/appsignal/integrations/que.rb +26 -33
- data/lib/appsignal/integrations/railtie.rb +1 -4
- data/lib/appsignal/integrations/rake.rb +26 -2
- data/lib/appsignal/integrations/redis.rb +17 -0
- data/lib/appsignal/integrations/resque.rb +39 -10
- data/lib/appsignal/integrations/sidekiq.rb +171 -0
- data/lib/appsignal/integrations/unicorn.rb +28 -0
- data/lib/appsignal/integrations/webmachine.rb +22 -24
- data/lib/appsignal/minutely.rb +0 -12
- data/lib/appsignal/version.rb +1 -1
- data/spec/lib/appsignal/auth_check_spec.rb +1 -24
- data/spec/lib/appsignal/cli_spec.rb +1 -1
- data/spec/lib/appsignal/config_spec.rb +2 -66
- data/spec/lib/appsignal/event_formatter_spec.rb +0 -37
- data/spec/lib/appsignal/hooks/celluloid_spec.rb +6 -1
- data/spec/lib/appsignal/hooks/rake_spec.rb +1 -2
- data/spec/lib/appsignal/hooks/redis_spec.rb +50 -15
- data/spec/lib/appsignal/hooks/sidekiq_spec.rb +12 -464
- data/spec/lib/appsignal/hooks/unicorn_spec.rb +14 -3
- data/spec/lib/appsignal/hooks/webmachine_spec.rb +2 -13
- data/spec/lib/appsignal/hooks_spec.rb +6 -22
- data/spec/lib/appsignal/integrations/object_spec.rb +91 -8
- data/spec/lib/appsignal/integrations/padrino_spec.rb +2 -3
- data/spec/lib/appsignal/integrations/railtie_spec.rb +0 -45
- data/spec/lib/appsignal/integrations/sidekiq_spec.rb +524 -0
- data/spec/lib/appsignal/integrations/webmachine_spec.rb +26 -8
- data/spec/lib/appsignal/minutely_spec.rb +0 -19
- data/spec/lib/appsignal/transaction_spec.rb +1 -14
- data/spec/lib/appsignal/transmitter_spec.rb +1 -1
- data/spec/lib/appsignal_spec.rb +162 -116
- data/spec/spec_helper.rb +1 -15
- metadata +11 -21
- data/lib/appsignal/cli/notify_of_deploy.rb +0 -131
- data/lib/appsignal/integrations/object_ruby_19.rb +0 -37
- data/lib/appsignal/integrations/object_ruby_modern.rb +0 -64
- data/lib/appsignal/integrations/resque_active_job.rb +0 -19
- data/lib/appsignal/js_exception_transaction.rb +0 -56
- data/lib/appsignal/rack/js_exception_catcher.rb +0 -80
- data/spec/lib/appsignal/cli/notify_of_deploy_spec.rb +0 -180
- data/spec/lib/appsignal/integrations/object_19_spec.rb +0 -266
- data/spec/lib/appsignal/integrations/resque_active_job_spec.rb +0 -28
- data/spec/lib/appsignal/integrations/resque_spec.rb +0 -28
- data/spec/lib/appsignal/js_exception_transaction_spec.rb +0 -128
- data/spec/lib/appsignal/rack/js_exception_catcher_spec.rb +0 -170
@@ -3,6 +3,11 @@ describe Appsignal::Hooks::CelluloidHook do
|
|
3
3
|
before :context do
|
4
4
|
module Celluloid
|
5
5
|
def self.shutdown
|
6
|
+
@shut_down = true
|
7
|
+
end
|
8
|
+
|
9
|
+
def self.shut_down?
|
10
|
+
@shut_down == true
|
6
11
|
end
|
7
12
|
end
|
8
13
|
Appsignal::Hooks::CelluloidHook.new.install
|
@@ -18,7 +23,7 @@ describe Appsignal::Hooks::CelluloidHook do
|
|
18
23
|
end
|
19
24
|
|
20
25
|
specify { expect(Appsignal).to receive(:stop) }
|
21
|
-
specify { expect(Celluloid).to
|
26
|
+
specify { expect(Celluloid.shut_down?).to be true }
|
22
27
|
|
23
28
|
after do
|
24
29
|
Celluloid.shutdown
|
@@ -1,33 +1,68 @@
|
|
1
1
|
describe Appsignal::Hooks::RedisHook do
|
2
2
|
before do
|
3
3
|
Appsignal.config = project_fixture_config
|
4
|
-
Appsignal::Hooks.load_hooks
|
5
4
|
end
|
6
5
|
|
7
6
|
if DependencyHelper.redis_present?
|
8
7
|
context "with redis" do
|
9
8
|
context "with instrumentation enabled" do
|
10
|
-
before do
|
11
|
-
Appsignal.config.config_hash[:instrument_redis] = true
|
12
|
-
allow_any_instance_of(Redis::Client).to receive(:process_without_appsignal).and_return(1)
|
13
|
-
end
|
14
|
-
|
15
9
|
describe "#dependencies_present?" do
|
16
10
|
subject { described_class.new.dependencies_present? }
|
17
11
|
|
18
12
|
it { is_expected.to be_truthy }
|
19
13
|
end
|
20
14
|
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
15
|
+
describe "integration" do
|
16
|
+
before do
|
17
|
+
Appsignal.config.config_hash[:instrument_redis] = true
|
18
|
+
end
|
19
|
+
|
20
|
+
context "install" do
|
21
|
+
before do
|
22
|
+
Appsignal::Hooks.load_hooks
|
23
|
+
end
|
24
|
+
|
25
|
+
it "does something" do
|
26
|
+
# Test if the last included module (prepended module) was our
|
27
|
+
# integration. That's not certain with the assertions below
|
28
|
+
# because we have to overwrite the `process` method for the test.
|
29
|
+
expect(Redis::Client.included_modules.first)
|
30
|
+
.to eql(Appsignal::Integrations::RedisIntegration)
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
context "instrumentation" do
|
35
|
+
before do
|
36
|
+
# Stub Redis::Client class so that it doesn't perform an actual
|
37
|
+
# Redis query. This class will be included (prepended) with the
|
38
|
+
# AppSignal Redis integration.
|
39
|
+
stub_const("Redis::Client", Class.new do
|
40
|
+
def id
|
41
|
+
:stub_id
|
42
|
+
end
|
43
|
+
|
44
|
+
def process(_commands)
|
45
|
+
:stub_process
|
46
|
+
end
|
47
|
+
end)
|
48
|
+
# Load the integration again for the stubbed Redis::Client class.
|
49
|
+
# Call it directly because {Appsignal::Hooks.load_hooks} keeps
|
50
|
+
# track if it was installed already or not.
|
51
|
+
Appsignal::Hooks::RedisHook.new.install
|
52
|
+
end
|
53
|
+
|
54
|
+
it "instrument a redis call" do
|
55
|
+
Appsignal::Transaction.create("uuid", Appsignal::Transaction::HTTP_REQUEST, "test")
|
56
|
+
expect(Appsignal::Transaction.current).to receive(:start_event)
|
57
|
+
.at_least(:once)
|
58
|
+
expect(Appsignal::Transaction.current).to receive(:finish_event)
|
59
|
+
.at_least(:once)
|
60
|
+
.with("query.redis", :stub_id, "get ?", 0)
|
28
61
|
|
29
|
-
|
30
|
-
|
62
|
+
client = Redis::Client.new
|
63
|
+
expect(client.process([[:get, "key"]])).to eql(:stub_process)
|
64
|
+
end
|
65
|
+
end
|
31
66
|
end
|
32
67
|
end
|
33
68
|
|
@@ -51,6 +51,10 @@ describe Appsignal::Hooks::SidekiqHook do
|
|
51
51
|
yield middlewares if block_given?
|
52
52
|
middlewares
|
53
53
|
end
|
54
|
+
|
55
|
+
def self.error_handlers
|
56
|
+
@error_handlers ||= []
|
57
|
+
end
|
54
58
|
end
|
55
59
|
|
56
60
|
def add_middleware(middleware)
|
@@ -64,6 +68,12 @@ describe Appsignal::Hooks::SidekiqHook do
|
|
64
68
|
stub_const "Sidekiq", SidekiqMock
|
65
69
|
end
|
66
70
|
|
71
|
+
it "adds error handler" do
|
72
|
+
Sidekiq.middleware_mock = SidekiqMiddlewareMockWithPrepend
|
73
|
+
described_class.new.install
|
74
|
+
expect(Sidekiq.error_handlers).to include(Appsignal::Integrations::SidekiqErrorHandler)
|
75
|
+
end
|
76
|
+
|
67
77
|
context "when Sidekiq middleware responds to prepend method" do # Sidekiq 3.3.0 and newer
|
68
78
|
before { Sidekiq.middleware_mock = SidekiqMiddlewareMockWithPrepend }
|
69
79
|
|
@@ -75,7 +85,7 @@ describe Appsignal::Hooks::SidekiqHook do
|
|
75
85
|
add_middleware(user_middleware2)
|
76
86
|
|
77
87
|
expect(Sidekiq.server_middleware).to eql([
|
78
|
-
Appsignal::
|
88
|
+
Appsignal::Integrations::SidekiqMiddleware, # Prepend makes it the first entry
|
79
89
|
user_middleware1,
|
80
90
|
user_middleware2
|
81
91
|
])
|
@@ -95,472 +105,10 @@ describe Appsignal::Hooks::SidekiqHook do
|
|
95
105
|
# Add middlewares in whatever order they were added
|
96
106
|
expect(Sidekiq.server_middleware).to eql([
|
97
107
|
user_middleware1,
|
98
|
-
Appsignal::
|
108
|
+
Appsignal::Integrations::SidekiqMiddleware,
|
99
109
|
user_middleware2
|
100
110
|
])
|
101
111
|
end
|
102
112
|
end
|
103
113
|
end
|
104
114
|
end
|
105
|
-
|
106
|
-
describe Appsignal::Hooks::SidekiqPlugin, :with_yaml_parse_error => false do
|
107
|
-
class DelayedTestClass; end
|
108
|
-
|
109
|
-
let(:namespace) { Appsignal::Transaction::BACKGROUND_JOB }
|
110
|
-
let(:worker) { anything }
|
111
|
-
let(:queue) { anything }
|
112
|
-
let(:given_args) do
|
113
|
-
[
|
114
|
-
"foo",
|
115
|
-
{
|
116
|
-
:foo => "Foo",
|
117
|
-
:bar => "Bar",
|
118
|
-
"baz" => { 1 => :foo }
|
119
|
-
}
|
120
|
-
]
|
121
|
-
end
|
122
|
-
let(:expected_args) do
|
123
|
-
[
|
124
|
-
"foo",
|
125
|
-
{
|
126
|
-
"foo" => "Foo",
|
127
|
-
"bar" => "Bar",
|
128
|
-
"baz" => { "1" => "foo" }
|
129
|
-
}
|
130
|
-
]
|
131
|
-
end
|
132
|
-
let(:job_class) { "TestClass" }
|
133
|
-
let(:jid) { "b4a577edbccf1d805744efa9" }
|
134
|
-
let(:item) do
|
135
|
-
{
|
136
|
-
"jid" => jid,
|
137
|
-
"class" => job_class,
|
138
|
-
"retry_count" => 0,
|
139
|
-
"queue" => "default",
|
140
|
-
"created_at" => Time.parse("2001-01-01 10:00:00UTC").to_f,
|
141
|
-
"enqueued_at" => Time.parse("2001-01-01 10:00:00UTC").to_f,
|
142
|
-
"args" => given_args,
|
143
|
-
"extra" => "data"
|
144
|
-
}
|
145
|
-
end
|
146
|
-
let(:plugin) { Appsignal::Hooks::SidekiqPlugin.new }
|
147
|
-
let(:log) { StringIO.new }
|
148
|
-
before do
|
149
|
-
start_agent
|
150
|
-
Appsignal.logger = test_logger(log)
|
151
|
-
end
|
152
|
-
around { |example| keep_transactions { example.run } }
|
153
|
-
after :with_yaml_parse_error => false do
|
154
|
-
expect(log_contents(log)).to_not contains_log(:warn, "Unable to load YAML")
|
155
|
-
end
|
156
|
-
|
157
|
-
describe "internal Sidekiq job values" do
|
158
|
-
it "does not save internal Sidekiq values as metadata on transaction" do
|
159
|
-
perform_job
|
160
|
-
|
161
|
-
transaction_hash = transaction.to_h
|
162
|
-
expect(transaction_hash["metadata"].keys)
|
163
|
-
.to_not include(*Appsignal::Hooks::SidekiqPlugin::EXCLUDED_JOB_KEYS)
|
164
|
-
end
|
165
|
-
end
|
166
|
-
|
167
|
-
context "with parameter filtering" do
|
168
|
-
before do
|
169
|
-
Appsignal.config = project_fixture_config("production")
|
170
|
-
Appsignal.config[:filter_parameters] = ["foo"]
|
171
|
-
end
|
172
|
-
|
173
|
-
it "filters selected arguments" do
|
174
|
-
perform_job
|
175
|
-
|
176
|
-
transaction_hash = transaction.to_h
|
177
|
-
expect(transaction_hash["sample_data"]).to include(
|
178
|
-
"params" => [
|
179
|
-
"foo",
|
180
|
-
{
|
181
|
-
"foo" => "[FILTERED]",
|
182
|
-
"bar" => "Bar",
|
183
|
-
"baz" => { "1" => "foo" }
|
184
|
-
}
|
185
|
-
]
|
186
|
-
)
|
187
|
-
end
|
188
|
-
end
|
189
|
-
|
190
|
-
context "with encrypted arguments" do
|
191
|
-
before do
|
192
|
-
item["encrypt"] = true
|
193
|
-
item["args"] << "super secret value" # Last argument will be replaced
|
194
|
-
end
|
195
|
-
|
196
|
-
it "replaces the last argument (the secret bag) with an [encrypted data] string" do
|
197
|
-
perform_job
|
198
|
-
|
199
|
-
transaction_hash = transaction.to_h
|
200
|
-
expect(transaction_hash["sample_data"]).to include(
|
201
|
-
"params" => expected_args << "[encrypted data]"
|
202
|
-
)
|
203
|
-
end
|
204
|
-
end
|
205
|
-
|
206
|
-
context "when using the Sidekiq delayed extension" do
|
207
|
-
let(:item) do
|
208
|
-
{
|
209
|
-
"jid" => jid,
|
210
|
-
"class" => "Sidekiq::Extensions::DelayedClass",
|
211
|
-
"queue" => "default",
|
212
|
-
"args" => [
|
213
|
-
"---\n- !ruby/class 'DelayedTestClass'\n- :foo_method\n- - :bar: baz\n"
|
214
|
-
],
|
215
|
-
"retry" => true,
|
216
|
-
"created_at" => Time.parse("2001-01-01 10:00:00UTC").to_f,
|
217
|
-
"enqueued_at" => Time.parse("2001-01-01 10:00:00UTC").to_f,
|
218
|
-
"extra" => "data"
|
219
|
-
}
|
220
|
-
end
|
221
|
-
|
222
|
-
it "uses the delayed class and method name for the action" do
|
223
|
-
perform_job
|
224
|
-
|
225
|
-
transaction_hash = transaction.to_h
|
226
|
-
expect(transaction_hash["action"]).to eq("DelayedTestClass.foo_method")
|
227
|
-
expect(transaction_hash["sample_data"]).to include(
|
228
|
-
"params" => ["bar" => "baz"]
|
229
|
-
)
|
230
|
-
end
|
231
|
-
|
232
|
-
context "when job arguments is a malformed YAML object", :with_yaml_parse_error => true do
|
233
|
-
before { item["args"] = [] }
|
234
|
-
|
235
|
-
it "logs a warning and uses the default argument" do
|
236
|
-
perform_job
|
237
|
-
|
238
|
-
transaction_hash = transaction.to_h
|
239
|
-
expect(transaction_hash["action"]).to eq("Sidekiq::Extensions::DelayedClass#perform")
|
240
|
-
expect(transaction_hash["sample_data"]).to include("params" => [])
|
241
|
-
expect(log_contents(log)).to contains_log(:warn, "Unable to load YAML")
|
242
|
-
end
|
243
|
-
end
|
244
|
-
end
|
245
|
-
|
246
|
-
context "when using the Sidekiq ActiveRecord instance delayed extension" do
|
247
|
-
let(:item) do
|
248
|
-
{
|
249
|
-
"jid" => jid,
|
250
|
-
"class" => "Sidekiq::Extensions::DelayedModel",
|
251
|
-
"queue" => "default",
|
252
|
-
"args" => [
|
253
|
-
"---\n- !ruby/object:DelayedTestClass {}\n- :foo_method\n- - :bar: :baz\n"
|
254
|
-
],
|
255
|
-
"retry" => true,
|
256
|
-
"created_at" => Time.parse("2001-01-01 10:00:00UTC").to_f,
|
257
|
-
"enqueued_at" => Time.parse("2001-01-01 10:00:00UTC").to_f,
|
258
|
-
"extra" => "data"
|
259
|
-
}
|
260
|
-
end
|
261
|
-
|
262
|
-
it "uses the delayed class and method name for the action" do
|
263
|
-
perform_job
|
264
|
-
|
265
|
-
transaction_hash = transaction.to_h
|
266
|
-
expect(transaction_hash["action"]).to eq("DelayedTestClass#foo_method")
|
267
|
-
expect(transaction_hash["sample_data"]).to include(
|
268
|
-
"params" => ["bar" => "baz"]
|
269
|
-
)
|
270
|
-
end
|
271
|
-
|
272
|
-
context "when job arguments is a malformed YAML object", :with_yaml_parse_error => true do
|
273
|
-
before { item["args"] = [] }
|
274
|
-
|
275
|
-
it "logs a warning and uses the default argument" do
|
276
|
-
perform_job
|
277
|
-
|
278
|
-
transaction_hash = transaction.to_h
|
279
|
-
expect(transaction_hash["action"]).to eq("Sidekiq::Extensions::DelayedModel#perform")
|
280
|
-
expect(transaction_hash["sample_data"]).to include("params" => [])
|
281
|
-
expect(log_contents(log)).to contains_log(:warn, "Unable to load YAML")
|
282
|
-
end
|
283
|
-
end
|
284
|
-
end
|
285
|
-
|
286
|
-
context "with an error" do
|
287
|
-
let(:error) { ExampleException }
|
288
|
-
|
289
|
-
it "creates a transaction and adds the error" do
|
290
|
-
expect(Appsignal).to receive(:increment_counter)
|
291
|
-
.with("sidekiq_queue_job_count", 1, :queue => "default", :status => :failed)
|
292
|
-
expect(Appsignal).to receive(:increment_counter)
|
293
|
-
.with("sidekiq_queue_job_count", 1, :queue => "default", :status => :processed)
|
294
|
-
|
295
|
-
expect do
|
296
|
-
perform_job { raise error, "uh oh" }
|
297
|
-
end.to raise_error(error)
|
298
|
-
|
299
|
-
transaction_hash = transaction.to_h
|
300
|
-
expect(transaction_hash).to include(
|
301
|
-
"id" => jid,
|
302
|
-
"action" => "TestClass#perform",
|
303
|
-
"error" => {
|
304
|
-
"name" => "ExampleException",
|
305
|
-
"message" => "uh oh",
|
306
|
-
# TODO: backtrace should be an Array of Strings
|
307
|
-
# https://github.com/appsignal/appsignal-agent/issues/294
|
308
|
-
"backtrace" => kind_of(String)
|
309
|
-
},
|
310
|
-
"metadata" => {
|
311
|
-
"extra" => "data",
|
312
|
-
"queue" => "default",
|
313
|
-
"retry_count" => "0"
|
314
|
-
},
|
315
|
-
"namespace" => namespace,
|
316
|
-
"sample_data" => {
|
317
|
-
"environment" => {},
|
318
|
-
"params" => expected_args,
|
319
|
-
"tags" => {},
|
320
|
-
"breadcrumbs" => []
|
321
|
-
}
|
322
|
-
)
|
323
|
-
expect_transaction_to_have_sidekiq_event(transaction_hash)
|
324
|
-
end
|
325
|
-
end
|
326
|
-
|
327
|
-
context "without an error" do
|
328
|
-
it "creates a transaction with events" do
|
329
|
-
expect(Appsignal).to receive(:increment_counter)
|
330
|
-
.with("sidekiq_queue_job_count", 1, :queue => "default", :status => :processed)
|
331
|
-
|
332
|
-
perform_job
|
333
|
-
|
334
|
-
transaction_hash = transaction.to_h
|
335
|
-
expect(transaction_hash).to include(
|
336
|
-
"id" => jid,
|
337
|
-
"action" => "TestClass#perform",
|
338
|
-
"error" => nil,
|
339
|
-
"metadata" => {
|
340
|
-
"extra" => "data",
|
341
|
-
"queue" => "default",
|
342
|
-
"retry_count" => "0"
|
343
|
-
},
|
344
|
-
"namespace" => namespace,
|
345
|
-
"sample_data" => {
|
346
|
-
"environment" => {},
|
347
|
-
"params" => expected_args,
|
348
|
-
"tags" => {},
|
349
|
-
"breadcrumbs" => []
|
350
|
-
}
|
351
|
-
)
|
352
|
-
# TODO: Not available in transaction.to_h yet.
|
353
|
-
# https://github.com/appsignal/appsignal-agent/issues/293
|
354
|
-
expect(transaction.request.env).to eq(
|
355
|
-
:queue_start => Time.parse("2001-01-01 10:00:00UTC").to_f
|
356
|
-
)
|
357
|
-
expect_transaction_to_have_sidekiq_event(transaction_hash)
|
358
|
-
end
|
359
|
-
end
|
360
|
-
|
361
|
-
def perform_job
|
362
|
-
Timecop.freeze(Time.parse("2001-01-01 10:01:00UTC")) do
|
363
|
-
plugin.call(worker, item, queue) do
|
364
|
-
yield if block_given?
|
365
|
-
end
|
366
|
-
end
|
367
|
-
end
|
368
|
-
|
369
|
-
def transaction
|
370
|
-
last_transaction
|
371
|
-
end
|
372
|
-
|
373
|
-
def expect_transaction_to_have_sidekiq_event(transaction_hash)
|
374
|
-
events = transaction_hash["events"]
|
375
|
-
expect(events.count).to eq(1)
|
376
|
-
expect(events.first).to include(
|
377
|
-
"name" => "perform_job.sidekiq",
|
378
|
-
"title" => "",
|
379
|
-
"count" => 1,
|
380
|
-
"body" => "",
|
381
|
-
"body_format" => Appsignal::EventFormatter::DEFAULT
|
382
|
-
)
|
383
|
-
end
|
384
|
-
end
|
385
|
-
|
386
|
-
if DependencyHelper.active_job_present?
|
387
|
-
require "active_job"
|
388
|
-
require "action_mailer"
|
389
|
-
require "sidekiq/testing"
|
390
|
-
|
391
|
-
describe "Sidekiq ActiveJob integration" do
|
392
|
-
let(:namespace) { Appsignal::Transaction::BACKGROUND_JOB }
|
393
|
-
let(:time) { Time.parse("2001-01-01 10:00:00UTC") }
|
394
|
-
let(:log) { StringIO.new }
|
395
|
-
let(:given_args) do
|
396
|
-
[
|
397
|
-
"foo",
|
398
|
-
{
|
399
|
-
:foo => "Foo",
|
400
|
-
"bar" => "Bar",
|
401
|
-
"baz" => { "1" => "foo" }
|
402
|
-
}
|
403
|
-
]
|
404
|
-
end
|
405
|
-
let(:expected_args) do
|
406
|
-
[
|
407
|
-
"foo",
|
408
|
-
{
|
409
|
-
"_aj_symbol_keys" => ["foo"],
|
410
|
-
"foo" => "Foo",
|
411
|
-
"bar" => "Bar",
|
412
|
-
"baz" => {
|
413
|
-
"_aj_symbol_keys" => [],
|
414
|
-
"1" => "foo"
|
415
|
-
}
|
416
|
-
}
|
417
|
-
]
|
418
|
-
end
|
419
|
-
let(:expected_tags) do
|
420
|
-
{}.tap do |hash|
|
421
|
-
hash["active_job_id"] = kind_of(String)
|
422
|
-
if DependencyHelper.rails_version >= Gem::Version.new("5.0.0")
|
423
|
-
hash["provider_job_id"] = kind_of(String)
|
424
|
-
end
|
425
|
-
end
|
426
|
-
end
|
427
|
-
before do
|
428
|
-
start_agent
|
429
|
-
Appsignal.logger = test_logger(log)
|
430
|
-
ActiveJob::Base.queue_adapter = :sidekiq
|
431
|
-
|
432
|
-
class ActiveJobSidekiqTestJob < ActiveJob::Base
|
433
|
-
self.queue_adapter = :sidekiq
|
434
|
-
|
435
|
-
def perform(*_args)
|
436
|
-
end
|
437
|
-
end
|
438
|
-
|
439
|
-
class ActiveJobSidekiqErrorTestJob < ActiveJob::Base
|
440
|
-
self.queue_adapter = :sidekiq
|
441
|
-
|
442
|
-
def perform(*_args)
|
443
|
-
raise "uh oh"
|
444
|
-
end
|
445
|
-
end
|
446
|
-
# Manually add the AppSignal middleware for the Testing environment.
|
447
|
-
# It doesn't use configured middlewares by default looks like.
|
448
|
-
# We test somewhere else if the middleware is installed properly.
|
449
|
-
Sidekiq::Testing.server_middleware do |chain|
|
450
|
-
chain.add Appsignal::Hooks::SidekiqPlugin
|
451
|
-
end
|
452
|
-
end
|
453
|
-
around do |example|
|
454
|
-
keep_transactions do
|
455
|
-
Sidekiq::Testing.fake! do
|
456
|
-
example.run
|
457
|
-
end
|
458
|
-
end
|
459
|
-
end
|
460
|
-
after do
|
461
|
-
Object.send(:remove_const, :ActiveJobSidekiqTestJob)
|
462
|
-
Object.send(:remove_const, :ActiveJobSidekiqErrorTestJob)
|
463
|
-
end
|
464
|
-
|
465
|
-
it "reports the transaction from the ActiveJob integration" do
|
466
|
-
perform_job(ActiveJobSidekiqTestJob, given_args)
|
467
|
-
|
468
|
-
transaction = last_transaction
|
469
|
-
transaction_hash = transaction.to_h
|
470
|
-
expect(transaction_hash).to include(
|
471
|
-
"action" => "ActiveJobSidekiqTestJob#perform",
|
472
|
-
"error" => nil,
|
473
|
-
"namespace" => namespace,
|
474
|
-
"metadata" => hash_including(
|
475
|
-
"queue" => "default"
|
476
|
-
),
|
477
|
-
"sample_data" => hash_including(
|
478
|
-
"environment" => {},
|
479
|
-
"params" => [expected_args],
|
480
|
-
"tags" => expected_tags.merge("queue" => "default")
|
481
|
-
)
|
482
|
-
)
|
483
|
-
expect(transaction.request.env).to eq(:queue_start => time.to_f)
|
484
|
-
events = transaction_hash["events"]
|
485
|
-
.sort_by { |e| e["start"] }
|
486
|
-
.map { |event| event["name"] }
|
487
|
-
expect(events)
|
488
|
-
.to eq(["perform_job.sidekiq", "perform_start.active_job", "perform.active_job"])
|
489
|
-
end
|
490
|
-
|
491
|
-
context "with error" do
|
492
|
-
it "reports the error on the transaction from the ActiveRecord integration" do
|
493
|
-
expect do
|
494
|
-
perform_job(ActiveJobSidekiqErrorTestJob, given_args)
|
495
|
-
end.to raise_error(RuntimeError, "uh oh")
|
496
|
-
|
497
|
-
transaction = last_transaction
|
498
|
-
transaction_hash = transaction.to_h
|
499
|
-
expect(transaction_hash).to include(
|
500
|
-
"action" => "ActiveJobSidekiqErrorTestJob#perform",
|
501
|
-
"error" => {
|
502
|
-
"name" => "RuntimeError",
|
503
|
-
"message" => "uh oh",
|
504
|
-
"backtrace" => kind_of(String)
|
505
|
-
},
|
506
|
-
"namespace" => namespace,
|
507
|
-
"metadata" => hash_including(
|
508
|
-
"queue" => "default"
|
509
|
-
),
|
510
|
-
"sample_data" => hash_including(
|
511
|
-
"environment" => {},
|
512
|
-
"params" => [expected_args],
|
513
|
-
"tags" => expected_tags.merge("queue" => "default")
|
514
|
-
)
|
515
|
-
)
|
516
|
-
expect(transaction.request.env).to eq(:queue_start => time.to_f)
|
517
|
-
events = transaction_hash["events"]
|
518
|
-
.sort_by { |e| e["start"] }
|
519
|
-
.map { |event| event["name"] }
|
520
|
-
expect(events)
|
521
|
-
.to eq(["perform_job.sidekiq", "perform_start.active_job", "perform.active_job"])
|
522
|
-
end
|
523
|
-
end
|
524
|
-
|
525
|
-
context "with ActionMailer" do
|
526
|
-
include ActionMailerHelpers
|
527
|
-
|
528
|
-
before do
|
529
|
-
class ActionMailerSidekiqTestJob < ActionMailer::Base
|
530
|
-
def welcome(*args)
|
531
|
-
end
|
532
|
-
end
|
533
|
-
end
|
534
|
-
|
535
|
-
it "reports ActionMailer data on the transaction" do
|
536
|
-
perform_mailer(ActionMailerSidekiqTestJob, :welcome, given_args)
|
537
|
-
|
538
|
-
transaction = last_transaction
|
539
|
-
transaction_hash = transaction.to_h
|
540
|
-
expect(transaction_hash).to include(
|
541
|
-
"action" => "ActionMailerSidekiqTestJob#welcome",
|
542
|
-
"sample_data" => hash_including(
|
543
|
-
"params" => ["ActionMailerSidekiqTestJob", "welcome", "deliver_now"] + expected_args
|
544
|
-
)
|
545
|
-
)
|
546
|
-
end
|
547
|
-
end
|
548
|
-
|
549
|
-
def perform_sidekiq
|
550
|
-
Timecop.freeze(time) do
|
551
|
-
yield
|
552
|
-
# Combined with Sidekiq::Testing.fake! and drain_all we get a
|
553
|
-
# enqueue_at in the job data.
|
554
|
-
Sidekiq::Worker.drain_all
|
555
|
-
end
|
556
|
-
end
|
557
|
-
|
558
|
-
def perform_job(job_class, args)
|
559
|
-
perform_sidekiq { job_class.perform_later(args) }
|
560
|
-
end
|
561
|
-
|
562
|
-
def perform_mailer(mailer, method, args = nil)
|
563
|
-
perform_sidekiq { perform_action_mailer(mailer, method, args) }
|
564
|
-
end
|
565
|
-
end
|
566
|
-
end
|