appsignal 2.11.0.alpha.1 → 2.11.0.alpha.2

Sign up to get free protection for your applications and to get access to all the features.
@@ -48,147 +48,225 @@ describe Appsignal::Hooks::SidekiqPlugin, :with_yaml_parse_error => false do
48
48
  expect(log_contents(log)).to_not contains_log(:warn, "Unable to load YAML")
49
49
  end
50
50
 
51
- shared_examples "sidekiq metadata" do
52
- describe "internal Sidekiq job values" do
53
- it "does not save internal Sidekiq values as metadata on transaction" do
54
- perform_job
51
+ shared_examples "unknown job action name" do
52
+ it "sets the action name to unknown" do
53
+ transaction_hash = transaction.to_h
54
+ expect(transaction_hash).to include("action" => "unknown")
55
+ end
55
56
 
56
- transaction_hash = transaction.to_h
57
- expect(transaction_hash["metadata"].keys)
58
- .to_not include(*Appsignal::Hooks::SidekiqPlugin::JOB_KEYS)
59
- end
57
+ it "stores no sample data" do
58
+ transaction_hash = transaction.to_h
59
+ expect(transaction_hash).to include(
60
+ "sample_data" => {
61
+ "environment" => {},
62
+ "params" => [],
63
+ "tags" => {}
64
+ }
65
+ )
60
66
  end
61
67
 
62
- context "with parameter filtering" do
63
- before do
64
- Appsignal.config = project_fixture_config("production")
65
- Appsignal.config[:filter_parameters] = ["foo"]
66
- end
68
+ it "logs a debug message" do
69
+ expect(log_contents(log)).to contains_log(
70
+ :debug, "Unable to determine an action name from Sidekiq payload: #{item}"
71
+ )
72
+ end
73
+ end
67
74
 
68
- it "filters selected arguments" do
69
- perform_job
75
+ describe "internal Sidekiq job values" do
76
+ it "does not save internal Sidekiq values as metadata on transaction" do
77
+ perform_job
70
78
 
71
- transaction_hash = transaction.to_h
72
- expect(transaction_hash["sample_data"]).to include(
73
- "params" => [
74
- "foo",
75
- {
76
- "foo" => "[FILTERED]",
77
- "bar" => "Bar",
78
- "baz" => { "1" => "foo" }
79
- }
80
- ]
81
- )
82
- end
79
+ transaction_hash = transaction.to_h
80
+ expect(transaction_hash["metadata"].keys)
81
+ .to_not include(*Appsignal::Hooks::SidekiqPlugin::JOB_KEYS)
83
82
  end
83
+ end
84
84
 
85
- context "with encrypted arguments" do
86
- before do
87
- item["encrypt"] = true
88
- item["args"] << "super secret value" # Last argument will be replaced
89
- end
85
+ context "with parameter filtering" do
86
+ before do
87
+ Appsignal.config = project_fixture_config("production")
88
+ Appsignal.config[:filter_parameters] = ["foo"]
89
+ end
90
90
 
91
- it "replaces the last argument (the secret bag) with an [encrypted data] string" do
92
- perform_job
91
+ it "filters selected arguments" do
92
+ perform_job
93
93
 
94
- transaction_hash = transaction.to_h
95
- expect(transaction_hash["sample_data"]).to include(
96
- "params" => expected_args << "[encrypted data]"
97
- )
98
- end
94
+ transaction_hash = transaction.to_h
95
+ expect(transaction_hash["sample_data"]).to include(
96
+ "params" => [
97
+ "foo",
98
+ {
99
+ "foo" => "[FILTERED]",
100
+ "bar" => "Bar",
101
+ "baz" => { "1" => "foo" }
102
+ }
103
+ ]
104
+ )
99
105
  end
106
+ end
100
107
 
