appsignal 3.9.2-java → 3.10.0-java

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (105) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/ci.yml +3138 -0
  3. data/.rubocop.yml +28 -20
  4. data/.rubocop_todo.yml +7 -33
  5. data/CHANGELOG.md +130 -0
  6. data/README.md +0 -1
  7. data/Rakefile +80 -65
  8. data/appsignal.gemspec +1 -1
  9. data/build_matrix.yml +112 -184
  10. data/ext/base.rb +1 -1
  11. data/gemfiles/hanami-2.1.gemfile +7 -0
  12. data/gemfiles/webmachine1.gemfile +5 -4
  13. data/lib/appsignal/cli/diagnose.rb +1 -1
  14. data/lib/appsignal/config.rb +5 -1
  15. data/lib/appsignal/demo.rb +0 -1
  16. data/lib/appsignal/environment.rb +11 -2
  17. data/lib/appsignal/extension/jruby.rb +1 -1
  18. data/lib/appsignal/helpers/instrumentation.rb +164 -2
  19. data/lib/appsignal/hooks/active_job.rb +1 -6
  20. data/lib/appsignal/integrations/grape.rb +19 -47
  21. data/lib/appsignal/integrations/hanami.rb +8 -7
  22. data/lib/appsignal/integrations/padrino.rb +51 -52
  23. data/lib/appsignal/integrations/railtie.rb +0 -3
  24. data/lib/appsignal/integrations/rake.rb +46 -12
  25. data/lib/appsignal/integrations/sidekiq.rb +1 -11
  26. data/lib/appsignal/integrations/sinatra.rb +0 -1
  27. data/lib/appsignal/integrations/webmachine.rb +15 -9
  28. data/lib/appsignal/probes/gvl.rb +24 -2
  29. data/lib/appsignal/probes/sidekiq.rb +1 -1
  30. data/lib/appsignal/probes.rb +1 -1
  31. data/lib/appsignal/rack/abstract_middleware.rb +104 -33
  32. data/lib/appsignal/rack/body_wrapper.rb +143 -0
  33. data/lib/appsignal/rack/event_handler.rb +12 -3
  34. data/lib/appsignal/rack/generic_instrumentation.rb +5 -4
  35. data/lib/appsignal/rack/grape_middleware.rb +40 -0
  36. data/lib/appsignal/rack/hanami_middleware.rb +2 -12
  37. data/lib/appsignal/rack/instrumentation_middleware.rb +62 -0
  38. data/lib/appsignal/rack/rails_instrumentation.rb +14 -57
  39. data/lib/appsignal/rack/sinatra_instrumentation.rb +1 -3
  40. data/lib/appsignal/rack/streaming_listener.rb +13 -59
  41. data/lib/appsignal/rack.rb +31 -0
  42. data/lib/appsignal/transaction.rb +50 -8
  43. data/lib/appsignal/utils/integration_memory_logger.rb +78 -0
  44. data/lib/appsignal/utils.rb +1 -0
  45. data/lib/appsignal/version.rb +1 -1
  46. data/lib/appsignal.rb +36 -33
  47. data/spec/.rubocop.yml +1 -1
  48. data/spec/lib/appsignal/cli/diagnose_spec.rb +1 -1
  49. data/spec/lib/appsignal/cli/install_spec.rb +3 -3
  50. data/spec/lib/appsignal/config_spec.rb +8 -5
  51. data/spec/lib/appsignal/demo_spec.rb +38 -41
  52. data/spec/lib/appsignal/hooks/action_cable_spec.rb +86 -167
  53. data/spec/lib/appsignal/hooks/active_support_notifications/finish_with_state_shared_examples.rb +8 -20
  54. data/spec/lib/appsignal/hooks/active_support_notifications/instrument_shared_examples.rb +38 -84
  55. data/spec/lib/appsignal/hooks/active_support_notifications/start_finish_shared_examples.rb +16 -37
  56. data/spec/lib/appsignal/hooks/active_support_notifications_spec.rb +4 -4
  57. data/spec/lib/appsignal/hooks/activejob_spec.rb +111 -200
  58. data/spec/lib/appsignal/hooks/delayed_job_spec.rb +54 -91
  59. data/spec/lib/appsignal/hooks/dry_monitor_spec.rb +14 -32
  60. data/spec/lib/appsignal/hooks/excon_spec.rb +8 -12
  61. data/spec/lib/appsignal/hooks/net_http_spec.rb +7 -42
  62. data/spec/lib/appsignal/hooks/rake_spec.rb +107 -34
  63. data/spec/lib/appsignal/hooks/redis_client_spec.rb +18 -30
  64. data/spec/lib/appsignal/hooks/redis_spec.rb +10 -16
  65. data/spec/lib/appsignal/hooks/resque_spec.rb +42 -62
  66. data/spec/lib/appsignal/hooks/shoryuken_spec.rb +33 -74
  67. data/spec/lib/appsignal/integrations/hanami_spec.rb +79 -21
  68. data/spec/lib/appsignal/integrations/http_spec.rb +12 -20
  69. data/spec/lib/appsignal/integrations/net_http_spec.rb +33 -0
  70. data/spec/lib/appsignal/integrations/object_spec.rb +29 -36
  71. data/spec/lib/appsignal/integrations/padrino_spec.rb +190 -163
  72. data/spec/lib/appsignal/integrations/que_spec.rb +43 -70
  73. data/spec/lib/appsignal/integrations/railtie_spec.rb +26 -67
  74. data/spec/lib/appsignal/integrations/sidekiq_spec.rb +86 -160
  75. data/spec/lib/appsignal/integrations/sinatra_spec.rb +10 -3
  76. data/spec/lib/appsignal/integrations/webmachine_spec.rb +77 -40
  77. data/spec/lib/appsignal/probes/gvl_spec.rb +80 -3
  78. data/spec/lib/appsignal/probes_spec.rb +7 -4
  79. data/spec/lib/appsignal/rack/abstract_middleware_spec.rb +302 -105
  80. data/spec/lib/appsignal/rack/body_wrapper_spec.rb +263 -0
  81. data/spec/lib/appsignal/rack/event_handler_spec.rb +81 -78
  82. data/spec/lib/appsignal/rack/generic_instrumentation_spec.rb +70 -27
  83. data/spec/lib/appsignal/rack/grape_middleware_spec.rb +234 -0
  84. data/spec/lib/appsignal/rack/hanami_middleware_spec.rb +2 -16
  85. data/spec/lib/appsignal/rack/instrumentation_middleware_spec.rb +38 -0
  86. data/spec/lib/appsignal/rack/rails_instrumentation_spec.rb +67 -131
  87. data/spec/lib/appsignal/rack/sinatra_instrumentation_spec.rb +36 -44
  88. data/spec/lib/appsignal/rack/streaming_listener_spec.rb +44 -139
  89. data/spec/lib/appsignal/transaction_spec.rb +239 -94
  90. data/spec/lib/appsignal/utils/integration_memory_logger_spec.rb +163 -0
  91. data/spec/lib/appsignal_spec.rb +556 -344
  92. data/spec/support/helpers/dependency_helper.rb +6 -1
  93. data/spec/support/helpers/std_streams_helper.rb +1 -1
  94. data/spec/support/helpers/transaction_helpers.rb +8 -0
  95. data/spec/support/matchers/transaction.rb +185 -0
  96. data/spec/support/mocks/dummy_app.rb +20 -0
  97. data/spec/support/shared_examples/instrument.rb +17 -12
  98. data/spec/support/testing.rb +18 -9
  99. metadata +20 -11
  100. data/.semaphore/semaphore.yml +0 -2347
  101. data/script/lint_git +0 -22
  102. data/spec/lib/appsignal/integrations/grape_spec.rb +0 -239
  103. data/spec/support/matchers/be_completed.rb +0 -5
  104. data/support/check_versions +0 -22
  105. /data/gemfiles/{hanami.gemfile → hanami-2.0.gemfile} +0 -0
