appsignal 3.9.2-java → 3.9.3-java

Sign up to get free protection for your applications and to get access to all the features.
Files changed (89) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/ci.yml +3135 -0
  3. data/.rubocop.yml +28 -20
  4. data/.rubocop_todo.yml +7 -33
  5. data/CHANGELOG.md +38 -0
  6. data/Rakefile +79 -64
  7. data/appsignal.gemspec +1 -1
  8. data/build_matrix.yml +109 -179
  9. data/ext/base.rb +1 -1
  10. data/gemfiles/hanami-2.1.gemfile +7 -0
  11. data/lib/appsignal/cli/diagnose.rb +1 -1
  12. data/lib/appsignal/config.rb +1 -1
  13. data/lib/appsignal/demo.rb +0 -1
  14. data/lib/appsignal/environment.rb +5 -1
  15. data/lib/appsignal/extension/jruby.rb +1 -1
  16. data/lib/appsignal/helpers/instrumentation.rb +1 -1
  17. data/lib/appsignal/integrations/grape.rb +19 -47
  18. data/lib/appsignal/integrations/hanami.rb +8 -7
  19. data/lib/appsignal/integrations/padrino.rb +46 -43
  20. data/lib/appsignal/integrations/railtie.rb +0 -3
  21. data/lib/appsignal/integrations/sinatra.rb +0 -1
  22. data/lib/appsignal/probes/gvl.rb +24 -2
  23. data/lib/appsignal/probes/sidekiq.rb +1 -1
  24. data/lib/appsignal/probes.rb +1 -1
  25. data/lib/appsignal/rack/abstract_middleware.rb +62 -28
  26. data/lib/appsignal/rack/event_handler.rb +12 -3
  27. data/lib/appsignal/rack/grape_middleware.rb +40 -0
  28. data/lib/appsignal/rack/hanami_middleware.rb +1 -11
  29. data/lib/appsignal/rack/rails_instrumentation.rb +14 -55
  30. data/lib/appsignal/utils/integration_memory_logger.rb +78 -0
  31. data/lib/appsignal/utils.rb +1 -0
  32. data/lib/appsignal/version.rb +1 -1
  33. data/lib/appsignal.rb +34 -33
  34. data/spec/.rubocop.yml +1 -1
  35. data/spec/lib/appsignal/cli/diagnose_spec.rb +1 -1
  36. data/spec/lib/appsignal/cli/install_spec.rb +3 -3
  37. data/spec/lib/appsignal/config_spec.rb +7 -5
  38. data/spec/lib/appsignal/demo_spec.rb +38 -41
  39. data/spec/lib/appsignal/hooks/action_cable_spec.rb +86 -167
  40. data/spec/lib/appsignal/hooks/active_support_notifications/finish_with_state_shared_examples.rb +8 -20
  41. data/spec/lib/appsignal/hooks/active_support_notifications/instrument_shared_examples.rb +38 -84
  42. data/spec/lib/appsignal/hooks/active_support_notifications/start_finish_shared_examples.rb +16 -37
  43. data/spec/lib/appsignal/hooks/active_support_notifications_spec.rb +4 -4
  44. data/spec/lib/appsignal/hooks/activejob_spec.rb +111 -200
  45. data/spec/lib/appsignal/hooks/delayed_job_spec.rb +54 -91
  46. data/spec/lib/appsignal/hooks/dry_monitor_spec.rb +14 -32
  47. data/spec/lib/appsignal/hooks/excon_spec.rb +8 -12
  48. data/spec/lib/appsignal/hooks/net_http_spec.rb +7 -42
  49. data/spec/lib/appsignal/hooks/rake_spec.rb +9 -19
  50. data/spec/lib/appsignal/hooks/redis_client_spec.rb +18 -30
  51. data/spec/lib/appsignal/hooks/redis_spec.rb +10 -16
  52. data/spec/lib/appsignal/hooks/resque_spec.rb +42 -62
  53. data/spec/lib/appsignal/hooks/shoryuken_spec.rb +33 -74
  54. data/spec/lib/appsignal/integrations/hanami_spec.rb +79 -21
  55. data/spec/lib/appsignal/integrations/http_spec.rb +12 -20
  56. data/spec/lib/appsignal/integrations/net_http_spec.rb +33 -0
  57. data/spec/lib/appsignal/integrations/object_spec.rb +29 -36
  58. data/spec/lib/appsignal/integrations/padrino_spec.rb +47 -70
  59. data/spec/lib/appsignal/integrations/que_spec.rb +43 -70
  60. data/spec/lib/appsignal/integrations/railtie_spec.rb +26 -67
  61. data/spec/lib/appsignal/integrations/sidekiq_spec.rb +86 -160
  62. data/spec/lib/appsignal/integrations/sinatra_spec.rb +0 -1
  63. data/spec/lib/appsignal/integrations/webmachine_spec.rb +28 -39
  64. data/spec/lib/appsignal/probes/gvl_spec.rb +80 -3
  65. data/spec/lib/appsignal/probes_spec.rb +7 -4
  66. data/spec/lib/appsignal/rack/abstract_middleware_spec.rb +215 -106
  67. data/spec/lib/appsignal/rack/event_handler_spec.rb +81 -78
  68. data/spec/lib/appsignal/rack/generic_instrumentation_spec.rb +2 -12
  69. data/spec/lib/appsignal/rack/grape_middleware_spec.rb +234 -0
  70. data/spec/lib/appsignal/rack/hanami_middleware_spec.rb +2 -16
  71. data/spec/lib/appsignal/rack/rails_instrumentation_spec.rb +67 -131
  72. data/spec/lib/appsignal/rack/sinatra_instrumentation_spec.rb +36 -44
  73. data/spec/lib/appsignal/rack/streaming_listener_spec.rb +68 -86
  74. data/spec/lib/appsignal/transaction_spec.rb +76 -90
  75. data/spec/lib/appsignal/utils/integration_memory_logger_spec.rb +163 -0
  76. data/spec/lib/appsignal_spec.rb +363 -342
  77. data/spec/support/helpers/dependency_helper.rb +6 -1
  78. data/spec/support/helpers/std_streams_helper.rb +1 -1
  79. data/spec/support/helpers/transaction_helpers.rb +8 -0
  80. data/spec/support/matchers/transaction.rb +185 -0
  81. data/spec/support/mocks/dummy_app.rb +20 -0
  82. data/spec/support/shared_examples/instrument.rb +17 -12
  83. data/spec/support/testing.rb +18 -9
  84. metadata +15 -10
  85. data/.semaphore/semaphore.yml +0 -2347
  86. data/script/lint_git +0 -22
  87. data/spec/lib/appsignal/integrations/grape_spec.rb +0 -239
  88. data/spec/support/matchers/be_completed.rb +0 -5
  89. /data/gemfiles/{hanami.gemfile → hanami-2.0.gemfile} +0 -0
