- Updated CI workflows to set the YAO_SANDBOX_CONTAINER_USER environment variable, ensuring proper user permissions during sandbox tests. - Modified the Config struct to include ContainerUser, allowing for user specification in container execution. - Improved test setup in config_test.go to clear conflicting environment variables, enhancing test reliability. - Refactored manager_test.go to utilize the new getContainerUser function for consistent user handling across tests.
234 lines
6.5 KiB
Go
234 lines
6.5 KiB
Go
package sandbox
|
|
|
|
import (
|
|
"os"
|
|
"testing"
|
|
"time"
|
|
)
|
|
|
|
func TestDefaultConfig(t *testing.T) {
|
|
cfg := DefaultConfig()
|
|
|
|
if cfg.Image != "yaoapp/sandbox-claude:latest" {
|
|
t.Errorf("expected default image 'yaoapp/sandbox-claude:latest', got '%s'", cfg.Image)
|
|
}
|
|
if cfg.MaxContainers != 100 {
|
|
t.Errorf("expected MaxContainers 100, got %d", cfg.MaxContainers)
|
|
}
|
|
if cfg.IdleTimeout != 30*time.Minute {
|
|
t.Errorf("expected IdleTimeout 30m, got %v", cfg.IdleTimeout)
|
|
}
|
|
if cfg.MaxMemory != "2g" {
|
|
t.Errorf("expected MaxMemory '2g', got '%s'", cfg.MaxMemory)
|
|
}
|
|
if cfg.MaxCPU != 1.0 {
|
|
t.Errorf("expected MaxCPU 1.0, got %f", cfg.MaxCPU)
|
|
}
|
|
}
|
|
|
|
func TestConfigInit(t *testing.T) {
|
|
// Clear any existing environment variables that might interfere
|
|
os.Unsetenv("YAO_SANDBOX_WORKSPACE")
|
|
os.Unsetenv("YAO_SANDBOX_IPC")
|
|
|
|
// Test with dataRoot
|
|
cfg := &Config{}
|
|
cfg.Init("/tmp/yao-test")
|
|
|
|
if cfg.WorkspaceRoot != "/tmp/yao-test/sandbox/workspace" {
|
|
t.Errorf("expected WorkspaceRoot '/tmp/yao-test/sandbox/workspace', got '%s'", cfg.WorkspaceRoot)
|
|
}
|
|
if cfg.IPCDir != "/tmp/yao-test/sandbox/ipc" {
|
|
t.Errorf("expected IPCDir '/tmp/yao-test/sandbox/ipc', got '%s'", cfg.IPCDir)
|
|
}
|
|
}
|
|
|
|
func TestConfigInitWithEnv(t *testing.T) {
|
|
// Set environment variables
|
|
os.Setenv("YAO_SANDBOX_IMAGE", "test/image:v1")
|
|
os.Setenv("YAO_SANDBOX_MAX", "50")
|
|
os.Setenv("YAO_SANDBOX_IDLE_TIMEOUT", "15m")
|
|
os.Setenv("YAO_SANDBOX_MEMORY", "4g")
|
|
os.Setenv("YAO_SANDBOX_CPU", "2.5")
|
|
defer func() {
|
|
os.Unsetenv("YAO_SANDBOX_IMAGE")
|
|
os.Unsetenv("YAO_SANDBOX_MAX")
|
|
os.Unsetenv("YAO_SANDBOX_IDLE_TIMEOUT")
|
|
os.Unsetenv("YAO_SANDBOX_MEMORY")
|
|
os.Unsetenv("YAO_SANDBOX_CPU")
|
|
}()
|
|
|
|
cfg := &Config{}
|
|
cfg.Init("/tmp/yao-test")
|
|
|
|
if cfg.Image != "test/image:v1" {
|
|
t.Errorf("expected Image 'test/image:v1', got '%s'", cfg.Image)
|
|
}
|
|
if cfg.MaxContainers != 50 {
|
|
t.Errorf("expected MaxContainers 50, got %d", cfg.MaxContainers)
|
|
}
|
|
if cfg.IdleTimeout != 15*time.Minute {
|
|
t.Errorf("expected IdleTimeout 15m, got %v", cfg.IdleTimeout)
|
|
}
|
|
if cfg.MaxMemory != "4g" {
|
|
t.Errorf("expected MaxMemory '4g', got '%s'", cfg.MaxMemory)
|
|
}
|
|
if cfg.MaxCPU != 2.5 {
|
|
t.Errorf("expected MaxCPU 2.5, got %f", cfg.MaxCPU)
|
|
}
|
|
}
|
|
|
|
func TestConfigInitWithWorkspaceEnv(t *testing.T) {
|
|
// Test YAO_SANDBOX_WORKSPACE env var
|
|
os.Setenv("YAO_SANDBOX_WORKSPACE", "/custom/workspace")
|
|
os.Setenv("YAO_SANDBOX_IPC", "/custom/ipc")
|
|
defer func() {
|
|
os.Unsetenv("YAO_SANDBOX_WORKSPACE")
|
|
os.Unsetenv("YAO_SANDBOX_IPC")
|
|
}()
|
|
|
|
cfg := &Config{}
|
|
cfg.Init("/tmp/yao-test")
|
|
|
|
if cfg.WorkspaceRoot != "/custom/workspace" {
|
|
t.Errorf("expected WorkspaceRoot '/custom/workspace', got '%s'", cfg.WorkspaceRoot)
|
|
}
|
|
if cfg.IPCDir != "/custom/ipc" {
|
|
t.Errorf("expected IPCDir '/custom/ipc', got '%s'", cfg.IPCDir)
|
|
}
|
|
}
|
|
|
|
func TestConfigInitWithPresetValues(t *testing.T) {
|
|
// Test that preset values are not overwritten by defaults
|
|
cfg := &Config{
|
|
Image: "preset/image:v2",
|
|
MaxContainers: 200,
|
|
IdleTimeout: 1 * time.Hour,
|
|
MaxMemory: "8g",
|
|
MaxCPU: 4.0,
|
|
WorkspaceRoot: "/preset/workspace",
|
|
IPCDir: "/preset/ipc",
|
|
}
|
|
cfg.Init("/tmp/yao-test")
|
|
|
|
if cfg.Image != "preset/image:v2" {
|
|
t.Errorf("expected Image 'preset/image:v2', got '%s'", cfg.Image)
|
|
}
|
|
if cfg.MaxContainers != 200 {
|
|
t.Errorf("expected MaxContainers 200, got %d", cfg.MaxContainers)
|
|
}
|
|
if cfg.IdleTimeout != 1*time.Hour {
|
|
t.Errorf("expected IdleTimeout 1h, got %v", cfg.IdleTimeout)
|
|
}
|
|
if cfg.MaxMemory != "8g" {
|
|
t.Errorf("expected MaxMemory '8g', got '%s'", cfg.MaxMemory)
|
|
}
|
|
if cfg.MaxCPU != 4.0 {
|
|
t.Errorf("expected MaxCPU 4.0, got %f", cfg.MaxCPU)
|
|
}
|
|
if cfg.WorkspaceRoot != "/preset/workspace" {
|
|
t.Errorf("expected WorkspaceRoot '/preset/workspace', got '%s'", cfg.WorkspaceRoot)
|
|
}
|
|
if cfg.IPCDir != "/preset/ipc" {
|
|
t.Errorf("expected IPCDir '/preset/ipc', got '%s'", cfg.IPCDir)
|
|
}
|
|
}
|
|
|
|
func TestConfigInitInvalidEnvValues(t *testing.T) {
|
|
// Test with invalid environment values
|
|
os.Setenv("YAO_SANDBOX_MAX", "invalid")
|
|
os.Setenv("YAO_SANDBOX_IDLE_TIMEOUT", "not-a-duration")
|
|
os.Setenv("YAO_SANDBOX_CPU", "not-a-float")
|
|
defer func() {
|
|
os.Unsetenv("YAO_SANDBOX_MAX")
|
|
os.Unsetenv("YAO_SANDBOX_IDLE_TIMEOUT")
|
|
os.Unsetenv("YAO_SANDBOX_CPU")
|
|
}()
|
|
|
|
cfg := &Config{}
|
|
cfg.Init("/tmp/yao-test")
|
|
|
|
// Invalid env values should fall back to defaults
|
|
if cfg.MaxContainers != 100 {
|
|
t.Errorf("expected MaxContainers 100 (default), got %d", cfg.MaxContainers)
|
|
}
|
|
if cfg.IdleTimeout != 30*time.Minute {
|
|
t.Errorf("expected IdleTimeout 30m (default), got %v", cfg.IdleTimeout)
|
|
}
|
|
if cfg.MaxCPU != 1.0 {
|
|
t.Errorf("expected MaxCPU 1.0 (default), got %f", cfg.MaxCPU)
|
|
}
|
|
}
|
|
|
|
func TestConfigInitNegativeValues(t *testing.T) {
|
|
// Test with negative/zero values in env
|
|
os.Setenv("YAO_SANDBOX_MAX", "-5")
|
|
os.Setenv("YAO_SANDBOX_CPU", "-1.0")
|
|
defer func() {
|
|
os.Unsetenv("YAO_SANDBOX_MAX")
|
|
os.Unsetenv("YAO_SANDBOX_CPU")
|
|
}()
|
|
|
|
cfg := &Config{}
|
|
cfg.Init("/tmp/yao-test")
|
|
|
|
// Negative values should fall back to defaults
|
|
if cfg.MaxContainers != 100 {
|
|
t.Errorf("expected MaxContainers 100 (default), got %d", cfg.MaxContainers)
|
|
}
|
|
if cfg.MaxCPU != 1.0 {
|
|
t.Errorf("expected MaxCPU 1.0 (default), got %f", cfg.MaxCPU)
|
|
}
|
|
}
|
|
|
|
func TestConfigInitZeroMax(t *testing.T) {
|
|
// Test with zero max containers
|
|
os.Setenv("YAO_SANDBOX_MAX", "0")
|
|
defer os.Unsetenv("YAO_SANDBOX_MAX")
|
|
|
|
cfg := &Config{}
|
|
cfg.Init("/tmp/yao-test")
|
|
|
|
// Zero is rejected by v > 0 check, should use default
|
|
if cfg.MaxContainers != 100 {
|
|
t.Errorf("expected MaxContainers 100 (default), got %d", cfg.MaxContainers)
|
|
}
|
|
}
|
|
|
|
func TestContainerName(t *testing.T) {
|
|
tests := []struct {
|
|
userID string
|
|
chatID string
|
|
expected string
|
|
}{
|
|
{"user1", "chat1", "yao-sandbox-user1-chat1"},
|
|
{"u123", "c456", "yao-sandbox-u123-c456"},
|
|
{"test-user", "test-chat", "yao-sandbox-test-user-test-chat"},
|
|
{"", "", "yao-sandbox--"},
|
|
{"user_with_underscore", "chat-with-dash", "yao-sandbox-user_with_underscore-chat-with-dash"},
|
|
{"UPPERCASE", "lowercase", "yao-sandbox-UPPERCASE-lowercase"},
|
|
}
|
|
|
|
for _, tt := range tests {
|
|
result := containerName(tt.userID, tt.chatID)
|
|
if result != tt.expected {
|
|
t.Errorf("containerName(%s, %s) = %s, want %s", tt.userID, tt.chatID, result, tt.expected)
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestConfigEnvPriority(t *testing.T) {
|
|
// Env vars should override preset config values
|
|
os.Setenv("YAO_SANDBOX_IMAGE", "env/override:latest")
|
|
defer os.Unsetenv("YAO_SANDBOX_IMAGE")
|
|
|
|
cfg := &Config{
|
|
Image: "preset/image:v1",
|
|
}
|
|
cfg.Init("/tmp/yao-test")
|
|
|
|
// Env should win
|
|
if cfg.Image != "env/override:latest" {
|
|
t.Errorf("expected Image 'env/override:latest' (from env), got '%s'", cfg.Image)
|
|
}
|
|
}
|