package runner import ( "context" "strings" "testing" "time" "unicode/utf8" ) func TestMapExit(t *testing.T) { cases := map[int]Status{0: StatusOK, 1: StatusWarning, 2: StatusCritical, 3: StatusUnknown, 255: StatusUnknown} for code, want := range cases { if got := MapExit(code); got != want { t.Errorf("MapExit(%d)=%s want %s", code, got, want) } } } func TestTruncateUTF8Short(t *testing.T) { out, tr := TruncateUTF8([]byte("hi"), 100) if tr || out != "hi" { t.Fatalf("got %q tr=%v", out, tr) } } func TestTruncateUTF8Long(t *testing.T) { in := strings.Repeat("a", 9000) out, tr := TruncateUTF8([]byte(in), MaxOutputBytes) if !tr { t.Fatal("expected truncated") } if len([]byte(out)) > MaxOutputBytes { t.Fatalf("byte len %d > %d", len([]byte(out)), MaxOutputBytes) } if !strings.Contains(out, "truncated") { t.Fatalf("no marker: %q", out[len(out)-50:]) } } func TestTruncateUTF8SanitizesInvalidBytes(t *testing.T) { // invalid UTF-8 bytes that json.Marshal would replace with U+FFFD (3 bytes each) in := append([]byte("hello"), 0xff, 0xfe, 0xfd) out, tr := TruncateUTF8(in, 100) if tr { t.Fatal("should fit") } if !utf8.ValidString(out) { t.Fatalf("output must be valid UTF-8: %q", out) } } func TestTruncateUTF8Multibyte(t *testing.T) { in := strings.Repeat("ё", 5000) // 2 bytes per rune = 10000 bytes out, tr := TruncateUTF8([]byte(in), MaxOutputBytes) if !tr { t.Fatal("expected truncated") } if !utf8.ValidString(out) { t.Fatal("invalid UTF-8 after truncate") } if len([]byte(out)) > MaxOutputBytes { t.Fatalf("byte len %d > %d", len([]byte(out)), MaxOutputBytes) } } func TestRunOK(t *testing.T) { r := Run(context.Background(), []string{"sh", "-c", "echo ok"}, 2*time.Second) if r.Status != StatusOK || r.ExitCode != 0 { t.Fatalf("got %+v", r) } if !strings.Contains(r.Output, "ok") { t.Fatalf("output: %q", r.Output) } } func TestRunWarning(t *testing.T) { r := Run(context.Background(), []string{"sh", "-c", "exit 1"}, 2*time.Second) if r.Status != StatusWarning || r.ExitCode != 1 { t.Fatalf("got %+v", r) } } func TestRunCritical(t *testing.T) { r := Run(context.Background(), []string{"sh", "-c", "exit 2"}, 2*time.Second) if r.Status != StatusCritical { t.Fatalf("got %+v", r) } } func TestRunUnknownExit(t *testing.T) { r := Run(context.Background(), []string{"sh", "-c", "exit 7"}, 2*time.Second) if r.Status != StatusUnknown || r.ExitCode != 7 { t.Fatalf("got %+v", r) } } func TestRunTimeout(t *testing.T) { r := Run(context.Background(), []string{"sh", "-c", "sleep 5"}, 200*time.Millisecond) if r.Status != StatusUnknown { t.Fatalf("got %+v", r) } if r.DurationMs > 2000 { t.Fatalf("duration too long: %d", r.DurationMs) } } func TestRunNoExec(t *testing.T) { r := Run(context.Background(), []string{"/does/not/exist/zzz"}, 1*time.Second) if r.Status != StatusUnknown { t.Fatalf("got %+v", r) } }