wraith/internal/rdp/service_test.go
Vantz Stockwell 8a096d7f7b
Some checks failed
Build & Sign Wraith / Build Windows + Sign (push) Has been cancelled
Wraith v0.1.0 — Desktop SSH + RDP + SFTP Client
Go + Wails v3 + Vue 3 + SQLite + FreeRDP3 (purego)
183 tests, 76 source files, 9,910 lines of code

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-17 08:19:29 -04:00

256 lines
6.7 KiB
Go

package rdp
import "testing"
func TestNewRDPService(t *testing.T) {
svc := NewRDPService(func() RDPBackend { return NewMockBackend() })
if svc == nil {
t.Fatal("NewRDPService returned nil")
}
if len(svc.ListSessions()) != 0 {
t.Error("new service should have no sessions")
}
}
func TestConnectWithMockBackend(t *testing.T) {
svc := NewRDPService(func() RDPBackend { return NewMockBackend() })
config := RDPConfig{
Hostname: "test-host",
Port: 3389,
Username: "admin",
Width: 1024,
Height: 768,
}
sessionID, err := svc.Connect(config, 42)
if err != nil {
t.Fatalf("Connect error: %v", err)
}
if sessionID == "" {
t.Fatal("Connect returned empty session ID")
}
// Verify session is tracked
sessions := svc.ListSessions()
if len(sessions) != 1 {
t.Fatalf("expected 1 session, got %d", len(sessions))
}
if sessions[0].ID != sessionID {
t.Errorf("session ID = %q, want %q", sessions[0].ID, sessionID)
}
if sessions[0].ConnID != 42 {
t.Errorf("ConnID = %d, want 42", sessions[0].ConnID)
}
if sessions[0].Config.Hostname != "test-host" {
t.Errorf("Hostname = %q, want %q", sessions[0].Config.Hostname, "test-host")
}
}
func TestConnectDefaults(t *testing.T) {
svc := NewRDPService(func() RDPBackend { return NewMockBackend() })
// Connect with zero values — should get defaults
config := RDPConfig{Hostname: "host"}
sessionID, err := svc.Connect(config, 1)
if err != nil {
t.Fatalf("Connect error: %v", err)
}
info, err := svc.GetSessionInfo(sessionID)
if err != nil {
t.Fatalf("GetSessionInfo error: %v", err)
}
if info.Config.Port != 3389 {
t.Errorf("default Port = %d, want 3389", info.Config.Port)
}
if info.Config.Width != 1920 {
t.Errorf("default Width = %d, want 1920", info.Config.Width)
}
if info.Config.Height != 1080 {
t.Errorf("default Height = %d, want 1080", info.Config.Height)
}
if info.Config.ColorDepth != 32 {
t.Errorf("default ColorDepth = %d, want 32", info.Config.ColorDepth)
}
if info.Config.Security != "nla" {
t.Errorf("default Security = %q, want %q", info.Config.Security, "nla")
}
}
func TestDisconnect(t *testing.T) {
svc := NewRDPService(func() RDPBackend { return NewMockBackend() })
config := RDPConfig{Hostname: "host", Width: 800, Height: 600}
sessionID, err := svc.Connect(config, 1)
if err != nil {
t.Fatalf("Connect error: %v", err)
}
if err := svc.Disconnect(sessionID); err != nil {
t.Fatalf("Disconnect error: %v", err)
}
if len(svc.ListSessions()) != 0 {
t.Error("expected 0 sessions after disconnect")
}
// Verify double-disconnect returns error
if err := svc.Disconnect(sessionID); err == nil {
t.Error("expected error on double disconnect")
}
}
func TestDisconnectNotFound(t *testing.T) {
svc := NewRDPService(func() RDPBackend { return NewMockBackend() })
if err := svc.Disconnect("nonexistent"); err == nil {
t.Error("expected error for nonexistent session")
}
}
func TestSessionTracking(t *testing.T) {
svc := NewRDPService(func() RDPBackend { return NewMockBackend() })
config := RDPConfig{Hostname: "host", Width: 640, Height: 480}
id1, _ := svc.Connect(config, 1)
id2, _ := svc.Connect(config, 2)
id3, _ := svc.Connect(config, 3)
if len(svc.ListSessions()) != 3 {
t.Fatalf("expected 3 sessions, got %d", len(svc.ListSessions()))
}
// Disconnect middle session
if err := svc.Disconnect(id2); err != nil {
t.Fatalf("Disconnect error: %v", err)
}
sessions := svc.ListSessions()
if len(sessions) != 2 {
t.Fatalf("expected 2 sessions, got %d", len(sessions))
}
// Verify remaining sessions
ids := make(map[string]bool)
for _, s := range sessions {
ids[s.ID] = true
}
if !ids[id1] || !ids[id3] {
t.Error("remaining sessions should be id1 and id3")
}
}
func TestSendMouse(t *testing.T) {
svc := NewRDPService(func() RDPBackend { return NewMockBackend() })
config := RDPConfig{Hostname: "host", Width: 800, Height: 600}
sessionID, _ := svc.Connect(config, 1)
if err := svc.SendMouse(sessionID, 100, 200, MouseFlagMove); err != nil {
t.Errorf("SendMouse error: %v", err)
}
if err := svc.SendMouse(sessionID, 100, 200, MouseFlagButton1|MouseFlagDown); err != nil {
t.Errorf("SendMouse click error: %v", err)
}
}
func TestSendMouseNotFound(t *testing.T) {
svc := NewRDPService(func() RDPBackend { return NewMockBackend() })
if err := svc.SendMouse("nonexistent", 0, 0, 0); err == nil {
t.Error("expected error for nonexistent session")
}
}
func TestSendKey(t *testing.T) {
svc := NewRDPService(func() RDPBackend { return NewMockBackend() })
config := RDPConfig{Hostname: "host", Width: 800, Height: 600}
sessionID, _ := svc.Connect(config, 1)
// Send key down
sc, _ := JSKeyToScancode("KeyA")
if err := svc.SendKey(sessionID, sc, true); err != nil {
t.Errorf("SendKey down error: %v", err)
}
// Send key up
if err := svc.SendKey(sessionID, sc, false); err != nil {
t.Errorf("SendKey up error: %v", err)
}
}
func TestSendKeyNotFound(t *testing.T) {
svc := NewRDPService(func() RDPBackend { return NewMockBackend() })
if err := svc.SendKey("nonexistent", 0x001E, true); err == nil {
t.Error("expected error for nonexistent session")
}
}
func TestSendClipboard(t *testing.T) {
svc := NewRDPService(func() RDPBackend { return NewMockBackend() })
config := RDPConfig{Hostname: "host", Width: 800, Height: 600}
sessionID, _ := svc.Connect(config, 1)
if err := svc.SendClipboard(sessionID, "hello clipboard"); err != nil {
t.Errorf("SendClipboard error: %v", err)
}
}
func TestGetFrame(t *testing.T) {
svc := NewRDPService(func() RDPBackend { return NewMockBackend() })
config := RDPConfig{Hostname: "host", Width: 100, Height: 100}
sessionID, _ := svc.Connect(config, 1)
frame, err := svc.GetFrame(sessionID)
if err != nil {
t.Fatalf("GetFrame error: %v", err)
}
expectedLen := 100 * 100 * 4
if len(frame) != expectedLen {
t.Errorf("frame length = %d, want %d", len(frame), expectedLen)
}
// Verify the frame is not all zeros (mock generates colored content)
allZero := true
for _, b := range frame {
if b != 0 {
allZero = false
break
}
}
if allZero {
t.Error("mock frame should not be all zeros")
}
}
func TestGetFrameNotFound(t *testing.T) {
svc := NewRDPService(func() RDPBackend { return NewMockBackend() })
_, err := svc.GetFrame("nonexistent")
if err == nil {
t.Error("expected error for nonexistent session")
}
}
func TestIsConnected(t *testing.T) {
svc := NewRDPService(func() RDPBackend { return NewMockBackend() })
config := RDPConfig{Hostname: "host", Width: 800, Height: 600}
sessionID, _ := svc.Connect(config, 1)
if !svc.IsConnected(sessionID) {
t.Error("session should be connected")
}
svc.Disconnect(sessionID)
if svc.IsConnected(sessionID) {
t.Error("session should not be connected after disconnect")
}
}