8ea4b6e990
- Add SSH client with Connect/Execute/Close/IsConnected - Implement password, key, and both authentication methods - Support default key discovery (~/.ssh/id_ed25519, id_rsa, etc.) - Support passphrase-protected keys via ParsePrivateKeyWithPassphrase - Path expansion for ~ in KeyID - Integrate with HandleSSHError for user-friendly errors - All 4 SSH tests passing + 5 error tests still passing (9 total) Progress: Tasks 1-5 complete (~40%)
106 lines
2.3 KiB
Go
106 lines
2.3 KiB
Go
package ssh_test
|
|
|
|
import (
|
|
"context"
|
|
"testing"
|
|
"time"
|
|
|
|
"git.tukangketik.id/swanadiva/hostkeeper/internal/models"
|
|
"git.tukangketik.id/swanadiva/hostkeeper/pkg/ssh"
|
|
)
|
|
|
|
func TestNewClient(t *testing.T) {
|
|
host := &models.Host{
|
|
ID: "test-host",
|
|
Name: "Test Server",
|
|
Hostname: "localhost",
|
|
Port: 22,
|
|
Username: "testuser",
|
|
Auth: models.AuthConfig{
|
|
Type: "password",
|
|
Password: "testpass",
|
|
},
|
|
}
|
|
|
|
client := ssh.NewClient(host, 30*time.Second)
|
|
if client == nil {
|
|
t.Fatal("Failed to create SSH client")
|
|
}
|
|
|
|
if client.IsConnected() {
|
|
t.Error("Expected client to not be connected initially")
|
|
}
|
|
|
|
// Close should be safe even when not connected
|
|
if err := client.Close(); err != nil {
|
|
t.Errorf("Expected nil error on close when not connected, got %v", err)
|
|
}
|
|
}
|
|
|
|
func TestConnectFailure(t *testing.T) {
|
|
// Test connecting to a non-existent server
|
|
host := &models.Host{
|
|
ID: "test-host",
|
|
Name: "Non-existent Server",
|
|
Hostname: "127.0.0.1",
|
|
Port: 9999, // Port that's likely not running SSH
|
|
Username: "testuser",
|
|
Auth: models.AuthConfig{
|
|
Type: "password",
|
|
Password: "testpass",
|
|
},
|
|
}
|
|
|
|
client := ssh.NewClient(host, 2*time.Second)
|
|
ctx := context.Background()
|
|
err := client.Connect(ctx)
|
|
|
|
// We expect connection to fail
|
|
if err == nil {
|
|
t.Log("Connection succeeded (unexpected - SSH server may be running on port 9999)")
|
|
_ = client.Close()
|
|
} else {
|
|
t.Logf("Connection failed as expected: %v", err)
|
|
}
|
|
}
|
|
|
|
func TestExecuteWithoutConnection(t *testing.T) {
|
|
host := &models.Host{
|
|
ID: "test-host",
|
|
Name: "Test Server",
|
|
Hostname: "localhost",
|
|
Port: 22,
|
|
Username: "testuser",
|
|
Auth: models.AuthConfig{
|
|
Type: "password",
|
|
Password: "testpass",
|
|
},
|
|
}
|
|
|
|
client := ssh.NewClient(host, 30*time.Second)
|
|
ctx := context.Background()
|
|
|
|
_, err := client.Execute(ctx, "echo hello")
|
|
if err == nil {
|
|
t.Error("Expected error when executing command without connection")
|
|
}
|
|
}
|
|
|
|
func TestGetClient(t *testing.T) {
|
|
host := &models.Host{
|
|
ID: "test-host",
|
|
Name: "Test Server",
|
|
Hostname: "localhost",
|
|
Port: 22,
|
|
Username: "testuser",
|
|
Auth: models.AuthConfig{
|
|
Type: "password",
|
|
Password: "testpass",
|
|
},
|
|
}
|
|
|
|
client := ssh.NewClient(host, 30*time.Second)
|
|
if client.GetClient() != nil {
|
|
t.Error("Expected nil underlying client before connecting")
|
|
}
|
|
} |