yao/sandbox/v2/box_test.go
Max e633640998 refactor(sandbox/v2): transition from pool to node configuration
- Updated benchmark and test functions to utilize node configurations instead of pool configurations for improved clarity and consistency.
- Refactored related setup functions and test cases to align with the new node-based architecture.
- Adjusted error messages and documentation to reflect the transition from pool to node terminology.

Made-with: Cursor
2026-03-09 03:20:09 +08:00

224 lines
4.9 KiB
Go

package sandbox_test
import (
"context"
"io"
"strings"
"testing"
"time"
sandbox "github.com/yaoapp/yao/sandbox/v2"
)
func TestBoxExec(t *testing.T) {
skipIfNoDocker(t)
for _, pc := range testNodes() {
pc := pc
t.Run(pc.Name, func(t *testing.T) {
m := setupManagerForNode(t, &pc)
box := createTestBox(t, m, pc)
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
defer cancel()
result, err := box.Exec(ctx, []string{"echo", "box-exec"})
if err != nil {
t.Fatalf("Exec: %v", err)
}
if result.Stdout != "box-exec\n" {
t.Errorf("stdout = %q, want %q", result.Stdout, "box-exec\n")
}
})
}
}
func TestBoxExecWithOptions(t *testing.T) {
skipIfNoDocker(t)
for _, pc := range testNodes() {
pc := pc
t.Run(pc.Name, func(t *testing.T) {
m := setupManagerForNode(t, &pc)
box := createTestBox(t, m, pc)
ctx := context.Background()
result, err := box.Exec(ctx, []string{"pwd"},
sandbox.WithWorkDir("/tmp"),
)
if err != nil {
t.Fatalf("Exec: %v", err)
}
if result.Stdout != "/tmp\n" {
t.Errorf("stdout = %q, want %q", result.Stdout, "/tmp\n")
}
})
}
}
func TestBoxStream(t *testing.T) {
skipIfNoDocker(t)
for _, pc := range testNodes() {
pc := pc
t.Run(pc.Name, func(t *testing.T) {
m := setupManagerForNode(t, &pc)
box := createTestBox(t, m, pc)
ctx := context.Background()
stream, err := box.Stream(ctx, []string{"sh", "-c", "echo line1; echo line2"})
if err != nil {
t.Fatalf("Stream: %v", err)
}
out, err := io.ReadAll(stream.Stdout)
if err != nil {
t.Fatalf("ReadAll: %v", err)
}
if string(out) != "line1\nline2\n" {
t.Errorf("stdout = %q, want %q", string(out), "line1\nline2\n")
}
code, err := stream.Wait()
if err != nil {
t.Fatalf("Wait: %v", err)
}
if code != 0 {
t.Errorf("exit code = %d, want 0", code)
}
})
}
}
func TestBoxWorkspace(t *testing.T) {
skipIfNoDocker(t)
for _, pc := range testNodes() {
pc := pc
t.Run(pc.Name, func(t *testing.T) {
m := setupManagerForNode(t, &pc)
box := createTestBox(t, m, pc)
ws := box.Workspace()
if ws == nil {
t.Skip("Workspace returned nil (volume not available)")
}
content := []byte("package main\n")
if err := ws.WriteFile("main.go", content, 0644); err != nil {
t.Fatalf("WriteFile: %v", err)
}
data, err := ws.ReadFile("main.go")
if err != nil {
t.Fatalf("ReadFile: %v", err)
}
if string(data) != string(content) {
t.Errorf("content = %q, want %q", string(data), string(content))
}
if err := ws.MkdirAll("src/pkg", 0755); err != nil {
t.Fatalf("MkdirAll: %v", err)
}
entries, err := ws.ReadDir("src")
if err != nil {
t.Fatalf("ReadDir: %v", err)
}
if len(entries) == 0 {
t.Error("expected non-empty directory listing")
}
})
}
}
func TestBoxInfo(t *testing.T) {
skipIfNoDocker(t)
for _, pc := range testNodes() {
pc := pc
t.Run(pc.Name, func(t *testing.T) {
m := setupManagerForNode(t, &pc)
box := createTestBox(t, m, pc)
ctx := context.Background()
info, err := box.Info(ctx)
if err != nil {
t.Fatalf("Info: %v", err)
}
if info.ID != box.ID() {
t.Errorf("ID = %q, want %q", info.ID, box.ID())
}
if s := strings.ToLower(info.Status); s != "running" {
t.Errorf("status = %q, want running", info.Status)
}
if info.Owner != "test-user" {
t.Errorf("owner = %q, want test-user", info.Owner)
}
})
}
}
func TestBoxStopStart(t *testing.T) {
skipIfNoDocker(t)
for _, pc := range testNodes() {
pc := pc
t.Run(pc.Name, func(t *testing.T) {
m := setupManagerForNode(t, &pc)
box := createTestBox(t, m, pc)
ctx := context.Background()
if err := box.Stop(ctx); err != nil {
t.Fatalf("Stop: %v", err)
}
if err := box.Start(ctx); err != nil {
t.Fatalf("Start: %v", err)
}
result, err := box.Exec(ctx, []string{"echo", "after-restart"})
if err != nil {
t.Fatalf("Exec after restart: %v", err)
}
if result.Stdout != "after-restart\n" {
t.Errorf("stdout = %q", result.Stdout)
}
})
}
}
func TestBoxGetOrCreate(t *testing.T) {
skipIfNoDocker(t)
for _, pc := range testNodes() {
pc := pc
t.Run(pc.Name, func(t *testing.T) {
m := setupManagerForNode(t, &pc)
ctx := context.Background()
box1, err := m.GetOrCreate(ctx, sandbox.CreateOptions{
ID: "goc-" + pc.Name,
Image: testImage(),
Owner: "test-user",
NodeID: pc.TaiID,
})
if err != nil {
t.Fatalf("GetOrCreate first: %v", err)
}
defer m.Remove(ctx, box1.ID())
box2, err := m.GetOrCreate(ctx, sandbox.CreateOptions{
ID: "goc-" + pc.Name,
Image: testImage(),
Owner: "test-user",
NodeID: pc.TaiID,
})
if err != nil {
t.Fatalf("GetOrCreate second: %v", err)
}
if box2.ContainerID() != box1.ContainerID() {
t.Error("expected same container for GetOrCreate with same ID")
}
})
}
}