1 package runtime_test
2
3 import (
4 "context"
5 "encoding/json"
6 "fmt"
7 "net/http"
8 "net/http/httptest"
9 "strings"
10 "testing"
11
12 "github.com/grpc-ecosystem/grpc-gateway/runtime"
13 "google.golang.org/genproto/googleapis/rpc/errdetails"
14 "google.golang.org/grpc/codes"
15 "google.golang.org/grpc/status"
16 )
17
18 func TestDefaultHTTPError(t *testing.T) {
19 ctx := context.Background()
20
21 statusWithDetails, _ := status.New(codes.FailedPrecondition, "failed precondition").WithDetails(
22 &errdetails.PreconditionFailure{},
23 )
24
25 for _, spec := range []struct {
26 err error
27 status int
28 msg string
29 marshaler runtime.Marshaler
30 contentType string
31 details string
32 }{
33 {
34 err: fmt.Errorf("example error"),
35 status: http.StatusInternalServerError,
36 marshaler: &runtime.JSONPb{},
37 contentType: "application/json",
38 msg: "example error",
39 },
40 {
41 err: status.Error(codes.NotFound, "no such resource"),
42 status: http.StatusNotFound,
43 marshaler: &runtime.JSONPb{},
44 contentType: "application/json",
45 msg: "no such resource",
46 },
47 {
48 err: statusWithDetails.Err(),
49 status: http.StatusBadRequest,
50 marshaler: &runtime.JSONPb{},
51 contentType: "application/json",
52 msg: "failed precondition",
53 details: "type.googleapis.com/google.rpc.PreconditionFailure",
54 },
55 {
56 err: fmt.Errorf("example error"),
57 status: http.StatusInternalServerError,
58 marshaler: &CustomMarshaler{&runtime.JSONPb{}},
59 contentType: "Custom-Content-Type",
60 msg: "example error",
61 },
62 } {
63 w := httptest.NewRecorder()
64 req, _ := http.NewRequest("", "", nil)
65 runtime.DefaultHTTPError(ctx, &runtime.ServeMux{}, &runtime.JSONPb{}, w, req, spec.err)
66
67 if got, want := w.Header().Get("Content-Type"), "application/json"; got != want {
68 t.Errorf(`w.Header().Get("Content-Type") = %q; want %q; on spec.err=%v`, got, want, spec.err)
69 }
70 if got, want := w.Code, spec.status; got != want {
71 t.Errorf("w.Code = %d; want %d", got, want)
72 }
73
74 body := make(map[string]interface{})
75 if err := json.Unmarshal(w.Body.Bytes(), &body); err != nil {
76 t.Errorf("json.Unmarshal(%q, &body) failed with %v; want success", w.Body.Bytes(), err)
77 continue
78 }
79
80 if got, want := body["error"].(string), spec.msg; !strings.Contains(got, want) {
81 t.Errorf(`body["error"] = %q; want %q; on spec.err=%v`, got, want, spec.err)
82 }
83 if got, want := body["message"].(string), spec.msg; !strings.Contains(got, want) {
84 t.Errorf(`body["message"] = %q; want %q; on spec.err=%v`, got, want, spec.err)
85 }
86
87 if spec.details != "" {
88 details, ok := body["details"].([]interface{})
89 if !ok {
90 t.Errorf(`body["details"] = %T; want %T`, body["details"], []interface{}{})
91 continue
92 }
93 if len(details) != 1 {
94 t.Errorf(`len(body["details"]) = %v; want 1`, len(details))
95 continue
96 }
97 if details[0].(map[string]interface{})["@type"] != spec.details {
98 t.Errorf(`details.@type = %s; want %s`, details[0].(map[string]interface{})["@type"], spec.details)
99 }
100 }
101 }
102 }
103
View as plain text