test: Add tests for authHTTPError.Error and shouldFallbackToForm
Tests for Proxmox client authentication error handling: - authHTTPError.Error: message formatting based on status code (401/403 include status in message, others don't) - shouldFallbackToForm: determines when to retry with form encoding (triggers on 400/415, not on auth errors or server errors) 16 test cases covering all code paths.
This commit is contained in:
parent
447478785b
commit
ba31e4025d
1 changed files with 137 additions and 0 deletions
|
|
@ -872,3 +872,140 @@ func TestMemoryStatusEffectiveAvailable_RegressionIssue435(t *testing.T) {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestAuthHTTPError_Error(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
|
||||||
|
tests := []struct {
|
||||||
|
name string
|
||||||
|
err *authHTTPError
|
||||||
|
contains string
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
name: "unauthorized status includes status code",
|
||||||
|
err: &authHTTPError{status: 401, body: "invalid credentials"},
|
||||||
|
contains: "status 401",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "forbidden status includes status code",
|
||||||
|
err: &authHTTPError{status: 403, body: "access denied"},
|
||||||
|
contains: "status 403",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "unauthorized includes body",
|
||||||
|
err: &authHTTPError{status: 401, body: "bad user/pass"},
|
||||||
|
contains: "bad user/pass",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "forbidden includes body",
|
||||||
|
err: &authHTTPError{status: 403, body: "permission denied"},
|
||||||
|
contains: "permission denied",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "other status omits status code",
|
||||||
|
err: &authHTTPError{status: 500, body: "server error"},
|
||||||
|
contains: "authentication failed: server error",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "bad request omits status code",
|
||||||
|
err: &authHTTPError{status: 400, body: "bad request"},
|
||||||
|
contains: "authentication failed: bad request",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "zero status omits status code",
|
||||||
|
err: &authHTTPError{status: 0, body: "unknown error"},
|
||||||
|
contains: "authentication failed: unknown error",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, tc := range tests {
|
||||||
|
t.Run(tc.name, func(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
msg := tc.err.Error()
|
||||||
|
if !containsSubstring(msg, tc.contains) {
|
||||||
|
t.Errorf("Error() = %q, want to contain %q", msg, tc.contains)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestShouldFallbackToForm(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
|
||||||
|
tests := []struct {
|
||||||
|
name string
|
||||||
|
err error
|
||||||
|
want bool
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
name: "nil error",
|
||||||
|
err: nil,
|
||||||
|
want: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "non-authHTTPError",
|
||||||
|
err: fmt.Errorf("some other error"),
|
||||||
|
want: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "bad request triggers fallback",
|
||||||
|
err: &authHTTPError{status: 400, body: "bad request"},
|
||||||
|
want: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "unsupported media type triggers fallback",
|
||||||
|
err: &authHTTPError{status: 415, body: "unsupported media type"},
|
||||||
|
want: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "unauthorized does not trigger fallback",
|
||||||
|
err: &authHTTPError{status: 401, body: "unauthorized"},
|
||||||
|
want: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "forbidden does not trigger fallback",
|
||||||
|
err: &authHTTPError{status: 403, body: "forbidden"},
|
||||||
|
want: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "server error does not trigger fallback",
|
||||||
|
err: &authHTTPError{status: 500, body: "internal error"},
|
||||||
|
want: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "not found does not trigger fallback",
|
||||||
|
err: &authHTTPError{status: 404, body: "not found"},
|
||||||
|
want: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "zero status does not trigger fallback",
|
||||||
|
err: &authHTTPError{status: 0, body: ""},
|
||||||
|
want: false,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, tc := range tests {
|
||||||
|
t.Run(tc.name, func(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
got := shouldFallbackToForm(tc.err)
|
||||||
|
if got != tc.want {
|
||||||
|
t.Errorf("shouldFallbackToForm(%v) = %v, want %v", tc.err, got, tc.want)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// containsSubstring checks if s contains substr (helper for error message checks)
|
||||||
|
func containsSubstring(s, substr string) bool {
|
||||||
|
return len(s) >= len(substr) && (s == substr || len(substr) == 0 ||
|
||||||
|
(len(s) > 0 && len(substr) > 0 && findSubstring(s, substr)))
|
||||||
|
}
|
||||||
|
|
||||||
|
func findSubstring(s, substr string) bool {
|
||||||
|
for i := 0; i <= len(s)-len(substr); i++ {
|
||||||
|
if s[i:i+len(substr)] == substr {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue