appsignal 3.9.2-java → 3.9.3-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.
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
@@ -385,6 +385,8 @@ describe Appsignal::Config do
385
385
 
386
386
  context "without the selected env" do
387
387
  let(:config) { project_fixture_config("nonsense") }
388
+ let(:log_stream) { std_stream }
389
+ let(:log) { log_contents(log_stream) }
388
390
 
389
391
  it "is not valid or active" do
390
392
  expect(config.valid?).to be_falsy
@@ -392,11 +394,11 @@ describe Appsignal::Config do
392
394
  end
393
395
 
394
396
  it "logs an error" do
395
- expect_any_instance_of(Logger).to receive(:error).once
396
- .with("Not loading from config file: config for 'nonsense' not found")
397
- expect_any_instance_of(Logger).to receive(:error).once
398
- .with("Push API key not set after loading config")
399
- config
397
+ use_logger_with(log_stream) { config }
398
+ expect(log)
399
+ .to contains_log(:error, "Not loading from config file: config for 'nonsense' not found")
400
+ expect(log)
401
+ .to contains_log(:error, "Push API key not set after loading config")
400
402
  end
401
403
  end
402
404
  end
@@ -32,56 +32,53 @@ describe Appsignal::Demo do
32
32
  end
33
33
 
34
34
  describe ".create_example_error_request" do
35
- let!(:error_transaction) { http_request_transaction }
36
- let(:config) { project_fixture_config("production") }
37
- before do
38
- Appsignal.config = config
39
- expect(Appsignal::Transaction).to receive(:new).with(
40
- kind_of(String),
41
- Appsignal::Transaction::HTTP_REQUEST,
42
- kind_of(::Rack::Request),
43
- kind_of(Hash)
44
- ).and_return(error_transaction)
45
- end
46
- subject { described_class.send(:create_example_error_request) }
35
+ before { start_agent }
36
+ around { |example| keep_transactions { example.run } }
47
37
 
48
38
  it "sets an error" do
49
- expect(error_transaction).to receive(:set_error).with(kind_of(described_class::TestError))
50
- expect(error_transaction).to receive(:set_metadata).with("path", "/hello")
51
- expect(error_transaction).to receive(:set_metadata).with("method", "GET")
52
- expect(error_transaction).to receive(:set_metadata).with("demo_sample", "true")
53
- expect(error_transaction).to receive(:complete)
54
- subject
39
+ described_class.send(:create_example_error_request)
40
+
41
+ transaction = last_transaction
42
+ expect(transaction).to have_id
43
+ expect(transaction).to have_namespace(Appsignal::Transaction::HTTP_REQUEST)
44
+ expect(transaction).to have_action("DemoController#hello")
45
+ expect(transaction).to have_error(
46
+ "Appsignal::Demo::TestError",
47
+ "Hello world! This is an error used for demonstration purposes."
48
+ )
49
+ expect(transaction).to include_metadata(
50
+ "path" => "/hello",
51
+ "method" => "GET",
52
+ "demo_sample" => "true"
53
+ )
54
+ expect(transaction).to be_completed
55
55
  end
56
56
  end
57
57
 
58
58
  describe ".create_example_performance_request" do
59
- let!(:performance_transaction) { http_request_transaction }
60
- let(:config) { project_fixture_config("production") }
61
- before do
62
- Appsignal.config = config
63
- expect(Appsignal::Transaction).to receive(:new).with(
64
- kind_of(String),
65
- Appsignal::Transaction::HTTP_REQUEST,
66
- kind_of(::Rack::Request),
67
- kind_of(Hash)
68
- ).and_return(performance_transaction)
69
- end
70
- subject { described_class.send(:create_example_performance_request) }
59
+ before { start_agent }
60
+ around { |example| keep_transactions { example.run } }
71
61
 
72
62
  it "sends a performance sample" do