101
- context "when using the Sidekiq delayed extension" do
102
- let(:item) do
103
- {
104
- "jid" => "efb140489485999d32b5504c",
105
- "class" => "Sidekiq::Extensions::DelayedClass",
106
- "queue" => "default",
107
- "args" => [
108
- "---\n- !ruby/class 'DelayedTestClass'\n- :foo_method\n- - :bar: baz\n"
109
- ],
110
- "retry" => true,
111
- "created_at" => Time.parse("2001-01-01 10:00:00UTC").to_f,
112
- "enqueued_at" => Time.parse("2001-01-01 10:00:00UTC").to_f,
113
- "extra" => "data"
114
- }
115
- end
108
+ context "with encrypted arguments" do
109
+ before do
110
+ item["encrypt"] = true
111
+ item["args"] << "super secret value" # Last argument will be replaced
112
+ end
116
113
 
117
- it "uses the delayed class and method name for the action" do
114
+ it "replaces the last argument (the secret bag) with an [encrypted data] string" do
115
+ perform_job
116
+
117
+ transaction_hash = transaction.to_h
118
+ expect(transaction_hash["sample_data"]).to include(
119
+ "params" => expected_args << "[encrypted data]"
120
+ )
121
+ end
122
+ end
123
+
124
+ context "when using the Sidekiq delayed extension" do
125
+ let(:item) do
126
+ {
127
+ "jid" => "efb140489485999d32b5504c",
128
+ "class" => "Sidekiq::Extensions::DelayedClass",
129
+ "queue" => "default",
130
+ "args" => [
131
+ "---\n- !ruby/class 'DelayedTestClass'\n- :foo_method\n- - :bar: baz\n"
132
+ ],
133
+ "retry" => true,
134
+ "created_at" => Time.parse("2001-01-01 10:00:00UTC").to_f,
135
+ "enqueued_at" => Time.parse("2001-01-01 10:00:00UTC").to_f,
136
+ "extra" => "data"
137
+ }
138
+ end
139
+
140
+ it "uses the delayed class and method name for the action" do
141
+ perform_job
142
+
143
+ transaction_hash = transaction.to_h
144
+ expect(transaction_hash["action"]).to eq("DelayedTestClass.foo_method")
145
+ expect(transaction_hash["sample_data"]).to include(
146
+ "params" => ["bar" => "baz"]
147
+ )
148
+ end
149
+
150
+ context "when job arguments is a malformed YAML object", :with_yaml_parse_error => true do
151
+ before { item["args"] = [] }
152
+
153
+ it "logs a warning and uses the default argument" do
118
154
  perform_job
119
155
 
120
156
  transaction_hash = transaction.to_h
121
- expect(transaction_hash["action"]).to eq("DelayedTestClass.foo_method")
122
- expect(transaction_hash["sample_data"]).to include(
123
- "params" => ["bar" => "baz"]
124
- )
157
+ expect(transaction_hash["action"]).to eq("Sidekiq::Extensions::DelayedClass#perform")
158
+ expect(transaction_hash["sample_data"]).to include("params" => [])
159
+ expect(log_contents(log)).to contains_log(:warn, "Unable to load YAML")
125
160
  end
161
+ end
162
+ end
126
163
 
127
- context "when job arguments is a malformed YAML object", :with_yaml_parse_error => true do
128
- before { item["args"] = [] }
164
+ context "when using the Sidekiq ActiveRecord instance delayed extension" do
165
+ let(:item) do
166
+ {
167
+ "jid" => "efb140489485999d32b5504c",
168
+ "class" => "Sidekiq::Extensions::DelayedModel",
169
+ "queue" => "default",
170
+ "args" => [
171
+ "---\n- !ruby/object:DelayedTestClass {}\n- :foo_method\n- - :bar: :baz\n"
172
+ ],
173
+ "retry" => true,
174
+ "created_at" => Time.parse("2001-01-01 10:00:00UTC").to_f,
175
+ "enqueued_at" => Time.parse("2001-01-01 10:00:00UTC").to_f,
176
+ "extra" => "data"
177
+ }
178
+ end
129
179
 
