appsignal 3.10.0 → 3.12.0

Sign up to get free protection for your applications and to get access to all the features.
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