73
- expect(performance_transaction).to receive(:start_event)
74
- expect(performance_transaction).to receive(:finish_event).with(
75
- "action_view.render",
76
- "Render hello.html.erb",
77
- "<h1>Hello world!</h1>",
78
- Appsignal::EventFormatter::DEFAULT
63
+ described_class.send(:create_example_performance_request)
64
+
65
+ transaction = last_transaction
66
+ expect(transaction).to have_id
67
+ expect(transaction).to have_namespace(Appsignal::Transaction::HTTP_REQUEST)
68
+ expect(transaction).to have_action("DemoController#hello")
69
+ expect(transaction).to_not have_error
70
+ expect(transaction).to include_metadata(
71
+ "path" => "/hello",
72
+ "method" => "GET",
73
+ "demo_sample" => "true"
74
+ )
75
+ expect(transaction).to include_event(
76
+ "name" => "action_view.render",
77
+ "title" => "Render hello.html.erb",
78
+ "body" => "<h1>Hello world!</h1>",
79
+ "body_format" => Appsignal::EventFormatter::DEFAULT
79
80
  )
80
- expect(performance_transaction).to receive(:set_metadata).with("path", "/hello")
81
- expect(performance_transaction).to receive(:set_metadata).with("method", "GET")
82
- expect(performance_transaction).to receive(:set_metadata).with("demo_sample", "true")
83
- expect(performance_transaction).to receive(:complete)
84
- subject
81
+ expect(transaction).to be_completed
85
82
  end
86
83
  end
87
84
  end
@@ -46,19 +46,12 @@ describe Appsignal::Hooks::ActionCableHook do
46
46
  http_request_env_with_data("action_dispatch.request_id" => request_id, :params => params)
47
47
  end
48
48
  let(:instance) { channel.new(connection, identifier, params) }
49
- subject { transaction.to_h }
50
49
  before do
51
50
  start_agent
52
51
  expect(Appsignal.active?).to be_truthy
53
52
  transaction
54
53
 
55
- expect(Appsignal::Transaction).to receive(:create).with(
56
- transaction_id,
57
- Appsignal::Transaction::ACTION_CABLE,
58
- kind_of(ActionDispatch::Request)
59
- )
60
- .and_return(transaction)
61
- allow(Appsignal::Transaction).to receive(:current).and_return(transaction)
54
+ set_current_transaction(transaction)
62
55
 
63
56
  # Stub transmit call for subscribe/unsubscribe tests
64
57
  allow(connection).to receive(:websocket)
@@ -70,35 +63,25 @@ describe Appsignal::Hooks::ActionCableHook do
70
63
  it "creates a transaction for an action" do
71
64
  instance.perform_action("message" => "foo", "action" => "speak")
72
65
 
73
- expect(subject).to include(
74
- "action" => "MyChannel#speak",
75
- "error" => nil,
76
- "id" => transaction_id,
77
- "namespace" => Appsignal::Transaction::ACTION_CABLE,
78
- "metadata" => {
79
- "method" => "websocket",
80
- "path" => "/blog"
81
- }
66
+ transaction = last_transaction
67
+ expect(transaction).to have_id(transaction_id)
68
+ expect(transaction).to have_namespace(Appsignal::Transaction::ACTION_CABLE)
69
+ expect(transaction).to have_action("MyChannel#speak")
70
+ expect(transaction).to_not have_error
71
+ expect(transaction).to include_metadata(
72
+ "method" => "websocket",
73
+ "path" => "/blog"
82
74
  )
83
- expect(subject["events"].first).to include(
84
- "allocation_count" => kind_of(Integer),
75
+ expect(transaction).to include_event(
85
76
  "body" => "",
86
77
  "body_format" => Appsignal::EventFormatter::DEFAULT,
87
- "child_allocation_count" => kind_of(Integer),
88
- "child_duration" => kind_of(Float),
89
- "child_gc_duration" => kind_of(Float),
90
78
  "count" => 1,
91
- "gc_duration" => kind_of(Float),
92
- "start" => kind_of(Float),
93
- "duration" => kind_of(Float),
94
79
  "name" => "perform_action.action_cable",
95
80
  "title" => ""
96
81
  )
97
- expect(subject["sample_data"]).to include(
98
- "params" => {
99
- "action" => "speak",
100
- "message" => "foo"
101
- }
82
+ expect(transaction).to include_params(
83
+ "action" => "speak",
84
+ "message" => "foo"
102
85
  )
103
86
  end
104
87
 
@@ -120,7 +103,7 @@ describe Appsignal::Hooks::ActionCableHook do
120
103
  it "uses its own internal request_id set by the subscribed callback" do
121
104
  # Subscribe action, sets the request_id
122
105
  instance.subscribe_to_channel
123
- expect(transaction.to_h["id"]).to eq(transaction_id)
106
+ expect(transaction).to have_id(transaction_id)
124
107
 
125
108
  # Expect another transaction for the action.
126
109
  # This transaction will use the same request_id as the
@@ -131,12 +114,9 @@ describe Appsignal::Hooks::ActionCableHook do
131
114
  kind_of(ActionDispatch::Request)
132
115
  ).and_return(action_transaction)
133
116
  allow(Appsignal::Transaction).to receive(:current).and_return(action_transaction)
134
- # Stub complete call, stops it from being cleared in the extension
135
- # And allows us to call `#to_h` on it after it's been completed.
136
- expect(action_transaction.ext).to receive(:complete)
137
117
 
138
118
  instance.perform_action("message" => "foo", "action" => "speak")
139
- expect(action_transaction.to_h["id"]).to eq(transaction_id)
119
+ expect(action_transaction).to have_id(transaction_id)
140
120
  end
141
121
  end
142
122
 
@@ -158,25 +138,18 @@ describe Appsignal::Hooks::ActionCableHook do
158
138
  instance.perform_action("message" => "foo", "action" => "speak")
159
139
  end.to raise_error(ExampleException)
160
140
 
161
- expect(subject).to include(
162
- "action" => "MyChannel#speak",
163
- "id" => transaction_id,
164
- "namespace" => Appsignal::Transaction::ACTION_CABLE,
165
- "metadata" => {
166
- "method" => "websocket",
167
- "path" => "/blog"
168
- }
169
- )
170
- expect(subject["error"]).to include(
171
- "backtrace" => kind_of(String),
172
- "name" => "ExampleException",
173
- "message" => "oh no!"
141
+ transaction = last_transaction
142
+ expect(transaction).to have_id(transaction_id)
143
+ expect(transaction).to have_action("MyChannel#speak")
144
+ expect(transaction).to have_namespace(Appsignal::Transaction::ACTION_CABLE)
145
+ expect(transaction).to have_error("ExampleException", "oh no!")
146
+ expect(transaction).to include_metadata(
147
+ "method" => "websocket",
148
+ "path" => "/blog"
174
149
  )
175
- expect(subject["sample_data"]).to include(
176
- "params" => {
177
- "action" => "speak",
178
- "message" => "foo"
179
- }
150
+ expect(transaction).to include_params(
151
+ "action" => "speak",
152
+ "message" => "foo"
180
153
  )
181
154
  end
182
155
  end
@@ -188,33 +161,23 @@ describe Appsignal::Hooks::ActionCableHook do
188
161
  it "creates a transaction for a subscription" do
189
162
  instance.subscribe_to_channel
190
163
 
191
- expect(subject).to include(
192
- "action" => "MyChannel#subscribed",
193
- "error" => nil,
194
- "id" => transaction_id,
195
- "namespace" => Appsignal::Transaction::ACTION_CABLE,
196
- "metadata" => {
197
- "method" => "websocket",
198
- "path" => "/blog"
199
- }
164
+ transaction = last_transaction
165
+ expect(transaction).to have_id(transaction_id)
166
+ expect(transaction).to have_action("MyChannel#subscribed")
167
+ expect(transaction).to have_namespace(Appsignal::Transaction::ACTION_CABLE)
168
+ expect(transaction).to_not have_error
169
+ expect(transaction).to include_metadata(
170
+ "method" => "websocket",
171
+ "path" => "/blog"
200
172
  )
201
- expect(subject["events"].first).to include(
202
- "allocation_count" => kind_of(Integer),
173
+ expect(transaction).to include_params("internal" => "true")
174
+ expect(transaction).to include_event(
203
175
  "body" => "",
204
176
  "body_format" => Appsignal::EventFormatter::DEFAULT,
205
- "child_allocation_count" => kind_of(Integer),
206
- "child_duration" => kind_of(Float),
207
- "child_gc_duration" => kind_of(Float),
208
177
  "count" => 1,
209
- "gc_duration" => kind_of(Float),
210
- "start" => kind_of(Float),
211
- "duration" => kind_of(Float),
212
178
  "name" => "subscribed.action_cable",
213
179
  "title" => ""
214
180
  )
215
- expect(subject["sample_data"]).to include(
216
- "params" => { "internal" => "true" }
217
- )
218
181
  end
219
182
 
220
183
  context "without request_id (standalone server)" do
@@ -226,7 +189,7 @@ describe Appsignal::Hooks::ActionCableHook do
226
189
  end
227
190
 
228
191
  it "uses its own internal request_id" do
229
- expect(subject["id"]).to eq(transaction_id)
192
+ expect(last_transaction).to have_id(transaction_id)
230
193
  end
231
194
  end
232
195
 
@@ -248,23 +211,16 @@ describe Appsignal::Hooks::ActionCableHook do
248
211
  instance.subscribe_to_channel
249
212
  end.to raise_error(ExampleException)
250
213
 
251
- expect(subject).to include(
252
- "action" => "MyChannel#subscribed",
253
- "id" => transaction_id,
254
- "namespace" => Appsignal::Transaction::ACTION_CABLE,
255
- "metadata" => {
256
- "method" => "websocket",
257
- "path" => "/blog"
258
- }
259
- )
260
- expect(subject["error"]).to include(
261
- "backtrace" => kind_of(String),
262
- "name" => "ExampleException",
263
- "message" => "oh no!"
264
- )
265
- expect(subject["sample_data"]).to include(
266
- "params" => { "internal" => "true" }
214
+ transaction = last_transaction
215
+ expect(transaction).to have_id(transaction_id)
216
+ expect(transaction).to have_action("MyChannel#subscribed")
217
+ expect(transaction).to have_namespace(Appsignal::Transaction::ACTION_CABLE)
218
+ expect(transaction).to have_error("ExampleException", "oh no!")
219
+ expect(transaction).to include_metadata(
220
+ "method" => "websocket",
221
+ "path" => "/blog"
267
222
  )
223
+ expect(transaction).to include_params("internal" => "true")
268
224
  end
269
225
  end
270
226
 
@@ -280,33 +236,23 @@ describe Appsignal::Hooks::ActionCableHook do
280
236
  it "does not fail on missing `#env` method on `ConnectionStub`" do
281
237
  instance.subscribe_to_channel
282
238
 
283
- expect(subject).to include(
284
- "action" => "MyChannel#subscribed",
285
- "error" => nil,
286
- "id" => transaction_id,
287
- "namespace" => Appsignal::Transaction::ACTION_CABLE,
288
- "metadata" => {
289
- "method" => "websocket",
290
- "path" => "" # No path as the ConnectionStub doesn't have the real request env
291
- }
239
+ transaction = last_transaction
240
+ expect(transaction).to have_id(transaction_id)
241
+ expect(transaction).to have_action("MyChannel#subscribed")
242
+ expect(transaction).to have_namespace(Appsignal::Transaction::ACTION_CABLE)
243
+ expect(transaction).to_not have_error
244
+ expect(transaction).to include_metadata(
245
+ "method" => "websocket",
246
+ "path" => "" # No path as the ConnectionStub doesn't have the real request env
292
247
  )
293
- expect(subject["events"].first).to include(
294
- "allocation_count" => kind_of(Integer),
248
+ expect(transaction).to include_params("internal" => "true")
249
+ expect(transaction).to include_event(
295
250
  "body" => "",
296
251
  "body_format" => Appsignal::EventFormatter::DEFAULT,
297
- "child_allocation_count" => kind_of(Integer),
298
- "child_duration" => kind_of(Float),
299
- "child_gc_duration" => kind_of(Float),
300
252
  "count" => 1,
301
- "gc_duration" => kind_of(Float),
302
- "start" => kind_of(Float),
303
- "duration" => kind_of(Float),
304
253
  "name" => "subscribed.action_cable",
305
254
  "title" => ""
306
255
  )
307
- expect(subject["sample_data"]).to include(
308
- "params" => { "internal" => "true" }
309
- )
310
256
  end
311
257
  end
312
258
  end
@@ -318,33 +264,23 @@ describe Appsignal::Hooks::ActionCableHook do
318
264
  it "creates a transaction for a subscription" do
319
265
  instance.unsubscribe_from_channel
320
266
 
321
- expect(subject).to include(
322
- "action" => "MyChannel#unsubscribed",
323
- "error" => nil,
324
- "id" => transaction_id,
325
- "namespace" => Appsignal::Transaction::ACTION_CABLE,
326
- "metadata" => {
327
- "method" => "websocket",
328
- "path" => "/blog"
329
- }
267
+ transaction = last_transaction
268
+ expect(transaction).to have_id(transaction_id)
269
+ expect(transaction).to have_action("MyChannel#unsubscribed")
270
+ expect(transaction).to have_namespace(Appsignal::Transaction::ACTION_CABLE)
271
+ expect(transaction).to_not have_error
272
+ expect(transaction).to include_metadata(
273
+ "method" => "websocket",
274
+ "path" => "/blog"
330
275
  )
331
- expect(subject["events"].first).to include(
332
- "allocation_count" => kind_of(Integer),
276
+ expect(transaction).to include_params("internal" => "true")
277
+ expect(transaction).to include_event(
333
278
  "body" => "",
334
279
  "body_format" => Appsignal::EventFormatter::DEFAULT,
335
- "child_allocation_count" => kind_of(Integer),
336
- "child_duration" => kind_of(Float),
337
- "child_gc_duration" => kind_of(Float),
338
280
  "count" => 1,
339
- "gc_duration" => kind_of(Float),
340
- "start" => kind_of(Float),
341
- "duration" => kind_of(Float),
342
281
  "name" => "unsubscribed.action_cable",
343
282
  "title" => ""
344
283
  )
345
- expect(subject["sample_data"]).to include(
346
- "params" => { "internal" => "true" }
347
- )
348
284
  end
349
285
 
350
286
  context "without request_id (standalone server)" do
@@ -356,7 +292,7 @@ describe Appsignal::Hooks::ActionCableHook do
356
292
  end
357
293
 
358
294
  it "uses its own internal request_id" do
359
- expect(subject["id"]).to eq(transaction_id)
295
+ expect(transaction).to have_id(transaction_id)
360
296
  end
361
297
  end
362
298
 
@@ -378,23 +314,16 @@ describe Appsignal::Hooks::ActionCableHook do
378
314
  instance.unsubscribe_from_channel
379
315
  end.to raise_error(ExampleException)
380
316
 
381
- expect(subject).to include(
382
- "action" => "MyChannel#unsubscribed",
383
- "id" => transaction_id,
384
- "namespace" => Appsignal::Transaction::ACTION_CABLE,
385
- "metadata" => {
386
- "method" => "websocket",
387
- "path" => "/blog"
388
- }
389
- )
390
- expect(subject["error"]).to include(
391
- "backtrace" => kind_of(String),
392
- "name" => "ExampleException",
393
- "message" => "oh no!"
394
- )
395
- expect(subject["sample_data"]).to include(
396
- "params" => { "internal" => "true" }
317
+ transaction = last_transaction
318
+ expect(transaction).to have_id(transaction_id)
319
+ expect(transaction).to have_action("MyChannel#unsubscribed")
320
+ expect(transaction).to have_namespace(Appsignal::Transaction::ACTION_CABLE)
321
+ expect(transaction).to have_error("ExampleException", "oh no!")
322
+ expect(transaction).to include_metadata(
323
+ "method" => "websocket",
324
+ "path" => "/blog"
397
325
  )
326
+ expect(transaction).to include_params("internal" => "true")
398
327
  end
399
328
  end
400
329
 
@@ -410,33 +339,23 @@ describe Appsignal::Hooks::ActionCableHook do
410
339
  it "does not fail on missing `#env` method on `ConnectionStub`" do
411
340
  instance.unsubscribe_from_channel
412
341
 
413
- expect(subject).to include(
414
- "action" => "MyChannel#unsubscribed",
415
- "error" => nil,
416
- "id" => transaction_id,
417
- "namespace" => Appsignal::Transaction::ACTION_CABLE,
418
- "metadata" => {
419
- "method" => "websocket",
420
- "path" => "" # No path as the ConnectionStub doesn't have the real request env
421
- }
342
+ transaction = last_transaction
343
+ expect(transaction).to have_id(transaction_id)
344
+ expect(transaction).to have_action("MyChannel#unsubscribed")
345
+ expect(transaction).to have_namespace(Appsignal::Transaction::ACTION_CABLE)
346
+ expect(transaction).to_not have_error
347
+ expect(transaction).to include_metadata(
348
+ "method" => "websocket",
349
+ "path" => "" # No path as the ConnectionStub doesn't have the real request env
422
350
  )
423
- expect(subject["events"].first).to include(
424
- "allocation_count" => kind_of(Integer),
351
+ expect(transaction).to include_params("internal" => "true")
352
+ expect(transaction).to include_event(
425
353
  "body" => "",
426
354
  "body_format" => Appsignal::EventFormatter::DEFAULT,
427
- "child_allocation_count" => kind_of(Integer),
428
- "child_duration" => kind_of(Float),
429
- "child_gc_duration" => kind_of(Float),
430
355
  "count" => 1,
431
- "gc_duration" => kind_of(Float),
432
- "start" => kind_of(Float),
433
- "duration" => kind_of(Float),
434
356
  "name" => "unsubscribed.action_cable",
435
357
  "title" => ""
436
358
  )
437
- expect(subject["sample_data"]).to include(
438
- "params" => { "internal" => "true" }
439
- )
440
359
  end
441
360
  end
442
361
  end
@@ -5,31 +5,19 @@ shared_examples "activesupport finish_with_state override" do
5
5
  listeners_state = instrumenter.start("sql.active_record", {})
6
6
  instrumenter.finish_with_state(listeners_state, "sql.active_record", :sql => "SQL")
7
7
 
8
- expect(transaction.to_h["events"]).to match([
9
- {
10
- "allocation_count" => kind_of(Integer),
11
- "body" => "SQL",
12
- "body_format" => Appsignal::EventFormatter::SQL_BODY_FORMAT,
13
- "child_allocation_count" => kind_of(Integer),
14
- "child_duration" => kind_of(Float),
15
- "child_gc_duration" => kind_of(Float),
16
- "count" => 1,
17
- "duration" => kind_of(Float),
18
- "gc_duration" => kind_of(Float),
19
- "name" => "sql.active_record",
20
- "start" => kind_of(Float),
21
- "title" => ""
22
- }
23
- ])
8
+ expect(transaction).to include_event(
9
+ "body" => "SQL",
10
+ "body_format" => Appsignal::EventFormatter::SQL_BODY_FORMAT,
11
+ "count" => 1,
12
+ "name" => "sql.active_record",
13
+ "title" => ""
14
+ )
24
15
  end
25
16
 
26
17
  it "does not instrument events whose name starts with a bang" do
27
- expect(Appsignal::Transaction.current).not_to receive(:start_event)
28
- expect(Appsignal::Transaction.current).not_to receive(:finish_event)
29
-
30
18
  listeners_state = instrumenter.start("!sql.active_record", {})
31
19
  instrumenter.finish_with_state(listeners_state, "!sql.active_record", :sql => "SQL")
32
20
 
33
- expect(transaction.to_h["events"]).to be_empty
21
+ expect(transaction).to_not include_events
34
22
  end
35
23
  end