chore(testutil): extract testutil.CreateZip and testutil.CreateTar helpers (#15540)

Extracts `testutil.CreateTar` and `testutil.CreateZip` test helpers.
This commit is contained in:
Cian Johnston
2024-11-18 09:17:04 +00:00
committed by GitHub
parent f9d6698384
commit 4719d2406f
6 changed files with 89 additions and 116 deletions

View File

@ -9,6 +9,7 @@ import (
"github.com/stretchr/testify/require" "github.com/stretchr/testify/require"
"github.com/coder/coder/v2/provisionersdk/proto" "github.com/coder/coder/v2/provisionersdk/proto"
"github.com/coder/coder/v2/testutil"
) )
func TestParse(t *testing.T) { func TestParse(t *testing.T) {
@ -380,7 +381,7 @@ func TestParse(t *testing.T) {
t.Parallel() t.Parallel()
session := configure(ctx, t, api, &proto.Config{ session := configure(ctx, t, api, &proto.Config{
TemplateSourceArchive: makeTar(t, testCase.Files), TemplateSourceArchive: testutil.CreateTar(t, testCase.Files),
}) })
err := session.Send(&proto.Request{Type: &proto.Request_Parse{Parse: &proto.ParseRequest{}}}) err := session.Send(&proto.Request{Type: &proto.Request_Parse{Parse: &proto.ParseRequest{}}})

View File

@ -3,8 +3,6 @@
package terraform_test package terraform_test
import ( import (
"archive/tar"
"bytes"
"context" "context"
"encoding/json" "encoding/json"
"errors" "errors"
@ -28,6 +26,7 @@ import (
"github.com/coder/coder/v2/provisioner/terraform" "github.com/coder/coder/v2/provisioner/terraform"
"github.com/coder/coder/v2/provisionersdk" "github.com/coder/coder/v2/provisionersdk"
"github.com/coder/coder/v2/provisionersdk/proto" "github.com/coder/coder/v2/provisionersdk/proto"
"github.com/coder/coder/v2/testutil"
) )
type provisionerServeOptions struct { type provisionerServeOptions struct {
@ -78,39 +77,6 @@ func setupProvisioner(t *testing.T, opts *provisionerServeOptions) (context.Cont
return ctx, api return ctx, api
} }
func makeTar(t *testing.T, files map[string]string) []byte {
t.Helper()
var buffer bytes.Buffer
writer := tar.NewWriter(&buffer)
addedDirs := make(map[string]bool)
for name, content := range files {
// Add parent directories if they don't exist
dir := filepath.Dir(name)
if dir != "." && !addedDirs[dir] {
err := writer.WriteHeader(&tar.Header{
Name: dir + "/", // Directory names must end with /
Mode: 0o755,
Typeflag: tar.TypeDir,
})
require.NoError(t, err)
addedDirs[dir] = true
}
err := writer.WriteHeader(&tar.Header{
Name: name,
Size: int64(len(content)),
Mode: 0o644,
})
require.NoError(t, err)
_, err = writer.Write([]byte(content))
require.NoError(t, err)
}
err := writer.Flush()
require.NoError(t, err)
return buffer.Bytes()
}
func configure(ctx context.Context, t *testing.T, client proto.DRPCProvisionerClient, config *proto.Config) proto.DRPCProvisioner_SessionClient { func configure(ctx context.Context, t *testing.T, client proto.DRPCProvisionerClient, config *proto.Config) proto.DRPCProvisioner_SessionClient {
t.Helper() t.Helper()
sess, err := client.Session(ctx) sess, err := client.Session(ctx)
@ -200,7 +166,7 @@ func TestProvision_Cancel(t *testing.T) {
binaryPath: binPath, binaryPath: binPath,
}) })
sess := configure(ctx, t, api, &proto.Config{ sess := configure(ctx, t, api, &proto.Config{
TemplateSourceArchive: makeTar(t, nil), TemplateSourceArchive: testutil.CreateTar(t, nil),
}) })
err = sendPlan(sess, proto.WorkspaceTransition_START) err = sendPlan(sess, proto.WorkspaceTransition_START)
@ -271,7 +237,7 @@ func TestProvision_CancelTimeout(t *testing.T) {
}) })
sess := configure(ctx, t, api, &proto.Config{ sess := configure(ctx, t, api, &proto.Config{
TemplateSourceArchive: makeTar(t, nil), TemplateSourceArchive: testutil.CreateTar(t, nil),
}) })
// provisioner requires plan before apply, so test cancel with plan. // provisioner requires plan before apply, so test cancel with plan.
@ -360,7 +326,7 @@ func TestProvision_TextFileBusy(t *testing.T) {
}) })
sess := configure(ctx, t, api, &proto.Config{ sess := configure(ctx, t, api, &proto.Config{
TemplateSourceArchive: makeTar(t, nil), TemplateSourceArchive: testutil.CreateTar(t, nil),
}) })
err = sendPlan(sess, proto.WorkspaceTransition_START) err = sendPlan(sess, proto.WorkspaceTransition_START)
@ -811,7 +777,7 @@ func TestProvision(t *testing.T) {
ctx, api := setupProvisioner(t, nil) ctx, api := setupProvisioner(t, nil)
sess := configure(ctx, t, api, &proto.Config{ sess := configure(ctx, t, api, &proto.Config{
TemplateSourceArchive: makeTar(t, testCase.Files), TemplateSourceArchive: testutil.CreateTar(t, testCase.Files),
}) })
planRequest := &proto.Request{Type: &proto.Request_Plan{Plan: &proto.PlanRequest{ planRequest := &proto.Request{Type: &proto.Request_Plan{Plan: &proto.PlanRequest{
@ -925,7 +891,7 @@ func TestProvision_ExtraEnv(t *testing.T) {
ctx, api := setupProvisioner(t, nil) ctx, api := setupProvisioner(t, nil)
sess := configure(ctx, t, api, &proto.Config{ sess := configure(ctx, t, api, &proto.Config{
TemplateSourceArchive: makeTar(t, map[string]string{"main.tf": `resource "null_resource" "A" {}`}), TemplateSourceArchive: testutil.CreateTar(t, map[string]string{"main.tf": `resource "null_resource" "A" {}`}),
}) })
err := sendPlan(sess, proto.WorkspaceTransition_START) err := sendPlan(sess, proto.WorkspaceTransition_START)
@ -975,7 +941,7 @@ func TestProvision_SafeEnv(t *testing.T) {
ctx, api := setupProvisioner(t, nil) ctx, api := setupProvisioner(t, nil)
sess := configure(ctx, t, api, &proto.Config{ sess := configure(ctx, t, api, &proto.Config{
TemplateSourceArchive: makeTar(t, map[string]string{"main.tf": echoResource}), TemplateSourceArchive: testutil.CreateTar(t, map[string]string{"main.tf": echoResource}),
}) })
err := sendPlan(sess, proto.WorkspaceTransition_START) err := sendPlan(sess, proto.WorkspaceTransition_START)
@ -997,7 +963,7 @@ func TestProvision_MalformedModules(t *testing.T) {
ctx, api := setupProvisioner(t, nil) ctx, api := setupProvisioner(t, nil)
sess := configure(ctx, t, api, &proto.Config{ sess := configure(ctx, t, api, &proto.Config{
TemplateSourceArchive: makeTar(t, map[string]string{ TemplateSourceArchive: testutil.CreateTar(t, map[string]string{
"main.tf": `module "hello" { source = "./module" }`, "main.tf": `module "hello" { source = "./module" }`,
"module/module.tf": `resource "null_`, "module/module.tf": `resource "null_`,
}), }),

View File

@ -1,8 +1,6 @@
package tfparse_test package tfparse_test
import ( import (
"archive/tar"
"bytes"
"context" "context"
"io" "io"
"log" "log"
@ -11,7 +9,6 @@ import (
"cdr.dev/slog" "cdr.dev/slog"
"cdr.dev/slog/sloggers/sloghuman" "cdr.dev/slog/sloggers/sloghuman"
"cdr.dev/slog/sloggers/slogtest" "cdr.dev/slog/sloggers/slogtest"
"github.com/coder/coder/v2/archive"
"github.com/coder/coder/v2/provisioner/terraform/tfparse" "github.com/coder/coder/v2/provisioner/terraform/tfparse"
"github.com/coder/coder/v2/testutil" "github.com/coder/coder/v2/testutil"
@ -363,7 +360,7 @@ func Test_WorkspaceTagDefaultsFromFile(t *testing.T) {
t.Run(tc.name+"/tar", func(t *testing.T) { t.Run(tc.name+"/tar", func(t *testing.T) {
t.Parallel() t.Parallel()
ctx := testutil.Context(t, testutil.WaitShort) ctx := testutil.Context(t, testutil.WaitShort)
tar := createTar(t, tc.files) tar := testutil.CreateTar(t, tc.files)
logger := slogtest.Make(t, nil).Leveled(slog.LevelDebug) logger := slogtest.Make(t, nil).Leveled(slog.LevelDebug)
tmpDir := t.TempDir() tmpDir := t.TempDir()
tfparse.WriteArchive(tar, "application/x-tar", tmpDir) tfparse.WriteArchive(tar, "application/x-tar", tmpDir)
@ -381,7 +378,7 @@ func Test_WorkspaceTagDefaultsFromFile(t *testing.T) {
t.Run(tc.name+"/zip", func(t *testing.T) { t.Run(tc.name+"/zip", func(t *testing.T) {
t.Parallel() t.Parallel()
ctx := testutil.Context(t, testutil.WaitShort) ctx := testutil.Context(t, testutil.WaitShort)
zip := createZip(t, tc.files) zip := testutil.CreateZip(t, tc.files)
logger := slogtest.Make(t, nil).Leveled(slog.LevelDebug) logger := slogtest.Make(t, nil).Leveled(slog.LevelDebug)
tmpDir := t.TempDir() tmpDir := t.TempDir()
tfparse.WriteArchive(zip, "application/zip", tmpDir) tfparse.WriteArchive(zip, "application/zip", tmpDir)
@ -399,36 +396,6 @@ func Test_WorkspaceTagDefaultsFromFile(t *testing.T) {
} }
} }
func createTar(t testing.TB, files map[string]string) []byte {
var buffer bytes.Buffer
writer := tar.NewWriter(&buffer)
for path, content := range files {
err := writer.WriteHeader(&tar.Header{
Name: path,
Size: int64(len(content)),
Uid: 65534, // nobody
Gid: 65534, // nogroup
Mode: 0o666, // -rw-rw-rw-
})
require.NoError(t, err)
_, err = writer.Write([]byte(content))
require.NoError(t, err)
}
err := writer.Flush()
require.NoError(t, err)
return buffer.Bytes()
}
func createZip(t testing.TB, files map[string]string) []byte {
ta := createTar(t, files)
tr := tar.NewReader(bytes.NewReader(ta))
za, err := archive.CreateZipFromTar(tr, int64(len(ta)))
require.NoError(t, err)
return za
}
// Last run results: // Last run results:
// goos: linux // goos: linux
// goarch: amd64 // goarch: amd64
@ -460,8 +427,8 @@ func BenchmarkWorkspaceTagDefaultsFromFile(b *testing.B) {
} }
}`, }`,
} }
tarFile := createTar(b, files) tarFile := testutil.CreateTar(b, files)
zipFile := createZip(b, files) zipFile := testutil.CreateZip(b, files)
logger := discardLogger(b) logger := discardLogger(b)
b.ResetTimer() b.ResetTimer()
b.Run("Tar", func(b *testing.B) { b.Run("Tar", func(b *testing.B) {

View File

@ -34,7 +34,7 @@ func TestTimingsFromProvision(t *testing.T) {
binaryPath: fakeBin, binaryPath: fakeBin,
}) })
sess := configure(ctx, t, api, &proto.Config{ sess := configure(ctx, t, api, &proto.Config{
TemplateSourceArchive: makeTar(t, nil), TemplateSourceArchive: testutil.CreateTar(t, nil),
}) })
ctx, cancel := context.WithTimeout(ctx, testutil.WaitLong) ctx, cancel := context.WithTimeout(ctx, testutil.WaitLong)

View File

@ -1,8 +1,6 @@
package provisionerd_test package provisionerd_test
import ( import (
"archive/tar"
"bytes"
"context" "context"
"fmt" "fmt"
"io" "io"
@ -97,7 +95,7 @@ func TestProvisionerd(t *testing.T) {
err := stream.Send(&proto.AcquiredJob{ err := stream.Send(&proto.AcquiredJob{
JobId: "test", JobId: "test",
Provisioner: "someprovisioner", Provisioner: "someprovisioner",
TemplateSourceArchive: createTar(t, map[string]string{ TemplateSourceArchive: testutil.CreateTar(t, map[string]string{
"test.txt": "content", "test.txt": "content",
}), }),
Type: &proto.AcquiredJob_TemplateImport_{ Type: &proto.AcquiredJob_TemplateImport_{
@ -150,7 +148,7 @@ func TestProvisionerd(t *testing.T) {
acq = newAcquireOne(t, &proto.AcquiredJob{ acq = newAcquireOne(t, &proto.AcquiredJob{
JobId: "test", JobId: "test",
Provisioner: "someprovisioner", Provisioner: "someprovisioner",
TemplateSourceArchive: createTar(t, map[string]string{ TemplateSourceArchive: testutil.CreateTar(t, map[string]string{
"../../../etc/passwd": "content", "../../../etc/passwd": "content",
}), }),
Type: &proto.AcquiredJob_TemplateImport_{ Type: &proto.AcquiredJob_TemplateImport_{
@ -194,7 +192,7 @@ func TestProvisionerd(t *testing.T) {
err := stream.Send(&proto.AcquiredJob{ err := stream.Send(&proto.AcquiredJob{
JobId: "test", JobId: "test",
Provisioner: "someprovisioner", Provisioner: "someprovisioner",
TemplateSourceArchive: createTar(t, map[string]string{ TemplateSourceArchive: testutil.CreateTar(t, map[string]string{
"test.txt": "content", "test.txt": "content",
}), }),
Type: &proto.AcquiredJob_TemplateImport_{ Type: &proto.AcquiredJob_TemplateImport_{
@ -243,7 +241,7 @@ func TestProvisionerd(t *testing.T) {
acq = newAcquireOne(t, &proto.AcquiredJob{ acq = newAcquireOne(t, &proto.AcquiredJob{
JobId: "test", JobId: "test",
Provisioner: "someprovisioner", Provisioner: "someprovisioner",
TemplateSourceArchive: createTar(t, map[string]string{ TemplateSourceArchive: testutil.CreateTar(t, map[string]string{
"test.txt": "content", "test.txt": "content",
provisionersdk.ReadmeFile: "# A cool template 😎\n", provisionersdk.ReadmeFile: "# A cool template 😎\n",
}), }),
@ -325,7 +323,7 @@ func TestProvisionerd(t *testing.T) {
acq = newAcquireOne(t, &proto.AcquiredJob{ acq = newAcquireOne(t, &proto.AcquiredJob{
JobId: "test", JobId: "test",
Provisioner: "someprovisioner", Provisioner: "someprovisioner",
TemplateSourceArchive: createTar(t, map[string]string{ TemplateSourceArchive: testutil.CreateTar(t, map[string]string{
"test.txt": "content", "test.txt": "content",
}), }),
Type: &proto.AcquiredJob_TemplateDryRun_{ Type: &proto.AcquiredJob_TemplateDryRun_{
@ -396,7 +394,7 @@ func TestProvisionerd(t *testing.T) {
acq = newAcquireOne(t, &proto.AcquiredJob{ acq = newAcquireOne(t, &proto.AcquiredJob{
JobId: "test", JobId: "test",
Provisioner: "someprovisioner", Provisioner: "someprovisioner",
TemplateSourceArchive: createTar(t, map[string]string{ TemplateSourceArchive: testutil.CreateTar(t, map[string]string{
"test.txt": "content", "test.txt": "content",
}), }),
Type: &proto.AcquiredJob_WorkspaceBuild_{ Type: &proto.AcquiredJob_WorkspaceBuild_{
@ -459,7 +457,7 @@ func TestProvisionerd(t *testing.T) {
acq = newAcquireOne(t, &proto.AcquiredJob{ acq = newAcquireOne(t, &proto.AcquiredJob{
JobId: "test", JobId: "test",
Provisioner: "someprovisioner", Provisioner: "someprovisioner",
TemplateSourceArchive: createTar(t, map[string]string{ TemplateSourceArchive: testutil.CreateTar(t, map[string]string{
"test.txt": "content", "test.txt": "content",
}), }),
Type: &proto.AcquiredJob_WorkspaceBuild_{ Type: &proto.AcquiredJob_WorkspaceBuild_{
@ -549,7 +547,7 @@ func TestProvisionerd(t *testing.T) {
acq = newAcquireOne(t, &proto.AcquiredJob{ acq = newAcquireOne(t, &proto.AcquiredJob{
JobId: "test", JobId: "test",
Provisioner: "someprovisioner", Provisioner: "someprovisioner",
TemplateSourceArchive: createTar(t, map[string]string{ TemplateSourceArchive: testutil.CreateTar(t, map[string]string{
"test.txt": "content", "test.txt": "content",
}), }),
Type: &proto.AcquiredJob_WorkspaceBuild_{ Type: &proto.AcquiredJob_WorkspaceBuild_{
@ -645,7 +643,7 @@ func TestProvisionerd(t *testing.T) {
err := stream.Send(&proto.AcquiredJob{ err := stream.Send(&proto.AcquiredJob{
JobId: "test", JobId: "test",
Provisioner: "someprovisioner", Provisioner: "someprovisioner",
TemplateSourceArchive: createTar(t, map[string]string{ TemplateSourceArchive: testutil.CreateTar(t, map[string]string{
"test.txt": "content", "test.txt": "content",
}), }),
Type: &proto.AcquiredJob_WorkspaceBuild_{ Type: &proto.AcquiredJob_WorkspaceBuild_{
@ -725,7 +723,7 @@ func TestProvisionerd(t *testing.T) {
err := stream.Send(&proto.AcquiredJob{ err := stream.Send(&proto.AcquiredJob{
JobId: "test", JobId: "test",
Provisioner: "someprovisioner", Provisioner: "someprovisioner",
TemplateSourceArchive: createTar(t, map[string]string{ TemplateSourceArchive: testutil.CreateTar(t, map[string]string{
"test.txt": "content", "test.txt": "content",
}), }),
Type: &proto.AcquiredJob_WorkspaceBuild_{ Type: &proto.AcquiredJob_WorkspaceBuild_{
@ -819,7 +817,7 @@ func TestProvisionerd(t *testing.T) {
job := &proto.AcquiredJob{ job := &proto.AcquiredJob{
JobId: "test", JobId: "test",
Provisioner: "someprovisioner", Provisioner: "someprovisioner",
TemplateSourceArchive: createTar(t, map[string]string{ TemplateSourceArchive: testutil.CreateTar(t, map[string]string{
"test.txt": "content", "test.txt": "content",
}), }),
Type: &proto.AcquiredJob_WorkspaceBuild_{ Type: &proto.AcquiredJob_WorkspaceBuild_{
@ -916,7 +914,7 @@ func TestProvisionerd(t *testing.T) {
job := &proto.AcquiredJob{ job := &proto.AcquiredJob{
JobId: "test", JobId: "test",
Provisioner: "someprovisioner", Provisioner: "someprovisioner",
TemplateSourceArchive: createTar(t, map[string]string{ TemplateSourceArchive: testutil.CreateTar(t, map[string]string{
"test.txt": "content", "test.txt": "content",
}), }),
Type: &proto.AcquiredJob_WorkspaceBuild_{ Type: &proto.AcquiredJob_WorkspaceBuild_{
@ -1010,7 +1008,7 @@ func TestProvisionerd(t *testing.T) {
err := stream.Send(&proto.AcquiredJob{ err := stream.Send(&proto.AcquiredJob{
JobId: "test", JobId: "test",
Provisioner: "someprovisioner", Provisioner: "someprovisioner",
TemplateSourceArchive: createTar(t, map[string]string{ TemplateSourceArchive: testutil.CreateTar(t, map[string]string{
"test.txt": "content", "test.txt": "content",
}), }),
Type: &proto.AcquiredJob_WorkspaceBuild_{ Type: &proto.AcquiredJob_WorkspaceBuild_{
@ -1078,26 +1076,6 @@ func TestProvisionerd(t *testing.T) {
}) })
} }
// Creates an in-memory tar of the files provided.
func createTar(t *testing.T, files map[string]string) []byte {
var buffer bytes.Buffer
writer := tar.NewWriter(&buffer)
for path, content := range files {
err := writer.WriteHeader(&tar.Header{
Name: path,
Size: int64(len(content)),
})
require.NoError(t, err)
_, err = writer.Write([]byte(content))
require.NoError(t, err)
}
err := writer.Flush()
require.NoError(t, err)
return buffer.Bytes()
}
// Creates a provisionerd implementation with the provided dialer and provisioners. // Creates a provisionerd implementation with the provided dialer and provisioners.
func createProvisionerd(t *testing.T, dialer provisionerd.Dialer, connector provisionerd.LocalProvisioners) *provisionerd.Server { func createProvisionerd(t *testing.T, dialer provisionerd.Dialer, connector provisionerd.LocalProvisioners) *provisionerd.Server {
server := provisionerd.New(dialer, &provisionerd.Options{ server := provisionerd.New(dialer, &provisionerd.Options{

61
testutil/archive.go Normal file
View File

@ -0,0 +1,61 @@
package testutil
import (
"archive/tar"
"bytes"
"path/filepath"
"testing"
"github.com/stretchr/testify/require"
"github.com/coder/coder/v2/archive"
)
// Creates an in-memory tar of the files provided.
// Files in the archive are written with nobody
// owner/group, and -rw-rw-rw- permissions.
func CreateTar(t testing.TB, files map[string]string) []byte {
var buffer bytes.Buffer
writer := tar.NewWriter(&buffer)
// Keep track of directories previously added.
addedDirs := make(map[string]bool)
for path, content := range files {
// Add parent directories if they don't exist
dir := filepath.Dir(path)
if dir != "." && !addedDirs[dir] {
err := writer.WriteHeader(&tar.Header{
Name: dir + "/", // Directory names must end with /
Mode: 0o755,
Typeflag: tar.TypeDir,
})
require.NoError(t, err)
addedDirs[dir] = true
}
err := writer.WriteHeader(&tar.Header{
Name: path,
Size: int64(len(content)),
Uid: 65534, // nobody
Gid: 65534, // nogroup
Mode: 0o666, // -rw-rw-rw-
})
require.NoError(t, err)
_, err = writer.Write([]byte(content))
require.NoError(t, err)
}
err := writer.Flush()
require.NoError(t, err)
return buffer.Bytes()
}
// Creates an in-memory zip of the files provided.
// Uses archive.CreateZipFromTar under the hood.
func CreateZip(t testing.TB, files map[string]string) []byte {
ta := CreateTar(t, files)
tr := tar.NewReader(bytes.NewReader(ta))
za, err := archive.CreateZipFromTar(tr, int64(len(ta)))
require.NoError(t, err)
return za
}