appsignal 3.9.1-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 (94) 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 +58 -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 +3 -3
  17. data/lib/appsignal/hooks/active_job.rb +2 -1
  18. data/lib/appsignal/integrations/action_cable.rb +1 -1
  19. data/lib/appsignal/integrations/grape.rb +19 -47
  20. data/lib/appsignal/integrations/hanami.rb +27 -41
  21. data/lib/appsignal/integrations/padrino.rb +46 -43
  22. data/lib/appsignal/integrations/railtie.rb +1 -4
  23. data/lib/appsignal/integrations/resque.rb +1 -1
  24. data/lib/appsignal/integrations/sidekiq.rb +2 -4
  25. data/lib/appsignal/integrations/sinatra.rb +7 -2
  26. data/lib/appsignal/probes/gvl.rb +24 -2
  27. data/lib/appsignal/probes/sidekiq.rb +1 -1
  28. data/lib/appsignal/probes.rb +1 -1
  29. data/lib/appsignal/rack/abstract_middleware.rb +62 -28
  30. data/lib/appsignal/rack/event_handler.rb +37 -26
  31. data/lib/appsignal/rack/grape_middleware.rb +40 -0
  32. data/lib/appsignal/rack/hanami_middleware.rb +20 -0
  33. data/lib/appsignal/rack/rails_instrumentation.rb +14 -56
  34. data/lib/appsignal/utils/integration_memory_logger.rb +78 -0
  35. data/lib/appsignal/utils.rb +1 -0
  36. data/lib/appsignal/version.rb +1 -1
  37. data/lib/appsignal.rb +34 -33
  38. data/spec/.rubocop.yml +1 -1
  39. data/spec/lib/appsignal/cli/diagnose_spec.rb +1 -1
  40. data/spec/lib/appsignal/cli/install_spec.rb +3 -3
  41. data/spec/lib/appsignal/config_spec.rb +7 -5
  42. data/spec/lib/appsignal/demo_spec.rb +38 -41
  43. data/spec/lib/appsignal/hooks/action_cable_spec.rb +86 -167
  44. data/spec/lib/appsignal/hooks/active_support_notifications/finish_with_state_shared_examples.rb +8 -20
  45. data/spec/lib/appsignal/hooks/active_support_notifications/instrument_shared_examples.rb +38 -84
  46. data/spec/lib/appsignal/hooks/active_support_notifications/start_finish_shared_examples.rb +16 -37
  47. data/spec/lib/appsignal/hooks/active_support_notifications_spec.rb +4 -4
  48. data/spec/lib/appsignal/hooks/activejob_spec.rb +111 -200
  49. data/spec/lib/appsignal/hooks/delayed_job_spec.rb +54 -91
  50. data/spec/lib/appsignal/hooks/dry_monitor_spec.rb +14 -32
  51. data/spec/lib/appsignal/hooks/excon_spec.rb +8 -12
  52. data/spec/lib/appsignal/hooks/net_http_spec.rb +7 -42
  53. data/spec/lib/appsignal/hooks/rake_spec.rb +9 -19
  54. data/spec/lib/appsignal/hooks/redis_client_spec.rb +18 -30
  55. data/spec/lib/appsignal/hooks/redis_spec.rb +10 -16
  56. data/spec/lib/appsignal/hooks/resque_spec.rb +42 -62
  57. data/spec/lib/appsignal/hooks/shoryuken_spec.rb +33 -74
  58. data/spec/lib/appsignal/integrations/hanami_spec.rb +126 -64
  59. data/spec/lib/appsignal/integrations/http_spec.rb +12 -20
  60. data/spec/lib/appsignal/integrations/net_http_spec.rb +33 -0
  61. data/spec/lib/appsignal/integrations/object_spec.rb +29 -36
  62. data/spec/lib/appsignal/integrations/padrino_spec.rb +47 -70
  63. data/spec/lib/appsignal/integrations/que_spec.rb +43 -70
  64. data/spec/lib/appsignal/integrations/railtie_spec.rb +26 -67
  65. data/spec/lib/appsignal/integrations/sidekiq_spec.rb +86 -160
  66. data/spec/lib/appsignal/integrations/sinatra_spec.rb +8 -3
  67. data/spec/lib/appsignal/integrations/webmachine_spec.rb +28 -39
  68. data/spec/lib/appsignal/probes/gvl_spec.rb +80 -3
  69. data/spec/lib/appsignal/probes_spec.rb +7 -4
  70. data/spec/lib/appsignal/rack/abstract_middleware_spec.rb +215 -106
  71. data/spec/lib/appsignal/rack/event_handler_spec.rb +151 -69
  72. data/spec/lib/appsignal/rack/generic_instrumentation_spec.rb +2 -12
  73. data/spec/lib/appsignal/rack/grape_middleware_spec.rb +234 -0
  74. data/spec/lib/appsignal/rack/hanami_middleware_spec.rb +36 -0
  75. data/spec/lib/appsignal/rack/rails_instrumentation_spec.rb +67 -131
  76. data/spec/lib/appsignal/rack/sinatra_instrumentation_spec.rb +36 -44
  77. data/spec/lib/appsignal/rack/streaming_listener_spec.rb +68 -86
  78. data/spec/lib/appsignal/transaction_spec.rb +79 -93
  79. data/spec/lib/appsignal/utils/integration_memory_logger_spec.rb +163 -0
  80. data/spec/lib/appsignal_spec.rb +363 -342
  81. data/spec/support/hanami/hanami_app.rb +1 -3
  82. data/spec/support/helpers/dependency_helper.rb +6 -1
  83. data/spec/support/helpers/std_streams_helper.rb +1 -1
  84. data/spec/support/helpers/transaction_helpers.rb +8 -0
  85. data/spec/support/matchers/transaction.rb +185 -0
  86. data/spec/support/mocks/dummy_app.rb +20 -0
  87. data/spec/support/shared_examples/instrument.rb +17 -12
  88. data/spec/support/testing.rb +18 -9
  89. metadata +17 -10
  90. data/.semaphore/semaphore.yml +0 -2347
  91. data/script/lint_git +0 -22
  92. data/spec/lib/appsignal/integrations/grape_spec.rb +0 -239
  93. data/spec/support/matchers/be_completed.rb +0 -5
  94. /data/gemfiles/{hanami.gemfile → hanami-2.0.gemfile} +0 -0
