963ccc6553
Feature/demo support * index logs now debug * demo data loader
241 lines
7.1 KiB
Go
241 lines
7.1 KiB
Go
package usermanagement
|
|
|
|
import (
|
|
"errors"
|
|
"net/http"
|
|
"testing"
|
|
|
|
"github.com/aws/aws-sdk-go-v2/service/cognitoidentityprovider/types"
|
|
"github.com/aws/smithy-go"
|
|
"github.com/stretchr/testify/assert"
|
|
)
|
|
|
|
// mockAPIError implements smithy.APIError for testing.
|
|
type mockAPIError struct {
|
|
code string
|
|
message string
|
|
}
|
|
|
|
func (e *mockAPIError) Error() string { return e.message }
|
|
func (e *mockAPIError) ErrorCode() string { return e.code }
|
|
func (e *mockAPIError) ErrorMessage() string { return e.message }
|
|
func (e *mockAPIError) ErrorFault() smithy.ErrorFault { return smithy.FaultServer }
|
|
|
|
func TestClassifyCognitoError_NilError(t *testing.T) {
|
|
result := ClassifyCognitoError(nil, "test@example.com")
|
|
|
|
assert.Equal(t, http.StatusOK, result.HTTPStatus)
|
|
assert.Equal(t, CognitoErrorType(""), result.ErrorType)
|
|
assert.Empty(t, result.Message)
|
|
}
|
|
|
|
func TestClassifyCognitoError_UserNotFoundException(t *testing.T) {
|
|
email := "test@example.com"
|
|
err := &types.UserNotFoundException{
|
|
Message: stringPtr("User does not exist"),
|
|
}
|
|
|
|
result := ClassifyCognitoError(err, email)
|
|
|
|
assert.Equal(t, http.StatusNotFound, result.HTTPStatus)
|
|
assert.Equal(t, ErrTypeUserNotFound, result.ErrorType)
|
|
assert.Contains(t, result.Message, email)
|
|
assert.NotEmpty(t, result.Details)
|
|
}
|
|
|
|
func TestClassifyCognitoError_NotAuthorizedException(t *testing.T) {
|
|
email := "test@example.com"
|
|
err := &types.NotAuthorizedException{
|
|
Message: stringPtr("User is not authorized"),
|
|
}
|
|
|
|
result := ClassifyCognitoError(err, email)
|
|
|
|
assert.Equal(t, http.StatusUnauthorized, result.HTTPStatus)
|
|
assert.Equal(t, ErrTypeNotAuthorized, result.ErrorType)
|
|
assert.NotEmpty(t, result.Message)
|
|
}
|
|
|
|
func TestClassifyCognitoError_InvalidParameterException(t *testing.T) {
|
|
email := "test@example.com"
|
|
err := &types.InvalidParameterException{
|
|
Message: stringPtr("Invalid email format"),
|
|
}
|
|
|
|
result := ClassifyCognitoError(err, email)
|
|
|
|
assert.Equal(t, http.StatusBadRequest, result.HTTPStatus)
|
|
assert.Equal(t, ErrTypeInvalidParameter, result.ErrorType)
|
|
assert.NotEmpty(t, result.Message)
|
|
}
|
|
|
|
func TestClassifyCognitoError_TooManyRequestsException(t *testing.T) {
|
|
email := "test@example.com"
|
|
err := &types.TooManyRequestsException{
|
|
Message: stringPtr("Rate exceeded"),
|
|
}
|
|
|
|
result := ClassifyCognitoError(err, email)
|
|
|
|
assert.Equal(t, http.StatusTooManyRequests, result.HTTPStatus)
|
|
assert.Equal(t, ErrTypeRateLimited, result.ErrorType)
|
|
assert.NotEmpty(t, result.Message)
|
|
}
|
|
|
|
func TestClassifyCognitoError_InternalErrorException(t *testing.T) {
|
|
email := "test@example.com"
|
|
err := &types.InternalErrorException{
|
|
Message: stringPtr("Internal server error"),
|
|
}
|
|
|
|
result := ClassifyCognitoError(err, email)
|
|
|
|
assert.Equal(t, http.StatusServiceUnavailable, result.HTTPStatus)
|
|
assert.Equal(t, ErrTypeServiceUnavailable, result.ErrorType)
|
|
assert.NotEmpty(t, result.Message)
|
|
}
|
|
|
|
func TestClassifyCognitoError_UsernameExistsException(t *testing.T) {
|
|
email := "test@example.com"
|
|
err := &types.UsernameExistsException{
|
|
Message: stringPtr("User already exists"),
|
|
}
|
|
|
|
result := ClassifyCognitoError(err, email)
|
|
|
|
assert.Equal(t, http.StatusConflict, result.HTTPStatus)
|
|
assert.Equal(t, ErrTypeUserExists, result.ErrorType)
|
|
assert.Contains(t, result.Message, email)
|
|
}
|
|
|
|
func TestClassifyCognitoError_AccessDeniedException_ViaAPIError(t *testing.T) {
|
|
email := "test@example.com"
|
|
err := &mockAPIError{
|
|
code: "AccessDeniedException",
|
|
message: "User: arn:aws:sts::123456789:assumed-role/role is not authorized",
|
|
}
|
|
|
|
result := ClassifyCognitoError(err, email)
|
|
|
|
assert.Equal(t, http.StatusForbidden, result.HTTPStatus)
|
|
assert.Equal(t, ErrTypeAccessDenied, result.ErrorType)
|
|
assert.Contains(t, result.Message, "Access denied")
|
|
}
|
|
|
|
func TestClassifyCognitoError_GenericError(t *testing.T) {
|
|
email := "test@example.com"
|
|
err := errors.New("some unknown error")
|
|
|
|
result := ClassifyCognitoError(err, email)
|
|
|
|
assert.Equal(t, http.StatusBadGateway, result.HTTPStatus)
|
|
assert.Equal(t, ErrTypeServiceError, result.ErrorType)
|
|
assert.Contains(t, result.Message, "Failed to communicate with Cognito")
|
|
}
|
|
|
|
func TestClassifyCognitoError_UnknownAPIError(t *testing.T) {
|
|
email := "test@example.com"
|
|
err := &mockAPIError{
|
|
code: "SomeUnknownException",
|
|
message: "Unknown error occurred",
|
|
}
|
|
|
|
result := ClassifyCognitoError(err, email)
|
|
|
|
assert.Equal(t, http.StatusBadGateway, result.HTTPStatus)
|
|
assert.Equal(t, ErrTypeServiceError, result.ErrorType)
|
|
}
|
|
|
|
func TestSanitizeErrorMessage_RemovesARNs(t *testing.T) {
|
|
tests := []struct {
|
|
name string
|
|
input string
|
|
expected string
|
|
}{
|
|
{
|
|
name: "removes single ARN",
|
|
input: "User: arn:aws:sts::123456789012:assumed-role/TestRole/session is not authorized",
|
|
expected: "User: [REDACTED] is not authorized",
|
|
},
|
|
{
|
|
name: "removes multiple ARNs",
|
|
input: "arn:aws:iam::123:user/test and arn:aws:s3:::bucket",
|
|
expected: "[REDACTED] and [REDACTED]",
|
|
},
|
|
{
|
|
name: "handles no ARN",
|
|
input: "Simple error message",
|
|
expected: "Simple error message",
|
|
},
|
|
}
|
|
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
result := sanitizeErrorMessage(tt.input)
|
|
assert.Equal(t, tt.expected, result)
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestSanitizeErrorMessage_RemovesRequestIDs(t *testing.T) {
|
|
tests := []struct {
|
|
name string
|
|
input string
|
|
expected string
|
|
}{
|
|
{
|
|
name: "removes RequestID",
|
|
input: "Error occurred, RequestID: abc-123-def",
|
|
expected: "Error occurred,",
|
|
},
|
|
{
|
|
name: "removes Request ID with space",
|
|
input: "Error occurred, Request ID: abc-123-def something",
|
|
expected: "Error occurred, something",
|
|
},
|
|
}
|
|
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
result := sanitizeErrorMessage(tt.input)
|
|
assert.NotContains(t, result, "abc-123-def")
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestClassifyAPIError_AllCases(t *testing.T) {
|
|
email := "user@test.com"
|
|
|
|
tests := []struct {
|
|
name string
|
|
code string
|
|
expectedStatus int
|
|
expectedType CognitoErrorType
|
|
}{
|
|
{"AccessDenied", "AccessDeniedException", http.StatusForbidden, ErrTypeAccessDenied},
|
|
{"UserNotFound", "UserNotFoundException", http.StatusNotFound, ErrTypeUserNotFound},
|
|
{"NotAuthorized", "NotAuthorizedException", http.StatusUnauthorized, ErrTypeNotAuthorized},
|
|
{"InvalidParameter", "InvalidParameterException", http.StatusBadRequest, ErrTypeInvalidParameter},
|
|
{"TooManyRequests", "TooManyRequestsException", http.StatusTooManyRequests, ErrTypeRateLimited},
|
|
{"ServiceUnavailable", "ServiceUnavailable", http.StatusServiceUnavailable, ErrTypeServiceUnavailable},
|
|
{"InternalError", "InternalError", http.StatusServiceUnavailable, ErrTypeServiceUnavailable},
|
|
{"UsernameExists", "UsernameExistsException", http.StatusConflict, ErrTypeUserExists},
|
|
{"Unknown", "SomeRandomException", http.StatusBadGateway, ErrTypeServiceError},
|
|
}
|
|
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
apiErr := &mockAPIError{code: tt.code, message: "test message"}
|
|
result := classifyAPIError(apiErr, email)
|
|
|
|
assert.Equal(t, tt.expectedStatus, result.HTTPStatus)
|
|
assert.Equal(t, tt.expectedType, result.ErrorType)
|
|
})
|
|
}
|
|
}
|
|
|
|
// stringPtr is a helper to create a pointer to a string.
|
|
func stringPtr(s string) *string {
|
|
return &s
|
|
}
|