Files
hakurei/internal/pkg/pkg_test.go
Ophestra 3eb927823f
All checks were successful
Test / Create distribution (push) Successful in 42s
Test / Sandbox (push) Successful in 2m45s
Test / Hakurei (push) Successful in 3m36s
Test / ShareFS (push) Successful in 3m42s
Test / Hpkg (push) Successful in 4m17s
Test / Sandbox (race detector) (push) Successful in 4m49s
Test / Hakurei (race detector) (push) Successful in 5m48s
Test / Flake checks (push) Successful in 1m44s
internal/pkg: create symlinks for files
These are much easier to handle than hard links and should be just as transparent for this use case.

Signed-off-by: Ophestra <cat@gensokyo.uk>
2026-01-04 01:48:53 +09:00

539 lines
14 KiB
Go

package pkg_test
import (
"archive/tar"
"bytes"
"crypto/sha512"
"encoding/binary"
"io/fs"
"net/http"
"os"
"path/filepath"
"reflect"
"syscall"
"testing"
"hakurei.app/container"
"hakurei.app/container/check"
"hakurei.app/container/stub"
"hakurei.app/internal/pkg"
)
// A stubArtifact implements [Artifact] with hardcoded kind and identifier.
type stubArtifact struct {
kind pkg.Kind
id pkg.ID
}
func (a stubArtifact) Kind() pkg.Kind { return a.kind }
func (a stubArtifact) ID() pkg.ID { return a.id }
func (a stubArtifact) Hash() (pkg.Checksum, error) { panic("unreachable") }
func (a stubArtifact) Pathname() (*check.Absolute, error) { panic("unreachable") }
func TestIdent(t *testing.T) {
t.Parallel()
testCases := []struct {
name string
kind pkg.Kind
params []byte
deps []pkg.Artifact
want pkg.ID
}{
{"tar", pkg.KindTar, []byte{
pkg.TarGzip, 0, 0, 0, 0, 0, 0, 0,
}, []pkg.Artifact{
stubArtifact{pkg.KindHTTP, pkg.ID{}},
}, pkg.MustDecode("HnySzeLQvSBZuTUcvfmLEX_OmH4yJWWH788NxuLuv7kVn8_uPM6Ks4rqFWM2NZJY")},
}
for _, tc := range testCases {
t.Run(tc.name, func(t *testing.T) {
t.Parallel()
if got := tc.kind.Ident(tc.params, tc.deps...); got != tc.want {
t.Errorf("Ident: %s, want %s",
pkg.Encode(got),
pkg.Encode(tc.want))
}
})
}
}
// cacheTestCase is a test case passed to checkWithCache where a new instance
// of [pkg.Cache] is prepared for the test case, and is validated and removed
// on test completion.
type cacheTestCase struct {
name string
early func(t *testing.T, base *check.Absolute)
f func(t *testing.T, base *check.Absolute, c *pkg.Cache)
want pkg.Checksum
}
// checkWithCache runs a slice of cacheTestCase.
func checkWithCache(t *testing.T, testCases []cacheTestCase) {
t.Helper()
for _, tc := range testCases {
t.Run(tc.name, func(t *testing.T) {
t.Helper()
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)
}
if checksum, err := pkg.HashDir(base); err != nil {
t.Fatalf("HashDir: error = %v", err)
} else if checksum != tc.want {
t.Fatalf("HashDir: %v", &pkg.ChecksumMismatchError{
Got: checksum,
Want: tc.want,
})
}
})
}
}
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 := pkg.Encode(testdataChecksum)
testCases := []cacheTestCase{
{"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",
pkg.Encode(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)
}
}, pkg.MustDecode("St9rlE-mGZ5gXwiv_hzQ_B8bZP-UUvSNmf4nHUZzCMOumb6hKnheZSe0dmnuc4Q2")},
{"directory", nil, func(t *testing.T, base *check.Absolute, c *pkg.Cache) {
id := pkg.KindTar.Ident(
binary.LittleEndian.AppendUint64(nil, pkg.TarGzip),
stubArtifact{pkg.KindHTTP, testdataChecksum},
)
makeSample := func(work *check.Absolute) error {
if err := os.WriteFile(
work.Append("check").String(),
[]byte{0, 0},
0400,
); err != nil {
return err
}
if err := os.MkdirAll(work.Append(
"lib",
"pkgconfig",
).String(), 0700); err != nil {
return err
}
return os.Symlink(
"/proc/nonexistent/libedac.so",
work.Append(
"lib",
"libedac.so",
).String(),
)
}
wantChecksum := pkg.MustDecode(
"1TL00Qb8dcqayX7wTO8WNaraHvY6b-KCsctLDTrb64QBCmxj_-byK1HdIUwMaFEP",
)
wantPathname := base.Append(
"identifier",
pkg.Encode(id),
)
if pathname, store, err := c.Store(
id,
makeSample,
&wantChecksum,
true,
); err != nil {
t.Fatalf("Store: error = %v", err)
} else if !store {
t.Fatal("Store did not store nonpresent entry")
} else if !pathname.Is(wantPathname) {
t.Fatalf("Store: pathname = %q, want %q", pathname, wantPathname)
}
// check lookup
if pathname, store, err := c.Store(
id,
nil,
&wantChecksum,
true,
); err != nil {
t.Fatalf("Store: error = %v", err)
} else if store {
t.Fatal("Store stored over present entry")
} else if !pathname.Is(wantPathname) {
t.Fatalf("Store: pathname = %q, want %q", pathname, wantPathname)
}
// check exist
id0 := pkg.KindTar.Ident(
binary.LittleEndian.AppendUint64(nil, pkg.TarGzip),
stubArtifact{pkg.KindHTTP, pkg.ID{}},
)
wantPathname0 := base.Append(
"identifier",
pkg.Encode(id0),
)
if pathname, store, err := c.Store(
id0,
makeSample,
&wantChecksum,
true,
); err != nil {
t.Fatalf("Store: error = %v", err)
} else if !store {
t.Fatal("Store did not store nonpresent entry")
} else if !pathname.Is(wantPathname0) {
t.Fatalf("Store: pathname = %q, want %q", pathname, wantPathname0)
}
var wantErrMakeGarbage error
makeGarbage := func(work *check.Absolute) error {
mode := fs.FileMode(0)
if wantErrMakeGarbage == nil {
mode = 0500
}
if err := os.MkdirAll(work.Append(
"lib",
"pkgconfig",
).String(), 0700); err != nil {
return err
}
if err := os.WriteFile(work.Append(
"lib",
"check",
).String(), nil, 0400&mode); err != nil {
return err
}
if err := os.Chmod(work.Append(
"lib",
"pkgconfig",
).String(), 0500&mode); err != nil {
return err
}
if err := os.Chmod(work.Append(
"lib",
).String(), 0500&mode); err != nil {
return err
}
return wantErrMakeGarbage
}
// check makeArtifact fault
wantErrMakeGarbage = stub.UniqueError(0xcafe)
if _, store, err := c.Store(
pkg.ID{},
makeGarbage,
nil,
false,
); !reflect.DeepEqual(err, wantErrMakeGarbage) {
t.Fatalf("Store: error = %#v, want %#v", err, wantErrMakeGarbage)
} else if !store {
t.Fatal("Store did not store nonpresent entry")
}
// checksum mismatch
wantErrMakeGarbage = nil
wantErrMismatch := &pkg.ChecksumMismatchError{
Got: pkg.MustDecode("GbjlYMcHQANdfwL6qNGopBF99IscPTvCy95HSH1_kIF3eKjFDSLP0_iUUT0z8hiw"),
}
if _, store, err := c.Store(
pkg.ID{},
makeGarbage,
new(pkg.Checksum),
true,
); !reflect.DeepEqual(err, wantErrMismatch) {
t.Fatalf("Store: error = %v, want %v", err, wantErrMismatch)
} else if !store {
t.Fatal("Store did not store nonpresent entry")
}
}, pkg.MustDecode("8OP6YxJAdRrhV2WSBt1BPD7oC_n2Qh7JqUMyVMoGvjDX83bDqq2hgVMNcdiBH_64")},
}
checkWithCache(t, testCases)
}
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"},
{"ResponseStatusError", pkg.ResponseStatusError(
http.StatusNotAcceptable,
), "the requested URL returned non-OK status: Not Acceptable"},
{"DisallowedTypeflagError", pkg.DisallowedTypeflagError(
tar.TypeChar,
), "disallowed typeflag '3'"},
}
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)
}
})
}