165 lines
3.6 KiB
Go
165 lines
3.6 KiB
Go
package toolsrv_test
|
|
|
|
import (
|
|
"context"
|
|
"net"
|
|
"os"
|
|
"path/filepath"
|
|
"testing"
|
|
"time"
|
|
|
|
"ollie/toolsrv"
|
|
)
|
|
|
|
// TestSocketSpawnAndDial verifies the full lifecycle:
|
|
// spawn ollie-remote → dial the socket → call RPCs → close.
|
|
func TestSocketSpawnAndDial(t *testing.T) {
|
|
// Skip if ollie-remote binary not available.
|
|
if _, err := findBinary(); err != nil {
|
|
t.Skipf("ollie-remote not found: %v", err)
|
|
}
|
|
|
|
ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
|
|
defer cancel()
|
|
|
|
cwd, err := os.Getwd()
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
// Spawn the toolsrv subprocess.
|
|
proc, err := toolsrv.Spawn(ctx, cwd, toolsrv.WithYolo())
|
|
if err != nil {
|
|
t.Fatalf("Spawn: %v", err)
|
|
}
|
|
defer proc.Close()
|
|
|
|
if proc.Socket == "" {
|
|
t.Fatal("expected non-empty socket path")
|
|
}
|
|
|
|
// Verify socket file exists.
|
|
if _, err := os.Stat(proc.Socket); err != nil {
|
|
t.Fatalf("socket file not found: %v", err)
|
|
}
|
|
|
|
// Dial a connection.
|
|
conn, err := toolsrv.Dial(ctx, proc.Socket)
|
|
if err != nil {
|
|
t.Fatalf("Dial: %v", err)
|
|
}
|
|
defer conn.Close()
|
|
|
|
// Ping.
|
|
if err := conn.Ping(); err != nil {
|
|
t.Fatalf("Ping: %v", err)
|
|
}
|
|
|
|
// FetchHostInfo.
|
|
info, err := conn.FetchHostInfo()
|
|
if err != nil {
|
|
t.Fatalf("FetchHostInfo: %v", err)
|
|
}
|
|
if info.Platform == "" {
|
|
t.Error("expected non-empty platform")
|
|
}
|
|
|
|
// SetEnv (fire-and-forget, just verify no crash).
|
|
conn.SetEnv("TEST_KEY", "test_value")
|
|
|
|
// SetCWD.
|
|
conn.SetCWD("/tmp")
|
|
|
|
// ListTools. The remote server starts with no promoted tools; tools are
|
|
// loaded dynamically through the session tool registry.
|
|
if _, err := conn.ListTools(); err != nil {
|
|
t.Fatalf("ListTools: %v", err)
|
|
}
|
|
}
|
|
|
|
// TestSocketMultipleClients verifies multiple clients can connect simultaneously.
|
|
func TestSocketMultipleClients(t *testing.T) {
|
|
if _, err := findBinary(); err != nil {
|
|
t.Skipf("ollie-remote not found: %v", err)
|
|
}
|
|
|
|
ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
|
|
defer cancel()
|
|
|
|
cwd, err := os.Getwd()
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
proc, err := toolsrv.Spawn(ctx, cwd, toolsrv.WithYolo())
|
|
if err != nil {
|
|
t.Fatalf("Spawn: %v", err)
|
|
}
|
|
defer proc.Close()
|
|
|
|
// Dial three clients concurrently.
|
|
conns := make([]*toolsrv.Conn, 3)
|
|
for i := range conns {
|
|
c, err := toolsrv.Dial(ctx, proc.Socket)
|
|
if err != nil {
|
|
t.Fatalf("Dial[%d]: %v", i, err)
|
|
}
|
|
conns[i] = c
|
|
}
|
|
|
|
// Each client can ping independently.
|
|
for i, c := range conns {
|
|
if err := c.Ping(); err != nil {
|
|
t.Errorf("Ping[%d]: %v", i, err)
|
|
}
|
|
}
|
|
|
|
// Close all.
|
|
for _, c := range conns {
|
|
c.Close()
|
|
}
|
|
}
|
|
|
|
// TestSocketCleanup verifies the socket is removed after Close.
|
|
func TestSocketCleanup(t *testing.T) {
|
|
if _, err := findBinary(); err != nil {
|
|
t.Skipf("ollie-remote not found: %v", err)
|
|
}
|
|
|
|
ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
|
|
defer cancel()
|
|
|
|
cwd, err := os.Getwd()
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
proc, err := toolsrv.Spawn(ctx, cwd, toolsrv.WithYolo())
|
|
if err != nil {
|
|
t.Fatalf("Spawn: %v", err)
|
|
}
|
|
sockPath := proc.Socket
|
|
proc.Close()
|
|
|
|
// Socket should be cleaned up.
|
|
time.Sleep(100 * time.Millisecond)
|
|
if _, err := net.DialTimeout("unix", sockPath, time.Second); err == nil {
|
|
t.Error("expected socket to be removed after Close")
|
|
}
|
|
}
|
|
|
|
// findBinary checks if ollie-remote is available.
|
|
func findBinary() (string, error) {
|
|
home, _ := os.UserHomeDir()
|
|
candidates := []string{
|
|
filepath.Join(home, "bin", "ollie-remote"),
|
|
filepath.Join(home, ".local", "bin", "ollie-remote"),
|
|
}
|
|
for _, p := range candidates {
|
|
if _, err := os.Stat(p); err == nil {
|
|
return p, nil
|
|
}
|
|
}
|
|
return "", os.ErrNotExist
|
|
}
|