appsignal 4.0.6 → 4.0.8

Sign up to get free protection for your applications and to get access to all the features.
Files changed (202) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +20 -0
  3. data/Rakefile +9 -9
  4. data/appsignal.gemspec +22 -1
  5. data/ext/agent.rb +27 -27
  6. data/lib/appsignal/check_in.rb +1 -1
  7. data/lib/appsignal/config.rb +1 -3
  8. data/lib/appsignal/integrations/resque.rb +1 -6
  9. data/lib/appsignal/utils/hash_sanitizer.rb +4 -0
  10. data/lib/appsignal/version.rb +1 -1
  11. data/lib/appsignal.rb +10 -8
  12. metadata +2 -192
  13. data/.github/ISSUE_TEMPLATE/bug_report.md +0 -31
  14. data/.github/ISSUE_TEMPLATE/chore.md +0 -14
  15. data/.github/workflows/ci.yml +0 -3285
  16. data/.github/workflows/create_release_from_tag.yml +0 -62
  17. data/.gitignore +0 -35
  18. data/.gitmodules +0 -3
  19. data/.rspec +0 -4
  20. data/.yardopts +0 -8
  21. data/benchmark.rake +0 -139
  22. data/gemfiles/capistrano2.gemfile +0 -6
  23. data/gemfiles/capistrano3.gemfile +0 -7
  24. data/gemfiles/dry-monitor.gemfile +0 -5
  25. data/gemfiles/grape.gemfile +0 -5
  26. data/gemfiles/hanami-2.0.gemfile +0 -7
  27. data/gemfiles/hanami-2.1.gemfile +0 -7
  28. data/gemfiles/http5.gemfile +0 -5
  29. data/gemfiles/no_dependencies.gemfile +0 -10
  30. data/gemfiles/padrino.gemfile +0 -7
  31. data/gemfiles/psych-3.gemfile +0 -5
  32. data/gemfiles/psych-4.gemfile +0 -5
  33. data/gemfiles/que-1.gemfile +0 -5
  34. data/gemfiles/que-2.gemfile +0 -5
  35. data/gemfiles/rails-6.0.gemfile +0 -10
  36. data/gemfiles/rails-6.1.gemfile +0 -11
  37. data/gemfiles/rails-7.0.gemfile +0 -11
  38. data/gemfiles/rails-7.1.gemfile +0 -11
  39. data/gemfiles/rails-7.2.gemfile +0 -11
  40. data/gemfiles/redis-4.gemfile +0 -5
  41. data/gemfiles/redis-5.gemfile +0 -6
  42. data/gemfiles/resque-2.gemfile +0 -6
  43. data/gemfiles/sequel.gemfile +0 -10
  44. data/gemfiles/sinatra.gemfile +0 -5
  45. data/gemfiles/webmachine1.gemfile +0 -7
  46. data/gemfiles/webmachine2.gemfile +0 -6
  47. data/mono.yml +0 -16
  48. data/spec/.rubocop.yml +0 -7
  49. data/spec/lib/appsignal/auth_check_spec.rb +0 -84
  50. data/spec/lib/appsignal/capistrano2_spec.rb +0 -227
  51. data/spec/lib/appsignal/capistrano3_spec.rb +0 -284
  52. data/spec/lib/appsignal/check_in/cron_spec.rb +0 -210
  53. data/spec/lib/appsignal/check_in/scheduler_spec.rb +0 -557
  54. data/spec/lib/appsignal/cli/demo_spec.rb +0 -46
  55. data/spec/lib/appsignal/cli/diagnose/paths_spec.rb +0 -16
  56. data/spec/lib/appsignal/cli/diagnose/utils_spec.rb +0 -86
  57. data/spec/lib/appsignal/cli/diagnose_spec.rb +0 -1553
  58. data/spec/lib/appsignal/cli/helpers_spec.rb +0 -179
  59. data/spec/lib/appsignal/cli/install_spec.rb +0 -848
  60. data/spec/lib/appsignal/cli_spec.rb +0 -56
  61. data/spec/lib/appsignal/config_spec.rb +0 -1380
  62. data/spec/lib/appsignal/demo_spec.rb +0 -83
  63. data/spec/lib/appsignal/environment_spec.rb +0 -190
  64. data/spec/lib/appsignal/event_formatter/action_view/render_formatter_spec.rb +0 -60
  65. data/spec/lib/appsignal/event_formatter/active_record/instantiation_formatter_spec.rb +0 -21
  66. data/spec/lib/appsignal/event_formatter/active_record/sql_formatter_spec.rb +0 -21
  67. data/spec/lib/appsignal/event_formatter/elastic_search/search_formatter_spec.rb +0 -52
  68. data/spec/lib/appsignal/event_formatter/faraday/request_formatter_spec.rb +0 -21
  69. data/spec/lib/appsignal/event_formatter/mongo_ruby_driver/query_formatter_spec.rb +0 -84
  70. data/spec/lib/appsignal/event_formatter/rom/sql_formatter_spec.rb +0 -22
  71. data/spec/lib/appsignal/event_formatter/sequel/sql_formatter_spec.rb +0 -30
  72. data/spec/lib/appsignal/event_formatter/view_component/render_formatter_spec.rb +0 -41
  73. data/spec/lib/appsignal/event_formatter_spec.rb +0 -193
  74. data/spec/lib/appsignal/extension/jruby_spec.rb +0 -46
  75. data/spec/lib/appsignal/extension_install_failure_spec.rb +0 -20
  76. data/spec/lib/appsignal/extension_spec.rb +0 -178
  77. data/spec/lib/appsignal/garbage_collection_spec.rb +0 -98
  78. data/spec/lib/appsignal/hooks/action_cable_spec.rb +0 -345
  79. data/spec/lib/appsignal/hooks/action_mailer_spec.rb +0 -55
  80. data/spec/lib/appsignal/hooks/active_support_notifications/finish_with_state_shared_examples.rb +0 -23
  81. data/spec/lib/appsignal/hooks/active_support_notifications/instrument_shared_examples.rb +0 -99
  82. data/spec/lib/appsignal/hooks/active_support_notifications/start_finish_shared_examples.rb +0 -47
  83. data/spec/lib/appsignal/hooks/active_support_notifications_spec.rb +0 -47
  84. data/spec/lib/appsignal/hooks/activejob_spec.rb +0 -650
  85. data/spec/lib/appsignal/hooks/at_exit_spec.rb +0 -105
  86. data/spec/lib/appsignal/hooks/celluloid_spec.rb +0 -40
  87. data/spec/lib/appsignal/hooks/data_mapper_spec.rb +0 -40
  88. data/spec/lib/appsignal/hooks/delayed_job_spec.rb +0 -38
  89. data/spec/lib/appsignal/hooks/dry_monitor_spec.rb +0 -83
  90. data/spec/lib/appsignal/hooks/excon_spec.rb +0 -67
  91. data/spec/lib/appsignal/hooks/gvl_spec.rb +0 -145
  92. data/spec/lib/appsignal/hooks/http_spec.rb +0 -37
  93. data/spec/lib/appsignal/hooks/mongo_ruby_driver_spec.rb +0 -46
  94. data/spec/lib/appsignal/hooks/mri_spec.rb +0 -23
  95. data/spec/lib/appsignal/hooks/net_http_spec.rb +0 -18
  96. data/spec/lib/appsignal/hooks/passenger_spec.rb +0 -30
  97. data/spec/lib/appsignal/hooks/puma_spec.rb +0 -80
  98. data/spec/lib/appsignal/hooks/que_spec.rb +0 -19
  99. data/spec/lib/appsignal/hooks/rake_spec.rb +0 -144
  100. data/spec/lib/appsignal/hooks/redis_client_spec.rb +0 -218
  101. data/spec/lib/appsignal/hooks/redis_spec.rb +0 -124
  102. data/spec/lib/appsignal/hooks/resque_spec.rb +0 -27
  103. data/spec/lib/appsignal/hooks/sequel_spec.rb +0 -44
  104. data/spec/lib/appsignal/hooks/shoryuken_spec.rb +0 -29
  105. data/spec/lib/appsignal/hooks/sidekiq_spec.rb +0 -115
  106. data/spec/lib/appsignal/hooks/unicorn_spec.rb +0 -63
  107. data/spec/lib/appsignal/hooks/webmachine_spec.rb +0 -24
  108. data/spec/lib/appsignal/hooks_spec.rb +0 -124
  109. data/spec/lib/appsignal/integrations/data_mapper_spec.rb +0 -74
  110. data/spec/lib/appsignal/integrations/delayed_job_plugin_spec.rb +0 -454
  111. data/spec/lib/appsignal/integrations/http_spec.rb +0 -111
  112. data/spec/lib/appsignal/integrations/mongo_ruby_driver_spec.rb +0 -154
  113. data/spec/lib/appsignal/integrations/net_http_spec.rb +0 -33
  114. data/spec/lib/appsignal/integrations/object_spec.rb +0 -347
  115. data/spec/lib/appsignal/integrations/puma_spec.rb +0 -150
  116. data/spec/lib/appsignal/integrations/que_spec.rb +0 -187
  117. data/spec/lib/appsignal/integrations/railtie_spec.rb +0 -457
  118. data/spec/lib/appsignal/integrations/resque_spec.rb +0 -155
  119. data/spec/lib/appsignal/integrations/shoryuken_spec.rb +0 -165
  120. data/spec/lib/appsignal/integrations/sidekiq_spec.rb +0 -640
  121. data/spec/lib/appsignal/integrations/webmachine_spec.rb +0 -136
  122. data/spec/lib/appsignal/loaders/grape_spec.rb +0 -12
  123. data/spec/lib/appsignal/loaders/hanami_spec.rb +0 -92
  124. data/spec/lib/appsignal/loaders/padrino_spec.rb +0 -273
  125. data/spec/lib/appsignal/loaders/sinatra_spec.rb +0 -44
  126. data/spec/lib/appsignal/loaders_spec.rb +0 -144
  127. data/spec/lib/appsignal/logger_spec.rb +0 -205
  128. data/spec/lib/appsignal/marker_spec.rb +0 -51
  129. data/spec/lib/appsignal/probes/gvl_spec.rb +0 -164
  130. data/spec/lib/appsignal/probes/mri_spec.rb +0 -162
  131. data/spec/lib/appsignal/probes/sidekiq_spec.rb +0 -333
  132. data/spec/lib/appsignal/probes_spec.rb +0 -414
  133. data/spec/lib/appsignal/rack/abstract_middleware_spec.rb +0 -370
  134. data/spec/lib/appsignal/rack/body_wrapper_spec.rb +0 -319
  135. data/spec/lib/appsignal/rack/event_handler_spec.rb +0 -441
  136. data/spec/lib/appsignal/rack/grape_middleware_spec.rb +0 -201
  137. data/spec/lib/appsignal/rack/hanami_middleware_spec.rb +0 -36
  138. data/spec/lib/appsignal/rack/instrumentation_middleware_spec.rb +0 -38
  139. data/spec/lib/appsignal/rack/rails_instrumentation_spec.rb +0 -126
  140. data/spec/lib/appsignal/rack/sinatra_instrumentation_spec.rb +0 -217
  141. data/spec/lib/appsignal/rack_spec.rb +0 -243
  142. data/spec/lib/appsignal/sample_data_spec.rb +0 -238
  143. data/spec/lib/appsignal/span_spec.rb +0 -141
  144. data/spec/lib/appsignal/system_spec.rb +0 -126
  145. data/spec/lib/appsignal/transaction_spec.rb +0 -2115
  146. data/spec/lib/appsignal/transmitter_spec.rb +0 -198
  147. data/spec/lib/appsignal/utils/data_spec.rb +0 -166
  148. data/spec/lib/appsignal/utils/hash_sanitizer_spec.rb +0 -182
  149. data/spec/lib/appsignal/utils/integration_logger_spec.rb +0 -21
  150. data/spec/lib/appsignal/utils/integration_memory_logger_spec.rb +0 -153
  151. data/spec/lib/appsignal/utils/json_spec.rb +0 -44
  152. data/spec/lib/appsignal/utils/query_params_sanitizer_spec.rb +0 -192
  153. data/spec/lib/appsignal_spec.rb +0 -1919
  154. data/spec/lib/puma/appsignal_spec.rb +0 -334
  155. data/spec/spec_helper.rb +0 -179
  156. data/spec/support/fixtures/generated_config.yml +0 -24
  157. data/spec/support/fixtures/projects/broken/config/appsignal.yml +0 -1
  158. data/spec/support/fixtures/projects/valid/config/appsignal.yml +0 -57
  159. data/spec/support/fixtures/projects/valid/log/.gitkeep +0 -0
  160. data/spec/support/fixtures/projects/valid_with_rails_app/config/application.rb +0 -16
  161. data/spec/support/fixtures/projects/valid_with_rails_app/config/appsignal.yml +0 -56
  162. data/spec/support/fixtures/projects/valid_with_rails_app/config/environment.rb +0 -10
  163. data/spec/support/fixtures/projects/valid_with_rails_app/log/.gitkeep +0 -0
  164. data/spec/support/fixtures/uploaded_file.txt +0 -0
  165. data/spec/support/hanami/hanami_app.rb +0 -29
  166. data/spec/support/helpers/action_mailer_helpers.rb +0 -25
  167. data/spec/support/helpers/activejob_helpers.rb +0 -27
  168. data/spec/support/helpers/api_request_helper.rb +0 -60
  169. data/spec/support/helpers/cli_helpers.rb +0 -40
  170. data/spec/support/helpers/config_helpers.rb +0 -66
  171. data/spec/support/helpers/dependency_helper.rb +0 -155
  172. data/spec/support/helpers/directory_helper.rb +0 -27
  173. data/spec/support/helpers/env_helpers.rb +0 -41
  174. data/spec/support/helpers/environment_metdata_helper.rb +0 -16
  175. data/spec/support/helpers/example_exception.rb +0 -13
  176. data/spec/support/helpers/example_standard_error.rb +0 -13
  177. data/spec/support/helpers/loader_helper.rb +0 -21
  178. data/spec/support/helpers/log_helpers.rb +0 -36
  179. data/spec/support/helpers/rails_helper.rb +0 -28
  180. data/spec/support/helpers/std_streams_helper.rb +0 -94
  181. data/spec/support/helpers/system_helpers.rb +0 -8
  182. data/spec/support/helpers/take_at_most_helper.rb +0 -21
  183. data/spec/support/helpers/time_helpers.rb +0 -11
  184. data/spec/support/helpers/transaction_helpers.rb +0 -122
  185. data/spec/support/helpers/wait_for_helper.rb +0 -39
  186. data/spec/support/matchers/contains_log.rb +0 -26
  187. data/spec/support/matchers/have_colorized_text.rb +0 -28
  188. data/spec/support/matchers/transaction.rb +0 -200
  189. data/spec/support/mocks/appsignal_mock.rb +0 -18
  190. data/spec/support/mocks/dummy_app.rb +0 -20
  191. data/spec/support/mocks/fake_gc_profiler.rb +0 -19
  192. data/spec/support/mocks/fake_gvl_tools.rb +0 -28
  193. data/spec/support/mocks/hash_like.rb +0 -10
  194. data/spec/support/mocks/mock_probe.rb +0 -13
  195. data/spec/support/mocks/puma_mock.rb +0 -43
  196. data/spec/support/shared_examples/instrument.rb +0 -48
  197. data/spec/support/stubs/appsignal/loaders/loader_stub.rb +0 -7
  198. data/spec/support/stubs/delayed_job.rb +0 -0
  199. data/spec/support/stubs/sidekiq/api.rb +0 -4
  200. data/spec/support/testing.rb +0 -203
  201. data/support/bundler_wrapper +0 -12
  202. data/support/install_deps +0 -33
