appsignal 3.10.0-java → 3.12.0-java

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