@@ -22,17 +22,19 @@ describe Appsignal::Rack::EventHandler do
22
22
  event_handler_instance.on_start(request, response)
23
23
  end
24
24
 
25
+ def on_error(error)
26
+ event_handler_instance.on_error(request, response, error)
27
+ end
28
+
25
29
  describe "#on_start" do
26
30
  it "creates a new transaction" do
27
31
  expect { on_start }.to change { created_transactions.length }.by(1)
28
32
 
29
33
  transaction = last_transaction
30
- expect(transaction.to_h).to include(
31
- "id" => kind_of(String),
32
- "namespace" => Appsignal::Transaction::HTTP_REQUEST
33
- )
34
+ expect(transaction).to have_id
35
+ expect(transaction).to have_namespace(Appsignal::Transaction::HTTP_REQUEST)
34
36
 
35
- expect(Appsignal::Transaction.current).to eq(last_transaction)
37
+ expect(Appsignal::Transaction.current).to eq(transaction)
36
38
  end
37
39
 
38
40
  context "when the handler is nested in another EventHandler" do
@@ -66,6 +68,30 @@ describe Appsignal::Rack::EventHandler do
66
68
  expect(last_transaction.ext.queue_start).to eq(queue_start_time)
67
69
  end
68
70
 
71
+ context "with error inside rack.after_reply handler" do
72
+ before do
73
+ on_start
74
+ # A random spot we can access to raise an error for this test
75
+ expect(request.env[Appsignal::Rack::APPSIGNAL_TRANSACTION])
76
+ .to receive(:finish_event)
77
+ .and_raise(ExampleStandardError, "oh no")
78
+ callback = request.env[Appsignal::Rack::RACK_AFTER_REPLY].first
79
+ callback.call
80
+ end
81
+
82
+ it "completes the transaction" do
83
+ expect(last_transaction).to be_completed
84
+ end
85
+
86
+ it "logs an error" do
87
+ expect(log).to contains_log(
88
+ :error,
89
+ "Error occurred in Appsignal::Rack::EventHandler's after_reply: " \
90
+ "ExampleStandardError: oh no"
91
+ )
92
+ end
93
+ end
94
+
69
95
  it "logs errors from rack.after_reply callbacks" do