@@ -1,2115 +0,0 @@
1
- describe Appsignal::Transaction do
2
- let(:options) { {} }
3
- let(:time) { Time.at(fixed_time) }
4
-
5
- before do
6
- start_agent(:options => options)
7
- Timecop.freeze(time)
8
- end
9
- after { Timecop.return }
10
- around do |example|
11
- keep_transactions do
12
- example.run
13
- end
14
- end
15
-
16
- describe ".create" do
17
- context "when no transaction is running" do
18
- it "returns the created transaction" do
19
- mock_transaction_id = "mock-uuid"
20
- allow(SecureRandom).to receive(:uuid).and_return(mock_transaction_id)
21
-
22
- transaction = create_transaction
23
- expect(transaction).to be_a Appsignal::Transaction
24
-
25
- expect(transaction).to have_id(mock_transaction_id)
26
- expect(transaction.transaction_id).to eq(mock_transaction_id)
27
-
28
- expect(transaction).to have_namespace(default_namespace)
29
- expect(transaction.namespace).to eq(default_namespace)
30
- end
31
-
32
- it "assigns the transaction to current" do
33
- transaction = create_transaction
34
- expect(transaction).to eq current_transaction
35
- end
36
- end
37
-
38
- context "when an explicit extension transaction is passed in the initialiser" do
39
- let(:ext) { "some_ext" }
40
-
41
- it "assigns the extension transaction to the transaction" do
42
- expect(described_class.new("web", :ext => ext).ext).to be(ext)
43
- end
44
- end
45
-
46
- context "when a transaction is already running" do
47
- before do
48
- allow(SecureRandom).to receive(:uuid)
49
- .and_return(
50
- "transaction_id_1",
51
- "transaction_id_2"
52
- )
53
- create_transaction
54
- end
55
-
56
- it "does not create a new transaction, but returns the current transaction" do
57
- expect do
58
- new_transaction = create_transaction
59
-
60
- expect(new_transaction).to eq(current_transaction)
61
- end.to_not(change { current_transaction })
62
- end
63
-
64
- it "logs a debug message" do
65
- logs = capture_logs { create_transaction }
66
-
67
- expect(logs).to contains_log :warn,
68
- "Trying to start new transaction, but a transaction with id " \
69
- "'transaction_id_1' is already running. " \
70
- "Using transaction 'transaction_id_1'."
71
- end
72
- end
73
- end
74
-
75
- describe ".current" do
76
- context "when there is a current transaction" do
77
- let!(:transaction) { create_transaction }
78
-
79
- it "reads :appsignal_transaction from the current Thread" do
80
- expect(current_transaction).to eq(Thread.current[:appsignal_transaction])
81
- expect(current_transaction).to eq(transaction)
82
- end
83
-
84
- it "is not a NilTransaction" do
85
- expect(current_transaction.nil_transaction?).to be(false)
86
- expect(current_transaction).to be_a(Appsignal::Transaction)
87
- end
88
-
89
- it "returns true for current?" do
90
- expect(Appsignal::Transaction.current?).to be(true)
91
- end
92
- end
93
-
94
- context "when there is no current transaction" do
95
- it "has no :appsignal_transaction registered on the current Thread" do
96
- expect(Thread.current[:appsignal_transaction]).to be_nil
97
- end
98
-
99
- it "returns a NilTransaction stub" do
100
- expect(current_transaction.nil_transaction?).to be(true)
101
- expect(current_transaction).to be_a(Appsignal::Transaction::NilTransaction)
102
- end
103
-
104
- it "returns false for current?" do
105
- expect(Appsignal::Transaction.current?).to be(false)
106
- end
107
- end
108
- end
109
-
110
- describe ".complete_current!" do
111
- context "with active transaction" do
112
- let!(:transaction) { create_transaction }
113
-
114
- it "completes the current transaction" do
115
- expect(transaction).to eq(current_transaction)
116
-
117
- Appsignal::Transaction.complete_current!
118
-
119
- expect(transaction).to be_completed
120
- end
121
-
122
- it "unsets the current transaction on the current Thread" do
123
- expect do
124
- Appsignal::Transaction.complete_current!
125
- end.to change { Thread.current[:appsignal_transaction] }.from(transaction).to(nil)
126
- end
127
-
128
- context "when encountering an error while completing" do
129
- before do
130
- expect(transaction).to receive(:complete).and_raise ExampleStandardError
131
- end
132
-
133
- it "logs an error message" do
134
- logs =
135
- capture_logs do
136
- Appsignal::Transaction.complete_current!
137
- end
138
- expect(logs).to contains_log :error,
139
- "Failed to complete transaction ##{transaction.transaction_id}. ExampleStandardError"
140
- end
141
-
142
- it "clears the current transaction" do
143
- expect do
144
- Appsignal::Transaction.complete_current!
145
- end.to change { Thread.current[:appsignal_transaction] }.from(transaction).to(nil)
146
- end
147
- end
148
- end
149
-
150
- context "without active transaction" do
151
- it "does nothing" do
152
- expect do
153
- Appsignal::Transaction.complete_current!
154
- end.to_not(change { Thread.current[:appsignal_transaction] })
155
- end
156
- end
157
- end
158
-
159
- describe "#complete" do
160
- let(:transaction) { create_transaction }
161
-
162
- context "when transaction is being sampled" do
163
- it "samples data" do
164
- transaction.add_tags(:foo => "bar")
165
- keep_transactions { transaction.complete }
166
- expect(transaction).to include_tags("foo" => "bar")
167
- end
168
- end
169
-
170
- context "when transaction is not being sampled" do
171
- it "does not sample data" do
172
- keep_transactions(:sample => false) { transaction.complete }
173
- expect(transaction.to_h["sample_data"]).to be_empty
174
- end
175
- end
176
-
177
- context "when a transaction is marked as discarded" do
178
- it "does not complete the transaction" do
179
- expect do
180
- transaction.discard!
181
- end.to change { transaction.discarded? }.from(false).to(true)
182
-
183
- transaction.complete
184
-
185
- expect(transaction).to_not be_completed
186
- end
187
-
188
- it "logs a debug message" do
189
- allow(SecureRandom).to receive(:uuid).and_return("mock_transaction_id")
190
- transaction.discard!
191
- logs = capture_logs { transaction.complete }
192
-
193
- expect(logs).to contains_log :debug,
194
- "Skipping transaction 'mock_transaction_id' because it was manually discarded."
195
- end
196
-
197
- context "when a discarded transaction is restored" do
198
- before { transaction.discard! }
199
-
200
- it "completes the transaction" do
201
- expect do
202
- transaction.restore!
203
- end.to change { transaction.discarded? }.from(true).to(false)
204
-
205
- transaction.complete
206
-
207
- expect(transaction).to be_completed
208
- end
209
- end
210
- end
211
-
212
- context "when a transaction has errors" do
213
- let(:error) do
214
- ExampleStandardError.new("test message").tap do |e|
215
- e.set_backtrace(["line 1"])
216
- end
217
- end
218
-
219
- let(:other_error) do
220
- ExampleStandardError.new("other test message").tap do |e|
221
- e.set_backtrace(["line 2"])
222
- end
223
- end
224
-
225
- context "when an error is already set on the transaction" do
226
- it "reports errors as duplicate transactions" do
227
- transaction.set_error(error)
228
- transaction.add_error(other_error)
229
-
230
- expect do
231
- transaction.complete
232
- end.to change { created_transactions.count }.from(1).to(2)
233
-
234
- original_transaction, duplicate_transaction = created_transactions
235
-
236
- expect(original_transaction).to have_error(
237
- "ExampleStandardError",
238
- "test message",
239
- ["line 1"]
240
- )
241
- expect(original_transaction).to be_completed
242
-
243
- expect(duplicate_transaction).to have_error(
244
- "ExampleStandardError",
245
- "other test message",
246
- ["line 2"]
247
- )
248
- expect(duplicate_transaction).to be_completed
249
- end
250
- end
251
-
252
- context "when no error is set on the transaction" do
253
- it "reports the first error in the original transaction" do
254
- transaction.add_error(error)
255
- transaction.add_error(other_error)
256
-
257
- expect do
258
- transaction.complete
259
- end.to change { created_transactions.count }.from(1).to(2)
260
-
261
- original_transaction, duplicate_transaction = created_transactions
262
-
263
- expect(original_transaction).to have_error(
264
- "ExampleStandardError",
265
- "test message",
266
- ["line 1"]
267
- )
268
- expect(original_transaction).to be_completed
269
-
270
- expect(duplicate_transaction).to have_error(
271
- "ExampleStandardError",
272
- "other test message",
273
- ["line 2"]
274
- )
275
- expect(duplicate_transaction).to be_completed
276
- end
277
- end
278
-
279
- it "stores the last reported errors" do
280
- transaction.add_error(error)
281
- transaction.add_error(other_error)
282
- transaction.complete
283
-
284
- expect(Appsignal::Transaction.last_errors).to contain_exactly(error, other_error)
285
- end
286
-
287
- describe "metadata" do
288
- let(:tags) { { "tag" => "value" } }
289
- let(:params) { { "param" => "value" } }
290
- let(:headers) { { "REQUEST_METHOD" => "value" } }
291
- let(:session_data) { { "session_data" => "value" } }
292
- let(:custom_data) { { "custom_data" => "value" } }
293
- before do
294
- transaction.set_namespace("My namespace")
295
- transaction.set_action("My action")
296
- transaction.set_metadata("path", "/some/path")
297
- transaction.set_metadata("method", "GET")
298
- transaction.add_tags(tags)
299
- transaction.add_params(params)
300
- transaction.add_headers(headers)
301
- transaction.add_session_data(session_data)
302
- transaction.add_custom_data(custom_data)
303
- transaction.add_breadcrumb("category", "action", "message", { "meta" => "data" })
304
-
305
- transaction.start_event
306
- transaction.finish_event("name", "title", "body", 1)
307
-
308
- transaction.add_error(error)
309
- transaction.add_error(other_error)
310
-
311
- transaction.complete
312
- end
313
-
314
- it "copies the transaction metadata and sample data on the duplicate transaction" do
315
- original_transaction, duplicate_transaction = created_transactions
316
-
317
- duplicate_hash = duplicate_transaction.to_h.tap do |h|
318
- h.delete("id")
319
- h.delete("error")
320
- end
321
- original_hash = original_transaction.to_h.tap do |h|
322
- h.delete("id")
323
- h.delete("error")
324
- end
325
- expect(duplicate_hash).to eq(original_hash)
326
- end
327
-
328
- it "the duplicate transaction has a different transaction id" do
329
- original_transaction, duplicate_transaction = created_transactions
330
-
331
- expect(original_transaction.transaction_id)
332
- .to_not eq(duplicate_transaction.transaction_id)
333
- end
334
-
335
- it "the duplicate transaction has a different extension transaction than the original" do
336
- original_transaction, duplicate_transaction = created_transactions
337
-
338
- expect(original_transaction.ext).to_not eq(duplicate_transaction.ext)
339
- end
340
-
341
- it "marks transaction as duplicate on the duplicate transaction" do
342
- original_transaction, duplicate_transaction = created_transactions
343
-
344
- expect(original_transaction.duplicate?).to be(false)
345
- expect(duplicate_transaction.duplicate?).to be(true)
346
- end
347
- end
348
-
349
- it "merges sample data from the original transaction in the duplicate transaction" do
350
- transaction.add_tags("root" => "tag")
351
- transaction.add_params("root" => "param")
352
- transaction.add_session_data("root" => "session")
353
- transaction.add_headers("REQUEST_METHOD" => "root")
354
- transaction.add_custom_data("root" => "custom")
355
- transaction.add_breadcrumb("root", "breadcrumb")
356
- Appsignal.report_error(error) do |t|
357
- t.add_tags("original" => "tag")
358
- t.add_params("original" => "param")
359
- t.add_session_data("original" => "session")
360
- t.add_headers("REQUEST_PATH" => "/original")
361
- t.add_custom_data("original" => "custom")
362
- t.add_breadcrumb("original", "breadcrumb")
363
- end
364
- Appsignal.report_error(other_error) do |t|
365
- t.add_tags("duplicate" => "tag")
366
- t.add_params("duplicate" => "param")
367
- t.add_session_data("duplicate" => "session")
368
- t.add_headers("HTTP_ACCEPT" => "duplicate")
369
- t.add_custom_data("duplicate" => "custom")
370
- t.add_breadcrumb("duplicate", "breadcrumb")
371
- end
372
- transaction.add_tags("root2" => "tag")
373
- transaction.add_params("root2" => "param")
374
- transaction.add_session_data("root2" => "session")
375
- transaction.add_headers("PATH_INFO" => "/root2")
376
- transaction.add_custom_data("root2" => "custom")
377
- transaction.add_breadcrumb("root2", "breadcrumb")
378
- transaction.complete
379
-
380
- original_transaction, duplicate_transaction = created_transactions
381
- # Original
382
- expect(original_transaction).to include_tags(
383
- "root" => "tag",
384
- "original" => "tag",
385
- "root2" => "tag"
386
- )
387
- expect(original_transaction).to_not include_tags("duplicate" => anything)
388
- expect(original_transaction).to include_params(
389
- "root" => "param",
390
- "original" => "param",
391
- "root2" => "param"
392
- )
393
- expect(original_transaction).to_not include_params("duplicate" => anything)
394
- expect(original_transaction).to include_session_data(
395
- "root" => "session",
396
- "original" => "session",
397
- "root2" => "session"
398
- )
399
- expect(original_transaction).to_not include_session_data("duplicate" => anything)
400
- expect(original_transaction).to include_environment(
401
- "REQUEST_METHOD" => "root",
402
- "REQUEST_PATH" => "/original",
403
- "PATH_INFO" => "/root2"
404
- )
405
- expect(original_transaction).to_not include_environment("HTTP_ACCEPT" => anything)
406
- expect(original_transaction).to include_custom_data(
407
- "root" => "custom",
408
- "original" => "custom",
409
- "root2" => "custom"
410
- )
411
- expect(original_transaction).to_not include_custom_data("duplicate" => anything)
412
- expect(original_transaction).to include_breadcrumb("breadcrumb", "root")
413
- expect(original_transaction).to include_breadcrumb("breadcrumb", "original")
414
- expect(original_transaction).to include_breadcrumb("breadcrumb", "root2")
415
- expect(original_transaction).to_not include_breadcrumb("breadcrumb", "duplicate")
416
-
417
- # Duplicate
418
- expect(duplicate_transaction).to include_tags(
419
- "root" => "tag",
420
- "duplicate" => "tag",
421
- "root2" => "tag"
422
- )
423
- expect(duplicate_transaction).to_not include_tags("original" => anything)
424
- expect(duplicate_transaction).to include_params(
425
- "root" => "param",
426
- "duplicate" => "param",
427
- "root2" => "param"
428
- )
429
- expect(duplicate_transaction).to_not include_params("original" => anything)
430
- expect(duplicate_transaction).to include_session_data(
431
- "root" => "session",
432
- "duplicate" => "session",
433
- "root2" => "session"
434
- )
435
- expect(duplicate_transaction).to_not include_session_data("original" => anything)
436
- expect(duplicate_transaction).to include_environment(
437
- "PATH_INFO" => "/root2",
438
- "HTTP_ACCEPT" => "duplicate",
439
- "REQUEST_METHOD" => "root"
440
- )
441
- expect(duplicate_transaction).to_not include_environment("REQUEST_PATH" => anything)
442
- expect(duplicate_transaction).to include_custom_data(
443
- "root" => "custom",
444
- "duplicate" => "custom",
445
- "root2" => "custom"
446
- )
447
- expect(duplicate_transaction).to_not include_custom_data("original" => anything)
448
- expect(duplicate_transaction).to include_breadcrumb("breadcrumb", "root")
449
- expect(duplicate_transaction).to include_breadcrumb("breadcrumb", "duplicate")
450
- expect(duplicate_transaction).to include_breadcrumb("breadcrumb", "root2")
451
- expect(duplicate_transaction).to_not include_breadcrumb("breadcrumb", "original")
452
- end
453
-
454
- it "overrides sample data from the original transaction in the duplicate transaction" do
455
- transaction.add_tags("changeme" => "tag")
456
- transaction.add_params("changeme" => "param")
457
- transaction.add_session_data("changeme" => "session")
458
- transaction.add_headers("REQUEST_METHOD" => "root")
459
- transaction.add_custom_data("changeme" => "custom")
460
- Appsignal.report_error(error)
461
- Appsignal.report_error(other_error) do |t|
462
- t.add_tags("changeme" => "duplicate_tag")
463
- t.add_params("changeme" => "duplicate_param")
464
- t.add_session_data("changeme" => "duplicate_session")
465
- t.add_headers("REQUEST_METHOD" => "duplicate")
466
- t.add_custom_data("changeme" => "duplicate_custom")
467
- end
468
- transaction.add_tags("changeme" => "changed_tag")
469
- transaction.add_params("changeme" => "changed_param")
470
- transaction.add_session_data("changeme" => "changed_session")
471
- transaction.add_headers("REQUEST_METHOD" => "changed")
472
- transaction.add_custom_data("changeme" => "changed_custom")
473
- transaction.complete
474
-
475
- original_transaction, duplicate_transaction = created_transactions
476
- # Original
477
- expect(original_transaction).to include_tags(
478
- "changeme" => "changed_tag"
479
- )
480
- expect(original_transaction).to include_params(
481
- "changeme" => "changed_param"
482
- )
483
- expect(original_transaction).to include_session_data(
484
- "changeme" => "changed_session"
485
- )
486
- expect(original_transaction).to include_environment(
487
- "REQUEST_METHOD" => "changed"
488
- )
489
- expect(original_transaction).to include_custom_data(
490
- "changeme" => "changed_custom"
491
- )
492
-
493
- # Duplicate
494
- expect(duplicate_transaction).to include_tags(
495
- "changeme" => "duplicate_tag"
496
- )
497
- expect(duplicate_transaction).to include_params(
498
- "changeme" => "duplicate_param"
499
- )
500
- expect(duplicate_transaction).to include_session_data(
501
- "changeme" => "duplicate_session"
502
- )
503
- expect(duplicate_transaction).to include_environment(
504
- "REQUEST_METHOD" => "duplicate"
505
- )
506
- expect(duplicate_transaction).to include_custom_data(
507
- "changeme" => "duplicate_custom"
508
- )
509
- end
510
- end
511
- end
512
-
513
- context "pausing" do
514
- let(:transaction) { new_transaction }
515
-
516
- describe "#pause!" do
517
- it "changes the pause flag to true" do
518
- expect do
519
- transaction.pause!
520
- end.to change(transaction, :paused?).from(false).to(true)
521
- end
522
- end
523
-
524
- describe "#resume!" do
525
- before { transaction.pause! }
526
-
527
- it "changes the pause flag to false" do
528
- expect do
529
- transaction.resume!
530
- end.to change(transaction, :paused?).from(true).to(false)
531
- end
532
- end
533
-
534
- describe "#paused?" do
535
- context "when not paused" do
536
- it "return false" do
537
- expect(transaction.paused?).to be_falsy
538
- end
539
- end
540
-
541
- context "when paused" do
542
- before { transaction.pause! }
543
-
544
- it "returns true" do
545
- expect(transaction.paused?).to be_truthy
546
- end
547
- end
548
- end
549
- end
550
-
551
- context "initialization" do
552
- let(:transaction) { new_transaction }
553
-
554
- it "loads the AppSignal extension" do
555
- expect(transaction.ext).to_not be_nil
556
- end
557
-
558
- context "when extension is not loaded", :extension_installation_failure do
559
- around do |example|
560
- Appsignal::Testing.without_testing { example.run }
561
- end
562
-
563
- it "does not error on missing extension method calls" do
564
- expect(transaction.ext).to be_kind_of(Appsignal::Extension::MockTransaction)
565
- transaction.start_event
566
- transaction.finish_event(
567
- "name",
568
- "title",
569
- "body",
570
- Appsignal::EventFormatter::DEFAULT
571
- )
572
- end
573
- end
574
-
575
- it "sets the namespace to http_request" do
576
- expect(transaction.namespace).to eq "http_request"
577
- end
578
- end
579
-
580
- describe "#store" do
581
- let(:transaction) { new_transaction }
582
-
583
- it "returns an empty store when it's not already present" do
584
- expect(transaction.store("test")).to eql({})
585
- end
586
-
587
- it "stores changes to the store" do
588
- transaction_store = transaction.store("test")
589
- transaction_store["transaction"] = "value"
590
-
591
- expect(transaction.store("test")).to eql("transaction" => "value")
592
- end
593
-
594
- it "has a default value of a Hash for store values" do
595
- transaction.store("abc")["def"] = "123"
596
-
597
- expect(transaction.store("abc")).to eq("def" => "123")
598
- expect(transaction.store("xyz")).to eq({})
599
- end
600
- end
601
-
602
- describe "#add_params" do
603
- let(:transaction) { new_transaction }
604
-
605
- it "has a #set_params alias" do
606
- expect(transaction.method(:add_params)).to eq(transaction.method(:set_params))
607
- end
608
-
609
- it "adds the params to the transaction" do
610
- params = { "key" => "value" }
611
- transaction.add_params(params)
612
-
613
- transaction._sample
614
- expect(transaction).to include_params(params)
615
- end
616
-
617
- it "merges the params on the transaction" do
618
- transaction.add_params("abc" => "value")
619
- transaction.add_params("def" => "value")
620
- transaction.add_params { { "xyz" => "value" } }
621
-
622
- transaction._sample
623
- expect(transaction).to include_params(
624
- "abc" => "value",
625
- "def" => "value",
626
- "xyz" => "value"
627
- )
628
- end
629
-
630
- it "adds the params to the transaction with a block" do
631
- params = { "key" => "value" }
632
- transaction.add_params { params }
633
-
634
- transaction._sample
635
- expect(transaction).to include_params(params)
636
- end
637
-
638
- it "adds the params block value when both an argument and block are given" do
639
- arg_params = { "argument" => "value" }
640
- block_params = { "block" => "value" }
641
- transaction.add_params(arg_params) { block_params }
642
-
643
- transaction._sample
644
- expect(transaction).to include_params(block_params)
645
- end
646
-
647
- it "logs an error if an error occurred storing the params" do
648
- transaction.add_params { raise "uh oh" }
649
-
650
- logs = capture_logs { transaction._sample }
651
- expect(logs).to contains_log(
652
- :error,
653
- "Exception while fetching params: RuntimeError: uh oh"
654
- )
655
- end
656
-
657
- it "does not update the params on the transaction if the given value is nil" do
658
- params = { "key" => "value" }
659
- transaction.add_params(params)
660
- transaction.add_params(nil)
661
-
662
- transaction._sample
663
- expect(transaction).to include_params(params)
664
- end
665
-
666
- context "with AppSignal filtering" do
667
- let(:options) { { :filter_parameters => %w[foo] } }
668
-
669
- it "returns sanitized custom params" do
670
- transaction.add_params("foo" => "value", "baz" => "bat")
671
-
672
- transaction._sample
673
- expect(transaction).to include_params("foo" => "[FILTERED]", "baz" => "bat")
674
- end
675
- end
676
- end
677
-
678
- describe "#add_params_if_nil" do
679
- let(:transaction) { new_transaction }
680
-
681
- it "has a #set_params_if_nil alias" do
682
- expect(transaction.method(:add_params_if_nil)).to eq(transaction.method(:set_params_if_nil))
683
- end
684
-
685
- context "when the params are not set" do
686
- it "adds the params to the transaction" do
687
- params = { "key" => "value" }
688
- transaction.add_params_if_nil(params)
689
-
690
- transaction._sample
691
- expect(transaction).to include_params(params)
692
- end
693
-
694
- it "adds the params to the transaction with a block" do
695
- params = { "key" => "value" }
696
- transaction.add_params_if_nil { params }
697
-
698
- transaction._sample
699
- expect(transaction).to include_params(params)
700
- end
701
-
702
- it "adds the params block value when both an argument and block are given" do
703
- arg_params = { "argument" => "value" }
704
- block_params = { "block" => "value" }
705
- transaction.add_params_if_nil(arg_params) { block_params }
706
-
707
- transaction._sample
708
- expect(transaction).to include_params(block_params)
709
- end
710
-
711
- it "does not update the params on the transaction if the given value is nil" do
712
- params = { "key" => "value" }
713
- transaction.add_params(params)
714
- transaction.add_params_if_nil(nil)
715
-
716
- transaction._sample
717
- expect(transaction).to include_params(params)
718
- end
719
- end
720
-
721
- context "when the params are set" do
722
- it "does not update the params on the transaction" do
723
- preset_params = { "other" => "params" }
724
- params = { "key" => "value" }
725
- transaction.add_params(preset_params)
726
- transaction.add_params_if_nil(params)
727
-
728
- transaction._sample
729
- expect(transaction).to include_params(preset_params)
730
- end
731
-
732
- it "does not update the params with a block on the transaction" do
733
- preset_params = { "other" => "params" }
734
- params = { "key" => "value" }
735
- transaction.add_params(preset_params)
736
- transaction.add_params_if_nil { params }
737
-
738
- transaction._sample
739
- expect(transaction).to include_params(preset_params)
740
- end
741
- end
742
-
743
- context "when the params were set as an empty value" do
744
- it "does not set params on the transaction" do
745
- transaction.add_params("key1" => "value")
746
- transaction.set_empty_params!
747
- transaction.add_params_if_nil("key2" => "value")
748
-
749
- transaction._sample
750
- expect(transaction).to_not include_params
751
- end
752
- end
753
- end
754
-
755
- describe "#add_session_data" do
756
- let(:transaction) { new_transaction }
757
-
758
- it "has a #set_session_data alias" do
759
- expect(transaction.method(:add_session_data)).to eq(transaction.method(:set_session_data))
760
- end
761
-
762
- it "adds the session data to the transaction" do
763
- data = { "key" => "value" }
764
- transaction.add_session_data(data)
765
-
766
- transaction._sample
767
- expect(transaction).to include_session_data(data)
768
- end
769
-
770
- it "merges the session data on the transaction" do
771
- transaction.add_session_data("abc" => "value")
772
- transaction.add_session_data("def" => "value")
773
- transaction.add_session_data { { "xyz" => "value" } }
774
-
775
- transaction._sample
776
- expect(transaction).to include_session_data(
777
- "abc" => "value",
778
- "def" => "value",
779
- "xyz" => "value"
780
- )
781
- end
782
-
783
- it "adds the session data to the transaction with a block" do
784
- data = { "key" => "value" }
785
- transaction.add_session_data { data }
786
-
787
- transaction._sample
788
- expect(transaction).to include_session_data(data)
789
- end
790
-
791
- it "adds the session data block value when both an argument and block are given" do
792
- arg_data = { "argument" => "value" }
793
- block_data = { "block" => "value" }
794
- transaction.add_session_data(arg_data) { block_data }
795
-
796
- transaction._sample
797
- expect(transaction).to include_session_data(block_data)
798
- end
799
-
800
- it "logs an error if an error occurred storing the session data" do
801
- transaction.add_session_data { raise "uh oh" }
802
-
803
- logs = capture_logs { transaction._sample }
804
- expect(logs).to contains_log(
805
- :error,
806
- "Exception while fetching session data: RuntimeError: uh oh"
807
- )
808
- end
809
-
810
- it "does not update the session data on the transaction if the given value is nil" do
811
- data = { "key" => "value" }
812
- transaction.add_session_data(data)
813
- transaction.add_session_data(nil)
814
-
815
- transaction._sample
816
- expect(transaction).to include_session_data(data)
817
- end
818
-
819
- context "with filter_session_data" do
820
- let(:options) { { :filter_session_data => ["filtered_key"] } }
821
-
822
- it "does not include filtered out session data" do
823
- transaction.add_session_data("data" => "value1", "filtered_key" => "filtered_value")
824
-
825
- transaction._sample
826
- expect(transaction).to include_session_data("data" => "value1")
827
- end
828
- end
829
- end
830
-
831
- describe "#add_session_data_if_nil" do
832
- let(:transaction) { new_transaction }
833
-
834
- context "when the session data is not set" do
835
- it "sets the session data on the transaction" do
836
- data = { "key" => "value" }
837
- transaction.add_session_data_if_nil(data)
838
-
839
- transaction._sample
840
- expect(transaction).to include_session_data(data)
841
- end
842
-
843
- it "updates the session data on the transaction with a block" do
844
- data = { "key" => "value" }
845
- transaction.add_session_data_if_nil { data }
846
-
847
- transaction._sample
848
- expect(transaction).to include_session_data(data)
849
- end
850
-
851
- it "updates with the session data block when both an argument and block are given" do
852
- arg_data = { "argument" => "value" }
853
- block_data = { "block" => "value" }
854
- transaction.add_session_data_if_nil(arg_data) { block_data }
855
-
856
- transaction._sample
857
- expect(transaction).to include_session_data(block_data)
858
- end
859
-
860
- it "does not update the session data on the transaction if the given value is nil" do
861
- data = { "key" => "value" }
862
- transaction.add_session_data(data)
863
- transaction.add_session_data_if_nil(nil)
864
-
865
- transaction._sample
866
- expect(transaction).to include_session_data(data)
867
- end
868
- end
869
-
870
- context "when the session data are set" do
871
- it "does not update the session data on the transaction" do
872
- preset_data = { "other" => "data" }
873
- data = { "key" => "value" }
874
- transaction.add_session_data(preset_data)
875
- transaction.add_session_data_if_nil(data)
876
-
877
- transaction._sample
878
- expect(transaction).to include_session_data(preset_data)
879
- end
880
-
881
- it "does not update the session data with a block on the transaction" do
882
- preset_data = { "other" => "data" }
883
- data = { "key" => "value" }
884
- transaction.add_session_data(preset_data)
885
- transaction.add_session_data_if_nil { data }
886
-
887
- transaction._sample
888
- expect(transaction).to include_session_data(preset_data)
889
- end
890
- end
891
- end
892
-
893
- describe "#add_headers" do
894
- let(:transaction) { new_transaction }
895
-
896
- it "has a #set_headers alias" do
897
- expect(transaction.method(:add_headers)).to eq(transaction.method(:set_headers))
898
- end
899
-
900
- it "adds the headers to the transaction" do
901
- headers = { "PATH_INFO" => "value" }
902
- transaction.add_headers(headers)
903
-
904
- transaction._sample
905
- expect(transaction).to include_environment(headers)
906
- end
907
-
908
- it "merges the headers on the transaction" do
909
- transaction.add_headers("PATH_INFO" => "value")
910
- transaction.add_headers("REQUEST_METHOD" => "value")
911
- transaction.add_headers { { "HTTP_ACCEPT" => "value" } }
912
-
913
- transaction._sample
914
- expect(transaction).to include_environment(
915
- "PATH_INFO" => "value",
916
- "REQUEST_METHOD" => "value",
917
- "HTTP_ACCEPT" => "value"
918
- )
919
- end
920
-
921
- it "adds the headers to the transaction with a block" do
922
- headers = { "PATH_INFO" => "value" }
923
- transaction.add_headers { headers }
924
-
925
- transaction._sample
926
- expect(transaction).to include_environment(headers)
927
- end
928
-
929
- it "adds the headers block value when both an argument and block are given" do
930
- arg_data = { "PATH_INFO" => "/arg-path" }
931
- block_data = { "PATH_INFO" => "/block-path" }
932
- transaction.add_headers(arg_data) { block_data }
933
-
934
- transaction._sample
935
- expect(transaction).to include_environment(block_data)
936
- end
937
-
938
- it "logs an error if an error occurred storing the headers" do
939
- transaction.add_headers { raise "uh oh" }
940
-
941
- logs = capture_logs { transaction._sample }
942
- expect(logs).to contains_log(
943
- :error,
944
- "Exception while fetching headers: RuntimeError: uh oh"
945
- )
946
- end
947
-
948
- it "does not update the headers on the transaction if the given value is nil" do
949
- headers = { "PATH_INFO" => "value" }
950
- transaction.add_headers(headers)
951
- transaction.add_headers(nil)
952
-
953
- transaction._sample
954
- expect(transaction).to include_environment(headers)
955
- end
956
-
957
- context "with request_headers options" do
958
- let(:options) { { :request_headers => ["MY_HEADER"] } }
959
-
960
- it "does not include filtered out headers" do
961
- transaction.add_headers("MY_HEADER" => "value1", "filtered_key" => "filtered_value")
962
-
963
- transaction._sample
964
- expect(transaction).to include_environment("MY_HEADER" => "value1")
965
- end
966
- end
967
- end
968
-
969
- describe "#add_headers_if_nil" do
970
- let(:transaction) { new_transaction }
971
-
972
- it "has a #set_headers_if_nil alias" do
973
- expect(transaction.method(:add_headers_if_nil)).to eq(transaction.method(:set_headers_if_nil))
974
- end
975
-
976
- context "when the headers are not set" do
977
- it "adds the headers to the transaction" do
978
- headers = { "PATH_INFO" => "value" }
979
- transaction.add_headers_if_nil(headers)
980
-
981
- transaction._sample
982
- expect(transaction).to include_environment(headers)
983
- end
984
-
985
- it "adds the headers to the transaction with a block" do
986
- headers = { "PATH_INFO" => "value" }
987
- transaction.add_headers_if_nil { headers }
988
-
989
- transaction._sample
990
- expect(transaction).to include_environment(headers)
991
- end
992
-
993
- it "adds the headers block value when both an argument and block are given" do
994
- arg_data = { "PATH_INFO" => "/arg-path" }
995
- block_data = { "PATH_INFO" => "/block-path" }
996
- transaction.add_headers_if_nil(arg_data) { block_data }
997
-
998
- transaction._sample
999
- expect(transaction).to include_environment(block_data)
1000
- end
1001
-
1002
- it "does not update the headers on the transaction if the given value is nil" do
1003
- headers = { "PATH_INFO" => "value" }
1004
- transaction.add_headers(headers)
1005
- transaction.add_headers_if_nil(nil)
1006
-
1007
- transaction._sample
1008
- expect(transaction).to include_environment(headers)
1009
- end
1010
- end
1011
-
1012
- context "when the headers are set" do
1013
- it "does not update the headers on the transaction" do
1014
- preset_headers = { "PATH_INFO" => "/first-path" }
1015
- headers = { "PATH_INFO" => "/other-path" }
1016
- transaction.add_headers(preset_headers)
1017
- transaction.add_headers_if_nil(headers)
1018
-
1019
- transaction._sample
1020
- expect(transaction).to include_environment(preset_headers)
1021
- end
1022
-
1023
- it "does not update the headers with a block on the transaction" do
1024
- preset_headers = { "PATH_INFO" => "/first-path" }
1025
- headers = { "PATH_INFO" => "/other-path" }
1026
- transaction.add_headers(preset_headers)
1027
- transaction.add_headers_if_nil { headers }
1028
-
1029
- transaction._sample
1030
- expect(transaction).to include_environment(preset_headers)
1031
- end
1032
- end
1033
- end
1034
-
1035
- describe "#add_tags" do
1036
- let(:transaction) { new_transaction }
1037
- let(:long_string) { "a" * 10_001 }
1038
-
1039
- it "stores tags on the transaction" do
1040
- transaction.add_tags(
1041
- :valid_key => "valid_value",
1042
- "valid_string_key" => "valid_value",
1043
- :both_symbols => :valid_value,
1044
- :integer_value => 1,
1045
- :hash_value => { "invalid" => "hash" },
1046
- :array_value => %w[invalid array],
1047
- :object => Object.new,
1048
- :too_long_value => long_string,
1049
- long_string => "too_long_key",
1050
- :true_tag => true,
1051
- :false_tag => false
1052
- )
1053
- transaction._sample
1054
-
1055
- expect(transaction).to include_tags(
1056
- "valid_key" => "valid_value",
1057
- "valid_string_key" => "valid_value",
1058
- "both_symbols" => "valid_value",
1059
- "integer_value" => 1,
1060
- "too_long_value" => "#{"a" * 10_000}...",
1061
- long_string => "too_long_key",
1062
- "true_tag" => true,
1063
- "false_tag" => false
1064
- )
1065
- end
1066
-
1067
- it "merges the tags when called multiple times" do
1068
- transaction.add_tags(:key1 => "value1")
1069
- transaction.add_tags(:key2 => "value2")
1070
- transaction._sample
1071
-
1072
- expect(transaction).to include_tags(
1073
- "key1" => "value1",
1074
- "key2" => "value2"
1075
- )
1076
- end
1077
- end
1078
-
1079
- describe "#add_custom_data" do
1080
- let(:transaction) { new_transaction }
1081
-
1082
- it "has a #add_custom_data alias" do
1083
- expect(transaction.method(:add_custom_data)).to eq(transaction.method(:set_custom_data))
1084
- end
1085
-
1086
- it "adds a custom Hash data to the transaction" do
1087
- transaction.add_custom_data(
1088
- :user => {
1089
- :id => 123,
1090
- :locale => "abc"
1091
- },
1092
- :organization => {
1093
- :slug => "appsignal",
1094
- :plan => "enterprise"
1095
- }
1096
- )
1097
-
1098
- transaction._sample
1099
- expect(transaction).to include_custom_data(
1100
- "user" => {
1101
- "id" => 123,
1102
- "locale" => "abc"
1103
- },
1104
- "organization" => {
1105
- "slug" => "appsignal",
1106
- "plan" => "enterprise"
1107
- }
1108
- )
1109
- end
1110
-
1111
- it "adds a custom Array data to the transaction" do
1112
- transaction.add_custom_data([
1113
- [123, "abc"],
1114
- ["appsignal", "enterprise"]
1115
- ])
1116
-
1117
- transaction._sample
1118
- expect(transaction).to include_custom_data([
1119
- [123, "abc"],
1120
- ["appsignal", "enterprise"]
1121
- ])
1122
- end
1123
-
1124
- it "does not store non Hash or Array custom data" do
1125
- logs =
1126
- capture_logs do
1127
- transaction.add_custom_data("abc")
1128
- transaction._sample
1129
- expect(transaction).to_not include_custom_data
1130
-
1131
- transaction.add_custom_data(123)
1132
- transaction._sample
1133
- expect(transaction).to_not include_custom_data
1134
-
1135
- transaction.add_custom_data(Object.new)
1136
- transaction._sample
1137
- expect(transaction).to_not include_custom_data
1138
- end
1139
-
1140
- expect(logs).to contains_log(
1141
- :error,
1142
- %(Sample data 'custom_data': Unsupported data type 'String' received: "abc")
1143
- )
1144
- expect(logs).to contains_log(
1145
- :error,
1146
- %(Sample data 'custom_data': Unsupported data type 'Integer' received: 123)
1147
- )
1148
- expect(logs).to contains_log(
1149
- :error,
1150
- %(Sample data 'custom_data': Unsupported data type 'Object' received: #<Object:)
1151
- )
1152
- end
1153
-
1154
- it "merges the custom data if called multiple times" do
1155
- transaction.add_custom_data("abc" => "value")
1156
- transaction.add_custom_data("def" => "value")
1157
-
1158
- transaction._sample
1159
- expect(transaction).to include_custom_data(
1160
- "abc" => "value",
1161
- "def" => "value"
1162
- )
1163
- end
1164
- end
1165
-
1166
- describe "#add_breadcrumb" do
1167
- let(:transaction) { new_transaction }
1168
-
1169
- context "when over the limit" do
1170
- before do
1171
- 22.times do |i|
1172
- transaction.add_breadcrumb(
1173
- "network",
1174
- "GET http://localhost",
1175
- "User made external network request",
1176
- { :code => i + 1 },
1177
- Time.parse("10-10-2010 10:00:00 UTC")
1178
- )
1179
- end
1180
- transaction._sample
1181
- end
1182
-
1183
- it "stores last <LIMIT> breadcrumbs on the transaction" do
1184
- expect(transaction.to_h["sample_data"]["breadcrumbs"].length).to eql(20)
1185
- expect(transaction.to_h["sample_data"]["breadcrumbs"][0]).to eq(
1186
- "action" => "GET http://localhost",
1187
- "category" => "network",
1188
- "message" => "User made external network request",
1189
- "metadata" => { "code" => 3 },
1190
- "time" => 1286704800 # rubocop:disable Style/NumericLiterals
1191
- )
1192
- expect(transaction.to_h["sample_data"]["breadcrumbs"][19]).to eq(
1193
- "action" => "GET http://localhost",
1194
- "category" => "network",
1195
- "message" => "User made external network request",
1196
- "metadata" => { "code" => 22 },
1197
- "time" => 1286704800 # rubocop:disable Style/NumericLiterals
1198
- )
1199
- end
1200
- end
1201
-
1202
- context "with defaults" do
1203
- it "stores breadcrumb with defaults on transaction" do
1204
- timeframe_start = Time.now.utc.to_i
1205
- transaction.add_breadcrumb("user_action", "clicked HOME")
1206
- transaction._sample
1207
- timeframe_end = Time.now.utc.to_i
1208
-
1209
- expect(transaction).to include_breadcrumb(
1210
- "clicked HOME",
1211
- "user_action",
1212
- "",
1213
- {},
1214
- be_between(timeframe_start, timeframe_end)
1215
- )
1216
- end
1217
- end
1218
-
1219
- context "with metadata argument that's not a Hash" do
1220
- it "does not add the breadcrumb and logs and error" do
1221
- logs =
1222
- capture_logs do
1223
- transaction.add_breadcrumb("category", "action", "message", "invalid metadata")
1224
- end
1225
- transaction._sample
1226
-
1227
- expect(transaction).to_not include_breadcrumbs
1228
- expect(logs).to contains_log(
1229
- :error,
1230
- "add_breadcrumb: Cannot add breadcrumb. The given metadata argument is not a Hash."
1231
- )
1232
- end
1233
- end
1234
- end
1235
-
1236
- describe "#set_action" do
1237
- let(:transaction) { new_transaction }
1238
-
1239
- context "when the action is set" do
1240
- it "updates the action name on the transaction" do
1241
- action_name = "PagesController#show"
1242
- transaction.set_action(action_name)
1243
-
1244
- expect(transaction.action).to eq(action_name)
1245
- expect(transaction).to have_action(action_name)
1246
- end
1247
- end
1248
-
1249
- context "when the action is nil" do
1250
- it "does not update the action name on the transaction" do
1251
- action_name = "PagesController#show"
1252
- transaction.set_action(action_name)
1253
- transaction.set_action(nil)
1254
-
1255
- expect(transaction.action).to eq(action_name)
1256
- expect(transaction).to have_action(action_name)
1257
- end
1258
- end
1259
- end
1260
-
1261
- describe "#set_action_if_nil" do
1262
- let(:transaction) { new_transaction }
1263
-
1264
- context "when the action is not set" do
1265
- it "updates the action name on the transaction" do
1266
- expect(transaction.action).to eq(nil)
1267
- expect(transaction).to_not have_action
1268
-
1269
- action_name = "PagesController#show"
1270
- transaction.set_action_if_nil(action_name)
1271
-
1272
- expect(transaction.action).to eq(action_name)
1273
- expect(transaction).to have_action(action_name)
1274
- end
1275
-
1276
- context "when the given action is nil" do
1277
- it "does not update the action name on the transaction" do
1278
- action_name = "something"
1279
- transaction.set_action("something")
1280
- transaction.set_action_if_nil(nil)
1281
-
1282
- expect(transaction.action).to eq(action_name)
1283
- expect(transaction).to have_action(action_name)
1284
- end
1285
- end
1286
- end
1287
-
1288
- context "when the action is set" do
1289
- it "does not update the action name on the transaction" do
1290
- action_name = "something"
1291
- transaction.set_action("something")
1292
- transaction.set_action_if_nil("something else")
1293
-
1294
- expect(transaction.action).to eq(action_name)
1295
- expect(transaction).to have_action(action_name)
1296
- end
1297
- end
1298
- end
1299
-
1300
- describe "#set_namespace" do
1301
- let(:transaction) { new_transaction }
1302
-
1303
- context "when the namespace is not nil" do
1304
- it "updates the namespace on the transaction" do
1305
- namespace = "custom"
1306
- transaction.set_namespace(namespace)
1307
-
1308
- expect(transaction.namespace).to eq namespace
1309
- expect(transaction).to have_namespace(namespace)
1310
- end
1311
- end
1312
-
1313
- context "when the namespace is nil" do
1314
- it "does not update the namespace on the transaction" do
1315
- namespace = "custom"
1316
- transaction.set_namespace(namespace)
1317
- transaction.set_namespace(nil)
1318
-
1319
- expect(transaction.namespace).to eq(namespace)
1320
- expect(transaction).to have_namespace(namespace)
1321
- end
1322
- end
1323
- end
1324
-
1325
- describe "#set_queue_start" do
1326
- let(:transaction) { new_transaction }
1327
-
1328
- it "sets the queue start in extension" do
1329
- transaction.set_queue_start(10)
1330
-
1331
- expect(transaction).to have_queue_start(10)
1332
- end
1333
-
1334
- it "does not set the queue start in extension when value is nil" do
1335
- transaction.set_queue_start(nil)
1336
-
1337
- expect(transaction).to_not have_queue_start
1338
- end
1339
-
1340
- it "does not raise an error when the queue start is too big" do
1341
- expect(transaction.ext).to receive(:set_queue_start).and_raise(RangeError)
1342
-
1343
- expect(Appsignal.internal_logger).to receive(:warn).with("Queue start value 10 is too big")
1344
-
1345
- transaction.set_queue_start(10)
1346
- end
1347
- end
1348
-
1349
- describe "#set_metadata" do
1350
- let(:transaction) { new_transaction }
1351
-
1352
- it "updates the metadata on the transaction" do
1353
- transaction.set_metadata("request_method", "GET")
1354
-
1355
- expect(transaction).to include_metadata("request_method" => "GET")
1356
- end
1357
-
1358
- context "when filter_metadata includes metadata key" do
1359
- let(:options) { { :filter_metadata => ["filter_key"] } }
1360
-
1361
- it "does not set the metadata on the transaction" do
1362
- transaction.set_metadata(:filter_key, "filtered value")
1363
- transaction.set_metadata("filter_key", "filtered value")
1364
-
1365
- expect(transaction).to_not include_metadata("filter_key" => anything)
1366
- end
1367
- end
1368
-
1369
- context "when the key is nil" do
1370
- it "does not update the metadata on the transaction" do
1371
- transaction.set_metadata(nil, "GET")
1372
-
1373
- expect(transaction).to_not include_metadata
1374
- end
1375
- end
1376
-
1377
- context "when the value is nil" do
1378
- it "does not update the metadata on the transaction" do
1379
- transaction.set_metadata("request_method", nil)
1380
-
1381
- expect(transaction).to_not include_metadata
1382
- end
1383
- end
1384
- end
1385
-
1386
- describe "storing sample data" do
1387
- let(:transaction) { new_transaction }
1388
-
1389
- it "stores sample data on the transaction" do
1390
- transaction.set_params(
1391
- "string_param" => "string_value",
1392
- :symbol_param => "symbol_value",
1393
- "integer" => 123,
1394
- "float" => 123.45,
1395
- "array" => ["abc", 456, { "option" => true }],
1396
- "hash" => { "hash_key" => "hash_value" }
1397
- )
1398
-
1399
- transaction._sample
1400
- expect(transaction).to include_params(
1401
- "string_param" => "string_value",
1402
- "symbol_param" => "symbol_value",
1403
- "integer" => 123,
1404
- "float" => 123.45,
1405
- "array" => ["abc", 456, { "option" => true }],
1406
- "hash" => { "hash_key" => "hash_value" }
1407
- )
1408
- end
1409
-
1410
- it "does not store non-Array and non-Hash data" do
1411
- logs =
1412
- capture_logs do
1413
- transaction.set_params("some string")
1414
- transaction._sample
1415
- expect(transaction).to_not include_params
1416
-
1417
- transaction.set_params(123)
1418
- transaction._sample
1419
- expect(transaction).to_not include_params
1420
-
1421
- transaction.set_params(Class.new)
1422
- transaction._sample
1423
- expect(transaction).to_not include_params
1424
-
1425
- set = Set.new
1426
- set.add("some value")
1427
- transaction.set_params(set)
1428
- transaction._sample
1429
- expect(transaction).to_not include_params
1430
- end
1431
-
1432
- expect(logs).to contains_log(
1433
- :error,
1434
- %(Sample data 'params': Unsupported data type 'String' received: "some string")
1435
- )
1436
- expect(logs).to contains_log(
1437
- :error,
1438
- %(Sample data 'params': Unsupported data type 'Integer' received: 123)
1439
- )
1440
- expect(logs).to contains_log(
1441
- :error,
1442
- %(Sample data 'params': Unsupported data type 'Class' received: #<Class)
1443
- )
1444
- expect(logs).to contains_log(
1445
- :error,
1446
- %(Sample data 'params': Unsupported data type 'Set' received: #<Set: {"some value"}>)
1447
- )
1448
- end
1449
-
1450
- it "does not store data that can't be converted to JSON" do
1451
- klass = Class.new do
1452
- def initialize
1453
- @calls = 0
1454
- end
1455
-
1456
- def to_s
1457
- raise "foo" if @calls > 0 # Cause a deliberate error
1458
-
1459
- @calls += 1
1460
- end
1461
- end
1462
-
1463
- transaction.set_params(klass.new => 1)
1464
- logs = capture_logs { transaction._sample }
1465
-
1466
- expect(transaction).to_not include_params
1467
- expect(logs).to contains_log :error,
1468
- "Error generating data (RuntimeError: foo) for"
1469
- end
1470
- end
1471
-
1472
- describe "#set_sample_data" do
1473
- let(:transaction) { new_transaction }
1474
-
1475
- it "updates the sample data on the transaction" do
1476
- silence do
1477
- transaction.send(
1478
- :set_sample_data,
1479
- "params",
1480
- :controller => "blog_posts",
1481
- :action => "show",
1482
- :id => "1"
1483
- )
1484
- end
1485
-
1486
- expect(transaction).to include_params(
1487
- "action" => "show",
1488
- "controller" => "blog_posts",
1489
- "id" => "1"
1490
- )
1491
- end
1492
-
1493
- context "when the data is no Array or Hash" do
1494
- it "does not update the sample data on the transaction" do
1495
- logs =
1496
- capture_logs do
1497
- silence { transaction.send(:set_sample_data, "params", "string") }
1498
- end
1499
-
1500
- expect(transaction.to_h["sample_data"]).to eq({})
1501
- expect(logs).to contains_log :error,
1502
- %(Invalid sample data for 'params'. Value is not an Array or Hash: '"string"')
1503
- end
1504
- end
1505
-
1506
- context "when the data cannot be converted to JSON" do
1507
- it "does not update the sample data on the transaction" do
1508
- klass = Class.new do
1509
- def to_s
1510
- raise "foo" # Cause a deliberate error
1511
- end
1512
- end
1513
- logs =
1514
- capture_logs do
1515
- silence { transaction.send(:set_sample_data, "params", klass.new => 1) }
1516
- end
1517
-
1518
- expect(transaction).to_not include_params
1519
- expect(logs).to contains_log :error,
1520
- "Error generating data (RuntimeError: foo) for"
1521
- end
1522
- end
1523
- end
1524
-
1525
- describe "#add_error" do
1526
- let(:transaction) { create_transaction }
1527
-
1528
- let(:error) do
1529
- ExampleStandardError.new("test message").tap do |e|
1530
- e.set_backtrace(["line 1"])
1531
- end
1532
- end
1533
-
1534
- context "when error argument is not an error" do
1535
- let(:error) { Object.new }
1536
-
1537
- it "does not add the error" do
1538
- logs = capture_logs { transaction.add_error(error) }
1539
-
1540
- expect(transaction).to_not have_error
1541
- expect(logs).to contains_log(
1542
- :error,
1543
- "Appsignal::Transaction#add_error: Cannot add error. " \
1544
- "The given value is not an exception: #{error.inspect}"
1545
- )
1546
- end
1547
- end
1548
-
1549
- context "when AppSignal is not active" do
1550
- it "does not add the error" do
1551
- allow(Appsignal).to receive(:active?).and_return(false)
1552
-
1553
- transaction.add_error(error)
1554
-
1555
- expect(transaction).to_not have_error
1556
- end
1557
- end
1558
-
1559
- context "when a block is given" do
1560
- it "stores the block in the error blocks" do
1561
- block = proc { "block" }
1562
-
1563
- transaction.add_error(error, &block)
1564
-
1565
- expect(transaction.error_blocks).to eq({
1566
- error => [block]
1567
- })
1568
- end
1569
- end
1570
-
1571
- context "when no error is set in the transaction" do
1572
- it "sets the error on the transaction" do
1573
- transaction.add_error(error)
1574
-
1575
- expect(transaction).to have_error(
1576
- "ExampleStandardError",
1577
- "test message",
1578
- ["line 1"]
1579
- )
1580
- end
1581
-
1582
- it "does store the error in the errors" do
1583
- transaction.add_error(error)
1584
-
1585
- expect(transaction.error_blocks).to eq({ error => [] })
1586
- end
1587
- end
1588
-
1589
- context "when an error is already set in the transaction" do
1590
- let(:other_error) do
1591
- ExampleStandardError.new("other test message").tap do |e|
1592
- e.set_backtrace(["line 2"])
1593
- end
1594
- end
1595
-
1596
- before { transaction.set_error(other_error) }
1597
-
1598
- it "stores an error in the errors" do
1599
- transaction.add_error(error)
1600
-
1601
- expect(transaction.error_blocks).to eq({
1602
- other_error => [],
1603
- error => []
1604
- })
1605
- end
1606
-
1607
- it "does not set the error on the extension" do
1608
- transaction.add_error(error)
1609
-
1610
- expect(transaction).to have_error(
1611
- "ExampleStandardError",
1612
- "other test message",
1613
- ["line 2"]
1614
- )
1615
- end
1616
- end
1617
-
1618
- context "when the error has already been added" do
1619
- before { transaction.add_error(error) }
1620
-
1621
- it "does not add the error to the errors" do
1622
- expect(transaction.error_blocks).to eq({ error => [] })
1623
-
1624
- transaction.add_error(error)
1625
-
1626
- expect(transaction.error_blocks).to eq({ error => [] })
1627
- end
1628
-
1629
- context "when a block is given" do
1630
- it "adds the block to the error blocks" do
1631
- block = proc { "block" }
1632
-
1633
- transaction.add_error(error, &block)
1634
-
1635
- expect(transaction.error_blocks).to eq({ error => [block] })
1636
- end
1637
- end
1638
- end
1639
-
1640
- context "when the errors is at the limit" do
1641
- let(:seen_error) { ExampleStandardError.new("error 0") }
1642
-
1643
- before do
1644
- transaction.add_error(seen_error)
1645
-
1646
- 9.times do |i|
1647
- transaction.add_error(ExampleStandardError.new("error #{i}"))
1648
- end
1649
- end
1650
-
1651
- it "does not add a new error to the errors" do
1652
- expect(transaction).to have_error("ExampleStandardError", "error 0", [])
1653
- expect(transaction.error_blocks.length).to eq(10)
1654
- expected_error_blocks = transaction.error_blocks.dup
1655
-
1656
- transaction.add_error(error)
1657
-
1658
- expect(transaction).to have_error("ExampleStandardError", "error 0", [])
1659
- expect(transaction.error_blocks).to eq(expected_error_blocks)
1660
- end
1661
-
1662
- it "logs a debug message" do
1663
- logs = capture_logs { transaction.add_error(error) }
1664
-
1665
- expect(logs).to contains_log(
1666
- :warn,
1667
- "Appsignal::Transaction#add_error: Transaction has more than 10 distinct errors. " \
1668
- "Only the first 10 distinct errors will be reported."
1669
- )
1670
- end
1671
-
1672
- context "when the error has already been added" do
1673
- it "does not add the error to the errors" do
1674
- expect(transaction.error_blocks.length).to eq(10)
1675
-
1676
- transaction.add_error(seen_error)
1677
-
1678
- expect(transaction.error_blocks.length).to eq(10)
1679
- end
1680
-
1681
- it "does add the block to the error blocks" do
1682
- block = proc { "block" }
1683
-
1684
- transaction.add_error(seen_error, &block)
1685
-
1686
- expect(transaction.error_blocks[seen_error]).to eq([block])
1687
- end
1688
-
1689
- it "does not log a debug message" do
1690
- logs = capture_logs { transaction.add_error(seen_error) }
1691
-
1692
- expect(logs).to_not contains_log(
1693
- :warn,
1694
- "Appsignal::Transaction#add_error: Transaction has more than 10 distinct errors. " \
1695
- "Only the first 10 distinct errors will be reported."
1696
- )
1697
- end
1698
- end
1699
- end
1700
-
1701
- context "with a PG::UniqueViolation" do
1702
- let(:error) do
1703
- PG::UniqueViolation.new(
1704
- "ERROR: duplicate key value violates unique constraint " \
1705
- "\"index_users_on_email\" DETAIL: Key (email)=(test@test.com) already exists."
1706
- )
1707
- end
1708
- before do
1709
- stub_const("PG::UniqueViolation", Class.new(StandardError))
1710
- transaction.add_error(error)
1711
- end
1712
-
1713
- it "returns a sanizited error message" do
1714
- expect(transaction).to have_error(
1715
- "PG::UniqueViolation",
1716
- "ERROR: duplicate key value violates unique constraint " \
1717
- "\"index_users_on_email\" DETAIL: Key (email)=(?) already exists."
1718
- )
1719
- end
1720
- end
1721
-
1722
- context "with a ActiveRecord::RecordNotUnique" do
1723
- let(:error) do
1724
- ActiveRecord::RecordNotUnique.new(
1725
- "PG::UniqueViolation: ERROR: duplicate key value violates unique constraint " \
1726
- "\"example_constraint\"\nDETAIL: Key (email)=(foo@example.com) already exists."
1727
- )
1728
- end
1729
- before do
1730
- stub_const("ActiveRecord::RecordNotUnique", Class.new(StandardError))
1731
- transaction.add_error(error)
1732
- end
1733
-
1734
- it "returns a sanizited error message" do
1735
- expect(transaction).to have_error(
1736
- "ActiveRecord::RecordNotUnique",
1737
- "PG::UniqueViolation: ERROR: duplicate key value violates unique constraint " \
1738
- "\"example_constraint\"\nDETAIL: Key (email)=(?) already exists."
1739
- )
1740
- end
1741
- end
1742
-
1743
- context "with Rails module but without backtrace_cleaner method" do
1744
- it "returns the backtrace uncleaned" do
1745
- stub_const("Rails", Module.new)
1746
- error = ExampleStandardError.new("error message")
1747
- error.set_backtrace(["line 1", "line 2"])
1748
- transaction.add_error(error)
1749
-
1750
- expect(last_transaction).to have_error(
1751
- "ExampleStandardError",
1752
- "error message",
1753
- ["line 1", "line 2"]
1754
- )
1755
- end
1756
- end
1757
-
1758
- if rails_present?
1759
- context "with Rails" do
1760
- it "cleans the backtrace with the Rails backtrace cleaner" do
1761
- ::Rails.backtrace_cleaner.add_filter do |line|
1762
- line.tr("2", "?")
1763
- end
1764
-
1765
- error = ExampleStandardError.new("error message")
1766
- error.set_backtrace(["line 1", "line 2"])
1767
- transaction.add_error(error)
1768
- expect(last_transaction).to have_error(
1769
- "ExampleStandardError",
1770
- "error message",
1771
- ["line 1", "line ?"]
1772
- )
1773
- end
1774
- end
1775
- end
1776
- end
1777
-
1778
- describe "#_set_error" do
1779
- let(:transaction) { new_transaction }
1780
- let(:env) { http_request_env_with_data }
1781
- let(:error) do
1782
- ExampleStandardError.new("test message").tap do |e|
1783
- e.set_backtrace(["line 1"])
1784
- end
1785
- end
1786
-
1787
- it "responds to add_exception for backwards compatibility" do
1788
- expect(transaction).to respond_to(:add_exception)
1789
- end
1790
-
1791
- it "does not add the error to the errors" do
1792
- transaction.send(:_set_error, error)
1793
-
1794
- expect(transaction.error_blocks).to be_empty
1795
- end
1796
-
1797
- context "for a http request" do
1798
- it "sets an error on the transaction" do
1799
- transaction.send(:_set_error, error)
1800
-
1801
- expect(transaction).to have_error(
1802
- "ExampleStandardError",
1803
- "test message",
1804
- ["line 1"]
1805
- )
1806
- end
1807
- end
1808
-
1809
- context "when the error has no causes" do
1810
- it "should set an empty causes array as sample data" do
1811
- transaction.send(:_set_error, error)
1812
-
1813
- expect(transaction).to include_error_causes([])
1814
- end
1815
- end
1816
-
1817
- context "when the error has multiple causes" do
1818
- let(:error) do
1819
- e = ExampleStandardError.new("test message")
1820
- e.set_backtrace(["line 1"])
1821
- e2 = RuntimeError.new("cause message")
1822
- e3 = StandardError.new("cause message 2")
1823
- allow(e).to receive(:cause).and_return(e2)
1824
- allow(e2).to receive(:cause).and_return(e3)
1825
- e
1826
- end
1827
-
1828
- let(:error_without_cause) do
1829
- ExampleStandardError.new("error without cause")
1830
- end
1831
-
1832
- it "sends the causes information as sample data" do
1833
- transaction.send(:_set_error, error)
1834
-
1835
- expect(transaction).to have_error(
1836
- "ExampleStandardError",
1837
- "test message",
1838
- ["line 1"]
1839
- )
1840
- expect(transaction).to include_error_causes(
1841
- [
1842
- {
1843
- "name" => "RuntimeError",
1844
- "message" => "cause message"
1845
- },
1846
- {
1847
- "name" => "StandardError",
1848
- "message" => "cause message 2"
1849
- }
1850
- ]
1851
- )
1852
- end
1853
-
1854
- it "does not keep error causes from previously set errors" do
1855
- transaction.send(:_set_error, error)
1856
- transaction.send(:_set_error, error_without_cause)
1857
-
1858
- expect(transaction).to have_error(
1859
- "ExampleStandardError",
1860
- "error without cause",
1861
- []
1862
- )
1863
-
1864
- expect(transaction).to include_error_causes([])
1865
- end
1866
- end
1867
-
1868
- context "when the error has too many causes" do
1869
- let(:error) do
1870
- e = ExampleStandardError.new("root cause error")
1871
-
1872
- 11.times do |i|
1873
- next_e = ExampleStandardError.new("wrapper error #{i}")
1874
- allow(next_e).to receive(:cause).and_return(e)
1875
- e = next_e
1876
- end
1877
- e.set_backtrace(["line 1"])
1878
- e
1879
- end
1880
-
1881
- it "sends only the first causes as sample data" do
1882
- expected_error_causes =
1883
- Array.new(10) do |i|
1884
- {
1885
- "name" => "ExampleStandardError",
1886
- "message" => "wrapper error #{9 - i}"
1887
- }
1888
- end
1889
- expected_error_causes.last["is_root_cause"] = false
1890
-
1891
- logs = capture_logs { transaction.send(:_set_error, error) }
1892
-
1893
- expect(transaction).to have_error(
1894
- "ExampleStandardError",
1895
- "wrapper error 10",
1896
- ["line 1"]
1897
- )
1898
- expect(transaction).to include_error_causes(expected_error_causes)
1899
- expect(logs).to contains_log(
1900
- :debug,
1901
- "Appsignal::Transaction#add_error: Error has more " \
1902
- "than 10 error causes. Only the first 10 " \
1903
- "will be reported."
1904
- )
1905
- end
1906
- end
1907
-
1908
- context "when error message is nil" do
1909
- let(:error) do
1910
- e = ExampleStandardError.new
1911
- allow(e).to receive(:message).and_return(nil)
1912
- e.set_backtrace(["line 1"])
1913
- e
1914
- end
1915
-
1916
- it "does not raise an error" do
1917
- transaction.send(:_set_error, error)
1918
- end
1919
-
1920
- it "sets an error on the transaction without an error message" do
1921
- transaction.send(:_set_error, error)
1922
-
1923
- expect(transaction).to have_error(
1924
- "ExampleStandardError",
1925
- "",
1926
- ["line 1"]
1927
- )
1928
- end
1929
- end
1930
- end
1931
-
1932
- describe "#start_event" do
1933
- let(:transaction) { new_transaction }
1934
-
1935
- it "starts the event in the extension" do
1936
- expect(transaction.ext).to receive(:start_event).with(0).and_call_original
1937
-
1938
- transaction.start_event
1939
- end
1940
-
1941
- context "when transaction is paused" do
1942
- it "does not start the event" do
1943
- transaction.pause!
1944
- expect(transaction.ext).to_not receive(:start_event)
1945
-
1946
- transaction.start_event
1947
- end
1948
- end
1949
- end
1950
-
1951
- describe "#finish_event" do
1952
- let(:transaction) { new_transaction }
1953
- let(:fake_gc_time) { 0 }
1954
-
1955
- it "should finish the event in the extension" do
1956
- expect(transaction.ext).to receive(:finish_event).with(
1957
- "name",
1958
- "title",
1959
- "body",
1960
- 1,
1961
- fake_gc_time
1962
- ).and_call_original
1963
-
1964
- transaction.finish_event(
1965
- "name",
1966
- "title",
1967
- "body",
1968
- 1
1969
- )
1970
- end
1971
-
1972
- it "should finish the event in the extension with nil arguments" do
1973
- expect(transaction.ext).to receive(:finish_event).with(
1974
- "name",
1975
- "",
1976
- "",
1977
- 0,
1978
- fake_gc_time
1979
- ).and_call_original
1980
-
1981
- transaction.finish_event(
1982
- "name",
1983
- nil,
1984
- nil,
1985
- nil
1986
- )
1987
- end
1988
-
1989
- context "when transaction is paused" do
1990
- it "does not finish the event" do
1991
- transaction.pause!
1992
- expect(transaction.ext).to_not receive(:finish_event)
1993
-
1994
- transaction.start_event
1995
- end
1996
- end
1997
- end
1998
-
1999
- describe "#record_event" do
2000
- let(:transaction) { new_transaction }
2001
- let(:fake_gc_time) { 0 }
2002
-
2003
- it "should record the event in the extension" do
2004
- expect(transaction.ext).to receive(:record_event).with(
2005
- "name",
2006
- "title",
2007
- "body",
2008
- 1,
2009
- 1000,
2010
- fake_gc_time
2011
- ).and_call_original
2012
-
2013
- transaction.record_event(
2014
- "name",
2015
- "title",
2016
- "body",
2017
- 1000,
2018
- 1
2019
- )
2020
- end
2021
-
2022
- it "should finish the event in the extension with nil arguments" do
2023
- expect(transaction.ext).to receive(:record_event).with(
2024
- "name",
2025
- "",
2026
- "",
2027
- 0,
2028
- 1000,
2029
- fake_gc_time
2030
- ).and_call_original
2031
-
2032
- transaction.record_event(
2033
- "name",
2034
- nil,
2035
- nil,
2036
- 1000,
2037
- nil
2038
- )
2039
- end
2040
-
2041
- context "when transaction is paused" do
2042
- it "does not record the event" do
2043
- transaction.pause!
2044
- expect(transaction.ext).to_not receive(:record_event)
2045
-
2046
- transaction.record_event(
2047
- "name",
2048
- nil,
2049
- nil,
2050
- 1000,
2051
- nil
2052
- )
2053
- end
2054
- end
2055
- end
2056
-
2057
- describe "#instrument" do
2058
- it_behaves_like "instrument helper" do
2059
- let(:transaction) { new_transaction }
2060
- let(:instrumenter) { transaction }
2061
- end
2062
- end
2063
-
2064
- # private
2065
-
2066
- describe ".to_hash / .to_h" do
2067
- let(:transaction) { new_transaction }
2068
- subject { transaction.to_hash }
2069
-
2070
- context "when extension returns serialized JSON" do
2071
- it "parses the result and returns a Hash" do
2072
- expect(subject).to include(
2073
- "action" => nil,
2074
- "error" => nil,
2075
- "events" => [],
2076
- "id" => kind_of(String),
2077
- "metadata" => {},
2078
- "namespace" => default_namespace,
2079
- "sample_data" => {}
2080
- )
2081
- end
2082
- end
2083
-
2084
- context "when the extension returns invalid serialized JSON" do
2085
- before do
2086
- expect(transaction.ext).to receive(:to_json).and_return("foo")
2087
- end
2088
-
2089
- it "raises a JSON parse error" do
2090
- expect { subject }.to raise_error(JSON::ParserError)
2091
- end
2092
- end
2093
- end
2094
-
2095
- describe Appsignal::Transaction::NilTransaction do
2096
- subject { Appsignal::Transaction::NilTransaction.new }
2097
-
2098
- it "has method stubs" do
2099
- subject.complete
2100
- subject.pause!
2101
- subject.resume!
2102
- subject.paused?
2103
- subject.store(:key)
2104
- subject.add_tags(:tag => 1)
2105
- subject.set_action("action")
2106
- subject.set_http_or_background_action
2107
- subject.set_queue_start(1)
2108
- subject.set_http_or_background_queue_start
2109
- subject.set_metadata("key", "value")
2110
- subject.set_sample_data("key", "data")
2111
- subject._sample
2112
- subject.set_error("a")
2113
- end
2114
- end
2115
- end