6d0d63cb23
Conjunto completo de funciones SSH para operaciones remotas: conexión, verificación de host, ejecución de comandos, transferencia de archivos (upload/download) y gestión de túneles. Incluye tipo SSHConn y tests. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
61 lines
1.4 KiB
Go
61 lines
1.4 KiB
Go
package infra
|
|
|
|
import (
|
|
"strings"
|
|
"testing"
|
|
)
|
|
|
|
func TestSSHExec(t *testing.T) {
|
|
conn := skipIfNoSSH(t)
|
|
|
|
t.Run("echo simple", func(t *testing.T) {
|
|
stdout, stderr, code, err := SSHExec(conn, "echo hello")
|
|
if err != nil {
|
|
t.Fatalf("SSHExec error: %v", err)
|
|
}
|
|
if code != 0 {
|
|
t.Errorf("exit code = %d, want 0; stderr: %s", code, stderr)
|
|
}
|
|
if strings.TrimSpace(stdout) != "hello" {
|
|
t.Errorf("stdout = %q, want %q", strings.TrimSpace(stdout), "hello")
|
|
}
|
|
})
|
|
|
|
t.Run("captura stderr", func(t *testing.T) {
|
|
_, stderr, code, err := SSHExec(conn, "echo error >&2")
|
|
if err != nil {
|
|
t.Fatalf("SSHExec error: %v", err)
|
|
}
|
|
if code != 0 {
|
|
t.Errorf("exit code = %d, want 0", code)
|
|
}
|
|
if !strings.Contains(stderr, "error") {
|
|
t.Errorf("stderr = %q, want contener 'error'", stderr)
|
|
}
|
|
})
|
|
|
|
t.Run("exit code no cero", func(t *testing.T) {
|
|
_, _, code, err := SSHExec(conn, "exit 42")
|
|
if err != nil {
|
|
t.Fatalf("SSHExec error: %v", err)
|
|
}
|
|
if code != 42 {
|
|
t.Errorf("exit code = %d, want 42", code)
|
|
}
|
|
})
|
|
|
|
t.Run("comando multilinea", func(t *testing.T) {
|
|
stdout, _, code, err := SSHExec(conn, "hostname && uname -s")
|
|
if err != nil {
|
|
t.Fatalf("SSHExec error: %v", err)
|
|
}
|
|
if code != 0 {
|
|
t.Errorf("exit code = %d, want 0", code)
|
|
}
|
|
lines := strings.Split(strings.TrimSpace(stdout), "\n")
|
|
if len(lines) < 2 {
|
|
t.Errorf("esperaba al menos 2 lineas, got %d: %q", len(lines), stdout)
|
|
}
|
|
})
|
|
}
|