package osexec import ( "context" "errors" "strings" "testing" "time" ) func TestFakeRunnerSuccess(t *testing.T) { fr := &FakeRunner{Stdout: "ok"} ctx := context.Background() out, errOut, code, err := fr.Run(ctx, "echo", "ok") if err != nil { t.Fatalf("unexpected error: %v", err) } if out != "ok" || errOut != "" || code != 0 { t.Fatalf("expected ok, got out=%q err=%q code=%d", out, errOut, code) } } func TestExecWithFakeRunnerNonZero(t *testing.T) { fr := &FakeRunner{Stdout: "", Stderr: "fail", ExitCode: 2} ctx := context.Background() out, errOut, code, err := ExecWithRunner(fr, ctx, "false") if err == nil { t.Fatalf("expected ErrExitNonZero, got no error") } if e, ok := err.(ErrExitNonZero); !ok { t.Fatalf("expected ErrExitNonZero, got %T %v", err, err) } else if e.ExitCode != 2 { t.Fatalf("expected exit 2, got %d", e.ExitCode) } if code != 2 || out != "" || errOut != "fail" { t.Fatalf("mismatch output: code=%d out=%q err=%q", code, out, errOut) } } func TestExecWithFakeRunnerTimeout(t *testing.T) { fr := &FakeRunner{Stdout: "", Stderr: "", ExitCode: 0, Delay: 200 * time.Millisecond} ctx, cancel := context.WithTimeout(context.Background(), 50*time.Millisecond) defer cancel() _, _, _, err := ExecWithRunner(fr, ctx, "sleep") if !errors.Is(err, ErrTimeout) && err != context.DeadlineExceeded && err != context.Canceled { t.Fatalf("expected timeout error, got: %v", err) } } func TestRedact(t *testing.T) { r := NewDefaultRunner([]string{"s3_secret_[a-z0-9]+"}) // Redact function is unexported; replicate behavior out := "User: s3_secret_abc123 is set" redacted := r.redact(out) if strings.Contains(redacted, "s3_secret_") { t.Fatalf("expected redaction in %q", redacted) } } func TestTruncate(t *testing.T) { r := NewDefaultRunner(nil) r.MaxOutputBytes = 10 long := strings.Repeat("x", 50) truncated, truncatedFlag := r.truncate(long) if !truncatedFlag { t.Fatalf("expected truncated flag true") } if len(truncated) > r.MaxOutputBytes+20 { // includes '... (truncated)' t.Fatalf("unexpected truncated length") } }