@@ -4,6 +4,13 @@ describe Appsignal::Probes::GvlProbe do
4
4
 
5
5
  let(:hostname) { "some-host" }
6
6
 
7
+ around do |example|
8
+ real_program_name = $PROGRAM_NAME
9
+ example.run
10
+ ensure
11
+ $PROGRAM_NAME = real_program_name
12
+ end
13
+
7
14
  def gauges_for(metric)
8
15
  gauges = appsignal_mock.gauges.select do |gauge|
9
16
  gauge[0] == metric
@@ -14,7 +21,7 @@ describe Appsignal::Probes::GvlProbe do
14
21
  end
15
22
  end
16
23
 
17
- after(:each) { FakeGVLTools.reset }
24
+ after { FakeGVLTools.reset }
18
25
 
19
26
  it "gauges the global timer delta" do
20
27
  FakeGVLTools::GlobalTimer.monotonic_time = 100_000_000
@@ -26,6 +33,11 @@ describe Appsignal::Probes::GvlProbe do
26
33
  probe.call
27
34
 
28
35
  expect(gauges_for("gvl_global_timer")).to eq [
36
+ [200, {
37
+ :hostname => hostname,
38
+ :process_name => "rspec",
39
+ :process_id => Process.pid
40
+ }],
29
41
  [200, { :hostname => hostname }]
30
42
  ]
31
43
  end
