@@ -372,4 +372,220 @@ mod tests {
372372
373373 assert ! ( !span. span_context( ) . is_sampled( ) ) ;
374374 }
375+
376+ #[ test]
377+ fn in_span_with_context_uses_provided_context ( ) {
378+ use crate :: trace:: { InMemorySpanExporter , SimpleSpanProcessor } ;
379+
380+ let exporter = InMemorySpanExporter :: default ( ) ;
381+ let tracer_provider = crate :: trace:: SdkTracerProvider :: builder ( )
382+ . with_sampler ( Sampler :: AlwaysOn )
383+ . with_span_processor ( SimpleSpanProcessor :: new ( exporter. clone ( ) ) )
384+ . build ( ) ;
385+ let tracer = tracer_provider. tracer ( "test" ) ;
386+
387+ // Create a parent context explicitly
388+ let parent_span = tracer. start ( "parent" ) ;
389+ let parent_trace_id = parent_span. span_context ( ) . trace_id ( ) ;
390+ let parent_span_id = parent_span. span_context ( ) . span_id ( ) ;
391+ let parent_cx = Context :: current_with_span ( parent_span) ;
392+
393+ // Use in_span_with_context with explicit parent context
394+ let mut child_trace_id = None ;
395+ let mut child_span_id = None ;
396+ let mut executed = false ;
397+
398+ let returned_value = tracer. in_span_with_context ( "child-span" , & parent_cx, |cx| {
399+ let span = cx. span ( ) ;
400+ child_trace_id = Some ( span. span_context ( ) . trace_id ( ) ) ;
401+ child_span_id = Some ( span. span_context ( ) . span_id ( ) ) ;
402+ executed = true ;
403+ "test_result"
404+ } ) ;
405+
406+ // Verify child span inherited parent's trace_id
407+ assert_eq ! ( child_trace_id, Some ( parent_trace_id) ) ;
408+ // Verify child has a different span_id than parent
409+ assert_ne ! ( child_span_id, Some ( parent_span_id) ) ;
410+ // Verify the closure was executed
411+ assert ! ( executed) ;
412+ // Verify return value is passed through
413+ assert_eq ! ( returned_value, "test_result" ) ;
414+
415+ // End the parent span to export it
416+ drop ( parent_cx) ;
417+
418+ // Verify parent-child relationship through exporter
419+ let spans = exporter. get_finished_spans ( ) . unwrap ( ) ;
420+ assert_eq ! ( spans. len( ) , 2 ) ;
421+ let parent = spans. iter ( ) . find ( |s| s. name == "parent" ) . unwrap ( ) ;
422+ let child = spans. iter ( ) . find ( |s| s. name == "child-span" ) . unwrap ( ) ;
423+ assert_eq ! ( child. parent_span_id, parent. span_context. span_id( ) ) ;
424+ assert_eq ! ( child. span_context. trace_id( ) , parent. span_context. trace_id( ) ) ;
425+ }
426+
427+ #[ test]
428+ fn in_span_with_builder_uses_current_context ( ) {
429+ use crate :: trace:: { InMemorySpanExporter , SimpleSpanProcessor } ;
430+
431+ let exporter = InMemorySpanExporter :: default ( ) ;
432+ let tracer_provider = crate :: trace:: SdkTracerProvider :: builder ( )
433+ . with_sampler ( Sampler :: AlwaysOn )
434+ . with_span_processor ( SimpleSpanProcessor :: new ( exporter. clone ( ) ) )
435+ . build ( ) ;
436+ let tracer = tracer_provider. tracer ( "test" ) ;
437+
438+ // Create a parent span and attach it to the current context
439+ let parent_span = tracer. start ( "parent" ) ;
440+ let parent_trace_id = parent_span. span_context ( ) . trace_id ( ) ;
441+ let parent_span_id = parent_span. span_context ( ) . span_id ( ) ;
442+ let _attached = Context :: current_with_span ( parent_span) . attach ( ) ;
443+
444+ // Use in_span_with_builder with configured span
445+ let mut child_trace_id = None ;
446+
447+ tracer. in_span_with_builder (
448+ tracer
449+ . span_builder ( "child" )
450+ . with_kind ( SpanKind :: Client )
451+ . with_attributes ( vec ! [ KeyValue :: new( "test_key" , "test_value" ) ] ) ,
452+ |cx| {
453+ let span = cx. span ( ) ;
454+ child_trace_id = Some ( span. span_context ( ) . trace_id ( ) ) ;
455+ } ,
456+ ) ;
457+
458+ // Verify child span inherited parent's trace_id
459+ assert_eq ! ( child_trace_id, Some ( parent_trace_id) ) ;
460+
461+ // End the attached context to export the parent span
462+ drop ( _attached) ;
463+
464+ // Verify parent-child relationship through exporter
465+ let spans = exporter. get_finished_spans ( ) . unwrap ( ) ;
466+ assert_eq ! ( spans. len( ) , 2 ) ;
467+ let child = spans. iter ( ) . find ( |s| s. name == "child" ) . unwrap ( ) ;
468+ assert_eq ! ( child. parent_span_id, parent_span_id) ;
469+ assert_eq ! ( child. span_context. trace_id( ) , parent_trace_id) ;
470+ }
471+
472+ #[ test]
473+ fn in_span_with_builder_and_context_uses_provided_context ( ) {
474+ use crate :: trace:: { InMemorySpanExporter , SimpleSpanProcessor } ;
475+
476+ let exporter = InMemorySpanExporter :: default ( ) ;
477+ let tracer_provider = crate :: trace:: SdkTracerProvider :: builder ( )
478+ . with_sampler ( Sampler :: AlwaysOn )
479+ . with_span_processor ( SimpleSpanProcessor :: new ( exporter. clone ( ) ) )
480+ . build ( ) ;
481+ let tracer = tracer_provider. tracer ( "test" ) ;
482+
483+ // Create a parent context explicitly
484+ let parent_span = tracer. start ( "parent" ) ;
485+ let parent_trace_id = parent_span. span_context ( ) . trace_id ( ) ;
486+ let parent_span_id = parent_span. span_context ( ) . span_id ( ) ;
487+ let parent_cx = Context :: current_with_span ( parent_span) ;
488+
489+ // Use in_span_with_builder_and_context with explicit parent context
490+ let mut child_trace_id = None ;
491+ let mut result = 0 ;
492+
493+ let returned_value = tracer. in_span_with_builder_and_context (
494+ tracer
495+ . span_builder ( "child" )
496+ . with_kind ( SpanKind :: Server )
497+ . with_attributes ( vec ! [
498+ KeyValue :: new( "http.method" , "GET" ) ,
499+ KeyValue :: new( "http.url" , "/api/test" ) ,
500+ ] ) ,
501+ & parent_cx,
502+ |cx| {
503+ let span = cx. span ( ) ;
504+ child_trace_id = Some ( span. span_context ( ) . trace_id ( ) ) ;
505+ result = 42 ;
506+ result
507+ } ,
508+ ) ;
509+
510+ // Verify child span inherited parent's trace_id
511+ assert_eq ! ( child_trace_id, Some ( parent_trace_id) ) ;
512+ // Verify return value is passed through
513+ assert_eq ! ( returned_value, 42 ) ;
514+ assert_eq ! ( result, 42 ) ;
515+
516+ // End the parent span to export it
517+ drop ( parent_cx) ;
518+
519+ // Verify parent-child relationship through exporter
520+ let spans = exporter. get_finished_spans ( ) . unwrap ( ) ;
521+ assert_eq ! ( spans. len( ) , 2 ) ;
522+ let child = spans. iter ( ) . find ( |s| s. name == "child" ) . unwrap ( ) ;
523+ assert_eq ! ( child. parent_span_id, parent_span_id) ;
524+ assert_eq ! ( child. span_context. trace_id( ) , parent_trace_id) ;
525+ }
526+
527+ #[ test]
528+ fn in_span_with_builder_and_context_ignores_active_context ( ) {
529+ use crate :: trace:: { InMemorySpanExporter , SimpleSpanProcessor } ;
530+
531+ let exporter = InMemorySpanExporter :: default ( ) ;
532+ let tracer_provider = crate :: trace:: SdkTracerProvider :: builder ( )
533+ . with_sampler ( Sampler :: AlwaysOn )
534+ . with_span_processor ( SimpleSpanProcessor :: new ( exporter. clone ( ) ) )
535+ . build ( ) ;
536+ let tracer = tracer_provider. tracer ( "test" ) ;
537+
538+ // Create an active context with a specific trace context
539+ let active_span_context = SpanContext :: new (
540+ TraceId :: from ( 1u128 ) ,
541+ SpanId :: from ( 1u64 ) ,
542+ TraceFlags :: SAMPLED ,
543+ true ,
544+ Default :: default ( ) ,
545+ ) ;
546+ let active_trace_id = active_span_context. trace_id ( ) ;
547+ let active_span_id = active_span_context. span_id ( ) ;
548+ let _attached = Context :: current_with_span ( TestSpan ( active_span_context) ) . attach ( ) ;
549+
550+ // Create a different parent context with a different trace ID to explicitly provide
551+ let provided_span_context = SpanContext :: new (
552+ TraceId :: from ( 2u128 ) ,
553+ SpanId :: from ( 2u64 ) ,
554+ TraceFlags :: SAMPLED ,
555+ true ,
556+ Default :: default ( ) ,
557+ ) ;
558+ let provided_trace_id = provided_span_context. trace_id ( ) ;
559+ let provided_span_id = provided_span_context. span_id ( ) ;
560+ let provided_cx = Context :: current_with_span ( TestSpan ( provided_span_context) ) ;
561+
562+ // Ensure the two parents have different trace IDs
563+ assert_ne ! ( active_trace_id, provided_trace_id) ;
564+
565+ // Use in_span_with_builder_and_context with explicit parent context
566+ let mut child_trace_id = None ;
567+
568+ tracer. in_span_with_builder_and_context (
569+ tracer. span_builder ( "child" ) . with_kind ( SpanKind :: Internal ) ,
570+ & provided_cx,
571+ |cx| {
572+ let span = cx. span ( ) ;
573+ child_trace_id = Some ( span. span_context ( ) . trace_id ( ) ) ;
574+ } ,
575+ ) ;
576+
577+ // Verify child uses the provided context, NOT the active context
578+ assert_eq ! ( child_trace_id, Some ( provided_trace_id) ) ;
579+ assert_ne ! ( child_trace_id, Some ( active_trace_id) ) ;
580+
581+ // Verify parent-child relationship through exporter
582+ let spans = exporter. get_finished_spans ( ) . unwrap ( ) ;
583+ assert_eq ! ( spans. len( ) , 1 ) ;
584+ let child = & spans[ 0 ] ;
585+ assert_eq ! ( child. name, "child" ) ;
586+ assert_eq ! ( child. parent_span_id, provided_span_id) ;
587+ assert_eq ! ( child. span_context. trace_id( ) , provided_trace_id) ;
588+ assert_ne ! ( child. parent_span_id, active_span_id) ;
589+ assert_ne ! ( child. span_context. trace_id( ) , active_trace_id) ;
590+ }
375591}
0 commit comments