All checks were successful
Test / Create distribution (push) Successful in 46s
Test / Sandbox (push) Successful in 2m30s
Test / ShareFS (push) Successful in 3m34s
Test / Sandbox (race detector) (push) Successful in 4m42s
Test / Hpkg (push) Successful in 4m22s
Test / Hakurei (race detector) (push) Successful in 3m15s
Test / Hakurei (push) Successful in 2m28s
Test / Flake checks (push) Successful in 1m39s
This change contains primitives for validating and caching single-file artifacts. Signed-off-by: Ophestra <cat@gensokyo.uk>
367 lines
11 KiB
Go
367 lines
11 KiB
Go
package pkg_test
|
|
|
|
import (
|
|
"bytes"
|
|
"crypto/sha512"
|
|
"encoding/base64"
|
|
"io/fs"
|
|
"os"
|
|
"path/filepath"
|
|
"reflect"
|
|
"syscall"
|
|
"testing"
|
|
"testing/fstest"
|
|
|
|
"hakurei.app/container"
|
|
"hakurei.app/container/check"
|
|
"hakurei.app/container/stub"
|
|
"hakurei.app/internal/pkg"
|
|
)
|
|
|
|
func TestCache(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
const testdata = "" +
|
|
"\x00\x00\x00\x00" +
|
|
"\xad\x0b\x00" +
|
|
"\x04" +
|
|
"\xfe\xfe\x00\x00" +
|
|
"\xfe\xca\x00\x00"
|
|
|
|
testdataChecksum := func() pkg.Checksum {
|
|
h := sha512.New384()
|
|
h.Write([]byte(testdata))
|
|
return (pkg.Checksum)(h.Sum(nil))
|
|
}()
|
|
|
|
testdataChecksumString := base64.URLEncoding.EncodeToString(testdataChecksum[:])
|
|
|
|
testCases := []struct {
|
|
name string
|
|
early func(t *testing.T, base *check.Absolute)
|
|
f func(t *testing.T, base *check.Absolute, c *pkg.Cache)
|
|
check func(t *testing.T, base *check.Absolute)
|
|
}{
|
|
{"file", nil, func(t *testing.T, base *check.Absolute, c *pkg.Cache) {
|
|
wantErrNonexistent := &os.PathError{
|
|
Op: "open",
|
|
Path: base.Append(
|
|
"identifier",
|
|
testdataChecksumString,
|
|
).String(),
|
|
Err: syscall.ENOENT,
|
|
}
|
|
if _, _, err := c.LoadFile(testdataChecksum); !reflect.DeepEqual(err, wantErrNonexistent) {
|
|
t.Fatalf("LoadFile: error = %#v, want %#v", err, wantErrNonexistent)
|
|
}
|
|
|
|
identifier := (pkg.ID)(bytes.Repeat([]byte{
|
|
0x75, 0xe6, 0x9d, 0x6d, 0xe7, 0x9f,
|
|
}, 8))
|
|
wantPathname := base.Append(
|
|
"identifier",
|
|
"deadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeef",
|
|
)
|
|
identifier0 := (pkg.ID)(bytes.Repeat([]byte{
|
|
0x71, 0xa7, 0xde, 0x6d, 0xa6, 0xde,
|
|
}, 8))
|
|
wantPathname0 := base.Append(
|
|
"identifier",
|
|
"cafebabecafebabecafebabecafebabecafebabecafebabecafebabecafebabe",
|
|
)
|
|
|
|
// initial store
|
|
if pathname, err := c.StoreFile(
|
|
identifier,
|
|
[]byte(testdata),
|
|
&testdataChecksum,
|
|
true,
|
|
); err != nil {
|
|
t.Fatalf("StoreFile: error = %v", err)
|
|
} else if !pathname.Is(wantPathname) {
|
|
t.Fatalf("StoreFile: pathname = %q, want %q", pathname, wantPathname)
|
|
}
|
|
|
|
// load or store, identical content
|
|
if pathname, data, store, err := c.LoadOrStoreFile(identifier0, func() ([]byte, error) {
|
|
return []byte(testdata), nil
|
|
}, &testdataChecksum, true); err != nil {
|
|
t.Fatalf("LoadOrStoreFile: error = %v", err)
|
|
} else if !pathname.Is(wantPathname0) {
|
|
t.Fatalf("LoadOrStoreFile: pathname = %q, want %q", pathname, wantPathname0)
|
|
} else if string(data) != testdata {
|
|
t.Fatalf("LoadOrStoreFile: data = %x, want %x", data, testdata)
|
|
} else if !store {
|
|
t.Fatal("LoadOrStoreFile did not store nonpresent entry")
|
|
}
|
|
|
|
// load or store, existing entry
|
|
if pathname, data, store, err := c.LoadOrStoreFile(identifier, func() ([]byte, error) {
|
|
return []byte(testdata), nil
|
|
}, &testdataChecksum, true); err != nil {
|
|
t.Fatalf("LoadOrStoreFile: error = %v", err)
|
|
} else if !pathname.Is(wantPathname) {
|
|
t.Fatalf("LoadOrStoreFile: pathname = %q, want %q", pathname, wantPathname)
|
|
} else if string(data) != testdata {
|
|
t.Fatalf("LoadOrStoreFile: data = %x, want %x", data, testdata)
|
|
} else if store {
|
|
t.Fatal("LoadOrStoreFile stored over present entry")
|
|
}
|
|
|
|
// load, existing entry
|
|
if pathname, data, err := c.LoadFile(identifier0); err != nil {
|
|
t.Fatalf("LoadFile: error = %v", err)
|
|
} else if !pathname.Is(wantPathname0) {
|
|
t.Fatalf("LoadFile: pathname = %q, want %q", pathname, wantPathname0)
|
|
} else if string(data) != testdata {
|
|
t.Fatalf("LoadFile: data = %x, want %x", data, testdata)
|
|
}
|
|
|
|
// checksum mismatch
|
|
wantErrChecksum := &pkg.ChecksumMismatchError{
|
|
Got: testdataChecksum,
|
|
}
|
|
if _, err := c.StoreFile(
|
|
testdataChecksum,
|
|
[]byte(testdata),
|
|
new(pkg.Checksum),
|
|
true,
|
|
); !reflect.DeepEqual(err, wantErrChecksum) {
|
|
t.Fatalf("StoreFile: error = %#v, want %#v", err, wantErrChecksum)
|
|
}
|
|
|
|
// verify failed store
|
|
if _, _, err := c.LoadFile(testdataChecksum); !reflect.DeepEqual(err, wantErrNonexistent) {
|
|
t.Fatalf("LoadFile: error = %#v, want %#v", err, wantErrNonexistent)
|
|
}
|
|
|
|
// store, same identifier
|
|
wantPathnameF := base.Append(
|
|
"identifier",
|
|
testdataChecksumString,
|
|
)
|
|
if pathname, err := c.StoreFile(
|
|
testdataChecksum,
|
|
[]byte(testdata),
|
|
&testdataChecksum,
|
|
true,
|
|
); err != nil {
|
|
t.Fatalf("StoreFile: error = %v", err)
|
|
} else if !pathname.Is(wantPathnameF) {
|
|
t.Fatalf("StoreFile: pathname = %q, want %q", pathname, wantPathnameF)
|
|
}
|
|
|
|
// load, same identifier
|
|
if pathname, data, err := c.LoadFile(testdataChecksum); err != nil {
|
|
t.Fatalf("LoadFile: error = %v", err)
|
|
} else if !pathname.Is(wantPathnameF) {
|
|
t.Fatalf("LoadFile: pathname = %q, want %q", pathname, wantPathnameF)
|
|
} else if string(data) != testdata {
|
|
t.Fatalf("LoadFile: data = %x, want %x", data, testdata)
|
|
}
|
|
|
|
// store without validation
|
|
wantChecksum := pkg.Checksum{
|
|
0xbe, 0xc0, 0x21, 0xb4, 0xf3, 0x68,
|
|
0xe3, 0x06, 0x91, 0x34, 0xe0, 0x12,
|
|
0xc2, 0xb4, 0x30, 0x70, 0x83, 0xd3,
|
|
0xa9, 0xbd, 0xd2, 0x06, 0xe2, 0x4e,
|
|
0x5f, 0x0d, 0x86, 0xe1, 0x3d, 0x66,
|
|
0x36, 0x65, 0x59, 0x33, 0xec, 0x2b,
|
|
0x41, 0x34, 0x65, 0x96, 0x68, 0x17,
|
|
0xa9, 0xc2, 0x08, 0xa1, 0x17, 0x17,
|
|
}
|
|
var gotChecksum pkg.Checksum
|
|
wantPathnameG := base.Append(
|
|
"identifier",
|
|
base64.URLEncoding.EncodeToString(wantChecksum[:]),
|
|
)
|
|
if pathname, err := c.StoreFile(
|
|
wantChecksum,
|
|
[]byte{0},
|
|
&gotChecksum,
|
|
false,
|
|
); err != nil {
|
|
t.Fatalf("StoreFile: error = %#v", err)
|
|
} else if !pathname.Is(wantPathnameG) {
|
|
t.Fatalf("StoreFile: pathname = %q, want %q", pathname, wantPathnameG)
|
|
} else if gotChecksum != wantChecksum {
|
|
t.Fatalf("StoreFile: buf = %x, want %x", gotChecksum, wantChecksum)
|
|
}
|
|
|
|
// makeData passthrough
|
|
var zeroIdent pkg.ID
|
|
wantErrPassthrough := stub.UniqueError(0xcafe)
|
|
if _, _, _, err := c.LoadOrStoreFile(zeroIdent, func() ([]byte, error) {
|
|
return nil, wantErrPassthrough
|
|
}, new(pkg.Checksum), true); !reflect.DeepEqual(err, wantErrPassthrough) {
|
|
t.Fatalf("LoadOrStoreFile: error = %#v, want %#v", err, wantErrPassthrough)
|
|
}
|
|
|
|
// verify failed store
|
|
wantErrNonexistentZero := &os.PathError{
|
|
Op: "open",
|
|
Path: base.Append(
|
|
"identifier",
|
|
"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA",
|
|
).String(),
|
|
Err: syscall.ENOENT,
|
|
}
|
|
if _, _, err := c.LoadFile(zeroIdent); !reflect.DeepEqual(err, wantErrNonexistentZero) {
|
|
t.Fatalf("LoadFile: error = %#v, want %#v", err, wantErrNonexistentZero)
|
|
}
|
|
}, func(t *testing.T, base *check.Absolute) {
|
|
wantChecksum := pkg.MustDecode(
|
|
"lvK4lY9bQUFscHpxqHmiPvptjUwOgn3BFhzCXZMeupkY1n22WUPSuh7pswEvVZrx",
|
|
)
|
|
if checksum, err := pkg.HashDir(base); err != nil {
|
|
t.Fatalf("HashDir: error = %v", err)
|
|
} else if checksum != wantChecksum {
|
|
t.Fatalf("HashDir: %v", &pkg.ChecksumMismatchError{
|
|
Got: checksum,
|
|
Want: wantChecksum,
|
|
})
|
|
}
|
|
}},
|
|
}
|
|
for _, tc := range testCases {
|
|
t.Run(tc.name, func(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
base := check.MustAbs(t.TempDir())
|
|
if err := os.Chmod(base.String(), 0700); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
t.Cleanup(func() {
|
|
if err := filepath.WalkDir(base.String(), func(path string, d fs.DirEntry, err error) error {
|
|
if err != nil {
|
|
t.Error(err)
|
|
return nil
|
|
}
|
|
if !d.IsDir() {
|
|
return nil
|
|
}
|
|
return os.Chmod(path, 0700)
|
|
}); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
})
|
|
|
|
if c, err := pkg.New(base); err != nil {
|
|
t.Fatalf("New: error = %v", err)
|
|
} else {
|
|
if tc.early != nil {
|
|
tc.early(t, base)
|
|
}
|
|
tc.f(t, base, c)
|
|
tc.check(t, base)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestFlatten(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
testCases := []struct {
|
|
name string
|
|
fsys fs.FS
|
|
want pkg.Checksum
|
|
}{
|
|
{"sample cache file", fstest.MapFS{
|
|
".": {Mode: 020000000700},
|
|
|
|
"checksum": {Mode: 020000000700},
|
|
"checksum/vsAhtPNo4waRNOASwrQwcIPTqb3SBuJOXw2G4T1mNmVZM-wrQTRllmgXqcIIoRcX": {Mode: 0400, Data: []byte{0x0}},
|
|
"checksum/0bSFPu5Tnd-2Jj0Mv6co23PW2t3BmHc7eLFj9TgY3eIBg8zislo7xZYNBqovVLcq": {Mode: 0400, Data: []byte{0x0, 0x0, 0x0, 0x0, 0xad, 0xb, 0x0, 0x4, 0xfe, 0xfe, 0x0, 0x0, 0xfe, 0xca, 0x0, 0x0}},
|
|
|
|
"identifier": {Mode: 020000000700},
|
|
"identifier/vsAhtPNo4waRNOASwrQwcIPTqb3SBuJOXw2G4T1mNmVZM-wrQTRllmgXqcIIoRcX": {Mode: 0400, Data: []byte{0x0}},
|
|
"identifier/0bSFPu5Tnd-2Jj0Mv6co23PW2t3BmHc7eLFj9TgY3eIBg8zislo7xZYNBqovVLcq": {Mode: 0400, Data: []byte{0x0, 0x0, 0x0, 0x0, 0xad, 0xb, 0x0, 0x4, 0xfe, 0xfe, 0x0, 0x0, 0xfe, 0xca, 0x0, 0x0}},
|
|
"identifier/cafebabecafebabecafebabecafebabecafebabecafebabecafebabecafebabe": {Mode: 0400, Data: []byte{0x0, 0x0, 0x0, 0x0, 0xad, 0xb, 0x0, 0x4, 0xfe, 0xfe, 0x0, 0x0, 0xfe, 0xca, 0x0, 0x0}},
|
|
"identifier/deadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeef": {Mode: 0400, Data: []byte{0x0, 0x0, 0x0, 0x0, 0xad, 0xb, 0x0, 0x4, 0xfe, 0xfe, 0x0, 0x0, 0xfe, 0xca, 0x0, 0x0}},
|
|
}, pkg.MustDecode("lvK4lY9bQUFscHpxqHmiPvptjUwOgn3BFhzCXZMeupkY1n22WUPSuh7pswEvVZrx")},
|
|
}
|
|
for _, tc := range testCases {
|
|
t.Run(tc.name, func(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
if got, err := pkg.HashFS(tc.fsys, "."); err != nil {
|
|
t.Fatalf("HashFS: error = %v", err)
|
|
} else if got != tc.want {
|
|
t.Fatalf("HashFS: %v", &pkg.ChecksumMismatchError{
|
|
Got: got,
|
|
Want: tc.want,
|
|
})
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestErrors(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
testCases := []struct {
|
|
name string
|
|
err error
|
|
want string
|
|
}{
|
|
{"ChecksumMismatchError", &pkg.ChecksumMismatchError{
|
|
Want: (pkg.Checksum)(bytes.Repeat([]byte{
|
|
0x75, 0xe6, 0x9d, 0x6d, 0xe7, 0x9f,
|
|
}, 8)),
|
|
}, "got AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" +
|
|
" instead of deadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeef"},
|
|
}
|
|
for _, tc := range testCases {
|
|
t.Run(tc.name, func(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
if got := tc.err.Error(); got != tc.want {
|
|
t.Errorf("Error: %q, want %q", got, tc.want)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestNew(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
t.Run("nonexistent", func(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
wantErr := &os.PathError{
|
|
Op: "mkdir",
|
|
Path: container.Nonexistent,
|
|
Err: syscall.ENOENT,
|
|
}
|
|
if _, err := pkg.New(check.MustAbs(container.Nonexistent)); !reflect.DeepEqual(err, wantErr) {
|
|
t.Errorf("New: error = %#v, want %#v", err, wantErr)
|
|
}
|
|
})
|
|
|
|
t.Run("permission", func(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
tempDir := check.MustAbs(t.TempDir())
|
|
if err := os.Chmod(tempDir.String(), 0); err != nil {
|
|
t.Fatal(err)
|
|
} else {
|
|
t.Cleanup(func() {
|
|
if err = os.Chmod(tempDir.String(), 0700); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
})
|
|
}
|
|
|
|
wantErr := &os.PathError{
|
|
Op: "mkdir",
|
|
Path: tempDir.Append("cache").String(),
|
|
Err: syscall.EACCES,
|
|
}
|
|
if _, err := pkg.New(tempDir.Append("cache")); !reflect.DeepEqual(err, wantErr) {
|
|
t.Errorf("New: error = %#v, want %#v", err, wantErr)
|
|
}
|
|
})
|
|
}
|