@@ -58,7 +70,7 @@ describe Appsignal::Probes::GvlProbe do
58
70
  end
59
71
 
60
72
  context "when the waiting threads count is enabled" do
61
- before(:each) do
73
+ before do
62
74
  FakeGVLTools::WaitingThreads.enabled = true
63
75
  end
64
76
 
@@ -67,13 +79,18 @@ describe Appsignal::Probes::GvlProbe do
67
79
  probe.call
68
80
 
69
81
  expect(gauges_for("gvl_waiting_threads")).to eq [
82
+ [3, {
83
+ :hostname => hostname,
84
+ :process_name => "rspec",
85
+ :process_id => Process.pid
86
+ }],
70
87
  [3, { :hostname => hostname }]
71
88
  ]
72
89
  end
73
90
  end
74
91
 
75
92
  context "when the waiting threads count is disabled" do
76
- before(:each) do
93
+ before do
77
94
  FakeGVLTools::WaitingThreads.enabled = false
78
95
  end
79
96
 
@@ -84,4 +101,64 @@ describe Appsignal::Probes::GvlProbe do
84
101
  expect(gauges_for("gvl_waiting_threads")).to be_empty
85
102
  end
86
103
  end
104
+
105
+ context "when the process name is a custom value" do
106
+ before do
107
+ FakeGVLTools::WaitingThreads.enabled = true
108
+ end
109
+
110
+ it "uses only the first word as the process name" do
111
+ $PROGRAM_NAME = "sidekiq 7.1.6 app [0 of 5 busy]"
112
+ probe.call
113
+
114
+ expect(gauges_for("gvl_waiting_threads")).to eq [
115
+ [0, {
116
+ :hostname => hostname,
117
+ :process_name => "sidekiq",
118
+ :process_id => Process.pid
119
+ }],
120
+ [0, { :hostname => hostname }]
121
+ ]
122
+ end
123
+ end
124
+
125
+ context "when the process name is a path" do
126
+ before do
127
+ FakeGVLTools::WaitingThreads.enabled = true
128
+ end
129
+
130
+ it "uses only the binary name as the process name" do
131
+ $PROGRAM_NAME = "/foo/folder with spaces/bin/rails"
132
+ probe.call
133
+
134
+ expect(gauges_for("gvl_waiting_threads")).to eq [
135
+ [0, {
136
+ :hostname => hostname,
137
+ :process_name => "rails",
138
+ :process_id => Process.pid
139
+ }],
140
+ [0, { :hostname => hostname }]
141
+ ]
142
+ end
143
+ end
144
+
145
+ context "when the process name is an empty string" do
146
+ before do
147
+ FakeGVLTools::WaitingThreads.enabled = true
148
+ end
149
+
150
+ it "uses [unknown process] as the process name" do
151
+ $PROGRAM_NAME = ""
152
+ probe.call
153
+
154
+ expect(gauges_for("gvl_waiting_threads")).to eq [
155
+ [0, {
156
+ :hostname => hostname,
157
+ :process_name => "[unknown process]",
158
+ :process_id => Process.pid
159
+ }],
160
+ [0, { :hostname => hostname }]
161
+ ]
162
+ end
163
+ end
87
164
  end
@@ -20,7 +20,7 @@ describe Appsignal::Probes do
20
20
  .to include("appsignal WARNING: The constant Appsignal::Minutely has been deprecated.")
21
21
  end
22
22
 
23
- it "logs a warning to STDERR" do
23
+ it "logs a warning" do
24
24
  logs =
25
25
  capture_logs do
26
26
  silence do
@@ -28,7 +28,10 @@ describe Appsignal::Probes do
28
28
  end
29
29
  end
30
30
 
31
- expect(logs).to include("The constant Appsignal::Minutely has been deprecated.")
31
+ expect(logs).to contains_log(
32
+ :warn,
33
+ "The constant Appsignal::Minutely has been deprecated."
34
+ )
32
35
  end
33
36
  end
34
37
 
@@ -78,7 +81,7 @@ describe Appsignal::Probes do
78
81
  describe ".started?" do
79
82
  it "returns true when the probes thread has been started" do
80
83
  expect(Appsignal::Probes.started?).to be_falsy