70
96
  on_start
71
97
 
@@ -95,21 +121,11 @@ describe Appsignal::Rack::EventHandler do
95
121
  end
96
122
 
97
123
  describe "#on_error" do
98
- def on_error(error)
99
- event_handler_instance.on_error(request, response, error)
100
- end
101
-
102
124
  it "reports the error" do
103
125
  on_start
104
126
  on_error(ExampleStandardError.new("the error"))
105
127
 
106
- expect(last_transaction.to_h).to include(
107
- "error" => {
108
- "name" => "ExampleStandardError",
109
- "message" => "the error",
110
- "backtrace" => kind_of(String)
111
- }
112
- )
128
+ expect(last_transaction).to have_error("ExampleStandardError", "the error")
113
129
  end
114
130
 
115
131
  context "when the handler is nested in another EventHandler" do
@@ -117,7 +133,7 @@ describe Appsignal::Rack::EventHandler do
117
133
  on_start
118
134
  described_class.new.on_error(request, response, ExampleStandardError.new("the error"))
119
135
 
120
- expect(last_transaction.to_h).to include("error" => nil)
136
+ expect(last_transaction).to_not have_error
121
137
  end
122
138
  end
123
139
 
@@ -139,8 +155,8 @@ describe Appsignal::Rack::EventHandler do
139
155
  describe "#on_finish" do
140
156
  let(:response) { Rack::Events::BufferedResponse.new(200, {}, ["body"]) }
141
157
 
142
- def on_finish
143
- event_handler_instance.on_finish(request, response)
158
+ def on_finish(given_request = request, given_response = response)
159
+ event_handler_instance.on_finish(given_request, given_response)
144
160
  end
145
161
 
146
162
  it "doesn't do anything without a transaction" do
@@ -150,30 +166,92 @@ describe Appsignal::Rack::EventHandler do
150
166
 
151
167
  on_finish
152
168
 
153
- expect(last_transaction.to_h).to include(
154
- "action" => nil,
155
- "sample_data" => {},
156
- "events" => []
157
- )
169
+ expect(last_transaction).to_not have_action
170
+ expect(last_transaction).to_not include_events
171
+ expect(last_transaction).to include("sample_data" => {})
172
+ expect(last_transaction).to_not be_completed
158
173
  end
159
174
 
160
175
  it "completes the transaction" do
161
176
  on_start
162
177
  on_finish
163
178
 
