woodpecker-mcp/internal/woodpecker/errors_test.go
2026-08-08 01:37:47 +03:00

94 lines
2.7 KiB
Go

package woodpecker
import (
"encoding/json"
"strings"
"testing"
)
func TestAPIErrorToContextStatusMapping(t *testing.T) {
cases := []struct {
status int
wantCode string
wantInDesc string
}{
{401, "AUTH_ERROR", "Authentication failed"},
{403, "PERMISSION_ERROR", "Access denied"},
{404, "NOT_FOUND", "Resource not found"},
{429, "RATE_LIMIT", "Rate limit exceeded"},
{500, "SERVER_ERROR", "server error"},
{502, "SERVER_ERROR", "server error"},
{503, "SERVER_ERROR", "server error"},
{504, "SERVER_ERROR", "server error"},
{418, "UNKNOWN_ERROR", "Request failed"},
}
for _, tc := range cases {
t.Run(strings.ToLower(tc.wantCode), func(t *testing.T) {
e := &APIError{Status: tc.status, Message: "boom"}
got := e.ToContext("sample operation")
var ctx errorContext
if err := json.Unmarshal([]byte(got), &ctx); err != nil {
t.Fatalf("ToContext returned invalid JSON: %v\n%s", err, got)
}
if ctx.Error != tc.wantCode {
t.Errorf("error code = %q, want %q", ctx.Error, tc.wantCode)
}
if !strings.Contains(ctx.Description, tc.wantInDesc) {
t.Errorf("description %q does not contain %q", ctx.Description, tc.wantInDesc)
}
if !strings.Contains(ctx.Description, "sample operation") {
t.Errorf("description %q does not mention the context", ctx.Description)
}
if len(ctx.Suggestions) == 0 {
t.Error("suggestions must not be empty")
}
})
}
}
func TestAPIErrorToContextUnknownIncludesMessage(t *testing.T) {
e := &APIError{Status: 418, Message: "some detail"}
var ctx errorContext
if err := json.Unmarshal([]byte(e.ToContext("op")), &ctx); err != nil {
t.Fatal(err)
}
if !strings.Contains(ctx.Description, "some detail") {
t.Errorf("description %q should include the underlying message", ctx.Description)
}
}
func TestAPIErrorSuggestionsMatchReference(t *testing.T) {
cases := []struct {
status int
want []string
}{
{401, []string{
"Check that your WOODPECKER_TOKEN environment variable is set correctly",
"Verify the token has not expired",
"Ensure the token has sufficient permissions",
}},
{404, []string{
"Double-check the repository name, pipeline number, or step ID",
"Verify the resource exists and hasn't been deleted",
}},
}
for _, tc := range cases {
e := &APIError{Status: tc.status}
var ctx errorContext
if err := json.Unmarshal([]byte(e.ToContext("op")), &ctx); err != nil {
t.Fatal(err)
}
if len(ctx.Suggestions) != len(tc.want) {
t.Fatalf("status %d: got %d suggestions, want %d", tc.status, len(ctx.Suggestions), len(tc.want))
}
for i := range tc.want {
if ctx.Suggestions[i] != tc.want[i] {
t.Errorf("status %d suggestion %d = %q, want %q", tc.status, i, ctx.Suggestions[i], tc.want[i])
}
}
}
}