@@ -21,11 +21,14 @@ import (
2121 "github.com/dapr/durabletask-go/backend/sqlite"
2222 "github.com/dapr/durabletask-go/client"
2323 "github.com/dapr/durabletask-go/task"
24+ "github.com/dapr/durabletask-go/tests/utils"
25+ "go.opentelemetry.io/otel"
2426)
2527
2628var (
2729 grpcClient * client.TaskHubGrpcClient
2830 ctx = context .Background ()
31+ tracer = otel .Tracer ("grpc-test" )
2932)
3033
3134// TestMain is the entry point for the test suite. We use this to set up a gRPC server and client instance
@@ -418,9 +421,9 @@ func Test_Grpc_ReuseInstanceIDError(t *testing.T) {
418421 defer cancelListener ()
419422 instanceID := api .InstanceID ("THROW_IF_RUNNING_OR_COMPLETED" )
420423
421- id , err := grpcClient .ScheduleNewOrchestration (ctx , "SingleActivity" , api .WithInput ("世界" ), api .WithInstanceID (instanceID ))
424+ _ , err := grpcClient .ScheduleNewOrchestration (ctx , "SingleActivity" , api .WithInput ("世界" ), api .WithInstanceID (instanceID ))
422425 require .NoError (t , err )
423- id , err = grpcClient .ScheduleNewOrchestration (ctx , "SingleActivity" , api .WithInput ("World" ), api .WithInstanceID (id ))
426+ _ , err = grpcClient .ScheduleNewOrchestration (ctx , "SingleActivity" , api .WithInput ("World" ), api .WithInstanceID (id ))
424427 if assert .Error (t , err ) {
425428 assert .Contains (t , err .Error (), "orchestration instance already exists" )
426429 }
@@ -489,3 +492,51 @@ func Test_Grpc_SubOrchestratorRetries(t *testing.T) {
489492 // With 3 max attempts there will be two retries with 10 millis delay before each
490493 require .GreaterOrEqual (t , metadata .LastUpdatedAt .AsTime (), metadata .CreatedAt .AsTime ().Add (2 * 10 * time .Millisecond ))
491494}
495+
496+ func Test_SingleActivity_TaskSpan (t * testing.T ) {
497+ // Registration
498+ r := task .NewTaskRegistry ()
499+ r .AddOrchestratorN ("SingleActivity_TestSpan" , func (ctx * task.OrchestrationContext ) (any , error ) {
500+ var input string
501+ if err := ctx .GetInput (& input ); err != nil {
502+ return nil , err
503+ }
504+ var output string
505+ err := ctx .CallActivity ("SayHello" , task .WithActivityInput (input )).Await (& output )
506+ return output , err
507+ })
508+ r .AddActivityN ("SayHello" , func (ctx task.ActivityContext ) (any , error ) {
509+ var name string
510+ if err := ctx .GetInput (& name ); err != nil {
511+ return nil , err
512+ }
513+ _ , childSpan := tracer .Start (ctx .Context (), "activityChild_TestSpan" )
514+ childSpan .End ()
515+ return fmt .Sprintf ("Hello, %s!" , name ), nil
516+ })
517+
518+ exporter := utils .InitTracing ()
519+ cancelListener := startGrpcListener (t , r )
520+ defer cancelListener ()
521+
522+ // Run the orchestration
523+ id , err := grpcClient .ScheduleNewOrchestration (ctx , "SingleActivity_TestSpan" , api .WithInput ("世界" ))
524+ if assert .NoError (t , err ) {
525+ metadata , err := grpcClient .WaitForOrchestrationCompletion (ctx , id )
526+ if assert .NoError (t , err ) {
527+ assert .Equal (t , protos .OrchestrationStatus_ORCHESTRATION_STATUS_COMPLETED , metadata .RuntimeStatus )
528+ assert .Equal (t , `"Hello, 世界!"` , metadata .SerializedOutput )
529+ }
530+ }
531+
532+ // Validate the exported OTel traces
533+ spans := exporter .GetSpans ().Snapshots ()
534+ utils .AssertSpanSequence (t , spans ,
535+ utils .AssertOrchestratorCreated ("SingleActivity_TestSpan" , id ),
536+ utils .AssertSpan ("activityChild_TestSpan" ),
537+ utils .AssertActivity ("SayHello" , id , 0 ),
538+ utils .AssertOrchestratorExecuted ("SingleActivity_TestSpan" , id , "COMPLETED" ),
539+ )
540+ // assert child-parent relationship
541+ assert .Equal (t , spans [1 ].Parent ().SpanID (), spans [2 ].SpanContext ().SpanID ())
542+ }
0 commit comments