164
- expect(last_transaction.to_h).to include(
179
+ expect(last_transaction).to_not have_action
180
+ expect(last_transaction).to include_environment(
181
+ "REQUEST_METHOD" => "GET",
182
+ "PATH_INFO" => "/path"
183
+ )
184
+ expect(last_transaction).to have_queue_start(queue_start_time)
185
+ expect(last_transaction).to be_completed
186
+ end
187
+
188
+ context "without a response" do
189
+ it "completes the transaction" do
190
+ on_start
191
+ on_finish(request, nil)
192
+
165
193
  # The action is not set on purpose, as we can't set a normalized route
166
194
  # It requires the app to set an action name
167
- "action" => nil,
168
- "sample_data" => hash_including(
169
- "environment" => {
170
- "REQUEST_METHOD" => "GET",
171
- "PATH_INFO" => "/path"
172
- }
195
+ expect(last_transaction).to_not have_action
196
+ expect(last_transaction).to include_environment(
197
+ "REQUEST_METHOD" => "GET",
198
+ "PATH_INFO" => "/path"
173
199
  )
174
- )
175
- expect(last_transaction.ext.queue_start).to eq(queue_start_time)
176
- expect(last_transaction).to be_completed
200
+ expect(last_transaction).to have_queue_start(queue_start_time)
201
+ expect(last_transaction).to be_completed
202
+ end
203
+
204
+ it "does not set a response_status tag" do
205
+ on_start
206
+ on_finish(request, nil)
207
+
208
+ expect(last_transaction).to_not include_tags("response_status" => anything)
209
+ end
210
+
211
+ it "does not report a response_status counter metric" do
212
+ expect(Appsignal).to_not receive(:increment_counter)
213
+ .with(:response_status, anything, anything)
214
+
215
+ on_start
216
+ on_finish(request, nil)
217
+ end
218
+
219
+ context "with an error previously recorded by on_error" do
220
+ it "sets response status 500 as a tag" do
221
+ on_start
222
+ on_error(ExampleStandardError.new("the error"))
223
+ on_finish(request, nil)
224
+
225
+ expect(last_transaction).to include_tags("response_status" => 500)
226
+ end
227
+
228
+ it "increments the response status counter for response status 500" do
229
+ expect(Appsignal).to receive(:increment_counter)
230
+ .with(:response_status, 1, :status => 500, :namespace => :web)
231
+
232
+ on_start
233
+ on_error(ExampleStandardError.new("the error"))
234
+ on_finish(request, nil)
235
+ end
236
+ end
237
+ end
238
+
239
+ context "with error inside on_finish handler" do
240
+ before do
241
+ on_start
242
+ # A random spot we can access to raise an error for this test
243
+ expect(Appsignal).to receive(:increment_counter).and_raise(ExampleStandardError, "oh no")
244
+ on_finish
245
+ end
246
+
247
+ it "completes the transaction" do
248
+ expect(last_transaction).to be_completed
249
+ end
250
+
251
+ it "logs an error" do
252
+ expect(log).to contains_log(:error,
253
+ "Error occurred in Appsignal::Rack::EventHandler#on_finish: ExampleStandardError: oh no")
254
+ end
177
255
  end
178
256
 
179
257
  context "when the handler is nested in another EventHandler" do
@@ -181,12 +259,10 @@ describe Appsignal::Rack::EventHandler do
181
259
  on_start
182
260
  described_class.new.on_finish(request, response)
183
261
 
184
- expect(last_transaction.to_h).to include(
185
- "action" => nil,
186
- "metadata" => {},
187
- "sample_data" => {},
188
- "events" => []
189
- )
262
+ expect(last_transaction).to_not have_action
263
+ expect(last_transaction).to_not include_metadata
264
+ expect(last_transaction).to_not include_events
265
+ expect(last_transaction.to_h).to include("sample_data" => {})
190
266
  expect(last_transaction).to_not be_completed
191
267
  end
192
268
  end
@@ -196,49 +272,55 @@ describe Appsignal::Rack::EventHandler do
196
272
  last_transaction.set_action("My action")
197
273
  on_finish
198
274
 
199
- expect(last_transaction.to_h).to include(
200
- "action" => "My action"
201
- )
275
+ expect(last_transaction).to have_action("My action")
202
276
  end
203
277
 
204
278
  it "finishes the process_request.rack event" do
205
279
  on_start
206
280
  on_finish
207
281
 
208
- expect(last_transaction.to_h).to include(
209
- "events" => [
210
- hash_including(
211
- "name" => "process_request.rack",
212
- "title" => "",
213
- "body" => "",
214
- "body_format" => Appsignal::EventFormatter::DEFAULT
215
- )
216
- ]
217
- )
282
+ expect(last_transaction).to include_event("name" => "process_request.rack")
218
283
  end
219
284
 
220
- it "sets the response status as a tag" do
221
- on_start
222
- on_finish
285
+ context "with response" do
286
+ it "sets the response status as a tag" do
287
+ on_start
288
+ on_finish
223
289
 
224
- expect(last_transaction.to_h).to include(
225
- "sample_data" => hash_including(
226
- "tags" => { "response_status" => 200 }
227
- )
228
- )
229
- end
290
+ expect(last_transaction).to include_tags("response_status" => 200)
291
+ end
230
292
 
231
- it "increments the response status counter for response status" do
232
- expect(Appsignal).to receive(:increment_counter)
233
- .with(:response_status, 1, :status => 200, :namespace => :web)
293
+ it "increments the response status counter for response status" do
294
+ expect(Appsignal).to receive(:increment_counter)
295
+ .with(:response_status, 1, :status => 200, :namespace => :web)
234
296
 
235
- on_start
236
- on_finish
297
+ on_start
298
+ on_finish
299
+ end
300
+
301
+ context "with an error previously recorded by on_error" do
302
+ it "sets response status from the response as a tag" do
303
+ on_start
304
+ on_error(ExampleStandardError.new("the error"))
305
+ on_finish
306
+
307
+ expect(last_transaction).to include_tags("response_status" => 200)
308
+ end
309
+
310
+ it "increments the response status counter based on the response" do
311
+ expect(Appsignal).to receive(:increment_counter)
312
+ .with(:response_status, 1, :status => 200, :namespace => :web)
313
+
314
+ on_start
315
+ on_error(ExampleStandardError.new("the error"))
316
+ on_finish
317
+ end
318
+ end
237
319
  end
238
320
 
239
321
  it "logs an error in case of an error" do
240
- expect(Appsignal::Transaction)
241
- .to receive(:complete_current!).and_raise(ExampleStandardError, "oh no")
322
+ # A random spot we can access to raise an error for this test
323
+ expect(Appsignal).to receive(:increment_counter).and_raise(ExampleStandardError, "oh no")
242
324
 
243
325
  on_start
244
326
  on_finish
@@ -14,17 +14,7 @@ describe Appsignal::Rack::GenericInstrumentation do
14
14
  it "reports a process_action.generic event" do
15
15
  make_request(env)
16
16
 
17
- expect(last_transaction.to_h).to include(
18
- "events" => [
19
- hash_including(
20
- "body" => "",
21
- "body_format" => Appsignal::EventFormatter::DEFAULT,
22
- "count" => 1,
23
- "name" => "process_action.generic",
24
- "title" => ""
25
- )
26
- ]
27
- )
17
+ expect(last_transaction).to include_event("name" => "process_action.generic")
28
18
  end
29
19
  end
30
20
 
@@ -32,7 +22,7 @@ describe Appsignal::Rack::GenericInstrumentation do
32
22
  it "reports 'unknown' as the action name" do
33
23
  make_request(env)
34
24
 
35
- expect(last_transaction.to_h).to include("action" => "unknown")
25
+ expect(last_transaction).to have_action("unknown")
36
26
  end
37
27
  end
38
28
  end
@@ -0,0 +1,234 @@
1
+ if DependencyHelper.grape_present?
2
+ require "appsignal/integrations/grape"
3
+
4
+ context "Appsignal::Grape::Middleware constant" do
5
+ let(:err_stream) { std_stream }
6
+ let(:stderr) { err_stream.read }
7
+
8
+ it "returns the Probes constant calling the Minutely constant" do
9
+ silence { expect(Appsignal::Grape::Middleware).to be(Appsignal::Rack::GrapeMiddleware) }
10
+ end
11
+
12
+ it "prints a deprecation warning to STDERR" do
13
+ capture_std_streams(std_stream, err_stream) do
14
+ expect(Appsignal::Grape::Middleware).to be(Appsignal::Rack::GrapeMiddleware)
15
+ end
16
+
17
+ expect(stderr).to include(
18
+ "appsignal WARNING: The constant Appsignal::Grape::Middleware has been deprecated."
19
+ )
20
+ end
21
+
22
+ it "logs a warning" do
23
+ logs =
24
+ capture_logs do
25
+ silence do
26
+ expect(Appsignal::Grape::Middleware).to be(Appsignal::Rack::GrapeMiddleware)
27
+ end
28
+ end
29
+
30
+ expect(logs).to contains_log(
31
+ :warn,
32
+ "The constant Appsignal::Grape::Middleware has been deprecated."
33
+ )
34
+ end
35
+ end
36
+
37
+ describe Appsignal::Rack::GrapeMiddleware do
38
+ let(:app) do
39
+ Class.new(::Grape::API) do
40
+ format :json
41
+ post :ping do
42
+ { :message => "Hello world!" }
43
+ end
44
+ end
45
+ end
46
+ let(:api_endpoint) { app.endpoints.first }
47
+ let(:env) do
48
+ http_request_env_with_data \
49
+ "api.endpoint" => api_endpoint,
50
+ "REQUEST_METHOD" => "POST",
51
+ :path => "/ping"
52
+ end
53
+ let(:middleware) { Appsignal::Rack::GrapeMiddleware.new(api_endpoint) }
54
+ let(:transaction) { http_request_transaction }
55
+ before(:context) { start_agent }
56
+ around do |example|
57
+ GrapeExample = Module.new
58
+ GrapeExample.send(:const_set, :Api, app)
59
+ keep_transactions { example.run }
60
+ Object.send(:remove_const, :GrapeExample)
61
+ end
62
+
63
+ def make_request(env)
64
+ middleware.call(env)
65
+ end
66
+
67
+ def make_request_with_exception(env, exception_class, exception_message)
68
+ expect do
69
+ middleware.call(env)
70
+ end.to raise_error(exception_class, exception_message)
71
+ end
72
+
73
+ context "with error" do
74
+ let(:app) do
75
+ Class.new(::Grape::API) do
76
+ format :json
77
+ post :ping do
78
+ raise ExampleException, "error message"
79
+ end
80
+ end
81
+ end
82
+
83
+ it "sets the error" do
84
+ make_request_with_exception(env, ExampleException, "error message")
85
+
86
+ expect(last_transaction).to have_error("ExampleException", "error message")
87
+ end
88
+
89
+ context "with env['grape.skip_appsignal_error'] = true" do
90
+ let(:app) do
91
+ Class.new(::Grape::API) do
92
+ format :json
93
+ post :ping do
94
+ env["grape.skip_appsignal_error"] = true
95
+ raise ExampleException, "error message"
96
+ end
97
+ end
98
+ end
99
+
100
+ it "does not add the error" do
101
+ make_request_with_exception(env, ExampleException, "error message")
102
+
103
+ expect(last_transaction).to_not have_error
104
+ end
105
+ end
106
+ end
107
+
108
+ context "with route" do
109
+ let(:app) do
110
+ Class.new(::Grape::API) do
111
+ route([:get, :post], "hello") do
112
+ "Hello!"
113
+ end
114
+ end
115
+ end
116
+ let(:env) do
117
+ http_request_env_with_data \
118
+ "api.endpoint" => api_endpoint,
119
+ "REQUEST_METHOD" => "GET",
120
+ :path => ""
121
+ end
122
+
123
+ it "sets non-unique route path" do
124
+ make_request(env)
125
+
126
+ expect(last_transaction).to have_action("GET::GrapeExample::Api#/hello")
127
+ expect(last_transaction).to include_metadata("path" => "/hello", "method" => "GET")
128
+ end
129
+ end
130
+
131
+ context "with route_param" do
132
+ let(:app) do
133
+ Class.new(::Grape::API) do
134
+ format :json
135
+ resource :users do
136
+ route_param :id do
137
+ get do
138
+ { :name => "Tom" }
139
+ end
140
+ end
141
+ end
142
+ end
143
+ end
144
+ let(:env) do
145
+ http_request_env_with_data \
146
+ "api.endpoint" => api_endpoint,
147
+ "REQUEST_METHOD" => "GET",
148
+ :path => ""
149
+ end
150
+
151
+ it "sets non-unique route_param path" do
152
+ make_request(env)
153
+
154
+ expect(last_transaction).to have_action("GET::GrapeExample::Api#/users/:id/")
155
+ expect(last_transaction).to include_metadata("path" => "/users/:id/", "method" => "GET")
156
+ end
157
+ end
158
+
159
+ context "with namespaced path" do
160
+ context "with symbols" do
161
+ let(:app) do
162
+ Class.new(::Grape::API) do
163
+ format :json
164
+ namespace :v1 do
165
+ namespace :beta do
166
+ post :ping do
167
+ { :message => "Hello namespaced world!" }
168
+ end
169
+ end
170
+ end
171
+ end
172
+ end
173
+
174
+ it "sets namespaced path" do
175
+ make_request(env)
176
+
177
+ expect(last_transaction).to have_action("POST::GrapeExample::Api#/v1/beta/ping")
178
+ expect(last_transaction).to include_metadata("path" => "/v1/beta/ping",
179
+ "method" => "POST")
180
+ end
181
+ end
182
+
183
+ context "with strings" do
184
+ context "without / prefix" do
185
+ let(:app) do
186
+ Class.new(::Grape::API) do
187
+ format :json
188
+ namespace "v1" do
189
+ namespace "beta" do
190
+ post "ping" do
191
+ { :message => "Hello namespaced world!" }
192
+ end
193
+ end
194
+ end
195
+ end
196
+ end
197
+
198
+ it "sets namespaced path" do
199
+ make_request(env)
200
+
201
+ expect(last_transaction).to have_action("POST::GrapeExample::Api#/v1/beta/ping")
202
+ expect(last_transaction).to include_metadata(
203
+ "path" => "/v1/beta/ping",
204
+ "method" => "POST"
205
+ )
206
+ end
207
+ end
208
+
209
+ context "with / prefix" do
210
+ let(:app) do
211
+ Class.new(::Grape::API) do
212
+ format :json
213
+ namespace "/v1" do
214
+ namespace "/beta" do
215
+ post "/ping" do
216
+ { :message => "Hello namespaced world!" }
217
+ end
218
+ end
219
+ end
220
+ end
221
+ end
222
+
223
+ it "sets namespaced path" do
224
+ make_request(env)
225
+
226
+ expect(last_transaction).to have_action("POST::GrapeExample::Api#/v1/beta/ping")
227
+ expect(last_transaction).to include_metadata("path" => "/v1/beta/ping",
228
+ "method" => "POST")
229
+ end
230
+ end
231
+ end
232
+ end
233
+ end
234
+ end
@@ -0,0 +1,36 @@
1
+ require "appsignal/rack/hanami_middleware"
2
+
3
+ if DependencyHelper.hanami2_present?
4
+ describe Appsignal::Rack::HanamiMiddleware do
5
+ let(:app) { double(:call => true) }
6
+ let(:router_params) { { "param1" => "value1", "param2" => "value2" } }
7
+ let(:env) do
8
+ Rack::MockRequest.env_for(
9
+ "/some/path",
10
+ "router.params" => router_params
11
+ )
12
+ end
13
+ let(:middleware) { Appsignal::Rack::HanamiMiddleware.new(app, {}) }
14
+
15
+ before(:context) { start_agent }
16
+ around { |example| keep_transactions { example.run } }
17
+
18
+ def make_request(env)
19
+ middleware.call(env)
20
+ end
21
+
22
+ context "with params" do
23
+ it "sets request parameters on the transaction" do
24
+ make_request(env)
25
+
26
+ expect(last_transaction).to include_params("param1" => "value1", "param2" => "value2")
27
+ end
28
+ end
29
+
30
+ it "reports a process_action.hanami event" do
31
+ make_request(env)
32
+
33
+ expect(last_transaction).to include_event("name" => "process_action.hanami")
34
+ end
35
+ end
36
+ end