Skip to content

Commit 024ab6d

Browse files
authored
fix: Use in-memory filesystem for echo provisioner tests (#2408)
* fix: Use in-memory filesystem for echo provisioner tests This should reduce IO in CI to shave some time off tests! * test: Increase timeouts to reduce flakes It's difficult to understand what's timing out due to a lock vs. taking a long time. This should help resolve! 🕵️
1 parent 5e673cc commit 024ab6d

File tree

6 files changed

+44
-27
lines changed

6 files changed

+44
-27
lines changed

cli/server.go

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ import (
3232
"github.com/pion/turn/v2"
3333
"github.com/pion/webrtc/v3"
3434
"github.com/prometheus/client_golang/prometheus/promhttp"
35+
"github.com/spf13/afero"
3536
"github.com/spf13/cobra"
3637
sdktrace "go.opentelemetry.io/otel/sdk/trace"
3738
"golang.org/x/oauth2"
@@ -550,7 +551,7 @@ func newProvisionerDaemon(ctx context.Context, coderAPI *coderd.API,
550551
if dev {
551552
echoClient, echoServer := provisionersdk.TransportPipe()
552553
go func() {
553-
err := echo.Serve(ctx, &provisionersdk.ServeOptions{Listener: echoServer})
554+
err := echo.Serve(ctx, afero.NewOsFs(), &provisionersdk.ServeOptions{Listener: echoServer})
554555
if err != nil {
555556
errChan <- err
556557
}

coderd/coderdtest/coderdtest.go

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,8 @@ import (
2525
"testing"
2626
"time"
2727

28+
"github.com/spf13/afero"
29+
2830
"github.com/coder/coder/coderd/rbac"
2931
"github.com/coder/coder/coderd/util/ptr"
3032

@@ -190,18 +192,20 @@ func NewProvisionerDaemon(t *testing.T, coderAPI *coderd.API) io.Closer {
190192
_ = echoServer.Close()
191193
cancelFunc()
192194
})
195+
fs := afero.NewMemMapFs()
193196
go func() {
194-
err := echo.Serve(ctx, &provisionersdk.ServeOptions{
197+
err := echo.Serve(ctx, fs, &provisionersdk.ServeOptions{
195198
Listener: echoServer,
196199
})
197200
assert.NoError(t, err)
198201
}()
199202

200203
closer := provisionerd.New(coderAPI.ListenProvisionerDaemon, &provisionerd.Options{
204+
Filesystem: fs,
201205
Logger: slogtest.Make(t, nil).Named("provisionerd").Leveled(slog.LevelDebug),
202-
PollInterval: 50 * time.Millisecond,
203-
UpdateInterval: 250 * time.Millisecond,
204-
ForceCancelInterval: 250 * time.Millisecond,
206+
PollInterval: 10 * time.Millisecond,
207+
UpdateInterval: 25 * time.Millisecond,
208+
ForceCancelInterval: 25 * time.Millisecond,
205209
Provisioners: provisionerd.Provisioners{
206210
string(database.ProvisionerTypeEcho): proto.NewDRPCProvisionerClient(provisionersdk.Conn(echoClient)),
207211
},

go.mod

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -227,7 +227,7 @@ require (
227227
github.com/rcrowley/go-metrics v0.0.0-20200313005456-10cdbea86bc0 // indirect
228228
github.com/rivo/uniseg v0.2.0 // indirect
229229
github.com/sirupsen/logrus v1.8.1 // indirect
230-
github.com/spf13/afero v1.8.2 // indirect
230+
github.com/spf13/afero v1.8.2
231231
github.com/spf13/cast v1.5.0 // indirect
232232
github.com/spf13/jwalterweatherman v1.1.0 // indirect
233233
github.com/tadvi/systray v0.0.0-20190226123456-11a2b8fa57af // indirect

provisioner/echo/serve.go

Lines changed: 15 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -5,12 +5,13 @@ import (
55
"bytes"
66
"context"
77
"fmt"
8-
"os"
98
"path/filepath"
109

1110
"golang.org/x/xerrors"
1211
protobuf "google.golang.org/protobuf/proto"
1312

13+
"github.com/spf13/afero"
14+
1415
"github.com/coder/coder/provisionersdk"
1516
"github.com/coder/coder/provisionersdk/proto"
1617
)
@@ -31,28 +32,32 @@ var (
3132
)
3233

3334
// Serve starts the echo provisioner.
34-
func Serve(ctx context.Context, options *provisionersdk.ServeOptions) error {
35-
return provisionersdk.Serve(ctx, &echo{}, options)
35+
func Serve(ctx context.Context, filesystem afero.Fs, options *provisionersdk.ServeOptions) error {
36+
return provisionersdk.Serve(ctx, &echo{
37+
filesystem: filesystem,
38+
}, options)
3639
}
3740

3841
// The echo provisioner serves as a dummy provisioner primarily
3942
// used for testing. It echos responses from JSON files in the
4043
// format %d.protobuf. It's used for testing.
41-
type echo struct{}
44+
type echo struct {
45+
filesystem afero.Fs
46+
}
4247

4348
// Parse reads requests from the provided directory to stream responses.
44-
func (*echo) Parse(request *proto.Parse_Request, stream proto.DRPCProvisioner_ParseStream) error {
49+
func (e *echo) Parse(request *proto.Parse_Request, stream proto.DRPCProvisioner_ParseStream) error {
4550
for index := 0; ; index++ {
4651
path := filepath.Join(request.Directory, fmt.Sprintf("%d.parse.protobuf", index))
47-
_, err := os.Stat(path)
52+
_, err := e.filesystem.Stat(path)
4853
if err != nil {
4954
if index == 0 {
5055
// Error if nothing is around to enable failed states.
5156
return xerrors.New("no state")
5257
}
5358
break
5459
}
55-
data, err := os.ReadFile(path)
60+
data, err := afero.ReadFile(e.filesystem, path)
5661
if err != nil {
5762
return xerrors.Errorf("read file %q: %w", path, err)
5863
}
@@ -71,7 +76,7 @@ func (*echo) Parse(request *proto.Parse_Request, stream proto.DRPCProvisioner_Pa
7176
}
7277

7378
// Provision reads requests from the provided directory to stream responses.
74-
func (*echo) Provision(stream proto.DRPCProvisioner_ProvisionStream) error {
79+
func (e *echo) Provision(stream proto.DRPCProvisioner_ProvisionStream) error {
7580
msg, err := stream.Recv()
7681
if err != nil {
7782
return err
@@ -83,15 +88,15 @@ func (*echo) Provision(stream proto.DRPCProvisioner_ProvisionStream) error {
8388
extension = ".dry.protobuf"
8489
}
8590
path := filepath.Join(request.Directory, fmt.Sprintf("%d.provision"+extension, index))
86-
_, err := os.Stat(path)
91+
_, err := e.filesystem.Stat(path)
8792
if err != nil {
8893
if index == 0 {
8994
// Error if nothing is around to enable failed states.
9095
return xerrors.New("no state")
9196
}
9297
break
9398
}
94-
data, err := os.ReadFile(path)
99+
data, err := afero.ReadFile(e.filesystem, path)
95100
if err != nil {
96101
return xerrors.Errorf("read file %q: %w", path, err)
97102
}

provisioner/echo/serve_test.go

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import (
99
"path/filepath"
1010
"testing"
1111

12+
"github.com/spf13/afero"
1213
"github.com/stretchr/testify/assert"
1314
"github.com/stretchr/testify/require"
1415

@@ -20,6 +21,7 @@ import (
2021
func TestEcho(t *testing.T) {
2122
t.Parallel()
2223

24+
fs := afero.NewMemMapFs()
2325
// Create an in-memory provisioner to communicate with.
2426
client, server := provisionersdk.TransportPipe()
2527
ctx, cancelFunc := context.WithCancel(context.Background())
@@ -29,7 +31,7 @@ func TestEcho(t *testing.T) {
2931
cancelFunc()
3032
})
3133
go func() {
32-
err := echo.Serve(ctx, &provisionersdk.ServeOptions{
34+
err := echo.Serve(ctx, fs, &provisionersdk.ServeOptions{
3335
Listener: server,
3436
})
3537
assert.NoError(t, err)
@@ -59,7 +61,7 @@ func TestEcho(t *testing.T) {
5961
})
6062
require.NoError(t, err)
6163
client, err := api.Parse(ctx, &proto.Parse_Request{
62-
Directory: unpackTar(t, data),
64+
Directory: unpackTar(t, fs, data),
6365
})
6466
require.NoError(t, err)
6567
log, err := client.Recv()
@@ -98,7 +100,7 @@ func TestEcho(t *testing.T) {
98100
err = client.Send(&proto.Provision_Request{
99101
Type: &proto.Provision_Request_Start{
100102
Start: &proto.Provision_Start{
101-
Directory: unpackTar(t, data),
103+
Directory: unpackTar(t, fs, data),
102104
},
103105
},
104106
})
@@ -113,7 +115,7 @@ func TestEcho(t *testing.T) {
113115
})
114116
}
115117

116-
func unpackTar(t *testing.T, data []byte) string {
118+
func unpackTar(t *testing.T, fs afero.Fs, data []byte) string {
117119
directory := t.TempDir()
118120
reader := tar.NewReader(bytes.NewReader(data))
119121
for {
@@ -123,7 +125,7 @@ func unpackTar(t *testing.T, data []byte) string {
123125
}
124126
// #nosec
125127
path := filepath.Join(directory, header.Name)
126-
file, err := os.OpenFile(path, os.O_CREATE|os.O_RDWR, 0600)
128+
file, err := fs.OpenFile(path, os.O_CREATE|os.O_RDWR, 0600)
127129
require.NoError(t, err)
128130
_, err = io.CopyN(file, reader, 1<<20)
129131
require.ErrorIs(t, err, io.EOF)

provisionerd/provisionerd.go

Lines changed: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ import (
1717

1818
"github.com/google/uuid"
1919
"github.com/hashicorp/yamux"
20+
"github.com/spf13/afero"
2021
"go.uber.org/atomic"
2122
"golang.org/x/xerrors"
2223

@@ -45,7 +46,8 @@ type Provisioners map[string]sdkproto.DRPCProvisionerClient
4546

4647
// Options provides customizations to the behavior of a provisioner daemon.
4748
type Options struct {
48-
Logger slog.Logger
49+
Filesystem afero.Fs
50+
Logger slog.Logger
4951

5052
ForceCancelInterval time.Duration
5153
UpdateInterval time.Duration
@@ -65,6 +67,9 @@ func New(clientDialer Dialer, opts *Options) *Server {
6567
if opts.ForceCancelInterval == 0 {
6668
opts.ForceCancelInterval = time.Minute
6769
}
70+
if opts.Filesystem == nil {
71+
opts.Filesystem = afero.NewOsFs()
72+
}
6873
ctx, ctxCancel := context.WithCancel(context.Background())
6974
daemon := &Server{
7075
clientDialer: clientDialer,
@@ -303,7 +308,7 @@ func (p *Server) runJob(ctx context.Context, job *proto.AcquiredJob) {
303308
defer func() {
304309
// Cleanup the work directory after execution.
305310
for attempt := 0; attempt < 5; attempt++ {
306-
err := os.RemoveAll(p.opts.WorkDirectory)
311+
err := p.opts.Filesystem.RemoveAll(p.opts.WorkDirectory)
307312
if err != nil {
308313
// On Windows, open files cannot be removed.
309314
// When the provisioner daemon is shutting down,
@@ -326,7 +331,7 @@ func (p *Server) runJob(ctx context.Context, job *proto.AcquiredJob) {
326331
return
327332
}
328333

329-
err := os.MkdirAll(p.opts.WorkDirectory, 0700)
334+
err := p.opts.Filesystem.MkdirAll(p.opts.WorkDirectory, 0700)
330335
if err != nil {
331336
p.failActiveJobf("create work directory %q: %s", p.opts.WorkDirectory, err)
332337
return
@@ -374,14 +379,14 @@ func (p *Server) runJob(ctx context.Context, job *proto.AcquiredJob) {
374379
}
375380
switch header.Typeflag {
376381
case tar.TypeDir:
377-
err = os.MkdirAll(headerPath, mode)
382+
err = p.opts.Filesystem.MkdirAll(headerPath, mode)
378383
if err != nil {
379384
p.failActiveJobf("mkdir %q: %s", headerPath, err)
380385
return
381386
}
382387
p.opts.Logger.Debug(context.Background(), "extracted directory", slog.F("path", headerPath))
383388
case tar.TypeReg:
384-
file, err := os.OpenFile(headerPath, os.O_CREATE|os.O_RDWR, mode)
389+
file, err := p.opts.Filesystem.OpenFile(headerPath, os.O_CREATE|os.O_RDWR, mode)
385390
if err != nil {
386391
p.failActiveJobf("create file %q (mode %s): %s", headerPath, mode, err)
387392
return
@@ -470,7 +475,7 @@ func (p *Server) runReadmeParse(ctx context.Context, job *proto.AcquiredJob) {
470475
return
471476
}
472477

473-
fi, err := os.ReadFile(path.Join(p.opts.WorkDirectory, ReadmeFile))
478+
fi, err := afero.ReadFile(p.opts.Filesystem, path.Join(p.opts.WorkDirectory, ReadmeFile))
474479
if err != nil {
475480
_, err := client.UpdateJob(ctx, &proto.UpdateJobRequest{
476481
JobId: job.GetJobId(),

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