81
- Appsignal::Probes.register :my_probe, (lambda {})
84
+ Appsignal::Probes.register :my_probe, lambda {}
82
85
  Appsignal::Probes.start
83
86
  expect(Appsignal::Probes.started?).to be_truthy
84
87
  end
@@ -475,7 +478,7 @@ describe Appsignal::Probes do
475
478
  probe = lambda {}
476
479
  collection.internal_register :my_probe, probe
477
480
  list = []
478
- collection.each do |name, p|
481
+ collection.each do |name, p| # rubocop:disable Style/MapIntoArray
479
482
  list << [name, p]
480
483
  end
481
484
  expect(list).to eql([[:my_probe, probe]])
@@ -1,5 +1,5 @@
1
1
  describe Appsignal::Rack::AbstractMiddleware do
2
- let(:app) { double(:call => true) }
2
+ let(:app) { DummyApp.new }
3
3
  let(:request_path) { "/some/path" }
4
4
  let(:env) do
5
5
  Rack::MockRequest.env_for(
@@ -9,176 +9,235 @@ describe Appsignal::Rack::AbstractMiddleware do
9
9
  )
10
10
  end
11
11
  let(:options) { {} }
12
- let(:middleware) { Appsignal::Rack::AbstractMiddleware.new(app, options) }
12
+ let(:middleware) { described_class.new(app, options) }
13
13
 
14
14
  before(:context) { start_agent }
15
15
  around { |example| keep_transactions { example.run } }
16
16
 
17
- def make_request(env)
17
+ def make_request
18
18
  middleware.call(env)
19
19
  end
20
20
 
21
- def make_request_with_error(env, error)
22
- expect { make_request(env) }.to raise_error(error)
21
+ def make_request_with_error(error_class, error_message)
22
+ expect { make_request }.to raise_error(error_class, error_message)
23
23
  end
24
24
 
25
25
  describe "#call" do
26
- context "when appsignal is not active" do
26
+ context "when not active" do
27
27
  before { allow(Appsignal).to receive(:active?).and_return(false) }
28
28
 
29
- it "does not instrument requests" do
30
- expect { make_request(env) }.to_not(change { created_transactions.count })
29
+ it "does not instrument the request" do
30
+ expect { make_request }.to_not(change { created_transactions.count })
31
31
  end
32
32
 
33
33
  it "calls the next middleware in the stack" do
34
- expect(app).to receive(:call).with(env)
35
- make_request(env)
34
+ make_request
35
+ expect(app).to be_called
36
36
  end
37
37
  end
38
38
 
39
39
  context "when appsignal is active" do
40
40
  before { allow(Appsignal).to receive(:active?).and_return(true) }
41
41
 
42
- it "calls the next middleware in the stack" do
43
- make_request(env)
42
+ it "creates a transaction for the request" do
43
+ expect { make_request }.to(change { created_transactions.count }.by(1))
44
44
 
45
- expect(app).to have_received(:call).with(env)
45
+ expect(last_transaction).to have_namespace(Appsignal::Transaction::HTTP_REQUEST)
46
46
  end
47
47
 
48
- context "without an exception" do
49
- it "create a transaction for the request" do
50
- expect { make_request(env) }.to(change { created_transactions.count }.by(1))
48
+ context "without an error" do
49
+ before { make_request }
51
50
 
52
- expect(last_transaction.to_h).to include(
53
- "namespace" => Appsignal::Transaction::HTTP_REQUEST,
54
- "action" => nil,
55
- "error" => nil
56
- )
51
+ it "calls the next middleware in the stack" do
52
+ expect(app).to be_called
57
53
  end
58
54
 
59
- it "reports a process.abstract event" do
60
- make_request(env)
55
+ it "does not record an error" do
56
+ expect(last_transaction).to_not have_error
57
+ end
61
58
 
62
- expect(last_transaction.to_h).to include(
63
- "events" => [
64
- hash_including(
65
- "body" => "",
66
- "body_format" => Appsignal::EventFormatter::DEFAULT,
67
- "count" => 1,
68
- "name" => "process.abstract",
69
- "title" => ""
70
- )
71
- ]
72
- )
59
+ it "records an instrumentation event" do
60
+ expect(last_transaction).to include_event(:name => "process.abstract")
73
61
  end
74
62
 
75
63
  it "completes the transaction" do
76
- make_request(env)
77
64
  expect(last_transaction).to be_completed
65
+ expect(Appsignal::Transaction.current)
66
+ .to be_kind_of(Appsignal::Transaction::NilTransaction)
67
+ end
68
+
69
+ context "when instrument_span_name option is nil" do
70
+ let(:options) { { :instrument_span_name => nil } }
71
+
72
+ it "does not record an instrumentation event" do
73
+ expect(last_transaction).to_not include_events
74
+ end
78
75
  end
79
76
  end
80
77
 
81
- context "with an exception" do
78
+ context "with an error" do
82
79
  let(:error) { ExampleException.new("error message") }
83
- before do
84
- allow(app).to receive(:call).and_raise(error)
85
- expect { make_request_with_error(env, error) }
80
+ let(:app) { lambda { |_env| raise ExampleException, "error message" } }
81
+
82
+ it "create a transaction for the request" do
83
+ expect { make_request_with_error(ExampleException, "error message") }
86
84
  .to(change { created_transactions.count }.by(1))
87
- end
88
85
 
89
- it "creates a transaction for the request and records the exception" do
90
- expect(last_transaction.to_h).to include(
91
- "error" => hash_including(
92
- "name" => "ExampleException",
93
- "message" => "error message"
94
- )
95
- )
86
+ expect(last_transaction).to have_namespace(Appsignal::Transaction::HTTP_REQUEST)
96
87
  end
97
88
 
98
- it "completes the transaction" do
99
- expect(last_transaction).to be_completed
89
+ describe "error" do
90
+ before do
91
+ make_request_with_error(ExampleException, "error message")
92
+ end
93
+
94
+ it "records the error" do
95
+ expect(last_transaction).to have_error("ExampleException", "error message")
96
+ end
97
+
98
+ it "completes the transaction" do
99
+ expect(last_transaction).to be_completed
100
+ expect(Appsignal::Transaction.current)
101
+ .to be_kind_of(Appsignal::Transaction::NilTransaction)
102
+ end
103
+
104
+ context "with :report_errors set to false" do
105
+ let(:app) { lambda { |_env| raise ExampleException, "error message" } }
106
+ let(:options) { { :report_errors => false } }
107
+
108
+ it "does not record the exception on the transaction" do
109
+ expect(last_transaction).to_not have_error
110
+ end
111
+ end
112
+
113
+ context "with :report_errors set to true" do
114
+ let(:app) { lambda { |_env| raise ExampleException, "error message" } }
115
+ let(:options) { { :report_errors => true } }
116
+
117
+ it "records the exception on the transaction" do
118
+ expect(last_transaction).to have_error("ExampleException", "error message")
119
+ end
120
+ end
121
+
122
+ context "with :report_errors set to a lambda that returns false" do
123
+ let(:app) { lambda { |_env| raise ExampleException, "error message" } }
124
+ let(:options) { { :report_errors => lambda { |_env| false } } }
125
+
126
+ it "does not record the exception on the transaction" do
127
+ expect(last_transaction).to_not have_error
128
+ end
129
+ end
130
+
131
+ context "with :report_errors set to a lambda that returns true" do
132
+ let(:app) { lambda { |_env| raise ExampleException, "error message" } }
133
+ let(:options) { { :report_errors => lambda { |_env| true } } }
134
+
135
+ it "records the exception on the transaction" do
136
+ expect(last_transaction).to have_error("ExampleException", "error message")
137
+ end
138
+ end
100
139
  end
101
140
  end
102
141
 
103
142
  context "without action name metadata" do
104
143
  it "reports no action name" do
105
- make_request(env)
144
+ make_request
106
145
 
107
- expect(last_transaction.to_h).to include("action" => nil)
146
+ expect(last_transaction).to_not have_action
108
147
  end
109
148
  end
110
149
 
111
150
  context "with appsignal.route env" do
112
- before do
113
- env["appsignal.route"] = "POST /my-route"
114
- end
115
-
116
151
  it "reports the appsignal.route value as the action name" do
117
- make_request(env)
152
+ env["appsignal.route"] = "POST /my-route"
153
+ make_request
118
154
 
119
- expect(last_transaction.to_h).to include("action" => "POST /my-route")
155
+ expect(last_transaction).to have_action("POST /my-route")
120
156
  end
121
157
  end
122
158
 
123
159
  context "with appsignal.action env" do
124
- before do
125
- env["appsignal.action"] = "POST /my-action"
126
- end
127
-
128
160
  it "reports the appsignal.route value as the action name" do
129
- make_request(env)
161
+ env["appsignal.action"] = "POST /my-action"
162
+ make_request
130
163
 
131
- expect(last_transaction.to_h).to include("action" => "POST /my-action")
164
+ expect(last_transaction).to have_action("POST /my-action")
132
165
  end
133
166
  end
134
167
 
135
168
  describe "request metadata" do
136
- before do
137
- env.merge("PATH_INFO" => "/some/path", "REQUEST_METHOD" => "GET")
138
- end
139
-
140
169
  it "sets request metadata" do
141
- make_request(env)
142
-
143
- expect(last_transaction.to_h).to include(
144
- "metadata" => {
145
- "method" => "GET",
146
- "path" => "/some/path"
147
- },
148
- "sample_data" => hash_including(
149
- "environment" => hash_including(
150
- "REQUEST_METHOD" => "GET",
151
- "PATH_INFO" => "/some/path"
152
- # and more, but we don't need to test Rack mock defaults
153
- )
154
- )
170
+ env.merge!("PATH_INFO" => "/some/path", "REQUEST_METHOD" => "GET")
171
+ make_request
172
+
173
+ expect(last_transaction).to include_metadata(
174
+ "method" => "GET",
175
+ "path" => "/some/path"
176
+ )
177
+ expect(last_transaction).to include_environment(
178
+ "REQUEST_METHOD" => "GET",
179
+ "PATH_INFO" => "/some/path"
180
+ # and more, but we don't need to test Rack mock defaults
155
181
  )
156
182
  end
157
183
 
184
+ context "with an invalid HTTP request method" do
185
+ it "stores the invalid HTTP request method" do
186
+ env["REQUEST_METHOD"] = "FOO"
187
+ make_request
188
+
189
+ expect(last_transaction).to include_metadata("method" => "FOO")
190
+ end
191
+ end
192
+
193
+ context "with fetching the request method raises an error" do
194
+ class BrokenRequestMethodRequest < Rack::Request
195
+ def request_method
196
+ raise "uh oh!"
197
+ end
198
+ end
199
+
200
+ let(:options) { { :request_class => BrokenRequestMethodRequest } }
201
+ it "does not store the invalid HTTP request method" do
202
+ env["REQUEST_METHOD"] = "FOO"
203
+ make_request
204
+
205
+ expect(last_transaction).to_not include_metadata("method" => anything)
206
+ end
207
+ end
208
+
158
209
  it "sets request parameters" do
159
- make_request(env)
160
-
161
- expect(last_transaction.to_h).to include(
162
- "sample_data" => hash_including(
163
- "params" => hash_including(
164
- "page" => "2",
165
- "query" => "lorem"
166
- )
167
- )
210
+ make_request
211
+
212
+ expect(last_transaction).to include_params(
213
+ "page" => "2",
214
+ "query" => "lorem"
168
215
  )
169
216
  end
217
+
218
+ context "when setting custom params" do
219
+ let(:app) do
220
+ DummyApp.new do |_env|
221
+ Appsignal::Transaction.current.set_params("custom" => "param")
222
+ end
223
+ end
224
+
225
+ it "allow custom request parameters to be set" do
226
+ make_request
227
+
228
+ expect(last_transaction).to include_params("custom" => "param")
229
+ end
230
+ end
170
231
  end
171
232
 
172
233
  context "with queue start header" do
173
234
  let(:queue_start_time) { fixed_time * 1_000 }
174
- before do
175
- env["HTTP_X_REQUEST_START"] = "t=#{queue_start_time.to_i}" # in milliseconds
176
- end
177
235
 
178
236
  it "sets the queue start" do
179
- make_request(env)
237
+ env["HTTP_X_REQUEST_START"] = "t=#{queue_start_time.to_i}" # in milliseconds
238
+ make_request
180
239
 
181
- expect(last_transaction.ext.queue_start).to eq(queue_start_time)
240
+ expect(last_transaction).to have_queue_start(queue_start_time)
182
241
  end
183
242
  end
184
243
 
@@ -208,13 +267,9 @@ describe Appsignal::Rack::AbstractMiddleware do
208
267
  end
209
268
 
210
269
  it "uses the overridden request class and params method to fetch params" do
211
- make_request(env)
270
+ make_request
212
271
 
213
- expect(last_transaction.to_h).to include(
214
- "sample_data" => hash_including(
215
- "params" => { "abc" => "123" }
216
- )
217
- )
272
+ expect(last_transaction).to include_params("abc" => "123")
218
273
  end
219
274
  end
220
275
 
@@ -224,13 +279,23 @@ describe Appsignal::Rack::AbstractMiddleware do
224
279
  end
225
280
 
226
281
  it "uses the existing transaction" do
227
- make_request(env)
282
+ make_request
228
283
 
229
- expect { make_request(env) }.to_not(change { created_transactions.count })
284
+ expect { make_request }.to_not(change { created_transactions.count })
285
+ end
286
+
287
+ context "with error" do
288
+ let(:app) { lambda { |_env| raise ExampleException, "error message" } }
289
+
290
+ it "doesn't record the error on the transaction" do
291
+ make_request_with_error(ExampleException, "error message")
292
+
293
+ expect(last_transaction).to_not have_error
294
+ end
230
295
  end
231
296
 
232
297
  it "doesn't complete the existing transaction" do
233
- make_request(env)
298
+ make_request
234
299
 
235
300
  expect(env[Appsignal::Rack::APPSIGNAL_TRANSACTION]).to_not be_completed
236
301
  end
@@ -239,9 +304,53 @@ describe Appsignal::Rack::AbstractMiddleware do
239
304
  it "does not overwrite the action name" do
240
305
  env[Appsignal::Rack::APPSIGNAL_TRANSACTION].set_action("My custom action")
241
306
  env["appsignal.action"] = "POST /my-action"
242
- make_request(env)
307
+ make_request
308
+
309
+ expect(last_transaction).to have_action("My custom action")
310
+ end
311
+ end
312
+
313
+ context "with :report_errors set to false" do
314
+ let(:app) { lambda { |_env| raise ExampleException, "error message" } }
315
+ let(:options) { { :report_errors => false } }
316
+
317
+ it "does not record the error on the transaction" do
318
+ make_request_with_error(ExampleException, "error message")
319
+
320
+ expect(last_transaction).to_not have_error
321
+ end
322
+ end
323
+
324
+ context "with :report_errors set to true" do
325
+ let(:app) { lambda { |_env| raise ExampleException, "error message" } }
326
+ let(:options) { { :report_errors => true } }
327
+
328
+ it "records the error on the transaction" do
329
+ make_request_with_error(ExampleException, "error message")
330
+
331
+ expect(last_transaction).to have_error("ExampleException", "error message")
332
+ end
333
+ end
334
+
335
+ context "with :report_errors set to a lambda that returns false" do
336
+ let(:app) { lambda { |_env| raise ExampleException, "error message" } }
337
+ let(:options) { { :report_errors => lambda { |_env| false } } }
338
+
339
+ it "does not record the exception on the transaction" do
340
+ make_request_with_error(ExampleException, "error message")
341
+
342
+ expect(last_transaction).to_not have_error
343
+ end
344
+ end
345
+
346
+ context "with :report_errors set to a lambda that returns true" do
347
+ let(:app) { lambda { |_env| raise ExampleException, "error message" } }
348
+ let(:options) { { :report_errors => lambda { |_env| true } } }
349
+
350
+ it "records the error on the transaction" do
351
+ make_request_with_error(ExampleException, "error message")
243
352
 
244
- expect(last_transaction.to_h).to include("action" => "My custom action")
353
+ expect(last_transaction).to have_error("ExampleException", "error message")
245
354
  end
246
355
  end
247
356
  end