iop/apps/node/internal/adapters/cli/terminal_session_test.go
toki f01c7e5ecd refactor(node): CLI 실행 경계를 정리한다
터미널 세션 core와 CLI mode executor 경계를 분리해 후속 remote terminal bridge가 재사용할 내부 실행 기반을 만든다.

adapter 기본값과 vLLM experimental surface도 명시해 production 실행 경로가 mock fallback이나 미구현 실행으로 숨지 않게 한다.
2026-06-06 14:57:49 +09:00

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")
}
}