@@ -100,6 +100,16 @@ def my_span_and_context
100100 trace_id : be != nil
101101 )
102102 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
103113 end
104114
105115 with "#trace_context=" do
@@ -117,172 +127,201 @@ def my_span_and_context
117127 )
118128 end
119129 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
127136 end
128137
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
132143
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
135151 end
136152
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
140157
141- # Contexts should be different objects (different spans):
142- expect ( context1 ) . not . to be_equal ( context2 )
158+ expect ( result ) . to be == false
143159 end
144160 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
145168
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
160175 end
161176
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
167194 expect ( ::OpenTelemetry ::Context . current ) . to be_equal ( test_context )
168-
169- # Clean up by detaching:
170- ::OpenTelemetry ::Context . detach ( token )
171195 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 )
172200 end
173201
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
189205
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 )
197208
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 )
206220 end
207221
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}$/
214235 end
236+ end
237+
238+ it "uses specific context when provided" do
239+ headers = { }
215240
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}$/
226245 end
227246 end
228247
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 = {
232272 "traceparent" => "00-4bf92f3577b34da6a3ce929d0e0e4736-00f067aa0ba902b7-01"
233273 }
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
246274
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 )
254277
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"
261284 end
262285 end
263286
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 (
274314 "traceparent" => be_a ( String )
275315 )
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
286325 end
287326 end
288327 end
0 commit comments