alt/apps/cli/internal/cli/cli_test.go
toki 1c11a17eff feat: operator headless workflow validation and backtest support
- Implement backtest workflow validation for headless operator mode
- Add handoff evidence tracking for backtest runs
- Update operator client, runner, scenario, and output modules
- Add test files for handoff, backtest runner, and error handling
- Add test data for backtest scenarios and validation
2026-06-01 13:21:20 +09:00

81 lines
3 KiB
Go

package cli
import (
"bytes"
"path/filepath"
"strings"
"testing"
)
func TestRunVersion(t *testing.T) {
var stdout, stderr bytes.Buffer
code := Run([]string{"version"}, &stdout, &stderr)
if code != 0 {
t.Fatalf("exit code = %d, want 0 (stderr=%q)", code, stderr.String())
}
if got := strings.TrimSpace(stdout.String()); got != "alt dev" {
t.Errorf("stdout = %q, want \"alt dev\"", got)
}
}
func TestRunScenarioValidate(t *testing.T) {
path := filepath.Join("..", "..", "testdata", "operator", "api_connection_smoke.yaml")
var stdout, stderr bytes.Buffer
code := Run([]string{"operator", "scenario", "validate", "--file", path}, &stdout, &stderr)
if code != 0 {
t.Fatalf("exit code = %d, want 0 (stderr=%q)", code, stderr.String())
}
out := stdout.String()
for _, want := range []string{"scenario=api_connection_smoke", "status=valid", "steps=1"} {
if !strings.Contains(out, want) {
t.Errorf("stdout %q missing %q", out, want)
}
}
}
func TestRunScenarioValidateParseError(t *testing.T) {
path := filepath.Join("..", "..", "testdata", "operator", "malformed_scenario.yaml")
var stdout, stderr bytes.Buffer
code := Run([]string{"operator", "scenario", "validate", "--file", path}, &stdout, &stderr)
if code != 2 {
t.Fatalf("exit code = %d, want 2 (stdout=%q stderr=%q)", code, stdout.String(), stderr.String())
}
if !strings.Contains(stdout.String(), "status=parse_error") {
t.Errorf("stdout %q missing status=parse_error", stdout.String())
}
}
func TestRunScenarioRunRequiresFlags(t *testing.T) {
// Missing --file (and --api-url) is a flag/usage error: exit code 2.
var stdout, stderr bytes.Buffer
code := Run([]string{"operator", "scenario", "run"}, &stdout, &stderr)
if code != 2 {
t.Fatalf("exit code = %d, want 2 (stderr=%q)", code, stderr.String())
}
}
func TestRunScenarioRunParseError(t *testing.T) {
path := filepath.Join("..", "..", "testdata", "operator", "malformed_scenario.yaml")
var stdout, stderr bytes.Buffer
code := Run([]string{"operator", "scenario", "run", "--file", path, "--api-url", "ws://127.0.0.1:8080/socket"}, &stdout, &stderr)
if code != 2 {
t.Fatalf("exit code = %d, want 2 (stdout=%q stderr=%q)", code, stdout.String(), stderr.String())
}
if !strings.Contains(stdout.String(), "status=parse_error") {
t.Errorf("stdout %q missing status=parse_error", stdout.String())
}
}
func TestRunScenarioRunTransportFailure(t *testing.T) {
// Port 1 is closed for inbound app traffic on localhost, so the dial fails
// before any typed response and the run reports a transport error.
path := filepath.Join("..", "..", "testdata", "operator", "api_connection_smoke.yaml")
var stdout, stderr bytes.Buffer
code := Run([]string{"operator", "scenario", "run", "--file", path, "--api-url", "ws://127.0.0.1:1/socket", "--timeout", "2s"}, &stdout, &stderr)
if code != 3 {
t.Fatalf("exit code = %d, want 3 (stdout=%q stderr=%q)", code, stdout.String(), stderr.String())
}
if !strings.Contains(stdout.String(), "status=transport_error") {
t.Errorf("stdout %q missing status=transport_error", stdout.String())
}
}