appsignal 3.9.2 → 3.9.3

Sign up to get free protection for your applications and to get access to all the features.
Files changed (89) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/ci.yml +3135 -0
  3. data/.rubocop.yml +28 -20
  4. data/.rubocop_todo.yml +7 -33
  5. data/CHANGELOG.md +38 -0
  6. data/Rakefile +79 -64
  7. data/appsignal.gemspec +1 -1
  8. data/build_matrix.yml +109 -179
  9. data/ext/base.rb +1 -1
  10. data/gemfiles/hanami-2.1.gemfile +7 -0
  11. data/lib/appsignal/cli/diagnose.rb +1 -1
  12. data/lib/appsignal/config.rb +1 -1
  13. data/lib/appsignal/demo.rb +0 -1
  14. data/lib/appsignal/environment.rb +5 -1
  15. data/lib/appsignal/extension/jruby.rb +1 -1
  16. data/lib/appsignal/helpers/instrumentation.rb +1 -1
  17. data/lib/appsignal/integrations/grape.rb +19 -47
  18. data/lib/appsignal/integrations/hanami.rb +8 -7
  19. data/lib/appsignal/integrations/padrino.rb +46 -43
  20. data/lib/appsignal/integrations/railtie.rb +0 -3
  21. data/lib/appsignal/integrations/sinatra.rb +0 -1
  22. data/lib/appsignal/probes/gvl.rb +24 -2
  23. data/lib/appsignal/probes/sidekiq.rb +1 -1
  24. data/lib/appsignal/probes.rb +1 -1
  25. data/lib/appsignal/rack/abstract_middleware.rb +62 -28
  26. data/lib/appsignal/rack/event_handler.rb +12 -3
  27. data/lib/appsignal/rack/grape_middleware.rb +40 -0
  28. data/lib/appsignal/rack/hanami_middleware.rb +1 -11
  29. data/lib/appsignal/rack/rails_instrumentation.rb +14 -55
  30. data/lib/appsignal/utils/integration_memory_logger.rb +78 -0
  31. data/lib/appsignal/utils.rb +1 -0
  32. data/lib/appsignal/version.rb +1 -1
  33. data/lib/appsignal.rb +34 -33
  34. data/spec/.rubocop.yml +1 -1
  35. data/spec/lib/appsignal/cli/diagnose_spec.rb +1 -1
  36. data/spec/lib/appsignal/cli/install_spec.rb +3 -3
  37. data/spec/lib/appsignal/config_spec.rb +7 -5
  38. data/spec/lib/appsignal/demo_spec.rb +38 -41
  39. data/spec/lib/appsignal/hooks/action_cable_spec.rb +86 -167
  40. data/spec/lib/appsignal/hooks/active_support_notifications/finish_with_state_shared_examples.rb +8 -20
  41. data/spec/lib/appsignal/hooks/active_support_notifications/instrument_shared_examples.rb +38 -84
  42. data/spec/lib/appsignal/hooks/active_support_notifications/start_finish_shared_examples.rb +16 -37
  43. data/spec/lib/appsignal/hooks/active_support_notifications_spec.rb +4 -4
  44. data/spec/lib/appsignal/hooks/activejob_spec.rb +111 -200
  45. data/spec/lib/appsignal/hooks/delayed_job_spec.rb +54 -91
  46. data/spec/lib/appsignal/hooks/dry_monitor_spec.rb +14 -32
  47. data/spec/lib/appsignal/hooks/excon_spec.rb +8 -12
  48. data/spec/lib/appsignal/hooks/net_http_spec.rb +7 -42
  49. data/spec/lib/appsignal/hooks/rake_spec.rb +9 -19
  50. data/spec/lib/appsignal/hooks/redis_client_spec.rb +18 -30
  51. data/spec/lib/appsignal/hooks/redis_spec.rb +10 -16
  52. data/spec/lib/appsignal/hooks/resque_spec.rb +42 -62
  53. data/spec/lib/appsignal/hooks/shoryuken_spec.rb +33 -74
  54. data/spec/lib/appsignal/integrations/hanami_spec.rb +79 -21
  55. data/spec/lib/appsignal/integrations/http_spec.rb +12 -20
  56. data/spec/lib/appsignal/integrations/net_http_spec.rb +33 -0
  57. data/spec/lib/appsignal/integrations/object_spec.rb +29 -36
  58. data/spec/lib/appsignal/integrations/padrino_spec.rb +47 -70
  59. data/spec/lib/appsignal/integrations/que_spec.rb +43 -70
  60. data/spec/lib/appsignal/integrations/railtie_spec.rb +26 -67
  61. data/spec/lib/appsignal/integrations/sidekiq_spec.rb +86 -160
  62. data/spec/lib/appsignal/integrations/sinatra_spec.rb +0 -1
  63. data/spec/lib/appsignal/integrations/webmachine_spec.rb +28 -39
  64. data/spec/lib/appsignal/probes/gvl_spec.rb +80 -3
  65. data/spec/lib/appsignal/probes_spec.rb +7 -4
  66. data/spec/lib/appsignal/rack/abstract_middleware_spec.rb +215 -106
  67. data/spec/lib/appsignal/rack/event_handler_spec.rb +81 -78
  68. data/spec/lib/appsignal/rack/generic_instrumentation_spec.rb +2 -12
  69. data/spec/lib/appsignal/rack/grape_middleware_spec.rb +234 -0
  70. data/spec/lib/appsignal/rack/hanami_middleware_spec.rb +2 -16
  71. data/spec/lib/appsignal/rack/rails_instrumentation_spec.rb +67 -131
  72. data/spec/lib/appsignal/rack/sinatra_instrumentation_spec.rb +36 -44
  73. data/spec/lib/appsignal/rack/streaming_listener_spec.rb +68 -86
  74. data/spec/lib/appsignal/transaction_spec.rb +76 -90
  75. data/spec/lib/appsignal/utils/integration_memory_logger_spec.rb +163 -0
  76. data/spec/lib/appsignal_spec.rb +363 -342
  77. data/spec/support/helpers/dependency_helper.rb +6 -1
  78. data/spec/support/helpers/std_streams_helper.rb +1 -1
  79. data/spec/support/helpers/transaction_helpers.rb +8 -0
  80. data/spec/support/matchers/transaction.rb +185 -0
  81. data/spec/support/mocks/dummy_app.rb +20 -0
  82. data/spec/support/shared_examples/instrument.rb +17 -12
  83. data/spec/support/testing.rb +18 -9
  84. metadata +15 -10
  85. data/.semaphore/semaphore.yml +0 -2347
  86. data/script/lint_git +0 -22
  87. data/spec/lib/appsignal/integrations/grape_spec.rb +0 -239
  88. data/spec/support/matchers/be_completed.rb +0 -5
  89. /data/gemfiles/{hanami.gemfile → hanami-2.0.gemfile} +0 -0
