appsignal 3.9.2-java → 3.10.0-java

Sign up to get free protection for your applications and to get access to all the features.
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