Files

115 lines
4.0 KiB
Go

//go:build !windows
package windows
import (
"context"
"crypto/sha256"
"errors"
"io"
"strings"
"sync/atomic"
"testing"
"time"
rvboxv1 "github.com/rvbox/rvbox/gen/go/rvbox/v1"
"github.com/rvbox/rvbox/internal/client/supervisor"
"github.com/rvbox/rvbox/internal/domain"
)
func TestExecProcessReleaseIsIdempotent_BH_LAUNCH_05(t *testing.T) {
var calls atomic.Int32
process := &execProcess{releaseFn: func() error {
calls.Add(1)
return errors.New("release failed")
}}
if err := process.Release(context.Background()); err == nil || err.Error() != "release failed" {
t.Fatalf("first release error = %v", err)
}
if err := process.Release(context.Background()); err == nil || err.Error() != "release failed" {
t.Fatalf("repeated release error = %v", err)
}
if got := calls.Load(); got != 1 {
t.Fatalf("release calls = %d, want one", got)
}
}
func TestPortableSupervisorCapturesOutputAndSupportsStdin_HP_SUPERVISOR_03(t *testing.T) {
t.Parallel()
manager, err := NewSupervisor(NativeOptions{MaxOutputChunk: 8, WindowsTermGrace: 10 * time.Millisecond})
if err != nil {
t.Fatal(err)
}
issue, err := domain.ParseUUIDv7("019c46f1-1d02-7000-8000-0000000000c1")
if err != nil {
t.Fatal(err)
}
process, err := manager.Start(context.Background(), supervisor.StartSpec{IssueUUID: issue, CommandRevision: 1, WorkingDirectory: t.TempDir(), Execution: &rvboxv1.ExecutionSpec{ShellType: rvboxv1.ShellType_SHELL_SH, Source: &rvboxv1.ExecutionSpec_CommandText{CommandText: "read line; printf 'out:%s\\n' \"$line\"; printf 'err\\n' >&2"}}})
if err != nil {
t.Fatal(err)
}
if process.PID() == 0 {
t.Fatal("portable supervisor did not expose process identity PID")
}
if err := process.WriteStdin(context.Background(), []byte("hello"), true); err != nil {
t.Fatal(err)
}
if err := process.CloseStdin(context.Background()); err != nil {
t.Fatal(err)
}
status, err := process.Wait(context.Background())
if err != nil || status.Code != 0 {
t.Fatalf("wait = %+v, %v", status, err)
}
var output strings.Builder
streams := map[rvboxv1.StreamKind]bool{}
for {
chunk, err := process.ReadOutput(context.Background())
if errors.Is(err, io.EOF) {
break
}
if err != nil {
t.Fatal(err)
}
output.Write(chunk.Data)
streams[chunk.Stream] = true
}
if !strings.Contains(output.String(), "out:hello\n") || !strings.Contains(output.String(), "err\n") || !streams[rvboxv1.StreamKind_STREAM_STDOUT] || !streams[rvboxv1.StreamKind_STREAM_STDERR] {
t.Fatalf("captured output = %q streams=%v", output.String(), streams)
}
second, err := manager.Start(context.Background(), supervisor.StartSpec{IssueUUID: issue, CommandRevision: 1, WorkingDirectory: t.TempDir(), Execution: &rvboxv1.ExecutionSpec{ShellType: rvboxv1.ShellType_SHELL_SH, Source: &rvboxv1.ExecutionSpec_CommandText{CommandText: "true"}}})
if err != nil {
t.Fatalf("restart after terminal = %v", err)
}
_, _ = second.Wait(context.Background())
}
func TestPortableSupervisorScriptMaterializationAndCleanup_HP_SUPERVISOR_04(t *testing.T) {
t.Parallel()
manager, err := NewSupervisor(NativeOptions{MaxWrapperBytes: 1024})
if err != nil {
t.Fatal(err)
}
issue, _ := domain.ParseUUIDv7("019c46f1-1d02-7000-8000-0000000000c2")
body := []byte("printf script-ok")
process, err := manager.Start(context.Background(), supervisor.StartSpec{IssueUUID: issue, CommandRevision: 1, WorkingDirectory: t.TempDir(), ScriptBody: body, Execution: &rvboxv1.ExecutionSpec{ShellType: rvboxv1.ShellType_SHELL_SH, Source: &rvboxv1.ExecutionSpec_Script{Script: &rvboxv1.ScriptDescriptor{SizeBytes: uint64(len(body)), Sha256: digest(body)}}}})
if err != nil {
t.Fatal(err)
}
if _, err := process.Wait(context.Background()); err != nil {
t.Fatal(err)
}
chunk, err := process.ReadOutput(context.Background())
if err != nil || string(chunk.Data) != "script-ok" {
t.Fatalf("script output = %+v, %v", chunk, err)
}
if _, err := process.ReadOutput(context.Background()); !errors.Is(err, io.EOF) {
t.Fatalf("script output close = %v", err)
}
}
func digest(value []byte) []byte {
result := sha256.Sum256(value)
return result[:]
}