Skip to content

Commit b9d441f

Browse files
authored
fix: use concurrency-safe bytes buffer to avoid race (#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

Lines changed: 34 additions & 9 deletions
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)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy