package pkg_test import ( _ "embed" "encoding/gob" "errors" "io/fs" "net" "os" "os/exec" "slices" "testing" "unique" "hakurei.app/check" "hakurei.app/hst" "hakurei.app/internal/pkg" "hakurei.app/internal/stub" "hakurei.app/internal/pkg/internal/testtool/expected" ) // testtoolBin is the container test tool binary made available to the // execArtifact for testing its curing environment. // //go:generate env CGO_ENABLED=0 go build -tags testtool -o internal/testtool ./internal/testtool //go:embed internal/testtool/testtool var testtoolBin []byte func TestExec(t *testing.T) { t.Parallel() wantOffline := expectsFS{ ".": {Mode: fs.ModeDir | 0500}, "check": {Mode: 0400, Data: []byte{0}}, } wantOfflineEncode := pkg.Encode(wantOffline.hash()) checkWithCache(t, []cacheTestCase{ {"offline", pkg.CValidateKnown, nil, func(t *testing.T, base *check.Absolute, c *pkg.Cache) { 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, wantOffline, 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, nil, &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, nil, pkg.ErrInvalidPaths}, }) // 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) }, expectsFS{ ".": {Mode: fs.ModeDir | 0700}, "checksum": {Mode: fs.ModeDir | 0700}, "checksum/" + wantOfflineEncode: {Mode: fs.ModeDir | 0500}, "checksum/" + wantOfflineEncode + "/check": {Mode: 0400, Data: []byte{0}}, "checksum/MGWmEfjut2QE2xPJwTsmUzpff4BN_FEnQ7T0j7gvUCCiugJQNwqt9m151fm9D1yU": {Mode: fs.ModeDir | 0500}, "checksum/OLBgp1GsljhM2TJ-sbHjaiH9txEUvgdDTAzHv2P24donTt6_529l-9Ua0vFImLlb": {Mode: 0400, Data: []byte{}}, "identifier": {Mode: fs.ModeDir | 0700}, "identifier/_gAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA": {Mode: fs.ModeSymlink | 0777, Data: []byte("../checksum/OLBgp1GsljhM2TJ-sbHjaiH9txEUvgdDTAzHv2P24donTt6_529l-9Ua0vFImLlb")}, "identifier/" + expected.Offline: {Mode: fs.ModeSymlink | 0777, Data: []byte("../checksum/" + wantOfflineEncode)}, "identifier/vjz1MHPcGBKV7sjcs8jQP3cqxJ1hgPTiQBMCEHP9BGXjGxd-tJmEmXKaStObo5gK": {Mode: fs.ModeSymlink | 0777, Data: []byte("../checksum/MGWmEfjut2QE2xPJwTsmUzpff4BN_FEnQ7T0j7gvUCCiugJQNwqt9m151fm9D1yU")}, "temp": {Mode: fs.ModeDir | 0700}, "work": {Mode: fs.ModeDir | 0700}, }}, {"net", pkg.CValidateKnown, nil, func(t *testing.T, base *check.Absolute, c *pkg.Cache) { testtool, testtoolDestroy := newTesttool() wantNet := expectsFS{ ".": {Mode: fs.ModeDir | 0500}, "check": {Mode: 0400, Data: []byte("net")}, } cureMany(t, c, []cureStep{ {"container", pkg.NewExec( "exec-net", new(wantNet.hash()), 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, wantNet, nil}, }) testtoolDestroy(t, base, c) }, expectsFS{ ".": {Mode: fs.ModeDir | 0700}, "checksum": {Mode: fs.ModeDir | 0700}, "checksum/MGWmEfjut2QE2xPJwTsmUzpff4BN_FEnQ7T0j7gvUCCiugJQNwqt9m151fm9D1yU": {Mode: fs.ModeDir | 0500}, "checksum/OLBgp1GsljhM2TJ-sbHjaiH9txEUvgdDTAzHv2P24donTt6_529l-9Ua0vFImLlb": {Mode: 0400, Data: []byte{}}, "checksum/a1F_i9PVQI4qMcoHgTQkORuyWLkC1GLIxOhDt2JpU1NGAxWc5VJzdlfRK-PYBh3W": {Mode: fs.ModeDir | 0500}, "checksum/a1F_i9PVQI4qMcoHgTQkORuyWLkC1GLIxOhDt2JpU1NGAxWc5VJzdlfRK-PYBh3W/check": {Mode: 0400, Data: []byte("net")}, "identifier": {Mode: fs.ModeDir | 0700}, "identifier/" + expected.Net: {Mode: fs.ModeSymlink | 0777, Data: []byte("../checksum/a1F_i9PVQI4qMcoHgTQkORuyWLkC1GLIxOhDt2JpU1NGAxWc5VJzdlfRK-PYBh3W")}, "identifier/_gAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA": {Mode: fs.ModeSymlink | 0777, Data: []byte("../checksum/OLBgp1GsljhM2TJ-sbHjaiH9txEUvgdDTAzHv2P24donTt6_529l-9Ua0vFImLlb")}, "identifier/vjz1MHPcGBKV7sjcs8jQP3cqxJ1hgPTiQBMCEHP9BGXjGxd-tJmEmXKaStObo5gK": {Mode: fs.ModeSymlink | 0777, Data: []byte("../checksum/MGWmEfjut2QE2xPJwTsmUzpff4BN_FEnQ7T0j7gvUCCiugJQNwqt9m151fm9D1yU")}, "temp": {Mode: fs.ModeDir | 0700}, "work": {Mode: fs.ModeDir | 0700}, }}, {"overlay root", pkg.CValidateKnown, nil, func(t *testing.T, base *check.Absolute, c *pkg.Cache) { 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, wantOffline, nil}, }) testtoolDestroy(t, base, c) }, expectsFS{ ".": {Mode: fs.ModeDir | 0700}, "checksum": {Mode: fs.ModeDir | 0700}, "checksum/" + wantOfflineEncode: {Mode: fs.ModeDir | 0500}, "checksum/" + wantOfflineEncode + "/check": {Mode: 0400, Data: []byte{0}}, "checksum/MGWmEfjut2QE2xPJwTsmUzpff4BN_FEnQ7T0j7gvUCCiugJQNwqt9m151fm9D1yU": {Mode: fs.ModeDir | 0500}, "identifier": {Mode: fs.ModeDir | 0700}, "identifier/" + expected.OvlRoot: {Mode: fs.ModeSymlink | 0777, Data: []byte("../checksum/" + wantOfflineEncode)}, "identifier/vjz1MHPcGBKV7sjcs8jQP3cqxJ1hgPTiQBMCEHP9BGXjGxd-tJmEmXKaStObo5gK": {Mode: fs.ModeSymlink | 0777, Data: []byte("../checksum/MGWmEfjut2QE2xPJwTsmUzpff4BN_FEnQ7T0j7gvUCCiugJQNwqt9m151fm9D1yU")}, "temp": {Mode: fs.ModeDir | 0700}, "work": {Mode: fs.ModeDir | 0700}, }}, {"overlay work", pkg.CValidateKnown, nil, func(t *testing.T, base *check.Absolute, c *pkg.Cache) { 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, wantOffline, nil}, }) testtoolDestroy(t, base, c) }, expectsFS{ ".": {Mode: fs.ModeDir | 0700}, "checksum": {Mode: fs.ModeDir | 0700}, "checksum/" + wantOfflineEncode: {Mode: fs.ModeDir | 0500}, "checksum/" + wantOfflineEncode + "/check": {Mode: 0400, Data: []byte{0}}, "checksum/MGWmEfjut2QE2xPJwTsmUzpff4BN_FEnQ7T0j7gvUCCiugJQNwqt9m151fm9D1yU": {Mode: fs.ModeDir | 0500}, "identifier": {Mode: fs.ModeDir | 0700}, "identifier/" + expected.Work: {Mode: fs.ModeSymlink | 0777, Data: []byte("../checksum/" + wantOfflineEncode)}, "identifier/vjz1MHPcGBKV7sjcs8jQP3cqxJ1hgPTiQBMCEHP9BGXjGxd-tJmEmXKaStObo5gK": {Mode: fs.ModeSymlink | 0777, Data: []byte("../checksum/MGWmEfjut2QE2xPJwTsmUzpff4BN_FEnQ7T0j7gvUCCiugJQNwqt9m151fm9D1yU")}, "temp": {Mode: fs.ModeDir | 0700}, "work": {Mode: fs.ModeDir | 0700}, }}, {"multiple layers", pkg.CValidateKnown, nil, func(t *testing.T, base *check.Absolute, c *pkg.Cache) { 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, wantOffline, nil}, }) testtoolDestroy(t, base, c) }, expectsFS{ ".": {Mode: fs.ModeDir | 0700}, "checksum": {Mode: fs.ModeDir | 0700}, "checksum/" + wantOfflineEncode: {Mode: fs.ModeDir | 0500}, "checksum/" + wantOfflineEncode + "/check": {Mode: 0400, Data: []byte{0}}, "checksum/MGWmEfjut2QE2xPJwTsmUzpff4BN_FEnQ7T0j7gvUCCiugJQNwqt9m151fm9D1yU": {Mode: fs.ModeDir | 0500}, "checksum/OLBgp1GsljhM2TJ-sbHjaiH9txEUvgdDTAzHv2P24donTt6_529l-9Ua0vFImLlb": {Mode: 0400, Data: []byte{}}, "checksum/nY_CUdiaUM1OL4cPr5TS92FCJ3rCRV7Hm5oVTzAvMXwC03_QnTRfQ5PPs7mOU9fK": {Mode: fs.ModeDir | 0500}, "checksum/nY_CUdiaUM1OL4cPr5TS92FCJ3rCRV7Hm5oVTzAvMXwC03_QnTRfQ5PPs7mOU9fK/check": {Mode: 0400, Data: []byte("layers")}, "identifier": {Mode: fs.ModeDir | 0700}, "identifier/_gAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA": {Mode: fs.ModeSymlink | 0777, Data: []byte("../checksum/OLBgp1GsljhM2TJ-sbHjaiH9txEUvgdDTAzHv2P24donTt6_529l-9Ua0vFImLlb")}, "identifier/B-kc5iJMx8GtlCua4dz6BiJHnDAOUfPjgpbKq4e-QEn0_CZkSYs3fOA1ve06qMs2": {Mode: fs.ModeSymlink | 0777, Data: []byte("../checksum/nY_CUdiaUM1OL4cPr5TS92FCJ3rCRV7Hm5oVTzAvMXwC03_QnTRfQ5PPs7mOU9fK")}, "identifier/" + expected.Layers: {Mode: fs.ModeSymlink | 0777, Data: []byte("../checksum/" + wantOfflineEncode)}, "identifier/vjz1MHPcGBKV7sjcs8jQP3cqxJ1hgPTiQBMCEHP9BGXjGxd-tJmEmXKaStObo5gK": {Mode: fs.ModeSymlink | 0777, Data: []byte("../checksum/MGWmEfjut2QE2xPJwTsmUzpff4BN_FEnQ7T0j7gvUCCiugJQNwqt9m151fm9D1yU")}, "temp": {Mode: fs.ModeDir | 0700}, "work": {Mode: fs.ModeDir | 0700}, }}, {"overlay layer promotion", pkg.CValidateKnown, nil, func(t *testing.T, base *check.Absolute, c *pkg.Cache) { 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, wantOffline, nil}, }) testtoolDestroy(t, base, c) }, expectsFS{ ".": {Mode: fs.ModeDir | 0700}, "checksum": {Mode: fs.ModeDir | 0700}, "checksum/" + wantOfflineEncode: {Mode: fs.ModeDir | 0500}, "checksum/" + wantOfflineEncode + "/check": {Mode: 0400, Data: []byte{0}}, "checksum/MGWmEfjut2QE2xPJwTsmUzpff4BN_FEnQ7T0j7gvUCCiugJQNwqt9m151fm9D1yU": {Mode: fs.ModeDir | 0500}, "identifier": {Mode: fs.ModeDir | 0700}, "identifier/kvJIqZo5DKFOxC2ZQ-8_nPaQzEAz9cIm3p6guO-uLqm-xaiPu7oRkSnsu411jd_U": {Mode: fs.ModeSymlink | 0777, Data: []byte("../checksum/MGWmEfjut2QE2xPJwTsmUzpff4BN_FEnQ7T0j7gvUCCiugJQNwqt9m151fm9D1yU")}, "identifier/vjz1MHPcGBKV7sjcs8jQP3cqxJ1hgPTiQBMCEHP9BGXjGxd-tJmEmXKaStObo5gK": {Mode: fs.ModeSymlink | 0777, Data: []byte("../checksum/MGWmEfjut2QE2xPJwTsmUzpff4BN_FEnQ7T0j7gvUCCiugJQNwqt9m151fm9D1yU")}, "identifier/" + expected.Promote: {Mode: fs.ModeSymlink | 0777, Data: []byte("../checksum/" + wantOfflineEncode)}, "temp": {Mode: fs.ModeDir | 0700}, "work": {Mode: fs.ModeDir | 0700}, }}, }) } // 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 }