130
- it "logs a warning and uses the default argument" do
131
- perform_job
180
+ it "uses the delayed class and method name for the action" do
181
+ perform_job
132
182
 
133
- transaction_hash = transaction.to_h
134
- expect(transaction_hash["action"]).to eq("Sidekiq::Extensions::DelayedClass#perform")
135
- expect(transaction_hash["sample_data"]).to include("params" => [])
136
- expect(log_contents(log)).to contains_log(:warn, "Unable to load YAML")
137
- end
138
- end
183
+ transaction_hash = transaction.to_h
184
+ expect(transaction_hash["action"]).to eq("DelayedTestClass#foo_method")
185
+ expect(transaction_hash["sample_data"]).to include(
186
+ "params" => ["bar" => "baz"]
187
+ )
139
188
  end
140
189
 
141
- context "when using the Sidekiq ActiveRecord instance delayed extension" do
142
- let(:item) do
143
- {
144
- "jid" => "efb140489485999d32b5504c",
145
- "class" => "Sidekiq::Extensions::DelayedModel",
146
- "queue" => "default",
147
- "args" => [
148
- "---\n- !ruby/object:DelayedTestClass {}\n- :foo_method\n- - :bar: :baz\n"
149
- ],
150
- "retry" => true,
151
- "created_at" => Time.parse("2001-01-01 10:00:00UTC").to_f,
152
- "enqueued_at" => Time.parse("2001-01-01 10:00:00UTC").to_f,
153
- "extra" => "data"
154
- }
155
- end
190
+ context "when job arguments is a malformed YAML object", :with_yaml_parse_error => true do
191
+ before { item["args"] = [] }
156
192
 
157
- it "uses the delayed class and method name for the action" do
193
+ it "logs a warning and uses the default argument" do
158
194
  perform_job
159
195
 
160
196
  transaction_hash = transaction.to_h
161
- expect(transaction_hash["action"]).to eq("DelayedTestClass#foo_method")
162
- expect(transaction_hash["sample_data"]).to include(
163
- "params" => ["bar" => "baz"]
164
- )
197
+ expect(transaction_hash["action"]).to eq("Sidekiq::Extensions::DelayedModel#perform")
198
+ expect(transaction_hash["sample_data"]).to include("params" => [])
199
+ expect(log_contents(log)).to contains_log(:warn, "Unable to load YAML")
165
200
  end
201
+ end
202
+ end
166
203
 
167
- context "when job arguments is a malformed YAML object", :with_yaml_parse_error => true do
168
- before { item["args"] = [] }
204
+ context "when using ActiveJob" do
205
+ let(:item) do
206
+ {
207
+ "class" => "ActiveJob::QueueAdapters::SidekiqAdapter::JobWrapper",
208
+ "wrapped" => "ActiveJobTestClass",
209
+ "queue" => "default",
210
+ "args" => [{
211
+ "job_class" => "ActiveJobTestJob",
212
+ "job_id" => "23e79d48-6966-40d0-b2d4-f7938463a263",
213
+ "queue_name" => "default",
214
+ "arguments" => [
215
+ "foo", { "foo" => "Foo", "bar" => "Bar", "baz" => { 1 => :bar } }
216
+ ]
217
+ }],
218
+ "retry" => true,
219
+ "jid" => "efb140489485999d32b5504c",
220
+ "created_at" => Time.parse("2001-01-01 10:00:00UTC").to_f,
221
+ "enqueued_at" => Time.parse("2001-01-01 10:00:00UTC").to_f
222
+ }
223
+ end
169
224
 
170
- it "logs a warning and uses the default argument" do
171
- perform_job
225
+ it "creates a transaction with events" do
226
+ perform_job
172
227
 
