터미널 세션 core와 CLI mode executor 경계를 분리해 후속 remote terminal bridge가 재사용할 내부 실행 기반을 만든다. adapter 기본값과 vLLM experimental surface도 명시해 production 실행 경로가 mock fallback이나 미구현 실행으로 숨지 않게 한다.
153 lines
3.7 KiB
Go
153 lines
3.7 KiB
Go
package cli
|
|
|
|
import (
|
|
"context"
|
|
"os"
|
|
"strings"
|
|
"testing"
|
|
"time"
|
|
)
|
|
|
|
func TestTerminalSessionCoreWritesPrompt(t *testing.T) {
|
|
opts := terminalSessionOptions{
|
|
Command: "sh",
|
|
}
|
|
core, err := startTerminalSessionCore(context.Background(), opts)
|
|
if err != nil {
|
|
t.Fatalf("failed to start terminal session: %v", err)
|
|
}
|
|
defer core.Close()
|
|
|
|
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
|
|
defer cancel()
|
|
|
|
// Write prompt "echo hello-world" (WritePrompt will append \r)
|
|
if err := core.WritePrompt(ctx, "echo hello-world"); err != nil {
|
|
t.Fatalf("failed to write prompt: %v", err)
|
|
}
|
|
|
|
// Wait for the output to propagate
|
|
var tail string
|
|
success := false
|
|
for {
|
|
select {
|
|
case <-ctx.Done():
|
|
t.Fatalf("timeout waiting for output. tail was: %q", tail)
|
|
case <-time.After(100 * time.Millisecond):
|
|
tail = core.Snapshot().Tail
|
|
if strings.Contains(tail, "hello-world") {
|
|
success = true
|
|
break
|
|
}
|
|
}
|
|
if success {
|
|
break
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestTerminalSessionCoreSnapshot(t *testing.T) {
|
|
opts := terminalSessionOptions{
|
|
Command: "sh",
|
|
}
|
|
core, err := startTerminalSessionCore(context.Background(), opts)
|
|
if err != nil {
|
|
t.Fatalf("failed to start terminal session: %v", err)
|
|
}
|
|
defer core.Close()
|
|
|
|
ctx, cancel := context.WithTimeout(context.Background(), 2*time.Second)
|
|
defer cancel()
|
|
|
|
if err := core.WritePrompt(ctx, "echo test-snapshot"); err != nil {
|
|
t.Fatalf("failed to write prompt: %v", err)
|
|
}
|
|
|
|
time.Sleep(200 * time.Millisecond)
|
|
snap := core.Snapshot()
|
|
if !strings.Contains(snap.Tail, "test-snapshot") {
|
|
t.Errorf("snapshot tail does not contain test-snapshot: %q", snap.Tail)
|
|
}
|
|
}
|
|
|
|
func TestTerminalSessionCoreCloseIsIdempotent(t *testing.T) {
|
|
opts := terminalSessionOptions{
|
|
Command: "sh",
|
|
}
|
|
core, err := startTerminalSessionCore(context.Background(), opts)
|
|
if err != nil {
|
|
t.Fatalf("failed to start terminal session: %v", err)
|
|
}
|
|
|
|
if err := core.Close(); err != nil {
|
|
t.Errorf("first close failed: %v", err)
|
|
}
|
|
|
|
if err := core.Close(); err != nil {
|
|
t.Errorf("second close failed: %v", err)
|
|
}
|
|
}
|
|
|
|
func TestTerminalSessionCoreResizeValidatesBounds(t *testing.T) {
|
|
opts := terminalSessionOptions{
|
|
Command: "sh",
|
|
}
|
|
core, err := startTerminalSessionCore(context.Background(), opts)
|
|
if err != nil {
|
|
t.Fatalf("failed to start terminal session: %v", err)
|
|
}
|
|
defer core.Close()
|
|
|
|
if err := core.Resize(0, 80); err == nil {
|
|
t.Error("expected error when resizing with rows=0")
|
|
}
|
|
|
|
if err := core.Resize(80, 0); err == nil {
|
|
t.Error("expected error when resizing with cols=0")
|
|
}
|
|
|
|
if err := core.Resize(40, 120); err != nil {
|
|
t.Errorf("failed to resize with valid dimensions: %v", err)
|
|
}
|
|
}
|
|
|
|
func TestTerminalSessionCoreRejectsWriteAfterClose(t *testing.T) {
|
|
opts := terminalSessionOptions{
|
|
Command: "sh",
|
|
}
|
|
core, err := startTerminalSessionCore(context.Background(), opts)
|
|
if err != nil {
|
|
t.Fatalf("failed to start terminal session: %v", err)
|
|
}
|
|
|
|
if err := core.Close(); err != nil {
|
|
t.Fatalf("close failed: %v", err)
|
|
}
|
|
|
|
ctx := context.Background()
|
|
if err := core.WritePrompt(ctx, "ls"); err == nil {
|
|
t.Error("expected WritePrompt to reject writing after close")
|
|
}
|
|
|
|
if err := core.WriteInput(ctx, []byte("ls\n")); err == nil {
|
|
t.Error("expected WriteInput to reject writing after close")
|
|
}
|
|
}
|
|
|
|
func TestTerminalSessionCoreSignalAfterClose(t *testing.T) {
|
|
opts := terminalSessionOptions{
|
|
Command: "sh",
|
|
}
|
|
core, err := startTerminalSessionCore(context.Background(), opts)
|
|
if err != nil {
|
|
t.Fatalf("failed to start terminal session: %v", err)
|
|
}
|
|
|
|
if err := core.Close(); err != nil {
|
|
t.Fatalf("close failed: %v", err)
|
|
}
|
|
|
|
if err := core.Signal(os.Interrupt); err == nil {
|
|
t.Error("expected Signal to reject signal after close")
|
|
}
|
|
}
|