Skip to content

Commit b9d441f

Browse files
authored
fix: use concurrency-safe bytes buffer to avoid race (coder#15142)
Fixes coder/internal#93 `bytes.Buffer` is not concurrency-safe. `cmd` could write to the buffer concurrently while we're reading the buffer in ``` require.Eventually(t, func() bool { return bytes.Contains(output.Bytes(), []byte("ERROR: Downloaded agent binary returned unexpected version output")) }, testutil.WaitShort, testutil.IntervalSlow) ``` Not sure about the `os: process already finished` flake, though. --------- Signed-off-by: Danny Kopping <danny@coder.com>
1 parent 9b8e707 commit b9d441f

File tree

1 file changed

+34
-9
lines changed

1 file changed

+34
-9
lines changed

provisionersdk/agent_test.go

+34-9
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,6 @@ package provisionersdk_test
88

99
import (
1010
"bytes"
11-
"context"
1211
"errors"
1312
"fmt"
1413
"net/http"
@@ -47,12 +46,10 @@ func TestAgentScript(t *testing.T) {
4746
t.Run("Valid", func(t *testing.T) {
4847
t.Parallel()
4948

49+
ctx := testutil.Context(t, testutil.WaitShort)
5050
script := serveScript(t, bashEcho)
5151

52-
ctx, cancel := context.WithTimeout(context.Background(), testutil.WaitShort)
53-
t.Cleanup(cancel)
54-
55-
var output bytes.Buffer
52+
var output safeBuffer
5653
// This is intentionally ran in single quotes to mimic how a customer may
5754
// embed our script. Our scripts should not include any single quotes.
5855
// nolint:gosec
@@ -84,12 +81,10 @@ func TestAgentScript(t *testing.T) {
8481
t.Run("Invalid", func(t *testing.T) {
8582
t.Parallel()
8683

84+
ctx := testutil.Context(t, testutil.WaitShort)
8785
script := serveScript(t, unexpectedEcho)
8886

89-
ctx, cancel := context.WithTimeout(context.Background(), testutil.WaitShort)
90-
t.Cleanup(cancel)
91-
92-
var output bytes.Buffer
87+
var output safeBuffer
9388
// This is intentionally ran in single quotes to mimic how a customer may
9489
// embed our script. Our scripts should not include any single quotes.
9590
// nolint:gosec
@@ -159,3 +154,33 @@ func serveScript(t *testing.T, in string) string {
159154
script = strings.ReplaceAll(script, "${AUTH_TYPE}", "token")
160155
return script
161156
}
157+
158+
// safeBuffer is a concurrency-safe bytes.Buffer
159+
type safeBuffer struct {
160+
mu sync.Mutex
161+
buf bytes.Buffer
162+
}
163+
164+
func (sb *safeBuffer) Write(p []byte) (n int, err error) {
165+
sb.mu.Lock()
166+
defer sb.mu.Unlock()
167+
return sb.buf.Write(p)
168+
}
169+
170+
func (sb *safeBuffer) Read(p []byte) (n int, err error) {
171+
sb.mu.Lock()
172+
defer sb.mu.Unlock()
173+
return sb.buf.Read(p)
174+
}
175+
176+
func (sb *safeBuffer) Bytes() []byte {
177+
sb.mu.Lock()
178+
defer sb.mu.Unlock()
179+
return sb.buf.Bytes()
180+
}
181+
182+
func (sb *safeBuffer) String() string {
183+
sb.mu.Lock()
184+
defer sb.mu.Unlock()
185+
return sb.buf.String()
186+
}

0 commit comments

Comments
 (0)