@@ -136,8 +136,8 @@ if DependencyHelper.rails_present?
136
136
  it "does nothing" do
137
137
  with_rails_error_reporter do
138
138
  expect do
139
- Rails.error.record { raise ExampleStandardError }
140
- end.to raise_error(ExampleStandardError)
139
+ Rails.error.record { raise ExampleStandardError, "error message" }
140
+ end.to raise_error(ExampleStandardError, "error message")
141
141
  end
142
142
 
143
143
  expect(created_transactions).to be_empty
@@ -156,24 +156,15 @@ if DependencyHelper.rails_present?
156
156
 
157
157
  with_rails_error_reporter do
158
158
  with_current_transaction current_transaction do
159
- Rails.error.handle { raise ExampleStandardError }
159
+ Rails.error.handle { raise ExampleStandardError, "error message" }
160
160
 
161
161
  transaction = last_transaction
162
- transaction_hash = transaction.to_h
163
- expect(transaction_hash).to include(
164
- "action" => "CustomAction",
165
- "namespace" => "custom",
166
- "error" => {
167
- "name" => "ExampleStandardError",
168
- "message" => "ExampleStandardError",
169
- "backtrace" => kind_of(String)
170
- },
171
- "sample_data" => hash_including(
172
- "tags" => hash_including(
173
- "duplicated_tag" => "duplicated value",
174
- "severity" => "warning"
175
- )
176
- )
162
+ expect(transaction).to have_namespace("custom")
163
+ expect(transaction).to have_action("CustomAction")
164
+ expect(transaction).to have_error("ExampleStandardError", "error message")
165
+ expect(transaction).to include_tags(
166
+ "duplicated_tag" => "duplicated value",
167
+ "severity" => "warning"
177
168
  )
178
169
  end
179
170
  end
@@ -188,16 +179,10 @@ if DependencyHelper.rails_present?
188
179
  given_context = { :tag1 => "value1", :tag2 => "value2" }
189
180
  Rails.error.handle(:context => given_context) { raise ExampleStandardError }
190
181
 
191
- transaction = last_transaction
192
- transaction_hash = transaction.to_h
193
- expect(transaction_hash).to include(
194
- "sample_data" => hash_including(
195
- "tags" => hash_including(
196
- "tag1" => "value1",
197
- "tag2" => "value2",
198
- "severity" => "warning"
199
- )
200
- )
182
+ expect(last_transaction).to include_tags(
183
+ "tag1" => "value1",
184
+ "tag2" => "value2",
185
+ "severity" => "warning"
201
186
  )
202
187
  end
203
188
  end
@@ -219,14 +204,9 @@ if DependencyHelper.rails_present?
219
204
  Rails.error.handle(:context => given_context) { raise ExampleStandardError }
220
205
 
221
206
  transaction = last_transaction
222
- transaction_hash = transaction.to_h
223
- expect(transaction_hash).to include(
224
- "sample_data" => hash_including(
225
- "custom_data" => {
226
- "array" => [1, 2],
227
- "hash" => { "one" => 1, "two" => 2 }
228
- }
229
- )
207
+ expect(transaction).to include_custom_data(
208
+ "array" => [1, 2],
209
+ "hash" => { "one" => 1, "two" => 2 }
230
210
  )
231
211
  end
232
212
  end
@@ -245,11 +225,8 @@ if DependencyHelper.rails_present?
245
225
  Rails.error.handle(:context => given_context) { raise ExampleStandardError }
246
226
 
247
227
  transaction = last_transaction
248
- transaction_hash = transaction.to_h
249
- expect(transaction_hash).to include(
250
- "namespace" => "context",
251
- "action" => "ContextAction"
252
- )
228
+ expect(transaction).to have_namespace("context")
229
+ expect(transaction).to have_action("ContextAction")
253
230
  end
254
231
  end
255
232
  end
@@ -301,17 +278,9 @@ if DependencyHelper.rails_present?
301
278
  end
302
279
 
303
280
  transaction = last_transaction
304
- transaction_hash = transaction.to_h
305
- expect(transaction_hash).to include(
306
- "action" => "ExampleRailsControllerMock#index",
307
- "metadata" => hash_including(
308
- "path" => "path",
309
- "method" => "GET"
310
- ),
311
- "sample_data" => hash_including(
312
- "params" => { "user_id" => 123, "password" => "[FILTERED]" }
313
- )
314
- )
281
+ expect(transaction).to have_action("ExampleRailsControllerMock#index")
282
+ expect(transaction).to include_metadata("path" => "path", "method" => "GET")
283
+ expect(transaction).to include_params("user_id" => 123, "password" => "[FILTERED]")
315
284
  end
316
285
 
317
286
  it "sets no action if no execution context is present" do
@@ -320,11 +289,7 @@ if DependencyHelper.rails_present?
320
289
  Rails.error.handle { raise ExampleStandardError }
321
290
  end
322
291
 
323
- transaction = last_transaction
324
- transaction_hash = transaction.to_h
325
- expect(transaction_hash).to include(
326
- "action" => nil
327
- )
292
+ expect(last_transaction).to_not have_action
328
293
  end
329
294
  end
330
295
 
@@ -340,16 +305,10 @@ if DependencyHelper.rails_present?
340
305
  Rails.error.handle(:context => given_context) { raise ExampleStandardError }
341
306
  end
342
307
 
343
- transaction = last_transaction
344
- transaction_hash = transaction.to_h
345
- expect(transaction_hash).to include(
346
- "sample_data" => hash_including(
347
- "tags" => hash_including(
348
- "tag1" => "value1",
349
- "tag2" => "value2",
350
- "severity" => "warning"
351
- )
352
- )
308
+ expect(last_transaction).to include_tags(
309
+ "tag1" => "value1",
310
+ "tag2" => "value2",
311
+ "severity" => "warning"
353
312
  )
354
313
  end
355
314
  end
@@ -20,17 +20,11 @@ describe Appsignal::Integrations::SidekiqDeathHandler do
20
20
  end
21
21
 
22
22
  def expect_error_on_transaction
23
- expect(last_transaction.to_h).to include(
24
- "error" => hash_including(
25
- "name" => "ExampleStandardError",
26
- "message" => "uh oh",
27
- "backtrace" => kind_of(String)
28
- )
29
- )
23
+ expect(last_transaction).to have_error("ExampleStandardError", "uh oh")
30
24
  end
31
25
 
32
26
  def expect_no_error_on_transaction
33
- expect(last_transaction.to_h).to include("error" => nil)
27
+ expect(last_transaction).to_not have_error
34
28
  end
35
29
 
36
30
  context "when sidekiq_report_errors = none" do
@@ -90,21 +84,13 @@ describe Appsignal::Integrations::SidekiqErrorHandler do
90
84
  described_class.new.call(exception, job_context)
91
85
  end.to(change { created_transactions.count }.by(1))
92
86
 
93
- transaction_hash = last_transaction.to_h
94
- expect(transaction_hash).to include(
95
- "action" => "SidekiqInternal",
96
- "error" => hash_including(
97
- "name" => "ExampleStandardError",
98
- "message" => "uh oh",
99
- "backtrace" => kind_of(String)
100
- )
101
- )
102
- expect(transaction_hash["sample_data"]).to include(
103
- "params" => {
104
- "jobstr" => "{ bad json }"
105
- }
87
+ transaction = last_transaction
88
+ expect(transaction).to have_action("SidekiqInternal")
89
+ expect(transaction).to have_error("ExampleStandardError", "uh oh")
90
+ expect(transaction).to include_params(
91
+ "jobstr" => "{ bad json }"
106
92
  )
107
- expect(transaction_hash["metadata"]).to include(
93
+ expect(transaction).to include_metadata(
108
94
  "sidekiq_error" => "Sidekiq internal error!"
109
95
  )
110
96
  end
@@ -149,17 +135,11 @@ describe Appsignal::Integrations::SidekiqErrorHandler do
149
135
  end
150
136
 
151
137
  def expect_error_on_transaction
152
- expect(last_transaction.to_h).to include(
153
- "error" => hash_including(
154
- "name" => "ExampleStandardError",
155
- "message" => "uh oh",
156
- "backtrace" => kind_of(String)
157
- )
158
- )
138
+ expect(last_transaction).to have_error("ExampleStandardError", "uh oh")
159
139
  end
160
140
 
161
141
  def expect_no_error_on_transaction
162
- expect(last_transaction.to_h).to include("error" => nil)
142
+ expect(last_transaction).to_not have_error
163
143
  end
164
144
 
165
145
  context "when sidekiq_report_errors = none" do
@@ -270,9 +250,8 @@ describe Appsignal::Integrations::SidekiqMiddleware, :with_yaml_parse_error => f
270
250
  it "filters selected arguments" do
271
251
  perform_sidekiq_job
272
252
 
273
- transaction_hash = transaction.to_h
274
- expect(transaction_hash["sample_data"]).to include(
275
- "params" => [
253
+ expect(transaction).to include_params(
254
+ [
276
255
  "foo",
277
256
  {
278
257
  "foo" => "[FILTERED]",
@@ -293,10 +272,7 @@ describe Appsignal::Integrations::SidekiqMiddleware, :with_yaml_parse_error => f
293
272
  it "replaces the last argument (the secret bag) with an [encrypted data] string" do
294
273
  perform_sidekiq_job
295
274
 
296
- transaction_hash = transaction.to_h
297
- expect(transaction_hash["sample_data"]).to include(
298
- "params" => expected_args << "[encrypted data]"
299
- )
275
+ expect(transaction).to include_params(expected_args << "[encrypted data]")
300
276
  end
301
277
  end
302
278
 
@@ -319,11 +295,8 @@ describe Appsignal::Integrations::SidekiqMiddleware, :with_yaml_parse_error => f
319
295
  it "uses the delayed class and method name for the action" do
320
296
  perform_sidekiq_job
321
297
 
322
- transaction_hash = transaction.to_h
323
- expect(transaction_hash["action"]).to eq("DelayedTestClass.foo_method")
324
- expect(transaction_hash["sample_data"]).to include(
325
- "params" => ["bar" => "baz"]
326
- )
298
+ expect(transaction).to have_action("DelayedTestClass.foo_method")
299
+ expect(transaction).to include_params(["bar" => "baz"])
327
300
  end
328
301
 
329
302
  context "when job arguments is a malformed YAML object", :with_yaml_parse_error => true do
@@ -332,9 +305,8 @@ describe Appsignal::Integrations::SidekiqMiddleware, :with_yaml_parse_error => f
332
305
  it "logs a warning and uses the default argument" do
333
306
  perform_sidekiq_job
334
307
 
335
- transaction_hash = transaction.to_h
336
- expect(transaction_hash["action"]).to eq("Sidekiq::Extensions::DelayedClass#perform")
337
- expect(transaction_hash["sample_data"]).to include("params" => [])
308
+ expect(transaction).to have_action("Sidekiq::Extensions::DelayedClass#perform")
309
+ expect(transaction).to include_params([])
338
310
  expect(log_contents(log)).to contains_log(:warn, "Unable to load YAML")
339
311
  end
340
312
  end
@@ -359,11 +331,8 @@ describe Appsignal::Integrations::SidekiqMiddleware, :with_yaml_parse_error => f
359
331
  it "uses the delayed class and method name for the action" do
360
332
  perform_sidekiq_job
361
333
 
362
- transaction_hash = transaction.to_h
363
- expect(transaction_hash["action"]).to eq("DelayedTestClass#foo_method")
364
- expect(transaction_hash["sample_data"]).to include(
365
- "params" => ["bar" => "baz"]
366
- )
334
+ expect(transaction).to have_action("DelayedTestClass#foo_method")
335
+ expect(transaction).to include_params(["bar" => "baz"])
367
336
  end
368
337
 
369
338
  context "when job arguments is a malformed YAML object", :with_yaml_parse_error => true do
@@ -372,9 +341,8 @@ describe Appsignal::Integrations::SidekiqMiddleware, :with_yaml_parse_error => f
372
341
  it "logs a warning and uses the default argument" do
373
342
  perform_sidekiq_job
374
343
 
375
- transaction_hash = transaction.to_h
376
- expect(transaction_hash["action"]).to eq("Sidekiq::Extensions::DelayedModel#perform")
377
- expect(transaction_hash["sample_data"]).to include("params" => [])
344
+ expect(transaction).to have_action("Sidekiq::Extensions::DelayedModel#perform")
345
+ expect(transaction).to include_params([])
378
346
  expect(log_contents(log)).to contains_log(:warn, "Unable to load YAML")
379
347
  end
380
348
  end
@@ -394,31 +362,20 @@ describe Appsignal::Integrations::SidekiqMiddleware, :with_yaml_parse_error => f
394
362
  perform_sidekiq_job { raise error, "uh oh" }
395
363
  end.to raise_error(error)
396
364
 
397
- transaction_hash = transaction.to_h
398
- expect(transaction_hash).to include(
399
- "id" => jid,
400
- "action" => "TestClass#perform",
401
- "error" => {
402
- "name" => "ExampleException",
403
- "message" => "uh oh",
404
- # TODO: backtrace should be an Array of Strings
405
- # https://github.com/appsignal/appsignal-agent/issues/294
406
- "backtrace" => kind_of(String)
407
- },
408
- "metadata" => {
409
- "extra" => "data",
410
- "queue" => "default",
411
- "retry_count" => "0"
412
- },
413
- "namespace" => namespace,
414
- "sample_data" => {
415
- "environment" => {},
416
- "params" => expected_args,
417
- "tags" => {},
418
- "breadcrumbs" => []
419
- }
365
+ expect(transaction).to have_id(jid)
366
+ expect(transaction).to have_namespace(namespace)
367
+ expect(transaction).to have_action("TestClass#perform")
368
+ expect(transaction).to have_error("ExampleException", "uh oh")
369
+ expect(transaction).to include_metadata(
370
+ "extra" => "data",
371
+ "queue" => "default",
372
+ "retry_count" => "0"
420
373
  )
421
- expect_transaction_to_have_sidekiq_event(transaction_hash)
374
+ expect(transaction).to_not include_environment
375
+ expect(transaction).to include_params(expected_args)
376
+ expect(transaction).to_not include_tags
377
+ expect(transaction).to_not include_breadcrumbs
378
+ expect_transaction_to_have_sidekiq_event(transaction)
422
379
  end
423
380
  end
424
381
 
@@ -438,17 +395,17 @@ describe Appsignal::Integrations::SidekiqMiddleware, :with_yaml_parse_error => f
438
395
  end
439
396
 
440
397
  expect(created_transactions.count).to eq(2)
441
- expected_transaction = {
442
- "namespace" => "background_job",
443
- "action" => "TestClass#perform",
444
- "sample_data" => hash_including(
445
- "tags" => hash_including("test_tag" => "value")
446
- )
447
- }
448
- sidekiq_transaction = created_transactions.first.to_h
449
- error_reporter_transaction = created_transactions.last.to_h
450
- expect(sidekiq_transaction).to include(expected_transaction)
451
- expect(error_reporter_transaction).to include(expected_transaction)
398
+ tags = { "test_tag" => "value" }
399
+ sidekiq_transaction = created_transactions.first
400
+ error_reporter_transaction = created_transactions.last
401
+
402
+ expect(sidekiq_transaction).to have_namespace("background_job")
403
+ expect(sidekiq_transaction).to have_action("TestClass#perform")
404
+ expect(sidekiq_transaction).to include_tags(tags)
405
+
406
+ expect(error_reporter_transaction).to have_namespace("background_job")
407
+ expect(error_reporter_transaction).to have_action("TestClass#perform")
408
+ expect(error_reporter_transaction).to include_tags(tags)
452
409
  end
453
410
  end
454
411
  end
@@ -461,30 +418,21 @@ describe Appsignal::Integrations::SidekiqMiddleware, :with_yaml_parse_error => f
461
418
  .with("sidekiq_queue_job_count", 1, { :queue => "default", :status => :processed })
462
419
  perform_sidekiq_job
463
420
 
464
- transaction_hash = transaction.to_h
465
- expect(transaction_hash).to include(
466
- "id" => jid,
467
- "action" => "TestClass#perform",
468
- "error" => nil,
469
- "metadata" => {
470
- "extra" => "data",
471
- "queue" => "default",
472
- "retry_count" => "0"
473
- },
474
- "namespace" => namespace,
475
- "sample_data" => {
476
- "environment" => {},
477
- "params" => expected_args,
478
- "tags" => {},
479
- "breadcrumbs" => []
480
- }
481
- )
482
- # TODO: Not available in transaction.to_h yet.
483
- # https://github.com/appsignal/appsignal-agent/issues/293
484
- expect(transaction.request.env).to eq(
485
- :queue_start => Time.parse("2001-01-01 10:00:00UTC").to_f
421
+ expect(transaction).to have_id(jid)
422
+ expect(transaction).to have_namespace(namespace)
423
+ expect(transaction).to have_action("TestClass#perform")
424
+ expect(transaction).to_not have_error
425
+ expect(transaction).to_not include_tags
426
+ expect(transaction).to_not include_environment
427
+ expect(transaction).to_not include_breadcrumbs
428
+ expect(transaction).to_not include_params(expected_args)
429
+ expect(transaction).to include_metadata(
430
+ "extra" => "data",
431
+ "queue" => "default",
432
+ "retry_count" => "0"
486
433
  )
487
- expect_transaction_to_have_sidekiq_event(transaction_hash)
434
+ expect(transaction).to have_queue_start(Time.parse("2001-01-01 10:00:00UTC").to_i * 1000)
435
+ expect_transaction_to_have_sidekiq_event(transaction)
488
436
  end
489
437
  end
490
438
 
@@ -505,10 +453,9 @@ describe Appsignal::Integrations::SidekiqMiddleware, :with_yaml_parse_error => f
505
453
  last_transaction
506
454
  end
507
455
 
508
- def expect_transaction_to_have_sidekiq_event(transaction_hash)
509
- events = transaction_hash["events"]
510
- expect(events.count).to eq(1)
511
- expect(events.first).to include(
456
+ def expect_transaction_to_have_sidekiq_event(transaction)
457
+ expect(transaction.to_h["events"].count).to eq(1)
458
+ expect(transaction).to include_event(
512
459
  "name" => "perform_job.sidekiq",
513
460
  "title" => "",
514
461
  "count" => 1,
@@ -621,25 +568,18 @@ if DependencyHelper.active_job_present?
621
568
  perform_sidekiq_job(ActiveJobSidekiqTestJob, given_args)
622
569
 
623
570
  transaction = last_transaction
624
- transaction_hash = transaction.to_h
625
- expect(transaction_hash).to include(
626
- "action" => "ActiveJobSidekiqTestJob#perform",
627
- "error" => nil,
628
- "namespace" => namespace,
629
- "metadata" => hash_including(
630
- "queue" => "default"
631
- ),
632
- "sample_data" => hash_including(
633
- "environment" => {},
634
- "params" => [expected_args],
635
- "tags" => expected_tags.merge("queue" => "default")
636
- )
637
- )
638
- expect(transaction.request.env).to eq(:queue_start => time.to_f)
639
- events = transaction_hash["events"]
571
+ expect(transaction).to have_namespace(namespace)
572
+ expect(transaction).to have_action("ActiveJobSidekiqTestJob#perform")
573
+ expect(transaction).to_not have_error
574
+ expect(transaction).to include_metadata("queue" => "default")
575
+ expect(transaction).to_not include_environment
576
+ expect(transaction).to include_params([expected_args])
577
+ expect(transaction).to include_tags(expected_tags.merge("queue" => "default"))
578
+ expect(transaction).to have_queue_start(time.to_i * 1000)
579
+
580
+ events = transaction.to_h["events"]
640
581
  .sort_by { |e| e["start"] }
641
582
  .map { |event| event["name"] }
642
-
643
583
  expect(events).to eq(expected_perform_events)
644
584
  end
645
585
 
@@ -650,29 +590,18 @@ if DependencyHelper.active_job_present?
650
590
  end.to raise_error(RuntimeError, "uh oh")
651
591
 
652
592
  transaction = last_transaction
653
- transaction_hash = transaction.to_h
654
- expect(transaction_hash).to include(
655
- "action" => "ActiveJobSidekiqErrorTestJob#perform",
656
- "error" => {
657
- "name" => "RuntimeError",
658
- "message" => "uh oh",
659
- "backtrace" => kind_of(String)
660
- },
661
- "namespace" => namespace,
662
- "metadata" => hash_including(
663
- "queue" => "default"
664
- ),
665
- "sample_data" => hash_including(
666
- "environment" => {},
667
- "params" => [expected_args],
668
- "tags" => expected_tags.merge("queue" => "default")
669
- )
670
- )
671
- expect(transaction.request.env).to eq(:queue_start => time.to_f)
672
- events = transaction_hash["events"]
593
+ expect(transaction).to have_namespace(namespace)
594
+ expect(transaction).to have_action("ActiveJobSidekiqErrorTestJob#perform")
595
+ expect(transaction).to have_error("RuntimeError", "uh oh")
596
+ expect(transaction).to include_metadata("queue" => "default")
597
+ expect(transaction).to_not include_environment
598
+ expect(transaction).to include_params([expected_args])
599
+ expect(transaction).to include_tags(expected_tags.merge("queue" => "default"))
600
+ expect(transaction).to have_queue_start(time.to_i * 1000)
601
+
602
+ events = transaction.to_h["events"]
673
603
  .sort_by { |e| e["start"] }
674
604
  .map { |event| event["name"] }
675
-
676
605
  expect(events).to eq(expected_perform_events)
677
606
  end
678
607
  end
@@ -691,13 +620,10 @@ if DependencyHelper.active_job_present?
691
620
  perform_mailer(ActionMailerSidekiqTestJob, :welcome, given_args)
692
621
 
693
622
  transaction = last_transaction
694
- transaction_hash = transaction.to_h
695
- expect(transaction_hash).to include(
696
- "action" => "ActionMailerSidekiqTestJob#welcome",
697
- "sample_data" => hash_including(
698
- "params" => ["ActionMailerSidekiqTestJob", "welcome",
699
- "deliver_now"] + expected_wrapped_args
700
- )
623
+ expect(transaction).to have_action("ActionMailerSidekiqTestJob#welcome")
624
+ expect(transaction).to include_params(
625
+ ["ActionMailerSidekiqTestJob", "welcome",
626
+ "deliver_now"] + expected_wrapped_args
701
627
  )
702
628
  end
703
629
  end
@@ -24,7 +24,6 @@ if DependencyHelper.sinatra_present?
24
24
  it "does not start AppSignal again" do
25
25
  expect(Appsignal::Config).to_not receive(:new)
26
26
  expect(Appsignal).to_not receive(:start)
27
- expect(Appsignal).to_not receive(:start_logger)
28
27
  install_sinatra_integration
29
28
  end
30
29
 
@@ -17,70 +17,59 @@ if DependencyHelper.webmachine_present?
17
17
  let(:request) do
18
18
  Webmachine::Request.new("GET", "http://google.com:80/foo", {}, nil)
19
19
  end
20
- let(:resource) { double(:trace? => false, :handle_exception => true, :"code=" => nil) }
21
- let(:response) { Response.new }
22
- let(:transaction) { double(:set_action_if_nil => true) }
20
+ let(:resource) { double(:trace? => false, :handle_exception => true, :"code=" => nil) }
21
+ let(:response) { Response.new }
23
22
  let(:fsm) { Webmachine::Decision::FSM.new(resource, request, response) }
24
23
  before(:context) { start_agent }
24
+ around { |example| keep_transactions { example.run } }
25
25
 
26
26
  # Make sure the request responds to the method we need to get query params.
27
27
  describe "request" do
28
- it "should respond to `query`" do
28
+ it "responds to #query" do
29
29
  expect(request).to respond_to(:query)
30
30
  end
31
31
  end
32
32
 
33
33
  describe "#run" do
34
- before do
35
- allow(SecureRandom).to receive(:uuid).and_return("uuid")
36
- allow(Appsignal::Transaction).to receive(:create).and_return(transaction)
37
- end
34
+ before { allow(fsm).to receive(:call).and_call_original }
38
35
 
39
- it "should create a transaction" do
40
- expect(Appsignal::Transaction).to receive(:create).with(
41
- "uuid",
42
- Appsignal::Transaction::HTTP_REQUEST,
43
- request,
44
- :params_method => :query
45
- ).and_return(transaction)
36
+ it "creates a transaction" do
37
+ expect { fsm.run }.to(change { created_transactions.count }.by(1))
46
38
  end
47
39
 
48
- it "should set the action" do
49
- expect(transaction).to receive(:set_action_if_nil).with("RSpec::Mocks::Double#GET")
40
+ it "sets the action" do
41
+ fsm.run
42
+ expect(last_transaction).to have_action("RSpec::Mocks::Double#GET")
50
43
  end
51
44
 
52
- it "should call the original method" do
53
- expect(fsm).to receive(:run)
45
+ it "records an instrumentation event" do
46
+ fsm.run
47
+ expect(last_transaction).to include_event("name" => "process_action.webmachine")
54
48
  end
55
49
 
56
- it "should instrument the original method" do
57
- expect(Appsignal).to receive(:instrument).with("process_action.webmachine")
50
+ it "closes the transaction" do
51
+ fsm.run
52
+ expect(last_transaction).to be_completed
53
+ expect(current_transaction?).to be_falsy
58
54
  end
59
55
 
60
- it "should close the transaction" do
61
- expect(Appsignal::Transaction).to receive(:complete_current!)
62
- end
63
-
64
- after { fsm.run }
65
-
66
- describe "concerning the response" do
67
- it "sets a response code" do
68
- expect(fsm.response.code).to be_nil
69
- fsm.run
70
- expect(fsm.response.code).not_to be_nil
71
- end
56
+ it "sets a response code" do
57
+ expect(fsm.response.code).to be_nil
58
+ fsm.run
59
+ expect(fsm.response.code).not_to be_nil
72
60
  end
73
61
  end
74
62
 
75
63
  describe "#handle_exceptions" do
76
- let(:error) { ExampleException }
64
+ let(:error) { ExampleException.new("error message") }
65
+ let(:transaction) { http_request_transaction }
77
66
 
78
- it "should catch the error and send it to AppSignal" do
79
- expect(Appsignal).to receive(:set_error).with(error)
80
- end
67
+ it "tracks the error" do
68
+ with_current_transaction(transaction) do
69
+ fsm.send(:handle_exceptions) { raise error }
70
+ end
81
71
 
82
- after do
83
- fsm.send(:handle_exceptions) { raise error }
72
+ expect(last_transaction).to have_error("ExampleException", "error message")
84
73
  end
85
74
  end
86
75
  end