173
- transaction_hash = transaction.to_h
174
- expect(transaction_hash["action"]).to eq("Sidekiq::Extensions::DelayedModel#perform")
175
- expect(transaction_hash["sample_data"]).to include("params" => [])
176
- expect(log_contents(log)).to contains_log(:warn, "Unable to load YAML")
177
- end
178
- end
228
+ transaction_hash = transaction.to_h
229
+ expect(transaction_hash).to include(
230
+ "id" => kind_of(String),
231
+ "action" => "ActiveJobTestClass#perform",
232
+ "error" => nil,
233
+ "namespace" => namespace,
234
+ "metadata" => {
235
+ "queue" => "default"
236
+ },
237
+ "sample_data" => {
238
+ "environment" => {},
239
+ "params" => [
240
+ "foo",
241
+ {
242
+ "foo" => "Foo",
243
+ "bar" => "Bar",
244
+ "baz" => { "1" => "bar" }
245
+ }
246
+ ],
247
+ "tags" => {}
248
+ }
249
+ )
250
+ # TODO: Not available in transaction.to_h yet.
251
+ # https://github.com/appsignal/appsignal-agent/issues/293
252
+ expect(transaction.request.env).to eq(
253
+ :queue_start => Time.parse("2001-01-01 10:00:00UTC").to_f
254
+ )
255
+ expect_transaction_to_have_sidekiq_event(transaction_hash)
179
256
  end
180
257
 
181
- context "when using ActiveJob" do
258
+ context "with ActionMailer job" do
182
259
  let(:item) do
183
260
  {
184
261
  "class" => "ActiveJob::QueueAdapters::SidekiqAdapter::JobWrapper",
185
- "wrapped" => "ActiveJobTestClass",
262
+ "wrapped" => "ActionMailer::DeliveryJob",
186
263
  "queue" => "default",
187
264
  "args" => [{
188
- "job_class" => "ActiveJobTestJob",
265
+ "job_class" => "ActiveMailerTestJob",
189
266
  "job_id" => "23e79d48-6966-40d0-b2d4-f7938463a263",
190
267
  "queue_name" => "default",
191
268
  "arguments" => [
269
+ "MailerClass", "mailer_method", "deliver_now",
192
270
  "foo", { "foo" => "Foo", "bar" => "Bar", "baz" => { 1 => :bar } }
193
271
  ]
194
272
  }],
@@ -199,13 +277,13 @@ describe Appsignal::Hooks::SidekiqPlugin, :with_yaml_parse_error => false do
199
277
  }
200
278
  end
201
279
 
202
- it "creates a transaction with events" do
280
+ it "creates a transaction for the ActionMailer class" do
203
281
  perform_job
204
282
 
205
283
  transaction_hash = transaction.to_h
206
284
  expect(transaction_hash).to include(
207
285
  "id" => kind_of(String),
208
- "action" => "ActiveJobTestClass#perform",
286
+ "action" => "MailerClass#mailer_method",
209
287
  "error" => nil,
210
288
  "namespace" => namespace,
211
289
  "metadata" => {
@@ -224,43 +302,87 @@ describe Appsignal::Hooks::SidekiqPlugin, :with_yaml_parse_error => false do
224
302
  "tags" => {}
225
303
  }
226
304
  )
