internal/pkg: record cache variant on-disk
All checks were successful
Test / Create distribution (push) Successful in 1m4s
Test / Sandbox (push) Successful in 2m47s
Test / ShareFS (push) Successful in 3m51s
Test / Sandbox (race detector) (push) Successful in 5m16s
Test / Hakurei (race detector) (push) Successful in 6m23s
Test / Hakurei (push) Successful in 2m39s
Test / Flake checks (push) Successful in 1m25s
All checks were successful
Test / Create distribution (push) Successful in 1m4s
Test / Sandbox (push) Successful in 2m47s
Test / ShareFS (push) Successful in 3m51s
Test / Sandbox (race detector) (push) Successful in 5m16s
Test / Hakurei (race detector) (push) Successful in 6m23s
Test / Hakurei (push) Successful in 2m39s
Test / Flake checks (push) Successful in 1m25s
This makes custom artifacts much less error-prone to use. Signed-off-by: Ophestra <cat@gensokyo.uk>
This commit is contained in:
@@ -41,6 +41,25 @@ func unsafeOpen(
|
||||
lock bool,
|
||||
) (*pkg.Cache, error)
|
||||
|
||||
var (
|
||||
// extension is a string uniquely identifying a set of custom [Artifact]
|
||||
// implementations registered by calling [Register].
|
||||
//
|
||||
//go:linkname extension hakurei.app/internal/pkg.extension
|
||||
extension string
|
||||
|
||||
// opened is false if [Open] was never called.
|
||||
//
|
||||
//go:linkname opened hakurei.app/internal/pkg.opened
|
||||
opened bool
|
||||
|
||||
// irArtifact refers to artifact IR interpretation functions and must not be
|
||||
// written to directly.
|
||||
//
|
||||
//go:linkname irArtifact hakurei.app/internal/pkg.irArtifact
|
||||
irArtifact map[pkg.Kind]pkg.IRReadFunc
|
||||
)
|
||||
|
||||
// newRContext returns the address of a new [pkg.RContext] unsafely created for
|
||||
// the specified [testing.TB].
|
||||
func newRContext(tb testing.TB, c *pkg.Cache) *pkg.RContext {
|
||||
@@ -342,9 +361,20 @@ func checkWithCache(t *testing.T, testCases []cacheTestCase) {
|
||||
restoreTemp = true
|
||||
}
|
||||
|
||||
// destroy lock file to avoid changing cache checksums
|
||||
if err := os.Remove(base.Append("lock").String()); err != nil {
|
||||
t.Fatal(err)
|
||||
// destroy lock and variant file to avoid changing cache checksums
|
||||
for _, s := range []string{
|
||||
"lock",
|
||||
"variant",
|
||||
} {
|
||||
pathname := base.Append(s)
|
||||
if p, err := os.ReadFile(pathname.String()); err != nil {
|
||||
t.Fatal(err)
|
||||
} else if len(p) != 0 {
|
||||
t.Fatalf("file %q: %q", s, string(p))
|
||||
}
|
||||
if err := os.Remove(pathname.String()); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
// destroy non-deterministic status files
|
||||
@@ -1101,6 +1131,10 @@ func TestErrors(t *testing.T) {
|
||||
Want: pkg.IRKindIdent,
|
||||
Ancillary: 0xcafe,
|
||||
}, "got invalid kind 48879 IR value (0xcafe) instead of ident"},
|
||||
|
||||
{"UnsupportedVariantError", pkg.UnsupportedVariantError(
|
||||
"rosa",
|
||||
), `unsupported variant "rosa"`},
|
||||
}
|
||||
for _, tc := range testCases {
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
@@ -1309,6 +1343,8 @@ func (a earlyFailureF) Cure(*pkg.FContext) error {
|
||||
}
|
||||
|
||||
func TestDependencyCureErrorEarly(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
checkWithCache(t, []cacheTestCase{
|
||||
{"early", 0, nil, func(t *testing.T, _ *check.Absolute, c *pkg.Cache) {
|
||||
_, _, err := c.Cure(earlyFailureF(8))
|
||||
@@ -1319,7 +1355,7 @@ func TestDependencyCureErrorEarly(t *testing.T) {
|
||||
})
|
||||
}
|
||||
|
||||
func TestNew(t *testing.T) {
|
||||
func TestOpen(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
t.Run("nonexistent", func(t *testing.T) {
|
||||
@@ -1367,3 +1403,219 @@ func TestNew(t *testing.T) {
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
func TestExtensionRegister(t *testing.T) {
|
||||
extensionOld := extension
|
||||
openedOld := opened
|
||||
t.Cleanup(func() { extension = extensionOld; opened = openedOld })
|
||||
extension = ""
|
||||
opened = false
|
||||
|
||||
t.Run("set", func(t *testing.T) {
|
||||
t.Cleanup(func() { extension = "" })
|
||||
|
||||
const want = "rosa"
|
||||
pkg.SetExtension(want)
|
||||
if got := pkg.Extension(); got != want {
|
||||
t.Fatalf("Extension: %q, want %q", got, want)
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("twice", func(t *testing.T) {
|
||||
t.Cleanup(func() { extension = "" })
|
||||
|
||||
defer func() {
|
||||
const wantPanic = "attempting to set extension twice"
|
||||
if r := recover(); r != wantPanic {
|
||||
t.Errorf("panic: %#v, want %q", r, wantPanic)
|
||||
}
|
||||
}()
|
||||
pkg.SetExtension("rosa")
|
||||
pkg.SetExtension("rosa")
|
||||
})
|
||||
|
||||
t.Run("invalid", func(t *testing.T) {
|
||||
defer func() {
|
||||
var wantPanic = pkg.ErrInvalidExtension
|
||||
if r := recover(); r != wantPanic {
|
||||
t.Errorf("panic: %#v, want %#v", r, wantPanic)
|
||||
}
|
||||
}()
|
||||
pkg.SetExtension(" ")
|
||||
})
|
||||
|
||||
t.Run("opened", func(t *testing.T) {
|
||||
t.Cleanup(func() { opened = false })
|
||||
|
||||
if _, err := pkg.Open(
|
||||
t.Context(),
|
||||
message.New(log.Default()),
|
||||
0, 0, 0,
|
||||
check.MustAbs(container.Nonexistent),
|
||||
); !errors.Is(err, os.ErrNotExist) {
|
||||
t.Fatalf("Open: error = %v", err)
|
||||
}
|
||||
|
||||
t.Run("variant", func(t *testing.T) {
|
||||
defer func() {
|
||||
const wantPanic = "attempting to set extension after open"
|
||||
if r := recover(); r != wantPanic {
|
||||
t.Errorf("panic: %#v, want %q", r, wantPanic)
|
||||
}
|
||||
}()
|
||||
pkg.SetExtension("rosa")
|
||||
})
|
||||
|
||||
t.Run("register", func(t *testing.T) {
|
||||
defer func() {
|
||||
const wantPanic = "attempting to register after open"
|
||||
if r := recover(); r != wantPanic {
|
||||
t.Errorf("panic: %#v, want %q", r, wantPanic)
|
||||
}
|
||||
}()
|
||||
pkg.Register(pkg.KindCustomOffset, nil)
|
||||
})
|
||||
})
|
||||
|
||||
t.Run("incomplete", func(t *testing.T) {
|
||||
t.Cleanup(func() { delete(irArtifact, pkg.KindCustomOffset) })
|
||||
|
||||
defer func() {
|
||||
const wantPanic = "attempting to open cache with incomplete variant setup"
|
||||
if r := recover(); r != wantPanic {
|
||||
t.Errorf("panic: %#v, want %q", r, wantPanic)
|
||||
}
|
||||
}()
|
||||
pkg.Register(pkg.KindCustomOffset, nil)
|
||||
|
||||
t.Cleanup(func() { opened = false })
|
||||
_, _ = pkg.Open(nil, nil, 0, 0, 0, nil)
|
||||
panic("unreachable")
|
||||
})
|
||||
|
||||
t.Run("create", func(t *testing.T) {
|
||||
t.Cleanup(func() { extension = "" })
|
||||
const want = "rosa"
|
||||
pkg.SetExtension(want)
|
||||
|
||||
base := check.MustAbs(t.TempDir())
|
||||
t.Cleanup(func() { opened = false })
|
||||
if c, err := pkg.Open(
|
||||
t.Context(), nil,
|
||||
0, 0, 0,
|
||||
base,
|
||||
); err != nil {
|
||||
t.Fatal(err)
|
||||
} else {
|
||||
c.Close()
|
||||
}
|
||||
|
||||
if got, err := os.ReadFile(base.Append("variant").String()); err != nil {
|
||||
t.Fatal(err)
|
||||
} else if string(got) != want {
|
||||
t.Fatalf("variant: %q", string(got))
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("access", func(t *testing.T) {
|
||||
base := check.MustAbs(t.TempDir())
|
||||
t.Cleanup(func() { opened = false })
|
||||
|
||||
if err := os.WriteFile(base.Append("variant").String(), nil, 0); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
wantErr := &os.PathError{
|
||||
Op: "open",
|
||||
Path: base.Append("variant").String(),
|
||||
Err: syscall.EACCES,
|
||||
}
|
||||
if _, err := pkg.Open(
|
||||
t.Context(), nil,
|
||||
0, 0, 0,
|
||||
base,
|
||||
); !reflect.DeepEqual(err, wantErr) {
|
||||
t.Fatalf("Open: error = %v, want %v", err, wantErr)
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("promote", func(t *testing.T) {
|
||||
t.Cleanup(func() { extension = "" })
|
||||
const want = "rosa"
|
||||
pkg.SetExtension(want)
|
||||
|
||||
base := check.MustAbs(t.TempDir())
|
||||
t.Cleanup(func() { opened = false })
|
||||
|
||||
variantPath := base.Append("variant")
|
||||
if err := os.WriteFile(variantPath.String(), nil, 0600); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if _, err := pkg.Open(
|
||||
t.Context(), nil,
|
||||
0, 0, 0,
|
||||
base,
|
||||
); !reflect.DeepEqual(err, pkg.ErrWouldPromote) {
|
||||
t.Fatalf("Open: error = %v", err)
|
||||
}
|
||||
|
||||
if p, err := os.ReadFile(variantPath.String()); err != nil {
|
||||
t.Fatal(err)
|
||||
} else if len(p) != 0 {
|
||||
t.Fatalf("variant: %q", string(p))
|
||||
}
|
||||
|
||||
if c, err := pkg.Open(
|
||||
t.Context(), nil,
|
||||
pkg.CPromoteVariant, 0, 0,
|
||||
base,
|
||||
); err != nil {
|
||||
t.Fatalf("Open: error = %v", err)
|
||||
} else {
|
||||
c.Close()
|
||||
}
|
||||
|
||||
if p, err := os.ReadFile(variantPath.String()); err != nil {
|
||||
t.Fatal(err)
|
||||
} else if string(p) != want {
|
||||
t.Fatalf("variant: %q, want %q", string(p), want)
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("open invalid", func(t *testing.T) {
|
||||
base := check.MustAbs(t.TempDir())
|
||||
t.Cleanup(func() { opened = false })
|
||||
|
||||
variantPath := base.Append("variant")
|
||||
if err := os.WriteFile(variantPath.String(), make([]byte, 129), 0400); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if _, err := pkg.Open(
|
||||
t.Context(), nil,
|
||||
0, 0, 0,
|
||||
base,
|
||||
); !reflect.DeepEqual(err, pkg.ErrInvalidExtension) {
|
||||
t.Fatalf("Open: error = %v", err)
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("unsupported", func(t *testing.T) {
|
||||
base := check.MustAbs(t.TempDir())
|
||||
t.Cleanup(func() { opened = false })
|
||||
|
||||
variantPath := base.Append("variant")
|
||||
if err := os.WriteFile(variantPath.String(), []byte("rosa"), 0400); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if _, err := pkg.Open(
|
||||
t.Context(), nil,
|
||||
0, 0, 0,
|
||||
base,
|
||||
); !reflect.DeepEqual(err, pkg.UnsupportedVariantError("rosa")) {
|
||||
t.Fatalf("Open: error = %v", err)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user