github.com/moby/docker@v26.1.3+incompatible/integration/build/build_traces_test.go (about) 1 package build 2 3 import ( 4 "context" 5 "fmt" 6 "testing" 7 "time" 8 9 "github.com/docker/docker/client/buildkit" 10 "github.com/docker/docker/testutil" 11 moby_buildkit_v1 "github.com/moby/buildkit/api/services/control" 12 "github.com/moby/buildkit/client" 13 "github.com/moby/buildkit/client/llb" 14 "github.com/moby/buildkit/util/progress/progressui" 15 "go.opentelemetry.io/otel" 16 "golang.org/x/sync/errgroup" 17 "gotest.tools/v3/assert" 18 "gotest.tools/v3/poll" 19 "gotest.tools/v3/skip" 20 ) 21 22 type testWriter struct { 23 *testing.T 24 } 25 26 func (t *testWriter) Write(p []byte) (int, error) { 27 t.Log(string(p)) 28 return len(p), nil 29 } 30 31 func TestBuildkitHistoryTracePropagation(t *testing.T) { 32 skip.If(t, testEnv.DaemonInfo.OSType == "windows", "buildkit is not supported on Windows") 33 34 ctx := testutil.StartSpan(baseContext, t) 35 36 opts := buildkit.ClientOpts(testEnv.APIClient()) 37 bc, err := client.New(ctx, "", opts...) 38 assert.NilError(t, err) 39 defer bc.Close() 40 41 def, err := llb.Scratch().Marshal(ctx) 42 assert.NilError(t, err) 43 44 eg, ctxGo := errgroup.WithContext(ctx) 45 ch := make(chan *client.SolveStatus) 46 47 ctxHistory, cancel := context.WithCancel(ctx) 48 defer cancel() 49 50 sub, err := bc.ControlClient().ListenBuildHistory(ctxHistory, &moby_buildkit_v1.BuildHistoryRequest{ActiveOnly: true}) 51 assert.NilError(t, err) 52 sub.CloseSend() 53 54 defer func() { 55 cancel() 56 <-sub.Context().Done() 57 }() 58 59 d, err := progressui.NewDisplay(&testWriter{t}, progressui.AutoMode, progressui.WithPhase("test")) 60 assert.NilError(t, err) 61 62 eg.Go(func() error { 63 _, err := d.UpdateFrom(ctxGo, ch) 64 return err 65 }) 66 67 eg.Go(func() error { 68 _, err := bc.Solve(ctxGo, def, client.SolveOpt{}, ch) 69 return err 70 }) 71 assert.NilError(t, eg.Wait()) 72 73 he, err := sub.Recv() 74 assert.NilError(t, err) 75 assert.Assert(t, he != nil) 76 cancel() 77 78 // Traces for history records are recorded asynchronously, so we need to wait for it to be available. 79 if he.Record.Trace != nil { 80 return 81 } 82 83 // Split this into a new span so it doesn't clutter up the trace reporting GUI. 84 ctx, span := otel.Tracer("").Start(ctx, "Wait for trace to propagate to history record") 85 defer span.End() 86 87 t.Log("Waiting for trace to be available") 88 poll.WaitOn(t, func(logger poll.LogT) poll.Result { 89 ctx, cancel := context.WithCancel(ctx) 90 defer cancel() 91 92 sub, err := bc.ControlClient().ListenBuildHistory(ctx, &moby_buildkit_v1.BuildHistoryRequest{Ref: he.Record.Ref}) 93 if err != nil { 94 return poll.Error(err) 95 } 96 sub.CloseSend() 97 98 defer func() { 99 cancel() 100 <-sub.Context().Done() 101 }() 102 103 msg, err := sub.Recv() 104 if err != nil { 105 return poll.Error(err) 106 } 107 108 if msg.Record.Ref != he.Record.Ref { 109 return poll.Error(fmt.Errorf("got incorrect history record")) 110 } 111 if msg.Record.Trace != nil { 112 return poll.Success() 113 } 114 return poll.Continue("trace not available yet") 115 }, poll.WithDelay(time.Second), poll.WithTimeout(30*time.Second)) 116 117 }