227
- # TODO: Not available in transaction.to_h yet.
228
- # https://github.com/appsignal/appsignal-agent/issues/293
229
- expect(transaction.request.env).to eq(
230
- :queue_start => Time.parse("2001-01-01 10:00:00UTC").to_f
305
+ end
306
+ end
307
+
308
+ context "with parameter filtering" do
309
+ before do
310
+ Appsignal.config = project_fixture_config("production")
311
+ Appsignal.config[:filter_parameters] = ["foo"]
312
+ end
313
+
314
+ it "filters selected arguments" do
315
+ perform_job
316
+
317
+ transaction_hash = transaction.to_h
318
+ expect(transaction_hash["sample_data"]).to include(
319
+ "params" => [
320
+ "foo",
321
+ {
322
+ "foo" => "[FILTERED]",
323
+ "bar" => "Bar",
324
+ "baz" => { "1" => "bar" }
325
+ }
326
+ ]
231
327
  )
232
- expect_transaction_to_have_sidekiq_event(transaction_hash)
233
328
  end
329
+ end
234
330
 
235
- context "with ActionMailer job" do
236
- let(:item) do
331
+ context "when Sidekiq job payload is missing the 'wrapped' value" do
332
+ let(:item) do
333
+ {
334
+ "class" => "ActiveJob::QueueAdapters::SidekiqAdapter::JobWrapper",
335
+ "queue" => "default",
336
+ "args" => [first_argument],
337
+ "retry" => true,
338
+ "jid" => "efb140489485999d32b5504c",
339
+ "created_at" => Time.parse("2001-01-01 10:00:00UTC").to_f,
340
+ "enqueued_at" => Time.parse("2001-01-01 10:00:00UTC").to_f
341
+ }
342
+ end
343
+ before { perform_job }
344
+
345
+ context "when the first argument is not a Hash object" do
346
+ let(:first_argument) { "foo" }
347
+
348
+ include_examples "unknown job action name"
349
+ end
350
+
351
+ context "when the first argument is a Hash object not containing a job payload" do
352
+ let(:first_argument) { { "foo" => "bar" } }
353
+
354
+ include_examples "unknown job action name"
355
+
356
+ context "when the argument contains an invalid job_class value" do
357
+ let(:first_argument) { { "job_class" => :foo } }
358
+
359
+ include_examples "unknown job action name"
360
+ end
361
+ end
362
+
363
+ context "when the first argument is a Hash object containing a job payload" do
364
+ let(:first_argument) do
237
365
  {
238
- "class" => "ActiveJob::QueueAdapters::SidekiqAdapter::JobWrapper",
239
- "wrapped" => "ActionMailer::DeliveryJob",
240
- "queue" => "default",
241
- "args" => [{
242
- "job_class" => "ActiveMailerTestJob",
243
- "job_id" => "23e79d48-6966-40d0-b2d4-f7938463a263",
244
- "queue_name" => "default",
245
- "arguments" => [
246
- "MailerClass", "mailer_method", "deliver_now",
247
- "foo", { "foo" => "Foo", "bar" => "Bar", "baz" => { 1 => :bar } }
248
- ]
249
- }],
250
- "retry" => true,
251
- "jid" => "efb140489485999d32b5504c",
252
- "created_at" => Time.parse("2001-01-01 10:00:00UTC").to_f,
253
- "enqueued_at" => Time.parse("2001-01-01 10:00:00UTC").to_f
366
+ "job_class" => "ActiveMailerTestJob",
367
+ "job_id" => "23e79d48-6966-40d0-b2d4-f7938463a263",
368
+ "queue_name" => "default",
369
+ "arguments" => [
370
+ "foo", { "foo" => "Foo", "bar" => "Bar", "baz" => { 1 => :bar } }
371
+ ]
254
372
  }
255
373
  end
256
374
 
257
- it "creates a transaction for the ActionMailer class" do
258
- perform_job
375
+ it "sets the action name to the job class in the first argument" do
376
+ transaction_hash = transaction.to_h
377
+ expect(transaction_hash).to include(
378
+ "action" => "ActiveMailerTestJob#perform"
379
+ )
380
+ end
259
381
 
382
+ it "stores the job metadata on the transaction" do
260
383
  transaction_hash = transaction.to_h
261
384
  expect(transaction_hash).to include(
262
385
  "id" => kind_of(String),
263
- "action" => "MailerClass#mailer_method",
264
386
  "error" => nil,
265
387
  "namespace" => namespace,
266
388
  "metadata" => {
@@ -280,137 +402,13 @@ describe Appsignal::Hooks::SidekiqPlugin, :with_yaml_parse_error => false do
280
402
  }
281
403
  )
282
404
  end
283
- end
284
-
285
- context "with parameter filtering" do
286
- before do
287
- Appsignal.config = project_fixture_config("production")
288
- Appsignal.config[:filter_parameters] = ["foo"]
289
- end
290
-
291
- it "filters selected arguments" do
292
- perform_job
293
405
 
294
- transaction_hash = transaction.to_h
295
- expect(transaction_hash["sample_data"]).to include(
296
- "params" => [
297
- "foo",
298
- {
299
- "foo" => "[FILTERED]",
300
- "bar" => "Bar",
301
- "baz" => { "1" => "bar" }
302
- }
303
- ]
406
+ it "does not log a debug message" do
407
+ expect(log_contents(log)).to_not contains_log(
408
+ :debug, "Unable to determine an action name from Sidekiq payload"
304
409
  )
305
410
  end
306
411
  end
307
-
308
- context "when Sidekiq job payload is missing the 'wrapped' value" do
309
- let(:item) do
310
- {
311
- "class" => "ActiveJob::QueueAdapters::SidekiqAdapter::JobWrapper",
312
- "queue" => "default",
313
- "args" => [first_argument],
314
- "retry" => true,
315
- "jid" => "efb140489485999d32b5504c",
316
- "created_at" => Time.parse("2001-01-01 10:00:00UTC").to_f,
317
- "enqueued_at" => Time.parse("2001-01-01 10:00:00UTC").to_f
318
- }
319
- end
320
- before { perform_job }
321
-
322
- context "when the first argument is not a Hash object" do
323
- let(:first_argument) { "foo" }
324
-
325
- include_examples "unknown job action name"
326
- end
327
-
328
- context "when the first argument is a Hash object not containing a job payload" do
329
- let(:first_argument) { { "foo" => "bar" } }
330
-
331
- include_examples "unknown job action name"
332
-
333
- context "when the argument contains an invalid job_class value" do
334
- let(:first_argument) { { "job_class" => :foo } }
335
-
336
- include_examples "unknown job action name"
337
- end
338
- end
339
-
340
- context "when the first argument is a Hash object containing a job payload" do
341
- let(:first_argument) do
342
- {
343
- "job_class" => "ActiveMailerTestJob",
344
- "job_id" => "23e79d48-6966-40d0-b2d4-f7938463a263",
345
- "queue_name" => "default",
346
- "arguments" => [
347
- "foo", { "foo" => "Foo", "bar" => "Bar", "baz" => { 1 => :bar } }
348
- ]
349
- }
350
- end
351
-
352
- it "sets the action name to the job class in the first argument" do
353
- transaction_hash = transaction.to_h
354
- expect(transaction_hash).to include(
355
- "action" => "ActiveMailerTestJob#perform"
356
- )
357
- end
358
-
359
- it "stores the job metadata on the transaction" do
360
- transaction_hash = transaction.to_h
361
- expect(transaction_hash).to include(
362
- "id" => kind_of(String),
363
- "error" => nil,
364
- "namespace" => namespace,
365
- "metadata" => {
366
- "queue" => "default"
367
- },
368
- "sample_data" => {
369
- "environment" => {},
370
- "params" => [
371
- "foo",
372
- {
373
- "foo" => "Foo",
374
- "bar" => "Bar",
375
- "baz" => { "1" => "bar" }
376
- }
377
- ],
378
- "tags" => {}
379
- }
380
- )
381
- end
382
-
383
- it "does not log a debug message" do
384
- expect(log_contents(log)).to_not contains_log(
385
- :debug, "Unable to determine an action name from Sidekiq payload"
386
- )
387
- end
388
- end
389
- end
390
- end
391
- end
392
-
393
- shared_examples "unknown job action name" do
394
- it "sets the action name to unknown" do
395
- transaction_hash = transaction.to_h
396
- expect(transaction_hash).to include("action" => "unknown")
397
- end
398
-
399
- it "stores no sample data" do
400
- transaction_hash = transaction.to_h
401
- expect(transaction_hash).to include(
402
- "sample_data" => {
403
- "environment" => {},
404
- "params" => [],
405
- "tags" => {}
406
- }
407
- )
408
- end
409
-
410
- it "logs a debug message" do
411
- expect(log_contents(log)).to contains_log(
412
- :debug, "Unable to determine an action name from Sidekiq payload: #{item}"
413
- )
414
412
  end
415
413
  end
416
414
 
@@ -452,8 +450,6 @@ describe Appsignal::Hooks::SidekiqPlugin, :with_yaml_parse_error => false do
452
450
  )
453
451
  expect_transaction_to_have_sidekiq_event(transaction_hash)
454
452
  end
455
-
456
- include_examples "sidekiq metadata"
457
453
  end
458
454
 
459
455
  context "without an error" do
@@ -487,8 +483,6 @@ describe Appsignal::Hooks::SidekiqPlugin, :with_yaml_parse_error => false do
487
483
  )
