github.com/grpc-ecosystem/grpc-gateway/v2@v2.19.1/runtime/errors_test.go (about) 1 package runtime_test 2 3 import ( 4 "context" 5 "errors" 6 "net/http" 7 "net/http/httptest" 8 "strconv" 9 "strings" 10 "testing" 11 12 "github.com/grpc-ecosystem/grpc-gateway/v2/runtime" 13 "google.golang.org/genproto/googleapis/rpc/errdetails" 14 statuspb "google.golang.org/genproto/googleapis/rpc/status" 15 "google.golang.org/grpc/codes" 16 "google.golang.org/grpc/status" 17 ) 18 19 func TestDefaultHTTPError(t *testing.T) { 20 ctx := context.Background() 21 22 statusWithDetails, _ := status.New(codes.FailedPrecondition, "failed precondition").WithDetails( 23 &errdetails.PreconditionFailure{}, 24 ) 25 26 for i, spec := range []struct { 27 err error 28 status int 29 msg string 30 marshaler runtime.Marshaler 31 contentType string 32 details string 33 }{ 34 { 35 err: errors.New("example error"), 36 status: http.StatusInternalServerError, 37 marshaler: &runtime.JSONPb{}, 38 contentType: "application/json", 39 msg: "example error", 40 }, 41 { 42 err: status.Error(codes.NotFound, "no such resource"), 43 status: http.StatusNotFound, 44 marshaler: &runtime.JSONPb{}, 45 contentType: "application/json", 46 msg: "no such resource", 47 }, 48 { 49 err: statusWithDetails.Err(), 50 status: http.StatusBadRequest, 51 marshaler: &runtime.JSONPb{}, 52 contentType: "application/json", 53 msg: "failed precondition", 54 details: "type.googleapis.com/google.rpc.PreconditionFailure", 55 }, 56 { 57 err: errors.New("example error"), 58 status: http.StatusInternalServerError, 59 marshaler: &CustomMarshaler{&runtime.JSONPb{}}, 60 contentType: "Custom-Content-Type", 61 msg: "example error", 62 }, 63 { 64 err: &runtime.HTTPStatusError{ 65 HTTPStatus: http.StatusMethodNotAllowed, 66 Err: status.Error(codes.Unimplemented, http.StatusText(http.StatusMethodNotAllowed)), 67 }, 68 status: http.StatusMethodNotAllowed, 69 marshaler: &runtime.JSONPb{}, 70 contentType: "application/json", 71 msg: "Method Not Allowed", 72 }, 73 } { 74 t.Run(strconv.Itoa(i), func(t *testing.T) { 75 w := httptest.NewRecorder() 76 req, _ := http.NewRequestWithContext(ctx, "", "", nil) // Pass in an empty request to match the signature 77 mux := runtime.NewServeMux() 78 marshaler := &runtime.JSONPb{} 79 runtime.HTTPError(ctx, mux, marshaler, w, req, spec.err) 80 81 if got, want := w.Header().Get("Content-Type"), "application/json"; got != want { 82 t.Errorf(`w.Header().Get("Content-Type") = %q; want %q; on spec.err=%v`, got, want, spec.err) 83 } 84 if got, want := w.Code, spec.status; got != want { 85 t.Errorf("w.Code = %d; want %d", got, want) 86 } 87 88 var st statuspb.Status 89 if err := marshaler.Unmarshal(w.Body.Bytes(), &st); err != nil { 90 t.Errorf("marshaler.Unmarshal(%q, &body) failed with %v; want success", w.Body.Bytes(), err) 91 return 92 } 93 94 if got, want := st.Message, spec.msg; !strings.Contains(got, want) { 95 t.Errorf(`st.Message = %q; want %q; on spec.err=%v`, got, want, spec.err) 96 } 97 98 if spec.details != "" { 99 if len(st.Details) != 1 { 100 t.Errorf(`len(st.Details) = %v; want 1`, len(st.Details)) 101 return 102 } 103 if st.Details[0].TypeUrl != spec.details { 104 t.Errorf(`details.type_url = %s; want %s`, st.Details[0].TypeUrl, spec.details) 105 } 106 } 107 }) 108 } 109 }