From ca9df87014e50137830d4ce37411a108f1a91ae7 Mon Sep 17 00:00:00 2001 From: "Jonathan A. Sternberg" Date: Tue, 10 Mar 2026 12:03:35 -0500 Subject: [PATCH] dap: fix the race condition in the dap unit tests The context used for serving the dap server was being canceled too early because it used defer which would initiate at the end of the function while every other cleanup function used `t.Cleanup` which executes in its own goroutine. One possible solution was to move the cancel to the cleanup, but the context being passed to serve and start doesn't make sense because if it ever does get canceled, it'll likely cause a similar race condition with `Stop`. This removes the context from the methods that were causing this issue in favor of just relying on the caller calling `Stop` when they are done with the adapter and server. This seems to have only affected tests and I don't believe it affected the actual dap command. Signed-off-by: Jonathan A. Sternberg --- commands/dap.go | 3 +-- dap/adapter.go | 6 +++--- dap/adapter_test.go | 14 +++++++------- dap/server.go | 4 ++-- 4 files changed, 13 insertions(+), 14 deletions(-) diff --git a/commands/dap.go b/commands/dap.go index f2b3ef3f8..067740037 100644 --- a/commands/dap.go +++ b/commands/dap.go @@ -1,7 +1,6 @@ package commands import ( - "context" "io" "net" "os" @@ -75,7 +74,7 @@ type adapterProtocolDebugger struct { } func (d *adapterProtocolDebugger) Start(printer *progress.Printer, opts *BuildOptions) error { - cfg, err := d.Adapter.Start(context.Background(), d.conn) + cfg, err := d.Adapter.Start(d.conn) if err != nil { return errors.Wrap(err, "debug adapter did not start") } diff --git a/dap/adapter.go b/dap/adapter.go index 7ced02dce..6b4135031 100644 --- a/dap/adapter.go +++ b/dap/adapter.go @@ -67,10 +67,10 @@ func New[C LaunchConfig]() *Adapter[C] { return d } -func (d *Adapter[C]) Start(ctx context.Context, conn Conn) (C, error) { - d.eg, _ = errgroup.WithContext(ctx) +func (d *Adapter[C]) Start(conn Conn) (C, error) { + d.eg, _ = errgroup.WithContext(context.Background()) d.eg.Go(func() error { - return d.srv.Serve(ctx, conn) + return d.srv.Serve(conn) }) <-d.initialized diff --git a/dap/adapter_test.go b/dap/adapter_test.go index cf2f1db15..288519e73 100644 --- a/dap/adapter_test.go +++ b/dap/adapter_test.go @@ -24,7 +24,7 @@ func TestLaunch(t *testing.T) { eg, _ := errgroup.WithContext(ctx) eg.Go(func() error { - _, err := adapter.Start(ctx, conn) + _, err := adapter.Start(conn) assert.NoError(t, err) return nil }) @@ -57,13 +57,13 @@ func TestLaunch(t *testing.T) { // We should have received the initialized event. select { case <-initialized: - default: + case <-ctx.Done(): assert.Fail(t, "did not receive initialized event") } select { case <-configurationDone: - case <-time.After(10 * time.Second): + case <-ctx.Done(): assert.Fail(t, "did not receive configurationDone response") } return nil @@ -82,7 +82,7 @@ func TestSetBreakpoints(t *testing.T) { eg, _ := errgroup.WithContext(ctx) eg.Go(func() error { - _, err := adapter.Start(ctx, conn) + _, err := adapter.Start(conn) assert.NoError(t, err) return nil }) @@ -118,7 +118,7 @@ func TestSetBreakpoints(t *testing.T) { // We should have received the initialized event. select { case <-initialized: - default: + case <-ctx.Done(): assert.Fail(t, "did not receive initialized event") } @@ -127,7 +127,7 @@ func TestSetBreakpoints(t *testing.T) { assert.True(t, setBreakpointsResp.Success) assert.Len(t, setBreakpointsResp.Body.Breakpoints, 0) assert.NotNil(t, setBreakpointsResp.Body.Breakpoints, "breakpoints should be an empty array instead of null in the JSON") - case <-time.After(10 * time.Second): + case <-ctx.Done(): assert.Fail(t, "did not receive setBreakpoints response") } return nil @@ -249,11 +249,11 @@ func NewTestAdapter[C LaunchConfig](t *testing.T) (*Adapter[C], Conn, *daptest.C t.Cleanup(func() { clientConn.Close() }) adapter := New[C]() - t.Cleanup(func() { adapter.Stop() }) client := daptest.NewClient(clientConn) t.Cleanup(func() { client.Close() }) + t.Cleanup(func() { adapter.Stop() }) return adapter, srvConn, client } diff --git a/dap/server.go b/dap/server.go index 63ba606c4..c5dcbf4c2 100644 --- a/dap/server.go +++ b/dap/server.go @@ -33,11 +33,11 @@ func NewServer(h Handler) *Server { return &Server{h: h} } -func (s *Server) Serve(ctx context.Context, conn Conn) error { +func (s *Server) Serve(conn Conn) error { writeCh := make(chan dap.Message) s.ch = writeCh - s.ctx, s.cancel = context.WithCancelCause(ctx) + s.ctx, s.cancel = context.WithCancelCause(context.Background()) // Start an error group to handle server-initiated tasks. s.eg, _ = errgroup.WithContext(s.ctx)