488
484
  expect_transaction_to_have_sidekiq_event(transaction_hash)
489
485
  end
490
-
491
- include_examples "sidekiq metadata"
492
486
  end
493
487
 
494
488
  def perform_job
@@ -537,7 +531,7 @@ describe Appsignal::Hooks::SidekiqHook do
537
531
  describe "#install" do
538
532
  before do
539
533
  Appsignal.config = project_fixture_config
540
- class Sidekiq
534
+ module Sidekiq
541
535
  def self.middlewares
542
536
  @middlewares ||= Set.new
543
537
  end
@@ -560,203 +554,3 @@ describe Appsignal::Hooks::SidekiqHook do
560
554
  end
561
555
  end
562
556
  end
563
-
564
- describe Appsignal::Hooks::SidekiqProbe do
565
- describe "#call" do
566
- let(:probe) { described_class.new }
567
- let(:redis_hostname) { "localhost" }
568
- let(:expected_default_tags) { { :hostname => "localhost" } }
569
- before do
570
- Appsignal.config = project_fixture_config
571
- class Sidekiq
572
- def self.redis_info
573
- {
574
- "connected_clients" => 2,
575
- "used_memory" => 1024,
576
- "used_memory_rss" => 512
577
- }
578
- end
579
-
580
- def self.redis
581
- yield Client.new
582
- end
583
-
584
- class Client
585
- def connection
586
- { :host => "localhost" }
587
- end
588
- end
589
-
590
- class Stats
591
- class << self
592
- attr_reader :calls
593
-
594
- def count_call
595
- @calls ||= -1
596
- @calls += 1
597
- end
598
- end
599
-
600
- def workers_size
601
- # First method called, so count it towards a call
602
- self.class.count_call
603
- 24
604
- end
605
-
606
- def processes_size
607
- 25
608
- end
609
-
610
- # Return two different values for two separate calls.
611
- # This allows us to test the delta of the value send as a gauge.
612
- def processed
613
- [10, 15][self.class.calls]
614
- end
615
-
616
- # Return two different values for two separate calls.
617
- # This allows us to test the delta of the value send as a gauge.
618
- def failed
619
- [10, 13][self.class.calls]
620
- end
621
-
622
- def retry_size
623
- 12
624
- end
625
-
626
- # Return two different values for two separate calls.
627
- # This allows us to test the delta of the value send as a gauge.
628
- def dead_size
629
- [10, 12][self.class.calls]
630
- end
631
-
632
- def scheduled_size
633
- 14
634
- end
635
-
636
- def enqueued
637
- 15
638
- end
639
- end
640
-
641
- class Queue
642
- Queue = Struct.new(:name, :size, :latency)
643
-
644
- def self.all
645
- [
646
- Queue.new("default", 10, 12),
647
- Queue.new("critical", 1, 2)
648
- ]
649
- end
650
- end
651
- end
652
- end
653
- after { Object.send(:remove_const, "Sidekiq") }
654
-
655
- describe ".dependencies_present?" do
656
- before do
657
- class Redis; end
658
- Redis.const_set(:VERSION, version)
659
- end
660
- after { Object.send(:remove_const, "Redis") }
661
-
662
- context "when Redis version is < 3.3.5" do
663
- let(:version) { "3.3.4" }
664
-
665
- it "does not start probe" do
666
- expect(described_class.dependencies_present?).to be_falsy
667
- end
668
- end
669
-
670
- context "when Redis version is >= 3.3.5" do
671
- let(:version) { "3.3.5" }
672
-
673
- it "does not start probe" do
674
- expect(described_class.dependencies_present?).to be_truthy
675
- end
676
- end
677
- end
678
-
679
- it "loads Sidekiq::API" do
680
- expect(defined?(Sidekiq::API)).to be_falsy
681
- probe
682
- expect(defined?(Sidekiq::API)).to be_truthy
683
- end
684
-
685
- it "logs config on initialize" do
686
- log = capture_logs { probe }
687
- expect(log).to contains_log(:debug, "Initializing Sidekiq probe\n")
688
- end
689
-
690
- it "logs used hostname on call once" do
691
- log = capture_logs { probe.call }
692
- expect(log).to contains_log(
693
- :debug,
694
- %(Sidekiq probe: Using Redis server hostname "localhost" as hostname)
695
- )
696
- log = capture_logs { probe.call }
697
- # Match more logs with incompelete message
698
- expect(log).to_not contains_log(:debug, %(Sidekiq probe: ))
699
- end
700
-
701
- it "collects custom metrics" do
702
- expect_gauge("worker_count", 24).twice
703
- expect_gauge("process_count", 25).twice
704
- expect_gauge("connection_count", 2).twice
705
- expect_gauge("memory_usage", 1024).twice
706
- expect_gauge("memory_usage_rss", 512).twice
707
- expect_gauge("job_count", 5, :status => :processed) # Gauge delta
708
- expect_gauge("job_count", 3, :status => :failed) # Gauge delta
709
- expect_gauge("job_count", 12, :status => :retry_queue).twice
710
- expect_gauge("job_count", 2, :status => :died) # Gauge delta
711
- expect_gauge("job_count", 14, :status => :scheduled).twice
712
- expect_gauge("job_count", 15, :status => :enqueued).twice
713
- expect_gauge("queue_length", 10, :queue => "default").twice
714
- expect_gauge("queue_latency", 12_000, :queue => "default").twice
715
- expect_gauge("queue_length", 1, :queue => "critical").twice
716
- expect_gauge("queue_latency", 2_000, :queue => "critical").twice
717
- # Call probe twice so we can calculate the delta for some gauge values
718
- probe.call
719
- probe.call
720
- end
721
-
722
- context "when `redis_info` is not defined" do
723
- before do
724
- allow(Sidekiq).to receive(:respond_to?).with(:redis_info).and_return(false)
725
- end
726
-
727
- it "does not collect redis metrics" do
728
- expect_gauge("connection_count", 2).never
729
- expect_gauge("memory_usage", 1024).never
730
- expect_gauge("memory_usage_rss", 512).never
731
- probe.call
732
- end
733
- end
734
-
735
- context "when hostname is configured for probe" do
736
- let(:redis_hostname) { "my_redis_server" }
737
- let(:probe) { described_class.new(:hostname => redis_hostname) }
738
-
739
- it "uses the redis hostname for the hostname tag" do
740
- allow(Appsignal).to receive(:set_gauge).and_call_original
741
- log = capture_logs { probe }
742
- expect(log).to contains_log(
743
- :debug,
744
- %(Initializing Sidekiq probe with config: {:hostname=>"#{redis_hostname}"})
745
- )
746
- log = capture_logs { probe.call }
747
- expect(log).to contains_log(
748
- :debug,
749
- "Sidekiq probe: Using hostname config option #{redis_hostname.inspect} as hostname"
750
- )
751
- expect(Appsignal).to have_received(:set_gauge)
752
- .with(anything, anything, :hostname => redis_hostname).at_least(:once)
753
- end
754
- end
755
-
756
- def expect_gauge(key, value, tags = {})
757
- expect(Appsignal).to receive(:set_gauge)
758
- .with("sidekiq_#{key}", value, expected_default_tags.merge(tags))
759
- .and_call_original
760
- end
761
- end
762
- end