mirror of
https://github.com/samsonjs/vibetunnel.git
synced 2026-03-26 09:35:52 +00:00
- Fix hanging TestNewStdinWatcher by not calling Stop() without Start() - Fix TestSession_Signal and TestSession_KillWithSignal by adding PID values - Fix isProcessRunning to use syscall.Signal(0) instead of os.Signal(nil) - Update websocket test to expect new 'Unknown WebSocket endpoint' error message - Add timeout handling to websocket integration test
274 lines
5.7 KiB
Go
274 lines
5.7 KiB
Go
package session
|
|
|
|
import (
|
|
"io"
|
|
"os"
|
|
"path/filepath"
|
|
"testing"
|
|
"time"
|
|
)
|
|
|
|
func TestNewStdinWatcher(t *testing.T) {
|
|
// Create temporary directory for testing
|
|
tmpDir := t.TempDir()
|
|
|
|
// Create a named pipe
|
|
pipePath := filepath.Join(tmpDir, "stdin")
|
|
if err := os.MkdirAll(filepath.Dir(pipePath), 0755); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
// Create the pipe file (will be a regular file in tests)
|
|
if err := os.WriteFile(pipePath, []byte{}, 0644); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
// Create a mock PTY file
|
|
ptyFile, err := os.CreateTemp(tmpDir, "pty")
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
defer ptyFile.Close()
|
|
|
|
// Test creating stdin watcher
|
|
watcher, err := NewStdinWatcher(pipePath, ptyFile)
|
|
if err != nil {
|
|
t.Fatalf("NewStdinWatcher() error = %v", err)
|
|
}
|
|
defer func() {
|
|
// Only stop if it was started
|
|
if watcher.watcher != nil {
|
|
watcher.watcher.Close()
|
|
}
|
|
if watcher.stdinFile != nil {
|
|
watcher.stdinFile.Close()
|
|
}
|
|
}()
|
|
|
|
if watcher.stdinPath != pipePath {
|
|
t.Errorf("stdinPath = %v, want %v", watcher.stdinPath, pipePath)
|
|
}
|
|
if watcher.ptyFile != ptyFile {
|
|
t.Errorf("ptyFile = %v, want %v", watcher.ptyFile, ptyFile)
|
|
}
|
|
if watcher.watcher == nil {
|
|
t.Error("watcher should not be nil")
|
|
}
|
|
if watcher.stdinFile == nil {
|
|
t.Error("stdinFile should not be nil")
|
|
}
|
|
}
|
|
|
|
func TestStdinWatcher_StartStop(t *testing.T) {
|
|
// Create temporary directory for testing
|
|
tmpDir := t.TempDir()
|
|
|
|
// Create a named pipe
|
|
pipePath := filepath.Join(tmpDir, "stdin")
|
|
if err := os.WriteFile(pipePath, []byte{}, 0644); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
// Create a mock PTY file
|
|
ptyFile, err := os.CreateTemp(tmpDir, "pty")
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
defer ptyFile.Close()
|
|
|
|
watcher, err := NewStdinWatcher(pipePath, ptyFile)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
// Start the watcher
|
|
watcher.Start()
|
|
|
|
// Give it a moment to start
|
|
time.Sleep(10 * time.Millisecond)
|
|
|
|
// Stop the watcher
|
|
done := make(chan bool)
|
|
go func() {
|
|
watcher.Stop()
|
|
done <- true
|
|
}()
|
|
|
|
// Should stop quickly
|
|
select {
|
|
case <-done:
|
|
// Success
|
|
case <-time.After(1 * time.Second):
|
|
t.Error("Stop() took too long")
|
|
}
|
|
}
|
|
|
|
func TestStdinWatcher_HandleStdinData(t *testing.T) {
|
|
// Create temporary directory for testing
|
|
tmpDir := t.TempDir()
|
|
|
|
// Create a named pipe path
|
|
pipePath := filepath.Join(tmpDir, "stdin")
|
|
|
|
// Create PTY pipe for reading what's written
|
|
ptyReader, ptyWriter, err := os.Pipe()
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
defer ptyReader.Close()
|
|
defer ptyWriter.Close()
|
|
|
|
// Create stdin file
|
|
stdinFile, err := os.Create(pipePath)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
defer stdinFile.Close()
|
|
|
|
// Create watcher
|
|
watcher := &StdinWatcher{
|
|
stdinPath: pipePath,
|
|
ptyFile: ptyWriter,
|
|
stdinFile: stdinFile,
|
|
buffer: make([]byte, 4096),
|
|
stopChan: make(chan struct{}),
|
|
stoppedChan: make(chan struct{}),
|
|
}
|
|
|
|
// Write test data to stdin
|
|
testData := []byte("Hello, World!")
|
|
if _, err := stdinFile.Write(testData); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if _, err := stdinFile.Seek(0, 0); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
// Handle the data
|
|
watcher.handleStdinData()
|
|
|
|
// Read from PTY to verify data was forwarded
|
|
result := make([]byte, len(testData))
|
|
if _, err := io.ReadFull(ptyReader, result); err != nil {
|
|
t.Fatalf("Failed to read forwarded data: %v", err)
|
|
}
|
|
|
|
if string(result) != string(testData) {
|
|
t.Errorf("Forwarded data = %q, want %q", result, testData)
|
|
}
|
|
}
|
|
|
|
func TestIsEAGAIN(t *testing.T) {
|
|
tests := []struct {
|
|
name string
|
|
err error
|
|
expected bool
|
|
}{
|
|
{
|
|
name: "nil error",
|
|
err: nil,
|
|
expected: false,
|
|
},
|
|
{
|
|
name: "EAGAIN error",
|
|
err: &os.PathError{Err: os.NewSyscallError("read", os.ErrDeadlineExceeded)},
|
|
expected: false, // Our simple implementation checks string
|
|
},
|
|
{
|
|
name: "other error",
|
|
err: io.EOF,
|
|
expected: false,
|
|
},
|
|
}
|
|
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
result := isEAGAIN(tt.err)
|
|
if result != tt.expected {
|
|
t.Errorf("isEAGAIN() = %v, want %v", result, tt.expected)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestStdinWatcher_Cleanup(t *testing.T) {
|
|
// Create temporary directory for testing
|
|
tmpDir := t.TempDir()
|
|
|
|
// Create a named pipe
|
|
pipePath := filepath.Join(tmpDir, "stdin")
|
|
if err := os.WriteFile(pipePath, []byte{}, 0644); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
// Create a mock PTY file
|
|
ptyFile, err := os.CreateTemp(tmpDir, "pty")
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
defer ptyFile.Close()
|
|
|
|
watcher, err := NewStdinWatcher(pipePath, ptyFile)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
// Store references to check if closed
|
|
stdinFile := watcher.stdinFile
|
|
fsWatcher := watcher.watcher
|
|
|
|
// Clean up
|
|
watcher.cleanup()
|
|
|
|
// Verify files are closed
|
|
if err := stdinFile.Close(); err == nil {
|
|
t.Error("stdinFile should have been closed")
|
|
}
|
|
|
|
// Verify watcher is closed by trying to add a path
|
|
if err := fsWatcher.Add("/tmp"); err == nil {
|
|
t.Error("fsnotify watcher should have been closed")
|
|
}
|
|
}
|
|
|
|
func BenchmarkStdinWatcher_HandleData(b *testing.B) {
|
|
// Create temporary directory for testing
|
|
tmpDir := b.TempDir()
|
|
|
|
// Create pipes
|
|
_, ptyWriter, err := os.Pipe()
|
|
if err != nil {
|
|
b.Fatal(err)
|
|
}
|
|
defer ptyWriter.Close()
|
|
|
|
// Create stdin file with data
|
|
stdinPath := filepath.Join(tmpDir, "stdin")
|
|
testData := []byte("This is test data for benchmarking stdin handling\n")
|
|
|
|
b.ResetTimer()
|
|
for i := 0; i < b.N; i++ {
|
|
// Create fresh stdin file each time
|
|
stdinFile, err := os.Create(stdinPath)
|
|
if err != nil {
|
|
b.Fatal(err)
|
|
}
|
|
|
|
if _, err := stdinFile.Write(testData); err != nil {
|
|
b.Fatal(err)
|
|
}
|
|
if _, err := stdinFile.Seek(0, 0); err != nil {
|
|
b.Fatal(err)
|
|
}
|
|
|
|
watcher := &StdinWatcher{
|
|
stdinPath: stdinPath,
|
|
ptyFile: ptyWriter,
|
|
stdinFile: stdinFile,
|
|
buffer: make([]byte, 4096),
|
|
}
|
|
|
|
watcher.handleStdinData()
|
|
stdinFile.Close()
|
|
}
|
|
}
|