@@ -64,23 +64,18 @@ describe Appsignal::Hooks::DelayedJobHook do
64
64
  context "with a normal call" do
65
65
  it "wraps it in a transaction" do
66
66
  perform
67
- transaction_data = last_transaction.to_h
68
- expect(transaction_data).to include(
69
- "action" => "TestClass#perform",
70
- "namespace" => "background_job",
71
- "error" => nil
72
- )
73
- expect(transaction_data["events"].map { |e| e["name"] })
74
- .to eql(["perform_job.delayed_job"])
75
- expect(transaction_data["sample_data"]).to include(
76
- "metadata" => {
77
- "priority" => 1,
78
- "attempts" => 1,
79
- "queue" => "default",
80
- "id" => "123"
81
- },
82
- "params" => ["argument"]
67
+ transaction = last_transaction
68
+ expect(transaction).to have_action("TestClass#perform")
69
+ expect(transaction).to have_namespace("background_job")
70
+ expect(transaction).to_not have_error
71
+ expect(transaction).to include_event(:name => "perform_job.delayed_job")
72
+ expect(transaction).to include_sample_metadata(
73
+ "priority" => 1,
74
+ "attempts" => 1,
75
+ "queue" => "default",
76
+ "id" => "123"
83
77
  )
78
+ expect(transaction).to include_params(["argument"])
84
79
  end
85
80
 
86
81
  context "with more complex params" do
@@ -93,13 +88,8 @@ describe Appsignal::Hooks::DelayedJobHook do
93
88
 
94
89
  it "adds the more complex arguments" do
95
90
  perform
96
- transaction_data = last_transaction.to_h
97
- expect(transaction_data["sample_data"]).to include(
98
- "params" => {
99
- "foo" => "Foo",
100
- "bar" => "Bar"
101
- }
102
- )
91
+
92
+ expect(last_transaction).to include_params("foo" => "Foo", "bar" => "Bar")
103
93
  end
104
94
 
105
95
  context "with parameter filtering" do
@@ -110,13 +100,8 @@ describe Appsignal::Hooks::DelayedJobHook do
110
100
 
111
101
  it "filters selected arguments" do
112
102
  perform
113
- transaction_data = last_transaction.to_h
114
- expect(transaction_data["sample_data"]).to include(
115
- "params" => {
116
- "foo" => "[FILTERED]",
117
- "bar" => "Bar"
118
- }
119
- )
103
+
104
+ expect(last_transaction).to include_params("foo" => "[FILTERED]", "bar" => "Bar")
120
105
  end
121
106
  end
122
107
  end
@@ -125,13 +110,9 @@ describe Appsignal::Hooks::DelayedJobHook do
125
110
  let(:run_at) { Time.parse("2017-01-01 10:01:00UTC") }
126
111
 
127
112
  it "reports queue_start with run_at time" do
128
- # TODO: Not available in transaction.to_h yet.
129
- # https://github.com/appsignal/appsignal-agent/issues/293
130
- expect(Appsignal).to receive(:monitor_transaction).with(
131
- "perform_job.delayed_job",
132
- a_hash_including(:queue_start => run_at)
133
- ).and_call_original
134
113
  perform
114
+
115
+ expect(last_transaction).to have_queue_start(run_at.to_i * 1000)
135
116
  end
136
117
  end
137
118
 
@@ -142,7 +123,7 @@ describe Appsignal::Hooks::DelayedJobHook do
142
123
 
143
124
  it "wraps it in a transaction using the class method job name" do
144
125
  perform
145
- expect(last_transaction.to_h["action"]).to eql("CustomClassMethod.perform")
126
+ expect(last_transaction).to have_action("CustomClassMethod.perform")
146
127
  end
147
128
  end
148
129
 
@@ -155,7 +136,7 @@ describe Appsignal::Hooks::DelayedJobHook do
155
136
  let(:payload_object) { double(:appsignal_name => "CustomClass#perform") }
156
137
 
157
138
  it "wraps it in a transaction using the custom name" do
158
- expect(last_transaction.to_h["action"]).to eql("CustomClass#perform")
139
+ expect(last_transaction).to have_action("CustomClass#perform")
159
140
  end
160
141
  end
161
142
 
@@ -163,7 +144,7 @@ describe Appsignal::Hooks::DelayedJobHook do
163
144
  let(:payload_object) { double(:appsignal_name => Object.new) }
164
145
 
165
146
  it "wraps it in a transaction using the original job name" do
166
- expect(last_transaction.to_h["action"]).to eql("TestClass#perform")
147
+ expect(last_transaction).to have_action("TestClass#perform")
167
148
  end
168
149
  end
169
150
 
@@ -172,7 +153,7 @@ describe Appsignal::Hooks::DelayedJobHook do
172
153
 
173
154
  it "wraps it in a transaction using the custom name" do
174
155
  perform
175
- expect(last_transaction.to_h["action"]).to eql("CustomClassMethod.perform")
156
+ expect(last_transaction).to have_action("CustomClassMethod.perform")
176
157
  end
177
158
  end
178
159
  end
@@ -182,7 +163,7 @@ describe Appsignal::Hooks::DelayedJobHook do
182
163
  let(:payload_object) { double(:appsignal_name => "CustomClassHash#perform") }
183
164
 
184
165
  it "wraps it in a transaction using the custom name" do
185
- expect(last_transaction.to_h["action"]).to eql("CustomClassHash#perform")
166
+ expect(last_transaction).to have_action("CustomClassHash#perform")
186
167
  end
187
168
  end
188
169
 
@@ -190,7 +171,7 @@ describe Appsignal::Hooks::DelayedJobHook do
190
171
  let(:payload_object) { double(:appsignal_name => Object.new) }
191
172
 
192
173
  it "wraps it in a transaction using the original job name" do
193
- expect(last_transaction.to_h["action"]).to eql("TestClass#perform")
174
+ expect(last_transaction).to have_action("TestClass#perform")
194
175
  end
195
176
  end
196
177
 
@@ -199,7 +180,7 @@ describe Appsignal::Hooks::DelayedJobHook do
199
180
 
200
181
  it "wraps it in a transaction using the custom name" do
201
182
  perform
202
- expect(last_transaction.to_h["action"]).to eql("CustomClassMethod.perform")
183
+ expect(last_transaction).to have_action("CustomClassMethod.perform")
203
184
  end
204
185
  end
205
186
  end
@@ -221,7 +202,7 @@ describe Appsignal::Hooks::DelayedJobHook do
221
202
  # of `self.appsignal_name`. Since this isn't a valid `String`
222
203
  # we return the default job name as action name.
223
204
  it "wraps it in a transaction using the original job name" do
224
- expect(last_transaction.to_h["action"]).to eql("TestClass#perform")
205
+ expect(last_transaction).to have_action("TestClass#perform")
225
206
  end
226
207
  end
227
208
  end
@@ -234,7 +215,7 @@ describe Appsignal::Hooks::DelayedJobHook do
234
215
 
235
216
  it "appends #perform to the class name" do
236
217
  perform
237
- expect(last_transaction.to_h["action"]).to eql("Banana#perform")
218
+ expect(last_transaction).to have_action("Banana#perform")
238
219
  end
239
220
  end
240
221
 
@@ -267,23 +248,19 @@ describe Appsignal::Hooks::DelayedJobHook do
267
248
 
268
249
  it "wraps it in a transaction with the correct params" do
269
250
  perform
270
- transaction_data = last_transaction.to_h
271
- expect(transaction_data).to include(
272
- "action" => "TestClass#perform",
273
- "namespace" => "background_job",
274
- "error" => nil
275
- )
276
- expect(transaction_data["events"].map { |e| e["name"] })
277
- .to eql(["perform_job.delayed_job"])
278
- expect(transaction_data["sample_data"]).to include(
279
- "metadata" => {
280
- "priority" => 1,
281
- "attempts" => 1,
282
- "queue" => "default",
283
- "id" => "123"
284
- },
285
- "params" => ["activejob_argument"]
251
+
252
+ transaction = last_transaction
253
+ expect(transaction).to have_namespace("background_job")
254
+ expect(transaction).to have_action("TestClass#perform")
255
+ expect(transaction).to_not have_error
256
+ expect(transaction).to include_event("name" => "perform_job.delayed_job")
257
+ expect(transaction).to include_sample_metadata(
258
+ "priority" => 1,
259
+ "attempts" => 1,
260
+ "queue" => "default",
261
+ "id" => "123"
286
262
  )
263
+ expect(transaction).to include_params(["activejob_argument"])
287
264
  end
288
265
 
289
266
  context "with more complex params" do
@@ -296,13 +273,11 @@ describe Appsignal::Hooks::DelayedJobHook do
296
273
 
297
274
  it "adds the more complex arguments" do
298
275
  perform
299
- transaction_data = last_transaction.to_h
300
- expect(transaction_data).to include("action" => "TestClass#perform")
301
- expect(transaction_data["sample_data"]).to include(
302
- "params" => {
303
- "foo" => "Foo",
304
- "bar" => "Bar"
305
- }
276
+ transaction = last_transaction
277
+ expect(transaction).to have_action("TestClass#perform")
278
+ expect(transaction).to include_params(
279
+ "foo" => "Foo",
280
+ "bar" => "Bar"
306
281
  )
307
282
  end
308
283
 
@@ -314,13 +289,11 @@ describe Appsignal::Hooks::DelayedJobHook do
314
289
 
315
290
  it "filters selected arguments" do
316
291
  perform
317
- transaction_data = last_transaction.to_h
318
- expect(transaction_data).to include("action" => "TestClass#perform")
319
- expect(transaction_data["sample_data"]).to include(
320
- "params" => {
321
- "foo" => "[FILTERED]",
322
- "bar" => "Bar"
323
- }
292
+ transaction = last_transaction
293
+ expect(transaction).to have_action("TestClass#perform")
294
+ expect(transaction).to include_params(
295
+ "foo" => "[FILTERED]",
296
+ "bar" => "Bar"
324
297
  )
325
298
  end
326
299
  end
@@ -330,11 +303,9 @@ describe Appsignal::Hooks::DelayedJobHook do
330
303
  let(:run_at) { Time.parse("2017-01-01 10:01:00UTC") }
331
304
 
332
305
  it "reports queue_start with run_at time" do
333
- expect(Appsignal).to receive(:monitor_transaction).with(
334
- "perform_job.delayed_job",
335
- a_hash_including(:queue_start => run_at)
336
- ).and_call_original
337
306
  perform
307
+
308
+ expect(last_transaction).to have_queue_start(run_at.to_i * 1000)
338
309
  end
339
310
  end
340
311
  end
@@ -352,18 +323,10 @@ describe Appsignal::Hooks::DelayedJobHook do
352
323
  perform
353
324
  end.to raise_error(error)
354
325
 
355
- transaction_data = last_transaction.to_h
356
- expect(transaction_data).to include(
357
- "action" => "TestClass#perform",
358
- "namespace" => "background_job",
359
- "error" => {
360
- "name" => "ExampleException",
361
- "message" => "uh oh",
362
- # TODO: backtrace should be an Array of Strings
363
- # https://github.com/appsignal/appsignal-agent/issues/294
364
- "backtrace" => kind_of(String)
365
- }
366
- )
326
+ transaction = last_transaction
327
+ expect(transaction).to have_namespace("background_job")
328
+ expect(transaction).to have_action("TestClass#perform")
329
+ expect(transaction).to have_error("ExampleException", "uh oh")
367
330
  end
368
331
  end
369
332
  end
@@ -53,22 +53,13 @@ if DependencyHelper.dry_monitor_present?
53
53
 
54
54
  it "creates an sql event" do
55
55
  notifications.instrument(event_id, payload)
56
- expect(transaction.to_h["events"]).to match([
57
- {
58
- "allocation_count" => kind_of(Integer),
59
- "body" => "SELECT * FROM users",
60
- "body_format" => Appsignal::EventFormatter::SQL_BODY_FORMAT,
61
- "child_allocation_count" => kind_of(Integer),
62
- "child_duration" => kind_of(Float),
63
- "child_gc_duration" => kind_of(Float),
64
- "count" => 1,
65
- "duration" => kind_of(Float),
66
- "gc_duration" => kind_of(Float),
67
- "name" => "query.postgres",
68
- "start" => kind_of(Float),
69
- "title" => "query.postgres"
70
- }
71
- ])
56
+ expect(transaction).to include_event(
57
+ "body" => "SELECT * FROM users",
58
+ "body_format" => Appsignal::EventFormatter::SQL_BODY_FORMAT,
59
+ "count" => 1,
60
+ "name" => "query.postgres",
61
+ "title" => "query.postgres"
62
+ )
72
63
  end
73
64
  end
74
65
 
@@ -82,22 +73,13 @@ if DependencyHelper.dry_monitor_present?
82
73
 
83
74
  it "creates a generic event" do
84
75
  notifications.instrument(event_id, payload)
85
- expect(transaction.to_h["events"]).to match([
86
- {
87
- "allocation_count" => kind_of(Integer),
88
- "body" => "",
89
- "body_format" => Appsignal::EventFormatter::DEFAULT,
90
- "child_allocation_count" => kind_of(Integer),
91
- "child_duration" => kind_of(Float),
92
- "child_gc_duration" => kind_of(Float),
93
- "count" => 1,
94
- "duration" => kind_of(Float),
95
- "gc_duration" => kind_of(Float),
96
- "name" => "foo",
97
- "start" => kind_of(Float),
98
- "title" => ""
99
- }
100
- ])
76
+ expect(transaction).to include_event(
77
+ "body" => "",
78
+ "body_format" => Appsignal::EventFormatter::DEFAULT,
79
+ "count" => 1,
80
+ "name" => "foo",
81
+ "title" => ""
82
+ )
101
83
  end
102
84
  end
103
85
  end
@@ -40,12 +40,10 @@ describe Appsignal::Hooks::ExconHook do
40
40
  }
41
41
  Excon.defaults[:instrumentor].instrument("excon.request", data) {} # rubocop:disable Lint/EmptyBlock
42
42
 
43
- expect(transaction.to_h["events"]).to include(
44
- hash_including(
45
- "name" => "request.excon",
46
- "title" => "GET http://www.google.com",
47
- "body" => ""
48
- )
43
+ expect(transaction).to include_event(
44
+ "name" => "request.excon",
45
+ "title" => "GET http://www.google.com",
46
+ "body" => ""
49
47
  )
50
48
  end
51
49
 
@@ -53,12 +51,10 @@ describe Appsignal::Hooks::ExconHook do
53
51
  data = { :host => "www.google.com" }
54
52
  Excon.defaults[:instrumentor].instrument("excon.response", data) {} # rubocop:disable Lint/EmptyBlock
55
53
 
56
- expect(transaction.to_h["events"]).to include(
57
- hash_including(
58
- "name" => "response.excon",
59
- "title" => "www.google.com",
60
- "body" => ""
61
- )
54
+ expect(transaction).to include_event(
55
+ "name" => "response.excon",
56
+ "title" => "www.google.com",
57
+ "body" => ""
62
58
  )
63
59
  end
64
60
  end
@@ -1,51 +1,16 @@
1
1
  describe Appsignal::Hooks::NetHttpHook do
2
- before :context do
3
- start_agent
4
- end
2
+ before(:context) { start_agent }
5
3
 
6
- context "with Net::HTTP instrumentation enabled" do
7
- describe "#dependencies_present?" do
8
- subject { described_class.new.dependencies_present? }
4
+ describe "#dependencies_present?" do
5
+ subject { described_class.new.dependencies_present? }
9
6
 
7
+ context "with Net::HTTP instrumentation enabled" do
10
8
  it { is_expected.to be_truthy }
11
9
  end
12
10
 
13
- it "should instrument a http request" do
14
- Appsignal::Transaction.create("uuid", Appsignal::Transaction::HTTP_REQUEST, "test")
15
- expect(Appsignal::Transaction.current).to receive(:start_event)
16
- .at_least(:once)
17
- expect(Appsignal::Transaction.current).to receive(:finish_event)
18
- .at_least(:once)
19
- .with("request.net_http", "GET http://www.google.com", nil, 0)
20
-
21
- stub_request(:any, "http://www.google.com/")
22
-
23
- Net::HTTP.get_response(URI.parse("http://www.google.com"))
24
- end
25
-
26
- it "should instrument a https request" do
27
- Appsignal::Transaction.create("uuid", Appsignal::Transaction::HTTP_REQUEST, "test")
28
- expect(Appsignal::Transaction.current).to receive(:start_event)
29
- .at_least(:once)
30
- expect(Appsignal::Transaction.current).to receive(:finish_event)
31
- .at_least(:once)
32
- .with("request.net_http", "GET https://www.google.com", nil, 0)
33
-
34
- stub_request(:any, "https://www.google.com/")
35
-
36
- uri = URI.parse("https://www.google.com")
37
- http = Net::HTTP.new(uri.host, uri.port)
38
- http.use_ssl = true
39
- http.get(uri.request_uri)
40
- end
41
- end
42
-
43
- context "with Net::HTTP instrumentation disabled" do
44
- before { Appsignal.config.config_hash[:instrument_net_http] = false }
45
- after { Appsignal.config.config_hash[:instrument_net_http] = true }
46
-
47
- describe "#dependencies_present?" do
48
- subject { described_class.new.dependencies_present? }
11
+ context "with Net::HTTP instrumentation disabled" do
12
+ before { Appsignal.config.config_hash[:instrument_net_http] = false }
13
+ after { Appsignal.config.config_hash[:instrument_net_http] = true }
49
14
 
50
15
  it { is_expected.to be_falsy }
51
16
  end
@@ -1,61 +1,106 @@
1
1
  require "rake"
2
2
 
3
3
  describe Appsignal::Hooks::RakeHook do
4
+ let(:helper) { Appsignal::Integrations::RakeIntegrationHelper }
4
5
  let(:task) { Rake::Task.new("task:name", Rake::Application.new) }
5
6
  let(:arguments) { Rake::TaskArguments.new(["foo"], ["bar"]) }
6
- let(:generic_request) { Appsignal::Transaction::GenericRequest.new({}) }
7
- before(:context) { start_agent }
7
+ before do
8
+ start_agent
9
+ allow(Kernel).to receive(:at_exit)
10
+ end
11
+ around { |example| keep_transactions { example.run } }
12
+ after do
13
+ if helper.instance_variable_defined?(:@register_at_exit_hook)
14
+ helper.remove_instance_variable(:@register_at_exit_hook)
15
+ end
16
+ end
17
+
18
+ def expect_to_not_have_registered_at_exit_hook
19
+ expect(Kernel).to_not have_received(:at_exit)
20
+ end
21
+
22
+ def expect_to_have_registered_at_exit_hook
23
+ expect(Kernel).to have_received(:at_exit)
24
+ end
8
25
 
9
26
  describe "#execute" do
10
27
  context "without error" do
11
- before { expect(Appsignal).to_not receive(:stop) }
12
-
13
28
  def perform
14
29
  task.execute(arguments)
15
30
  end
16
31
 
17
- it "creates no transaction" do
18
- expect(Appsignal::Transaction).to_not receive(:new)
19
- expect { perform }.to_not(change { created_transactions })
32
+ context "with :enable_rake_performance_instrumentation == false" do
33
+ before do
34
+ Appsignal.config[:enable_rake_performance_instrumentation] = false
35
+ end
36
+
37
+ it "creates no transaction" do
38
+ expect { perform }.to_not(change { created_transactions.count })
39
+ end
40
+
41
+ it "calls the original task" do
42
+ expect(perform).to eq([])
43
+ end
44
+
45
+ it "does not register an at_exit hook" do
46
+ perform
47
+ expect_to_not_have_registered_at_exit_hook
48
+ end
20
49
  end
21
50
 
22
- it "calls the original task" do
23
- expect(perform).to eq([])
51
+ context "with :enable_rake_performance_instrumentation == true" do
52
+ before do
53
+ Appsignal.config[:enable_rake_performance_instrumentation] = true
54
+ end
55
+
56
+ it "creates a transaction" do
57
+ expect { perform }.to(change { created_transactions.count }.by(1))
58
+
59
+ transaction = last_transaction
60
+ expect(transaction).to have_id
61
+ expect(transaction).to have_namespace(Appsignal::Transaction::BACKGROUND_JOB)
62
+ expect(transaction).to have_action("task:name")
63
+ expect(transaction).to_not have_error
64
+ expect(transaction).to include_params("foo" => "bar")
65
+ expect(transaction).to include_event("name" => "task.rake")
66
+ expect(transaction).to be_completed
67
+ end
68
+
69
+ it "calls the original task" do
70
+ expect(perform).to eq([])
71
+ end
72
+
73
+ it "registers an at_exit hook" do
74
+ perform
75
+ expect_to_have_registered_at_exit_hook
76
+ end
24
77
  end
25
78
  end
26
79
 
27
80
  context "with error" do
28
- let(:error) { ExampleException }
29
81
  before do
30
- task.enhance { raise error, "my error message" }
31
- # We don't call `and_call_original` here as we don't want AppSignal to
32
- # stop and start for every spec.
33
- expect(Appsignal).to receive(:stop).with("rake")
82
+ task.enhance { raise ExampleException, "error message" }
34
83
  end
35
84
 
36
85
  def perform
37
- keep_transactions do
38
- expect { task.execute(arguments) }.to raise_error(error)
39
- end
86
+ expect { task.execute(arguments) }.to raise_error(ExampleException, "error message")
40
87
  end
41
88
 
42
89
  it "creates a background job transaction" do
43
90
  perform
44
91
 
45
- expect(last_transaction).to be_completed
46
- expect(last_transaction.to_h).to include(
47
- "id" => kind_of(String),
48
- "namespace" => Appsignal::Transaction::BACKGROUND_JOB,
49
- "action" => "task:name",
50
- "error" => {
51
- "name" => "ExampleException",
52
- "message" => "my error message",
53
- "backtrace" => kind_of(String)
54
- },
55
- "sample_data" => hash_including(
56
- "params" => { "foo" => "bar" }
57
- )
58
- )
92
+ transaction = last_transaction
93
+ expect(transaction).to have_id
94
+ expect(transaction).to have_namespace(Appsignal::Transaction::BACKGROUND_JOB)
95
+ expect(transaction).to have_action("task:name")
96
+ expect(transaction).to have_error("ExampleException", "error message")
97
+ expect(transaction).to include_params("foo" => "bar")
98
+ expect(transaction).to be_completed
99
+ end
100
+
101
+ it "registers an at_exit hook" do
102
+ perform
103
+ expect_to_have_registered_at_exit_hook
59
104
  end
60
105
 
61
106
  context "when first argument is not a `Rake::TaskArguments`" do
@@ -64,11 +109,39 @@ describe Appsignal::Hooks::RakeHook do
64
109
  it "does not add the params to the transaction" do
65
110
  perform
66
111
 
67
- expect(last_transaction.to_h).to include(
68
- "sample_data" => hash_excluding("params")
69
- )
112
+ expect(last_transaction).to_not include_params
70
113
  end
71
114
  end
72
115
  end
73
116
  end
74
117
  end
118
+
119
+ describe "Appsignal::Integrations::RakeIntegrationHelper" do
120
+ let(:helper) { Appsignal::Integrations::RakeIntegrationHelper }
121
+ describe ".register_at_exit_hook" do
122
+ before do
123
+ start_agent
124
+ allow(Appsignal).to receive(:stop)
125
+ end
126
+
127
+ it "registers the at_exit hook only once" do
128
+ allow(Kernel).to receive(:at_exit)
129
+ helper.register_at_exit_hook
130
+ helper.register_at_exit_hook
131
+ expect(Kernel).to have_received(:at_exit).once
132
+ end
133
+ end
134
+
135
+ describe ".at_exit_hook" do
136
+ let(:helper) { Appsignal::Integrations::RakeIntegrationHelper }
137
+ before do
138
+ start_agent
139
+ allow(Appsignal).to receive(:stop)
140
+ end
141
+
142
+ it "calls Appsignal.stop" do
143
+ helper.at_exit_hook
144
+ expect(Appsignal).to have_received(:stop).with("rake")
145
+ end
146
+ end
147
+ end