appsignal 4.0.5 → 4.0.7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (203) 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/build_matrix.yml +2 -1
  6. data/ext/agent.rb +27 -27
  7. data/lib/appsignal/check_in/scheduler.rb +3 -4
  8. data/lib/appsignal/check_in.rb +1 -1
  9. data/lib/appsignal/config.rb +1 -3
  10. data/lib/appsignal/integrations/que.rb +8 -2
  11. data/lib/appsignal/integrations/resque.rb +1 -6
  12. data/lib/appsignal/utils/hash_sanitizer.rb +4 -0
  13. data/lib/appsignal/version.rb +1 -1
  14. metadata +2 -191
  15. data/.github/ISSUE_TEMPLATE/bug_report.md +0 -31
  16. data/.github/ISSUE_TEMPLATE/chore.md +0 -14
  17. data/.github/workflows/ci.yml +0 -3150
  18. data/.github/workflows/create_release_from_tag.yml +0 -62
  19. data/.gitignore +0 -35
  20. data/.gitmodules +0 -3
  21. data/.rspec +0 -4
  22. data/.yardopts +0 -8
  23. data/benchmark.rake +0 -139
  24. data/gemfiles/capistrano2.gemfile +0 -6
  25. data/gemfiles/capistrano3.gemfile +0 -7
  26. data/gemfiles/dry-monitor.gemfile +0 -5
  27. data/gemfiles/grape.gemfile +0 -5
  28. data/gemfiles/hanami-2.0.gemfile +0 -7
  29. data/gemfiles/hanami-2.1.gemfile +0 -7
  30. data/gemfiles/http5.gemfile +0 -5
  31. data/gemfiles/no_dependencies.gemfile +0 -10
  32. data/gemfiles/padrino.gemfile +0 -7
  33. data/gemfiles/psych-3.gemfile +0 -5
  34. data/gemfiles/psych-4.gemfile +0 -5
  35. data/gemfiles/que.gemfile +0 -5
  36. data/gemfiles/rails-6.0.gemfile +0 -10
  37. data/gemfiles/rails-6.1.gemfile +0 -11
  38. data/gemfiles/rails-7.0.gemfile +0 -11
  39. data/gemfiles/rails-7.1.gemfile +0 -11
  40. data/gemfiles/rails-7.2.gemfile +0 -11
  41. data/gemfiles/redis-4.gemfile +0 -5
  42. data/gemfiles/redis-5.gemfile +0 -6
  43. data/gemfiles/resque-2.gemfile +0 -6
  44. data/gemfiles/sequel.gemfile +0 -10
  45. data/gemfiles/sinatra.gemfile +0 -5
  46. data/gemfiles/webmachine1.gemfile +0 -7
  47. data/gemfiles/webmachine2.gemfile +0 -6
  48. data/mono.yml +0 -16
  49. data/spec/.rubocop.yml +0 -7
  50. data/spec/lib/appsignal/auth_check_spec.rb +0 -84
  51. data/spec/lib/appsignal/capistrano2_spec.rb +0 -227
  52. data/spec/lib/appsignal/capistrano3_spec.rb +0 -284
  53. data/spec/lib/appsignal/check_in/cron_spec.rb +0 -202
  54. data/spec/lib/appsignal/check_in/scheduler_spec.rb +0 -443
  55. data/spec/lib/appsignal/cli/demo_spec.rb +0 -46
  56. data/spec/lib/appsignal/cli/diagnose/paths_spec.rb +0 -16
  57. data/spec/lib/appsignal/cli/diagnose/utils_spec.rb +0 -86
  58. data/spec/lib/appsignal/cli/diagnose_spec.rb +0 -1553
  59. data/spec/lib/appsignal/cli/helpers_spec.rb +0 -179
  60. data/spec/lib/appsignal/cli/install_spec.rb +0 -848
  61. data/spec/lib/appsignal/cli_spec.rb +0 -56
  62. data/spec/lib/appsignal/config_spec.rb +0 -1380
  63. data/spec/lib/appsignal/demo_spec.rb +0 -83
  64. data/spec/lib/appsignal/environment_spec.rb +0 -190
  65. data/spec/lib/appsignal/event_formatter/action_view/render_formatter_spec.rb +0 -60
  66. data/spec/lib/appsignal/event_formatter/active_record/instantiation_formatter_spec.rb +0 -21
  67. data/spec/lib/appsignal/event_formatter/active_record/sql_formatter_spec.rb +0 -21
  68. data/spec/lib/appsignal/event_formatter/elastic_search/search_formatter_spec.rb +0 -52
  69. data/spec/lib/appsignal/event_formatter/faraday/request_formatter_spec.rb +0 -21
  70. data/spec/lib/appsignal/event_formatter/mongo_ruby_driver/query_formatter_spec.rb +0 -84
  71. data/spec/lib/appsignal/event_formatter/rom/sql_formatter_spec.rb +0 -22
  72. data/spec/lib/appsignal/event_formatter/sequel/sql_formatter_spec.rb +0 -30
  73. data/spec/lib/appsignal/event_formatter/view_component/render_formatter_spec.rb +0 -41
  74. data/spec/lib/appsignal/event_formatter_spec.rb +0 -193
  75. data/spec/lib/appsignal/extension/jruby_spec.rb +0 -46
  76. data/spec/lib/appsignal/extension_install_failure_spec.rb +0 -20
  77. data/spec/lib/appsignal/extension_spec.rb +0 -178
  78. data/spec/lib/appsignal/garbage_collection_spec.rb +0 -98
  79. data/spec/lib/appsignal/hooks/action_cable_spec.rb +0 -345
  80. data/spec/lib/appsignal/hooks/action_mailer_spec.rb +0 -55
  81. data/spec/lib/appsignal/hooks/active_support_notifications/finish_with_state_shared_examples.rb +0 -23
  82. data/spec/lib/appsignal/hooks/active_support_notifications/instrument_shared_examples.rb +0 -99
  83. data/spec/lib/appsignal/hooks/active_support_notifications/start_finish_shared_examples.rb +0 -47
  84. data/spec/lib/appsignal/hooks/active_support_notifications_spec.rb +0 -47
  85. data/spec/lib/appsignal/hooks/activejob_spec.rb +0 -650
  86. data/spec/lib/appsignal/hooks/at_exit_spec.rb +0 -105
  87. data/spec/lib/appsignal/hooks/celluloid_spec.rb +0 -40
  88. data/spec/lib/appsignal/hooks/data_mapper_spec.rb +0 -40
  89. data/spec/lib/appsignal/hooks/delayed_job_spec.rb +0 -38
  90. data/spec/lib/appsignal/hooks/dry_monitor_spec.rb +0 -83
  91. data/spec/lib/appsignal/hooks/excon_spec.rb +0 -67
  92. data/spec/lib/appsignal/hooks/gvl_spec.rb +0 -145
  93. data/spec/lib/appsignal/hooks/http_spec.rb +0 -37
  94. data/spec/lib/appsignal/hooks/mongo_ruby_driver_spec.rb +0 -46
  95. data/spec/lib/appsignal/hooks/mri_spec.rb +0 -23
  96. data/spec/lib/appsignal/hooks/net_http_spec.rb +0 -18
  97. data/spec/lib/appsignal/hooks/passenger_spec.rb +0 -30
  98. data/spec/lib/appsignal/hooks/puma_spec.rb +0 -80
  99. data/spec/lib/appsignal/hooks/que_spec.rb +0 -19
  100. data/spec/lib/appsignal/hooks/rake_spec.rb +0 -144
  101. data/spec/lib/appsignal/hooks/redis_client_spec.rb +0 -218
  102. data/spec/lib/appsignal/hooks/redis_spec.rb +0 -124
  103. data/spec/lib/appsignal/hooks/resque_spec.rb +0 -27
  104. data/spec/lib/appsignal/hooks/sequel_spec.rb +0 -44
  105. data/spec/lib/appsignal/hooks/shoryuken_spec.rb +0 -29
  106. data/spec/lib/appsignal/hooks/sidekiq_spec.rb +0 -115
  107. data/spec/lib/appsignal/hooks/unicorn_spec.rb +0 -63
  108. data/spec/lib/appsignal/hooks/webmachine_spec.rb +0 -24
  109. data/spec/lib/appsignal/hooks_spec.rb +0 -124
  110. data/spec/lib/appsignal/integrations/data_mapper_spec.rb +0 -74
  111. data/spec/lib/appsignal/integrations/delayed_job_plugin_spec.rb +0 -454
  112. data/spec/lib/appsignal/integrations/http_spec.rb +0 -111
  113. data/spec/lib/appsignal/integrations/mongo_ruby_driver_spec.rb +0 -154
  114. data/spec/lib/appsignal/integrations/net_http_spec.rb +0 -33
  115. data/spec/lib/appsignal/integrations/object_spec.rb +0 -347
  116. data/spec/lib/appsignal/integrations/puma_spec.rb +0 -150
  117. data/spec/lib/appsignal/integrations/que_spec.rb +0 -152
  118. data/spec/lib/appsignal/integrations/railtie_spec.rb +0 -457
  119. data/spec/lib/appsignal/integrations/resque_spec.rb +0 -155
  120. data/spec/lib/appsignal/integrations/shoryuken_spec.rb +0 -165
  121. data/spec/lib/appsignal/integrations/sidekiq_spec.rb +0 -640
  122. data/spec/lib/appsignal/integrations/webmachine_spec.rb +0 -136
  123. data/spec/lib/appsignal/loaders/grape_spec.rb +0 -12
  124. data/spec/lib/appsignal/loaders/hanami_spec.rb +0 -92
  125. data/spec/lib/appsignal/loaders/padrino_spec.rb +0 -273
  126. data/spec/lib/appsignal/loaders/sinatra_spec.rb +0 -44
  127. data/spec/lib/appsignal/loaders_spec.rb +0 -144
  128. data/spec/lib/appsignal/logger_spec.rb +0 -205
  129. data/spec/lib/appsignal/marker_spec.rb +0 -51
  130. data/spec/lib/appsignal/probes/gvl_spec.rb +0 -164
  131. data/spec/lib/appsignal/probes/mri_spec.rb +0 -162
  132. data/spec/lib/appsignal/probes/sidekiq_spec.rb +0 -333
  133. data/spec/lib/appsignal/probes_spec.rb +0 -411
  134. data/spec/lib/appsignal/rack/abstract_middleware_spec.rb +0 -370
  135. data/spec/lib/appsignal/rack/body_wrapper_spec.rb +0 -319
  136. data/spec/lib/appsignal/rack/event_handler_spec.rb +0 -441
  137. data/spec/lib/appsignal/rack/grape_middleware_spec.rb +0 -201
  138. data/spec/lib/appsignal/rack/hanami_middleware_spec.rb +0 -36
  139. data/spec/lib/appsignal/rack/instrumentation_middleware_spec.rb +0 -38
  140. data/spec/lib/appsignal/rack/rails_instrumentation_spec.rb +0 -126
  141. data/spec/lib/appsignal/rack/sinatra_instrumentation_spec.rb +0 -217
  142. data/spec/lib/appsignal/rack_spec.rb +0 -243
  143. data/spec/lib/appsignal/sample_data_spec.rb +0 -238
  144. data/spec/lib/appsignal/span_spec.rb +0 -141
  145. data/spec/lib/appsignal/system_spec.rb +0 -126
  146. data/spec/lib/appsignal/transaction_spec.rb +0 -2111
  147. data/spec/lib/appsignal/transmitter_spec.rb +0 -198
  148. data/spec/lib/appsignal/utils/data_spec.rb +0 -166
  149. data/spec/lib/appsignal/utils/hash_sanitizer_spec.rb +0 -182
  150. data/spec/lib/appsignal/utils/integration_logger_spec.rb +0 -21
  151. data/spec/lib/appsignal/utils/integration_memory_logger_spec.rb +0 -153
  152. data/spec/lib/appsignal/utils/json_spec.rb +0 -44
  153. data/spec/lib/appsignal/utils/query_params_sanitizer_spec.rb +0 -192
  154. data/spec/lib/appsignal_spec.rb +0 -1919
  155. data/spec/lib/puma/appsignal_spec.rb +0 -334
  156. data/spec/spec_helper.rb +0 -173
  157. data/spec/support/fixtures/generated_config.yml +0 -24
  158. data/spec/support/fixtures/projects/broken/config/appsignal.yml +0 -1
  159. data/spec/support/fixtures/projects/valid/config/appsignal.yml +0 -57
  160. data/spec/support/fixtures/projects/valid/log/.gitkeep +0 -0
  161. data/spec/support/fixtures/projects/valid_with_rails_app/config/application.rb +0 -16
  162. data/spec/support/fixtures/projects/valid_with_rails_app/config/appsignal.yml +0 -56
  163. data/spec/support/fixtures/projects/valid_with_rails_app/config/environment.rb +0 -10
  164. data/spec/support/fixtures/projects/valid_with_rails_app/log/.gitkeep +0 -0
  165. data/spec/support/fixtures/uploaded_file.txt +0 -0
  166. data/spec/support/hanami/hanami_app.rb +0 -29
  167. data/spec/support/helpers/action_mailer_helpers.rb +0 -25
  168. data/spec/support/helpers/activejob_helpers.rb +0 -27
  169. data/spec/support/helpers/api_request_helper.rb +0 -20
  170. data/spec/support/helpers/cli_helpers.rb +0 -40
  171. data/spec/support/helpers/config_helpers.rb +0 -66
  172. data/spec/support/helpers/dependency_helper.rb +0 -150
  173. data/spec/support/helpers/directory_helper.rb +0 -27
  174. data/spec/support/helpers/env_helpers.rb +0 -41
  175. data/spec/support/helpers/environment_metdata_helper.rb +0 -16
  176. data/spec/support/helpers/example_exception.rb +0 -13
  177. data/spec/support/helpers/example_standard_error.rb +0 -13
  178. data/spec/support/helpers/loader_helper.rb +0 -21
  179. data/spec/support/helpers/log_helpers.rb +0 -36
  180. data/spec/support/helpers/rails_helper.rb +0 -28
  181. data/spec/support/helpers/std_streams_helper.rb +0 -94
  182. data/spec/support/helpers/system_helpers.rb +0 -8
  183. data/spec/support/helpers/take_at_most_helper.rb +0 -21
  184. data/spec/support/helpers/time_helpers.rb +0 -11
  185. data/spec/support/helpers/transaction_helpers.rb +0 -122
  186. data/spec/support/helpers/wait_for_helper.rb +0 -39
  187. data/spec/support/matchers/contains_log.rb +0 -26
  188. data/spec/support/matchers/have_colorized_text.rb +0 -28
  189. data/spec/support/matchers/transaction.rb +0 -200
  190. data/spec/support/mocks/appsignal_mock.rb +0 -18
  191. data/spec/support/mocks/dummy_app.rb +0 -20
  192. data/spec/support/mocks/fake_gc_profiler.rb +0 -19
  193. data/spec/support/mocks/fake_gvl_tools.rb +0 -28
  194. data/spec/support/mocks/hash_like.rb +0 -10
  195. data/spec/support/mocks/mock_probe.rb +0 -13
  196. data/spec/support/mocks/puma_mock.rb +0 -43
  197. data/spec/support/shared_examples/instrument.rb +0 -48
  198. data/spec/support/stubs/appsignal/loaders/loader_stub.rb +0 -7
  199. data/spec/support/stubs/delayed_job.rb +0 -0
  200. data/spec/support/stubs/sidekiq/api.rb +0 -4
  201. data/spec/support/testing.rb +0 -194
  202. data/support/bundler_wrapper +0 -12
  203. data/support/install_deps +0 -33
