Claude의 단일 Anthropic 요청 안에서 IOP가 Plan, Work, Review와 workspace 도구 실행을 끝내고 실제 dev smoke로 계약을 검증할 수 있어야 한다.\n\n완료 task evidence와 마일스톤 검토 상태도 같은 변경에 고정한다.
174 lines
8.7 KiB
Go
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)
|
|
}
|
|
}
|
|
}
|