github.com/dgraph-io/dgraph@v1.2.8/graphql/schema/response_test.go (about) 1 /* 2 * Copyright 2019 Dgraph Labs, Inc. and Contributors 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package schema 18 19 import ( 20 "bytes" 21 "testing" 22 23 "github.com/dgraph-io/dgraph/x" 24 "github.com/pkg/errors" 25 "github.com/stretchr/testify/assert" 26 "github.com/vektah/gqlparser/gqlerror" 27 ) 28 29 func TestDataAndErrors(t *testing.T) { 30 31 tests := map[string]struct { 32 data []string 33 errors []error 34 expected string 35 }{ 36 "empty response": { 37 data: nil, 38 errors: nil, 39 expected: `{"extensions": { "requestID": "reqID"}}`, 40 }, 41 "add initial": { 42 data: []string{`"Some": "Data"`}, 43 errors: nil, 44 expected: `{"data": {"Some": "Data"}, "extensions": { "requestID": "reqID"}}`, 45 }, 46 "add nothing": { 47 data: []string{`"Some": "Data"`, ""}, 48 errors: nil, 49 expected: `{"data": {"Some": "Data"}, "extensions": { "requestID": "reqID"}}`, 50 }, 51 "add more": { 52 data: []string{`"Some": "Data"`, `"And": "More"`}, 53 errors: nil, 54 expected: `{ 55 "data": {"Some": "Data", "And": "More"}, 56 "extensions": { "requestID": "reqID"}}`, 57 }, 58 "errors and data": { 59 data: []string{`"Some": "Data"`, `"And": "More"`}, 60 errors: []error{errors.New("An Error")}, 61 expected: `{ 62 "errors":[{"message":"An Error"}], 63 "data": {"Some": "Data", "And": "More"}, 64 "extensions": { "requestID": "reqID"}}`, 65 }, 66 "many errors": { 67 data: []string{`"Some": "Data"`}, 68 errors: []error{errors.New("An Error"), errors.New("Another Error")}, 69 expected: `{ 70 "errors":[{"message":"An Error"}, {"message":"Another Error"}], 71 "data": {"Some": "Data"}, 72 "extensions": { "requestID": "reqID"}}`, 73 }, 74 "gql error": { 75 data: []string{`"Some": "Data"`}, 76 errors: []error{ 77 &x.GqlError{Message: "An Error", Locations: []x.Location{{Line: 1, Column: 1}}}}, 78 expected: `{ 79 "errors":[{"message":"An Error", "locations": [{"line":1,"column":1}]}], 80 "data": {"Some": "Data"}, 81 "extensions": { "requestID": "reqID"}}`, 82 }, 83 "gql error with path": { 84 data: []string{`"Some": "Data"`}, 85 errors: []error{ 86 &x.GqlError{ 87 Message: "An Error", 88 Locations: []x.Location{{Line: 1, Column: 1}}, 89 Path: []interface{}{"q", 2, "n"}}}, 90 expected: `{ 91 "errors":[{ 92 "message":"An Error", 93 "locations": [{"line":1,"column":1}], 94 "path": ["q", 2, "n"]}], 95 "data": {"Some": "Data"}, 96 "extensions": { "requestID": "reqID"}}`, 97 }, 98 "gql error list": { 99 data: []string{`"Some": "Data"`}, 100 errors: []error{x.GqlErrorList{ 101 &x.GqlError{Message: "An Error", Locations: []x.Location{{Line: 1, Column: 1}}}, 102 &x.GqlError{Message: "Another Error", Locations: []x.Location{{Line: 1, Column: 1}}}}}, 103 expected: `{ 104 "errors":[ 105 {"message":"An Error", "locations": [{"line":1,"column":1}]}, 106 {"message":"Another Error", "locations": [{"line":1,"column":1}]}], 107 "data": {"Some": "Data"}, 108 "extensions": { "requestID": "reqID"}}`, 109 }, 110 } 111 112 for name, tcase := range tests { 113 t.Run(name, func(t *testing.T) { 114 resp := &Response{Extensions: &Extensions{RequestID: "reqID"}} 115 116 for _, d := range tcase.data { 117 resp.AddData([]byte(d)) 118 } 119 for _, e := range tcase.errors { 120 resp.WithError(e) 121 } 122 123 buf := new(bytes.Buffer) 124 resp.WriteTo(buf) 125 126 assert.JSONEq(t, tcase.expected, buf.String()) 127 }) 128 } 129 } 130 131 func TestWriteTo_BadDataWithReqID(t *testing.T) { 132 resp := &Response{Extensions: &Extensions{RequestID: "reqID"}} 133 resp.AddData([]byte(`"not json"`)) 134 135 buf := new(bytes.Buffer) 136 resp.WriteTo(buf) 137 138 assert.JSONEq(t, 139 `{"errors":[{"message":"Internal error - failed to marshal a valid JSON response"}], 140 "data": null, 141 "extensions": { "requestID": "reqID"}}`, 142 buf.String()) 143 } 144 145 func TestWriteTo_BadData(t *testing.T) { 146 resp := &Response{} 147 resp.AddData([]byte(`"not json"`)) 148 149 buf := new(bytes.Buffer) 150 resp.WriteTo(buf) 151 152 assert.JSONEq(t, 153 `{"errors":[{"message":"Internal error - failed to marshal a valid JSON response"}], 154 "data": null, 155 "extensions": { "requestID": "unknown request ID"}}`, 156 buf.String()) 157 } 158 159 func TestErrorResponse(t *testing.T) { 160 161 tests := map[string]struct { 162 err error 163 expected string 164 }{ 165 "an error": { 166 err: errors.New("An Error"), 167 expected: `{"errors":[{"message":"An Error"}], "extensions": {"requestID":"reqID"}}`, 168 }, 169 170 "an x.GqlError": { 171 err: x.GqlErrorf("A GraphQL error"). 172 WithLocations(x.Location{Line: 1, Column: 2}), 173 expected: `{"errors":[{"message": "A GraphQL error", "locations": [{"column":2, "line":1}]}], 174 "extensions": {"requestID":"reqID"}}`}, 175 "an x.GqlErrorList": { 176 err: x.GqlErrorList{ 177 x.GqlErrorf("A GraphQL error"), 178 x.GqlErrorf("Another GraphQL error").WithLocations(x.Location{Line: 1, Column: 2})}, 179 expected: `{"errors":[ 180 {"message":"A GraphQL error"}, 181 {"message":"Another GraphQL error", "locations": [{"column":2, "line":1}]}], 182 "extensions": {"requestID":"reqID"}}`}, 183 "a gqlerror": { 184 err: &gqlerror.Error{ 185 Message: "A GraphQL error", 186 Locations: []gqlerror.Location{{Line: 1, Column: 2}}}, 187 expected: `{ 188 "errors":[{"message":"A GraphQL error", "locations": [{"line":1,"column":2}]}], 189 "extensions": {"requestID":"reqID"}}`, 190 }, 191 "a list of gql errors": { 192 err: gqlerror.List{ 193 gqlerror.Errorf("A GraphQL error"), 194 &gqlerror.Error{ 195 Message: "Another GraphQL error", 196 Locations: []gqlerror.Location{{Line: 1, Column: 2}}}}, 197 expected: `{"errors":[ 198 {"message":"A GraphQL error"}, 199 {"message":"Another GraphQL error", "locations": [{"line":1,"column":2}]}], 200 "extensions": {"requestID":"reqID"}}`, 201 }, 202 } 203 204 for name, tcase := range tests { 205 t.Run(name, func(t *testing.T) { 206 207 // ErrorResponse doesn't add data - it should only be called before starting 208 // execution - so in all cases no data should be present. 209 resp := ErrorResponse(tcase.err, "reqID") 210 211 buf := new(bytes.Buffer) 212 resp.WriteTo(buf) 213 214 assert.JSONEq(t, tcase.expected, buf.String()) 215 }) 216 } 217 } 218 219 func TestNilResponse(t *testing.T) { 220 var resp *Response 221 222 buf := new(bytes.Buffer) 223 resp.WriteTo(buf) 224 225 assert.JSONEq(t, 226 `{"errors":[{"message":"Internal error - no response to write."}], 227 "data": null, 228 "extensions": {"requestID":"unknown request ID"}}`, 229 buf.String()) 230 }