internal/pkg: hold artifact in DCE
All checks were successful
Test / Create distribution (push) Successful in 1m3s
Test / Sandbox (push) Successful in 2m42s
Test / ShareFS (push) Successful in 3m43s
Test / Hakurei (push) Successful in 3m56s
Test / Sandbox (race detector) (push) Successful in 5m20s
Test / Hakurei (race detector) (push) Successful in 6m24s
Test / Flake checks (push) Successful in 1m21s
All checks were successful
Test / Create distribution (push) Successful in 1m3s
Test / Sandbox (push) Successful in 2m42s
Test / ShareFS (push) Successful in 3m43s
Test / Hakurei (push) Successful in 3m56s
Test / Sandbox (race detector) (push) Successful in 5m20s
Test / Hakurei (race detector) (push) Successful in 6m24s
Test / Flake checks (push) Successful in 1m21s
This is significantly slower but enables much better error reporting. Signed-off-by: Ophestra <cat@gensokyo.uk>
This commit is contained in:
@@ -11,7 +11,6 @@ import (
|
|||||||
"path/filepath"
|
"path/filepath"
|
||||||
"slices"
|
"slices"
|
||||||
"testing"
|
"testing"
|
||||||
"unique"
|
|
||||||
|
|
||||||
"hakurei.app/check"
|
"hakurei.app/check"
|
||||||
"hakurei.app/container"
|
"hakurei.app/container"
|
||||||
@@ -50,6 +49,13 @@ func TestExec(t *testing.T) {
|
|||||||
"check": {Mode: 0400, Data: []byte{0}},
|
"check": {Mode: 0400, Data: []byte{0}},
|
||||||
}
|
}
|
||||||
wantOfflineEncode := pkg.Encode(wantOffline.hash())
|
wantOfflineEncode := pkg.Encode(wantOffline.hash())
|
||||||
|
failingArtifact := &stubArtifact{
|
||||||
|
kind: pkg.KindTar,
|
||||||
|
params: []byte("doomed artifact"),
|
||||||
|
cure: func(t *pkg.TContext) error {
|
||||||
|
return stub.UniqueError(0xcafe)
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
checkWithCache(t, []cacheTestCase{
|
checkWithCache(t, []cacheTestCase{
|
||||||
{"offline", pkg.CValidateKnown | checkDestroySubstitutes, nil, func(t *testing.T, base *check.Absolute, c *pkg.Cache) {
|
{"offline", pkg.CValidateKnown | checkDestroySubstitutes, nil, func(t *testing.T, base *check.Absolute, c *pkg.Cache) {
|
||||||
@@ -86,18 +92,10 @@ func TestExec(t *testing.T) {
|
|||||||
check.MustAbs("/opt/bin/testtool"),
|
check.MustAbs("/opt/bin/testtool"),
|
||||||
[]string{"testtool"},
|
[]string{"testtool"},
|
||||||
|
|
||||||
pkg.MustPath("/proc/nonexistent", false, &stubArtifact{
|
pkg.MustPath("/proc/nonexistent", false, failingArtifact),
|
||||||
kind: pkg.KindTar,
|
|
||||||
params: []byte("doomed artifact"),
|
|
||||||
cure: func(t *pkg.TContext) error {
|
|
||||||
return stub.UniqueError(0xcafe)
|
|
||||||
},
|
|
||||||
}),
|
|
||||||
), nil, nil, &pkg.DependencyCureError{
|
), nil, nil, &pkg.DependencyCureError{
|
||||||
{
|
{
|
||||||
Ident: unique.Make(pkg.ID(pkg.MustDecode(
|
A: failingArtifact,
|
||||||
"Sowo6oZRmG6xVtUaxB6bDWZhVsqAJsIJWUp0OPKlE103cY0lodx7dem8J-qQF0Z1",
|
|
||||||
))),
|
|
||||||
Err: stub.UniqueError(0xcafe),
|
Err: stub.UniqueError(0xcafe),
|
||||||
},
|
},
|
||||||
}},
|
}},
|
||||||
|
|||||||
@@ -1485,8 +1485,8 @@ func (c *Cache) Cure(a Artifact) (
|
|||||||
|
|
||||||
// CureError wraps a non-nil error returned attempting to cure an [Artifact].
|
// CureError wraps a non-nil error returned attempting to cure an [Artifact].
|
||||||
type CureError struct {
|
type CureError struct {
|
||||||
Ident unique.Handle[ID]
|
A Artifact
|
||||||
Err error
|
Err error
|
||||||
}
|
}
|
||||||
|
|
||||||
// Unwrap returns the underlying error.
|
// Unwrap returns the underlying error.
|
||||||
@@ -1499,22 +1499,22 @@ func (e *CureError) Error() string { return e.Err.Error() }
|
|||||||
type DependencyCureError []*CureError
|
type DependencyCureError []*CureError
|
||||||
|
|
||||||
// unwrapM recursively expands underlying errors into a caller-supplied map.
|
// unwrapM recursively expands underlying errors into a caller-supplied map.
|
||||||
func (e *DependencyCureError) unwrapM(me map[unique.Handle[ID]]*CureError) {
|
func (e *DependencyCureError) unwrapM(me map[Artifact]*CureError) {
|
||||||
for _, err := range *e {
|
for _, err := range *e {
|
||||||
if _, ok := me[err.Ident]; ok {
|
if _, ok := me[err.A]; ok {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
if _e, ok := err.Err.(*DependencyCureError); ok {
|
if _e, ok := err.Err.(*DependencyCureError); ok {
|
||||||
_e.unwrapM(me)
|
_e.unwrapM(me)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
me[err.Ident] = err
|
me[err.A] = err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// unwrap recursively expands and deduplicates underlying errors.
|
// unwrap recursively expands and deduplicates underlying errors.
|
||||||
func (e *DependencyCureError) unwrap() DependencyCureError {
|
func (e *DependencyCureError) unwrap() DependencyCureError {
|
||||||
me := make(map[unique.Handle[ID]]*CureError)
|
me := make(map[Artifact]*CureError)
|
||||||
e.unwrapM(me)
|
e.unwrapM(me)
|
||||||
errs := slices.AppendSeq(
|
errs := slices.AppendSeq(
|
||||||
make(DependencyCureError, 0, len(me)),
|
make(DependencyCureError, 0, len(me)),
|
||||||
@@ -1522,8 +1522,9 @@ func (e *DependencyCureError) unwrap() DependencyCureError {
|
|||||||
)
|
)
|
||||||
|
|
||||||
var identBuf [2]ID
|
var identBuf [2]ID
|
||||||
|
ir := NewIR()
|
||||||
slices.SortFunc(errs, func(a, b *CureError) int {
|
slices.SortFunc(errs, func(a, b *CureError) int {
|
||||||
identBuf[0], identBuf[1] = a.Ident.Value(), b.Ident.Value()
|
identBuf[0], identBuf[1] = ir.Ident(a.A).Value(), ir.Ident(b.A).Value()
|
||||||
return slices.Compare(identBuf[0][:], identBuf[1][:])
|
return slices.Compare(identBuf[0][:], identBuf[1][:])
|
||||||
})
|
})
|
||||||
|
|
||||||
@@ -1548,8 +1549,11 @@ func (e *DependencyCureError) Error() string {
|
|||||||
}
|
}
|
||||||
var buf strings.Builder
|
var buf strings.Builder
|
||||||
buf.WriteString("errors curing dependencies:")
|
buf.WriteString("errors curing dependencies:")
|
||||||
|
ir := NewIR()
|
||||||
for _, err := range errs {
|
for _, err := range errs {
|
||||||
buf.WriteString("\n\t" + Encode(err.Ident.Value()) + ": " + err.Error())
|
buf.WriteString("\n\t" +
|
||||||
|
reportName(err.A, ir.Ident(err.A)) + ": " +
|
||||||
|
err.Error())
|
||||||
}
|
}
|
||||||
return buf.String()
|
return buf.String()
|
||||||
}
|
}
|
||||||
@@ -2082,7 +2086,7 @@ func (pending *pendingArtifactDep) cure(c *Cache) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pending.errsMu.Lock()
|
pending.errsMu.Lock()
|
||||||
*pending.errs = append(*pending.errs, &CureError{c.Ident(pending.a), err})
|
*pending.errs = append(*pending.errs, &CureError{pending.a, err})
|
||||||
pending.errsMu.Unlock()
|
pending.errsMu.Unlock()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -651,6 +651,15 @@ func TestCache(t *testing.T) {
|
|||||||
"identifier",
|
"identifier",
|
||||||
"cafebabecafebabecafebabecafebabecafebabecafebabecafebabecafebabe",
|
"cafebabecafebabecafebabecafebabecafebabecafebabecafebabecafebabe",
|
||||||
)
|
)
|
||||||
|
failingFile := newStubFile(
|
||||||
|
pkg.KindHTTPGet,
|
||||||
|
pkg.ID{0xff, 3},
|
||||||
|
nil,
|
||||||
|
nil, struct {
|
||||||
|
_ []byte
|
||||||
|
stub.UniqueError
|
||||||
|
}{UniqueError: 0xbad},
|
||||||
|
)
|
||||||
|
|
||||||
cureMany(t, c, []cureStep{
|
cureMany(t, c, []cureStep{
|
||||||
{"initial file", newStubFile(
|
{"initial file", newStubFile(
|
||||||
@@ -732,22 +741,14 @@ func TestCache(t *testing.T) {
|
|||||||
{"noncomparable error", &stubArtifactF{
|
{"noncomparable error", &stubArtifactF{
|
||||||
kind: pkg.KindExec,
|
kind: pkg.KindExec,
|
||||||
params: []byte("artifact with dependency returning noncomparable error"),
|
params: []byte("artifact with dependency returning noncomparable error"),
|
||||||
deps: []pkg.Artifact{newStubFile(
|
deps: []pkg.Artifact{failingFile},
|
||||||
pkg.KindHTTPGet,
|
|
||||||
pkg.ID{0xff, 3},
|
|
||||||
nil,
|
|
||||||
nil, struct {
|
|
||||||
_ []byte
|
|
||||||
stub.UniqueError
|
|
||||||
}{UniqueError: 0xbad},
|
|
||||||
)},
|
|
||||||
|
|
||||||
cure: func(f *pkg.FContext) error {
|
cure: func(f *pkg.FContext) error {
|
||||||
panic("attempting to cure impossible artifact")
|
panic("attempting to cure impossible artifact")
|
||||||
},
|
},
|
||||||
}, nil, nil, &pkg.DependencyCureError{
|
}, nil, nil, &pkg.DependencyCureError{
|
||||||
{
|
{
|
||||||
Ident: unique.Make(pkg.ID{0xff, 3}),
|
A: failingFile,
|
||||||
Err: struct {
|
Err: struct {
|
||||||
_ []byte
|
_ []byte
|
||||||
stub.UniqueError
|
stub.UniqueError
|
||||||
@@ -1511,6 +1512,12 @@ errors during scrub:
|
|||||||
func TestDependencyCureError(t *testing.T) {
|
func TestDependencyCureError(t *testing.T) {
|
||||||
t.Parallel()
|
t.Parallel()
|
||||||
|
|
||||||
|
makeIdent := func(ident ...byte) pkg.Artifact {
|
||||||
|
var a overrideIdent
|
||||||
|
copy(a.id[:], ident)
|
||||||
|
return a
|
||||||
|
}
|
||||||
|
|
||||||
testCases := []struct {
|
testCases := []struct {
|
||||||
name string
|
name string
|
||||||
err pkg.DependencyCureError
|
err pkg.DependencyCureError
|
||||||
@@ -1518,51 +1525,51 @@ func TestDependencyCureError(t *testing.T) {
|
|||||||
unwrap []error
|
unwrap []error
|
||||||
}{
|
}{
|
||||||
{"simple", pkg.DependencyCureError{
|
{"simple", pkg.DependencyCureError{
|
||||||
{Ident: unique.Make(pkg.ID{0xff, 9}), Err: stub.UniqueError(0xbad09)},
|
{A: makeIdent(0xff, 9), Err: stub.UniqueError(0xbad09)},
|
||||||
{Ident: unique.Make(pkg.ID{0xff, 0}), Err: stub.UniqueError(0xbad00)},
|
{A: makeIdent(0xff, 0), Err: stub.UniqueError(0xbad00)},
|
||||||
{Ident: unique.Make(pkg.ID{0xff, 0xf}), Err: stub.UniqueError(0xbad0f)},
|
{A: makeIdent(0xff, 0xf), Err: stub.UniqueError(0xbad0f)},
|
||||||
{Ident: unique.Make(pkg.ID{0xff, 1}), Err: stub.UniqueError(0xbad01)},
|
{A: makeIdent(0xff, 1), Err: stub.UniqueError(0xbad01)},
|
||||||
}, `errors curing dependencies:
|
}, `errors curing dependencies:
|
||||||
_wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA: unique error 765184 injected by the test suite
|
_wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA: unique error 765184 injected by the test suite
|
||||||
_wEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA: unique error 765185 injected by the test suite
|
_wEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA: unique error 765185 injected by the test suite
|
||||||
_wkAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA: unique error 765193 injected by the test suite
|
_wkAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA: unique error 765193 injected by the test suite
|
||||||
_w8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA: unique error 765199 injected by the test suite`, []error{
|
_w8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA: unique error 765199 injected by the test suite`, []error{
|
||||||
&pkg.CureError{Ident: unique.Make(pkg.ID{0xff, 0}), Err: stub.UniqueError(0xbad00)},
|
&pkg.CureError{A: makeIdent(0xff, 0), Err: stub.UniqueError(0xbad00)},
|
||||||
&pkg.CureError{Ident: unique.Make(pkg.ID{0xff, 1}), Err: stub.UniqueError(0xbad01)},
|
&pkg.CureError{A: makeIdent(0xff, 1), Err: stub.UniqueError(0xbad01)},
|
||||||
&pkg.CureError{Ident: unique.Make(pkg.ID{0xff, 9}), Err: stub.UniqueError(0xbad09)},
|
&pkg.CureError{A: makeIdent(0xff, 9), Err: stub.UniqueError(0xbad09)},
|
||||||
&pkg.CureError{Ident: unique.Make(pkg.ID{0xff, 0xf}), Err: stub.UniqueError(0xbad0f)},
|
&pkg.CureError{A: makeIdent(0xff, 0xf), Err: stub.UniqueError(0xbad0f)},
|
||||||
}},
|
}},
|
||||||
|
|
||||||
{"dedup", pkg.DependencyCureError{
|
{"dedup", pkg.DependencyCureError{
|
||||||
{Ident: unique.Make(pkg.ID{0xff, 9}), Err: stub.UniqueError(0xbad09)},
|
{A: makeIdent(0xff, 9), Err: stub.UniqueError(0xbad09)},
|
||||||
{Ident: unique.Make(pkg.ID{0xff, 0}), Err: stub.UniqueError(0xbad00)},
|
{A: makeIdent(0xff, 0), Err: stub.UniqueError(0xbad00)},
|
||||||
{Ident: unique.Make(pkg.ID{0xff, 0xfd}), Err: &pkg.DependencyCureError{
|
{A: makeIdent(0xff, 0xfd), Err: &pkg.DependencyCureError{
|
||||||
{Ident: unique.Make(pkg.ID{0xff, 9}), Err: stub.UniqueError(0xbad09)},
|
{A: makeIdent(0xff, 9), Err: stub.UniqueError(0xbad09)},
|
||||||
{Ident: unique.Make(pkg.ID{0xff, 0xc}), Err: &pkg.DependencyCureError{
|
{A: makeIdent(0xff, 0xc), Err: &pkg.DependencyCureError{
|
||||||
{Ident: unique.Make(pkg.ID{0xff, 0xf}), Err: stub.UniqueError(0xbad0f)},
|
{A: makeIdent(0xff, 0xf), Err: stub.UniqueError(0xbad0f)},
|
||||||
{Ident: unique.Make(pkg.ID{0xff, 0}), Err: stub.UniqueError(0xbad00)},
|
{A: makeIdent(0xff, 0), Err: stub.UniqueError(0xbad00)},
|
||||||
}},
|
}},
|
||||||
{Ident: unique.Make(pkg.ID{0xff, 0}), Err: stub.UniqueError(0xbad00)},
|
{A: makeIdent(0xff, 0), Err: stub.UniqueError(0xbad00)},
|
||||||
{Ident: unique.Make(pkg.ID{0xff, 0}), Err: stub.UniqueError(0xbad00)},
|
{A: makeIdent(0xff, 0), Err: stub.UniqueError(0xbad00)},
|
||||||
}},
|
}},
|
||||||
{Ident: unique.Make(pkg.ID{0xff, 0xff}), Err: &pkg.DependencyCureError{
|
{A: makeIdent(0xff, 0xff), Err: &pkg.DependencyCureError{
|
||||||
{Ident: unique.Make(pkg.ID{0xff, 9}), Err: stub.UniqueError(0xbad09)},
|
{A: makeIdent(0xff, 9), Err: stub.UniqueError(0xbad09)},
|
||||||
{Ident: unique.Make(pkg.ID{0xff, 0xc}), Err: &pkg.DependencyCureError{
|
{A: makeIdent(0xff, 0xc), Err: &pkg.DependencyCureError{
|
||||||
{Ident: unique.Make(pkg.ID{0xff, 0}), Err: stub.UniqueError(0xbad00)},
|
{A: makeIdent(0xff, 0), Err: stub.UniqueError(0xbad00)},
|
||||||
}},
|
}},
|
||||||
{Ident: unique.Make(pkg.ID{0xff, 0}), Err: stub.UniqueError(0xbad00)},
|
{A: makeIdent(0xff, 0), Err: stub.UniqueError(0xbad00)},
|
||||||
}},
|
}},
|
||||||
{Ident: unique.Make(pkg.ID{0xff, 0xf}), Err: stub.UniqueError(0xbad0f)},
|
{A: makeIdent(0xff, 0xf), Err: stub.UniqueError(0xbad0f)},
|
||||||
{Ident: unique.Make(pkg.ID{0xff, 1}), Err: stub.UniqueError(0xbad01)},
|
{A: makeIdent(0xff, 1), Err: stub.UniqueError(0xbad01)},
|
||||||
}, `errors curing dependencies:
|
}, `errors curing dependencies:
|
||||||
_wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA: unique error 765184 injected by the test suite
|
_wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA: unique error 765184 injected by the test suite
|
||||||
_wEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA: unique error 765185 injected by the test suite
|
_wEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA: unique error 765185 injected by the test suite
|
||||||
_wkAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA: unique error 765193 injected by the test suite
|
_wkAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA: unique error 765193 injected by the test suite
|
||||||
_w8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA: unique error 765199 injected by the test suite`, []error{
|
_w8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA: unique error 765199 injected by the test suite`, []error{
|
||||||
&pkg.CureError{Ident: unique.Make(pkg.ID{0xff, 0}), Err: stub.UniqueError(0xbad00)},
|
&pkg.CureError{A: makeIdent(0xff, 0), Err: stub.UniqueError(0xbad00)},
|
||||||
&pkg.CureError{Ident: unique.Make(pkg.ID{0xff, 1}), Err: stub.UniqueError(0xbad01)},
|
&pkg.CureError{A: makeIdent(0xff, 1), Err: stub.UniqueError(0xbad01)},
|
||||||
&pkg.CureError{Ident: unique.Make(pkg.ID{0xff, 9}), Err: stub.UniqueError(0xbad09)},
|
&pkg.CureError{A: makeIdent(0xff, 9), Err: stub.UniqueError(0xbad09)},
|
||||||
&pkg.CureError{Ident: unique.Make(pkg.ID{0xff, 0xf}), Err: stub.UniqueError(0xbad0f)},
|
&pkg.CureError{A: makeIdent(0xff, 0xf), Err: stub.UniqueError(0xbad0f)},
|
||||||
}},
|
}},
|
||||||
}
|
}
|
||||||
for _, tc := range testCases {
|
for _, tc := range testCases {
|
||||||
|
|||||||
Reference in New Issue
Block a user