mirror of
https://github.com/sipeed/picoclaw.git
synced 2026-07-28 01:27:58 +00:00
134 lines
3.0 KiB
Go
134 lines
3.0 KiB
Go
package providers
|
|
|
|
import (
|
|
"errors"
|
|
"fmt"
|
|
"testing"
|
|
|
|
"github.com/sipeed/picoclaw/pkg/providers/common"
|
|
)
|
|
|
|
func TestClassifyError_HTTPErrorStatus(t *testing.T) {
|
|
err := fmt.Errorf("provider request: %w", &common.HTTPError{
|
|
StatusCode: httpStatusUnauthorized,
|
|
BodyPreview: `{"error":"unauthorized"}`,
|
|
ContentType: "application/json",
|
|
APIBase: "https://api.example.com",
|
|
})
|
|
|
|
result := ClassifyError(err, "openai", "gpt-4")
|
|
if result == nil {
|
|
t.Fatal("expected classified error")
|
|
}
|
|
if result.Reason != FailoverAuth {
|
|
t.Fatalf("reason = %q, want %q", result.Reason, FailoverAuth)
|
|
}
|
|
if result.Status != httpStatusUnauthorized {
|
|
t.Fatalf("status = %d, want %d", result.Status, httpStatusUnauthorized)
|
|
}
|
|
}
|
|
|
|
func TestClassifyAuthError(t *testing.T) {
|
|
tests := []struct {
|
|
name string
|
|
err error
|
|
want AuthErrorKind
|
|
}{
|
|
{
|
|
name: "invalid api key",
|
|
err: errors.New(
|
|
`API request failed: Status: 401 Body: {"error":{"message":"Incorrect API key provided"}}`,
|
|
),
|
|
want: AuthErrorInvalidAPIKey,
|
|
},
|
|
{
|
|
name: "missing api key",
|
|
err: errors.New("API key not configured"),
|
|
want: AuthErrorMissingAPIKey,
|
|
},
|
|
{
|
|
name: "expired token",
|
|
err: errors.New("oauth token refresh failed: token has expired"),
|
|
want: AuthErrorExpiredToken,
|
|
},
|
|
{
|
|
name: "structured generic auth",
|
|
err: &common.HTTPError{
|
|
StatusCode: httpStatusUnauthorized,
|
|
BodyPreview: `{"error":"unauthorized"}`,
|
|
ContentType: "application/json",
|
|
APIBase: "https://api.example.com",
|
|
},
|
|
want: AuthErrorGeneric,
|
|
},
|
|
}
|
|
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
got, ok := ClassifyAuthError(tt.err)
|
|
if !ok {
|
|
t.Fatal("expected auth classification")
|
|
}
|
|
if got != tt.want {
|
|
t.Fatalf("kind = %q, want %q", got, tt.want)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestClassifyAuthError_FallbackExhaustedAllAuth(t *testing.T) {
|
|
err := &FallbackExhaustedError{
|
|
Attempts: []FallbackAttempt{
|
|
{
|
|
Reason: FailoverAuth,
|
|
Error: &FailoverError{
|
|
Reason: FailoverAuth,
|
|
Wrapped: errors.New("invalid api key"),
|
|
},
|
|
},
|
|
{
|
|
Reason: FailoverAuth,
|
|
Error: &FailoverError{
|
|
Reason: FailoverAuth,
|
|
Wrapped: errors.New("unauthorized"),
|
|
},
|
|
},
|
|
},
|
|
}
|
|
|
|
got, ok := ClassifyAuthError(err)
|
|
if !ok {
|
|
t.Fatal("expected auth classification")
|
|
}
|
|
if got != AuthErrorInvalidAPIKey {
|
|
t.Fatalf("kind = %q, want %q", got, AuthErrorInvalidAPIKey)
|
|
}
|
|
}
|
|
|
|
func TestClassifyAuthError_FallbackExhaustedMixedFailures(t *testing.T) {
|
|
err := &FallbackExhaustedError{
|
|
Attempts: []FallbackAttempt{
|
|
{
|
|
Reason: FailoverAuth,
|
|
Error: &FailoverError{
|
|
Reason: FailoverAuth,
|
|
Wrapped: errors.New("invalid api key"),
|
|
},
|
|
},
|
|
{
|
|
Reason: FailoverRateLimit,
|
|
Error: &FailoverError{
|
|
Reason: FailoverRateLimit,
|
|
Wrapped: errors.New("rate limit exceeded"),
|
|
},
|
|
},
|
|
},
|
|
}
|
|
|
|
if got, ok := ClassifyAuthError(err); ok {
|
|
t.Fatalf("kind = %q, want no auth classification for mixed failures", got)
|
|
}
|
|
}
|
|
|
|
const httpStatusUnauthorized = 401
|