github.com/grafana/pyroscope@v1.18.0/pkg/util/http/error_test.go (about) 1 package http 2 3 import ( 4 "context" 5 "errors" 6 "fmt" 7 "io" 8 "net/http" 9 "net/http/httptest" 10 "strings" 11 "testing" 12 13 "connectrpc.com/connect" 14 "github.com/gogo/status" 15 "github.com/grafana/dskit/httpgrpc" 16 "github.com/stretchr/testify/assert" 17 "google.golang.org/grpc/codes" 18 19 "github.com/grafana/pyroscope/pkg/tenant" 20 ) 21 22 func Test_writeError(t *testing.T) { 23 for _, tt := range []struct { 24 name string 25 26 err error 27 msg string 28 expectedStatus int 29 }{ 30 {"cancelled", context.Canceled, `{"code":"canceled","message":"the request was cancelled by the client"}`, StatusClientClosedRequest}, 31 {"rpc cancelled", status.New(codes.Canceled, context.Canceled.Error()).Err(), `{"code":"canceled","message":"the request was cancelled by the client"}`, StatusClientClosedRequest}, 32 {"orgid", tenant.ErrNoTenantID, `{"code":"invalid_argument","message":"no org id"}`, http.StatusBadRequest}, 33 {"deadline", context.DeadlineExceeded, `{"code":"deadline_exceeded","message":"request timed out, decrease the duration of the request or add more label matchers (prefer exact match over regex match) to reduce the amount of data processed"}`, http.StatusGatewayTimeout}, 34 {"rpc deadline", status.New(codes.DeadlineExceeded, context.DeadlineExceeded.Error()).Err(), `{"code":"deadline_exceeded","message":"request timed out, decrease the duration of the request or add more label matchers (prefer exact match over regex match) to reduce the amount of data processed"}`, http.StatusGatewayTimeout}, 35 // {"mixed context, rpc deadline and another", multierror.MultiError{errors.New("standard error"), context.DeadlineExceeded, status.New(codes.DeadlineExceeded, context.DeadlineExceeded.Error()).Err()}, "3 errors: standard error; context deadline exceeded; rpc error: code = DeadlineExceeded desc = context deadline exceeded", http.StatusInternalServerError}, 36 {"httpgrpc", httpgrpc.Errorf(http.StatusBadRequest, "foo"), `{"code":"invalid_argument","message":"foo"}`, http.StatusBadRequest}, 37 {"internal", errors.New("foo"), `{"code":"unknown","message":"foo"}`, http.StatusInternalServerError}, 38 {"connect", connect.NewError(connect.CodeInvalidArgument, errors.New("foo")), `{"code":"invalid_argument","message":"foo"}`, http.StatusBadRequest}, 39 {"connect wrapped", fmt.Errorf("foo %w", connect.NewError(connect.CodeInvalidArgument, errors.New("foo"))), `{"code":"invalid_argument","message":"foo"}`, http.StatusBadRequest}, 40 // {"multi mixed", multierror.MultiError{context.Canceled, context.DeadlineExceeded}, "2 errors: context canceled; context deadline exceeded", http.StatusInternalServerError}, 41 } { 42 t.Run(tt.name, func(t *testing.T) { 43 rec := httptest.NewRecorder() 44 Error(rec, tt.err) 45 assert.Equal(t, tt.expectedStatus, rec.Result().StatusCode) 46 b, err := io.ReadAll(rec.Result().Body) 47 if err != nil { 48 t.Fatal(err) 49 } 50 assert.Equal(t, tt.msg, strings.TrimSpace(string(b))) 51 }) 52 } 53 }