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  }