All checks were successful
Test / Create distribution (push) Successful in 1m0s
Test / Sandbox (push) Successful in 2m41s
Test / Hakurei (push) Successful in 4m1s
Test / ShareFS (push) Successful in 4m1s
Test / Hpkg (push) Successful in 4m35s
Test / Sandbox (race detector) (push) Successful in 5m4s
Test / Hakurei (race detector) (push) Successful in 6m0s
Test / Flake checks (push) Successful in 1m46s
This should hopefully provide good separation between the artifact curing backend implementation and the (still work in progress) language. Making the IR parseable also guarantees uniqueness of the representation. Signed-off-by: Ophestra <cat@gensokyo.uk>
340 lines
9.6 KiB
Go
340 lines
9.6 KiB
Go
package pkg_test
|
|
|
|
//go:generate env CGO_ENABLED=0 go build -tags testtool -o testdata/testtool ./testdata
|
|
|
|
import (
|
|
_ "embed"
|
|
"encoding/gob"
|
|
"errors"
|
|
"net"
|
|
"os"
|
|
"os/exec"
|
|
"slices"
|
|
"testing"
|
|
"unique"
|
|
|
|
"hakurei.app/container/check"
|
|
"hakurei.app/container/stub"
|
|
"hakurei.app/hst"
|
|
"hakurei.app/internal/pkg"
|
|
)
|
|
|
|
// testtoolBin is the container test tool binary made available to the
|
|
// execArtifact for testing its curing environment.
|
|
//
|
|
//go:embed testdata/testtool
|
|
var testtoolBin []byte
|
|
|
|
func TestExec(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
wantChecksumOffline := pkg.MustDecode(
|
|
"GPa4aBakdSJd7Tz7LYj_VJFoojzyZinmVcG3k6M5xI6CZ821J5sXLhLDDuS47gi9",
|
|
)
|
|
|
|
checkWithCache(t, []cacheTestCase{
|
|
{"offline", nil, func(t *testing.T, base *check.Absolute, c *pkg.Cache) {
|
|
c.SetStrict(true)
|
|
testtool, testtoolDestroy := newTesttool()
|
|
|
|
cureMany(t, c, []cureStep{
|
|
{"container", pkg.NewExec(
|
|
"exec-offline", nil, 0, false,
|
|
pkg.AbsWork,
|
|
[]string{"HAKUREI_TEST=1"},
|
|
check.MustAbs("/opt/bin/testtool"),
|
|
[]string{"testtool"},
|
|
|
|
pkg.MustPath("/file", false, newStubFile(
|
|
pkg.KindHTTPGet,
|
|
pkg.ID{0xfe, 0},
|
|
nil,
|
|
nil, nil,
|
|
)),
|
|
pkg.MustPath("/.hakurei", false, &stubArtifact{
|
|
kind: pkg.KindTar,
|
|
params: []byte("empty directory"),
|
|
cure: func(t *pkg.TContext) error {
|
|
return os.MkdirAll(t.GetWorkDir().String(), 0700)
|
|
},
|
|
}),
|
|
pkg.MustPath("/opt", false, testtool),
|
|
), ignorePathname, wantChecksumOffline, nil},
|
|
|
|
{"error passthrough", pkg.NewExec(
|
|
"", nil, 0, true,
|
|
pkg.AbsWork,
|
|
[]string{"HAKUREI_TEST=1"},
|
|
check.MustAbs("/opt/bin/testtool"),
|
|
[]string{"testtool"},
|
|
|
|
pkg.MustPath("/proc/nonexistent", false, &stubArtifact{
|
|
kind: pkg.KindTar,
|
|
params: []byte("doomed artifact"),
|
|
cure: func(t *pkg.TContext) error {
|
|
return stub.UniqueError(0xcafe)
|
|
},
|
|
}),
|
|
), nil, pkg.Checksum{}, &pkg.DependencyCureError{
|
|
{
|
|
Ident: unique.Make(pkg.ID(pkg.MustDecode(
|
|
"Sowo6oZRmG6xVtUaxB6bDWZhVsqAJsIJWUp0OPKlE103cY0lodx7dem8J-qQF0Z1",
|
|
))),
|
|
Err: stub.UniqueError(0xcafe),
|
|
},
|
|
}},
|
|
|
|
{"invalid paths", pkg.NewExec(
|
|
"", nil, 0, false,
|
|
pkg.AbsWork,
|
|
[]string{"HAKUREI_TEST=1"},
|
|
check.MustAbs("/opt/bin/testtool"),
|
|
[]string{"testtool"},
|
|
|
|
pkg.ExecPath{},
|
|
), nil, pkg.Checksum{}, os.ErrInvalid},
|
|
})
|
|
|
|
// check init failure passthrough
|
|
var exitError *exec.ExitError
|
|
if _, _, err := c.Cure(pkg.NewExec(
|
|
"", nil, 0, false,
|
|
pkg.AbsWork,
|
|
nil,
|
|
check.MustAbs("/opt/bin/testtool"),
|
|
[]string{"testtool"},
|
|
)); !errors.As(err, &exitError) ||
|
|
exitError.ExitCode() != hst.ExitFailure {
|
|
t.Fatalf("Cure: error = %v, want init exit status 1", err)
|
|
}
|
|
|
|
testtoolDestroy(t, base, c)
|
|
}, pkg.MustDecode("Q5DluWQCAeohLoiGRImurwFp3vdz9IfQCoj7Fuhh73s4KQPRHpEQEnHTdNHmB8Fx")},
|
|
|
|
{"net", nil, func(t *testing.T, base *check.Absolute, c *pkg.Cache) {
|
|
c.SetStrict(true)
|
|
testtool, testtoolDestroy := newTesttool()
|
|
|
|
wantChecksum := pkg.MustDecode(
|
|
"a1F_i9PVQI4qMcoHgTQkORuyWLkC1GLIxOhDt2JpU1NGAxWc5VJzdlfRK-PYBh3W",
|
|
)
|
|
cureMany(t, c, []cureStep{
|
|
{"container", pkg.NewExec(
|
|
"exec-net", &wantChecksum, 0, false,
|
|
pkg.AbsWork,
|
|
[]string{"HAKUREI_TEST=1"},
|
|
check.MustAbs("/opt/bin/testtool"),
|
|
[]string{"testtool", "net"},
|
|
|
|
pkg.MustPath("/file", false, newStubFile(
|
|
pkg.KindHTTPGet,
|
|
pkg.ID{0xfe, 0},
|
|
nil,
|
|
nil, nil,
|
|
)),
|
|
pkg.MustPath("/.hakurei", false, &stubArtifact{
|
|
kind: pkg.KindTar,
|
|
params: []byte("empty directory"),
|
|
cure: func(t *pkg.TContext) error {
|
|
return os.MkdirAll(t.GetWorkDir().String(), 0700)
|
|
},
|
|
}),
|
|
pkg.MustPath("/opt", false, testtool),
|
|
), ignorePathname, wantChecksum, nil},
|
|
})
|
|
|
|
testtoolDestroy(t, base, c)
|
|
}, pkg.MustDecode("bPYvvqxpfV7xcC1EptqyKNK1klLJgYHMDkzBcoOyK6j_Aj5hb0mXNPwTwPSK5F6Z")},
|
|
|
|
{"overlay root", nil, func(t *testing.T, base *check.Absolute, c *pkg.Cache) {
|
|
c.SetStrict(true)
|
|
testtool, testtoolDestroy := newTesttool()
|
|
|
|
cureMany(t, c, []cureStep{
|
|
{"container", pkg.NewExec(
|
|
"exec-overlay-root", nil, 0, false,
|
|
pkg.AbsWork,
|
|
[]string{"HAKUREI_TEST=1", "HAKUREI_ROOT=1"},
|
|
check.MustAbs("/opt/bin/testtool"),
|
|
[]string{"testtool"},
|
|
|
|
pkg.MustPath("/", true, &stubArtifact{
|
|
kind: pkg.KindTar,
|
|
params: []byte("empty directory"),
|
|
cure: func(t *pkg.TContext) error {
|
|
return os.MkdirAll(t.GetWorkDir().String(), 0700)
|
|
},
|
|
}),
|
|
pkg.MustPath("/opt", false, testtool),
|
|
), ignorePathname, wantChecksumOffline, nil},
|
|
})
|
|
|
|
testtoolDestroy(t, base, c)
|
|
}, pkg.MustDecode("PO2DSSCa4yoSgEYRcCSZfQfwow1yRigL3Ry-hI0RDI4aGuFBha-EfXeSJnG_5_Rl")},
|
|
|
|
{"overlay work", nil, func(t *testing.T, base *check.Absolute, c *pkg.Cache) {
|
|
c.SetStrict(true)
|
|
testtool, testtoolDestroy := newTesttool()
|
|
|
|
cureMany(t, c, []cureStep{
|
|
{"container", pkg.NewExec(
|
|
"exec-overlay-work", nil, 0, false,
|
|
pkg.AbsWork,
|
|
[]string{"HAKUREI_TEST=1", "HAKUREI_ROOT=1"},
|
|
check.MustAbs("/work/bin/testtool"),
|
|
[]string{"testtool"},
|
|
|
|
pkg.MustPath("/", true, &stubArtifact{
|
|
kind: pkg.KindTar,
|
|
params: []byte("empty directory"),
|
|
cure: func(t *pkg.TContext) error {
|
|
return os.MkdirAll(t.GetWorkDir().String(), 0700)
|
|
},
|
|
}), pkg.MustPath("/work/", false, &stubArtifact{
|
|
kind: pkg.KindTar,
|
|
params: []byte("empty directory"),
|
|
cure: func(t *pkg.TContext) error {
|
|
return os.MkdirAll(t.GetWorkDir().String(), 0700)
|
|
},
|
|
}), pkg.Path(pkg.AbsWork, false /* ignored */, testtool),
|
|
), ignorePathname, wantChecksumOffline, nil},
|
|
})
|
|
|
|
testtoolDestroy(t, base, c)
|
|
}, pkg.MustDecode("iaRt6l_Wm2n-h5UsDewZxQkCmjZjyL8r7wv32QT2kyV55-Lx09Dq4gfg9BiwPnKs")},
|
|
|
|
{"multiple layers", nil, func(t *testing.T, base *check.Absolute, c *pkg.Cache) {
|
|
c.SetStrict(true)
|
|
testtool, testtoolDestroy := newTesttool()
|
|
|
|
cureMany(t, c, []cureStep{
|
|
{"container", pkg.NewExec(
|
|
"exec-multiple-layers", nil, 0, false,
|
|
pkg.AbsWork,
|
|
[]string{"HAKUREI_TEST=1", "HAKUREI_ROOT=1"},
|
|
check.MustAbs("/opt/bin/testtool"),
|
|
[]string{"testtool", "layers"},
|
|
|
|
pkg.MustPath("/", true, &stubArtifact{
|
|
kind: pkg.KindTar,
|
|
params: []byte("empty directory"),
|
|
cure: func(t *pkg.TContext) error {
|
|
return os.MkdirAll(t.GetWorkDir().String(), 0700)
|
|
},
|
|
}, &stubArtifactF{
|
|
kind: pkg.KindExec,
|
|
params: []byte("test sample with dependencies"),
|
|
|
|
deps: slices.Repeat([]pkg.Artifact{newStubFile(
|
|
pkg.KindHTTPGet,
|
|
pkg.ID{0xfe, 0},
|
|
nil,
|
|
nil, nil,
|
|
), &stubArtifact{
|
|
kind: pkg.KindTar,
|
|
params: []byte("empty directory"),
|
|
|
|
// this is queued and might run instead of the other
|
|
// one so do not leave it as nil
|
|
cure: func(t *pkg.TContext) error {
|
|
return os.MkdirAll(t.GetWorkDir().String(), 0700)
|
|
},
|
|
}}, 1<<5 /* concurrent cache hits */),
|
|
|
|
cure: func(f *pkg.FContext) error {
|
|
work := f.GetWorkDir()
|
|
if err := os.MkdirAll(work.String(), 0700); err != nil {
|
|
return err
|
|
}
|
|
return os.WriteFile(work.Append("check").String(), []byte("layers"), 0400)
|
|
},
|
|
}),
|
|
pkg.MustPath("/opt", false, testtool),
|
|
), ignorePathname, wantChecksumOffline, nil},
|
|
})
|
|
|
|
testtoolDestroy(t, base, c)
|
|
}, pkg.MustDecode("O2YzyR7IUGU5J2CADy0hUZ3A5NkP_Vwzs4UadEdn2oMZZVWRtH0xZGJ3HXiimTnZ")},
|
|
|
|
{"overlay layer promotion", nil, func(t *testing.T, base *check.Absolute, c *pkg.Cache) {
|
|
c.SetStrict(true)
|
|
testtool, testtoolDestroy := newTesttool()
|
|
|
|
cureMany(t, c, []cureStep{
|
|
{"container", pkg.NewExec(
|
|
"exec-layer-promotion", nil, 0, true,
|
|
pkg.AbsWork,
|
|
[]string{"HAKUREI_TEST=1", "HAKUREI_ROOT=1"},
|
|
check.MustAbs("/opt/bin/testtool"),
|
|
[]string{"testtool", "promote"},
|
|
|
|
pkg.MustPath("/", true, &stubArtifact{
|
|
kind: pkg.KindTar,
|
|
params: []byte("another empty directory"),
|
|
cure: func(t *pkg.TContext) error {
|
|
return os.MkdirAll(t.GetWorkDir().String(), 0700)
|
|
},
|
|
}, &stubArtifact{
|
|
kind: pkg.KindTar,
|
|
params: []byte("empty directory"),
|
|
cure: func(t *pkg.TContext) error {
|
|
return os.MkdirAll(t.GetWorkDir().String(), 0700)
|
|
},
|
|
}),
|
|
pkg.MustPath("/opt", false, testtool),
|
|
), ignorePathname, wantChecksumOffline, nil},
|
|
})
|
|
|
|
testtoolDestroy(t, base, c)
|
|
}, pkg.MustDecode("3EaW6WibLi9gl03_UieiFPaFcPy5p4x3JPxrnLJxGaTI-bh3HU9DK9IMx7c3rrNm")},
|
|
})
|
|
}
|
|
|
|
// newTesttool returns an [Artifact] that cures into testtoolBin. The returned
|
|
// function must be called at the end of the test but not deferred.
|
|
func newTesttool() (
|
|
testtool pkg.Artifact,
|
|
testtoolDestroy func(t *testing.T, base *check.Absolute, c *pkg.Cache),
|
|
) {
|
|
// testtoolBin is built during go:generate and is not deterministic
|
|
testtool = overrideIdent{pkg.ID{0xfe, 0xff}, &stubArtifact{
|
|
kind: pkg.KindTar,
|
|
cure: func(t *pkg.TContext) error {
|
|
work := t.GetWorkDir()
|
|
if err := os.MkdirAll(
|
|
work.Append("bin").String(),
|
|
0700,
|
|
); err != nil {
|
|
return err
|
|
}
|
|
|
|
if ift, err := net.Interfaces(); err != nil {
|
|
return err
|
|
} else {
|
|
var f *os.File
|
|
if f, err = os.Create(t.GetWorkDir().Append(
|
|
"ift",
|
|
).String()); err != nil {
|
|
return err
|
|
} else {
|
|
err = gob.NewEncoder(f).Encode(ift)
|
|
closeErr := f.Close()
|
|
if err != nil {
|
|
return err
|
|
}
|
|
if closeErr != nil {
|
|
return closeErr
|
|
}
|
|
}
|
|
}
|
|
|
|
return os.WriteFile(t.GetWorkDir().Append(
|
|
"bin",
|
|
"testtool",
|
|
).String(), testtoolBin, 0500)
|
|
},
|
|
}}
|
|
testtoolDestroy = newDestroyArtifactFunc(testtool)
|
|
return
|
|
}
|