aboutsummaryrefslogtreecommitdiffhomepage
path: root/internal/pkg/exec_test.go
diff options
context:
space:
mode:
authorOphestra <cat@gensokyo.uk>2026-01-06 04:36:01 +0900
committerOphestra <cat@gensokyo.uk>2026-01-06 05:05:34 +0900
commit79adf217f4ca94fdfeb8a190fc7dc49fd26254dd (patch)
treebc9cfb855369bb6539fb11634fa0d132a6ef6a4e /internal/pkg/exec_test.go
parent8efffd72f4c5a0f241075fd13e4d07d71fd7fde8 (diff)
internal/pkg: implement exec artifact
This runs a program in a container environment. Artifacts can be made available to the container, they are cured concurrently and mounted in order. Signed-off-by: Ophestra <cat@gensokyo.uk>
Diffstat (limited to 'internal/pkg/exec_test.go')
-rw-r--r--internal/pkg/exec_test.go138
1 files changed, 138 insertions, 0 deletions
diff --git a/internal/pkg/exec_test.go b/internal/pkg/exec_test.go
new file mode 100644
index 00000000..e718b260
--- /dev/null
+++ b/internal/pkg/exec_test.go
@@ -0,0 +1,138 @@
+package pkg_test
+
+//go:generate go build -tags testtool -ldflags "-extldflags='-static'" -o testdata/testtool ./testdata
+
+import (
+ _ "embed"
+ "errors"
+ "log"
+ "os"
+ "os/exec"
+ "testing"
+
+ "hakurei.app/container/check"
+ "hakurei.app/container/stub"
+ "hakurei.app/hst"
+ "hakurei.app/internal/pkg"
+ "hakurei.app/message"
+)
+
+// 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()
+
+ checkWithCache(t, []cacheTestCase{
+ {"container", nil, func(t *testing.T, base *check.Absolute, c *pkg.Cache) {
+ c.SetStrict(true)
+
+ // this is built during go:generate and is not deterministic
+ testtool := overrideIdent{pkg.ID{0xfe, 0xff}, stubArtifact{
+ kind: pkg.KindTar,
+ cure: func(c *pkg.CureContext) error {
+ work := c.GetWorkDir()
+ if err := os.MkdirAll(
+ work.Append("bin").String(),
+ 0700,
+ ); err != nil {
+ return err
+ }
+ return os.WriteFile(c.GetWorkDir().Append(
+ "bin",
+ "testtool",
+ ).String(), testtoolBin, 0500)
+ },
+ }}
+
+ msg := message.New(log.New(os.Stderr, "container: ", 0))
+ msg.SwapVerbose(testing.Verbose())
+
+ cureMany(t, c, []cureStep{
+ {"container", pkg.NewExec(
+ t.Context(),
+ msg,
+ 0,
+ check.MustAbs("/work"),
+ []string{"HAKUREI_TEST=1"},
+ check.MustAbs("/opt/bin/testtool"),
+ []string{"testtool"},
+
+ pkg.MustPath("/file", newStubFile(
+ pkg.KindHTTPGet,
+ pkg.ID{0xfe, 0},
+ nil,
+ nil, nil,
+ )),
+ pkg.MustPath("/.hakurei", stubArtifact{
+ kind: pkg.KindTar,
+ params: []byte("empty directory"),
+ cure: func(c *pkg.CureContext) error {
+ return os.MkdirAll(c.GetWorkDir().String(), 0700)
+ },
+ }),
+ pkg.MustPath("/opt", testtool),
+ ), ignorePathname, pkg.MustDecode(
+ "GPa4aBakdSJd7Tz7LYj_VJFoojzyZinmVcG3k6M5xI6CZ821J5sXLhLDDuS47gi9",
+ ), nil},
+
+ {"error passthrough", pkg.NewExec(
+ t.Context(),
+ msg,
+ 0,
+ check.MustAbs("/work"),
+ []string{"HAKUREI_TEST=1"},
+ check.MustAbs("/opt/bin/testtool"),
+ []string{"testtool"},
+
+ pkg.MustPath("/proc/nonexistent", stubArtifact{
+ kind: pkg.KindTar,
+ params: []byte("doomed artifact"),
+ cure: func(c *pkg.CureContext) error {
+ return stub.UniqueError(0xcafe)
+ },
+ }),
+ ), nil, pkg.Checksum{}, errors.Join(stub.UniqueError(0xcafe))},
+ })
+
+ // check init failure passthrough
+ var exitError *exec.ExitError
+ if _, _, err := c.Cure(pkg.NewExec(
+ t.Context(),
+ msg,
+ 0,
+ check.MustAbs("/work"),
+ 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)
+ }
+
+ // the testtool is not deterministic
+ if pathname, checksum, err := c.Cure(testtool); err != nil {
+ t.Fatalf("Cure: error = %v", err)
+ } else if err = os.Remove(pathname.String()); err != nil {
+ t.Fatal(err)
+ } else {
+ p := base.Append(
+ "checksum",
+ pkg.Encode(checksum),
+ )
+ if err = os.Chmod(p.Append("bin").String(), 0700); err != nil {
+ t.Fatal(err)
+ }
+ if err = os.Chmod(p.String(), 0700); err != nil {
+ t.Fatal(err)
+ }
+ if err = os.RemoveAll(p.String()); err != nil {
+ t.Fatal(err)
+ }
+ }
+ }, pkg.MustDecode("7PoPpWLjFPXIymbuIYLZAzOpCYr-2PN4CZ11jFdO-mDlnZNgFO3JyOtK8HW8Jxvm")},
+ })
+}