@@ -1,2111 +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
- e = ExampleStandardError.new("test message")
215
- allow(e).to receive(:backtrace).and_return(["line 1"])
216
- e
217
- end
218
-
219
- let(:other_error) do
220
- e = ExampleStandardError.new("other test message")
221
- allow(e).to receive(:backtrace).and_return(["line 2"])
222
- e
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
- e = ExampleStandardError.new("test message")
1530
- allow(e).to receive(:backtrace).and_return(["line 1"])
1531
- e
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
- e = ExampleStandardError.new("other test message")
1592
- allow(e).to receive(:backtrace).and_return(["line 2"])
1593
- e
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
- end
1701
-
1702
- describe "#_set_error" do
1703
- let(:transaction) { new_transaction }
1704
- let(:env) { http_request_env_with_data }
1705
- let(:error) { ExampleStandardError.new("test message") }
1706
-
1707
- it "responds to add_exception for backwards compatibility" do
1708
- expect(transaction).to respond_to(:add_exception)
1709
- end
1710
-
1711
- it "does not add the error to the errors" do
1712
- transaction.send(:_set_error, error)
1713
-
1714
- expect(transaction.error_blocks).to be_empty
1715
- end
1716
-
1717
- context "for a http request" do
1718
- it "sets an error on the transaction" do
1719
- allow(error).to receive(:backtrace).and_return(["line 1"])
1720
- transaction.send(:_set_error, error)
1721
-
1722
- expect(transaction).to have_error(
1723
- "ExampleStandardError",
1724
- "test message",
1725
- ["line 1"]
1726
- )
1727
- end
1728
- end
1729
-
1730
- context "when the error has no causes" do
1731
- it "should set an empty causes array as sample data" do
1732
- transaction.send(:_set_error, error)
1733
-
1734
- expect(transaction).to include_error_causes([])
1735
- end
1736
- end
1737
-
1738
- context "when the error has multiple causes" do
1739
- let(:error) do
1740
- e = ExampleStandardError.new("test message")
1741
- e2 = RuntimeError.new("cause message")
1742
- e3 = StandardError.new("cause message 2")
1743
- allow(e).to receive(:backtrace).and_return(["line 1"])
1744
- allow(e).to receive(:cause).and_return(e2)
1745
- allow(e2).to receive(:cause).and_return(e3)
1746
- e
1747
- end
1748
-
1749
- let(:error_without_cause) do
1750
- ExampleStandardError.new("error without cause")
1751
- end
1752
-
1753
- it "sends the causes information as sample data" do
1754
- transaction.send(:_set_error, error)
1755
-
1756
- expect(transaction).to have_error(
1757
- "ExampleStandardError",
1758
- "test message",
1759
- ["line 1"]
1760
- )
1761
- expect(transaction).to include_error_causes(
1762
- [
1763
- {
1764
- "name" => "RuntimeError",
1765
- "message" => "cause message"
1766
- },
1767
- {
1768
- "name" => "StandardError",
1769
- "message" => "cause message 2"
1770
- }
1771
- ]
1772
- )
1773
- end
1774
-
1775
- it "does not keep error causes from previously set errors" do
1776
- transaction.send(:_set_error, error)
1777
- transaction.send(:_set_error, error_without_cause)
1778
-
1779
- expect(transaction).to have_error(
1780
- "ExampleStandardError",
1781
- "error without cause",
1782
- []
1783
- )
1784
-
1785
- expect(transaction).to include_error_causes([])
1786
- end
1787
- end
1788
-
1789
- context "when the error has too many causes" do
1790
- let(:error) do
1791
- e = ExampleStandardError.new("root cause error")
1792
-
1793
- 11.times do |i|
1794
- next_e = ExampleStandardError.new("wrapper error #{i}")
1795
- allow(next_e).to receive(:cause).and_return(e)
1796
- e = next_e
1797
- end
1798
-
1799
- allow(e).to receive(:backtrace).and_return(["line 1"])
1800
- e
1801
- end
1802
-
1803
- it "sends only the first causes as sample data" do
1804
- expected_error_causes =
1805
- Array.new(10) do |i|
1806
- {
1807
- "name" => "ExampleStandardError",
1808
- "message" => "wrapper error #{9 - i}"
1809
- }
1810
- end
1811
- expected_error_causes.last["is_root_cause"] = false
1812
-
1813
- logs = capture_logs { transaction.send(:_set_error, error) }
1814
-
1815
- expect(transaction).to have_error(
1816
- "ExampleStandardError",
1817
- "wrapper error 10",
1818
- ["line 1"]
1819
- )
1820
- expect(transaction).to include_error_causes(expected_error_causes)
1821
- expect(logs).to contains_log(
1822
- :debug,
1823
- "Appsignal::Transaction#add_error: Error has more " \
1824
- "than 10 error causes. Only the first 10 " \
1825
- "will be reported."
1826
- )
1827
- end
1828
- end
1829
-
1830
- context "when error message is nil" do
1831
- let(:error) do
1832
- e = ExampleStandardError.new
1833
- allow(e).to receive(:message).and_return(nil)
1834
- allow(e).to receive(:backtrace).and_return(["line 1"])
1835
- e
1836
- end
1837
-
1838
- it "does not raise an error" do
1839
- transaction.send(:_set_error, error)
1840
- end
1841
-
1842
- it "sets an error on the transaction without an error message" do
1843
- transaction.send(:_set_error, error)
1844
-
1845
- expect(transaction).to have_error(
1846
- "ExampleStandardError",
1847
- "",
1848
- ["line 1"]
1849
- )
1850
- end
1851
- end
1852
- end
1853
-
1854
- describe "#start_event" do
1855
- let(:transaction) { new_transaction }
1856
-
1857
- it "starts the event in the extension" do
1858
- expect(transaction.ext).to receive(:start_event).with(0).and_call_original
1859
-
1860
- transaction.start_event
1861
- end
1862
-
1863
- context "when transaction is paused" do
1864
- it "does not start the event" do
1865
- transaction.pause!
1866
- expect(transaction.ext).to_not receive(:start_event)
1867
-
1868
- transaction.start_event
1869
- end
1870
- end
1871
- end
1872
-
1873
- describe "#finish_event" do
1874
- let(:transaction) { new_transaction }
1875
- let(:fake_gc_time) { 0 }
1876
-
1877
- it "should finish the event in the extension" do
1878
- expect(transaction.ext).to receive(:finish_event).with(
1879
- "name",
1880
- "title",
1881
- "body",
1882
- 1,
1883
- fake_gc_time
1884
- ).and_call_original
1885
-
1886
- transaction.finish_event(
1887
- "name",
1888
- "title",
1889
- "body",
1890
- 1
1891
- )
1892
- end
1893
-
1894
- it "should finish the event in the extension with nil arguments" do
1895
- expect(transaction.ext).to receive(:finish_event).with(
1896
- "name",
1897
- "",
1898
- "",
1899
- 0,
1900
- fake_gc_time
1901
- ).and_call_original
1902
-
1903
- transaction.finish_event(
1904
- "name",
1905
- nil,
1906
- nil,
1907
- nil
1908
- )
1909
- end
1910
-
1911
- context "when transaction is paused" do
1912
- it "does not finish the event" do
1913
- transaction.pause!
1914
- expect(transaction.ext).to_not receive(:finish_event)
1915
-
1916
- transaction.start_event
1917
- end
1918
- end
1919
- end
1920
-
1921
- describe "#record_event" do
1922
- let(:transaction) { new_transaction }
1923
- let(:fake_gc_time) { 0 }
1924
-
1925
- it "should record the event in the extension" do
1926
- expect(transaction.ext).to receive(:record_event).with(
1927
- "name",
1928
- "title",
1929
- "body",
1930
- 1,
1931
- 1000,
1932
- fake_gc_time
1933
- ).and_call_original
1934
-
1935
- transaction.record_event(
1936
- "name",
1937
- "title",
1938
- "body",
1939
- 1000,
1940
- 1
1941
- )
1942
- end
1943
-
1944
- it "should finish the event in the extension with nil arguments" do
1945
- expect(transaction.ext).to receive(:record_event).with(
1946
- "name",
1947
- "",
1948
- "",
1949
- 0,
1950
- 1000,
1951
- fake_gc_time
1952
- ).and_call_original
1953
-
1954
- transaction.record_event(
1955
- "name",
1956
- nil,
1957
- nil,
1958
- 1000,
1959
- nil
1960
- )
1961
- end
1962
-
1963
- context "when transaction is paused" do
1964
- it "does not record the event" do
1965
- transaction.pause!
1966
- expect(transaction.ext).to_not receive(:record_event)
1967
-
1968
- transaction.record_event(
1969
- "name",
1970
- nil,
1971
- nil,
1972
- 1000,
1973
- nil
1974
- )
1975
- end
1976
- end
1977
- end
1978
-
1979
- describe "#instrument" do
1980
- it_behaves_like "instrument helper" do
1981
- let(:transaction) { new_transaction }
1982
- let(:instrumenter) { transaction }
1983
- end
1984
- end
1985
-
1986
- # private
1987
-
1988
- describe "#cleaned_backtrace" do
1989
- let(:transaction) { new_transaction }
1990
- subject { transaction.send(:cleaned_backtrace, ["line 1", "line 2"]) }
1991
-
1992
- it "returns the backtrace" do
1993
- expect(subject).to eq ["line 1", "line 2"]
1994
- end
1995
-
1996
- context "with Rails module but without backtrace_cleaner method" do
1997
- it "returns the backtrace uncleaned" do
1998
- stub_const("Rails", Module.new)
1999
- expect(subject).to eq ["line 1", "line 2"]
2000
- end
2001
- end
2002
-
2003
- if rails_present?
2004
- context "with rails" do
2005
- it "cleans the backtrace with the Rails backtrace cleaner" do
2006
- ::Rails.backtrace_cleaner.add_filter do |line|
2007
- line.tr("2", "?")
2008
- end
2009
- expect(subject).to eq ["line 1", "line ?"]
2010
- end
2011
- end
2012
- end
2013
- end
2014
-
2015
- describe "#cleaned_error_message" do
2016
- let(:transaction) { new_transaction }
2017
- let(:error) { StandardError.new("Error message") }
2018
- subject { transaction.send(:cleaned_error_message, error) }
2019
-
2020
- it "returns the error message" do
2021
- expect(subject).to eq "Error message"
2022
- end
2023
-
2024
- context "with a PG::UniqueViolation" do
2025
- before do
2026
- stub_const("PG::UniqueViolation", Class.new(StandardError))
2027
- end
2028
-
2029
- let(:error) do
2030
- PG::UniqueViolation.new(
2031
- "ERROR: duplicate key value violates unique constraint " \
2032
- "\"index_users_on_email\" DETAIL: Key (email)=(test@test.com) already exists."
2033
- )
2034
- end
2035
-
2036
- it "returns a sanizited error message" do
2037
- expect(subject).to eq "ERROR: duplicate key value violates unique constraint " \
2038
- "\"index_users_on_email\" DETAIL: Key (email)=(?) already exists."
2039
- end
2040
- end
2041
-
2042
- context "with a ActiveRecord::RecordNotUnique" do
2043
- before do
2044
- stub_const("ActiveRecord::RecordNotUnique", Class.new(StandardError))
2045
- end
2046
-
2047
- let(:error) do
2048
- ActiveRecord::RecordNotUnique.new(
2049
- "PG::UniqueViolation: ERROR: duplicate key value violates unique constraint " \
2050
- "\"example_constraint\"\nDETAIL: Key (email)=(foo@example.com) already exists."
2051
- )
2052
- end
2053
-
2054
- it "returns a sanizited error message" do
2055
- expect(subject).to eq \
2056
- "PG::UniqueViolation: ERROR: duplicate key value violates unique constraint " \
2057
- "\"example_constraint\"\nDETAIL: Key (email)=(?) already exists."
2058
- end
2059
- end
2060
- end
2061
-
2062
- describe ".to_hash / .to_h" do
2063
- let(:transaction) { new_transaction }
2064
- subject { transaction.to_hash }
2065
-
2066
- context "when extension returns serialized JSON" do
2067
- it "parses the result and returns a Hash" do
2068
- expect(subject).to include(
2069
- "action" => nil,
2070
- "error" => nil,
2071
- "events" => [],
2072
- "id" => kind_of(String),
2073
- "metadata" => {},
2074
- "namespace" => default_namespace,
2075
- "sample_data" => {}
2076
- )
2077
- end
2078
- end
2079
-
2080
- context "when the extension returns invalid serialized JSON" do
2081
- before do
2082
- expect(transaction.ext).to receive(:to_json).and_return("foo")
2083
- end
2084
-
2085
- it "raises a JSON parse error" do
2086
- expect { subject }.to raise_error(JSON::ParserError)
2087
- end
2088
- end
2089
- end
2090
-
2091
- describe Appsignal::Transaction::NilTransaction do
2092
- subject { Appsignal::Transaction::NilTransaction.new }
2093
-
2094
- it "has method stubs" do
2095
- subject.complete
2096
- subject.pause!
2097
- subject.resume!
2098
- subject.paused?
2099
- subject.store(:key)
2100
- subject.add_tags(:tag => 1)
2101
- subject.set_action("action")
2102
- subject.set_http_or_background_action
2103
- subject.set_queue_start(1)
2104
- subject.set_http_or_background_queue_start
2105
- subject.set_metadata("key", "value")
2106
- subject.set_sample_data("key", "data")
2107
- subject._sample
2108
- subject.set_error("a")
2109
- end
2110
- end
2111
- end