Add profile loading and process execution
This commit is contained in:
145
internal/process/process_test.go
Normal file
145
internal/process/process_test.go
Normal file
@@ -0,0 +1,145 @@
|
||||
package process
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"os"
|
||||
"os/exec"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"testing"
|
||||
"time"
|
||||
)
|
||||
|
||||
func TestRunPassesArgumentsDirectoryAndEnvironment(t *testing.T) {
|
||||
workdir := filepath.Join(t.TempDir(), "directory with spaces")
|
||||
if err := os.Mkdir(workdir, 0o700); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
t.Setenv("RELEASEKIT_PROCESS_OVERLAY", "parent")
|
||||
t.Setenv("RELEASEKIT_PROCESS_INHERITED", "inherited")
|
||||
|
||||
var stdout, stderr bytes.Buffer
|
||||
err := Run(context.Background(), Invocation{
|
||||
Args: []string{helperExecutable(t), "-test.run=TestProcessHelper", "--", "argument with spaces", "success"},
|
||||
Dir: workdir,
|
||||
Env: map[string]string{
|
||||
"RELEASEKIT_PROCESS_HELPER": "1",
|
||||
"RELEASEKIT_PROCESS_OVERLAY": "child",
|
||||
},
|
||||
Stdout: &stdout,
|
||||
Stderr: &stderr,
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
want := fmt.Sprintf("%s|argument with spaces|child|inherited", workdir)
|
||||
if stdout.String() != want {
|
||||
t.Fatalf("stdout = %q, want %q", stdout.String(), want)
|
||||
}
|
||||
if stderr.String() != "child stderr\n" {
|
||||
t.Fatalf("stderr = %q, want %q", stderr.String(), "child stderr\n")
|
||||
}
|
||||
if got := os.Getenv("RELEASEKIT_PROCESS_OVERLAY"); got != "parent" {
|
||||
t.Fatalf("parent environment changed: got %q, want %q", got, "parent")
|
||||
}
|
||||
}
|
||||
|
||||
func TestRunPreservesExitError(t *testing.T) {
|
||||
err := Run(context.Background(), Invocation{
|
||||
Args: []string{helperExecutable(t), "-test.run=TestProcessHelper", "--", "unused", "exit"},
|
||||
Env: map[string]string{"RELEASEKIT_PROCESS_HELPER": "1"},
|
||||
})
|
||||
var exitErr *exec.ExitError
|
||||
if !errors.As(err, &exitErr) || exitErr.ExitCode() != 7 {
|
||||
t.Fatalf("Run() error = %v, want exit code 7", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestRunReportsMissingExecutable(t *testing.T) {
|
||||
err := Run(context.Background(), Invocation{Args: []string{"releasekit-command-that-does-not-exist"}})
|
||||
if err == nil || !strings.Contains(err.Error(), "releasekit-command-that-does-not-exist") {
|
||||
t.Fatalf("Run() error = %v, want missing executable diagnostic", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestRunReturnsCancellation(t *testing.T) {
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
defer cancel()
|
||||
started := make(chan struct{}, 1)
|
||||
invocation := Invocation{
|
||||
Args: []string{helperExecutable(t), "-test.run=TestProcessHelper", "--", "unused", "wait"},
|
||||
Env: map[string]string{"RELEASEKIT_PROCESS_HELPER": "1"},
|
||||
Stdout: writerFunc(func([]byte) (int, error) {
|
||||
select {
|
||||
case started <- struct{}{}:
|
||||
default:
|
||||
}
|
||||
return len("started\n"), nil
|
||||
}),
|
||||
}
|
||||
|
||||
result := make(chan error, 1)
|
||||
go func() { result <- Run(ctx, invocation) }()
|
||||
select {
|
||||
case <-started:
|
||||
cancel()
|
||||
case <-time.After(5 * time.Second):
|
||||
t.Fatal("child did not start")
|
||||
}
|
||||
select {
|
||||
case err := <-result:
|
||||
if !errors.Is(err, context.Canceled) {
|
||||
t.Fatalf("Run() error = %v, want context cancellation", err)
|
||||
}
|
||||
case <-time.After(5 * time.Second):
|
||||
t.Fatal("Run() did not return after cancellation")
|
||||
}
|
||||
}
|
||||
|
||||
func TestProcessHelper(t *testing.T) {
|
||||
if os.Getenv("RELEASEKIT_PROCESS_HELPER") != "1" {
|
||||
return
|
||||
}
|
||||
args := os.Args
|
||||
if len(args) < 2 {
|
||||
os.Exit(8)
|
||||
}
|
||||
mode := args[len(args)-1]
|
||||
switch mode {
|
||||
case "success":
|
||||
workdir, err := os.Getwd()
|
||||
if err != nil {
|
||||
os.Exit(9)
|
||||
}
|
||||
fmt.Fprintf(os.Stdout, "%s|%s|%s|%s", workdir, args[len(args)-2], os.Getenv("RELEASEKIT_PROCESS_OVERLAY"), os.Getenv("RELEASEKIT_PROCESS_INHERITED"))
|
||||
fmt.Fprintln(os.Stderr, "child stderr")
|
||||
os.Exit(0)
|
||||
case "exit":
|
||||
os.Exit(7)
|
||||
case "wait":
|
||||
fmt.Fprintln(os.Stdout, "started")
|
||||
for {
|
||||
time.Sleep(time.Second)
|
||||
}
|
||||
default:
|
||||
os.Exit(10)
|
||||
}
|
||||
}
|
||||
|
||||
type writerFunc func([]byte) (int, error)
|
||||
|
||||
func (write writerFunc) Write(p []byte) (int, error) {
|
||||
return write(p)
|
||||
}
|
||||
|
||||
func helperExecutable(t *testing.T) string {
|
||||
t.Helper()
|
||||
executable, err := os.Executable()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
return executable
|
||||
}
|
||||
Reference in New Issue
Block a user