iop/packages/go/workspaceprotocol/terminal_test.go
toki d7a150c7fe feat(agent): 단일 요청 실행 경로를 완성한다
Claude의 단일 Anthropic 요청 안에서 IOP가 Plan, Work, Review와 workspace 도구 실행을 끝내고 실제 dev smoke로 계약을 검증할 수 있어야 한다.\n\n완료 task evidence와 마일스톤 검토 상태도 같은 변경에 고정한다.
2026-08-08 23:35:13 +09:00

174 lines
8.7 KiB
Go

package workspaceprotocol_test
import (
"testing"
"iop/packages/go/workspaceprotocol"
iop "iop/proto/gen/iop"
)
func TestWorkspaceTerminalTool(t *testing.T) {
valid := []struct {
status iop.WorkspaceStatus
code iop.WorkspaceErrorCode
message string
}{
{iop.WorkspaceStatus_WORKSPACE_STATUS_SUCCESS, iop.WorkspaceErrorCode_WORKSPACE_ERROR_CODE_UNSPECIFIED, ""},
{iop.WorkspaceStatus_WORKSPACE_STATUS_UNSUPPORTED, iop.WorkspaceErrorCode_WORKSPACE_ERROR_CODE_NOT_READY, "workspace runtime not ready"},
{iop.WorkspaceStatus_WORKSPACE_STATUS_UNSUPPORTED, iop.WorkspaceErrorCode_WORKSPACE_ERROR_CODE_UNSUPPORTED, "workspace operation unsupported"},
{iop.WorkspaceStatus_WORKSPACE_STATUS_ERROR, iop.WorkspaceErrorCode_WORKSPACE_ERROR_CODE_NOT_FOUND, "workspace entry not found"},
{iop.WorkspaceStatus_WORKSPACE_STATUS_ERROR, iop.WorkspaceErrorCode_WORKSPACE_ERROR_CODE_INVALID_REQUEST, "workspace request rejected"},
{iop.WorkspaceStatus_WORKSPACE_STATUS_TIMEOUT, iop.WorkspaceErrorCode_WORKSPACE_ERROR_CODE_TIMEOUT, "workspace command timed out"},
{iop.WorkspaceStatus_WORKSPACE_STATUS_CANCELLED, iop.WorkspaceErrorCode_WORKSPACE_ERROR_CODE_CANCELLED, "workspace command cancelled"},
{iop.WorkspaceStatus_WORKSPACE_STATUS_ERROR, iop.WorkspaceErrorCode_WORKSPACE_ERROR_CODE_INTERNAL, "workspace operation failed"},
}
for _, tc := range valid {
msg, ok := workspaceprotocol.ToolTerminal(tc.status, tc.code)
if !ok || msg != tc.message {
t.Errorf("ToolTerminal(%v, %v) = (%q, %v), want (%q, true)", tc.status, tc.code, msg, ok, tc.message)
}
}
invalid := []struct {
status iop.WorkspaceStatus
code iop.WorkspaceErrorCode
}{
{iop.WorkspaceStatus_WORKSPACE_STATUS_SUCCESS, iop.WorkspaceErrorCode_WORKSPACE_ERROR_CODE_INVALID_REQUEST},
{iop.WorkspaceStatus_WORKSPACE_STATUS_SUCCESS, iop.WorkspaceErrorCode_WORKSPACE_ERROR_CODE_INTERNAL},
{iop.WorkspaceStatus_WORKSPACE_STATUS_ERROR, iop.WorkspaceErrorCode_WORKSPACE_ERROR_CODE_UNSPECIFIED},
{iop.WorkspaceStatus_WORKSPACE_STATUS_TIMEOUT, iop.WorkspaceErrorCode_WORKSPACE_ERROR_CODE_INTERNAL},
{iop.WorkspaceStatus_WORKSPACE_STATUS_CANCELLED, iop.WorkspaceErrorCode_WORKSPACE_ERROR_CODE_UNSPECIFIED},
{iop.WorkspaceStatus_WORKSPACE_STATUS_UNSUPPORTED, iop.WorkspaceErrorCode_WORKSPACE_ERROR_CODE_INVALID_REQUEST},
}
for _, tc := range invalid {
msg, ok := workspaceprotocol.ToolTerminal(tc.status, tc.code)
if ok {
t.Errorf("ToolTerminal(%v, %v) unexpectedly succeeded with %q", tc.status, tc.code, msg)
}
}
}
func TestWorkspaceTerminalCancel(t *testing.T) {
valid := []struct {
status iop.WorkspaceStatus
code iop.WorkspaceErrorCode
message string
}{
{iop.WorkspaceStatus_WORKSPACE_STATUS_CANCELLED, iop.WorkspaceErrorCode_WORKSPACE_ERROR_CODE_CANCELLED, "workspace command cancelled"},
{iop.WorkspaceStatus_WORKSPACE_STATUS_ERROR, iop.WorkspaceErrorCode_WORKSPACE_ERROR_CODE_NOT_FOUND, "workspace command not found"},
{iop.WorkspaceStatus_WORKSPACE_STATUS_ERROR, iop.WorkspaceErrorCode_WORKSPACE_ERROR_CODE_INVALID_REQUEST, "workspace cancellation rejected"},
{iop.WorkspaceStatus_WORKSPACE_STATUS_UNSUPPORTED, iop.WorkspaceErrorCode_WORKSPACE_ERROR_CODE_NOT_READY, "workspace runtime not ready"},
}
for _, tc := range valid {
msg, ok := workspaceprotocol.CancelTerminal(tc.status, tc.code)
if !ok || msg != tc.message {
t.Errorf("CancelTerminal(%v, %v) = (%q, %v), want (%q, true)", tc.status, tc.code, msg, ok, tc.message)
}
}
invalid := []struct {
status iop.WorkspaceStatus
code iop.WorkspaceErrorCode
}{
{iop.WorkspaceStatus_WORKSPACE_STATUS_SUCCESS, iop.WorkspaceErrorCode_WORKSPACE_ERROR_CODE_UNSPECIFIED},
{iop.WorkspaceStatus_WORKSPACE_STATUS_CANCELLED, iop.WorkspaceErrorCode_WORKSPACE_ERROR_CODE_UNSPECIFIED},
{iop.WorkspaceStatus_WORKSPACE_STATUS_ERROR, iop.WorkspaceErrorCode_WORKSPACE_ERROR_CODE_CANCELLED},
}
for _, tc := range invalid {
msg, ok := workspaceprotocol.CancelTerminal(tc.status, tc.code)
if ok {
t.Errorf("CancelTerminal(%v, %v) unexpectedly succeeded with %q", tc.status, tc.code, msg)
}
}
}
func TestWorkspaceTerminalArtifact(t *testing.T) {
valid := []struct {
status iop.WorkspaceStatus
code iop.WorkspaceErrorCode
message string
}{
{iop.WorkspaceStatus_WORKSPACE_STATUS_SUCCESS, iop.WorkspaceErrorCode_WORKSPACE_ERROR_CODE_UNSPECIFIED, ""},
{iop.WorkspaceStatus_WORKSPACE_STATUS_UNSUPPORTED, iop.WorkspaceErrorCode_WORKSPACE_ERROR_CODE_NOT_READY, "workspace runtime not ready"},
{iop.WorkspaceStatus_WORKSPACE_STATUS_ERROR, iop.WorkspaceErrorCode_WORKSPACE_ERROR_CODE_NOT_FOUND, "workspace artifact not found"},
{iop.WorkspaceStatus_WORKSPACE_STATUS_ERROR, iop.WorkspaceErrorCode_WORKSPACE_ERROR_CODE_INVALID_REQUEST, "workspace artifact request rejected"},
{iop.WorkspaceStatus_WORKSPACE_STATUS_ERROR, iop.WorkspaceErrorCode_WORKSPACE_ERROR_CODE_INTERNAL, "workspace artifact operation failed"},
}
for _, tc := range valid {
msg, ok := workspaceprotocol.ArtifactTerminal(tc.status, tc.code)
if !ok || msg != tc.message {
t.Errorf("ArtifactTerminal(%v, %v) = (%q, %v), want (%q, true)", tc.status, tc.code, msg, ok, tc.message)
}
}
invalid := []struct {
status iop.WorkspaceStatus
code iop.WorkspaceErrorCode
}{
{iop.WorkspaceStatus_WORKSPACE_STATUS_SUCCESS, iop.WorkspaceErrorCode_WORKSPACE_ERROR_CODE_NOT_FOUND},
{iop.WorkspaceStatus_WORKSPACE_STATUS_ERROR, iop.WorkspaceErrorCode_WORKSPACE_ERROR_CODE_UNSPECIFIED},
{iop.WorkspaceStatus_WORKSPACE_STATUS_UNSUPPORTED, iop.WorkspaceErrorCode_WORKSPACE_ERROR_CODE_UNSUPPORTED},
{iop.WorkspaceStatus_WORKSPACE_STATUS_TIMEOUT, iop.WorkspaceErrorCode_WORKSPACE_ERROR_CODE_TIMEOUT},
{iop.WorkspaceStatus_WORKSPACE_STATUS_CANCELLED, iop.WorkspaceErrorCode_WORKSPACE_ERROR_CODE_CANCELLED},
}
for _, tc := range invalid {
if msg, ok := workspaceprotocol.ArtifactTerminal(tc.status, tc.code); ok {
t.Errorf("ArtifactTerminal(%v, %v) unexpectedly succeeded with %q", tc.status, tc.code, msg)
}
}
}
func TestWorkspaceTerminalOpenAndCleanup(t *testing.T) {
if msg, ok := workspaceprotocol.OpenTerminal(iop.WorkspaceStatus_WORKSPACE_STATUS_SUCCESS, iop.WorkspaceErrorCode_WORKSPACE_ERROR_CODE_UNSPECIFIED); !ok || msg != "" {
t.Errorf("OpenTerminal success failed: (%q, %v)", msg, ok)
}
if msg, ok := workspaceprotocol.OpenTerminal(iop.WorkspaceStatus_WORKSPACE_STATUS_ERROR, iop.WorkspaceErrorCode_WORKSPACE_ERROR_CODE_INVALID_REQUEST); !ok || msg != "workspace open rejected" {
t.Errorf("OpenTerminal error failed: (%q, %v)", msg, ok)
}
if _, ok := workspaceprotocol.OpenTerminal(iop.WorkspaceStatus_WORKSPACE_STATUS_CANCELLED, iop.WorkspaceErrorCode_WORKSPACE_ERROR_CODE_CANCELLED); ok {
t.Errorf("OpenTerminal unexpectedly accepted cancelled")
}
cleanupValid := []struct {
status iop.WorkspaceStatus
code iop.WorkspaceErrorCode
message string
}{
{iop.WorkspaceStatus_WORKSPACE_STATUS_SUCCESS, iop.WorkspaceErrorCode_WORKSPACE_ERROR_CODE_UNSPECIFIED, ""},
{iop.WorkspaceStatus_WORKSPACE_STATUS_UNSUPPORTED, iop.WorkspaceErrorCode_WORKSPACE_ERROR_CODE_NOT_READY, "workspace runtime not ready"},
{iop.WorkspaceStatus_WORKSPACE_STATUS_UNSUPPORTED, iop.WorkspaceErrorCode_WORKSPACE_ERROR_CODE_UNSUPPORTED, "workspace cleanup unsupported"},
{iop.WorkspaceStatus_WORKSPACE_STATUS_ERROR, iop.WorkspaceErrorCode_WORKSPACE_ERROR_CODE_NOT_FOUND, "workspace request not found"},
{iop.WorkspaceStatus_WORKSPACE_STATUS_ERROR, iop.WorkspaceErrorCode_WORKSPACE_ERROR_CODE_INVALID_REQUEST, "workspace cleanup rejected"},
{iop.WorkspaceStatus_WORKSPACE_STATUS_TIMEOUT, iop.WorkspaceErrorCode_WORKSPACE_ERROR_CODE_TIMEOUT, "workspace cleanup timed out"},
{iop.WorkspaceStatus_WORKSPACE_STATUS_ERROR, iop.WorkspaceErrorCode_WORKSPACE_ERROR_CODE_INTERNAL, "workspace cleanup failed"},
}
for _, tc := range cleanupValid {
msg, ok := workspaceprotocol.CleanupTerminal(tc.status, tc.code)
if !ok || msg != tc.message {
t.Errorf("CleanupTerminal(%v, %v) = (%q, %v), want (%q, true)", tc.status, tc.code, msg, ok, tc.message)
}
}
cleanupInvalid := []struct {
status iop.WorkspaceStatus
code iop.WorkspaceErrorCode
}{
{iop.WorkspaceStatus_WORKSPACE_STATUS_SUCCESS, iop.WorkspaceErrorCode_WORKSPACE_ERROR_CODE_INTERNAL},
{iop.WorkspaceStatus_WORKSPACE_STATUS_ERROR, iop.WorkspaceErrorCode_WORKSPACE_ERROR_CODE_CANCELLED},
{iop.WorkspaceStatus_WORKSPACE_STATUS_UNSUPPORTED, iop.WorkspaceErrorCode_WORKSPACE_ERROR_CODE_INVALID_REQUEST},
{iop.WorkspaceStatus_WORKSPACE_STATUS_CANCELLED, iop.WorkspaceErrorCode_WORKSPACE_ERROR_CODE_CANCELLED},
{iop.WorkspaceStatus_WORKSPACE_STATUS_TIMEOUT, iop.WorkspaceErrorCode_WORKSPACE_ERROR_CODE_INVALID_REQUEST},
}
for _, tc := range cleanupInvalid {
msg, ok := workspaceprotocol.CleanupTerminal(tc.status, tc.code)
if ok {
t.Errorf("CleanupTerminal(%v, %v) unexpectedly succeeded with %q", tc.status, tc.code, msg)
}
}
}