Fix tests

This commit is contained in:
2025-10-25 00:14:42 +02:00
parent 58f8861d17
commit 6a973fae2d
3 changed files with 201 additions and 143 deletions

View File

@@ -11,26 +11,29 @@ import (
) )
func TestNewInstance(t *testing.T) { func TestNewInstance(t *testing.T) {
backendConfig := &config.BackendConfig{ globalConfig := &config.AppConfig{
LlamaCpp: config.BackendSettings{ Backends: config.BackendConfig{
Command: "llama-server", LlamaCpp: config.BackendSettings{
Args: []string{}, Command: "llama-server",
Args: []string{},
},
MLX: config.BackendSettings{
Command: "mlx_lm.server",
Args: []string{},
},
VLLM: config.BackendSettings{
Command: "vllm",
Args: []string{"serve"},
},
}, },
MLX: config.BackendSettings{ Instances: config.InstancesConfig{
Command: "mlx_lm.server", LogsDir: "/tmp/test",
Args: []string{}, DefaultAutoRestart: true,
DefaultMaxRestarts: 3,
DefaultRestartDelay: 5,
}, },
VLLM: config.BackendSettings{ Nodes: map[string]config.NodeConfig{},
Command: "vllm", LocalNode: "main",
Args: []string{"serve"},
},
}
globalSettings := &config.InstancesConfig{
LogsDir: "/tmp/test",
DefaultAutoRestart: true,
DefaultMaxRestarts: 3,
DefaultRestartDelay: 5,
} }
options := &instance.Options{ options := &instance.Options{
@@ -46,7 +49,7 @@ func TestNewInstance(t *testing.T) {
// Mock onStatusChange function // Mock onStatusChange function
mockOnStatusChange := func(oldStatus, newStatus instance.Status) {} mockOnStatusChange := func(oldStatus, newStatus instance.Status) {}
inst := instance.New("test-instance", backendConfig, globalSettings, options, "main", mockOnStatusChange) inst := instance.New("test-instance", globalConfig, options, mockOnStatusChange)
if inst.Name != "test-instance" { if inst.Name != "test-instance" {
t.Errorf("Expected name 'test-instance', got %q", inst.Name) t.Errorf("Expected name 'test-instance', got %q", inst.Name)
@@ -79,8 +82,8 @@ func TestNewInstance(t *testing.T) {
autoRestart := false autoRestart := false
maxRestarts := 10 maxRestarts := 10
optionsWithOverrides := &instance.Options{ optionsWithOverrides := &instance.Options{
AutoRestart: &autoRestart, AutoRestart: &autoRestart,
MaxRestarts: &maxRestarts, MaxRestarts: &maxRestarts,
BackendOptions: backends.Options{ BackendOptions: backends.Options{
BackendType: backends.BackendTypeLlamaCpp, BackendType: backends.BackendTypeLlamaCpp,
LlamaServerOptions: &backends.LlamaServerOptions{ LlamaServerOptions: &backends.LlamaServerOptions{
@@ -89,7 +92,7 @@ func TestNewInstance(t *testing.T) {
}, },
} }
inst2 := instance.New("test-override", backendConfig, globalSettings, optionsWithOverrides, "main", mockOnStatusChange) inst2 := instance.New("test-override", globalConfig, optionsWithOverrides, mockOnStatusChange)
opts2 := inst2.GetOptions() opts2 := inst2.GetOptions()
if opts2.AutoRestart == nil || *opts2.AutoRestart { if opts2.AutoRestart == nil || *opts2.AutoRestart {
@@ -101,26 +104,29 @@ func TestNewInstance(t *testing.T) {
} }
func TestSetOptions(t *testing.T) { func TestSetOptions(t *testing.T) {
backendConfig := &config.BackendConfig{ globalConfig := &config.AppConfig{
LlamaCpp: config.BackendSettings{ Backends: config.BackendConfig{
Command: "llama-server", LlamaCpp: config.BackendSettings{
Args: []string{}, Command: "llama-server",
Args: []string{},
},
MLX: config.BackendSettings{
Command: "mlx_lm.server",
Args: []string{},
},
VLLM: config.BackendSettings{
Command: "vllm",
Args: []string{"serve"},
},
}, },
MLX: config.BackendSettings{ Instances: config.InstancesConfig{
Command: "mlx_lm.server", LogsDir: "/tmp/test",
Args: []string{}, DefaultAutoRestart: true,
DefaultMaxRestarts: 3,
DefaultRestartDelay: 5,
}, },
VLLM: config.BackendSettings{ Nodes: map[string]config.NodeConfig{},
Command: "vllm", LocalNode: "main",
Args: []string{"serve"},
},
}
globalSettings := &config.InstancesConfig{
LogsDir: "/tmp/test",
DefaultAutoRestart: true,
DefaultMaxRestarts: 3,
DefaultRestartDelay: 5,
} }
initialOptions := &instance.Options{ initialOptions := &instance.Options{
@@ -136,7 +142,7 @@ func TestSetOptions(t *testing.T) {
// Mock onStatusChange function // Mock onStatusChange function
mockOnStatusChange := func(oldStatus, newStatus instance.Status) {} mockOnStatusChange := func(oldStatus, newStatus instance.Status) {}
inst := instance.New("test-instance", backendConfig, globalSettings, initialOptions, "main", mockOnStatusChange) inst := instance.New("test-instance", globalConfig, initialOptions, mockOnStatusChange)
// Update options // Update options
newOptions := &instance.Options{ newOptions := &instance.Options{
@@ -166,23 +172,26 @@ func TestSetOptions(t *testing.T) {
} }
func TestGetProxy(t *testing.T) { func TestGetProxy(t *testing.T) {
backendConfig := &config.BackendConfig{ globalConfig := &config.AppConfig{
LlamaCpp: config.BackendSettings{ Backends: config.BackendConfig{
Command: "llama-server", LlamaCpp: config.BackendSettings{
Args: []string{}, Command: "llama-server",
Args: []string{},
},
MLX: config.BackendSettings{
Command: "mlx_lm.server",
Args: []string{},
},
VLLM: config.BackendSettings{
Command: "vllm",
Args: []string{"serve"},
},
}, },
MLX: config.BackendSettings{ Instances: config.InstancesConfig{
Command: "mlx_lm.server", LogsDir: "/tmp/test",
Args: []string{},
}, },
VLLM: config.BackendSettings{ Nodes: map[string]config.NodeConfig{},
Command: "vllm", LocalNode: "main",
Args: []string{"serve"},
},
}
globalSettings := &config.InstancesConfig{
LogsDir: "/tmp/test",
} }
options := &instance.Options{ options := &instance.Options{
@@ -199,7 +208,7 @@ func TestGetProxy(t *testing.T) {
// Mock onStatusChange function // Mock onStatusChange function
mockOnStatusChange := func(oldStatus, newStatus instance.Status) {} mockOnStatusChange := func(oldStatus, newStatus instance.Status) {}
inst := instance.New("test-instance", backendConfig, globalSettings, options, "main", mockOnStatusChange) inst := instance.New("test-instance", globalConfig, options, mockOnStatusChange)
// Get proxy for the first time // Get proxy for the first time
proxy1, err := inst.GetProxy() proxy1, err := inst.GetProxy()
@@ -221,10 +230,14 @@ func TestGetProxy(t *testing.T) {
} }
func TestMarshalJSON(t *testing.T) { func TestMarshalJSON(t *testing.T) {
backendConfig := &config.BackendConfig{ globalConfig := &config.AppConfig{
LlamaCpp: config.BackendSettings{Command: "llama-server"}, Backends: config.BackendConfig{
LlamaCpp: config.BackendSettings{Command: "llama-server"},
},
Instances: config.InstancesConfig{LogsDir: "/tmp/test"},
Nodes: map[string]config.NodeConfig{},
LocalNode: "main",
} }
globalSettings := &config.InstancesConfig{LogsDir: "/tmp/test"}
options := &instance.Options{ options := &instance.Options{
BackendOptions: backends.Options{ BackendOptions: backends.Options{
BackendType: backends.BackendTypeLlamaCpp, BackendType: backends.BackendTypeLlamaCpp,
@@ -235,7 +248,7 @@ func TestMarshalJSON(t *testing.T) {
}, },
} }
inst := instance.New("test-instance", backendConfig, globalSettings, options, "main", nil) inst := instance.New("test-instance", globalConfig, options, nil)
data, err := json.Marshal(inst) data, err := json.Marshal(inst)
if err != nil { if err != nil {
@@ -342,23 +355,26 @@ func TestCreateOptionsValidation(t *testing.T) {
}, },
} }
backendConfig := &config.BackendConfig{ globalConfig := &config.AppConfig{
LlamaCpp: config.BackendSettings{ Backends: config.BackendConfig{
Command: "llama-server", LlamaCpp: config.BackendSettings{
Args: []string{}, Command: "llama-server",
Args: []string{},
},
MLX: config.BackendSettings{
Command: "mlx_lm.server",
Args: []string{},
},
VLLM: config.BackendSettings{
Command: "vllm",
Args: []string{"serve"},
},
}, },
MLX: config.BackendSettings{ Instances: config.InstancesConfig{
Command: "mlx_lm.server", LogsDir: "/tmp/test",
Args: []string{},
}, },
VLLM: config.BackendSettings{ Nodes: map[string]config.NodeConfig{},
Command: "vllm", LocalNode: "main",
Args: []string{"serve"},
},
}
globalSettings := &config.InstancesConfig{
LogsDir: "/tmp/test",
} }
for _, tt := range tests { for _, tt := range tests {
@@ -377,7 +393,7 @@ func TestCreateOptionsValidation(t *testing.T) {
// Mock onStatusChange function // Mock onStatusChange function
mockOnStatusChange := func(oldStatus, newStatus instance.Status) {} mockOnStatusChange := func(oldStatus, newStatus instance.Status) {}
instance := instance.New("test", backendConfig, globalSettings, options, "main", mockOnStatusChange) instance := instance.New("test", globalConfig, options, mockOnStatusChange)
opts := instance.GetOptions() opts := instance.GetOptions()
if opts.MaxRestarts == nil { if opts.MaxRestarts == nil {
@@ -396,10 +412,14 @@ func TestCreateOptionsValidation(t *testing.T) {
} }
func TestStatusChangeCallback(t *testing.T) { func TestStatusChangeCallback(t *testing.T) {
backendConfig := &config.BackendConfig{ globalConfig := &config.AppConfig{
LlamaCpp: config.BackendSettings{Command: "llama-server"}, Backends: config.BackendConfig{
LlamaCpp: config.BackendSettings{Command: "llama-server"},
},
Instances: config.InstancesConfig{LogsDir: "/tmp/test"},
Nodes: map[string]config.NodeConfig{},
LocalNode: "main",
} }
globalSettings := &config.InstancesConfig{LogsDir: "/tmp/test"}
options := &instance.Options{ options := &instance.Options{
BackendOptions: backends.Options{ BackendOptions: backends.Options{
BackendType: backends.BackendTypeLlamaCpp, BackendType: backends.BackendTypeLlamaCpp,
@@ -418,7 +438,7 @@ func TestStatusChangeCallback(t *testing.T) {
callbackCalled = true callbackCalled = true
} }
inst := instance.New("test", backendConfig, globalSettings, options, "main", onStatusChange) inst := instance.New("test", globalConfig, options, onStatusChange)
inst.SetStatus(instance.Running) inst.SetStatus(instance.Running)
@@ -434,10 +454,14 @@ func TestStatusChangeCallback(t *testing.T) {
} }
func TestSetOptions_NodesPreserved(t *testing.T) { func TestSetOptions_NodesPreserved(t *testing.T) {
backendConfig := &config.BackendConfig{ globalConfig := &config.AppConfig{
LlamaCpp: config.BackendSettings{Command: "llama-server"}, Backends: config.BackendConfig{
LlamaCpp: config.BackendSettings{Command: "llama-server"},
},
Instances: config.InstancesConfig{LogsDir: "/tmp/test"},
Nodes: map[string]config.NodeConfig{},
LocalNode: "main",
} }
globalSettings := &config.InstancesConfig{LogsDir: "/tmp/test"}
tests := []struct { tests := []struct {
name string name string
@@ -477,7 +501,7 @@ func TestSetOptions_NodesPreserved(t *testing.T) {
}, },
} }
inst := instance.New("test", backendConfig, globalSettings, options, "main", nil) inst := instance.New("test", globalConfig, options, nil)
// Attempt to update nodes (should be ignored) // Attempt to update nodes (should be ignored)
updateOptions := &instance.Options{ updateOptions := &instance.Options{
@@ -512,10 +536,14 @@ func TestSetOptions_NodesPreserved(t *testing.T) {
} }
func TestProcessErrorCases(t *testing.T) { func TestProcessErrorCases(t *testing.T) {
backendConfig := &config.BackendConfig{ globalConfig := &config.AppConfig{
LlamaCpp: config.BackendSettings{Command: "llama-server"}, Backends: config.BackendConfig{
LlamaCpp: config.BackendSettings{Command: "llama-server"},
},
Instances: config.InstancesConfig{LogsDir: "/tmp/test"},
Nodes: map[string]config.NodeConfig{},
LocalNode: "main",
} }
globalSettings := &config.InstancesConfig{LogsDir: "/tmp/test"}
options := &instance.Options{ options := &instance.Options{
BackendOptions: backends.Options{ BackendOptions: backends.Options{
BackendType: backends.BackendTypeLlamaCpp, BackendType: backends.BackendTypeLlamaCpp,
@@ -525,7 +553,7 @@ func TestProcessErrorCases(t *testing.T) {
}, },
} }
inst := instance.New("test", backendConfig, globalSettings, options, "main", nil) inst := instance.New("test", globalConfig, options, nil)
// Stop when not running should return error // Stop when not running should return error
err := inst.Stop() err := inst.Stop()
@@ -544,10 +572,14 @@ func TestProcessErrorCases(t *testing.T) {
} }
func TestRemoteInstanceOperations(t *testing.T) { func TestRemoteInstanceOperations(t *testing.T) {
backendConfig := &config.BackendConfig{ globalConfig := &config.AppConfig{
LlamaCpp: config.BackendSettings{Command: "llama-server"}, Backends: config.BackendConfig{
LlamaCpp: config.BackendSettings{Command: "llama-server"},
},
Instances: config.InstancesConfig{LogsDir: "/tmp/test"},
Nodes: map[string]config.NodeConfig{},
LocalNode: "main",
} }
globalSettings := &config.InstancesConfig{LogsDir: "/tmp/test"}
options := &instance.Options{ options := &instance.Options{
Nodes: map[string]struct{}{"remote-node": {}}, // Remote instance Nodes: map[string]struct{}{"remote-node": {}}, // Remote instance
BackendOptions: backends.Options{ BackendOptions: backends.Options{
@@ -558,7 +590,7 @@ func TestRemoteInstanceOperations(t *testing.T) {
}, },
} }
inst := instance.New("remote-test", backendConfig, globalSettings, options, "main", nil) inst := instance.New("remote-test", globalConfig, options, nil)
if !inst.IsRemote() { if !inst.IsRemote() {
t.Error("Expected instance to be remote") t.Error("Expected instance to be remote")
@@ -591,14 +623,18 @@ func TestRemoteInstanceOperations(t *testing.T) {
} }
func TestIdleTimeout(t *testing.T) { func TestIdleTimeout(t *testing.T) {
backendConfig := &config.BackendConfig{ globalConfig := &config.AppConfig{
LlamaCpp: config.BackendSettings{Command: "llama-server"}, Backends: config.BackendConfig{
LlamaCpp: config.BackendSettings{Command: "llama-server"},
},
Instances: config.InstancesConfig{LogsDir: "/tmp/test"},
Nodes: map[string]config.NodeConfig{},
LocalNode: "main",
} }
globalSettings := &config.InstancesConfig{LogsDir: "/tmp/test"}
t.Run("not running never times out", func(t *testing.T) { t.Run("not running never times out", func(t *testing.T) {
timeout := 1 timeout := 1
inst := instance.New("test", backendConfig, globalSettings, &instance.Options{ inst := instance.New("test", globalConfig, &instance.Options{
IdleTimeout: &timeout, IdleTimeout: &timeout,
BackendOptions: backends.Options{ BackendOptions: backends.Options{
BackendType: backends.BackendTypeLlamaCpp, BackendType: backends.BackendTypeLlamaCpp,
@@ -606,7 +642,7 @@ func TestIdleTimeout(t *testing.T) {
Model: "/path/to/model.gguf", Model: "/path/to/model.gguf",
}, },
}, },
}, "main", nil) }, nil)
if inst.ShouldTimeout() { if inst.ShouldTimeout() {
t.Error("Non-running instance should never timeout") t.Error("Non-running instance should never timeout")
@@ -614,7 +650,7 @@ func TestIdleTimeout(t *testing.T) {
}) })
t.Run("no timeout configured", func(t *testing.T) { t.Run("no timeout configured", func(t *testing.T) {
inst := instance.New("test", backendConfig, globalSettings, &instance.Options{ inst := instance.New("test", globalConfig, &instance.Options{
IdleTimeout: nil, // No timeout IdleTimeout: nil, // No timeout
BackendOptions: backends.Options{ BackendOptions: backends.Options{
BackendType: backends.BackendTypeLlamaCpp, BackendType: backends.BackendTypeLlamaCpp,
@@ -622,7 +658,7 @@ func TestIdleTimeout(t *testing.T) {
Model: "/path/to/model.gguf", Model: "/path/to/model.gguf",
}, },
}, },
}, "main", nil) }, nil)
inst.SetStatus(instance.Running) inst.SetStatus(instance.Running)
if inst.ShouldTimeout() { if inst.ShouldTimeout() {
@@ -632,15 +668,17 @@ func TestIdleTimeout(t *testing.T) {
t.Run("timeout exceeded", func(t *testing.T) { t.Run("timeout exceeded", func(t *testing.T) {
timeout := 1 // 1 minute timeout := 1 // 1 minute
inst := instance.New("test", backendConfig, globalSettings, &instance.Options{ inst := instance.New("test", globalConfig, &instance.Options{
IdleTimeout: &timeout, IdleTimeout: &timeout,
BackendOptions: backends.Options{ BackendOptions: backends.Options{
BackendType: backends.BackendTypeLlamaCpp, BackendType: backends.BackendTypeLlamaCpp,
LlamaServerOptions: &backends.LlamaServerOptions{ LlamaServerOptions: &backends.LlamaServerOptions{
Model: "/path/to/model.gguf", Model: "/path/to/model.gguf",
Host: "localhost",
Port: 8080,
}, },
}, },
}, "main", nil) }, nil)
inst.SetStatus(instance.Running) inst.SetStatus(instance.Running)
// Use mock time provider // Use mock time provider

View File

@@ -14,11 +14,10 @@ import (
func TestManager_PersistsAndLoadsInstances(t *testing.T) { func TestManager_PersistsAndLoadsInstances(t *testing.T) {
tempDir := t.TempDir() tempDir := t.TempDir()
cfg := createPersistenceConfig(tempDir) appConfig := createTestAppConfig(tempDir)
backendConfig := createBackendConfig()
// Create instance and check file was created // Create instance and check file was created
manager1 := manager.New(backendConfig, cfg, map[string]config.NodeConfig{}, "main") manager1 := manager.New(appConfig)
options := &instance.Options{ options := &instance.Options{
BackendOptions: backends.Options{ BackendOptions: backends.Options{
BackendType: backends.BackendTypeLlamaCpp, BackendType: backends.BackendTypeLlamaCpp,
@@ -40,7 +39,7 @@ func TestManager_PersistsAndLoadsInstances(t *testing.T) {
} }
// Load instances from disk // Load instances from disk
manager2 := manager.New(backendConfig, cfg, map[string]config.NodeConfig{}, "main") manager2 := manager.New(appConfig)
instances, err := manager2.ListInstances() instances, err := manager2.ListInstances()
if err != nil { if err != nil {
t.Fatalf("ListInstances failed: %v", err) t.Fatalf("ListInstances failed: %v", err)
@@ -55,10 +54,9 @@ func TestManager_PersistsAndLoadsInstances(t *testing.T) {
func TestDeleteInstance_RemovesPersistenceFile(t *testing.T) { func TestDeleteInstance_RemovesPersistenceFile(t *testing.T) {
tempDir := t.TempDir() tempDir := t.TempDir()
cfg := createPersistenceConfig(tempDir) appConfig := createTestAppConfig(tempDir)
backendConfig := createBackendConfig()
mgr := manager.New(backendConfig, cfg, map[string]config.NodeConfig{}, "main") mgr := manager.New(appConfig)
options := &instance.Options{ options := &instance.Options{
BackendOptions: backends.Options{ BackendOptions: backends.Options{
BackendType: backends.BackendTypeLlamaCpp, BackendType: backends.BackendTypeLlamaCpp,
@@ -135,39 +133,57 @@ func TestConcurrentAccess(t *testing.T) {
} }
// Helper functions for test configuration // Helper functions for test configuration
func createBackendConfig() config.BackendConfig { func createTestAppConfig(instancesDir string) *config.AppConfig {
// Use 'sleep' as a test command instead of 'llama-server' // Use 'sleep' as a test command instead of 'llama-server'
// This allows tests to run in CI environments without requiring actual LLM binaries // This allows tests to run in CI environments without requiring actual LLM binaries
// The sleep command will be invoked with model paths and other args, which it ignores // The sleep command will be invoked with model paths and other args, which it ignores
return config.BackendConfig{ return &config.AppConfig{
LlamaCpp: config.BackendSettings{ Backends: config.BackendConfig{
Command: "sleep", LlamaCpp: config.BackendSettings{
Command: "sleep",
},
MLX: config.BackendSettings{
Command: "sleep",
},
}, },
MLX: config.BackendSettings{ Instances: config.InstancesConfig{
Command: "sleep", PortRange: [2]int{8000, 9000},
InstancesDir: instancesDir,
LogsDir: instancesDir,
MaxInstances: 10,
MaxRunningInstances: 10,
DefaultAutoRestart: true,
DefaultMaxRestarts: 3,
DefaultRestartDelay: 5,
TimeoutCheckInterval: 5,
}, },
} LocalNode: "main",
} Nodes: map[string]config.NodeConfig{},
func createPersistenceConfig(dir string) config.InstancesConfig {
return config.InstancesConfig{
PortRange: [2]int{8000, 9000},
InstancesDir: dir,
MaxInstances: 10,
TimeoutCheckInterval: 5,
} }
} }
func createTestManager() manager.InstanceManager { func createTestManager() manager.InstanceManager {
cfg := config.InstancesConfig{ appConfig := &config.AppConfig{
PortRange: [2]int{8000, 9000}, Backends: config.BackendConfig{
LogsDir: "/tmp/test", LlamaCpp: config.BackendSettings{
MaxInstances: 10, Command: "sleep",
MaxRunningInstances: 10, },
DefaultAutoRestart: true, MLX: config.BackendSettings{
DefaultMaxRestarts: 3, Command: "sleep",
DefaultRestartDelay: 5, },
TimeoutCheckInterval: 5, },
Instances: config.InstancesConfig{
PortRange: [2]int{8000, 9000},
LogsDir: "/tmp/test",
MaxInstances: 10,
MaxRunningInstances: 10,
DefaultAutoRestart: true,
DefaultMaxRestarts: 3,
DefaultRestartDelay: 5,
TimeoutCheckInterval: 5,
},
LocalNode: "main",
Nodes: map[string]config.NodeConfig{},
} }
return manager.New(createBackendConfig(), cfg, map[string]config.NodeConfig{}, "main") return manager.New(appConfig)
} }

View File

@@ -36,17 +36,21 @@ func TestCreateInstance_FailsWithDuplicateName(t *testing.T) {
} }
func TestCreateInstance_FailsWhenMaxInstancesReached(t *testing.T) { func TestCreateInstance_FailsWhenMaxInstancesReached(t *testing.T) {
backendConfig := config.BackendConfig{ appConfig := &config.AppConfig{
LlamaCpp: config.BackendSettings{ Backends: config.BackendConfig{
Command: "llama-server", LlamaCpp: config.BackendSettings{
Command: "llama-server",
},
}, },
Instances: config.InstancesConfig{
PortRange: [2]int{8000, 9000},
MaxInstances: 1, // Very low limit for testing
TimeoutCheckInterval: 5,
},
LocalNode: "main",
Nodes: map[string]config.NodeConfig{},
} }
cfg := config.InstancesConfig{ limitedManager := manager.New(appConfig)
PortRange: [2]int{8000, 9000},
MaxInstances: 1, // Very low limit for testing
TimeoutCheckInterval: 5,
}
limitedManager := manager.New(backendConfig, cfg, map[string]config.NodeConfig{}, "main")
options := &instance.Options{ options := &instance.Options{
BackendOptions: backends.Options{ BackendOptions: backends.Options{