github.com/dgraph-io/dgraph@v1.2.8/graphql/e2e/common/query.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 common
    18  
    19  import (
    20  	"encoding/json"
    21  	"fmt"
    22  	"math/rand"
    23  	"sort"
    24  	"strings"
    25  	"testing"
    26  	"time"
    27  
    28  	"github.com/dgraph-io/dgraph/testutil"
    29  	"github.com/dgraph-io/dgraph/x"
    30  	"github.com/google/go-cmp/cmp"
    31  	"github.com/stretchr/testify/require"
    32  )
    33  
    34  func queryCountryByRegExp(t *testing.T, regexp string, expectedCountries []*country) {
    35  	getCountryParams := &GraphQLParams{
    36  		Query: `query queryCountry($regexp: String!) {
    37  			queryCountry(filter: { name: { regexp: $regexp } }) {
    38  				name
    39  			}
    40  		}`,
    41  		Variables: map[string]interface{}{"regexp": regexp},
    42  	}
    43  
    44  	gqlResponse := getCountryParams.ExecuteAsPost(t, graphqlURL)
    45  	requireNoGQLErrors(t, gqlResponse)
    46  
    47  	var expected, result struct {
    48  		QueryCountry []*country
    49  	}
    50  	expected.QueryCountry = expectedCountries
    51  	err := json.Unmarshal([]byte(gqlResponse.Data), &result)
    52  	require.NoError(t, err)
    53  
    54  	countrySort := func(i, j int) bool {
    55  		return result.QueryCountry[i].Name < result.QueryCountry[j].Name
    56  	}
    57  	sort.Slice(result.QueryCountry, countrySort)
    58  
    59  	if diff := cmp.Diff(expected, result); diff != "" {
    60  		t.Errorf("result mismatch (-want +got):\n%s", diff)
    61  	}
    62  }
    63  
    64  // This test checks that all the different combinations of
    65  // request sending compressed / uncompressed query and receiving
    66  // compressed / uncompressed result.
    67  func gzipCompression(t *testing.T) {
    68  	r := []bool{false, true}
    69  	for _, acceptGzip := range r {
    70  		for _, gzipEncoding := range r {
    71  			t.Run(fmt.Sprintf("TestQueryByType acceptGzip=%t gzipEncoding=%t",
    72  				acceptGzip, gzipEncoding), func(t *testing.T) {
    73  
    74  				queryByTypeWithEncoding(t, acceptGzip, gzipEncoding)
    75  			})
    76  		}
    77  	}
    78  }
    79  
    80  func queryByType(t *testing.T) {
    81  	queryByTypeWithEncoding(t, true, true)
    82  }
    83  
    84  func queryByTypeWithEncoding(t *testing.T, acceptGzip, gzipEncoding bool) {
    85  	queryCountry := &GraphQLParams{
    86  		Query: `query {
    87  			queryCountry {
    88  				name
    89  			}
    90  		}`,
    91  		acceptGzip:   acceptGzip,
    92  		gzipEncoding: gzipEncoding,
    93  	}
    94  
    95  	gqlResponse := queryCountry.ExecuteAsPost(t, graphqlURL)
    96  	requireNoGQLErrors(t, gqlResponse)
    97  
    98  	var expected, result struct {
    99  		QueryCountry []*country
   100  	}
   101  	expected.QueryCountry = []*country{
   102  		&country{Name: "Angola"},
   103  		&country{Name: "Bangladesh"},
   104  		&country{Name: "Mozambique"},
   105  	}
   106  	err := json.Unmarshal([]byte(gqlResponse.Data), &result)
   107  	require.NoError(t, err)
   108  
   109  	sort.Slice(result.QueryCountry, func(i, j int) bool {
   110  		return result.QueryCountry[i].Name < result.QueryCountry[j].Name
   111  	})
   112  
   113  	if diff := cmp.Diff(expected, result); diff != "" {
   114  		t.Errorf("result mismatch (-want +got):\n%s", diff)
   115  	}
   116  }
   117  
   118  func uidAlias(t *testing.T) {
   119  	queryCountry := &GraphQLParams{
   120  		Query: `query {
   121  			queryCountry(order: { asc: name }) {
   122  				uid: name
   123  			}
   124  		}`,
   125  	}
   126  	type countryUID struct {
   127  		UID string
   128  	}
   129  
   130  	gqlResponse := queryCountry.ExecuteAsPost(t, graphqlURL)
   131  	requireNoGQLErrors(t, gqlResponse)
   132  
   133  	var expected, result struct {
   134  		QueryCountry []*countryUID
   135  	}
   136  	expected.QueryCountry = []*countryUID{
   137  		&countryUID{UID: "Angola"},
   138  		&countryUID{UID: "Bangladesh"},
   139  		&countryUID{UID: "Mozambique"},
   140  	}
   141  	err := json.Unmarshal([]byte(gqlResponse.Data), &result)
   142  	require.NoError(t, err)
   143  
   144  	if diff := cmp.Diff(expected, result); diff != "" {
   145  		t.Errorf("result mismatch (-want +got):\n%s", diff)
   146  	}
   147  }
   148  
   149  func orderAtRoot(t *testing.T) {
   150  	queryCountry := &GraphQLParams{
   151  		Query: `query {
   152  			queryCountry(order: { asc: name }) {
   153  				name
   154  			}
   155  		}`,
   156  	}
   157  
   158  	gqlResponse := queryCountry.ExecuteAsPost(t, graphqlURL)
   159  	requireNoGQLErrors(t, gqlResponse)
   160  
   161  	var expected, result struct {
   162  		QueryCountry []*country
   163  	}
   164  	expected.QueryCountry = []*country{
   165  		&country{Name: "Angola"},
   166  		&country{Name: "Bangladesh"},
   167  		&country{Name: "Mozambique"},
   168  	}
   169  	err := json.Unmarshal([]byte(gqlResponse.Data), &result)
   170  	require.NoError(t, err)
   171  
   172  	if diff := cmp.Diff(expected, result); diff != "" {
   173  		t.Errorf("result mismatch (-want +got):\n%s", diff)
   174  	}
   175  }
   176  
   177  func pageAtRoot(t *testing.T) {
   178  	queryCountry := &GraphQLParams{
   179  		Query: `query {
   180  			queryCountry(order: { desc: name }, first: 2, offset: 1) {
   181  				name
   182  			}
   183  		}`,
   184  	}
   185  
   186  	gqlResponse := queryCountry.ExecuteAsPost(t, graphqlURL)
   187  	requireNoGQLErrors(t, gqlResponse)
   188  
   189  	var expected, result struct {
   190  		QueryCountry []*country
   191  	}
   192  	expected.QueryCountry = []*country{
   193  		&country{Name: "Bangladesh"},
   194  		&country{Name: "Angola"},
   195  	}
   196  	err := json.Unmarshal([]byte(gqlResponse.Data), &result)
   197  	require.NoError(t, err)
   198  
   199  	if diff := cmp.Diff(expected, result); diff != "" {
   200  		t.Errorf("result mismatch (-want +got):\n%s", diff)
   201  	}
   202  }
   203  
   204  func regExp(t *testing.T) {
   205  	queryCountryByRegExp(t, "/[Aa]ng/",
   206  		[]*country{
   207  			&country{Name: "Angola"},
   208  			&country{Name: "Bangladesh"},
   209  		})
   210  }
   211  
   212  func multipleSearchIndexes(t *testing.T) {
   213  	query := `query queryPost($filter: PostFilter){
   214  		  queryPost (filter: $filter) {
   215  		      title
   216  		  }
   217  	}`
   218  
   219  	testCases := []interface{}{
   220  		map[string]interface{}{"title": map[string]interface{}{"anyofterms": "Introducing"}},
   221  		map[string]interface{}{"title": map[string]interface {
   222  		}{"alloftext": "Introducing GraphQL in Dgraph"}},
   223  	}
   224  	for _, filter := range testCases {
   225  		getCountryParams := &GraphQLParams{
   226  			Query:     query,
   227  			Variables: map[string]interface{}{"filter": filter},
   228  		}
   229  
   230  		gqlResponse := getCountryParams.ExecuteAsPost(t, graphqlURL)
   231  		requireNoGQLErrors(t, gqlResponse)
   232  
   233  		var expected, result struct {
   234  			QueryPost []*post
   235  		}
   236  
   237  		expected.QueryPost = []*post{
   238  			&post{Title: "Introducing GraphQL in Dgraph"},
   239  		}
   240  		err := json.Unmarshal([]byte(gqlResponse.Data), &result)
   241  		require.NoError(t, err)
   242  
   243  		if diff := cmp.Diff(expected, result); diff != "" {
   244  			t.Errorf("result mismatch (-want +got):\n%s", diff)
   245  		}
   246  	}
   247  }
   248  
   249  func multipleSearchIndexesWrongField(t *testing.T) {
   250  	queryPostParams := &GraphQLParams{
   251  		Query: `query {
   252  			queryPost (filter: {title : { regexp : "/Introducing.*$/" }} ) {
   253  			    title
   254  			}
   255  		}`,
   256  	}
   257  
   258  	gqlResponse := queryPostParams.ExecuteAsPost(t, graphqlURL)
   259  	require.NotNil(t, gqlResponse.Errors)
   260  
   261  	expected := `Field "regexp" is not defined by type StringFullTextFilter_StringTermFilter`
   262  	require.Contains(t, gqlResponse.Errors[0].Error(), expected)
   263  }
   264  
   265  func hashSearch(t *testing.T) {
   266  	queryAuthorParams := &GraphQLParams{
   267  		Query: `query {
   268  			queryAuthor(filter: { name: { eq: "Ann Author" } }) {
   269  				name
   270  				dob
   271  			}
   272  		}`,
   273  	}
   274  
   275  	gqlResponse := queryAuthorParams.ExecuteAsPost(t, graphqlURL)
   276  	requireNoGQLErrors(t, gqlResponse)
   277  
   278  	var expected, result struct {
   279  		QueryAuthor []*author
   280  	}
   281  	dob := time.Date(2000, time.January, 1, 0, 0, 0, 0, time.UTC)
   282  	expected.QueryAuthor = []*author{{Name: "Ann Author", Dob: &dob}}
   283  	err := json.Unmarshal([]byte(gqlResponse.Data), &result)
   284  	require.NoError(t, err)
   285  
   286  	if diff := cmp.Diff(expected, result); diff != "" {
   287  		t.Errorf("result mismatch (-want +got):\n%s", diff)
   288  	}
   289  }
   290  
   291  func allPosts(t *testing.T) []*post {
   292  	queryPostParams := &GraphQLParams{
   293  		Query: `query {
   294  			queryPost {
   295  				postID
   296  				title
   297  				text
   298  				tags
   299  				numLikes
   300  				isPublished
   301  				postType
   302  			}
   303  		}`,
   304  	}
   305  	gqlResponse := queryPostParams.ExecuteAsPost(t, graphqlURL)
   306  	requireNoGQLErrors(t, gqlResponse)
   307  
   308  	var result struct {
   309  		QueryPost []*post
   310  	}
   311  	err := json.Unmarshal([]byte(gqlResponse.Data), &result)
   312  	require.NoError(t, err)
   313  
   314  	require.Equal(t, 4, len(result.QueryPost))
   315  
   316  	return result.QueryPost
   317  }
   318  
   319  func deepFilter(t *testing.T) {
   320  	getAuthorParams := &GraphQLParams{
   321  		Query: `query {
   322  			queryAuthor(filter: { name: { eq: "Ann Other Author" } }) {
   323  				name
   324  				posts(filter: { title: { anyofterms: "GraphQL" } }) {
   325  					title
   326  				}
   327  			}
   328  		}`,
   329  	}
   330  
   331  	gqlResponse := getAuthorParams.ExecuteAsPost(t, graphqlURL)
   332  	requireNoGQLErrors(t, gqlResponse)
   333  
   334  	var result struct {
   335  		QueryAuthor []*author
   336  	}
   337  	err := json.Unmarshal([]byte(gqlResponse.Data), &result)
   338  	require.NoError(t, err)
   339  	require.Equal(t, 1, len(result.QueryAuthor))
   340  
   341  	expected := &author{
   342  		Name:  "Ann Other Author",
   343  		Posts: []*post{{Title: "Learning GraphQL in Dgraph"}},
   344  	}
   345  
   346  	if diff := cmp.Diff(expected, result.QueryAuthor[0]); diff != "" {
   347  		t.Errorf("result mismatch (-want +got):\n%s", diff)
   348  	}
   349  }
   350  
   351  // manyQueries runs multiple queries in the one block.  Internally, the GraphQL
   352  // server should run those concurrently, but the results should be returned in the
   353  // requested order.  This makes sure those many test runs are reassembled correctly.
   354  func manyQueries(t *testing.T) {
   355  	posts := allPosts(t)
   356  
   357  	getPattern := `getPost(postID: "%s") {
   358  		postID
   359  		title
   360  		text
   361  		tags
   362  		isPublished
   363  		postType
   364  		numLikes
   365  	}
   366  	`
   367  
   368  	var bld strings.Builder
   369  	x.Check2(bld.WriteString("query {\n"))
   370  	for idx, p := range posts {
   371  		x.Check2(bld.WriteString(fmt.Sprintf("  query%v : ", idx)))
   372  		x.Check2(bld.WriteString(fmt.Sprintf(getPattern, p.PostID)))
   373  	}
   374  	x.Check2(bld.WriteString("}"))
   375  
   376  	queryParams := &GraphQLParams{
   377  		Query: bld.String(),
   378  	}
   379  
   380  	gqlResponse := queryParams.ExecuteAsPost(t, graphqlURL)
   381  	requireNoGQLErrors(t, gqlResponse)
   382  
   383  	var result map[string]*post
   384  	err := json.Unmarshal([]byte(gqlResponse.Data), &result)
   385  	require.NoError(t, err)
   386  
   387  	for idx, expectedPost := range posts {
   388  		resultPost := result[fmt.Sprintf("query%v", idx)]
   389  		if diff := cmp.Diff(expectedPost, resultPost); diff != "" {
   390  			t.Errorf("result mismatch (-want +got):\n%s", diff)
   391  		}
   392  	}
   393  }
   394  
   395  func queryOrderAtRoot(t *testing.T) {
   396  	posts := allPosts(t)
   397  
   398  	answers := make([]*post, 2)
   399  	for _, p := range posts {
   400  		if p.NumLikes == 77 {
   401  			answers[0] = p
   402  		} else if p.NumLikes == 100 {
   403  			answers[1] = p
   404  		}
   405  	}
   406  
   407  	filter := map[string]interface{}{
   408  		"postID": []string{answers[0].PostID, answers[1].PostID},
   409  	}
   410  
   411  	orderLikesDesc := map[string]interface{}{
   412  		"desc": "numLikes",
   413  	}
   414  
   415  	orderLikesAsc := map[string]interface{}{
   416  		"asc": "numLikes",
   417  	}
   418  
   419  	var result, expected struct {
   420  		QueryPost []*post
   421  	}
   422  
   423  	cases := map[string]struct {
   424  		Order    map[string]interface{}
   425  		First    int
   426  		Offset   int
   427  		Expected []*post
   428  	}{
   429  		"orderAsc": {
   430  			Order:    orderLikesAsc,
   431  			First:    2,
   432  			Offset:   0,
   433  			Expected: []*post{answers[0], answers[1]},
   434  		},
   435  		"orderDesc": {
   436  			Order:    orderLikesDesc,
   437  			First:    2,
   438  			Offset:   0,
   439  			Expected: []*post{answers[1], answers[0]},
   440  		},
   441  		"first": {
   442  			Order:    orderLikesDesc,
   443  			First:    1,
   444  			Offset:   0,
   445  			Expected: []*post{answers[1]},
   446  		},
   447  		"offset": {
   448  			Order:    orderLikesDesc,
   449  			First:    2,
   450  			Offset:   1,
   451  			Expected: []*post{answers[0]},
   452  		},
   453  	}
   454  
   455  	for name, test := range cases {
   456  		t.Run(name, func(t *testing.T) {
   457  			getParams := &GraphQLParams{
   458  				Query: `query queryPost($filter: PostFilter, $order: PostOrder,
   459  		$first: Int, $offset: Int) {
   460  			queryPost(
   461  			  filter: $filter,
   462  			  order: $order,
   463  			  first: $first,
   464  			  offset: $offset) {
   465  				postID
   466  				title
   467  				text
   468  				tags
   469  				isPublished
   470  				postType
   471  				numLikes
   472  			}
   473  		}
   474  		`,
   475  				Variables: map[string]interface{}{
   476  					"filter": filter,
   477  					"order":  test.Order,
   478  					"first":  test.First,
   479  					"offset": test.Offset,
   480  				},
   481  			}
   482  
   483  			gqlResponse := getParams.ExecuteAsPost(t, graphqlURL)
   484  			requireNoGQLErrors(t, gqlResponse)
   485  
   486  			expected.QueryPost = test.Expected
   487  			err := json.Unmarshal([]byte(gqlResponse.Data), &result)
   488  			require.NoError(t, err)
   489  
   490  			require.Equal(t, len(result.QueryPost), len(expected.QueryPost))
   491  			if diff := cmp.Diff(expected, result); diff != "" {
   492  				t.Errorf("result mismatch (-want +got):\n%s", diff)
   493  			}
   494  		})
   495  	}
   496  
   497  }
   498  
   499  // queriesWithError runs multiple queries in the one block with
   500  // an error.  Internally, the GraphQL server should run those concurrently, and
   501  // an error in one query should not affect the results of any others.
   502  func queriesWithError(t *testing.T) {
   503  	posts := allPosts(t)
   504  
   505  	getPattern := `getPost(postID: "%s") {
   506  		postID
   507  		title
   508  		text
   509  		tags
   510  		isPublished
   511  		postType
   512  		numLikes
   513  	}
   514  	`
   515  
   516  	// make one random query fail
   517  	shouldFail := rand.New(rand.NewSource(time.Now().UnixNano())).Intn(len(posts))
   518  
   519  	var bld strings.Builder
   520  	x.Check2(bld.WriteString("query {\n"))
   521  	for idx, p := range posts {
   522  		x.Check2(bld.WriteString(fmt.Sprintf("  query%v : ", idx)))
   523  		if idx == shouldFail {
   524  			x.Check2(bld.WriteString(fmt.Sprintf(getPattern, "Not_An_ID")))
   525  		} else {
   526  			x.Check2(bld.WriteString(fmt.Sprintf(getPattern, p.PostID)))
   527  		}
   528  	}
   529  	x.Check2(bld.WriteString("}"))
   530  
   531  	queryParams := &GraphQLParams{
   532  		Query: bld.String(),
   533  	}
   534  
   535  	gqlResponse := queryParams.ExecuteAsPost(t, graphqlURL)
   536  	require.Len(t, gqlResponse.Errors, 1, "expected 1 error from malformed query")
   537  
   538  	var result map[string]*post
   539  	err := json.Unmarshal([]byte(gqlResponse.Data), &result)
   540  	require.NoError(t, err)
   541  
   542  	for idx, expectedPost := range posts {
   543  		resultPost := result[fmt.Sprintf("query%v", idx)]
   544  		if idx == shouldFail {
   545  			require.Nil(t, resultPost, "expected this query to fail and return nil")
   546  		} else {
   547  			if diff := cmp.Diff(expectedPost, resultPost); diff != "" {
   548  				t.Errorf("result mismatch (-want +got):\n%s", diff)
   549  			}
   550  		}
   551  	}
   552  }
   553  
   554  func dateFilters(t *testing.T) {
   555  	cases := map[string]struct {
   556  		Filter   interface{}
   557  		Expected []*author
   558  	}{
   559  		"less than": {
   560  			Filter:   map[string]interface{}{"dob": map[string]interface{}{"lt": "2000-01-01"}},
   561  			Expected: []*author{{Name: "Ann Other Author"}}},
   562  		"less or equal": {
   563  			Filter:   map[string]interface{}{"dob": map[string]interface{}{"le": "2000-01-01"}},
   564  			Expected: []*author{{Name: "Ann Author"}, {Name: "Ann Other Author"}}},
   565  		"equal": {
   566  			Filter:   map[string]interface{}{"dob": map[string]interface{}{"eq": "2000-01-01"}},
   567  			Expected: []*author{{Name: "Ann Author"}}},
   568  		"greater or equal": {
   569  			Filter:   map[string]interface{}{"dob": map[string]interface{}{"ge": "2000-01-01"}},
   570  			Expected: []*author{{Name: "Ann Author"}, {Name: "Three Author"}}},
   571  		"greater than": {
   572  			Filter:   map[string]interface{}{"dob": map[string]interface{}{"gt": "2000-01-01"}},
   573  			Expected: []*author{{Name: "Three Author"}}},
   574  	}
   575  
   576  	for name, test := range cases {
   577  		t.Run(name, func(t *testing.T) {
   578  			authorTest(t, test.Filter, test.Expected)
   579  		})
   580  	}
   581  }
   582  
   583  func floatFilters(t *testing.T) {
   584  	cases := map[string]struct {
   585  		Filter   interface{}
   586  		Expected []*author
   587  	}{
   588  		"less than": {
   589  			Filter:   map[string]interface{}{"reputation": map[string]interface{}{"lt": 8.9}},
   590  			Expected: []*author{{Name: "Ann Author"}}},
   591  		"less or equal": {
   592  			Filter:   map[string]interface{}{"reputation": map[string]interface{}{"le": 8.9}},
   593  			Expected: []*author{{Name: "Ann Author"}, {Name: "Ann Other Author"}}},
   594  		"equal": {
   595  			Filter:   map[string]interface{}{"reputation": map[string]interface{}{"eq": 8.9}},
   596  			Expected: []*author{{Name: "Ann Other Author"}}},
   597  		"greater or equal": {
   598  			Filter:   map[string]interface{}{"reputation": map[string]interface{}{"ge": 8.9}},
   599  			Expected: []*author{{Name: "Ann Other Author"}, {Name: "Three Author"}}},
   600  		"greater than": {
   601  			Filter:   map[string]interface{}{"reputation": map[string]interface{}{"gt": 8.9}},
   602  			Expected: []*author{{Name: "Three Author"}}},
   603  	}
   604  
   605  	for name, test := range cases {
   606  		t.Run(name, func(t *testing.T) {
   607  			authorTest(t, test.Filter, test.Expected)
   608  		})
   609  	}
   610  }
   611  
   612  func authorTest(t *testing.T, filter interface{}, expected []*author) {
   613  	queryParams := &GraphQLParams{
   614  		Query: `query filterVariable($filter: AuthorFilter) {
   615  			queryAuthor(filter: $filter, order: { asc: name }) {
   616  				name
   617  			}
   618  		}`,
   619  		Variables: map[string]interface{}{"filter": filter},
   620  	}
   621  
   622  	gqlResponse := queryParams.ExecuteAsPost(t, graphqlURL)
   623  	requireNoGQLErrors(t, gqlResponse)
   624  
   625  	var result struct {
   626  		QueryAuthor []*author
   627  	}
   628  	err := json.Unmarshal([]byte(gqlResponse.Data), &result)
   629  	require.NoError(t, err)
   630  
   631  	if diff := cmp.Diff(expected, result.QueryAuthor); diff != "" {
   632  		t.Errorf("result mismatch (-want +got):\n%s", diff)
   633  	}
   634  }
   635  
   636  func intFilters(t *testing.T) {
   637  	cases := map[string]struct {
   638  		Filter   interface{}
   639  		Expected []*post
   640  	}{
   641  		"less than": {
   642  			Filter: map[string]interface{}{"numLikes": map[string]interface{}{"lt": 87}},
   643  			Expected: []*post{
   644  				{Title: "GraphQL doco"},
   645  				{Title: "Random post"}}},
   646  		"less or equal": {
   647  			Filter: map[string]interface{}{"numLikes": map[string]interface{}{"le": 87}},
   648  			Expected: []*post{
   649  				{Title: "GraphQL doco"},
   650  				{Title: "Learning GraphQL in Dgraph"},
   651  				{Title: "Random post"}}},
   652  		"equal": {
   653  			Filter:   map[string]interface{}{"numLikes": map[string]interface{}{"eq": 87}},
   654  			Expected: []*post{{Title: "Learning GraphQL in Dgraph"}}},
   655  		"greater or equal": {
   656  			Filter: map[string]interface{}{"numLikes": map[string]interface{}{"ge": 87}},
   657  			Expected: []*post{
   658  				{Title: "Introducing GraphQL in Dgraph"},
   659  				{Title: "Learning GraphQL in Dgraph"}}},
   660  		"greater than": {
   661  			Filter:   map[string]interface{}{"numLikes": map[string]interface{}{"gt": 87}},
   662  			Expected: []*post{{Title: "Introducing GraphQL in Dgraph"}}},
   663  	}
   664  
   665  	for name, test := range cases {
   666  		t.Run(name, func(t *testing.T) {
   667  			postTest(t, test.Filter, test.Expected)
   668  		})
   669  	}
   670  }
   671  
   672  func booleanFilters(t *testing.T) {
   673  	cases := map[string]struct {
   674  		Filter   interface{}
   675  		Expected []*post
   676  	}{
   677  		"true": {
   678  			Filter: map[string]interface{}{"isPublished": true},
   679  			Expected: []*post{
   680  				{Title: "GraphQL doco"},
   681  				{Title: "Introducing GraphQL in Dgraph"},
   682  				{Title: "Learning GraphQL in Dgraph"}}},
   683  		"false": {
   684  			Filter:   map[string]interface{}{"isPublished": false},
   685  			Expected: []*post{{Title: "Random post"}}},
   686  	}
   687  
   688  	for name, test := range cases {
   689  		t.Run(name, func(t *testing.T) {
   690  			postTest(t, test.Filter, test.Expected)
   691  		})
   692  	}
   693  }
   694  
   695  func termFilters(t *testing.T) {
   696  	cases := map[string]struct {
   697  		Filter   interface{}
   698  		Expected []*post
   699  	}{
   700  		"all of terms": {
   701  			Filter: map[string]interface{}{
   702  				"title": map[string]interface{}{"allofterms": "GraphQL Dgraph"}},
   703  			Expected: []*post{
   704  				{Title: "Introducing GraphQL in Dgraph"},
   705  				{Title: "Learning GraphQL in Dgraph"}}},
   706  		"any of terms": {
   707  			Filter: map[string]interface{}{
   708  				"title": map[string]interface{}{"anyofterms": "GraphQL Dgraph"}},
   709  			Expected: []*post{
   710  				{Title: "GraphQL doco"},
   711  				{Title: "Introducing GraphQL in Dgraph"},
   712  				{Title: "Learning GraphQL in Dgraph"}}},
   713  	}
   714  
   715  	for name, test := range cases {
   716  		t.Run(name, func(t *testing.T) {
   717  			postTest(t, test.Filter, test.Expected)
   718  		})
   719  	}
   720  }
   721  
   722  func fullTextFilters(t *testing.T) {
   723  	cases := map[string]struct {
   724  		Filter   interface{}
   725  		Expected []*post
   726  	}{
   727  		"all of text": {
   728  			Filter: map[string]interface{}{
   729  				"text": map[string]interface{}{"alloftext": "learn GraphQL"}},
   730  			Expected: []*post{
   731  				{Title: "GraphQL doco"},
   732  				{Title: "Learning GraphQL in Dgraph"}}},
   733  		"any of text": {
   734  			Filter: map[string]interface{}{
   735  				"text": map[string]interface{}{"anyoftext": "learn GraphQL"}},
   736  			Expected: []*post{
   737  				{Title: "GraphQL doco"},
   738  				{Title: "Introducing GraphQL in Dgraph"},
   739  				{Title: "Learning GraphQL in Dgraph"}}},
   740  	}
   741  
   742  	for name, test := range cases {
   743  		t.Run(name, func(t *testing.T) {
   744  			postTest(t, test.Filter, test.Expected)
   745  		})
   746  	}
   747  }
   748  
   749  func stringExactFilters(t *testing.T) {
   750  	cases := map[string]struct {
   751  		Filter   interface{}
   752  		Expected []*post
   753  	}{
   754  		"less than": {
   755  			Filter:   map[string]interface{}{"topic": map[string]interface{}{"lt": "GraphQL"}},
   756  			Expected: []*post{{Title: "GraphQL doco"}}},
   757  		"less or equal": {
   758  			Filter: map[string]interface{}{"topic": map[string]interface{}{"le": "GraphQL"}},
   759  			Expected: []*post{
   760  				{Title: "GraphQL doco"},
   761  				{Title: "Introducing GraphQL in Dgraph"}}},
   762  		"equal": {
   763  			Filter:   map[string]interface{}{"topic": map[string]interface{}{"eq": "GraphQL"}},
   764  			Expected: []*post{{Title: "Introducing GraphQL in Dgraph"}}},
   765  		"greater or equal": {
   766  			Filter: map[string]interface{}{"topic": map[string]interface{}{"ge": "GraphQL"}},
   767  			Expected: []*post{
   768  				{Title: "Introducing GraphQL in Dgraph"},
   769  				{Title: "Learning GraphQL in Dgraph"},
   770  				{Title: "Random post"}}},
   771  		"greater than": {
   772  			Filter: map[string]interface{}{"topic": map[string]interface{}{"gt": "GraphQL"}},
   773  			Expected: []*post{
   774  				{Title: "Learning GraphQL in Dgraph"},
   775  				{Title: "Random post"}}},
   776  	}
   777  
   778  	for name, test := range cases {
   779  		t.Run(name, func(t *testing.T) {
   780  			postTest(t, test.Filter, test.Expected)
   781  		})
   782  	}
   783  }
   784  
   785  func scalarListFilters(t *testing.T) {
   786  
   787  	// tags is a list of strings with @search(by: exact).  So all the filters
   788  	// lt, le, ... mean "is there something in the list that's lt 'Dgraph'", etc.
   789  
   790  	cases := map[string]struct {
   791  		Filter   interface{}
   792  		Expected []*post
   793  	}{
   794  		"less than": {
   795  			Filter:   map[string]interface{}{"tags": map[string]interface{}{"lt": "Dgraph"}},
   796  			Expected: []*post{{Title: "Introducing GraphQL in Dgraph"}}},
   797  		"less or equal": {
   798  			Filter: map[string]interface{}{"tags": map[string]interface{}{"le": "Dgraph"}},
   799  			Expected: []*post{
   800  				{Title: "GraphQL doco"},
   801  				{Title: "Introducing GraphQL in Dgraph"},
   802  				{Title: "Learning GraphQL in Dgraph"}}},
   803  		"equal": {
   804  			Filter:   map[string]interface{}{"tags": map[string]interface{}{"eq": "Database"}},
   805  			Expected: []*post{{Title: "Introducing GraphQL in Dgraph"}}},
   806  		"greater or equal": {
   807  			Filter: map[string]interface{}{"tags": map[string]interface{}{"ge": "Dgraph"}},
   808  			Expected: []*post{
   809  				{Title: "GraphQL doco"},
   810  				{Title: "Introducing GraphQL in Dgraph"},
   811  				{Title: "Learning GraphQL in Dgraph"},
   812  				{Title: "Random post"}}},
   813  		"greater than": {
   814  			Filter:   map[string]interface{}{"tags": map[string]interface{}{"gt": "GraphQL"}},
   815  			Expected: []*post{{Title: "Random post"}}},
   816  	}
   817  
   818  	for name, test := range cases {
   819  		t.Run(name, func(t *testing.T) {
   820  			postTest(t, test.Filter, test.Expected)
   821  		})
   822  	}
   823  }
   824  
   825  func postTest(t *testing.T, filter interface{}, expected []*post) {
   826  	queryParams := &GraphQLParams{
   827  		Query: `query filterVariable($filter: PostFilter) {
   828  			queryPost(filter: $filter, order: { asc: title }) {
   829  				title
   830  			}
   831  		}`,
   832  		Variables: map[string]interface{}{"filter": filter},
   833  	}
   834  
   835  	gqlResponse := queryParams.ExecuteAsPost(t, graphqlURL)
   836  	requireNoGQLErrors(t, gqlResponse)
   837  
   838  	var result struct {
   839  		QueryPost []*post
   840  	}
   841  	err := json.Unmarshal([]byte(gqlResponse.Data), &result)
   842  	require.NoError(t, err)
   843  
   844  	if diff := cmp.Diff(expected, result.QueryPost); diff != "" {
   845  		t.Errorf("result mismatch (-want +got):\n%s", diff)
   846  	}
   847  }
   848  
   849  func skipDirective(t *testing.T) {
   850  	getAuthorParams := &GraphQLParams{
   851  		Query: `query ($skipPost: Boolean!, $skipName: Boolean!) {
   852  			queryAuthor(filter: { name: { eq: "Ann Other Author" } }) {
   853  				name @skip(if: $skipName)
   854  				dob
   855  				reputation
   856  				posts @skip(if: $skipPost) {
   857  					title
   858  				}
   859  			}
   860  		}`,
   861  		Variables: map[string]interface{}{
   862  			"skipPost": true,
   863  			"skipName": false,
   864  		},
   865  	}
   866  
   867  	gqlResponse := getAuthorParams.ExecuteAsPost(t, graphqlURL)
   868  	requireNoGQLErrors(t, gqlResponse)
   869  
   870  	expected := `{"queryAuthor":[{"name":"Ann Other Author",
   871  		"dob":"1988-01-01T00:00:00Z","reputation":8.9}]}`
   872  	require.JSONEq(t, expected, string(gqlResponse.Data))
   873  }
   874  
   875  func includeDirective(t *testing.T) {
   876  	getAuthorParams := &GraphQLParams{
   877  		Query: `query ($includeName: Boolean!, $includePost: Boolean!) {
   878  			queryAuthor(filter: { name: { eq: "Ann Other Author" } }) {
   879  			  name @include(if: $includeName)
   880  			  dob
   881  			  posts @include(if: $includePost) {
   882  				title
   883  			  }
   884  			}
   885  		  }`,
   886  		Variables: map[string]interface{}{
   887  			"includeName": true,
   888  			"includePost": false,
   889  		},
   890  	}
   891  
   892  	gqlResponse := getAuthorParams.ExecuteAsPost(t, graphqlURL)
   893  	requireNoGQLErrors(t, gqlResponse)
   894  
   895  	expected := `{"queryAuthor":[{"name":"Ann Other Author","dob":"1988-01-01T00:00:00Z"}]}`
   896  	require.JSONEq(t, expected, string(gqlResponse.Data))
   897  }
   898  
   899  func includeAndSkipDirective(t *testing.T) {
   900  	getAuthorParams := &GraphQLParams{
   901  		Query: `query ($includeFalse: Boolean!, $skipTrue: Boolean!, $includeTrue: Boolean!,
   902  			$skipFalse: Boolean!) {
   903  			queryAuthor (filter: { name: { eq: "Ann Other Author" } }) {
   904  			  dob @include(if: $includeFalse) @skip(if: $skipFalse)
   905  			  reputation @include(if: $includeFalse) @skip(if: $skipTrue)
   906  			  name @include(if: $includeTrue) @skip(if: $skipFalse)
   907  			  posts(filter: { title: { anyofterms: "GraphQL" } }, first: 10)
   908  			    @include(if: $includeTrue) @skip(if: $skipTrue) {
   909  				title
   910  				tags
   911  			  }
   912  			}
   913  		  }`,
   914  		Variables: map[string]interface{}{
   915  			"includeFalse": false,
   916  			"includeTrue":  true,
   917  			"skipFalse":    false,
   918  			"skipTrue":     true,
   919  		},
   920  	}
   921  
   922  	gqlResponse := getAuthorParams.ExecuteAsPost(t, graphqlURL)
   923  	requireNoGQLErrors(t, gqlResponse)
   924  
   925  	expected := `{"queryAuthor":[{"name":"Ann Other Author"}]}`
   926  	require.JSONEq(t, expected, string(gqlResponse.Data))
   927  }
   928  
   929  func queryByMultipleIds(t *testing.T) {
   930  	posts := allPosts(t)
   931  	ids := make([]string, 0, len(posts))
   932  	for _, post := range posts {
   933  		ids = append(ids, post.PostID)
   934  	}
   935  
   936  	queryParams := &GraphQLParams{
   937  		Query: `query queryPost($filter: PostFilter) {
   938  			queryPost(filter: $filter) {
   939  				postID
   940  				title
   941  				text
   942  				tags
   943  				numLikes
   944  				isPublished
   945  				postType
   946  			}
   947  		}`,
   948  		Variables: map[string]interface{}{"filter": map[string]interface{}{
   949  			"postID": ids,
   950  		}},
   951  	}
   952  
   953  	gqlResponse := queryParams.ExecuteAsPost(t, graphqlURL)
   954  	requireNoGQLErrors(t, gqlResponse)
   955  
   956  	var result struct {
   957  		QueryPost []*post
   958  	}
   959  	err := json.Unmarshal([]byte(gqlResponse.Data), &result)
   960  	require.NoError(t, err)
   961  	if diff := cmp.Diff(posts, result.QueryPost); diff != "" {
   962  		t.Errorf("result mismatch (-want +got):\n%s", diff)
   963  	}
   964  }
   965  
   966  func enumFilter(t *testing.T) {
   967  	posts := allPosts(t)
   968  
   969  	queryParams := &GraphQLParams{
   970  		Query: `query queryPost($filter: PostFilter) {
   971  			queryPost(filter: $filter) {
   972  				postID
   973  				title
   974  				text
   975  				tags
   976  				numLikes
   977  				isPublished
   978  				postType
   979  			}
   980  		}`,
   981  	}
   982  
   983  	facts := make([]*post, 0, len(posts))
   984  	questions := make([]*post, 0, len(posts))
   985  	for _, post := range posts {
   986  		if post.PostType == "Fact" {
   987  			facts = append(facts, post)
   988  		}
   989  		if post.PostType == "Question" {
   990  			questions = append(questions, post)
   991  		}
   992  	}
   993  
   994  	cases := map[string]struct {
   995  		Filter   interface{}
   996  		Expected []*post
   997  	}{
   998  		"Hash Filter test": {
   999  			Filter: map[string]interface{}{
  1000  				"postType": map[string]interface{}{
  1001  					"eq": "Fact",
  1002  				},
  1003  			},
  1004  			Expected: facts,
  1005  		},
  1006  
  1007  		"Regexp Filter test": {
  1008  			Filter: map[string]interface{}{
  1009  				"postType": map[string]interface{}{
  1010  					"regexp": "/(Fact)|(Question)/",
  1011  				},
  1012  			},
  1013  			Expected: append(questions, facts...),
  1014  		},
  1015  	}
  1016  
  1017  	for name, test := range cases {
  1018  		t.Run(name, func(t *testing.T) {
  1019  			queryParams.Variables = map[string]interface{}{"filter": test.Filter}
  1020  
  1021  			gqlResponse := queryParams.ExecuteAsPost(t, graphqlURL)
  1022  			requireNoGQLErrors(t, gqlResponse)
  1023  
  1024  			var result struct {
  1025  				QueryPost []*post
  1026  			}
  1027  
  1028  			postSort := func(i, j int) bool {
  1029  				return result.QueryPost[i].Title < result.QueryPost[j].Title
  1030  			}
  1031  			testSort := func(i, j int) bool {
  1032  				return test.Expected[i].Title < test.Expected[j].Title
  1033  			}
  1034  
  1035  			err := json.Unmarshal([]byte(gqlResponse.Data), &result)
  1036  			sort.Slice(result.QueryPost, postSort)
  1037  			sort.Slice(test.Expected, testSort)
  1038  
  1039  			require.NoError(t, err)
  1040  			if diff := cmp.Diff(test.Expected, result.QueryPost); diff != "" {
  1041  				t.Errorf("result mismatch (-want +got):\n%s", diff)
  1042  			}
  1043  		})
  1044  
  1045  	}
  1046  }
  1047  
  1048  func queryTypename(t *testing.T) {
  1049  	getCountryParams := &GraphQLParams{
  1050  		Query: `query queryCountry {
  1051  			queryCountry {
  1052  				name
  1053  				__typename
  1054  			}
  1055  		}`,
  1056  	}
  1057  
  1058  	gqlResponse := getCountryParams.ExecuteAsPost(t, graphqlURL)
  1059  	requireNoGQLErrors(t, gqlResponse)
  1060  
  1061  	expected := `{
  1062  	"queryCountry": [
  1063            {
  1064                  "name": "Angola",
  1065                  "__typename": "Country"
  1066            },
  1067            {
  1068                  "name": "Bangladesh",
  1069                  "__typename": "Country"
  1070            },
  1071            {
  1072                  "name": "Mozambique",
  1073                  "__typename": "Country"
  1074            }
  1075          ]
  1076  }`
  1077  	testutil.CompareJSON(t, expected, string(gqlResponse.Data))
  1078  
  1079  }
  1080  
  1081  func queryNestedTypename(t *testing.T) {
  1082  	getCountryParams := &GraphQLParams{
  1083  		Query: `query {
  1084  			queryAuthor(filter: { name: { eq: "Ann Author" } }) {
  1085  				name
  1086  				dob
  1087  				posts {
  1088  					title
  1089  					__typename
  1090  				}
  1091  			}
  1092  		}`,
  1093  	}
  1094  
  1095  	gqlResponse := getCountryParams.ExecuteAsPost(t, graphqlURL)
  1096  	requireNoGQLErrors(t, gqlResponse)
  1097  
  1098  	expected := `{
  1099  	"queryAuthor": [
  1100  	  {
  1101  		"name": "Ann Author",
  1102  		"dob": "2000-01-01T00:00:00Z",
  1103  		"posts": [
  1104  		  {
  1105  			"title": "Introducing GraphQL in Dgraph",
  1106  			"__typename": "Post"
  1107  		  },
  1108  		  {
  1109  			"title": "GraphQL doco",
  1110  			"__typename": "Post"
  1111  		  }
  1112  		]
  1113  	  }
  1114  	]
  1115  }`
  1116  	testutil.CompareJSON(t, expected, string(gqlResponse.Data))
  1117  }
  1118  
  1119  func typenameForInterface(t *testing.T) {
  1120  	newStarship := addStarship(t)
  1121  	humanID := addHuman(t, newStarship.ID)
  1122  	droidID := addDroid(t)
  1123  	updateCharacter(t, humanID)
  1124  
  1125  	t.Run("test __typename for interface types", func(t *testing.T) {
  1126  		queryCharacterParams := &GraphQLParams{
  1127  			Query: `query {
  1128  				queryCharacter (filter: {
  1129  					appearsIn: {
  1130  						eq: [EMPIRE]
  1131  					}
  1132  				}) {
  1133  					name
  1134  					__typename
  1135  					... on Human {
  1136  						totalCredits
  1137  			                }
  1138  					... on Droid {
  1139  						primaryFunction
  1140  			                }
  1141  				}
  1142  			}`,
  1143  		}
  1144  
  1145  		expected := `{
  1146  		"queryCharacter": [
  1147  		  {
  1148  			"name":"Han Solo",
  1149  			"__typename": "Human",
  1150  			"totalCredits": 10
  1151  		  },
  1152  		  {
  1153  			"name": "R2-D2",
  1154  			"__typename": "Droid",
  1155  			"primaryFunction": "Robot"
  1156  		  }
  1157  		]
  1158  	  }`
  1159  
  1160  		gqlResponse := queryCharacterParams.ExecuteAsPost(t, graphqlURL)
  1161  		requireNoGQLErrors(t, gqlResponse)
  1162  		testutil.CompareJSON(t, expected, string(gqlResponse.Data))
  1163  	})
  1164  
  1165  	cleanupStarwars(t, newStarship.ID, humanID, droidID)
  1166  }
  1167  
  1168  func defaultEnumFilter(t *testing.T) {
  1169  	newStarship := addStarship(t)
  1170  	humanID := addHuman(t, newStarship.ID)
  1171  	droidID := addDroid(t)
  1172  	updateCharacter(t, humanID)
  1173  
  1174  	t.Run("test query enum default index on appearsIn", func(t *testing.T) {
  1175  		queryCharacterParams := &GraphQLParams{
  1176  			Query: `query {
  1177  				queryCharacter (filter: {
  1178  					appearsIn: {
  1179  						eq: [EMPIRE]
  1180  					}
  1181  				}) {
  1182  					name
  1183  					appearsIn
  1184  				}
  1185  			}`,
  1186  		}
  1187  
  1188  		gqlResponse := queryCharacterParams.ExecuteAsPost(t, graphqlURL)
  1189  		requireNoGQLErrors(t, gqlResponse)
  1190  
  1191  		expected := `{
  1192  		"queryCharacter": [
  1193  		  {
  1194  			"name":"Han Solo",
  1195  			"appearsIn": ["EMPIRE"]
  1196  		  },
  1197  		  {
  1198  			"name": "R2-D2",
  1199  			"appearsIn": ["EMPIRE"]
  1200  		  }
  1201  		]
  1202  	  }`
  1203  		testutil.CompareJSON(t, expected, string(gqlResponse.Data))
  1204  	})
  1205  
  1206  	cleanupStarwars(t, newStarship.ID, humanID, droidID)
  1207  }
  1208  
  1209  func queryByMultipleInvalidIds(t *testing.T) {
  1210  	queryParams := &GraphQLParams{
  1211  		Query: `query queryPost($filter: PostFilter) {
  1212  			queryPost(filter: $filter) {
  1213  				postID
  1214  				title
  1215  				text
  1216  				tags
  1217  				numLikes
  1218  				isPublished
  1219  				postType
  1220  			}
  1221  		}`,
  1222  		Variables: map[string]interface{}{"filter": map[string]interface{}{
  1223  			"postID": []string{"foo", "bar"},
  1224  		}},
  1225  	}
  1226  	// Since the ids are invalid and can't be converted to uint64, the query sent to Dgraph should
  1227  	// have func: uid() at root and should return 0 results.
  1228  
  1229  	gqlResponse := queryParams.ExecuteAsPost(t, graphqlURL)
  1230  	requireNoGQLErrors(t, gqlResponse)
  1231  
  1232  	require.Equal(t, `{"queryPost":[]}`, string(gqlResponse.Data))
  1233  	var result struct {
  1234  		QueryPost []*post
  1235  	}
  1236  	err := json.Unmarshal([]byte(gqlResponse.Data), &result)
  1237  	require.NoError(t, err)
  1238  	require.Equal(t, 0, len(result.QueryPost))
  1239  }
  1240  
  1241  func getStateByXid(t *testing.T) {
  1242  	getStateParams := &GraphQLParams{
  1243  		Query: `{
  1244  			getState(xcode: "nsw") {
  1245  				name
  1246  			}
  1247  		}`,
  1248  	}
  1249  
  1250  	gqlResponse := getStateParams.ExecuteAsPost(t, graphqlURL)
  1251  	requireNoGQLErrors(t, gqlResponse)
  1252  	require.Equal(t, `{"getState":{"name":"NSW"}}`, string(gqlResponse.Data))
  1253  }
  1254  
  1255  func getStateWithoutArgs(t *testing.T) {
  1256  	getStateParams := &GraphQLParams{
  1257  		Query: `{
  1258  			getState {
  1259  				name
  1260  			}
  1261  		}`,
  1262  	}
  1263  
  1264  	gqlResponse := getStateParams.ExecuteAsPost(t, graphqlURL)
  1265  	requireNoGQLErrors(t, gqlResponse)
  1266  	require.JSONEq(t, `{"getState":null}`, string(gqlResponse.Data))
  1267  }
  1268  
  1269  func getStateByBothXidAndUid(t *testing.T) {
  1270  	getStateParams := &GraphQLParams{
  1271  		Query: `{
  1272  			getState(xcode: "nsw", id: "0x1") {
  1273  				name
  1274  			}
  1275  		}`,
  1276  	}
  1277  
  1278  	gqlResponse := getStateParams.ExecuteAsPost(t, graphqlURL)
  1279  	requireNoGQLErrors(t, gqlResponse)
  1280  	require.JSONEq(t, `{"getState":null}`, string(gqlResponse.Data))
  1281  }
  1282  
  1283  func queryStateByXid(t *testing.T) {
  1284  	getStateParams := &GraphQLParams{
  1285  		Query: `{
  1286  			queryState(filter: { xcode: { eq: "nsw"}}) {
  1287  				name
  1288  			}
  1289  		}`,
  1290  	}
  1291  
  1292  	gqlResponse := getStateParams.ExecuteAsPost(t, graphqlURL)
  1293  	requireNoGQLErrors(t, gqlResponse)
  1294  	require.Equal(t, `{"queryState":[{"name":"NSW"}]}`, string(gqlResponse.Data))
  1295  }
  1296  
  1297  func queryStateByXidRegex(t *testing.T) {
  1298  	getStateParams := &GraphQLParams{
  1299  		Query: `{
  1300  			queryState(filter: { xcode: { regexp: "/n/"}}) {
  1301  				name
  1302  			}
  1303  		}`,
  1304  	}
  1305  
  1306  	gqlResponse := getStateParams.ExecuteAsPost(t, graphqlURL)
  1307  	requireNoGQLErrors(t, gqlResponse)
  1308  	testutil.CompareJSON(t, `{"queryState":[{"name":"Nusa"},{"name": "NSW"}]}`,
  1309  		string(gqlResponse.Data))
  1310  }
  1311  
  1312  func multipleOperations(t *testing.T) {
  1313  	params := &GraphQLParams{
  1314  		Query: `query sortCountryByNameDesc {
  1315  			queryCountry(order: { desc: name }, first: 1) {
  1316  				name
  1317  			}
  1318  		}
  1319  
  1320  		query sortCountryByNameAsc {
  1321  			queryCountry(order: { asc: name }, first: 1) {
  1322  				name
  1323  			}
  1324  		}
  1325  		`,
  1326  		OperationName: "sortCountryByNameAsc",
  1327  	}
  1328  
  1329  	cases := []struct {
  1330  		name          string
  1331  		operationName string
  1332  		expectedError string
  1333  		expected      []*country
  1334  	}{
  1335  		{
  1336  			"second query name as operation name",
  1337  			"sortCountryByNameAsc",
  1338  			"",
  1339  			[]*country{{Name: "Angola"}},
  1340  		},
  1341  		{
  1342  			"first query name as operation name",
  1343  			"sortCountryByNameDesc",
  1344  			"",
  1345  			[]*country{{Name: "Mozambique"}},
  1346  		},
  1347  		{
  1348  			"operation name doesn't exist",
  1349  			"sortCountryByName",
  1350  			"Supplied operation name sortCountryByName isn't present in the request.",
  1351  			nil,
  1352  		},
  1353  		{
  1354  			"operation name is empty",
  1355  			"",
  1356  			"Operation name must by supplied when query has more than 1 operation.",
  1357  			nil,
  1358  		},
  1359  	}
  1360  
  1361  	for _, test := range cases {
  1362  		t.Run(test.name, func(t *testing.T) {
  1363  			params.OperationName = test.operationName
  1364  			gqlResponse := params.ExecuteAsPost(t, graphqlURL)
  1365  			if test.expectedError != "" {
  1366  				require.NotNil(t, gqlResponse.Errors)
  1367  				require.Equal(t, test.expectedError, gqlResponse.Errors[0].Error())
  1368  				return
  1369  			}
  1370  			requireNoGQLErrors(t, gqlResponse)
  1371  
  1372  			var expected, result struct {
  1373  				QueryCountry []*country
  1374  			}
  1375  			expected.QueryCountry = test.expected
  1376  			err := json.Unmarshal([]byte(gqlResponse.Data), &result)
  1377  			require.NoError(t, err)
  1378  
  1379  			if diff := cmp.Diff(expected, result); diff != "" {
  1380  				t.Errorf("result mismatch (-want +got):\n%s", diff)
  1381  			}
  1382  		})
  1383  	}
  1384  }
  1385  
  1386  func queryPostWithAuthor(t *testing.T) {
  1387  	queryPostParams := &GraphQLParams{
  1388  		Query: `query {
  1389  			queryPost (filter: {title : { anyofterms : "Introducing" }} ) {
  1390  				title
  1391  				author {
  1392  					name
  1393  				}
  1394  			}
  1395  		}`,
  1396  	}
  1397  
  1398  	gqlResponse := queryPostParams.ExecuteAsPost(t, graphqlURL)
  1399  	requireNoGQLErrors(t, gqlResponse)
  1400  	testutil.CompareJSON(t,
  1401  		`{"queryPost":[{"title":"Introducing GraphQL in Dgraph","author":{"name":"Ann Author"}}]}`,
  1402  		string(gqlResponse.Data))
  1403  }