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  }