// Package tests provides E2E tests for TUI SSH usability testing package tests import ( "strings" "testing" "time" testfixtures "github.com/jfraeys/fetch_ml/tests/fixtures" ) // TestTUI_SSHBasicConnectivity verifies SSH connection and basic command execution func TestTUI_SSHBasicConnectivity(t *testing.T) { t.Parallel() server := testfixtures.NewSSHTestServer(t) // Test basic command execution output, err := server.Exec("echo 'SSH connection successful'") if err != nil { t.Fatalf("Failed to execute command over SSH: %v", err) } if !strings.Contains(output, "SSH connection successful") { t.Errorf("Expected SSH output not found. Got: %s", output) } } // TestTUI_TERMPropagation verifies TERM variable is propagated correctly func TestTUI_TERMPropagation(t *testing.T) { t.Parallel() server := testfixtures.NewSSHTestServer(t) // Check TERM variable output, err := server.Exec("echo TERM=$TERM") if err != nil { t.Fatalf("Failed to check TERM: %v", err) } // Should have a TERM value set if !strings.Contains(output, "TERM=") { t.Errorf("TERM not set in SSH session. Got: %s", output) } t.Logf("TERM value: %s", strings.TrimSpace(output)) } // TestTUI_CaddyConnectivity verifies TUI can reach API through Caddy func TestTUI_CaddyConnectivity(t *testing.T) { t.Parallel() server := testfixtures.NewSSHTestServer(t) // Test API health through Caddy (TUI connects to Caddy on port 80) output, err := server.Exec("curl -s http://caddy:80/health") if err != nil { // Try direct API connection as fallback output, err = server.Exec("curl -s http://api-server:9101/health") if err != nil { t.Skipf("API not reachable from SSH container. Ensure docker-compose services are running: %v", err) } } if !strings.Contains(output, `"status":"healthy"`) && !strings.Contains(output, `healthy`) { t.Errorf("API health check failed. Got: %s", output) } } // TestTUI_WebSocketViaCaddy verifies WebSocket proxy through Caddy works func TestTUI_WebSocketViaCaddy(t *testing.T) { t.Parallel() server := testfixtures.NewSSHTestServer(t) // Test WebSocket upgrade works through Caddy output, err := server.Exec("curl -i -N -H 'Connection: Upgrade' -H 'Upgrade: websocket' http://caddy:80/ws/status 2>&1 | head -20") if err != nil { // Direct API test as fallback output, err = server.Exec("curl -i -N -H 'Connection: Upgrade' -H 'Upgrade: websocket' http://api-server:9101/ws/status 2>&1 | head -20") if err != nil { t.Skipf("WebSocket test skipped - services may not be running: %v", err) } } // Should see upgrade headers or connection if !strings.Contains(output, "Upgrade") && !strings.Contains(output, "101") { t.Logf("WebSocket response: %s", output) } } // TestTUI_TUIConfigExists verifies TUI config is mounted correctly func TestTUI_TUIConfigExists(t *testing.T) { t.Parallel() server := testfixtures.NewSSHTestServer(t) // Check TUI config exists output, err := server.Exec("cat /config/.ml/config.toml") if err != nil { t.Fatalf("TUI config not found in SSH container: %v", err) } // Verify config content requiredFields := []string{"worker_host", "worker_port", "worker_user"} for _, field := range requiredFields { if !strings.Contains(output, field) { t.Errorf("Config missing required field: %s", field) } } t.Logf("TUI config:\n%s", output) } // TestTUI_TUIRuns verifies TUI binary executes without errors func TestTUI_TUIRuns(t *testing.T) { t.Parallel() server := testfixtures.NewSSHTestServer(t) // Verify TUI binary exists and is executable output, err := server.Exec("ls -la /usr/local/bin/tui") if err != nil { t.Fatalf("TUI binary not found: %v", err) } if !strings.Contains(output, "tui") { t.Errorf("TUI binary not found. Got: %s", output) } // Test TUI can start (help/version check) // Note: Full TUI test requires PTY which is in integration tests output, err = server.Exec("file /usr/local/bin/tui") if err == nil { t.Logf("TUI binary info: %s", strings.TrimSpace(output)) } } // TestTUI_PTYSession tests PTY allocation for interactive TUI func TestTUI_PTYSession(t *testing.T) { t.Parallel() server := testfixtures.NewSSHTestServer(t) // Create PTY session session, err := server.ExecWithPTY("echo 'PTY test'", "xterm-256color", 80, 24) if err != nil { t.Skipf("PTY session failed - SSH server may not support PTY: %v", err) } defer session.Close() // Wait for command to complete done := make(chan error, 1) go func() { done <- session.Wait() }() select { case err := <-done: if err != nil { t.Logf("PTY session completed with error (may be expected): %v", err) } case <-time.After(5 * time.Second): t.Log("PTY session timed out") } } // TestTUI_TerminfoAvailable verifies terminfo database is available func TestTUI_TerminfoAvailable(t *testing.T) { t.Parallel() server := testfixtures.NewSSHTestServer(t) // Check for terminfo output, err := server.Exec("ls /usr/share/terminfo/x/ | head -5") if err != nil { t.Logf("terminfo check: %v", err) } else { t.Logf("Available terminfo entries: %s", strings.TrimSpace(output)) } // Check tput works output, err = server.Exec("tput colors 2>/dev/null || echo 'tput not available'") t.Logf("Color support: %s", strings.TrimSpace(output)) }