Major Improvements: - Added retry deployment buttons in machine list for failed deployments - Added retry button in SSH console modal footer for enhanced UX - Enhanced deployment process with comprehensive cleanup of existing services - Improved binary installation with password-based sudo authentication - Updated configuration generation to include all required sections (agent, ai, network, security) - Fixed deployment verification and error handling Security Enhancements: - Enhanced verifiedStopExistingServices with thorough cleanup process - Improved binary copying with proper sudo authentication - Added comprehensive configuration validation UX Improvements: - Users can retry deployments without re-running machine discovery - Retry buttons available from both machine list and console modal - Real-time deployment progress with detailed console output - Clear error states with actionable retry options Technical Changes: - Modified ServiceDeployment.tsx with retry button components - Enhanced api/setup_manager.go with improved deployment functions - Updated main.go with command line argument support (--config, --setup) - Added comprehensive zero-trust security validation system 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
198 lines
4.7 KiB
Go
198 lines
4.7 KiB
Go
package runtime
|
|
|
|
import (
|
|
"context"
|
|
"testing"
|
|
"time"
|
|
)
|
|
|
|
// MockLogger implements logging.Logger interface for testing
|
|
type MockLogger struct {
|
|
messages []string
|
|
}
|
|
|
|
func (m *MockLogger) Info(format string, args ...interface{}) {
|
|
m.messages = append(m.messages, "INFO")
|
|
}
|
|
|
|
func (m *MockLogger) Warn(format string, args ...interface{}) {
|
|
m.messages = append(m.messages, "WARN")
|
|
}
|
|
|
|
func (m *MockLogger) Error(format string, args ...interface{}) {
|
|
m.messages = append(m.messages, "ERROR")
|
|
}
|
|
|
|
func TestRuntimeTypes(t *testing.T) {
|
|
// Test BinaryType enum
|
|
agent := BinaryTypeAgent
|
|
hap := BinaryTypeHAP
|
|
|
|
if agent.String() != "agent" {
|
|
t.Errorf("Expected 'agent', got %s", agent.String())
|
|
}
|
|
|
|
if hap.String() != "hap" {
|
|
t.Errorf("Expected 'hap', got %s", hap.String())
|
|
}
|
|
|
|
// Test RuntimeError
|
|
err := NewRuntimeError(ErrConfigInvalid, "test", BinaryTypeAgent, "test error", nil)
|
|
if err.Code != ErrConfigInvalid {
|
|
t.Errorf("Expected ErrConfigInvalid, got %v", err.Code)
|
|
}
|
|
|
|
if err.BinaryType != BinaryTypeAgent {
|
|
t.Errorf("Expected BinaryTypeAgent, got %v", err.BinaryType)
|
|
}
|
|
|
|
if err.Error() != "test error" {
|
|
t.Errorf("Expected 'test error', got %s", err.Error())
|
|
}
|
|
}
|
|
|
|
func TestRuntimeInterface(t *testing.T) {
|
|
// Test that we can create a runtime instance
|
|
logger := &MockLogger{}
|
|
runtime := NewRuntime(logger)
|
|
|
|
if runtime == nil {
|
|
t.Fatal("Expected non-nil runtime")
|
|
}
|
|
|
|
// Test that the runtime implements the Runtime interface
|
|
var _ Runtime = runtime
|
|
}
|
|
|
|
func TestConfigValidator(t *testing.T) {
|
|
// Test config validator creation
|
|
validator := NewConfigValidator(BinaryTypeAgent)
|
|
if validator == nil {
|
|
t.Fatal("Expected non-nil validator")
|
|
}
|
|
|
|
if validator.binaryType != BinaryTypeAgent {
|
|
t.Errorf("Expected BinaryTypeAgent, got %v", validator.binaryType)
|
|
}
|
|
}
|
|
|
|
func TestTaskTracker(t *testing.T) {
|
|
// Test task tracker creation and basic operations
|
|
tracker := NewTaskTracker(5, "test-node", nil).(*TaskTracker)
|
|
|
|
if tracker.GetMaxTasks() != 5 {
|
|
t.Errorf("Expected max tasks 5, got %d", tracker.GetMaxTasks())
|
|
}
|
|
|
|
// Test task operations
|
|
tracker.AddTask("task1")
|
|
tasks := tracker.GetActiveTasks()
|
|
if len(tasks) != 1 {
|
|
t.Errorf("Expected 1 active task, got %d", len(tasks))
|
|
}
|
|
|
|
if !tracker.IsAvailable() {
|
|
t.Error("Expected tracker to be available")
|
|
}
|
|
|
|
status := tracker.GetStatus()
|
|
if status != "working" {
|
|
t.Errorf("Expected status 'working', got %s", status)
|
|
}
|
|
|
|
// Remove task
|
|
tracker.RemoveTask("task1")
|
|
tasks = tracker.GetActiveTasks()
|
|
if len(tasks) != 0 {
|
|
t.Errorf("Expected 0 active tasks, got %d", len(tasks))
|
|
}
|
|
|
|
status = tracker.GetStatus()
|
|
if status != "ready" {
|
|
t.Errorf("Expected status 'ready', got %s", status)
|
|
}
|
|
}
|
|
|
|
func TestCapabilityAnnouncer(t *testing.T) {
|
|
// Test capability announcer creation
|
|
announcer := NewCapabilityAnnouncer(nil, "test-node")
|
|
if announcer == nil {
|
|
t.Fatal("Expected non-nil announcer")
|
|
}
|
|
|
|
if announcer.nodeID != "test-node" {
|
|
t.Errorf("Expected node ID 'test-node', got %s", announcer.nodeID)
|
|
}
|
|
}
|
|
|
|
func TestStatusReporter(t *testing.T) {
|
|
// Test status reporter creation
|
|
reporter := NewStatusReporter(nil)
|
|
if reporter == nil {
|
|
t.Fatal("Expected non-nil reporter")
|
|
}
|
|
}
|
|
|
|
// Test that our architecture properly separates concerns
|
|
func TestArchitectureSeparation(t *testing.T) {
|
|
// Test that we can create runtime components independently
|
|
logger := &MockLogger{}
|
|
|
|
// Runtime
|
|
runtime := NewRuntime(logger)
|
|
if runtime == nil {
|
|
t.Fatal("Failed to create runtime")
|
|
}
|
|
|
|
// Config validator
|
|
agentValidator := NewConfigValidator(BinaryTypeAgent)
|
|
hapValidator := NewConfigValidator(BinaryTypeHAP)
|
|
|
|
if agentValidator.binaryType == hapValidator.binaryType {
|
|
t.Error("Expected different binary types for validators")
|
|
}
|
|
|
|
// Task tracker
|
|
tracker := NewTaskTracker(3, "test", nil)
|
|
if tracker.GetMaxTasks() != 3 {
|
|
t.Error("Task tracker not properly initialized")
|
|
}
|
|
|
|
// Capability announcer
|
|
announcer := NewCapabilityAnnouncer(nil, "test")
|
|
if announcer.nodeID != "test" {
|
|
t.Error("Announcer not properly initialized")
|
|
}
|
|
|
|
t.Log("✅ All runtime components can be created independently")
|
|
}
|
|
|
|
// Benchmark basic operations
|
|
func BenchmarkTaskTrackerOperations(b *testing.B) {
|
|
tracker := NewTaskTracker(100, "bench-node", nil).(*TaskTracker)
|
|
|
|
b.Run("AddTask", func(b *testing.B) {
|
|
for i := 0; i < b.N; i++ {
|
|
taskID := "task-" + string(rune(i))
|
|
tracker.AddTask(taskID)
|
|
}
|
|
})
|
|
|
|
b.Run("GetActiveTasks", func(b *testing.B) {
|
|
for i := 0; i < b.N; i++ {
|
|
_ = tracker.GetActiveTasks()
|
|
}
|
|
})
|
|
|
|
b.Run("GetStatus", func(b *testing.B) {
|
|
for i := 0; i < b.N; i++ {
|
|
_ = tracker.GetStatus()
|
|
}
|
|
})
|
|
}
|
|
|
|
func BenchmarkRuntimeErrorCreation(b *testing.B) {
|
|
for i := 0; i < b.N; i++ {
|
|
_ = NewRuntimeError(ErrConfigInvalid, "test", BinaryTypeAgent, "error", nil)
|
|
}
|
|
} |