<!-- Add the related story/sub-task/bug number, like Resolves #123, or remove if NA --> **Related issue:** Resolves #40028 # Checklist for submitter - [x] Changes file added for user-visible changes in `changes/`, `orbit/changes/` or `ee/fleetd-chrome/changes`. ## Testing - [x] Added/updated automated tests - [x] QA'd all new/changed functionality manually <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit ## Release Notes * **Bug Fixes** * Fixed telemetry misclassification where client-side errors were incorrectly reported as server errors. Client-side errors and request cancellations are now properly categorized for improved error tracking and observability. * **Tests** * Added test coverage for client error detection and context cancellation handling. <!-- end of auto-generated comment: release notes by coderabbit.ai -->
127 lines
2.4 KiB
Go
127 lines
2.4 KiB
Go
package endpointer
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
"net/http"
|
|
"net/http/httptest"
|
|
"testing"
|
|
|
|
platform_http "github.com/fleetdm/fleet/v4/server/platform/http"
|
|
"github.com/stretchr/testify/assert"
|
|
)
|
|
|
|
type foreignKeyError struct{}
|
|
|
|
func (foreignKeyError) IsForeignKey() bool { return true }
|
|
func (foreignKeyError) Error() string { return "" }
|
|
|
|
type alreadyExists struct{}
|
|
|
|
func (alreadyExists) IsExists() bool { return false }
|
|
func (alreadyExists) Error() string { return "" }
|
|
|
|
type newAndExciting struct{}
|
|
|
|
func (newAndExciting) Error() string { return "" }
|
|
|
|
type notFoundError struct {
|
|
platform_http.ErrorWithUUID
|
|
}
|
|
|
|
func (e *notFoundError) Error() string {
|
|
return "not found"
|
|
}
|
|
|
|
func (e *notFoundError) IsNotFound() bool {
|
|
return true
|
|
}
|
|
|
|
// validationError is a test implementation of validationErrorInterface.
|
|
type validationError struct {
|
|
errors []map[string]string
|
|
}
|
|
|
|
func (e validationError) Error() string {
|
|
return "validation failed"
|
|
}
|
|
|
|
func (e validationError) Invalid() []map[string]string {
|
|
return e.errors
|
|
}
|
|
|
|
// permissionError is a test implementation of permissionErrorInterface.
|
|
type permissionError struct {
|
|
message string
|
|
}
|
|
|
|
func (e permissionError) Error() string {
|
|
return e.message
|
|
}
|
|
|
|
func (e permissionError) PermissionError() []map[string]string {
|
|
return nil
|
|
}
|
|
|
|
func TestHandlesErrorsCode(t *testing.T) {
|
|
errorTests := []struct {
|
|
name string
|
|
err error
|
|
code int
|
|
}{
|
|
{
|
|
"validation",
|
|
validationError{errors: []map[string]string{{"name": "a", "reason": "b"}}},
|
|
http.StatusUnprocessableEntity,
|
|
},
|
|
{
|
|
"permission",
|
|
permissionError{message: "a"},
|
|
http.StatusForbidden,
|
|
},
|
|
{
|
|
"foreign key",
|
|
foreignKeyError{},
|
|
http.StatusUnprocessableEntity,
|
|
},
|
|
{
|
|
"data not found",
|
|
¬FoundError{},
|
|
http.StatusNotFound,
|
|
},
|
|
{
|
|
"already exists",
|
|
alreadyExists{},
|
|
http.StatusConflict,
|
|
},
|
|
{
|
|
"status coder",
|
|
platform_http.NewAuthFailedError(""),
|
|
http.StatusUnauthorized,
|
|
},
|
|
{
|
|
"context canceled",
|
|
context.Canceled,
|
|
499,
|
|
},
|
|
{
|
|
"wrapped context canceled",
|
|
fmt.Errorf("db query: %w", context.Canceled),
|
|
499,
|
|
},
|
|
{
|
|
"default",
|
|
newAndExciting{},
|
|
http.StatusInternalServerError,
|
|
},
|
|
}
|
|
|
|
for _, tt := range errorTests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
recorder := httptest.NewRecorder()
|
|
EncodeError(context.Background(), tt.err, recorder, nil)
|
|
assert.Equal(t, recorder.Code, tt.code)
|
|
})
|
|
}
|
|
}
|