217 lines
4.6 KiB
Go
217 lines
4.6 KiB
Go
package main
|
|
|
|
import (
|
|
"context"
|
|
"strings"
|
|
"testing"
|
|
"time"
|
|
)
|
|
|
|
func TestFS9P_Basic(t *testing.T) {
|
|
fs := NewFS9P("/tmp")
|
|
|
|
// Test CWD
|
|
if fs.CWD() != "/tmp" {
|
|
t.Errorf("CWD() = %q, want /tmp", fs.CWD())
|
|
}
|
|
|
|
fs.SetCWD("/home")
|
|
if fs.CWD() != "/home" {
|
|
t.Errorf("CWD() = %q, want /home", fs.CWD())
|
|
}
|
|
|
|
// Test Env
|
|
fs.SetEnv("FOO", "bar")
|
|
if fs.GetEnv("FOO") != "bar" {
|
|
t.Errorf("GetEnv(FOO) = %q, want bar", fs.GetEnv("FOO"))
|
|
}
|
|
|
|
// Test HostInfo
|
|
info := fs.HostInfo9P()
|
|
if !strings.Contains(info, "platform=") {
|
|
t.Errorf("HostInfo9P() missing platform")
|
|
}
|
|
}
|
|
|
|
func TestFS9P_ToolsWithoutRegistry(t *testing.T) {
|
|
fs := NewFS9P("/tmp")
|
|
|
|
// Without registry, ListTools should return nil
|
|
tools := fs.ListTools()
|
|
if tools != nil {
|
|
t.Errorf("ListTools() without registry = %v, want nil", tools)
|
|
}
|
|
|
|
// Load should fail without registry
|
|
err := fs.LoadTool("shell")
|
|
if err == nil {
|
|
t.Error("LoadTool without registry should fail")
|
|
}
|
|
}
|
|
|
|
func TestFS9P_HandleCtl(t *testing.T) {
|
|
fs := NewFS9P("/tmp")
|
|
|
|
// Unknown command
|
|
err := fs.HandleCtl("unknown")
|
|
if err == nil {
|
|
t.Error("HandleCtl(unknown) should fail")
|
|
}
|
|
|
|
// load without name
|
|
err = fs.HandleCtl("load")
|
|
if err == nil {
|
|
t.Error("HandleCtl(load) without name should fail")
|
|
}
|
|
|
|
// unload without name
|
|
err = fs.HandleCtl("unload")
|
|
if err == nil {
|
|
t.Error("HandleCtl(unload) without name should fail")
|
|
}
|
|
}
|
|
|
|
func TestFS9P_ProcLimit(t *testing.T) {
|
|
fs := NewFS9P("/tmp")
|
|
fs.procLimit = 2
|
|
|
|
// Create a fake registry and session ID
|
|
reg, err := NewRegistry()
|
|
if err != nil {
|
|
t.Skip("no tools directory available")
|
|
}
|
|
fs.SetRegistry(reg, "test-session")
|
|
|
|
// Load a simple tool if available
|
|
if err := reg.Load("test-session", "shell"); err != nil {
|
|
t.Skip("shell tool not available")
|
|
}
|
|
|
|
// Proc limit test would require actual tool execution
|
|
// For now just verify the limit is set
|
|
if fs.procLimit != 2 {
|
|
t.Errorf("procLimit = %d, want 2", fs.procLimit)
|
|
}
|
|
}
|
|
|
|
func TestFS9P_ParsePayload(t *testing.T) {
|
|
tests := []struct {
|
|
input string
|
|
want map[string]string
|
|
}{
|
|
{
|
|
input: "tool=shell\ncmd=ls -la\n",
|
|
want: map[string]string{"tool": "shell", "cmd": "ls -la"},
|
|
},
|
|
{
|
|
input: "key=value with spaces\n",
|
|
want: map[string]string{"key": "value with spaces"},
|
|
},
|
|
{
|
|
input: "multi=line\\none\\ntwo\n",
|
|
want: map[string]string{"multi": "line\none\ntwo"},
|
|
},
|
|
{
|
|
input: "escaped=back\\\\slash\n",
|
|
want: map[string]string{"escaped": "back\\slash"},
|
|
},
|
|
}
|
|
|
|
for _, tt := range tests {
|
|
got := parsePayload(tt.input)
|
|
for k, v := range tt.want {
|
|
if got[k] != v {
|
|
t.Errorf("parsePayload(%q)[%q] = %q, want %q", tt.input, k, got[k], v)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestFS9P_ProcLifecycle(t *testing.T) {
|
|
fs := NewFS9P("/tmp")
|
|
|
|
// No procs initially
|
|
pids := fs.ListProcs()
|
|
if len(pids) != 0 {
|
|
t.Errorf("ListProcs() = %v, want empty", pids)
|
|
}
|
|
|
|
// GetProc for non-existent
|
|
if fs.GetProc(999) != nil {
|
|
t.Error("GetProc(999) should return nil")
|
|
}
|
|
|
|
// DismissProc for non-existent
|
|
if fs.DismissProc(999) {
|
|
t.Error("DismissProc(999) should return false")
|
|
}
|
|
|
|
// SignalProc for non-existent
|
|
if err := fs.SignalProc(999, 15); err == nil {
|
|
t.Error("SignalProc(999) should fail")
|
|
}
|
|
}
|
|
|
|
func TestFS9P_HandleProcCtl(t *testing.T) {
|
|
fs := NewFS9P("/tmp")
|
|
|
|
// Unknown command
|
|
err := fs.HandleProcCtl(1, "unknown")
|
|
if err == nil {
|
|
t.Error("HandleProcCtl(unknown) should fail")
|
|
}
|
|
|
|
// signal without number
|
|
err = fs.HandleProcCtl(1, "signal")
|
|
if err == nil {
|
|
t.Error("HandleProcCtl(signal) without number should fail")
|
|
}
|
|
|
|
// signal with invalid number
|
|
err = fs.HandleProcCtl(1, "signal abc")
|
|
if err == nil {
|
|
t.Error("HandleProcCtl(signal abc) should fail")
|
|
}
|
|
|
|
// dismiss on non-existent (should succeed silently)
|
|
err = fs.HandleProcCtl(999, "dismiss")
|
|
if err != nil {
|
|
t.Errorf("HandleProcCtl(dismiss) on non-existent = %v, want nil", err)
|
|
}
|
|
}
|
|
|
|
func TestProc9P_Stat(t *testing.T) {
|
|
proc := &Proc9P{
|
|
PID: 1,
|
|
Tool: "shell",
|
|
StartTime: time.Now(),
|
|
done: make(chan struct{}),
|
|
}
|
|
|
|
// Running state
|
|
stat := proc.Stat()
|
|
if !strings.Contains(stat, "running") {
|
|
t.Errorf("Stat() for running proc should contain 'running', got %q", stat)
|
|
}
|
|
|
|
// Mark as exited
|
|
proc.Exited = true
|
|
proc.ExitCode = 0
|
|
proc.EndTime = time.Now()
|
|
|
|
stat = proc.Stat()
|
|
if !strings.Contains(stat, "exited 0") {
|
|
t.Errorf("Stat() for exited proc should contain 'exited 0', got %q", stat)
|
|
}
|
|
}
|
|
|
|
func TestFS9P_NewProcWithoutRegistry(t *testing.T) {
|
|
fs := NewFS9P("/tmp")
|
|
|
|
ctx := context.Background()
|
|
_, _, err := fs.NewProc(ctx, "tool=shell\ncmd=ls\n", false)
|
|
if err == nil {
|
|
t.Error("NewProc without registry should fail")
|
|
}
|
|
}
|