@@ -100,6 +100,16 @@ def my_span_and_context
100
100
trace_id : be != nil
101
101
)
102
102
end
103
+
104
+ it "returns nil when there is no active trace" do
105
+ # Use a new Fiber to create a clean context without any active traces
106
+ result = Fiber . new do
107
+ # trace_context should return nil when there's no active trace
108
+ Traces . trace_context
109
+ end . resume
110
+
111
+ expect ( result ) . to be_nil
112
+ end
103
113
end
104
114
105
115
with "#trace_context=" do
@@ -117,172 +127,201 @@ def my_span_and_context
117
127
)
118
128
end
119
129
end
120
- end
121
-
122
- describe "Context Propagation Methods" do
123
- with "#current_context" do
124
- it "returns current OpenTelemetry context" do
125
- current = Traces . current_context
126
- expect ( current ) . to be_a ( ::OpenTelemetry ::Context )
130
+
131
+ with "#active?" do
132
+ it "returns true when there is an active trace" do
133
+ Traces . trace ( "test" ) do
134
+ expect ( Traces . active? ) . to be == true
135
+ end
127
136
end
128
137
129
- it "returns different contexts in different spans" do
130
- context1 = nil
131
- context2 = nil
138
+ it "returns false when there is no active trace" do
139
+ # Use a new Fiber to create a clean context without any active traces
140
+ result = Fiber . new do
141
+ Traces . active?
142
+ end . resume
132
143
133
- Traces . trace ( "span1" ) do
134
- context1 = Traces . current_context
144
+ expect ( result ) . to be == false
145
+ end
146
+
147
+ it "returns false after a trace completes in a new execution context" do
148
+ Traces . trace ( "test" ) do |span |
149
+ # Should be active inside the trace
150
+ expect ( Traces . active? ) . to be == true
135
151
end
136
152
137
- Traces . trace ( "span2" ) do
138
- context2 = Traces . current_context
139
- end
153
+ # In a new Fiber, should not be active
154
+ result = Fiber . new do
155
+ Traces . active?
156
+ end . resume
140
157
141
- # Contexts should be different objects (different spans):
142
- expect ( context1 ) . not . to be_equal ( context2 )
158
+ expect ( result ) . to be == false
143
159
end
144
160
end
161
+ end
162
+
163
+ with "#current_context" do
164
+ it "returns current OpenTelemetry context" do
165
+ current = Traces . current_context
166
+ expect ( current ) . to be_a ( ::OpenTelemetry ::Context )
167
+ end
145
168
146
- with "#with_context" do
147
- it "executes block within specified context" do
148
- original_context = Traces . current_context
149
- test_context = ::OpenTelemetry ::Context . empty
150
- executed = false
151
-
152
- Traces . with_context ( test_context ) do
153
- executed = true
154
- expect ( ::OpenTelemetry ::Context . current ) . to be_equal ( test_context )
155
- end
156
-
157
- expect ( executed ) . to be == true
158
- # Context should be restored after block:
159
- expect ( ::OpenTelemetry ::Context . current ) . to be_equal ( original_context )
169
+ it "returns different contexts in different spans" do
170
+ context1 = nil
171
+ context2 = nil
172
+
173
+ Traces . trace ( "span1" ) do
174
+ context1 = Traces . current_context
160
175
end
161
176
162
- it "permanently sets context when called without block" do
163
- original_context = Traces . current_context
164
- test_context = ::OpenTelemetry ::Context . empty
165
-
166
- token = Traces . with_context ( test_context )
177
+ Traces . trace ( "span2" ) do
178
+ context2 = Traces . current_context
179
+ end
180
+
181
+ # Contexts should be different objects (different spans):
182
+ expect ( context1 ) . not . to be_equal ( context2 )
183
+ end
184
+ end
185
+
186
+ with "#with_context" do
187
+ it "executes block within specified context" do
188
+ original_context = Traces . current_context
189
+ test_context = ::OpenTelemetry ::Context . empty
190
+ executed = false
191
+
192
+ Traces . with_context ( test_context ) do
193
+ executed = true
167
194
expect ( ::OpenTelemetry ::Context . current ) . to be_equal ( test_context )
168
-
169
- # Clean up by detaching:
170
- ::OpenTelemetry ::Context . detach ( token )
171
195
end
196
+
197
+ expect ( executed ) . to be == true
198
+ # Context should be restored after block:
199
+ expect ( ::OpenTelemetry ::Context . current ) . to be_equal ( original_context )
172
200
end
173
201
174
- with "#inject" do
175
- it "injects trace context into headers" do
176
- headers = { }
177
-
178
- Traces . trace ( "test" ) do
179
- Traces . inject ( headers )
180
- end
181
-
182
- expect ( headers ) . to have_keys (
183
- "traceparent" => be_a ( String )
184
- )
185
-
186
- traceparent = headers [ "traceparent" ]
187
- expect ( traceparent ) . to be =~ /^00-[0-9a-f]{32}-[0-9a-f]{16}-[0-9a-f]{2}$/
188
- end
202
+ it "permanently sets context when called without block" do
203
+ original_context = Traces . current_context
204
+ test_context = ::OpenTelemetry ::Context . empty
189
205
190
- it "creates new headers hash when none provided" do
191
- Traces . trace ( "test" ) do
192
- headers = Traces . inject ( )
193
- expect ( headers ) . to be_a ( Hash )
194
- expect ( headers [ "traceparent" ] ) . to be =~ /^00-[0-9a-f]{32}-[0-9a-f]{16}-[0-9a-f]{2}$/
195
- end
196
- end
206
+ token = Traces . with_context ( test_context )
207
+ expect ( ::OpenTelemetry ::Context . current ) . to be_equal ( test_context )
197
208
198
- it "uses specific context when provided" do
199
- headers = { }
200
-
201
- Traces . trace ( "test" ) do
202
- specific_context = Traces . current_context
203
- Traces . inject ( headers , specific_context )
204
- expect ( headers [ "traceparent" ] ) . to be =~ /^00-[0-9a-f]{32}-[0-9a-f]{16}-[0-9a-f]{2}$/
205
- end
209
+ # Clean up by detaching:
210
+ ::OpenTelemetry ::Context . detach ( token )
211
+ end
212
+ end
213
+
214
+ with "#inject" do
215
+ it "injects trace context into headers" do
216
+ headers = { }
217
+
218
+ Traces . trace ( "test" ) do
219
+ Traces . inject ( headers )
206
220
end
207
221
208
- it "returns nil when no headers provided and no active trace" do
209
- # Clear any active trace:
210
- ::OpenTelemetry ::Context . clear
211
-
212
- result = Traces . inject ( )
213
- expect ( result ) . to be == nil
222
+ expect ( headers ) . to have_keys (
223
+ "traceparent" => be_a ( String )
224
+ )
225
+
226
+ traceparent = headers [ "traceparent" ]
227
+ expect ( traceparent ) . to be =~ /^00-[0-9a-f]{32}-[0-9a-f]{16}-[0-9a-f]{2}$/
228
+ end
229
+
230
+ it "creates new headers hash when none provided" do
231
+ Traces . trace ( "test" ) do
232
+ headers = Traces . inject ( )
233
+ expect ( headers ) . to be_a ( Hash )
234
+ expect ( headers [ "traceparent" ] ) . to be =~ /^00-[0-9a-f]{32}-[0-9a-f]{16}-[0-9a-f]{2}$/
214
235
end
236
+ end
237
+
238
+ it "uses specific context when provided" do
239
+ headers = { }
215
240
216
- it "returns nil when headers provided but no active trace" do
217
- # Clear any active trace:
218
- ::OpenTelemetry ::Context . clear
219
- headers = { "existing" => "value" }
220
-
221
- result = Traces . inject ( headers )
222
- expect ( result ) . to be == nil
223
- # Original headers should remain unchanged:
224
- expect ( headers [ "existing" ] ) . to be == "value"
225
- expect ( headers . key? ( "traceparent" ) ) . to be == false
241
+ Traces . trace ( "test" ) do
242
+ specific_context = Traces . current_context
243
+ Traces . inject ( headers , specific_context )
244
+ expect ( headers [ "traceparent" ] ) . to be =~ /^00-[0-9a-f]{32}-[0-9a-f]{16}-[0-9a-f]{2}$/
226
245
end
227
246
end
228
247
229
- with "#extract" do
230
- it "extracts context from headers" do
231
- headers = {
248
+ it "returns nil when no headers provided and no active trace" do
249
+ # Clear any active trace:
250
+ ::OpenTelemetry ::Context . clear
251
+
252
+ result = Traces . inject ( )
253
+ expect ( result ) . to be == nil
254
+ end
255
+
256
+ it "returns nil when headers provided but no active trace" do
257
+ # Clear any active trace:
258
+ ::OpenTelemetry ::Context . clear
259
+ headers = { "existing" => "value" }
260
+
261
+ result = Traces . inject ( headers )
262
+ expect ( result ) . to be == nil
263
+ # Original headers should remain unchanged:
264
+ expect ( headers [ "existing" ] ) . to be == "value"
265
+ expect ( headers . key? ( "traceparent" ) ) . to be == false
266
+ end
267
+ end
268
+
269
+ with "#extract" do
270
+ it "extracts context from headers" do
271
+ headers = {
232
272
"traceparent" => "00-4bf92f3577b34da6a3ce929d0e0e4736-00f067aa0ba902b7-01"
233
273
}
234
-
235
- context = Traces . extract ( headers )
236
- expect ( context ) . to be_a ( ::OpenTelemetry ::Context )
237
-
238
- # Verify we can use the extracted context:
239
- Traces . with_context ( context ) do
240
- span = ::OpenTelemetry ::Trace . current_span
241
- # Convert binary trace_id to hex for comparison:
242
- trace_id_hex = span . context . trace_id . unpack1 ( "H*" )
243
- expect ( trace_id_hex ) . to be == "4bf92f3577b34da6a3ce929d0e0e4736"
244
- end
245
- end
246
274
247
- it "returns original context for invalid headers" do
248
- headers = { "traceparent" => "invalid" }
249
- original_context = ::OpenTelemetry ::Context . current
250
-
251
- result = Traces . extract ( headers )
252
- expect ( result ) . to be_equal ( original_context )
253
- end
275
+ context = Traces . extract ( headers )
276
+ expect ( context ) . to be_a ( ::OpenTelemetry ::Context )
254
277
255
- it "handles missing headers gracefully" do
256
- headers = { }
257
- original_context = ::OpenTelemetry ::Context . current
258
-
259
- result = Traces . extract ( headers )
260
- expect ( result ) . to be_equal ( original_context )
278
+ # Verify we can use the extracted context:
279
+ Traces . with_context ( context ) do
280
+ span = ::OpenTelemetry ::Trace . current_span
281
+ # Convert binary trace_id to hex for comparison:
282
+ trace_id_hex = span . context . trace_id . unpack1 ( "H*" )
283
+ expect ( trace_id_hex ) . to be == "4bf92f3577b34da6a3ce929d0e0e4736"
261
284
end
262
285
end
263
286
264
- with "round-trip inject/extract" do
265
- it "preserves context through inject and extract cycle" do
266
- original_headers = { }
267
-
268
- # Create a trace and inject it:
269
- Traces . trace ( "test" ) do
270
- Traces . inject ( original_headers )
271
- end
272
-
273
- expect ( original_headers ) . to have_keys (
287
+ it "returns original context for invalid headers" do
288
+ headers = { "traceparent" => "invalid" }
289
+ original_context = ::OpenTelemetry ::Context . current
290
+
291
+ result = Traces . extract ( headers )
292
+ expect ( result ) . to be_equal ( original_context )
293
+ end
294
+
295
+ it "handles missing headers gracefully" do
296
+ headers = { }
297
+ original_context = ::OpenTelemetry ::Context . current
298
+
299
+ result = Traces . extract ( headers )
300
+ expect ( result ) . to be_equal ( original_context )
301
+ end
302
+ end
303
+
304
+ with "round-trip inject/extract" do
305
+ it "preserves context through inject and extract cycle" do
306
+ original_headers = { }
307
+
308
+ # Create a trace and inject it:
309
+ Traces . trace ( "test" ) do
310
+ Traces . inject ( original_headers )
311
+ end
312
+
313
+ expect ( original_headers ) . to have_keys (
274
314
"traceparent" => be_a ( String )
275
315
)
276
-
277
- # Extract the context:
278
- extracted_context = Traces . extract ( original_headers )
279
- expect ( extracted_context ) . to be_a ( ::OpenTelemetry ::Context )
280
-
281
- # Use extracted context to create another trace:
282
- Traces . with_context ( extracted_context ) do
283
- span = ::OpenTelemetry ::Trace . current_span
284
- expect ( span . context . remote? ) . to be == true
285
- end
316
+
317
+ # Extract the context:
318
+ extracted_context = Traces . extract ( original_headers )
319
+ expect ( extracted_context ) . to be_a ( ::OpenTelemetry ::Context )
320
+
321
+ # Use extracted context to create another trace:
322
+ Traces . with_context ( extracted_context ) do
323
+ span = ::OpenTelemetry ::Trace . current_span
324
+ expect ( span . context . remote? ) . to be == true
286
325
end
287
326
end
288
327
end
0 commit comments