From 7c077e5d138f352a1d791aa2af74e62e2600d79e Mon Sep 17 00:00:00 2001 From: Abhimanyu Singh Gaur <12651351+abhimanyusinghgaur@users.noreply.github.com> Date: Wed, 2 Dec 2020 14:23:34 +0530 Subject: [PATCH] chore(test): Refactor GraphQL tests to use best practices (GRAPHQL-885) (#7016) This PR does the following things: * adds a counter in `/probe/graphql` response which indicate how many time the GraphQL schema has been updated. * adds some common test methods to update the GQL schema which ensure schema update using the counter. * Refactors existing tests to use those methods in order to update the GQL schema. * adds the best practice of using `common.RequireNoGQLErrors` instead of `require.Nil` for verifying that the `GraphQLResponse` has no errors. * enables some skipped tests in `graphql/e2e/admin_auth`. With this PR, all the flakiness around GraphQL schema updates should no longer be there. --- dgraph/cmd/alpha/run.go | 4 +- go.mod | 2 +- go.sum | 4 + .../poorman_auth/admin_auth_test.go | 59 +- .../poorman_auth_with_acl/admin_auth_test.go | 72 +-- graphql/e2e/auth/add_mutation_test.go | 34 +- graphql/e2e/auth/auth_test.go | 64 +-- graphql/e2e/auth/debug_off/debugoff_test.go | 9 +- graphql/e2e/auth/delete_mutation_test.go | 38 +- graphql/e2e/auth/update_mutation_test.go | 32 +- graphql/e2e/common/admin.go | 538 +++--------------- graphql/e2e/common/common.go | 356 ++++++++++-- graphql/e2e/common/error.go | 2 +- graphql/e2e/common/mutation.go | 2 +- graphql/e2e/common/schema.go | 4 +- graphql/e2e/custom_logic/custom_logic_test.go | 261 +++------ graphql/e2e/schema/schema_test.go | 470 +++++---------- graphql/e2e/subscription/subscription_test.go | 280 +++------ testutil/client.go | 7 + testutil/graphql.go | 38 +- testutil/schema.go | 2 +- 21 files changed, 870 insertions(+), 1408 deletions(-) diff --git a/dgraph/cmd/alpha/run.go b/dgraph/cmd/alpha/run.go index 44bd2eae0be..c6b2259ff66 100644 --- a/dgraph/cmd/alpha/run.go +++ b/dgraph/cmd/alpha/run.go @@ -434,6 +434,7 @@ func setupServer(closer *z.Closer) { // Global Epoch is a lockless synchronization mechanism for graphql service. // It's is just an atomic counter used by the graphql subscription to update its state. // It's is used to detect the schema changes and server exit. + // It is also reported by /probe/graphql endpoint as the schemaUpdateCounter. // Implementation for schema change: // The global epoch is incremented when there is a schema change. @@ -458,7 +459,8 @@ func setupServer(closer *z.Closer) { } w.WriteHeader(httpStatusCode) w.Header().Set("Content-Type", "application/json") - x.Check2(w.Write([]byte(fmt.Sprintf(`{"status":"%s"}`, healthStatus.StatusMsg)))) + x.Check2(w.Write([]byte(fmt.Sprintf(`{"status":"%s","schemaUpdateCounter":%d}`, + healthStatus.StatusMsg, atomic.LoadUint64(&globalEpoch))))) }) http.Handle("/admin", allowedMethodsHandler(allowedMethods{ http.MethodGet: true, diff --git a/go.mod b/go.mod index dfefce7709c..e4e4bd701ae 100644 --- a/go.mod +++ b/go.mod @@ -53,7 +53,7 @@ require ( github.com/pkg/errors v0.9.1 github.com/pkg/profile v1.2.1 github.com/prometheus/client_golang v0.9.3 - github.com/prometheus/common v0.4.1 // indirect + github.com/prometheus/common v0.4.1 github.com/prometheus/procfs v0.0.0-20190517135640-51af30a78b0e // indirect github.com/soheilhy/cmux v0.1.4 github.com/spf13/cast v1.3.0 diff --git a/go.sum b/go.sum index 0b9b3cd87d2..9e94fd37d3c 100644 --- a/go.sum +++ b/go.sum @@ -48,7 +48,9 @@ github.com/agnivade/levenshtein v1.0.1/go.mod h1:CURSv5d9Uaml+FovSIICkLbAUZ9S4Rq github.com/agnivade/levenshtein v1.0.3 h1:M5ZnqLOoZR8ygVq0FfkXsNOKzMCk0xRiow0R5+5VkQ0= github.com/agnivade/levenshtein v1.0.3/go.mod h1:4SFRZbbXWLF4MU1T9Qg0pGgH3Pjs+t6ie5efyrwRJXs= github.com/ajg/form v1.5.1/go.mod h1:uL1WgH+h2mgNtvBq0339dVnzXdBETtL2LeUXaIv25UY= +github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc h1:cAKDfWh5VpdgMhJosfJnn5/FoN2SRZ4p7fJNX58YPaU= github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= +github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf h1:qet1QNfXsQxTZqLG4oE62mJzwPIB8+Tee4RNCL9ulrY= github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= github.com/andreyvit/diff v0.0.0-20170406064948-c7f18ee00883 h1:bvNMNQO63//z+xNgfBlViaCIJKLlCJ6/fmUseuG0wVQ= github.com/andreyvit/diff v0.0.0-20170406064948-c7f18ee00883/go.mod h1:rCTlJbsFo29Kk6CurOXKm700vrz8f0KW0JNfpkRJY/8= @@ -476,6 +478,7 @@ github.com/sirupsen/logrus v1.0.5/go.mod h1:pMByvHTf9Beacp5x1UXfOR9xyW/9antXMhjM github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= github.com/sirupsen/logrus v1.4.1/go.mod h1:ni0Sbl8bgC9z8RoU9G6nDWqqs/fq4eDPysMBDgk/93Q= github.com/sirupsen/logrus v1.5.0/go.mod h1:+F7Ogzej0PZc/94MaYx/nvG9jOFMD2osvC3s+Squfpo= +github.com/sirupsen/logrus v1.6.0 h1:UBcNElsrwanuuMsnGSlYmtmgbb23qDR5dG+6X6Oo89I= github.com/sirupsen/logrus v1.6.0/go.mod h1:7uNnSEd1DgxDLC74fIahvMZmmYsHGZGEOFrfsX/uA88= github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d h1:zE9ykElWQ6/NYmHa3jpm/yHnI4xSofP+UP6SpjHcSeM= github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc= @@ -741,6 +744,7 @@ google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyac gopkg.in/DataDog/dd-trace-go.v1 v1.13.1 h1:oTzOClfuudNhW9Skkp2jxjqYO92uDKXqKLbiuPA13Rk= gopkg.in/DataDog/dd-trace-go.v1 v1.13.1/go.mod h1:DVp8HmDh8PuTu2Z0fVVlBsyWaC++fzwVCaGWylTe3tg= gopkg.in/airbrake/gobrake.v2 v2.0.9/go.mod h1:/h5ZAUhDkGaJfjzjKLSjv6zCL6O0LLBxU4K+aSYdM/U= +gopkg.in/alecthomas/kingpin.v2 v2.2.6 h1:jMFz6MfLP0/4fUyZle81rXUoxOBFi19VUFKVDOQfozc= gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= gopkg.in/asn1-ber.v1 v1.0.0-20181015200546-f715ec2f112d/go.mod h1:cuepJuh7vyXfUyUwEgHQXw849cJrilpS5NeIjOWESAw= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= diff --git a/graphql/e2e/admin_auth/poorman_auth/admin_auth_test.go b/graphql/e2e/admin_auth/poorman_auth/admin_auth_test.go index 385e819c48a..9dc1479e5a3 100644 --- a/graphql/e2e/admin_auth/poorman_auth/admin_auth_test.go +++ b/graphql/e2e/admin_auth/poorman_auth/admin_auth_test.go @@ -20,6 +20,8 @@ import ( "net/http" "testing" + "github.com/dgraph-io/dgraph/x" + "github.com/stretchr/testify/require" "github.com/dgraph-io/dgraph/graphql/e2e/common" @@ -32,49 +34,28 @@ const ( ) func TestAdminOnlyPoorManAuth(t *testing.T) { - t.Skipf("TODO: This test is failing for some reason. FIX IT.") + schema := `type Person { + id: ID! + name: String! + }` // without X-Dgraph-AuthToken should give error - params := getUpdateGqlSchemaParams() - assertAuthTokenError(t, common.GraphqlAdminURL, params) + headers := http.Header{} + assertAuthTokenError(t, schema, headers) // setting a wrong value for the token should still give error - params.Headers.Set(authTokenHeader, wrongAuthToken) - assertAuthTokenError(t, common.GraphqlAdminURL, params) + headers.Set(authTokenHeader, wrongAuthToken) + assertAuthTokenError(t, schema, headers) - // setting correct value for the token should not give any GraphQL error - params.Headers.Set(authTokenHeader, authToken) - common.RequireNoGQLErrors(t, params.ExecuteAsPost(t, common.GraphqlAdminURL)) + // setting correct value for the token should successfully update the schema + headers.Set(authTokenHeader, authToken) + common.SafelyUpdateGQLSchema(t, common.Alpha1HTTP, schema, headers) } - -func assertAuthTokenError(t *testing.T, url string, params *common.GraphQLParams) { - req, err := params.CreateGQLPost(url) - require.NoError(t, err) - - resp, err := common.RunGQLRequest(req) - require.NoError(t, err) - require.JSONEq(t, `{ - "errors":[{ - "message":"Invalid X-Dgraph-AuthToken", - "extensions":{"code":"ErrorUnauthorized"} - }] - }`, string(resp)) -} - -func getUpdateGqlSchemaParams() *common.GraphQLParams { - schema := `type Person { - id: ID! - name: String! - }` - return &common.GraphQLParams{ - Query: `mutation updateGQLSchema($sch: String!) { - updateGQLSchema(input: { set: { schema: $sch }}) { - gqlSchema { - schema - } - } - }`, - Variables: map[string]interface{}{"sch": schema}, - Headers: http.Header{}, - } +func assertAuthTokenError(t *testing.T, schema string, headers http.Header) { + resp := common.RetryUpdateGQLSchema(t, common.Alpha1HTTP, schema, headers) + require.Equal(t, x.GqlErrorList{{ + Message: "Invalid X-Dgraph-AuthToken", + Extensions: map[string]interface{}{"code": "ErrorUnauthorized"}, + }}, resp.Errors) + require.Nil(t, resp.Data) } diff --git a/graphql/e2e/admin_auth/poorman_auth_with_acl/admin_auth_test.go b/graphql/e2e/admin_auth/poorman_auth_with_acl/admin_auth_test.go index d3ace3a9e6c..7352b2339c5 100644 --- a/graphql/e2e/admin_auth/poorman_auth_with_acl/admin_auth_test.go +++ b/graphql/e2e/admin_auth/poorman_auth_with_acl/admin_auth_test.go @@ -37,14 +37,13 @@ const ( ) func TestLoginWithPoorManAuth(t *testing.T) { - t.Skipf("TODO: This test is failing for some reason. FIX IT.") // without X-Dgraph-AuthToken should give error params := getGrootLoginParams() - assertAuthTokenError(t, common.GraphqlAdminURL, params) + assertAuthTokenError(t, params.ExecuteAsPost(t, common.GraphqlAdminURL)) // setting a wrong value for the token should still give error params.Headers.Set(authTokenHeader, wrongAuthToken) - assertAuthTokenError(t, common.GraphqlAdminURL, params) + assertAuthTokenError(t, params.ExecuteAsPost(t, common.GraphqlAdminURL)) // setting correct value for the token should not give any GraphQL error params.Headers.Set(authTokenHeader, authToken) @@ -52,45 +51,41 @@ func TestLoginWithPoorManAuth(t *testing.T) { } func TestAdminPoorManWithAcl(t *testing.T) { - t.Skipf("TODO: This test is failing for some reason. FIX IT.") + schema := `type Person { + id: ID! + name: String! + }` // without auth token and access JWT headers, should give auth token related error - params := getUpdateGqlSchemaParams() - assertAuthTokenError(t, common.GraphqlAdminURL, params) + headers := http.Header{} + assertAuthTokenError(t, common.RetryUpdateGQLSchema(t, common.Alpha1HTTP, schema, headers)) // setting a wrong value for the auth token should still give auth token related error - params.Headers.Set(authTokenHeader, wrongAuthToken) - assertAuthTokenError(t, common.GraphqlAdminURL, params) + headers.Set(authTokenHeader, wrongAuthToken) + assertAuthTokenError(t, common.RetryUpdateGQLSchema(t, common.Alpha1HTTP, schema, headers)) // setting correct value for the auth token should now give ACL related GraphQL error - params.Headers.Set(authTokenHeader, authToken) - assertMissingAclError(t, params) + headers.Set(authTokenHeader, authToken) + assertMissingAclError(t, common.RetryUpdateGQLSchema(t, common.Alpha1HTTP, schema, headers)) // setting wrong value for the access JWT should still give ACL related GraphQL error - params.Headers.Set(accessJwtHeader, wrongAuthToken) - assertBadAclError(t, params) + headers.Set(accessJwtHeader, wrongAuthToken) + assertBadAclError(t, common.RetryUpdateGQLSchema(t, common.Alpha1HTTP, schema, headers)) // setting correct value for both tokens should not give errors accessJwt, _ := grootLogin(t) - params.Headers.Set(accessJwtHeader, accessJwt) - common.RequireNoGQLErrors(t, params.ExecuteAsPost(t, common.GraphqlAdminURL)) + headers.Set(accessJwtHeader, accessJwt) + common.AssertUpdateGQLSchemaSuccess(t, common.Alpha1HTTP, schema, headers) } -func assertAuthTokenError(t *testing.T, url string, params *common.GraphQLParams) { - req, err := params.CreateGQLPost(url) - require.NoError(t, err) - - resp, err := common.RunGQLRequest(req) - require.NoError(t, err) - require.JSONEq(t, `{ - "errors":[{ - "message":"Invalid X-Dgraph-AuthToken", - "extensions":{"code":"ErrorUnauthorized"} - }] - }`, string(resp)) +func assertAuthTokenError(t *testing.T, resp *common.GraphQLResponse) { + require.Equal(t, x.GqlErrorList{{ + Message: "Invalid X-Dgraph-AuthToken", + Extensions: map[string]interface{}{"code": "ErrorUnauthorized"}, + }}, resp.Errors) + require.Nil(t, resp.Data) } -func assertMissingAclError(t *testing.T, params *common.GraphQLParams) { - resp := params.ExecuteAsPost(t, common.GraphqlAdminURL) +func assertMissingAclError(t *testing.T, resp *common.GraphQLResponse) { require.Equal(t, x.GqlErrorList{{ Message: "resolving updateGQLSchema failed because rpc error: code = PermissionDenied desc = no accessJwt available", Locations: []x.Location{{ @@ -100,8 +95,7 @@ func assertMissingAclError(t *testing.T, params *common.GraphQLParams) { }}, resp.Errors) } -func assertBadAclError(t *testing.T, params *common.GraphQLParams) { - resp := params.ExecuteAsPost(t, common.GraphqlAdminURL) +func assertBadAclError(t *testing.T, resp *common.GraphQLResponse) { require.Equal(t, x.GqlErrorList{{ Message: "resolving updateGQLSchema failed because rpc error: code = Unauthenticated desc = unable to parse jwt token:token contains an invalid number of segments", Locations: []x.Location{{ @@ -148,21 +142,3 @@ func getGrootLoginParams() *common.GraphQLParams { Headers: http.Header{}, } } - -func getUpdateGqlSchemaParams() *common.GraphQLParams { - schema := `type Person { - id: ID! - name: String! - }` - return &common.GraphQLParams{ - Query: `mutation updateGQLSchema($sch: String!) { - updateGQLSchema(input: { set: { schema: $sch }}) { - gqlSchema { - schema - } - } - }`, - Variables: map[string]interface{}{"sch": schema}, - Headers: http.Header{}, - } -} diff --git a/graphql/e2e/auth/add_mutation_test.go b/graphql/e2e/auth/add_mutation_test.go index f6880e4db33..b2766ad098d 100644 --- a/graphql/e2e/auth/add_mutation_test.go +++ b/graphql/e2e/auth/add_mutation_test.go @@ -39,7 +39,7 @@ func (p *Project) delete(t *testing.T, user, role string) { Variables: map[string]interface{}{"ids": []string{p.ProjID}}, } gqlResponse := getParams.ExecuteAsPost(t, common.GraphqlURL) - require.Nil(t, gqlResponse.Errors) + common.RequireNoGQLErrors(t, gqlResponse) } func (c *Column) delete(t *testing.T, user, role string) { @@ -55,7 +55,7 @@ func (c *Column) delete(t *testing.T, user, role string) { Variables: map[string]interface{}{"colids": []string{c.ColID}}, } gqlResponse := getParams.ExecuteAsPost(t, common.GraphqlURL) - require.Nil(t, gqlResponse.Errors) + common.RequireNoGQLErrors(t, gqlResponse) } func (i *Issue) delete(t *testing.T, user, role string) { @@ -71,7 +71,7 @@ func (i *Issue) delete(t *testing.T, user, role string) { Variables: map[string]interface{}{"ids": []string{i.Id}}, } gqlResponse := getParams.ExecuteAsPost(t, common.GraphqlURL) - require.Nil(t, gqlResponse.Errors) + common.RequireNoGQLErrors(t, gqlResponse) } func (l *Log) delete(t *testing.T, user, role string) { @@ -87,7 +87,7 @@ func (l *Log) delete(t *testing.T, user, role string) { Variables: map[string]interface{}{"ids": []string{l.Id}}, } gqlResponse := getParams.ExecuteAsPost(t, common.GraphqlURL) - require.Nil(t, gqlResponse.Errors) + common.RequireNoGQLErrors(t, gqlResponse) } func (m *Movie) delete(t *testing.T, user, role string) { @@ -103,7 +103,7 @@ func (m *Movie) delete(t *testing.T, user, role string) { Variables: map[string]interface{}{"ids": []string{m.Id}}, } gqlResponse := getParams.ExecuteAsPost(t, common.GraphqlURL) - require.Nil(t, gqlResponse.Errors) + common.RequireNoGQLErrors(t, gqlResponse) } func (a *Author) delete(t *testing.T) { @@ -118,7 +118,7 @@ func (a *Author) delete(t *testing.T) { Variables: map[string]interface{}{"ids": []string{a.Id}}, } gqlResponse := getParams.ExecuteAsPost(t, common.GraphqlURL) - require.Nil(t, gqlResponse.Errors) + common.RequireNoGQLErrors(t, gqlResponse) } func (q *Question) delete(t *testing.T, user string) { @@ -134,7 +134,7 @@ func (q *Question) delete(t *testing.T, user string) { Variables: map[string]interface{}{"ids": []string{q.Id}}, } gqlResponse := getParams.ExecuteAsPost(t, common.GraphqlURL) - require.Nil(t, gqlResponse.Errors) + common.RequireNoGQLErrors(t, gqlResponse) } func (f *FbPost) delete(t *testing.T, user, role string) { @@ -150,7 +150,7 @@ func (f *FbPost) delete(t *testing.T, user, role string) { Variables: map[string]interface{}{"ids": []string{f.Id}}, } gqlResponse := getParams.ExecuteAsPost(t, common.GraphqlURL) - require.Nil(t, gqlResponse.Errors) + common.RequireNoGQLErrors(t, gqlResponse) } func TestAuth_AddOnTypeWithRBACRuleOnInterface(t *testing.T) { @@ -237,7 +237,7 @@ func TestAuth_AddOnTypeWithRBACRuleOnInterface(t *testing.T) { continue } - require.Nil(t, gqlResponse.Errors) + common.RequireNoGQLErrors(t, gqlResponse) err := json.Unmarshal([]byte(tcase.result), &expected) require.NoError(t, err) @@ -335,7 +335,7 @@ func TestAuth_AddOnTypeWithGraphTraversalRuleOnInterface(t *testing.T) { continue } - require.Nil(t, gqlResponse.Errors) + common.RequireNoGQLErrors(t, gqlResponse) err := json.Unmarshal([]byte(tcase.result), &expected) require.NoError(t, err) @@ -448,7 +448,7 @@ func TestAddDeepFilter(t *testing.T) { continue } - require.Nil(t, gqlResponse.Errors) + common.RequireNoGQLErrors(t, gqlResponse) err := json.Unmarshal([]byte(tcase.result), &expected) require.NoError(t, err) @@ -551,7 +551,7 @@ func TestAddOrRBACFilter(t *testing.T) { continue } - require.Nil(t, gqlResponse.Errors) + common.RequireNoGQLErrors(t, gqlResponse) err := json.Unmarshal([]byte(tcase.result), &expected) require.NoError(t, err) @@ -630,7 +630,7 @@ func TestAddAndRBACFilterMultiple(t *testing.T) { continue } - require.Nil(t, gqlResponse.Errors) + common.RequireNoGQLErrors(t, gqlResponse) err := json.Unmarshal([]byte(tcase.result), &expected) require.NoError(t, err) @@ -705,7 +705,7 @@ func TestAddAndRBACFilter(t *testing.T) { continue } - require.Nil(t, gqlResponse.Errors) + common.RequireNoGQLErrors(t, gqlResponse) err := json.Unmarshal([]byte(tcase.result), &expected) require.NoError(t, err) @@ -809,7 +809,7 @@ func TestAddComplexFilter(t *testing.T) { continue } - require.Nil(t, gqlResponse.Errors) + common.RequireNoGQLErrors(t, gqlResponse) err := json.Unmarshal([]byte(tcase.result), &expected) require.NoError(t, err) @@ -877,7 +877,7 @@ func TestAddRBACFilter(t *testing.T) { continue } - require.Nil(t, gqlResponse.Errors) + common.RequireNoGQLErrors(t, gqlResponse) err := json.Unmarshal([]byte(tcase.result), &expected) require.NoError(t, err) @@ -941,7 +941,7 @@ func TestAddGQLOnly(t *testing.T) { continue } - require.Nil(t, gqlResponse.Errors) + common.RequireNoGQLErrors(t, gqlResponse) err := json.Unmarshal([]byte(tcase.result), &expected) require.NoError(t, err) diff --git a/graphql/e2e/auth/auth_test.go b/graphql/e2e/auth/auth_test.go index 1361a38efca..7bcdb5ce750 100644 --- a/graphql/e2e/auth/auth_test.go +++ b/graphql/e2e/auth/auth_test.go @@ -183,7 +183,7 @@ func (tasks Tasks) add(t *testing.T) { Variables: map[string]interface{}{"tasks": tasks}, } gqlResponse := getParams.ExecuteAsPost(t, common.GraphqlURL) - require.Nil(t, gqlResponse.Errors) + common.RequireNoGQLErrors(t, gqlResponse) } func (r *Region) add(t *testing.T, user, role string) { @@ -199,7 +199,7 @@ func (r *Region) add(t *testing.T, user, role string) { Variables: map[string]interface{}{"region": r}, } gqlResponse := getParams.ExecuteAsPost(t, common.GraphqlURL) - require.Nil(t, gqlResponse.Errors) + common.RequireNoGQLErrors(t, gqlResponse) } func (r *Region) delete(t *testing.T, user, role string) { @@ -215,7 +215,7 @@ func (r *Region) delete(t *testing.T, user, role string) { Variables: map[string]interface{}{"name": r.Name}, } gqlResponse := getParams.ExecuteAsPost(t, common.GraphqlURL) - require.Nil(t, gqlResponse.Errors) + common.RequireNoGQLErrors(t, gqlResponse) } func TestOptimizedNestedAuthQuery(t *testing.T) { @@ -239,7 +239,7 @@ func TestOptimizedNestedAuthQuery(t *testing.T) { } gqlResponse := getUserParams.ExecuteAsPost(t, common.GraphqlURL) - require.Nil(t, gqlResponse.Errors) + common.RequireNoGQLErrors(t, gqlResponse) beforeTouchUids := gqlResponse.Extensions["touched_uids"] beforeResult := gqlResponse.Data @@ -257,7 +257,7 @@ func TestOptimizedNestedAuthQuery(t *testing.T) { } gqlResponse = getUserParams.ExecuteAsPost(t, common.GraphqlURL) - require.Nil(t, gqlResponse.Errors) + common.RequireNoGQLErrors(t, gqlResponse) afterTouchUids := gqlResponse.Extensions["touched_uids"] require.Equal(t, beforeTouchUids, afterTouchUids) @@ -283,7 +283,7 @@ func (s Student) deleteByEmail(t *testing.T) { }}, } gqlResponse := getParams.ExecuteAsPost(t, common.GraphqlURL) - require.Nil(t, gqlResponse.Errors) + common.RequireNoGQLErrors(t, gqlResponse) } func (s Student) add(t *testing.T) { @@ -325,7 +325,7 @@ func TestAddMutationWithXid(t *testing.T) { // Add the tweet for the first time. gqlResponse := addTweetsParams.ExecuteAsPost(t, common.GraphqlURL) - require.Nil(t, gqlResponse.Errors) + common.RequireNoGQLErrors(t, gqlResponse) // Re-adding the tweet should fail. gqlResponse = addTweetsParams.ExecuteAsPost(t, common.GraphqlURL) @@ -487,7 +487,7 @@ func TestAuthOnInterfaces(t *testing.T) { Query: tcase.query, } gqlResponse := getUserParams.ExecuteAsPost(t, common.GraphqlURL) - require.Nil(t, gqlResponse.Errors) + common.RequireNoGQLErrors(t, gqlResponse) require.JSONEq(t, tcase.result, string(gqlResponse.Data)) }) } @@ -566,7 +566,7 @@ func TestAuthRulesWithMissingJWT(t *testing.T) { require.Contains(t, gqlResponse.Errors[0].Error(), "couldn't rewrite query queryProject because unable to parse jwt token") } else { - require.Nil(t, gqlResponse.Errors) + common.RequireNoGQLErrors(t, gqlResponse) } if diff := cmp.Diff(tcase.result, string(gqlResponse.Data)); diff != "" { @@ -675,7 +675,7 @@ func TestOrderAndOffset(t *testing.T) { } gqlResponse := getUserParams.ExecuteAsPost(t, common.GraphqlURL) - require.Nil(t, gqlResponse.Errors) + common.RequireNoGQLErrors(t, gqlResponse) require.JSONEq(t, string(gqlResponse.Data), tcase.result) }) @@ -693,7 +693,7 @@ func TestOrderAndOffset(t *testing.T) { Variables: map[string]interface{}{"tasks": tasks}, } gqlResponse := getParams.ExecuteAsPost(t, common.GraphqlURL) - require.Nil(t, gqlResponse.Errors) + common.RequireNoGQLErrors(t, gqlResponse) // Clean up `TaskOccurrence` getParams = &common.GraphQLParams{ @@ -707,7 +707,7 @@ func TestOrderAndOffset(t *testing.T) { Variables: map[string]interface{}{"tasks": tasks}, } gqlResponse = getParams.ExecuteAsPost(t, common.GraphqlURL) - require.Nil(t, gqlResponse.Errors) + common.RequireNoGQLErrors(t, gqlResponse) } func TestOrRBACFilter(t *testing.T) { @@ -762,7 +762,7 @@ func TestOrRBACFilter(t *testing.T) { } gqlResponse := getUserParams.ExecuteAsPost(t, common.GraphqlURL) - require.Nil(t, gqlResponse.Errors) + common.RequireNoGQLErrors(t, gqlResponse) require.JSONEq(t, string(gqlResponse.Data), tcase.result) }) @@ -790,7 +790,7 @@ func getColID(t *testing.T, tcase TestCase) string { } gqlResponse := getUserParams.ExecuteAsPost(t, common.GraphqlURL) - require.Nil(t, gqlResponse.Errors) + common.RequireNoGQLErrors(t, gqlResponse) err := json.Unmarshal(gqlResponse.Data, &result) require.Nil(t, err) @@ -842,7 +842,7 @@ func TestRootGetFilter(t *testing.T) { } gqlResponse := getUserParams.ExecuteAsPost(t, common.GraphqlURL) - require.Nil(t, gqlResponse.Errors) + common.RequireNoGQLErrors(t, gqlResponse) require.JSONEq(t, string(gqlResponse.Data), tcase.result) }) @@ -869,7 +869,7 @@ func getProjectID(t *testing.T, tcase TestCase) string { } gqlResponse := getUserParams.ExecuteAsPost(t, common.GraphqlURL) - require.Nil(t, gqlResponse.Errors) + common.RequireNoGQLErrors(t, gqlResponse) err := json.Unmarshal(gqlResponse.Data, &result) require.Nil(t, err) @@ -924,7 +924,7 @@ func TestRootGetDeepFilter(t *testing.T) { } gqlResponse := getUserParams.ExecuteAsPost(t, common.GraphqlURL) - require.Nil(t, gqlResponse.Errors) + common.RequireNoGQLErrors(t, gqlResponse) require.JSONEq(t, string(gqlResponse.Data), tcase.result) }) @@ -969,7 +969,7 @@ func TestDeepFilter(t *testing.T) { } gqlResponse := getUserParams.ExecuteAsPost(t, common.GraphqlURL) - require.Nil(t, gqlResponse.Errors) + common.RequireNoGQLErrors(t, gqlResponse) require.JSONEq(t, string(gqlResponse.Data), tcase.result) }) } @@ -1004,7 +1004,7 @@ func TestRootFilter(t *testing.T) { } gqlResponse := getUserParams.ExecuteAsPost(t, common.GraphqlURL) - require.Nil(t, gqlResponse.Errors) + common.RequireNoGQLErrors(t, gqlResponse) require.JSONEq(t, string(gqlResponse.Data), tcase.result) }) @@ -1102,7 +1102,7 @@ func TestDeepRBACValue(t *testing.T) { } gqlResponse := getUserParams.ExecuteAsPost(t, common.GraphqlURL) - require.Nil(t, gqlResponse.Errors) + common.RequireNoGQLErrors(t, gqlResponse) require.JSONEq(t, string(gqlResponse.Data), tcase.result) }) @@ -1131,7 +1131,7 @@ func TestRBACFilter(t *testing.T) { } gqlResponse := getUserParams.ExecuteAsPost(t, common.GraphqlURL) - require.Nil(t, gqlResponse.Errors) + common.RequireNoGQLErrors(t, gqlResponse) require.JSONEq(t, string(gqlResponse.Data), tcase.result) }) @@ -1222,7 +1222,7 @@ func TestAndRBACFilter(t *testing.T) { } gqlResponse := getUserParams.ExecuteAsPost(t, common.GraphqlURL) - require.Nil(t, gqlResponse.Errors) + common.RequireNoGQLErrors(t, gqlResponse) require.JSONEq(t, string(gqlResponse.Data), tcase.result) }) @@ -1334,7 +1334,7 @@ func TestNestedFilter(t *testing.T) { } gqlResponse := getUserParams.ExecuteAsPost(t, common.GraphqlURL) - require.Nil(t, gqlResponse.Errors) + common.RequireNoGQLErrors(t, gqlResponse) require.JSONEq(t, string(gqlResponse.Data), tcase.result) }) @@ -1384,7 +1384,7 @@ func TestDeleteAuthRule(t *testing.T) { } gqlResponse := getUserParams.ExecuteAsPost(t, common.GraphqlURL) - require.Nilf(t, gqlResponse.Errors, "%+v", gqlResponse.Errors) + common.RequireNoGQLErrors(t, gqlResponse) if diff := cmp.Diff(tcase.result, string(gqlResponse.Data)); diff != "" { t.Errorf("result mismatch (-want +got):\n%s", diff) @@ -1393,7 +1393,7 @@ func TestDeleteAuthRule(t *testing.T) { } func AddDeleteAuthTestData(t *testing.T) { - client, err := testutil.DgraphClient(common.AlphagRPC) + client, err := testutil.DgraphClient(common.Alpha1gRPC) require.NoError(t, err) data := `[{ "uid": "_:usersecret1", @@ -1407,7 +1407,7 @@ func AddDeleteAuthTestData(t *testing.T) { } func AddDeleteDeepAuthTestData(t *testing.T) { - client, err := testutil.DgraphClient(common.AlphagRPC) + client, err := testutil.DgraphClient(common.Alpha1gRPC) require.NoError(t, err) userQuery := `{ @@ -1494,7 +1494,7 @@ func TestDeleteDeepAuthRule(t *testing.T) { } gqlResponse := getUserParams.ExecuteAsPost(t, common.GraphqlURL) - require.Nil(t, gqlResponse.Errors) + common.RequireNoGQLErrors(t, gqlResponse) if diff := cmp.Diff(tcase.result, string(gqlResponse.Data)); diff != "" { t.Errorf("result mismatch (-want +got):\n%s", diff) @@ -1556,7 +1556,7 @@ func TestDeepRBACValueCascade(t *testing.T) { } gqlResponse := getUserParams.ExecuteAsPost(t, common.GraphqlURL) - require.Nil(t, gqlResponse.Errors) + common.RequireNoGQLErrors(t, gqlResponse) require.JSONEq(t, string(gqlResponse.Data), tcase.result) }) @@ -1653,7 +1653,7 @@ func TestChildAggregateQueryWithDeepRBAC(t *testing.T) { } gqlResponse := getUserParams.ExecuteAsPost(t, common.GraphqlURL) - require.Nil(t, gqlResponse.Errors) + common.RequireNoGQLErrors(t, gqlResponse) require.JSONEq(t, string(gqlResponse.Data), tcase.result) }) @@ -1729,7 +1729,7 @@ func TestChildAggregateQueryWithOtherFields(t *testing.T) { } gqlResponse := getUserParams.ExecuteAsPost(t, common.GraphqlURL) - require.Nil(t, gqlResponse.Errors) + common.RequireNoGQLErrors(t, gqlResponse) require.JSONEq(t, string(gqlResponse.Data), tcase.result) }) @@ -1767,7 +1767,7 @@ func deleteLog(t *testing.T, logID string) { Headers: common.GetJWT(t, "SomeUser", "ADMIN", metaInfo), } gqlResponse := deleteLogParams.ExecuteAsPost(t, common.GraphqlURL) - require.Nil(t, gqlResponse.Errors) + common.RequireNoGQLErrors(t, gqlResponse) } func deleteUser(t *testing.T, username string) { @@ -1783,7 +1783,7 @@ func deleteUser(t *testing.T, username string) { Variables: map[string]interface{}{"username": username}, } gqlResponse := deleteUserParams.ExecuteAsPost(t, common.GraphqlURL) - require.Nil(t, gqlResponse.Errors) + common.RequireNoGQLErrors(t, gqlResponse) } func TestAuthWithSecretDirective(t *testing.T) { diff --git a/graphql/e2e/auth/debug_off/debugoff_test.go b/graphql/e2e/auth/debug_off/debugoff_test.go index 289f944bfea..f18354c057b 100644 --- a/graphql/e2e/auth/debug_off/debugoff_test.go +++ b/graphql/e2e/auth/debug_off/debugoff_test.go @@ -2,11 +2,12 @@ package debugoff import ( "encoding/json" - "github.com/dgrijalva/jwt-go/v4" "io/ioutil" "os" "testing" + "github.com/dgrijalva/jwt-go/v4" + "github.com/dgraph-io/dgraph/graphql/authorization" "github.com/dgraph-io/dgraph/graphql/e2e/common" "github.com/dgraph-io/dgraph/testutil" @@ -72,7 +73,7 @@ func TestAddGQL(t *testing.T) { continue } - require.Nil(t, gqlResponse.Errors) + common.RequireNoGQLErrors(t, gqlResponse) err := json.Unmarshal([]byte(tcase.result), &expected) require.NoError(t, err) @@ -113,11 +114,11 @@ func TestAddMutationWithXid(t *testing.T) { // Add the tweet for the first time. gqlResponse := addTweetsParams.ExecuteAsPost(t, common.GraphqlURL) - require.Nil(t, gqlResponse.Errors) + common.RequireNoGQLErrors(t, gqlResponse) // Re-adding the tweet should fail. gqlResponse = addTweetsParams.ExecuteAsPost(t, common.GraphqlURL) - require.Nil(t, gqlResponse.Errors) + common.RequireNoGQLErrors(t, gqlResponse) // Clear the tweet. tweet.DeleteByID(t, user, metaInfo) diff --git a/graphql/e2e/auth/delete_mutation_test.go b/graphql/e2e/auth/delete_mutation_test.go index 00fc1d03421..5b8639e8fea 100644 --- a/graphql/e2e/auth/delete_mutation_test.go +++ b/graphql/e2e/auth/delete_mutation_test.go @@ -22,7 +22,7 @@ func (c *Column) add(t *testing.T, user, role string) { Variables: map[string]interface{}{"column": c}, } gqlResponse := getParams.ExecuteAsPost(t, common.GraphqlURL) - require.Nil(t, gqlResponse.Errors) + common.RequireNoGQLErrors(t, gqlResponse) } func (l *Log) add(t *testing.T, user, role string) { @@ -38,7 +38,7 @@ func (l *Log) add(t *testing.T, user, role string) { Variables: map[string]interface{}{"pwd": "password", "logs": l.Logs, "random": l.Random}, } gqlResponse := getParams.ExecuteAsPost(t, common.GraphqlURL) - require.Nil(t, gqlResponse.Errors) + common.RequireNoGQLErrors(t, gqlResponse) } func (i *Issue) add(t *testing.T, user, role string) { @@ -54,7 +54,7 @@ func (i *Issue) add(t *testing.T, user, role string) { Variables: map[string]interface{}{"issue": i}, } gqlResponse := getParams.ExecuteAsPost(t, common.GraphqlURL) - require.Nil(t, gqlResponse.Errors) + common.RequireNoGQLErrors(t, gqlResponse) } func (m *Movie) add(t *testing.T, user, role string) { @@ -70,7 +70,7 @@ func (m *Movie) add(t *testing.T, user, role string) { Variables: map[string]interface{}{"movie": m}, } gqlResponse := getParams.ExecuteAsPost(t, common.GraphqlURL) - require.Nil(t, gqlResponse.Errors) + common.RequireNoGQLErrors(t, gqlResponse) } func (cl *ComplexLog) add(t *testing.T, role string) { @@ -86,7 +86,7 @@ func (cl *ComplexLog) add(t *testing.T, role string) { Variables: map[string]interface{}{"complexlog": cl}, } gqlResponse := getParams.ExecuteAsPost(t, common.GraphqlURL) - require.Nil(t, gqlResponse.Errors) + common.RequireNoGQLErrors(t, gqlResponse) } func (q *Question) add(t *testing.T, user string, ans bool) { @@ -102,7 +102,7 @@ func (q *Question) add(t *testing.T, user string, ans bool) { Variables: map[string]interface{}{"text": q.Text, "ans": q.Answered, "id": q.Author.Id, "pwd": "password"}, } gqlResponse := getParams.ExecuteAsPost(t, common.GraphqlURL) - require.Nil(t, gqlResponse.Errors) + common.RequireNoGQLErrors(t, gqlResponse) } func (a *Answer) add(t *testing.T, user string) { @@ -118,7 +118,7 @@ func (a *Answer) add(t *testing.T, user string) { Variables: map[string]interface{}{"text": a.Text, "id": a.Author.Id, "pwd": "password"}, } gqlResponse := getParams.ExecuteAsPost(t, common.GraphqlURL) - require.Nil(t, gqlResponse.Errors) + common.RequireNoGQLErrors(t, gqlResponse) } func (f *FbPost) add(t *testing.T, user, role string) { @@ -134,7 +134,7 @@ func (f *FbPost) add(t *testing.T, user, role string) { Variables: map[string]interface{}{"text": f.Text, "id1": f.Author.Id, "id2": f.Sender.Id, "id3": f.Receiver.Id, "postCount": f.PostCount, "pwd": "password"}, } gqlResponse := getParams.ExecuteAsPost(t, common.GraphqlURL) - require.Nil(t, gqlResponse.Errors) + common.RequireNoGQLErrors(t, gqlResponse) } func getComplexLog(t *testing.T, role string) ([]*ComplexLog, []string) { @@ -152,7 +152,7 @@ func getComplexLog(t *testing.T, role string) ([]*ComplexLog, []string) { getParams.Headers = common.GetJWT(t, "", role, metaInfo) gqlResponse := getParams.ExecuteAsPost(t, common.GraphqlURL) - require.Nil(t, gqlResponse.Errors) + common.RequireNoGQLErrors(t, gqlResponse) var result struct { QueryComplexLog []*ComplexLog @@ -219,7 +219,7 @@ func TestAuth_DeleteOnInterfaceWithAuthRules(t *testing.T) { } gqlResponse := params.ExecuteAsPost(t, common.GraphqlURL) - require.Nil(t, gqlResponse.Errors) + common.RequireNoGQLErrors(t, gqlResponse) require.JSONEq(t, tcase.result, string(gqlResponse.Data)) // Restore the deleted Questions, Answers and FbPosts for other test cases. @@ -275,7 +275,7 @@ func TestAuth_DeleteTypeWithRBACFilteronInterface(t *testing.T) { } gqlResponse := params.ExecuteAsPost(t, common.GraphqlURL) - require.Nil(t, gqlResponse.Errors) + common.RequireNoGQLErrors(t, gqlResponse) require.JSONEq(t, tcase.result, string(gqlResponse.Data)) // Restore the deleted FbPosts for other test cases. @@ -331,7 +331,7 @@ func TestAuth_DeleteOnTypeWithGraphTraversalAuthRuleOnInterface(t *testing.T) { } gqlResponse := params.ExecuteAsPost(t, common.GraphqlURL) - require.Nil(t, gqlResponse.Errors) + common.RequireNoGQLErrors(t, gqlResponse) require.JSONEq(t, tcase.result, string(gqlResponse.Data)) // Restore the deleted Questions for other test cases. @@ -381,7 +381,7 @@ func TestDeleteRootFilter(t *testing.T) { } gqlResponse := getUserParams.ExecuteAsPost(t, common.GraphqlURL) - require.Nil(t, gqlResponse.Errors) + common.RequireNoGQLErrors(t, gqlResponse) require.JSONEq(t, tcase.result, string(gqlResponse.Data)) // Restore the deleted Columns. @@ -461,7 +461,7 @@ func TestDeleteRBACFilter(t *testing.T) { } gqlResponse := getUserParams.ExecuteAsPost(t, common.GraphqlURL) - require.Nil(t, gqlResponse.Errors) + common.RequireNoGQLErrors(t, gqlResponse) require.JSONEq(t, tcase.result, string(gqlResponse.Data)) // Restore the deleted logs. @@ -501,7 +501,7 @@ func TestDeleteOrRBACFilter(t *testing.T) { Variables: map[string]interface{}{"ids": allComplexLogIds}, } gqlResponse := getUserParams.ExecuteAsPost(t, common.GraphqlURL) - require.Nil(t, gqlResponse.Errors) + common.RequireNoGQLErrors(t, gqlResponse) require.JSONEq(t, tcase.result, string(gqlResponse.Data)) // Restore the deleted ComplexLog. @@ -554,7 +554,7 @@ func TestDeleteAndRBACFilter(t *testing.T) { } gqlResponse := getUserParams.ExecuteAsPost(t, common.GraphqlURL) - require.Nil(t, gqlResponse.Errors) + common.RequireNoGQLErrors(t, gqlResponse) require.JSONEq(t, string(gqlResponse.Data), tcase.result) // Restore the deleted Issues. @@ -607,7 +607,7 @@ func TestDeleteNestedFilter(t *testing.T) { } gqlResponse := getUserParams.ExecuteAsPost(t, common.GraphqlURL) - require.Nil(t, gqlResponse.Errors) + common.RequireNoGQLErrors(t, gqlResponse) require.JSONEq(t, string(gqlResponse.Data), tcase.result) // Restore the deleted Movies. @@ -641,7 +641,7 @@ func TestDeleteRBACRuleInverseField(t *testing.T) { } gqlResponse := addTweetsParams.ExecuteAsPost(t, common.GraphqlURL) - require.Nil(t, gqlResponse.Errors) + common.RequireNoGQLErrors(t, gqlResponse) testCases := []TestCase{ { @@ -678,7 +678,7 @@ func TestDeleteRBACRuleInverseField(t *testing.T) { } gqlResponse := deleteTweetsParams.ExecuteAsPost(t, common.GraphqlURL) - require.Nil(t, gqlResponse.Errors) + common.RequireNoGQLErrors(t, gqlResponse) require.JSONEq(t, string(gqlResponse.Data), tcase.result) }) } diff --git a/graphql/e2e/auth/update_mutation_test.go b/graphql/e2e/auth/update_mutation_test.go index ca499b5f803..1734c156e6c 100644 --- a/graphql/e2e/auth/update_mutation_test.go +++ b/graphql/e2e/auth/update_mutation_test.go @@ -44,7 +44,7 @@ func getAllProjects(t *testing.T, users, roles []string) []string { for _, role := range roles { getParams.Headers = common.GetJWT(t, user, role, metaInfo) gqlResponse := getParams.ExecuteAsPost(t, common.GraphqlURL) - require.Nil(t, gqlResponse.Errors) + common.RequireNoGQLErrors(t, gqlResponse) err := json.Unmarshal([]byte(gqlResponse.Data), &result) require.NoError(t, err) @@ -90,7 +90,7 @@ func getAllColumns(t *testing.T, users, roles []string) ([]*Column, []string) { for _, role := range roles { getParams.Headers = common.GetJWT(t, user, role, metaInfo) gqlResponse := getParams.ExecuteAsPost(t, common.GraphqlURL) - require.Nil(t, gqlResponse.Errors) + common.RequireNoGQLErrors(t, gqlResponse) err := json.Unmarshal(gqlResponse.Data, &result) require.NoError(t, err) @@ -140,7 +140,7 @@ func getAllQuestions(t *testing.T, users []string, answers []bool) ([]*Question, for _, ans := range answers { getParams.Headers = common.GetJWTForInterfaceAuth(t, user, "", ans, metaInfo) gqlResponse := getParams.ExecuteAsPost(t, common.GraphqlURL) - require.Nil(t, gqlResponse.Errors) + common.RequireNoGQLErrors(t, gqlResponse) err := json.Unmarshal(gqlResponse.Data, &result) require.NoError(t, err) @@ -210,7 +210,7 @@ func getAllFbPosts(t *testing.T, users []string, roles []string) ([]*FbPost, []s for _, role := range roles { getParams.Headers = common.GetJWT(t, user, role, metaInfo) gqlResponse := getParams.ExecuteAsPost(t, common.GraphqlURL) - require.Nil(t, gqlResponse.Errors) + common.RequireNoGQLErrors(t, gqlResponse) err := json.Unmarshal(gqlResponse.Data, &result) require.NoError(t, err) @@ -258,7 +258,7 @@ func getAllAnswers(t *testing.T, users []string) ([]*Answer, []string) { for _, user := range users { getParams.Headers = common.GetJWT(t, user, "", metaInfo) gqlResponse := getParams.ExecuteAsPost(t, common.GraphqlURL) - require.Nil(t, gqlResponse.Errors) + common.RequireNoGQLErrors(t, gqlResponse) err := json.Unmarshal(gqlResponse.Data, &result) require.NoError(t, err) @@ -306,7 +306,7 @@ func getAllIssues(t *testing.T, users, roles []string) ([]*Issue, []string) { for _, role := range roles { getParams.Headers = common.GetJWT(t, user, role, metaInfo) gqlResponse := getParams.ExecuteAsPost(t, common.GraphqlURL) - require.Nil(t, gqlResponse.Errors) + common.RequireNoGQLErrors(t, gqlResponse) err := json.Unmarshal(gqlResponse.Data, &result) require.NoError(t, err) @@ -355,7 +355,7 @@ func getAllMovies(t *testing.T, users, roles []string) ([]*Movie, []string) { for _, role := range roles { getParams.Headers = common.GetJWT(t, user, role, metaInfo) gqlResponse := getParams.ExecuteAsPost(t, common.GraphqlURL) - require.Nil(t, gqlResponse.Errors) + common.RequireNoGQLErrors(t, gqlResponse) err := json.Unmarshal(gqlResponse.Data, &result) require.NoError(t, err) @@ -401,7 +401,7 @@ func getAllLogs(t *testing.T, users, roles []string) ([]*Log, []string) { for _, role := range roles { getParams.Headers = common.GetJWT(t, user, role, metaInfo) gqlResponse := getParams.ExecuteAsPost(t, common.GraphqlURL) - require.Nil(t, gqlResponse.Errors) + common.RequireNoGQLErrors(t, gqlResponse) err := json.Unmarshal(gqlResponse.Data, &result) require.NoError(t, err) @@ -468,7 +468,7 @@ func TestAuth_UpdateOnInterfaceWithAuthRules(t *testing.T) { } gqlResponse := params.ExecuteAsPost(t, common.GraphqlURL) - require.Nil(t, gqlResponse.Errors) + common.RequireNoGQLErrors(t, gqlResponse) require.JSONEq(t, tcase.result, string(gqlResponse.Data)) }) } @@ -515,7 +515,7 @@ func TestAuth_UpdateOnTypeWithGraphFilterOnInterface(t *testing.T) { } gqlResponse := params.ExecuteAsPost(t, common.GraphqlURL) - require.Nil(t, gqlResponse.Errors) + common.RequireNoGQLErrors(t, gqlResponse) require.JSONEq(t, string(gqlResponse.Data), tcase.result) }) } @@ -561,7 +561,7 @@ func TestAuth_UpdateOnTypeWithRBACAuthRuleOnInterface(t *testing.T) { } gqlResponse := params.ExecuteAsPost(t, common.GraphqlURL) - require.Nil(t, gqlResponse.Errors) + common.RequireNoGQLErrors(t, gqlResponse) require.JSONEq(t, string(gqlResponse.Data), tcase.result) }) } @@ -604,7 +604,7 @@ func TestUpdateOrRBACFilter(t *testing.T) { } gqlResponse := getUserParams.ExecuteAsPost(t, common.GraphqlURL) - require.Nil(t, gqlResponse.Errors) + common.RequireNoGQLErrors(t, gqlResponse) require.JSONEq(t, string(gqlResponse.Data), tcase.result) }) } @@ -646,7 +646,7 @@ func TestUpdateRootFilter(t *testing.T) { } gqlResponse := getUserParams.ExecuteAsPost(t, common.GraphqlURL) - require.Nil(t, gqlResponse.Errors) + common.RequireNoGQLErrors(t, gqlResponse) require.JSONEq(t, string(gqlResponse.Data), tcase.result) }) @@ -679,7 +679,7 @@ func TestUpdateRBACFilter(t *testing.T) { } gqlResponse := getUserParams.ExecuteAsPost(t, common.GraphqlURL) - require.Nil(t, gqlResponse.Errors) + common.RequireNoGQLErrors(t, gqlResponse) require.JSONEq(t, string(gqlResponse.Data), tcase.result) }) @@ -722,7 +722,7 @@ func TestUpdateAndRBACFilter(t *testing.T) { } gqlResponse := getUserParams.ExecuteAsPost(t, common.GraphqlURL) - require.Nil(t, gqlResponse.Errors) + common.RequireNoGQLErrors(t, gqlResponse) require.JSONEq(t, string(gqlResponse.Data), tcase.result) }) @@ -761,7 +761,7 @@ func TestUpdateNestedFilter(t *testing.T) { } gqlResponse := getUserParams.ExecuteAsPost(t, common.GraphqlURL) - require.Nil(t, gqlResponse.Errors) + common.RequireNoGQLErrors(t, gqlResponse) require.JSONEq(t, string(gqlResponse.Data), tcase.result) }) diff --git a/graphql/e2e/common/admin.go b/graphql/e2e/common/admin.go index 619ed328ebd..6076259ca08 100644 --- a/graphql/e2e/common/admin.go +++ b/graphql/e2e/common/admin.go @@ -40,208 +40,25 @@ import ( ) const ( - // Dgraph schema should look like this if the GraphQL layer has started and - // successfully connected - initSchema = `{ - "schema": [ - { - "predicate": "dgraph.cors", - "type": "string", - "list": true, - "index": true, - "tokenizer": [ - "exact" - ], - "upsert": true - }, - { - "predicate": "dgraph.drop.op", - "type": "string" - }, - { - "predicate":"dgraph.graphql.p_query", - "type":"string" - }, - { - "predicate":"dgraph.graphql.p_sha256hash", - "type":"string", - "index":true, - "tokenizer":["exact"] - }, - { - "predicate": "dgraph.graphql.schema", - "type": "string" - }, - { - "predicate": "dgraph.graphql.schema_created_at", - "type": "datetime" - }, - { - "predicate": "dgraph.graphql.schema_history", - "type": "string" - }, - { - "predicate": "dgraph.graphql.xid", - "type": "string", - "index": true, - "tokenizer": [ - "exact" - ], - "upsert": true - }, - { - "predicate": "dgraph.type", - "type": "string", - "index": true, - "tokenizer": [ - "exact" - ], - "list": true - } - ], - "types": [ - { - "fields": [ - { - "name": "dgraph.graphql.schema" - },{ - "name": "dgraph.graphql.xid" - } - ], - "name": "dgraph.graphql" - }, - { - "fields": [ - { - "name": "dgraph.graphql.schema_history" - },{ - "name": "dgraph.graphql.schema_created_at" - } - ], - "name": "dgraph.graphql.history" - }, - { - "fields": [ - { - "name": "dgraph.graphql.p_query" - }, - { - "name": "dgraph.graphql.p_sha256hash" - } - ], - "name": "dgraph.graphql.persisted_query" - } - ] -}` - - firstTypes = ` + firstGqlSchema = ` type A { b: String }` - firstSchema = `{ - "schema": [ - { - "predicate": "A.b", - "type": "string" - }, - { - "predicate": "dgraph.cors", - "type": "string", - "list": true, - "index": true, - "tokenizer": [ - "exact" - ], - "upsert": true - }, - { - "predicate": "dgraph.drop.op", - "type": "string" - }, - { - "predicate":"dgraph.graphql.p_query", - "type":"string" - }, - { - "predicate":"dgraph.graphql.p_sha256hash", - "type":"string", - "index":true, - "tokenizer":["exact"] - }, - { - "predicate": "dgraph.graphql.schema", - "type": "string" - }, - { - "predicate": "dgraph.graphql.schema_created_at", - "type": "datetime" - }, - { - "predicate": "dgraph.graphql.schema_history", - "type": "string" - }, - { - "predicate": "dgraph.graphql.xid", - "type": "string", - "index": true, - "tokenizer": [ - "exact" - ], - "upsert": true - }, - { - "predicate": "dgraph.type", - "type": "string", - "index": true, - "tokenizer": [ - "exact" - ], - "list": true - } - ], - "types": [ - { - "fields": [ - { - "name": "A.b" - } - ], - "name": "A" - }, - { - "fields": [ - { - "name": "dgraph.graphql.schema" - },{ - "name": "dgraph.graphql.xid" - } - ], - "name": "dgraph.graphql" - }, - { - "fields": [ - { - "name": "dgraph.graphql.schema_history" - },{ - "name": "dgraph.graphql.schema_created_at" - } - ], - "name": "dgraph.graphql.history" - }, - { - "fields": [ - { - "name": "dgraph.graphql.p_query" - }, - { - "name": "dgraph.graphql.p_sha256hash" - } - ], - "name": "dgraph.graphql.persisted_query" - } - ] -}` - firstGQLSchema = `{ + firstPreds = ` + { + "predicate": "A.b", + "type": "string" + }` + firstTypes = ` + { + "fields": [ + { + "name": "A.b" + } + ], + "name": "A" + }` + firstIntrospectionResponse = `{ "__type": { "name": "A", "fields": [ @@ -252,122 +69,33 @@ const ( } }` - updatedTypes = ` + updatedGqlSchema = ` type A { b: String c: Int }` - updatedSchema = `{ - "schema": [ - { - "predicate": "A.b", - "type": "string" - }, - { - "predicate": "A.c", - "type": "int" - }, - { - "predicate": "dgraph.cors", - "type": "string", - "list": true, - "index": true, - "tokenizer": [ - "exact" - ], - "upsert": true - }, - { - "predicate": "dgraph.drop.op", - "type": "string" - }, - { - "predicate":"dgraph.graphql.p_query", - "type":"string" - }, - { - "predicate":"dgraph.graphql.p_sha256hash", - "type":"string", - "index":true, - "tokenizer":["exact"] - }, - { - "predicate": "dgraph.graphql.schema", - "type": "string" - }, - { - "predicate": "dgraph.graphql.schema_created_at", - "type": "datetime" - }, - { - "predicate": "dgraph.graphql.schema_history", - "type": "string" - }, - { - "predicate": "dgraph.graphql.xid", - "type": "string", - "index": true, - "tokenizer": [ - "exact" - ], - "upsert": true - }, - { - "predicate": "dgraph.type", - "type": "string", - "index": true, - "tokenizer": [ - "exact" - ], - "list": true - } - ], - "types": [ - { - "fields": [ - { - "name": "A.b" - }, - { - "name": "A.c" - } - ], - "name": "A" - }, - { - "fields": [ - { - "name": "dgraph.graphql.schema" - },{ - "name": "dgraph.graphql.xid" - } - ], - "name": "dgraph.graphql" - }, - { - "fields": [ - { - "name": "dgraph.graphql.schema_history" - },{ - "name": "dgraph.graphql.schema_created_at" - } - ], - "name": "dgraph.graphql.history" - }, - { - "fields": [ - { - "name": "dgraph.graphql.p_query" - }, - { - "name": "dgraph.graphql.p_sha256hash" - } - ], - "name": "dgraph.graphql.persisted_query" - } - ] -}` - updatedGQLSchema = `{ + updatedPreds = ` + { + "predicate": "A.b", + "type": "string" + }, + { + "predicate": "A.c", + "type": "int" + }` + updatedTypes = ` + { + "fields": [ + { + "name": "A.b" + }, + { + "name": "A.c" + } + ], + "name": "A" + }` + updatedIntrospectionResponse = `{ "__type": { "name": "A", "fields": [ @@ -381,14 +109,13 @@ const ( } }` - adminSchemaEndptTypes = ` + adminSchemaEndptGqlSchema = ` type A { b: String c: Int d: Float }` - adminSchemaEndptSchema = `{ - "schema": [ + adminSchemaEndptPreds = ` { "predicate": "A.b", "type": "string" @@ -400,111 +127,23 @@ const ( { "predicate": "A.d", "type": "float" - }, - { - "predicate": "dgraph.cors", - "type": "string", - "list": true, - "index": true, - "tokenizer": [ - "exact" - ], - "upsert": true - }, - { - "predicate": "dgraph.drop.op", - "type": "string" - }, - { - "predicate":"dgraph.graphql.p_query", - "type":"string" - }, - { - "predicate":"dgraph.graphql.p_sha256hash", - "type":"string", - "index":true, - "tokenizer":["exact"] - }, - { - "predicate": "dgraph.graphql.schema", - "type": "string" - }, - { - "predicate": "dgraph.graphql.schema_created_at", - "type": "datetime" - }, - { - "predicate": "dgraph.graphql.schema_history", - "type": "string" - }, - { - "predicate": "dgraph.graphql.xid", - "type": "string", - "index": true, - "tokenizer": [ - "exact" - ], - "upsert": true - }, - { - "predicate": "dgraph.type", - "type": "string", - "index": true, - "tokenizer": [ - "exact" - ], - "list": true - } - ], - "types": [ - { - "fields": [ - { - "name": "A.b" - }, - { - "name": "A.c" - }, - { - "name": "A.d" - } - ], - "name": "A" - }, - { - "fields": [ - { - "name": "dgraph.graphql.schema" - },{ - "name": "dgraph.graphql.xid" - } - ], - "name": "dgraph.graphql" - }, - { - "fields": [ - { - "name": "dgraph.graphql.schema_history" - },{ - "name": "dgraph.graphql.schema_created_at" - } - ], - "name": "dgraph.graphql.history" - }, - { - "fields": [ - { - "name": "dgraph.graphql.p_query" - }, - { - "name": "dgraph.graphql.p_sha256hash" - } - ], - "name": "dgraph.graphql.persisted_query" - } - ] -}` - adminSchemaEndptGQLSchema = `{ + }` + adminSchemaEndptTypes = ` + { + "fields": [ + { + "name": "A.b" + }, + { + "name": "A.c" + }, + { + "name": "A.d" + } + ], + "name": "A" + }` + adminSchemaEndptIntrospectionResponse = `{ "__type": { "name": "A", "fields": [ @@ -523,7 +162,7 @@ const ( ) func admin(t *testing.T) { - d, err := grpc.Dial(AlphagRPC, grpc.WithInsecure()) + d, err := grpc.Dial(Alpha1gRPC, grpc.WithInsecure()) require.NoError(t, err) client := dgo.NewDgraphClient(api.NewDgraphClient(d)) @@ -558,58 +197,59 @@ func admin(t *testing.T) { } func schemaIsInInitialState(t *testing.T, client *dgo.Dgraph) { - resp, err := client.NewReadOnlyTxn().Query(context.Background(), "schema {}") - require.NoError(t, err) - require.JSONEq(t, initSchema, string(resp.GetJson())) + testutil.VerifySchema(t, client, testutil.SchemaOptions{ExcludeAclSchema: true}) } func addGQLSchema(t *testing.T, client *dgo.Dgraph) { - err := addSchema(GraphqlAdminURL, firstTypes) - require.NoError(t, err) - - resp, err := client.NewReadOnlyTxn().Query(context.Background(), "schema {}") - require.NoError(t, err) + SafelyUpdateGQLSchemaOnAlpha1(t, firstGqlSchema) - require.JSONEq(t, firstSchema, string(resp.GetJson())) + testutil.VerifySchema(t, client, testutil.SchemaOptions{ + UserPreds: firstPreds, + UserTypes: firstTypes, + ExcludeAclSchema: true, + }) - introspect(t, firstGQLSchema) + introspect(t, firstIntrospectionResponse) } func updateSchema(t *testing.T, client *dgo.Dgraph) { - err := addSchema(GraphqlAdminURL, updatedTypes) - require.NoError(t, err) - - resp, err := client.NewReadOnlyTxn().Query(context.Background(), "schema {}") - require.NoError(t, err) + SafelyUpdateGQLSchemaOnAlpha1(t, updatedGqlSchema) - require.JSONEq(t, updatedSchema, string(resp.GetJson())) + testutil.VerifySchema(t, client, testutil.SchemaOptions{ + UserPreds: updatedPreds, + UserTypes: updatedTypes, + ExcludeAclSchema: true, + }) - introspect(t, updatedGQLSchema) + introspect(t, updatedIntrospectionResponse) } func updateSchemaThroughAdminSchemaEndpt(t *testing.T, client *dgo.Dgraph) { - err := addSchemaThroughAdminSchemaEndpt(graphqlAdminTestAdminSchemaURL, adminSchemaEndptTypes) - require.NoError(t, err) + assertUpdateGqlSchemaUsingAdminSchemaEndpt(t, Alpha1HTTP, adminSchemaEndptGqlSchema) - resp, err := client.NewReadOnlyTxn().Query(context.Background(), "schema {}") - require.NoError(t, err) - - require.JSONEq(t, adminSchemaEndptSchema, string(resp.GetJson())) + testutil.VerifySchema(t, client, testutil.SchemaOptions{ + UserPreds: adminSchemaEndptPreds, + UserTypes: adminSchemaEndptTypes, + ExcludeAclSchema: true, + }) - introspect(t, adminSchemaEndptGQLSchema) + introspect(t, adminSchemaEndptIntrospectionResponse) } func gqlSchemaNodeHasXid(t *testing.T, client *dgo.Dgraph) { resp, err := client.NewReadOnlyTxn().Query(context.Background(), `query { - gqlSchema(func: type(dgraph.graphql)) { + gqlSchema(func: has(dgraph.graphql.schema)) { dgraph.graphql.xid + dgraph.type } }`) require.NoError(t, err) - // confirm that there is only one node of type dgraph.graphql and it has xid. + // confirm that there is only one node having GraphQL schema, it has xid, + // and its type is dgraph.graphql require.JSONEq(t, `{ "gqlSchema": [{ - "dgraph.graphql.xid": "dgraph.graphql.schema" + "dgraph.graphql.xid": "dgraph.graphql.schema", + "dgraph.type": ["dgraph.graphql"] }] }`, string(resp.GetJson())) } @@ -659,7 +299,7 @@ func health(t *testing.T) { require.NoError(t, err) var health []pb.HealthInfo - resp, err := http.Get(adminDgraphHealthURL) + resp, err := http.Get(dgraphHealthURL) require.NoError(t, err) defer resp.Body.Close() healthRes, err := ioutil.ReadAll(resp.Body) @@ -825,7 +465,7 @@ func adminState(t *testing.T) { require.NoError(t, err) var state pb.MembershipState - resp, err := http.Get(adminDgraphStateURL) + resp, err := http.Get(dgraphStateURL) require.NoError(t, err) defer resp.Body.Close() stateRes, err := ioutil.ReadAll(resp.Body) diff --git a/graphql/e2e/common/common.go b/graphql/e2e/common/common.go index 483e4fb2873..faec43afe16 100644 --- a/graphql/e2e/common/common.go +++ b/graphql/e2e/common/common.go @@ -23,16 +23,17 @@ import ( "encoding/json" "io/ioutil" "net/http" + "runtime/debug" "strconv" "strings" "testing" "time" - "github.com/dgraph-io/dgraph/graphql/schema" - "github.com/golang/glog" + "github.com/prometheus/common/log" "github.com/dgraph-io/dgo/v200" "github.com/dgraph-io/dgo/v200/protos/api" + "github.com/dgraph-io/dgraph/graphql/schema" "github.com/dgraph-io/dgraph/testutil" "github.com/dgraph-io/dgraph/x" "github.com/pkg/errors" @@ -41,16 +42,30 @@ import ( ) var ( - GraphqlURL = "http://" + testutil.ContainerAddr("alpha1", 8080) + "/graphql" - GraphqlAdminURL = "http://" + testutil.ContainerAddr("alpha1", 8080) + "/admin" - AlphagRPC = testutil.ContainerAddr("alpha1", 9080) + Alpha1HTTP = testutil.ContainerAddr("alpha1", 8080) + Alpha1gRPC = testutil.ContainerAddr("alpha1", 9080) + + GraphqlURL = "http://" + Alpha1HTTP + "/graphql" + GraphqlAdminURL = "http://" + Alpha1HTTP + "/admin" - adminDgraphHealthURL = "http://" + testutil.ContainerAddr("alpha1", 8080) + "/health?all" - adminDgraphStateURL = "http://" + testutil.ContainerAddr("alpha1", 8080) + "/state" - graphqlAdminTestAdminSchemaURL = "http://" + testutil.ContainerAddr("alpha1", 8080) + "/admin/schema" + dgraphHealthURL = "http://" + Alpha1HTTP + "/health?all" + dgraphStateURL = "http://" + Alpha1HTTP + "/state" + + retryableUpdateGQLSchemaErrors = []string{ + "errIndexingInProgress", + "is already running", + "retry again, server is not ready", // given by Dgraph while applying the snapshot + "Unavailable: Server not ready", // given by GraphQL layer, during init on admin server + } + + safelyUpdateGQLSchemaErr = errors.New( + "Schema update counter didn't increment, " + + "indicating that the GraphQL layer didn't get the updated schema even after 10" + + " retries. The most probable cause is the new GraphQL schema is same as the old" + + " GraphQL schema.") ) -// GraphQLParams is parameters for the constructing a GraphQL query - that's +// GraphQLParams is parameters for constructing a GraphQL query - that's // http POST with this body, or http GET with this in the query string. // // https://graphql.org/learn/serving-over-http/ says: @@ -203,6 +218,251 @@ type Todo struct { Owner string `json:"owner,omitempty"` } +type ProbeGraphQLResp struct { + Healthy bool `json:"-"` + Status string + SchemaUpdateCounter uint64 +} + +type GqlSchema struct { + Id string + Schema string + GeneratedSchema string +} + +func probeGraphQL(authority string) (*ProbeGraphQLResp, error) { + resp, err := http.Get("http://" + authority + "/probe/graphql") + if err != nil { + return nil, err + } + + probeResp := ProbeGraphQLResp{} + if resp.StatusCode == http.StatusOK { + probeResp.Healthy = true + } + + b, err := ioutil.ReadAll(resp.Body) + if err != nil { + return nil, err + } + if err = json.Unmarshal(b, &probeResp); err != nil { + return nil, err + } + return &probeResp, nil +} + +func retryProbeGraphQL(authority string) *ProbeGraphQLResp { + for i := 0; i < 10; i++ { + resp, err := probeGraphQL(authority) + if err == nil && resp.Healthy { + return resp + } + time.Sleep(time.Second) + } + return nil +} + +func RetryProbeGraphQL(t *testing.T, authority string) *ProbeGraphQLResp { + if resp := retryProbeGraphQL(authority); resp != nil { + return resp + } + t.Fatal("Unable to get healthy response from /probe/graphql after 10 retries") + return nil +} + +// AssertSchemaUpdateCounterIncrement asserts that the schemaUpdateCounter is greater than the +// oldCounter, indicating that the GraphQL schema has been updated. +// If it can't make the assertion with enough retries, it fails the test. +func AssertSchemaUpdateCounterIncrement(t *testing.T, authority string, oldCounter uint64) { + for i := 0; i < 10; i++ { + if RetryProbeGraphQL(t, authority).SchemaUpdateCounter == oldCounter+1 { + return + } + time.Sleep(time.Second) + } + + // Even after atleast 10 seconds, the schema update hasn't reached GraphQL layer. + // That indicates something fatal. + t.Fatal(safelyUpdateGQLSchemaErr) +} + +func getGQLSchema(t *testing.T, authority string) *GraphQLResponse { + getSchemaParams := &GraphQLParams{ + Query: `query { + getGQLSchema { + id + schema + generatedSchema + } + }`, + } + return getSchemaParams.ExecuteAsPost(t, "http://"+authority+"/admin") +} + +// AssertGetGQLSchema queries the current GraphQL schema using getGQLSchema query and asserts that +// the query doesn't give any errors. It returns a *GqlSchema received in response to the query. +func AssertGetGQLSchema(t *testing.T, authority string) *GqlSchema { + resp := getGQLSchema(t, authority) + RequireNoGQLErrors(t, resp) + + var getResult struct { + GetGQLSchema *GqlSchema + } + require.NoError(t, json.Unmarshal(resp.Data, &getResult)) + + return getResult.GetGQLSchema +} + +// In addition to AssertGetGQLSchema, it also asserts that the response returned from the +// getGQLSchema query isn't nil and the Id in the response is actually a uid. +func AssertGetGQLSchemaRequireId(t *testing.T, authority string) *GqlSchema { + resp := AssertGetGQLSchema(t, authority) + require.NotNil(t, resp) + testutil.RequireUid(t, resp.Id) + return resp +} + +func updateGQLSchema(t *testing.T, authority, schema string, headers http.Header) *GraphQLResponse { + updateSchemaParams := &GraphQLParams{ + Query: `mutation updateGQLSchema($sch: String!) { + updateGQLSchema(input: { set: { schema: $sch }}) { + gqlSchema { + id + schema + generatedSchema + } + } + }`, + Variables: map[string]interface{}{"sch": schema}, + Headers: headers, + } + return updateSchemaParams.ExecuteAsPost(t, "http://"+authority+"/admin") +} + +func containsRetryableUpdateGQLSchemaError(str string) bool { + for _, retryableErr := range retryableUpdateGQLSchemaErrors { + if strings.Contains(str, retryableErr) { + return true + } + } + return false +} + +// RetryUpdateGQLSchema tries to update the GraphQL schema and if it receives a retryable error, it +// keeps retrying until it either receives no error or a non-retryable error. Then it returns the +// GraphQLResponse it received as a result of calling updateGQLSchema. +func RetryUpdateGQLSchema(t *testing.T, authority, schema string, headers http.Header) *GraphQLResponse { + for { + resp := updateGQLSchema(t, authority, schema, headers) + // return the response if we didn't get any error or get a non-retryable error + if resp.Errors == nil || !containsRetryableUpdateGQLSchemaError(resp.Errors.Error()) { + return resp + } + + // otherwise, retry schema update + t.Logf("Got error while updateGQLSchema: %s. Retrying...\n", resp.Errors.Error()) + time.Sleep(time.Second) + } +} + +// AssertUpdateGQLSchemaSuccess updates the GraphQL schema, asserts that the update succeeded and the +// returned response is correct. It returns a *GqlSchema it received in the response. +func AssertUpdateGQLSchemaSuccess(t *testing.T, authority, schema string, + headers http.Header) *GqlSchema { + // update the GraphQL schema + updateResp := RetryUpdateGQLSchema(t, authority, schema, headers) + // sanity: we shouldn't get any errors from update + RequireNoGQLErrors(t, updateResp) + + // sanity: update response should reflect the new schema + var updateResult struct { + UpdateGQLSchema struct { + GqlSchema *GqlSchema + } + } + if err := json.Unmarshal(updateResp.Data, &updateResult); err != nil { + t.Fatalf("failed to unmarshal updateGQLSchema response: %s", err.Error()) + } + require.NotNil(t, updateResult.UpdateGQLSchema.GqlSchema) + testutil.RequireUid(t, updateResult.UpdateGQLSchema.GqlSchema.Id) + require.Equalf(t, updateResult.UpdateGQLSchema.GqlSchema.Schema, schema, + "updateGQLSchema response doesn't reflect the updated schema") + + return updateResult.UpdateGQLSchema.GqlSchema +} + +// AssertUpdateGQLSchemaFailure tries to update the GraphQL schema and asserts that the update +// failed with all of the given errors. +func AssertUpdateGQLSchemaFailure(t *testing.T, authority, schema string, headers http.Header, + expectedErrors []string) { + resp := RetryUpdateGQLSchema(t, authority, schema, headers) + require.Equal(t, `{"updateGQLSchema":null}`, string(resp.Data)) + errString := resp.Errors.Error() + for _, err := range expectedErrors { + require.Contains(t, errString, err) + } +} + +// SafelyUpdateGQLSchema can be safely used in tests to update the GraphQL schema. Once the control +// returns from it, one can be sure that the newly applied schema is the one being served by the +// GraphQL layer, and hence it is safe to make any queries as per the new schema. Note that if the +// schema being provided is same as the current schema in the GraphQL layer, then this function will +// fail the test with a fatal error. +func SafelyUpdateGQLSchema(t *testing.T, authority, schema string, headers http.Header) *GqlSchema { + // first, make an initial probe to get the schema update counter + oldCounter := RetryProbeGraphQL(t, authority).SchemaUpdateCounter + + // update the GraphQL schema + gqlSchema := AssertUpdateGQLSchemaSuccess(t, authority, schema, headers) + + // now, return only after the GraphQL layer has seen the schema update. + // This makes sure that one can make queries as per the new schema. + AssertSchemaUpdateCounterIncrement(t, authority, oldCounter) + return gqlSchema +} + +// SafelyUpdateGQLSchemaOnAlpha1 is SafelyUpdateGQLSchema for alpha1 test container. +func SafelyUpdateGQLSchemaOnAlpha1(t *testing.T, schema string) *GqlSchema { + return SafelyUpdateGQLSchema(t, Alpha1HTTP, schema, nil) +} + +func updateGQLSchemaUsingAdminSchemaEndpt(t *testing.T, authority, schema string) string { + resp, err := http.Post("http://"+authority+"/admin/schema", "", strings.NewReader(schema)) + require.NoError(t, err) + + b, err := ioutil.ReadAll(resp.Body) + require.NoError(t, err) + + return string(b) +} + +func retryUpdateGQLSchemaUsingAdminSchemaEndpt(t *testing.T, authority, schema string) string { + for { + resp := updateGQLSchemaUsingAdminSchemaEndpt(t, authority, schema) + // return the response in case of success or a non-retryable error. + if !containsRetryableUpdateGQLSchemaError(resp) { + return resp + } + + // otherwise, retry schema update + t.Logf("Got error while updateGQLSchemaUsingAdminSchemaEndpt: %s. Retrying...\n", resp) + time.Sleep(time.Second) + } +} + +func assertUpdateGqlSchemaUsingAdminSchemaEndpt(t *testing.T, authority, schema string) { + // first, make an initial probe to get the schema update counter + oldCounter := RetryProbeGraphQL(t, authority).SchemaUpdateCounter + + // update the GraphQL schema and assert success + require.JSONEq(t, `{"data":{"code":"Success","message":"Done"}}`, + retryUpdateGQLSchemaUsingAdminSchemaEndpt(t, authority, schema)) + + // now, return only after the GraphQL layer has seen the schema update. + // This makes sure that one can make queries as per the new schema. + AssertSchemaUpdateCounterIncrement(t, authority, oldCounter) +} + func (twt *Tweets) DeleteByID(t *testing.T, user string, metaInfo *testutil.AuthMeta) { getParams := &GraphQLParams{ Headers: GetJWT(t, user, "", metaInfo), @@ -218,7 +478,7 @@ func (twt *Tweets) DeleteByID(t *testing.T, user string, metaInfo *testutil.Auth }}, } gqlResponse := getParams.ExecuteAsPost(t, GraphqlURL) - require.Nil(t, gqlResponse.Errors) + RequireNoGQLErrors(t, gqlResponse) } func (us *UserSecret) Delete(t *testing.T, user, role string, metaInfo *testutil.AuthMeta) { @@ -234,26 +494,46 @@ func (us *UserSecret) Delete(t *testing.T, user, role string, metaInfo *testutil Variables: map[string]interface{}{"ids": []string{us.Id}}, } gqlResponse := getParams.ExecuteAsPost(t, GraphqlURL) - require.Nil(t, gqlResponse.Errors) + RequireNoGQLErrors(t, gqlResponse) } func addSchemaAndData(schema, data []byte, client *dgo.Dgraph) { + // first, make an initial probe to get the schema update counter + oldProbe := retryProbeGraphQL(Alpha1HTTP) + + // then, add the GraphQL schema for { err := addSchema(GraphqlAdminURL, string(schema)) if err == nil { break } - if strings.Contains(err.Error(), "errIndexingInProgress") || - strings.Contains(err.Error(), "is already running") { - glog.V(2).Infof("Got error while addSchemaAndData: %v. Retrying...\n", err) + if containsRetryableUpdateGQLSchemaError(err.Error()) { + log.Infof("Got error while addSchemaAndData: %v. Retrying...\n", err) time.Sleep(time.Second) continue } + // panic, if got a non-retryable error x.Panic(err) } + // now, move forward only after the GraphQL layer has seen the schema update. + // This makes sure that one can make queries as per the new schema. + i := 0 + for ; i < 10; i++ { + newProbe := retryProbeGraphQL(Alpha1HTTP) + if newProbe.SchemaUpdateCounter > oldProbe.SchemaUpdateCounter { + break + } + time.Sleep(time.Second) + } + // Even after atleast 10 seconds, the schema update hasn't reached GraphQL layer. + // That indicates something fatal. + if i == 10 { + x.Panic(safelyUpdateGQLSchemaErr) + } + err := maybePopulateData(client, data) if err != nil { x.Panic(err) @@ -270,7 +550,7 @@ func BootstrapServer(schema, data []byte) { ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second) defer cancel() - d, err := grpc.DialContext(ctx, AlphagRPC, grpc.WithInsecure()) + d, err := grpc.DialContext(ctx, Alpha1gRPC, grpc.WithInsecure()) if err != nil { x.Panic(err) } @@ -546,7 +826,7 @@ func getQueryEmptyVariable(t *testing.T) { req.URL.RawQuery = q.Encode() res := queryCountry.Execute(t, req) - require.Nil(t, res.Errors) + RequireNoGQLErrors(t, res) } // Execute takes a HTTP request from either ExecuteAsPost or ExecuteAsGet @@ -703,16 +983,12 @@ func requireUID(t *testing.T, uid string) { } func RequireNoGQLErrors(t *testing.T, resp *GraphQLResponse) { - require.Nil(t, resp.Errors, - "required no GraphQL errors, but received :\n%s", serializeOrError(resp.Errors)) -} - -func serializeOrError(toSerialize interface{}) string { - byts, err := json.Marshal(toSerialize) - if err != nil { - return "unable to serialize because " + err.Error() + require.NotNil(t, resp) + if resp.Errors != nil { + t.Logf("required no GraphQL errors, but received: %s\n", resp.Errors.Error()) + debug.PrintStack() + t.FailNow() } - return string(byts) } func PopulateGraphQLData(client *dgo.Dgraph, data []byte) error { @@ -878,36 +1154,6 @@ func addSchema(url, schema string) error { return nil } -func addSchemaThroughAdminSchemaEndpt(url, schema string) error { - req, err := http.NewRequest(http.MethodPost, url, strings.NewReader(schema)) - if err != nil { - return errors.Wrap(err, "error running GraphQL query") - } - - resp, err := RunGQLRequest(req) - if err != nil { - return errors.Wrap(err, "error running GraphQL query") - } - - var addResult struct { - Data struct { - Code string - Message string - } - } - - err = json.Unmarshal(resp, &addResult) - if err != nil { - return errors.Wrap(err, "error trying to unmarshal GraphQL mutation result") - } - - if addResult.Data.Code != "Success" && addResult.Data.Message != "Done" { - return errors.New("GraphQL schema mutation failed") - } - - return nil -} - func GetJWT(t *testing.T, user, role string, metaInfo *testutil.AuthMeta) http.Header { metaInfo.AuthVars = map[string]interface{}{} if user != "" { diff --git a/graphql/e2e/common/error.go b/graphql/e2e/common/error.go index 409f9cfa3fe..a236d4cf7fc 100644 --- a/graphql/e2e/common/error.go +++ b/graphql/e2e/common/error.go @@ -61,7 +61,7 @@ func graphQLCompletionOn(t *testing.T) { // The schema states type Country `{ ... name: String! ... }` // so a query error will be raised if we ask for the country's name in a // query. Don't think a GraphQL update can do this ATM, so do through Dgraph. - d, err := grpc.Dial(AlphagRPC, grpc.WithInsecure()) + d, err := grpc.Dial(Alpha1gRPC, grpc.WithInsecure()) require.NoError(t, err) client := dgo.NewDgraphClient(api.NewDgraphClient(d)) mu := &api.Mutation{ diff --git a/graphql/e2e/common/mutation.go b/graphql/e2e/common/mutation.go index 4278b8c96dd..6058e55ead5 100644 --- a/graphql/e2e/common/mutation.go +++ b/graphql/e2e/common/mutation.go @@ -2144,7 +2144,7 @@ func manyMutationsWithQueryError(t *testing.T) { // The schema states type Country `{ ... name: String! ... }` // so a query error will be raised if we ask for the country's name in a // query. Don't think a GraphQL update can do this ATM, so do through Dgraph. - d, err := grpc.Dial(AlphagRPC, grpc.WithInsecure()) + d, err := grpc.Dial(Alpha1gRPC, grpc.WithInsecure()) require.NoError(t, err) client := dgo.NewDgraphClient(api.NewDgraphClient(d)) mu := &api.Mutation{ diff --git a/graphql/e2e/common/schema.go b/graphql/e2e/common/schema.go index 3c0871a692f..c09dee57e49 100644 --- a/graphql/e2e/common/schema.go +++ b/graphql/e2e/common/schema.go @@ -120,7 +120,7 @@ const ( ) func SchemaTest(t *testing.T, expectedDgraphSchema string) { - d, err := grpc.Dial(AlphagRPC, grpc.WithInsecure()) + d, err := grpc.Dial(Alpha1gRPC, grpc.WithInsecure()) require.NoError(t, err) client := dgo.NewDgraphClient(api.NewDgraphClient(d)) @@ -169,7 +169,7 @@ func graphQLDescriptions(t *testing.T) { } introspectionResult := introspect.ExecuteAsPost(t, GraphqlURL) - require.Nil(t, introspectionResult.Errors) + RequireNoGQLErrors(t, introspectionResult) require.JSONEq(t, tCase.expected, string(introspectionResult.Data)) }) diff --git a/graphql/e2e/custom_logic/custom_logic_test.go b/graphql/e2e/custom_logic/custom_logic_test.go index f16e210bd18..a794b02803c 100644 --- a/graphql/e2e/custom_logic/custom_logic_test.go +++ b/graphql/e2e/custom_logic/custom_logic_test.go @@ -75,25 +75,6 @@ const ( }` ) -func updateSchema(t *testing.T, sch string) *common.GraphQLResponse { - add := &common.GraphQLParams{ - Query: `mutation updateGQLSchema($sch: String!) { - updateGQLSchema(input: { set: { schema: $sch }}) { - gqlSchema { - schema - } - } - }`, - Variables: map[string]interface{}{"sch": sch}, - } - return add.ExecuteAsPost(t, common.GraphqlAdminURL) -} - -func updateSchemaRequireNoGQLErrors(t *testing.T, sch string) { - resp := updateSchema(t, sch) - common.RequireNoGQLErrors(t, resp) -} - func TestCustomGetQuery(t *testing.T) { schema := customTypes + ` type Query { @@ -102,8 +83,7 @@ func TestCustomGetQuery(t *testing.T) { method: "GET" }) }` - updateSchemaRequireNoGQLErrors(t, schema) - time.Sleep(2 * time.Second) + common.SafelyUpdateGQLSchemaOnAlpha1(t, schema) query := ` query { @@ -121,7 +101,7 @@ func TestCustomGetQuery(t *testing.T) { } result := params.ExecuteAsPost(t, common.GraphqlURL) - require.Nilf(t, result.Errors, "%+v", result.Errors) + common.RequireNoGQLErrors(t, result) expected := `{"myFavoriteMovies":[{"id":"0x3","name":"Star Wars","director":[{"id":"0x4","name":"George Lucas"}]},{"id":"0x5","name":"Star Trek","director":[{"id":"0x6","name":"J.J. Abrams"}]}]}` require.JSONEq(t, expected, string(result.Data)) @@ -135,8 +115,7 @@ func TestCustomPostQuery(t *testing.T) { method: "POST" }) }` - updateSchemaRequireNoGQLErrors(t, schema) - time.Sleep(2 * time.Second) + common.SafelyUpdateGQLSchemaOnAlpha1(t, schema) query := ` query { @@ -154,7 +133,7 @@ func TestCustomPostQuery(t *testing.T) { } result := params.ExecuteAsPost(t, common.GraphqlURL) - require.Nil(t, result.Errors) + common.RequireNoGQLErrors(t, result) expected := `{"myFavoriteMoviesPost":[{"id":"0x3","name":"Star Wars","director":[{"id":"0x4","name":"George Lucas"}]},{"id":"0x5","name":"Star Trek","director":[{"id":"0x6","name":"J.J. Abrams"}]}]}` require.JSONEq(t, expected, string(result.Data)) @@ -169,8 +148,7 @@ func TestCustomPostQueryWithBody(t *testing.T) { method: "POST" }) }` - updateSchemaRequireNoGQLErrors(t, schema) - time.Sleep(2 * time.Second) + common.SafelyUpdateGQLSchemaOnAlpha1(t, schema) query := ` query { @@ -188,7 +166,7 @@ func TestCustomPostQueryWithBody(t *testing.T) { } result := params.ExecuteAsPost(t, common.GraphqlURL) - require.Nil(t, result.Errors) + common.RequireNoGQLErrors(t, result) expected := `{"myFavoriteMoviesPost":[{"id":"0x3","name":"Star Wars","director": [{"id":"0x4","name":"George Lucas"}]},{"id":"0x5","name":"Star Trek","director": @@ -210,8 +188,7 @@ func TestCustomQueryShouldForwardHeaders(t *testing.T) { # Dgraph.Secret Github-Api-Token "random-fake-token" # Dgraph.Secret app "should-be-overriden" ` - updateSchemaRequireNoGQLErrors(t, schema) - time.Sleep(2 * time.Second) + common.SafelyUpdateGQLSchemaOnAlpha1(t, schema) query := ` query { @@ -230,7 +207,7 @@ func TestCustomQueryShouldForwardHeaders(t *testing.T) { } result := params.ExecuteAsPost(t, common.GraphqlURL) - require.Nilf(t, result.Errors, "%s", result.Errors) + common.RequireNoGQLErrors(t, result) expected := `{"verifyHeaders":[{"id":"0x3","name":"Star Wars"}]}` require.Equal(t, expected, string(result.Data)) } @@ -249,8 +226,7 @@ func TestCustomNameForwardHeaders(t *testing.T) { # Dgraph.Secret Github-Api-Token "random-fake-token" ` - updateSchemaRequireNoGQLErrors(t, schema) - time.Sleep(2 * time.Second) + common.SafelyUpdateGQLSchemaOnAlpha1(t, schema) query := ` query { @@ -269,7 +245,7 @@ func TestCustomNameForwardHeaders(t *testing.T) { } result := params.ExecuteAsPost(t, common.GraphqlURL) - require.Nilf(t, result.Errors, "%s", result.Errors) + common.RequireNoGQLErrors(t, result) expected := `{"verifyHeaders":[{"id":"0x3","name":"Star Wars"}]}` require.Equal(t, expected, string(result.Data)) } @@ -301,7 +277,7 @@ func TestSchemaIntrospectionForCustomQueryShouldForwardHeaders(t *testing.T) { # Dgraph.Secret GITHUB-API-TOKEN "random-api-token" ` - common.RequireNoGQLErrors(t, updateSchema(t, schema)) + common.SafelyUpdateGQLSchemaOnAlpha1(t, schema) } func TestServerShouldAllowForwardHeaders(t *testing.T) { @@ -333,8 +309,7 @@ func TestServerShouldAllowForwardHeaders(t *testing.T) { }) }` - updateSchemaRequireNoGQLErrors(t, schema) - time.Sleep(2 * time.Second) + common.SafelyUpdateGQLSchemaOnAlpha1(t, schema) req, err := http.NewRequest(http.MethodOptions, common.GraphqlURL, nil) require.NoError(t, err) @@ -347,7 +322,7 @@ func TestServerShouldAllowForwardHeaders(t *testing.T) { } func TestCustomFieldsInSubscription(t *testing.T) { - updateSchemaRequireNoGQLErrors(t, ` + common.SafelyUpdateGQLSchemaOnAlpha1(t, ` type Teacher @withSubscription { tid: ID! age: Int! @@ -376,7 +351,7 @@ func TestCustomFieldsInSubscription(t *testing.T) { } func TestSubscriptionInNestedCustomField(t *testing.T) { - updateSchemaRequireNoGQLErrors(t, ` + common.SafelyUpdateGQLSchemaOnAlpha1(t, ` type Episode { name: String! @id anotherName: String! @custom(http: { @@ -427,7 +402,7 @@ func addPerson(t *testing.T) *user { } result := addTeacherParams.ExecuteAsPost(t, common.GraphqlURL) - require.Nil(t, result.Errors) + common.RequireNoGQLErrors(t, result) var res struct { AddPerson struct { @@ -449,8 +424,7 @@ func TestCustomQueryWithNonExistentURLShouldReturnError(t *testing.T) { method: "GET" }) }` - updateSchema(t, schema) - time.Sleep(2 * time.Second) + common.SafelyUpdateGQLSchemaOnAlpha1(t, schema) query := ` query { @@ -518,9 +492,7 @@ func TestCustomQueryShouldPropagateErrorFromFields(t *testing.T) { mode: SINGLE }) }` - - updateSchema(t, schema) - time.Sleep(2 * time.Second) + common.SafelyUpdateGQLSchemaOnAlpha1(t, schema) p := addPerson(t) queryPerson := ` @@ -1025,8 +997,7 @@ func TestCustomFieldsShouldForwardHeaders(t *testing.T) { # Dgraph.Secret STRIPE-API-KEY "some-api-key" ` - updateSchemaRequireNoGQLErrors(t, schema) - time.Sleep(2 * time.Second) + common.SafelyUpdateGQLSchemaOnAlpha1(t, schema) users := addUsers(t) @@ -1047,7 +1018,7 @@ func TestCustomFieldsShouldForwardHeaders(t *testing.T) { } result := params.ExecuteAsPost(t, common.GraphqlURL) - require.Nilf(t, result.Errors, "%+v", result.Errors) + common.RequireNoGQLErrors(t, result) } func TestCustomFieldsShouldSkipNonEmptyVariable(t *testing.T) { @@ -1070,8 +1041,7 @@ func TestCustomFieldsShouldSkipNonEmptyVariable(t *testing.T) { # Dgraph.Secret GITHUB-API-TOKEN "some-api-token" ` - updateSchemaRequireNoGQLErrors(t, schema) - time.Sleep(2 * time.Second) + common.SafelyUpdateGQLSchemaOnAlpha1(t, schema) users := addUsers(t) queryUser := ` @@ -1088,11 +1058,11 @@ func TestCustomFieldsShouldSkipNonEmptyVariable(t *testing.T) { } result := params.ExecuteAsPost(t, common.GraphqlURL) - require.Nilf(t, result.Errors, "%+v", result.Errors) + common.RequireNoGQLErrors(t, result) } func TestCustomFieldsShouldPassBody(t *testing.T) { - dg, err := testutil.DgraphClient(common.AlphagRPC) + dg, err := testutil.DgraphClient(common.Alpha1gRPC) require.NoError(t, err) testutil.DropAll(t, dg) schema := ` @@ -1113,8 +1083,7 @@ func TestCustomFieldsShouldPassBody(t *testing.T) { } # Dgraph.Secret GITHUB-API-TOKEN "some-api-token" ` - updateSchemaRequireNoGQLErrors(t, schema) - time.Sleep(2 * time.Second) + common.SafelyUpdateGQLSchemaOnAlpha1(t, schema) params := &common.GraphQLParams{ Query: `mutation addUser { @@ -1144,7 +1113,7 @@ func TestCustomFieldsShouldPassBody(t *testing.T) { } result = params.ExecuteAsPost(t, common.GraphqlURL) - require.Nilf(t, result.Errors, "%+v", result.Errors) + common.RequireNoGQLErrors(t, result) } func TestCustomFieldsShouldBeResolved(t *testing.T) { @@ -1156,8 +1125,7 @@ func TestCustomFieldsShouldBeResolved(t *testing.T) { // 4. Single operation mode along with GraphQL. schema := readFile(t, "schemas/batch-mode-rest.graphql") - updateSchemaRequireNoGQLErrors(t, schema) - time.Sleep(2 * time.Second) + common.SafelyUpdateGQLSchemaOnAlpha1(t, schema) // add some data teachers := addTeachers(t) @@ -1172,21 +1140,21 @@ func TestCustomFieldsShouldBeResolved(t *testing.T) { t.Run("rest single operation mode", func(t *testing.T) { // lets update the schema and check single mode now schema := readFile(t, "schemas/single-mode-rest.graphql") - updateSchemaRequireNoGQLErrors(t, schema) + common.SafelyUpdateGQLSchemaOnAlpha1(t, schema) verifyData(t, users, teachers, schools) }) t.Run("graphql single operation mode", func(t *testing.T) { // update schema to single mode where fields are resolved using GraphQL endpoints. schema := readFile(t, "schemas/single-mode-graphql.graphql") - updateSchemaRequireNoGQLErrors(t, schema) + common.SafelyUpdateGQLSchemaOnAlpha1(t, schema) verifyData(t, users, teachers, schools) }) t.Run("graphql batch operation mode", func(t *testing.T) { // update schema to single mode where fields are resolved using GraphQL endpoints. schema := readFile(t, "schemas/batch-mode-graphql.graphql") - updateSchemaRequireNoGQLErrors(t, schema) + common.SafelyUpdateGQLSchemaOnAlpha1(t, schema) verifyData(t, users, teachers, schools) }) @@ -1194,7 +1162,7 @@ func TestCustomFieldsShouldBeResolved(t *testing.T) { t.Run("mixed mode", func(t *testing.T) { // update schema to single mode where fields are resolved using GraphQL endpoints. schema := readFile(t, "schemas/mixed-modes.graphql") - updateSchemaRequireNoGQLErrors(t, schema) + common.SafelyUpdateGQLSchemaOnAlpha1(t, schema) verifyData(t, users, teachers, schools) }) } @@ -1230,7 +1198,7 @@ func TestCustomFieldResolutionShouldPropagateGraphQLErrors(t *testing.T) { } ) }` - updateSchemaRequireNoGQLErrors(t, schema) + common.SafelyUpdateGQLSchemaOnAlpha1(t, schema) users := addUsers(t) // Sleep so that schema update can come through in Alpha. time.Sleep(time.Second) @@ -1321,10 +1289,8 @@ func TestForInvalidCustomQuery(t *testing.T) { graphql: "query($id: ID!) { country(code: $id) }" }) }` - res := updateSchema(t, schema) - require.Equal(t, `{"updateGQLSchema":null}`, string(res.Data)) - require.Len(t, res.Errors, 1) - require.Contains(t, res.Errors[0].Error(), " query `country` is not present in remote schema") + common.AssertUpdateGQLSchemaFailure(t, common.Alpha1HTTP, schema, nil, + []string{"query `country` is not present in remote schema"}) } func TestForInvalidArgument(t *testing.T) { @@ -1349,12 +1315,8 @@ func TestForInvalidArgument(t *testing.T) { graphql: "query($id: ID!) { country(code: $id) }" }) }` - res := updateSchema(t, schema) - require.Equal(t, `{"updateGQLSchema":null}`, string(res.Data)) - require.Len(t, res.Errors, 1) - require.Contains(t, res.Errors[0].Error(), "argument `code` is not present in remote query"+ - " `country`") - + common.AssertUpdateGQLSchemaFailure(t, common.Alpha1HTTP, schema, nil, + []string{"argument `code` is not present in remote query `country`"}) } func TestForInvalidType(t *testing.T) { @@ -1379,11 +1341,8 @@ func TestForInvalidType(t *testing.T) { graphql: "query($id: ID!) { country(code: $id) }" }) }` - res := updateSchema(t, schema) - require.Equal(t, `{"updateGQLSchema":null}`, string(res.Data)) - require.Len(t, res.Errors, 1) - require.Contains(t, res.Errors[0].Error(), "found type mismatch for "+ - "variable `$id` in query `country`, expected `ID!`, got `Int!`") + common.AssertUpdateGQLSchemaFailure(t, common.Alpha1HTTP, schema, nil, []string{ + "found type mismatch for variable `$id` in query `country`, expected `ID!`, got `Int!`"}) } func TestCustomLogicGraphql(t *testing.T) { @@ -1403,8 +1362,7 @@ func TestCustomLogicGraphql(t *testing.T) { } ) }` - updateSchemaRequireNoGQLErrors(t, schema) - time.Sleep(2 * time.Second) + common.SafelyUpdateGQLSchemaOnAlpha1(t, schema) query := ` query { getCountry1(id: "BI"){ @@ -1439,8 +1397,7 @@ func TestCustomLogicGraphqlWithArgumentsOnFields(t *testing.T) { } ) }` - updateSchemaRequireNoGQLErrors(t, schema) - time.Sleep(2 * time.Second) + common.SafelyUpdateGQLSchemaOnAlpha1(t, schema) query := ` query { getCountry2(id: "BI"){ @@ -1489,8 +1446,7 @@ func TestCustomLogicGraphqlWithError(t *testing.T) { graphql: "query($id: ID!) { country(code: $id) }" }) }` - updateSchemaRequireNoGQLErrors(t, schema) - time.Sleep(2 * time.Second) + common.SafelyUpdateGQLSchemaOnAlpha1(t, schema) query := ` query { getCountryOnlyErr(id: "BI"){ @@ -1524,8 +1480,7 @@ func TestCustomLogicGraphQLValidArrayResponse(t *testing.T) { } ) }` - updateSchemaRequireNoGQLErrors(t, schema) - time.Sleep(2 * time.Second) + common.SafelyUpdateGQLSchemaOnAlpha1(t, schema) query := ` query { getCountries(id: "BI"){ @@ -1574,8 +1529,7 @@ func TestCustomLogicWithErrorResponse(t *testing.T) { graphql: "query($id: ID!) { country(code: $id) }" }) }` - updateSchemaRequireNoGQLErrors(t, schema) - time.Sleep(2 * time.Second) + common.SafelyUpdateGQLSchemaOnAlpha1(t, schema) query := ` query { getCountriesErr(id: "BI"){ @@ -1682,8 +1636,7 @@ func TestCustomFieldsWithXidShouldBeResolved(t *testing.T) { }) episodes: [Episode] }` - updateSchemaRequireNoGQLErrors(t, schema) - time.Sleep(2 * time.Second) + common.SafelyUpdateGQLSchemaOnAlpha1(t, schema) ep1 := "episode-1" ep2 := "episode-2" @@ -1789,7 +1742,7 @@ func TestCustomFieldsWithXidShouldBeResolved(t *testing.T) { }) episodes: [Episode] }` - updateSchemaRequireNoGQLErrors(t, schema) + common.SafelyUpdateGQLSchemaOnAlpha1(t, schema) result = params.ExecuteAsPost(t, common.GraphqlURL) common.RequireNoGQLErrors(t, result) @@ -1816,8 +1769,7 @@ func TestCustomPostMutation(t *testing.T) { body: "{ movies: $input}" }) }` - updateSchemaRequireNoGQLErrors(t, schema) - time.Sleep(2 * time.Second) + common.SafelyUpdateGQLSchemaOnAlpha1(t, schema) params := &common.GraphQLParams{ Query: ` @@ -1895,8 +1847,7 @@ func TestCustomPostMutationNullInBody(t *testing.T) { body: "{ movies: $input}" }) }` - updateSchemaRequireNoGQLErrors(t, schema) - time.Sleep(2 * time.Second) + common.SafelyUpdateGQLSchemaOnAlpha1(t, schema) params := &common.GraphQLParams{ Query: ` @@ -1965,8 +1916,7 @@ func TestCustomPatchMutation(t *testing.T) { body: "$input" }) }` - updateSchemaRequireNoGQLErrors(t, schema) - time.Sleep(2 * time.Second) + common.SafelyUpdateGQLSchemaOnAlpha1(t, schema) params := &common.GraphQLParams{ Query: ` @@ -2016,8 +1966,7 @@ func TestCustomMutationShouldForwardHeaders(t *testing.T) { forwardHeaders: ["X-App-Token", "X-User-Id"] }) }` - updateSchemaRequireNoGQLErrors(t, schema) - time.Sleep(2 * time.Second) + common.SafelyUpdateGQLSchemaOnAlpha1(t, schema) params := &common.GraphQLParams{ Query: ` @@ -2056,10 +2005,8 @@ func TestCustomGraphqlNullQueryType(t *testing.T) { graphql: "query($id: ID!) { getCountry(id: $id) }" }) }` - res := updateSchema(t, schema) - require.Equal(t, `{"updateGQLSchema":null}`, string(res.Data)) - require.Len(t, res.Errors, 1) - require.Contains(t, res.Errors[0].Error(), "remote schema doesn't have any queries.") + common.AssertUpdateGQLSchemaFailure(t, common.Alpha1HTTP, schema, nil, + []string{"remote schema doesn't have any queries."}) } func TestCustomGraphqlNullMutationType(t *testing.T) { @@ -2071,10 +2018,8 @@ func TestCustomGraphqlNullMutationType(t *testing.T) { graphql: "mutation($input: CountryInput!) { putCountry(country: $input) }" }) }` - res := updateSchema(t, schema) - require.Equal(t, `{"updateGQLSchema":null}`, string(res.Data)) - require.Len(t, res.Errors, 1) - require.Contains(t, res.Errors[0].Error(), "remote schema doesn't have any mutations.") + common.AssertUpdateGQLSchemaFailure(t, common.Alpha1HTTP, schema, nil, + []string{"remote schema doesn't have any mutations."}) } func TestCustomGraphqlMissingQueryType(t *testing.T) { @@ -2086,10 +2031,8 @@ func TestCustomGraphqlMissingQueryType(t *testing.T) { graphql: "query($id: ID!) { getCountry(id: $id) }" }) }` - res := updateSchema(t, schema) - require.Equal(t, `{"updateGQLSchema":null}`, string(res.Data)) - require.Len(t, res.Errors, 1) - require.Contains(t, res.Errors[0].Error(), "remote schema doesn't have any type named Query.") + common.AssertUpdateGQLSchemaFailure(t, common.Alpha1HTTP, schema, nil, + []string{"remote schema doesn't have any type named Query."}) } func TestCustomGraphqlMissingMutationType(t *testing.T) { @@ -2101,10 +2044,8 @@ func TestCustomGraphqlMissingMutationType(t *testing.T) { graphql: "mutation($input: CountryInput!) { putCountry(country: $input) }" }) }` - res := updateSchema(t, schema) - require.Equal(t, `{"updateGQLSchema":null}`, string(res.Data)) - require.Len(t, res.Errors, 1) - require.Contains(t, res.Errors[0].Error(), "remote schema doesn't have any type named Mutation") + common.AssertUpdateGQLSchemaFailure(t, common.Alpha1HTTP, schema, nil, + []string{"remote schema doesn't have any type named Mutation"}) } func TestCustomGraphqlMissingMutation(t *testing.T) { @@ -2119,11 +2060,8 @@ func TestCustomGraphqlMissingMutation(t *testing.T) { } ) }` - res := updateSchema(t, schema) - require.Equal(t, `{"updateGQLSchema":null}`, string(res.Data)) - require.Len(t, res.Errors, 1) - require.Contains(t, res.Errors[0].Error(), "mutation `putCountry` is not present in remote"+ - " schema") + common.AssertUpdateGQLSchemaFailure(t, common.Alpha1HTTP, schema, nil, + []string{"mutation `putCountry` is not present in remote schema"}) } func TestCustomGraphqlReturnTypeMismatch(t *testing.T) { @@ -2135,11 +2073,8 @@ func TestCustomGraphqlReturnTypeMismatch(t *testing.T) { graphql: "mutation($input: CountryInput!) { setCountry(country: $input) }" }) }` - res := updateSchema(t, schema) - require.Equal(t, `{"updateGQLSchema":null}`, string(res.Data)) - require.Len(t, res.Errors, 1) - require.Contains(t, res.Errors[0].Error(), "found return type mismatch for mutation"+ - " `setCountry`, expected `Movie!`, got `Country!`") + common.AssertUpdateGQLSchemaFailure(t, common.Alpha1HTTP, schema, nil, []string{ + "found return type mismatch for mutation `setCountry`, expected `Movie!`, got `Country!`"}) } func TestCustomGraphqlReturnTypeMismatchForBatchedField(t *testing.T) { @@ -2160,13 +2095,10 @@ func TestCustomGraphqlReturnTypeMismatchForBatchedField(t *testing.T) { }) } ` - res := updateSchema(t, schema) - require.Equal(t, `{"updateGQLSchema":null}`, string(res.Data)) - require.Len(t, res.Errors, 1) - require.Contains(t, res.Errors[0].Error(), - "resolving updateGQLSchema failed because input:13: Type Post; Field author: inside "+ - "graphql in @custom directive, found return type mismatch for query `getPosts`, "+ - "expected `[Author!]`, got `[Post!]`.\n") + common.AssertUpdateGQLSchemaFailure(t, common.Alpha1HTTP, schema, nil, []string{ + "resolving updateGQLSchema failed because input:13: Type Post; Field author: inside " + + "graphql in @custom directive, found return type mismatch for query `getPosts`, " + + "expected `[Author!]`, got `[Post!]`.\n"}) } func TestCustomGraphqlInvalidInputFormatForBatchedField(t *testing.T) { @@ -2183,13 +2115,10 @@ func TestCustomGraphqlInvalidInputFormatForBatchedField(t *testing.T) { }) } ` - res := updateSchema(t, schema) - require.Equal(t, `{"updateGQLSchema":null}`, string(res.Data)) - require.Len(t, res.Errors, 1) - require.Contains(t, res.Errors[0].Error(), - "resolving updateGQLSchema failed because input:9: Type Post; Field comments: inside "+ - "graphql in @custom directive, for BATCH mode, query `getPosts` can have only one "+ - "argument whose value should be a variable.\n") + common.AssertUpdateGQLSchemaFailure(t, common.Alpha1HTTP, schema, nil, []string{ + "resolving updateGQLSchema failed because input:9: Type Post; Field comments: inside " + + "graphql in @custom directive, for BATCH mode, query `getPosts` can have only one " + + "argument whose value should be a variable.\n"}) } func TestCustomGraphqlMissingTypeForBatchedFieldInput(t *testing.T) { @@ -2206,13 +2135,10 @@ func TestCustomGraphqlMissingTypeForBatchedFieldInput(t *testing.T) { }) } ` - res := updateSchema(t, schema) - require.Equal(t, `{"updateGQLSchema":null}`, string(res.Data)) - require.Len(t, res.Errors, 1) - require.Contains(t, res.Errors[0].Error(), - "resolving updateGQLSchema failed because input:9: Type Post; Field comments: inside "+ - "graphql in @custom directive, remote schema doesn't have any type named "+ - "PostFilterInput.\n") + common.AssertUpdateGQLSchemaFailure(t, common.Alpha1HTTP, schema, nil, []string{ + "resolving updateGQLSchema failed because input:9: Type Post; Field comments: inside " + + "graphql in @custom directive, remote schema doesn't have any type named " + + "PostFilterInput.\n"}) } func TestCustomGraphqlMissingRequiredArgument(t *testing.T) { @@ -2248,11 +2174,9 @@ func TestCustomGraphqlMissingRequiredArgument(t *testing.T) { graphql: "mutation { setCountry() }" }) }` - res := updateSchema(t, schema) - require.Equal(t, `{"updateGQLSchema":null}`, string(res.Data)) - require.Len(t, res.Errors, 1) - require.Contains(t, res.Errors[0].Error(), "argument `country` in mutation"+ - " `setCountry` is missing, it is required by remote mutation.") + common.AssertUpdateGQLSchemaFailure(t, common.Alpha1HTTP, schema, nil, []string{ + "argument `country` in mutation" + + " `setCountry` is missing, it is required by remote mutation."}) } // this one accepts an object and returns an object @@ -2289,8 +2213,7 @@ func TestCustomGraphqlMutation1(t *testing.T) { graphql: "mutation($input: CountryInput!) { setCountry(country: $input) }" }) }` - updateSchemaRequireNoGQLErrors(t, schema) - time.Sleep(2 * time.Second) + common.SafelyUpdateGQLSchemaOnAlpha1(t, schema) params := &common.GraphQLParams{ Query: ` @@ -2379,8 +2302,7 @@ func TestCustomGraphqlMutation2(t *testing.T) { graphql: "mutation($name: String, $std: Int) { updateCountries(name: $name, std: $std) }" }) }` - updateSchemaRequireNoGQLErrors(t, schema) - time.Sleep(2 * time.Second) + common.SafelyUpdateGQLSchemaOnAlpha1(t, schema) params := &common.GraphQLParams{ Query: ` @@ -2437,8 +2359,7 @@ func TestForValidInputArgument(t *testing.T) { } ) }` - common.RequireNoGQLErrors(t, updateSchema(t, schema)) - time.Sleep(2 * time.Second) + common.SafelyUpdateGQLSchemaOnAlpha1(t, schema) params := &common.GraphQLParams{ Query: ` @@ -2495,8 +2416,8 @@ func TestForInvalidInputObject(t *testing.T) { myCustom(yo: CountryInput!): [Country!]! @custom(http: {url: "http://mock:8888/invalidfield", method: "POST", graphql: "query($yo: CountryInput!) {countries(filter: $yo)}"}) } ` - res := updateSchema(t, schema) - require.Contains(t, res.Errors.Error(), "expected type for the field code is Int! but got String! in type CountryInput") + common.AssertUpdateGQLSchemaFailure(t, common.Alpha1HTTP, schema, nil, + []string{"expected type for the field code is Int! but got String! in type CountryInput"}) } func TestForNestedInvalidInputObject(t *testing.T) { @@ -2530,8 +2451,8 @@ func TestForNestedInvalidInputObject(t *testing.T) { graphql: "query($yo: CountryInput!) {countries(filter: $yo)}"}) } ` - res := updateSchema(t, schema) - require.Contains(t, res.Errors.Error(), "expected type for the field name is Int! but got String! in type StateInput") + common.AssertUpdateGQLSchemaFailure(t, common.Alpha1HTTP, schema, nil, + []string{"expected type for the field name is Int! but got String! in type StateInput"}) } func TestRestCustomLogicInDeepNestedField(t *testing.T) { @@ -2562,8 +2483,7 @@ func TestRestCustomLogicInDeepNestedField(t *testing.T) { } ` - updateSchemaRequireNoGQLErrors(t, schema) - time.Sleep(2 * time.Second) + common.SafelyUpdateGQLSchemaOnAlpha1(t, schema) params := &common.GraphQLParams{ Query: ` @@ -2630,7 +2550,7 @@ func TestRestCustomLogicInDeepNestedField(t *testing.T) { } func TestCustomDQL(t *testing.T) { - dg, err := testutil.DgraphClient(common.AlphagRPC) + dg, err := testutil.DgraphClient(common.Alpha1gRPC) require.NoError(t, err) testutil.DropAll(t, dg) @@ -2706,8 +2626,7 @@ func TestCustomDQL(t *testing.T) { """) } ` - updateSchemaRequireNoGQLErrors(t, schema) - time.Sleep(2 * time.Second) + common.SafelyUpdateGQLSchemaOnAlpha1(t, schema) params := &common.GraphQLParams{ Query: ` @@ -2817,8 +2736,7 @@ func TestCustomGetQuerywithRESTError(t *testing.T) { method: "GET" }) }` - updateSchemaRequireNoGQLErrors(t, schema) - time.Sleep(2 * time.Second) + common.SafelyUpdateGQLSchemaOnAlpha1(t, schema) query := ` query { @@ -2877,8 +2795,7 @@ func TestCustomFieldsWithRestError(t *testing.T) { } ` - updateSchemaRequireNoGQLErrors(t, schema) - time.Sleep(2 * time.Second) + common.SafelyUpdateGQLSchemaOnAlpha1(t, schema) params := &common.GraphQLParams{ Query: `mutation addUser { @@ -2956,8 +2873,7 @@ func TestCustomPostMutationWithRESTError(t *testing.T) { body: "{ movies: $input}" }) }` - updateSchemaRequireNoGQLErrors(t, schema) - time.Sleep(2 * time.Second) + common.SafelyUpdateGQLSchemaOnAlpha1(t, schema) params := &common.GraphQLParams{ Query: ` @@ -3005,8 +2921,7 @@ func TestCustomResolverInInterfaceImplFrag(t *testing.T) { body: "{name: $name, totalCredits: $totalCredits}" }) }` - updateSchemaRequireNoGQLErrors(t, schema) - time.Sleep(2 * time.Second) + common.SafelyUpdateGQLSchemaOnAlpha1(t, schema) addCharacterParams := &common.GraphQLParams{ Query: `mutation { diff --git a/graphql/e2e/schema/schema_test.go b/graphql/e2e/schema/schema_test.go index 15aa1c969c7..430ca79effc 100644 --- a/graphql/e2e/schema/schema_test.go +++ b/graphql/e2e/schema/schema_test.go @@ -24,13 +24,10 @@ import ( "io/ioutil" "net/http" "os" - "runtime/debug" - "strings" "sync" "testing" "time" - "github.com/dgraph-io/dgo/v200" "github.com/dgraph-io/dgo/v200/protos/api" "github.com/dgraph-io/dgraph/graphql/e2e/common" "github.com/dgraph-io/dgraph/testutil" @@ -40,22 +37,17 @@ import ( ) var ( - groupOneServer = "http://" + testutil.ContainerAddr("alpha1", 8080) + "/graphql" - groupOneAdminServer = "http://" + testutil.ContainerAddr("alpha1", 8080) + "/admin" - groupOnegRPC = testutil.SockAddr - groupTwoServer = "http://" + testutil.ContainerAddr("alpha2", 8080) + "/graphql" - groupTwoAdminServer = "http://" + testutil.ContainerAddr("alpha2", 8080) + "/admin" - groupThreeServer = "http://" + testutil.ContainerAddr("alpha3", 8080) + "/graphql" - groupThreeAdminServer = "http://" + testutil.ContainerAddr("alpha3", 8080) + "/admin" -) + groupOneHTTP = testutil.ContainerAddr("alpha1", 8080) + groupTwoHTTP = testutil.ContainerAddr("alpha2", 8080) + groupThreeHTTP = testutil.ContainerAddr("alpha3", 8080) + groupOnegRPC = testutil.SockAddr -func requireNoErrors(t *testing.T, resp *common.GraphQLResponse) { - if len(resp.Errors) > 0 { - t.Logf("Got errors: %s\n", resp.Errors.Error()) - debug.PrintStack() - t.FailNow() - } -} + groupOneGraphQLServer = "http://" + groupOneHTTP + "/graphql" + groupTwoGraphQLServer = "http://" + groupTwoHTTP + "/graphql" + groupThreeGraphQLServer = "http://" + groupThreeHTTP + "/graphql" + + groupOneAdminServer = "http://" + groupOneHTTP + "/admin" +) // This test is supposed to test the graphql schema subscribe feature. Whenever schema is updated // in a dgraph alpha for one group, that update should also be propagated to alpha nodes in other @@ -66,7 +58,15 @@ func TestSchemaSubscribe(t *testing.T) { id: ID! name: String! }` - updateGQLSchemaRequireNoErrors(t, schema, groupOneAdminServer) + groupOnePreUpdateCounter := common.RetryProbeGraphQL(t, groupOneHTTP).SchemaUpdateCounter + common.SafelyUpdateGQLSchema(t, groupOneHTTP, schema, nil) + + // since the schema has been updated on group one, the schemaUpdateCounter on all the servers + // should have got incremented and must be the same, indicating that the schema update has + // reached all the servers. + common.AssertSchemaUpdateCounterIncrement(t, groupOneHTTP, groupOnePreUpdateCounter) + common.AssertSchemaUpdateCounterIncrement(t, groupTwoHTTP, groupOnePreUpdateCounter) + common.AssertSchemaUpdateCounterIncrement(t, groupThreeHTTP, groupOnePreUpdateCounter) introspectionQuery := ` query { @@ -96,16 +96,18 @@ func TestSchemaSubscribe(t *testing.T) { } }` - introspectionResult := runIntrospectWithRetryIfNecessary(t, introspect, groupOneServer) - requireNoErrors(t, introspectionResult) + // Also, the introspection query on all the servers should + // give the same result as they have the same schema. + introspectionResult := introspect.ExecuteAsPost(t, groupOneGraphQLServer) + common.RequireNoGQLErrors(t, introspectionResult) testutil.CompareJSON(t, expectedResult, string(introspectionResult.Data)) - introspectionResult = runIntrospectWithRetryIfNecessary(t, introspect, groupTwoServer) - requireNoErrors(t, introspectionResult) + introspectionResult = introspect.ExecuteAsPost(t, groupTwoGraphQLServer) + common.RequireNoGQLErrors(t, introspectionResult) testutil.CompareJSON(t, expectedResult, string(introspectionResult.Data)) - introspectionResult = runIntrospectWithRetryIfNecessary(t, introspect, groupThreeServer) - requireNoErrors(t, introspectionResult) + introspectionResult = introspect.ExecuteAsPost(t, groupThreeGraphQLServer) + common.RequireNoGQLErrors(t, introspectionResult) testutil.CompareJSON(t, expectedResult, string(introspectionResult.Data)) // Now update schema on an alpha node for group 3 and see if nodes in group 1 and 2 also get it. @@ -119,7 +121,12 @@ func TestSchemaSubscribe(t *testing.T) { interface Post { id: ID! }` - updateGQLSchemaRequireNoErrors(t, schema, groupThreeAdminServer) + groupThreePreUpdateCounter := groupOnePreUpdateCounter + 1 + common.SafelyUpdateGQLSchema(t, groupThreeHTTP, schema, nil) + + common.AssertSchemaUpdateCounterIncrement(t, groupOneHTTP, groupThreePreUpdateCounter) + common.AssertSchemaUpdateCounterIncrement(t, groupTwoHTTP, groupThreePreUpdateCounter) + common.AssertSchemaUpdateCounterIncrement(t, groupThreeHTTP, groupThreePreUpdateCounter) expectedResult = `{ @@ -141,16 +148,16 @@ func TestSchemaSubscribe(t *testing.T) { ] } }` - introspectionResult = runIntrospectWithRetryIfNecessary(t, introspect, groupOneServer) - requireNoErrors(t, introspectionResult) + introspectionResult = introspect.ExecuteAsPost(t, groupOneGraphQLServer) + common.RequireNoGQLErrors(t, introspectionResult) testutil.CompareJSON(t, expectedResult, string(introspectionResult.Data)) - introspectionResult = runIntrospectWithRetryIfNecessary(t, introspect, groupTwoServer) - requireNoErrors(t, introspectionResult) + introspectionResult = introspect.ExecuteAsPost(t, groupTwoGraphQLServer) + common.RequireNoGQLErrors(t, introspectionResult) testutil.CompareJSON(t, expectedResult, string(introspectionResult.Data)) - introspectionResult = runIntrospectWithRetryIfNecessary(t, introspect, groupThreeServer) - requireNoErrors(t, introspectionResult) + introspectionResult = introspect.ExecuteAsPost(t, groupThreeGraphQLServer) + common.RequireNoGQLErrors(t, introspectionResult) testutil.CompareJSON(t, expectedResult, string(introspectionResult.Data)) } @@ -160,7 +167,7 @@ func TestSchemaSubscribe(t *testing.T) { // 2. if the schema update succeeds, then the last successful schema update is reflected by both // Dgraph and GraphQL schema // -// It also makes sure that only one node exists for GraphQL schema in Dgraph after all the +// It also tests that only one node exists for GraphQL schema in Dgraph after all the // concurrent requests have executed. func TestConcurrentSchemaUpdates(t *testing.T) { dg, err := testutil.DgraphClient(groupOnegRPC) @@ -170,7 +177,7 @@ func TestConcurrentSchemaUpdates(t *testing.T) { tcases := []struct { graphQLSchema string dgraphSchema string - url string + authority string }{ { graphQLSchema: ` @@ -178,10 +185,10 @@ func TestConcurrentSchemaUpdates(t *testing.T) { b: String! }`, dgraphSchema: `{ - "predicate": "A.b", - "type": "string" - }`, - url: groupOneAdminServer, + "predicate": "A.b", + "type": "string" + }`, + authority: groupOneHTTP, }, { graphQLSchema: ` @@ -189,14 +196,14 @@ func TestConcurrentSchemaUpdates(t *testing.T) { b: String! @search(by: [term]) }`, dgraphSchema: `{ - "predicate": "A.b", - "type": "string", - "index": true, - "tokenizer": [ - "term" - ] - }`, - url: groupTwoAdminServer, + "predicate": "A.b", + "type": "string", + "index": true, + "tokenizer": [ + "term" + ] + }`, + authority: groupTwoHTTP, }, { graphQLSchema: ` @@ -204,14 +211,14 @@ func TestConcurrentSchemaUpdates(t *testing.T) { b: String! @search(by: [exact]) }`, dgraphSchema: `{ - "predicate": "A.b", - "type": "string", - "index": true, - "tokenizer": [ - "exact" - ] - }`, - url: groupThreeAdminServer, + "predicate": "A.b", + "type": "string", + "index": true, + "tokenizer": [ + "exact" + ] + }`, + authority: groupThreeHTTP, }, } @@ -229,7 +236,7 @@ func TestConcurrentSchemaUpdates(t *testing.T) { go func(reqIdx int) { tcaseIdx := reqIdx % numTcases // if the update succeeded, save the success request timestamp and tcase index - if updateGQLSchemaConcurrent(t, tcases[tcaseIdx].graphQLSchema, tcases[tcaseIdx].url) { + if updateGQLSchemaConcurrent(t, tcases[tcaseIdx].graphQLSchema, tcases[tcaseIdx].authority) { now := time.Now().UnixNano() mux.Lock() if now > lastSuccessReqTimestamp { @@ -249,112 +256,26 @@ func TestConcurrentSchemaUpdates(t *testing.T) { require.GreaterOrEqual(t, lastSuccessReqTimestamp, int64(0)) require.GreaterOrEqual(t, lastSuccessTcaseIdx, 0) - // build the final Dgraph schema - finalDgraphSchema := fmt.Sprintf(`{ - "schema": [ - %s, - { - "predicate": "dgraph.cors", - "type": "string", - "list": true, - "index": true, - "tokenizer": [ - "exact" - ], - "upsert": true - }, - { - "predicate":"dgraph.drop.op", - "type":"string" - }, - { - "predicate":"dgraph.graphql.p_query", - "type":"string" - }, - { - "predicate":"dgraph.graphql.p_sha256hash", - "type":"string", - "index":true, - "tokenizer":["exact"] - }, - { - "predicate": "dgraph.graphql.schema", - "type": "string" - }, - { - "predicate": "dgraph.graphql.schema_created_at", - "type": "datetime" - }, - { - "predicate": "dgraph.graphql.schema_history", - "type": "string" - }, - { - "predicate": "dgraph.graphql.xid", - "type": "string", - "index": true, - "tokenizer": [ - "exact" - ], - "upsert": true - }, - { - "predicate": "dgraph.type", - "type": "string", - "index": true, - "tokenizer": [ - "exact" - ], - "list": true - } - ], - "types": [ - { - "fields": [ - { - "name": "A.b" - } - ], - "name": "A" - }, - { - "fields": [ - { - "name": "dgraph.graphql.schema" - },{ - "name": "dgraph.graphql.xid" - } - ], - "name": "dgraph.graphql" - }, - { - "fields": [ - { - "name": "dgraph.graphql.schema_history" - },{ - "name": "dgraph.graphql.schema_created_at" - } - ], - "name": "dgraph.graphql.history" - }, - { - "fields": [ - { - "name": "dgraph.graphql.p_query" - }, - { - "name": "dgraph.graphql.p_sha256hash" - } - ], - "name": "dgraph.graphql.persisted_query" - } - ] -}`, tcases[lastSuccessTcaseIdx].dgraphSchema) + // find final GraphQL & Dgraph schemas finalGraphQLSchema := tcases[lastSuccessTcaseIdx].graphQLSchema + finalDgraphPreds := tcases[lastSuccessTcaseIdx].dgraphSchema + finalDgraphTypes := ` + { + "fields": [ + { + "name": "A.b" + } + ], + "name": "A" + }` // now check that both the final GraphQL schema and Dgraph schema are the ones we expect - require.Equal(t, finalGraphQLSchema, getGQLSchemaRequireId(t, groupOneAdminServer)) - require.JSONEq(t, finalDgraphSchema, getDgraphSchema(t, dg)) + require.Equal(t, finalGraphQLSchema, common.AssertGetGQLSchemaRequireId(t, groupOneHTTP).Schema) + testutil.VerifySchema(t, dg, testutil.SchemaOptions{ + UserPreds: finalDgraphPreds, + UserTypes: finalDgraphTypes, + ExcludeAclSchema: true, + }) // now check that there is exactly one node for GraphQL schema in Dgraph, // and that contains the same schema as the one we expect @@ -380,12 +301,13 @@ func TestConcurrentSchemaUpdates(t *testing.T) { // TestIntrospectionQueryAfterDropAll make sure that Introspection query after drop_all doesn't give any internal error func TestIntrospectionQueryAfterDropAll(t *testing.T) { - // First Do the drop_all operation + oldCounter := common.RetryProbeGraphQL(t, groupOneHTTP).SchemaUpdateCounter + // Then, Do the drop_all operation dg, err := testutil.DgraphClient(groupOnegRPC) require.NoError(t, err) testutil.DropAll(t, dg) - // wait for a bit - time.Sleep(time.Second) + // wait for the schema update to reach the GraphQL layer + common.AssertSchemaUpdateCounterIncrement(t, groupOneHTTP, oldCounter) introspectionQuery := ` query{ @@ -400,7 +322,7 @@ func TestIntrospectionQueryAfterDropAll(t *testing.T) { } // On doing Introspection Query Now, We should get the Expected Error Message, not the Internal Error. - introspectionResult := introspect.ExecuteAsPost(t, groupOneServer) + introspectionResult := introspect.ExecuteAsPost(t, groupOneGraphQLServer) require.Len(t, introspectionResult.Errors, 1) gotErrorMessage := introspectionResult.Errors[0].Message expectedErrorMessage := "Not resolving __schema. There's no GraphQL schema in Dgraph. Use the /admin API to add a GraphQL schema" @@ -409,10 +331,11 @@ func TestIntrospectionQueryAfterDropAll(t *testing.T) { // TestUpdateGQLSchemaAfterDropAll makes sure that updating the GraphQL schema after drop_all works func TestUpdateGQLSchemaAfterDropAll(t *testing.T) { - updateGQLSchemaRequireNoErrors(t, ` - type A { - b: String! - }`, groupOneAdminServer) + common.SafelyUpdateGQLSchema(t, groupOneHTTP, ` + type A { + b: String! + }`, nil) + oldCounter := common.RetryProbeGraphQL(t, groupOneHTTP).SchemaUpdateCounter // now do drop_all dg, err := testutil.DgraphClient(groupOnegRPC) @@ -420,28 +343,28 @@ func TestUpdateGQLSchemaAfterDropAll(t *testing.T) { testutil.DropAll(t, dg) // need to wait a bit, because the update notification takes time to reach the alpha - time.Sleep(time.Second) + common.AssertSchemaUpdateCounterIncrement(t, groupOneHTTP, oldCounter) // now retrieving the GraphQL schema should report no schema - gqlSchema := getGQLSchemaRequireId(t, groupOneAdminServer) - require.Empty(t, gqlSchema) + require.Empty(t, common.AssertGetGQLSchemaRequireId(t, groupOneHTTP).Schema) // updating the schema now should work schema := ` type A { b: String! @id }` - updateGQLSchemaRequireNoErrors(t, schema, groupOneAdminServer) + common.SafelyUpdateGQLSchema(t, groupOneHTTP, schema, nil) // we should get the schema we expect - require.Equal(t, schema, getGQLSchemaRequireId(t, groupOneAdminServer)) + require.Equal(t, schema, common.AssertGetGQLSchemaRequireId(t, groupOneHTTP).Schema) } -// TestGQLSchemaAfterDropData checks whether if the schema still exists after drop_data +// TestGQLSchemaAfterDropData checks if the schema still exists after drop_data func TestGQLSchemaAfterDropData(t *testing.T) { schema := ` type A { b: String! }` - updateGQLSchemaRequireNoErrors(t, schema, groupOneAdminServer) + common.SafelyUpdateGQLSchema(t, groupOneHTTP, schema, nil) + oldCounter := common.RetryProbeGraphQL(t, groupOneHTTP).SchemaUpdateCounter // now do drop_data dg, err := testutil.DgraphClient(groupOnegRPC) @@ -450,9 +373,12 @@ func TestGQLSchemaAfterDropData(t *testing.T) { // lets wait a bit to be sure that the update notification has reached the alpha, // otherwise we are anyways gonna get the previous schema from the in-memory schema - time.Sleep(time.Second) + time.Sleep(5 * time.Second) + // drop_data should not increment the schema update counter + newCounter := common.RetryProbeGraphQL(t, groupOneHTTP).SchemaUpdateCounter + require.Equal(t, oldCounter, newCounter) // we should still get the schema we inserted earlier - require.Equal(t, schema, getGQLSchemaRequireId(t, groupOneAdminServer)) + require.Equal(t, schema, common.AssertGetGQLSchemaRequireId(t, groupOneHTTP).Schema) } @@ -473,21 +399,21 @@ func TestSchemaHistory(t *testing.T) { }`, } getResult := get.ExecuteAsPost(t, groupOneAdminServer) - require.Nil(t, getResult.Errors) + common.RequireNoGQLErrors(t, getResult) require.JSONEq(t, `{ "querySchemaHistory": [] }`, string(getResult.Data)) // Let's add an schema and expect the history in the history api. - updateGQLSchemaRequireNoErrors(t, ` + schema := ` type A { b: String! - }`, groupOneAdminServer) - time.Sleep(time.Second) + }` + common.SafelyUpdateGQLSchema(t, groupOneHTTP, schema, nil) getResult = get.ExecuteAsPost(t, groupOneAdminServer) - require.Nil(t, getResult.Errors) + common.RequireNoGQLErrors(t, getResult) type History struct { Schema string `json:"schema"` CreatedAt string `json:"created_at"` @@ -498,37 +424,36 @@ func TestSchemaHistory(t *testing.T) { history := schemaHistory{} require.NoError(t, json.Unmarshal(getResult.Data, &history)) require.Equal(t, int(1), len(history.QuerySchemaHistory)) - require.Equal(t, history.QuerySchemaHistory[0].Schema, "\n\ttype A {\n\t\tb: String!\n\t}") + require.Equal(t, history.QuerySchemaHistory[0].Schema, schema) - // Let's update the same schema. But we should not get the 2 history because, we - // are updating the same schema. - updateGQLSchemaRequireNoErrors(t, ` - type A { - b: String! - }`, groupOneAdminServer) - time.Sleep(time.Second) + // Let's update with the same schema. But we should not get the 2 history because, we + // are updating with the same schema. + common.AssertUpdateGQLSchemaSuccess(t, groupOneHTTP, schema, nil) getResult = get.ExecuteAsPost(t, groupOneAdminServer) - require.Nil(t, getResult.Errors) + common.RequireNoGQLErrors(t, getResult) history = schemaHistory{} require.NoError(t, json.Unmarshal(getResult.Data, &history)) require.Equal(t, int(1), len(history.QuerySchemaHistory)) - require.Equal(t, history.QuerySchemaHistory[0].Schema, "\n\ttype A {\n\t\tb: String!\n\t}") + require.Equal(t, history.QuerySchemaHistory[0].Schema, schema) + // this wait is necessary to make sure that the new schema is created atleast 1s after the old + // schema, ensuring that the new schema is reported first in the query. + time.Sleep(time.Second) // Let's update a new schema and check the history. - updateGQLSchemaRequireNoErrors(t, ` + newSchema := ` type B { b: String! - }`, groupOneAdminServer) - time.Sleep(time.Second) + }` + common.SafelyUpdateGQLSchema(t, groupOneHTTP, newSchema, nil) getResult = get.ExecuteAsPost(t, groupOneAdminServer) - require.Nil(t, getResult.Errors) + common.RequireNoGQLErrors(t, getResult) history = schemaHistory{} require.NoError(t, json.Unmarshal(getResult.Data, &history)) require.Equal(t, int(2), len(history.QuerySchemaHistory)) - require.Equal(t, history.QuerySchemaHistory[0].Schema, "\n\ttype B {\n\t\tb: String!\n\t}") - require.Equal(t, history.QuerySchemaHistory[1].Schema, "\n\ttype A {\n\t\tb: String!\n\t}") + require.Equal(t, newSchema, history.QuerySchemaHistory[0].Schema) + require.Equal(t, schema, history.QuerySchemaHistory[1].Schema) // Check offset working properly or not. get = &common.GraphQLParams{ @@ -540,27 +465,21 @@ func TestSchemaHistory(t *testing.T) { }`, } getResult = get.ExecuteAsPost(t, groupOneAdminServer) - require.Nil(t, getResult.Errors) + common.RequireNoGQLErrors(t, getResult) history = schemaHistory{} require.NoError(t, json.Unmarshal(getResult.Data, &history)) require.Equal(t, int(1), len(history.QuerySchemaHistory)) - require.Equal(t, history.QuerySchemaHistory[0].Schema, "\n\ttype A {\n\t\tb: String!\n\t}") + require.Equal(t, history.QuerySchemaHistory[0].Schema, schema) - // Let's drop eveything and see whether we getting empty results are not. + // Let's drop everything and see whether we get empty results or not. require.NoError(t, dg.Alter(context.Background(), &api.Operation{DropOp: api.Operation_DATA, RunInBackground: false})) getResult = get.ExecuteAsPost(t, groupOneAdminServer) - require.Nil(t, getResult.Errors) + common.RequireNoGQLErrors(t, getResult) require.JSONEq(t, `{ "querySchemaHistory": [] }`, string(getResult.Data)) } -// verifyEmptySchema verifies that the schema is not set in the GraphQL server. -func verifyEmptySchema(t *testing.T) { - schema := getGQLSchema(t, groupOneAdminServer) - require.Empty(t, schema.Schema) -} - func TestGQLSchemaValidate(t *testing.T) { testCases := []struct { schema string @@ -618,7 +537,7 @@ func TestGQLSchemaValidate(t *testing.T) { require.NoError(t, err) // Verify that we only validate the schema and not set it. - verifyEmptySchema(t) + require.Empty(t, common.AssertGetGQLSchema(t, groupOneHTTP).Schema) if tcase.valid { require.Equal(t, resp.StatusCode, http.StatusOK) @@ -642,34 +561,8 @@ func TestUpdateGQLSchemaFields(t *testing.T) { generatedSchema, err := ioutil.ReadFile("generatedSchema.graphql") require.NoError(t, err) - - req := &common.GraphQLParams{ - Query: `mutation updateGQLSchema($sch: String!) { - updateGQLSchema(input: { set: { schema: $sch }}) { - gqlSchema { - schema - generatedSchema - } - } - }`, - Variables: map[string]interface{}{"sch": schema}, - } - resp := req.ExecuteAsPost(t, groupOneAdminServer) - require.NotNil(t, resp) - require.Nilf(t, resp.Errors, "%s", resp.Errors) - - var updateResp struct { - UpdateGQLSchema struct { - GQLSchema struct { - Schema string - GeneratedSchema string - } - } - } - require.NoError(t, json.Unmarshal(resp.Data, &updateResp)) - - require.Equal(t, schema, updateResp.UpdateGQLSchema.GQLSchema.Schema) - require.Equal(t, string(generatedSchema), updateResp.UpdateGQLSchema.GQLSchema.GeneratedSchema) + require.Equal(t, string(generatedSchema), common.SafelyUpdateGQLSchema(t, groupOneHTTP, + schema, nil).GeneratedSchema) } func TestIntrospection(t *testing.T) { @@ -687,16 +580,16 @@ func TestIntrospection(t *testing.T) { type Dog implements Node { name: String }` - updateGQLSchemaRequireNoErrors(t, schema, groupOneAdminServer) + common.SafelyUpdateGQLSchema(t, groupOneHTTP, schema, nil) query, err := ioutil.ReadFile("../../schema/testdata/introspection/input/full_query.graphql") require.NoError(t, err) introspectionParams := &common.GraphQLParams{Query: string(query)} - resp := introspectionParams.ExecuteAsPost(t, groupOneServer) + resp := introspectionParams.ExecuteAsPost(t, groupOneGraphQLServer) // checking that there are no errors in the response, i.e., we always get some data in the // introspection response. - require.Nilf(t, resp.Errors, "%s", resp.Errors) + common.RequireNoGQLErrors(t, resp) require.NotEmpty(t, resp.Data) // TODO: we should actually compare data here, but there seems to be some issue with either the // introspection response or the JSON comparison. Needs deeper looking. @@ -708,7 +601,7 @@ func TestDeleteSchemaAndExport(t *testing.T) { type Person { name: String }` - schemaResp := updateGQLSchemaReturnSchema(t, schema, groupOneAdminServer) + schemaResp := common.SafelyUpdateGQLSchema(t, groupOneHTTP, schema, nil) // now delete it with S * * delete mutation dg, err := testutil.DgraphClient(groupOnegRPC) @@ -732,55 +625,13 @@ func TestDeleteSchemaAndExport(t *testing.T) { common.RequireNoGQLErrors(t, exportGqlResp) // applying a new schema should still work - newSchemaResp := updateGQLSchemaReturnSchema(t, schema, groupOneAdminServer) + newSchemaResp := common.AssertUpdateGQLSchemaSuccess(t, groupOneHTTP, schema, nil) // we can assert that the uid allocated to new schema isn't same as the uid for old schema require.NotEqual(t, schemaResp.Id, newSchemaResp.Id) } -func updateGQLSchema(t *testing.T, schema, url string) *common.GraphQLResponse { - var resp *common.GraphQLResponse - for i := 0; i < 10; i++ { - req := &common.GraphQLParams{ - Query: `mutation updateGQLSchema($sch: String!) { - updateGQLSchema(input: { set: { schema: $sch }}) { - gqlSchema { - id - schema - } - } - }`, - Variables: map[string]interface{}{"sch": schema}, - } - resp = req.ExecuteAsPost(t, url) - if resp == nil || strings.Contains(resp.Errors.Error(), "server not ready") { - time.Sleep(time.Second) - continue - } - } - require.NotNil(t, resp) - return resp -} - -func updateGQLSchemaRequireNoErrors(t *testing.T, schema, url string) { - resp := updateGQLSchema(t, schema, url) - requireNoErrors(t, resp) -} - -func updateGQLSchemaReturnSchema(t *testing.T, schema, url string) gqlSchema { - resp := updateGQLSchema(t, schema, url) - require.Nil(t, resp.Errors) - - var updateResp struct { - UpdateGQLSchema struct { - GqlSchema gqlSchema - } - } - require.NoError(t, json.Unmarshal(resp.Data, &updateResp)) - return updateResp.UpdateGQLSchema.GqlSchema -} - -func updateGQLSchemaConcurrent(t *testing.T, schema, url string) bool { - res := updateGQLSchema(t, schema, url) +func updateGQLSchemaConcurrent(t *testing.T, schema, authority string) bool { + res := common.RetryUpdateGQLSchema(t, authority, schema, nil) err := res.Errors.Error() require.NotContains(t, err, worker.ErrMultipleGraphQLSchemaNodes) require.NotContains(t, err, worker.ErrGraphQLSchemaAlterFailed) @@ -788,57 +639,6 @@ func updateGQLSchemaConcurrent(t *testing.T, schema, url string) bool { return res.Errors == nil } -type gqlSchema struct { - Id string - Schema string -} - -func getGQLSchema(t *testing.T, url string) gqlSchema { - get := &common.GraphQLParams{ - Query: `query { - getGQLSchema { - id - schema - } - }`, - } - getResult := get.ExecuteAsPost(t, url) - require.Nil(t, getResult.Errors) - - var resp struct { - GetGQLSchema gqlSchema - } - require.NoError(t, json.Unmarshal(getResult.Data, &resp)) - - return resp.GetGQLSchema -} - -func getGQLSchemaRequireId(t *testing.T, url string) string { - schema := getGQLSchema(t, url) - require.NotEmpty(t, schema.Id, "Got empty ID in getGQLSchema") - return schema.Schema -} - -func getDgraphSchema(t *testing.T, dg *dgo.Dgraph) string { - resp, err := dg.NewReadOnlyTxn().Query(context.Background(), "schema {}") - require.NoError(t, err) - - return string(resp.GetJson()) -} - -func runIntrospectWithRetryIfNecessary(t *testing.T, query *common.GraphQLParams, url string) *common.GraphQLResponse { - var response *common.GraphQLResponse - for i := 0; i < 10; i++ { - response = query.ExecuteAsPost(t, url) - if response.Errors == nil || !strings.Contains(response.Errors.Error(), "There's no GraphQL schema in Dgraph.") { - return response - } - time.Sleep(2 * time.Second) - } - - return response -} - func TestMain(m *testing.M) { err := common.CheckGraphQLStarted(common.GraphqlAdminURL) if err != nil { diff --git a/graphql/e2e/subscription/subscription_test.go b/graphql/e2e/subscription/subscription_test.go index 7ac9b7154e9..6812b01324f 100644 --- a/graphql/e2e/subscription/subscription_test.go +++ b/graphql/e2e/subscription/subscription_test.go @@ -72,30 +72,19 @@ const ( } # Dgraph.Authorization {"VerificationKey":"secret","Header":"Authorization","Namespace":"https://dgraph.io","Algo":"HS256"} ` - subExp = 3 * time.Second + subExp = 3 * time.Second + pollInterval = time.Second ) func TestSubscription(t *testing.T) { - dg, err := testutil.DgraphClient(common.AlphagRPC) + dg, err := testutil.DgraphClient(common.Alpha1gRPC) require.NoError(t, err) testutil.DropAll(t, dg) var subscriptionResp common.GraphQLResponse - add := &common.GraphQLParams{ - Query: `mutation updateGQLSchema($sch: String!) { - updateGQLSchema(input: { set: { schema: $sch }}) { - gqlSchema { - schema - } - } - }`, - Variables: map[string]interface{}{"sch": sch}, - } - addResult := add.ExecuteAsPost(t, common.GraphqlAdminURL) - require.Nil(t, addResult.Errors) - time.Sleep(time.Second * 2) + common.SafelyUpdateGQLSchemaOnAlpha1(t, sch) - add = &common.GraphQLParams{ + add := &common.GraphQLParams{ Query: `mutation { addProduct(input: [ { name: "sanitizer"} @@ -107,9 +96,9 @@ func TestSubscription(t *testing.T) { } }`, } - addResult = add.ExecuteAsPost(t, common.GraphqlURL) - require.Nil(t, addResult.Errors) - time.Sleep(time.Second) + addResult := add.ExecuteAsPost(t, common.GraphqlURL) + common.RequireNoGQLErrors(t, addResult) + time.Sleep(pollInterval) subscriptionClient, err := common.NewGraphQLSubscription(subscriptionEndpoint, &schema.Request{ Query: `subscription{ @@ -125,7 +114,7 @@ func TestSubscription(t *testing.T) { touchedUidskey := "touched_uids" err = json.Unmarshal(res, &subscriptionResp) require.NoError(t, err) - require.Nil(t, subscriptionResp.Errors) + common.RequireNoGQLErrors(t, &subscriptionResp) require.JSONEq(t, `{"queryProduct":[{"name":"sanitizer"}]}`, string(subscriptionResp.Data)) require.Contains(t, subscriptionResp.Extensions, touchedUidskey) @@ -143,8 +132,8 @@ func TestSubscription(t *testing.T) { `, } addResult = add.ExecuteAsPost(t, common.GraphqlURL) - require.Nil(t, addResult.Errors) - time.Sleep(time.Second) + common.RequireNoGQLErrors(t, addResult) + time.Sleep(pollInterval) res, err = subscriptionClient.RecvMsg() require.NoError(t, err) @@ -154,7 +143,7 @@ func TestSubscription(t *testing.T) { subscriptionResp = common.GraphQLResponse{} err = json.Unmarshal(res, &subscriptionResp) require.NoError(t, err) - require.Nil(t, subscriptionResp.Errors) + common.RequireNoGQLErrors(t, &subscriptionResp) // Check the latest update. require.JSONEq(t, `{"queryProduct":[{"name":"mask"}]}`, string(subscriptionResp.Data)) @@ -162,42 +151,19 @@ func TestSubscription(t *testing.T) { require.Greater(t, int(subscriptionResp.Extensions[touchedUidskey].(float64)), 0) // Change schema to terminate subscription.. - add = &common.GraphQLParams{ - Query: `mutation updateGQLSchema($sch: String!) { - updateGQLSchema(input: { set: { schema: $sch }}) { - gqlSchema { - schema - } - } - }`, - Variables: map[string]interface{}{"sch": schAuth}, - } - addResult = add.ExecuteAsPost(t, common.GraphqlAdminURL) - require.Nil(t, addResult.Errors) - time.Sleep(time.Second) + common.SafelyUpdateGQLSchemaOnAlpha1(t, schAuth) + time.Sleep(pollInterval) res, err = subscriptionClient.RecvMsg() require.NoError(t, err) require.Nil(t, res) } func TestSubscriptionAuth(t *testing.T) { - dg, err := testutil.DgraphClient(common.AlphagRPC) + dg, err := testutil.DgraphClient(common.Alpha1gRPC) require.NoError(t, err) testutil.DropAll(t, dg) - add := &common.GraphQLParams{ - Query: `mutation updateGQLSchema($sch: String!) { - updateGQLSchema(input: { set: { schema: $sch }}) { - gqlSchema { - schema - } - } - }`, - Variables: map[string]interface{}{"sch": schAuth}, - } - addResult := add.ExecuteAsPost(t, common.GraphqlAdminURL) - require.Nil(t, addResult.Errors) - time.Sleep(time.Second * 2) + common.SafelyUpdateGQLSchemaOnAlpha1(t, schAuth) metaInfo := &testutil.AuthMeta{ PublicKey: "secret", @@ -210,7 +176,7 @@ func TestSubscriptionAuth(t *testing.T) { "ROLE": "USER", } - add = &common.GraphQLParams{ + add := &common.GraphQLParams{ Query: `mutation{ addTodo(input: [ {text : "GraphQL is exciting!!", @@ -225,9 +191,9 @@ func TestSubscriptionAuth(t *testing.T) { }`, } - addResult = add.ExecuteAsPost(t, common.GraphqlURL) - require.Nil(t, addResult.Errors) - time.Sleep(time.Second) + addResult := add.ExecuteAsPost(t, common.GraphqlURL) + common.RequireNoGQLErrors(t, addResult) + time.Sleep(pollInterval) jwtToken, err := metaInfo.GetSignedToken("secret", subExp) require.NoError(t, err) @@ -250,7 +216,7 @@ func TestSubscriptionAuth(t *testing.T) { err = json.Unmarshal(res, &resp) require.NoError(t, err) - require.Nil(t, resp.Errors) + common.RequireNoGQLErrors(t, &resp) require.JSONEq(t, `{"queryTodo":[{"owner":"jatin","text":"GraphQL is exciting!!"}]}`, string(resp.Data)) @@ -271,7 +237,7 @@ func TestSubscriptionAuth(t *testing.T) { }`, } addResult = add.ExecuteAsPost(t, common.GraphqlURL) - require.Nil(t, addResult.Errors) + common.RequireNoGQLErrors(t, addResult) // Add another TODO for jatin which we should get in the latest update. add = &common.GraphQLParams{ @@ -290,15 +256,15 @@ func TestSubscriptionAuth(t *testing.T) { } addResult = add.ExecuteAsPost(t, common.GraphqlURL) - require.Nil(t, addResult.Errors) - time.Sleep(time.Second) + common.RequireNoGQLErrors(t, addResult) + time.Sleep(pollInterval) res, err = subscriptionClient.RecvMsg() require.NoError(t, err) err = json.Unmarshal(res, &resp) require.NoError(t, err) - require.Nil(t, resp.Errors) + common.RequireNoGQLErrors(t, &resp) require.JSONEq(t, `{"queryTodo": [ { "owner": "jatin", @@ -314,23 +280,11 @@ func TestSubscriptionAuth(t *testing.T) { } func TestSubscriptionWithAuthShouldExpireWithJWT(t *testing.T) { - dg, err := testutil.DgraphClient(common.AlphagRPC) + dg, err := testutil.DgraphClient(common.Alpha1gRPC) require.NoError(t, err) testutil.DropAll(t, dg) - add := &common.GraphQLParams{ - Query: `mutation updateGQLSchema($sch: String!) { - updateGQLSchema(input: { set: { schema: $sch }}) { - gqlSchema { - schema - } - } - }`, - Variables: map[string]interface{}{"sch": schAuth}, - } - addResult := add.ExecuteAsPost(t, common.GraphqlAdminURL) - require.Nil(t, addResult.Errors) - time.Sleep(time.Second * 2) + common.SafelyUpdateGQLSchemaOnAlpha1(t, schAuth) metaInfo := &testutil.AuthMeta{ PublicKey: "secret", @@ -343,7 +297,7 @@ func TestSubscriptionWithAuthShouldExpireWithJWT(t *testing.T) { "ROLE": "USER", } - add = &common.GraphQLParams{ + add := &common.GraphQLParams{ Query: `mutation{ addTodo(input: [ {text : "GraphQL is exciting!!", @@ -358,9 +312,9 @@ func TestSubscriptionWithAuthShouldExpireWithJWT(t *testing.T) { }`, } - addResult = add.ExecuteAsPost(t, common.GraphqlURL) - require.Nil(t, addResult.Errors) - time.Sleep(time.Second) + addResult := add.ExecuteAsPost(t, common.GraphqlURL) + common.RequireNoGQLErrors(t, addResult) + time.Sleep(pollInterval) jwtToken, err := metaInfo.GetSignedToken("secret", subExp) require.NoError(t, err) @@ -384,7 +338,7 @@ func TestSubscriptionWithAuthShouldExpireWithJWT(t *testing.T) { err = json.Unmarshal(res, &resp) require.NoError(t, err) - require.Nil(t, resp.Errors) + common.RequireNoGQLErrors(t, &resp) require.JSONEq(t, `{"queryTodo":[{"owner":"bob","text":"GraphQL is exciting!!"}]}`, string(resp.Data)) @@ -409,8 +363,8 @@ func TestSubscriptionWithAuthShouldExpireWithJWT(t *testing.T) { } addResult = add.ExecuteAsPost(t, common.GraphqlURL) - require.Nil(t, addResult.Errors) - time.Sleep(time.Second) + common.RequireNoGQLErrors(t, addResult) + time.Sleep(pollInterval) res, err = subscriptionClient.RecvMsg() require.NoError(t, err) @@ -420,23 +374,11 @@ func TestSubscriptionWithAuthShouldExpireWithJWT(t *testing.T) { } func TestSubscriptionAuthWithoutExpiry(t *testing.T) { - dg, err := testutil.DgraphClient(common.AlphagRPC) + dg, err := testutil.DgraphClient(common.Alpha1gRPC) require.NoError(t, err) testutil.DropAll(t, dg) - add := &common.GraphQLParams{ - Query: `mutation updateGQLSchema($sch: String!) { - updateGQLSchema(input: { set: { schema: $sch }}) { - gqlSchema { - schema - } - } - }`, - Variables: map[string]interface{}{"sch": schAuth}, - } - addResult := add.ExecuteAsPost(t, common.GraphqlAdminURL) - require.Nil(t, addResult.Errors) - time.Sleep(time.Second * 2) + common.SafelyUpdateGQLSchemaOnAlpha1(t, schAuth) metaInfo := &testutil.AuthMeta{ PublicKey: "secret", @@ -449,7 +391,7 @@ func TestSubscriptionAuthWithoutExpiry(t *testing.T) { "ROLE": "USER", } - add = &common.GraphQLParams{ + add := &common.GraphQLParams{ Query: `mutation{ addTodo(input: [ {text : "GraphQL is exciting!!", @@ -464,8 +406,8 @@ func TestSubscriptionAuthWithoutExpiry(t *testing.T) { }`, } - addResult = add.ExecuteAsPost(t, common.GraphqlURL) - require.Nil(t, addResult.Errors) + addResult := add.ExecuteAsPost(t, common.GraphqlURL) + common.RequireNoGQLErrors(t, addResult) jwtToken, err := metaInfo.GetSignedToken("secret", -1) require.NoError(t, err) @@ -488,29 +430,17 @@ func TestSubscriptionAuthWithoutExpiry(t *testing.T) { err = json.Unmarshal(res, &resp) require.NoError(t, err) - require.Nil(t, resp.Errors) + common.RequireNoGQLErrors(t, &resp) require.JSONEq(t, `{"queryTodo":[{"owner":"jatin","text":"GraphQL is exciting!!"}]}`, string(resp.Data)) } func TestSubscriptionAuth_SameQueryAndClaimsButDifferentExpiry_ShouldExpireIndependently(t *testing.T) { - dg, err := testutil.DgraphClient(common.AlphagRPC) + dg, err := testutil.DgraphClient(common.Alpha1gRPC) require.NoError(t, err) testutil.DropAll(t, dg) - add := &common.GraphQLParams{ - Query: `mutation updateGQLSchema($sch: String!) { - updateGQLSchema(input: { set: { schema: $sch }}) { - gqlSchema { - schema - } - } - }`, - Variables: map[string]interface{}{"sch": schAuth}, - } - addResult := add.ExecuteAsPost(t, common.GraphqlAdminURL) - require.Nil(t, addResult.Errors) - time.Sleep(time.Second * 2) + common.SafelyUpdateGQLSchemaOnAlpha1(t, schAuth) metaInfo := &testutil.AuthMeta{ PublicKey: "secret", @@ -523,7 +453,7 @@ func TestSubscriptionAuth_SameQueryAndClaimsButDifferentExpiry_ShouldExpireIndep "ROLE": "USER", } - add = &common.GraphQLParams{ + add := &common.GraphQLParams{ Query: `mutation{ addTodo(input: [ {text : "GraphQL is exciting!!", @@ -538,9 +468,9 @@ func TestSubscriptionAuth_SameQueryAndClaimsButDifferentExpiry_ShouldExpireIndep }`, } - addResult = add.ExecuteAsPost(t, common.GraphqlURL) - require.Nil(t, addResult.Errors) - time.Sleep(time.Second) + addResult := add.ExecuteAsPost(t, common.GraphqlURL) + common.RequireNoGQLErrors(t, addResult) + time.Sleep(pollInterval) jwtToken, err := metaInfo.GetSignedToken("secret", subExp) require.NoError(t, err) @@ -563,7 +493,7 @@ func TestSubscriptionAuth_SameQueryAndClaimsButDifferentExpiry_ShouldExpireIndep var resp common.GraphQLResponse err = json.Unmarshal(res, &resp) require.NoError(t, err) - require.Nil(t, resp.Errors) + common.RequireNoGQLErrors(t, &resp) require.JSONEq(t, `{"queryTodo":[{"owner":"jatin","text":"GraphQL is exciting!!"}]}`, string(resp.Data)) @@ -585,7 +515,7 @@ func TestSubscriptionAuth_SameQueryAndClaimsButDifferentExpiry_ShouldExpireIndep require.NoError(t, err) err = json.Unmarshal(res, &resp) require.NoError(t, err) - require.Nil(t, resp.Errors) + common.RequireNoGQLErrors(t, &resp) require.JSONEq(t, `{"queryTodo":[{"owner":"jatin","text":"GraphQL is exciting!!"}]}`, string(resp.Data)) @@ -608,8 +538,8 @@ func TestSubscriptionAuth_SameQueryAndClaimsButDifferentExpiry_ShouldExpireIndep }`, } addResult = add.ExecuteAsPost(t, common.GraphqlURL) - require.Nil(t, addResult.Errors) - time.Sleep(time.Second) + common.RequireNoGQLErrors(t, addResult) + time.Sleep(pollInterval) res, err = subscriptionClient.RecvMsg() require.NoError(t, err) @@ -619,7 +549,7 @@ func TestSubscriptionAuth_SameQueryAndClaimsButDifferentExpiry_ShouldExpireIndep require.NoError(t, err) err = json.Unmarshal(res, &resp) require.NoError(t, err) - require.Nil(t, resp.Errors) + common.RequireNoGQLErrors(t, &resp) // 2nd one still running and should get the update require.JSONEq(t, `{"queryTodo": [ { @@ -649,8 +579,8 @@ func TestSubscriptionAuth_SameQueryAndClaimsButDifferentExpiry_ShouldExpireIndep }`, } addResult = add.ExecuteAsPost(t, common.GraphqlURL) - require.Nil(t, addResult.Errors) - time.Sleep(time.Second) + common.RequireNoGQLErrors(t, addResult) + time.Sleep(pollInterval) // 2nd subscription should get the empty response as subscription has expired. res, err = subscriptionClient1.RecvMsg() @@ -659,23 +589,11 @@ func TestSubscriptionAuth_SameQueryAndClaimsButDifferentExpiry_ShouldExpireIndep } func TestSubscriptionAuth_SameQueryDifferentClaimsAndExpiry_ShouldExpireIndependently(t *testing.T) { - dg, err := testutil.DgraphClient(common.AlphagRPC) + dg, err := testutil.DgraphClient(common.Alpha1gRPC) require.NoError(t, err) testutil.DropAll(t, dg) - add := &common.GraphQLParams{ - Query: `mutation updateGQLSchema($sch: String!) { - updateGQLSchema(input: { set: { schema: $sch }}) { - gqlSchema { - schema - } - } - }`, - Variables: map[string]interface{}{"sch": schAuth}, - } - addResult := add.ExecuteAsPost(t, common.GraphqlAdminURL) - require.Nil(t, addResult.Errors) - time.Sleep(time.Second * 2) + common.SafelyUpdateGQLSchemaOnAlpha1(t, schAuth) metaInfo := &testutil.AuthMeta{ PublicKey: "secret", @@ -688,7 +606,7 @@ func TestSubscriptionAuth_SameQueryDifferentClaimsAndExpiry_ShouldExpireIndepend "ROLE": "USER", } // for user jatin - add = &common.GraphQLParams{ + add := &common.GraphQLParams{ Query: `mutation{ addTodo(input: [ {text : "GraphQL is exciting!!", @@ -703,9 +621,9 @@ func TestSubscriptionAuth_SameQueryDifferentClaimsAndExpiry_ShouldExpireIndepend }`, } - addResult = add.ExecuteAsPost(t, common.GraphqlURL) - require.Nil(t, addResult.Errors) - time.Sleep(time.Second) + addResult := add.ExecuteAsPost(t, common.GraphqlURL) + common.RequireNoGQLErrors(t, addResult) + time.Sleep(pollInterval) jwtToken, err := metaInfo.GetSignedToken("secret", subExp) require.NoError(t, err) @@ -729,7 +647,7 @@ func TestSubscriptionAuth_SameQueryDifferentClaimsAndExpiry_ShouldExpireIndepend err = json.Unmarshal(res, &resp) require.NoError(t, err) - require.Nil(t, resp.Errors) + common.RequireNoGQLErrors(t, &resp) require.JSONEq(t, `{"queryTodo":[{"owner":"jatin","text":"GraphQL is exciting!!"}]}`, string(resp.Data)) @@ -750,8 +668,8 @@ func TestSubscriptionAuth_SameQueryDifferentClaimsAndExpiry_ShouldExpireIndepend } addResult = add.ExecuteAsPost(t, common.GraphqlURL) - require.Nil(t, addResult.Errors) - time.Sleep(time.Second) + common.RequireNoGQLErrors(t, addResult) + time.Sleep(pollInterval) // 2nd subscription metaInfo.AuthVars["USER"] = "pawan" @@ -774,7 +692,7 @@ func TestSubscriptionAuth_SameQueryDifferentClaimsAndExpiry_ShouldExpireIndepend err = json.Unmarshal(res, &resp) require.NoError(t, err) - require.Nil(t, resp.Errors) + common.RequireNoGQLErrors(t, &resp) require.JSONEq(t, `{"queryTodo":[{"owner":"pawan","text":"GraphQL is exciting!!"}]}`, string(resp.Data)) @@ -797,8 +715,8 @@ func TestSubscriptionAuth_SameQueryDifferentClaimsAndExpiry_ShouldExpireIndepend }`, } addResult = add.ExecuteAsPost(t, common.GraphqlURL) - require.Nil(t, addResult.Errors) - time.Sleep(time.Second) + common.RequireNoGQLErrors(t, addResult) + time.Sleep(pollInterval) // 1st subscription should get the empty response as subscription has expired res, err = subscriptionClient.RecvMsg() require.NoError(t, err) @@ -820,14 +738,14 @@ func TestSubscriptionAuth_SameQueryDifferentClaimsAndExpiry_ShouldExpireIndepend }`, } addResult = add.ExecuteAsPost(t, common.GraphqlURL) - require.Nil(t, addResult.Errors) - time.Sleep(time.Second) + common.RequireNoGQLErrors(t, addResult) + time.Sleep(pollInterval) res, err = subscriptionClient1.RecvMsg() require.NoError(t, err) err = json.Unmarshal(res, &resp) require.NoError(t, err) - require.Nil(t, resp.Errors) + common.RequireNoGQLErrors(t, &resp) // 2nd one still running and should get the update require.JSONEq(t, `{"queryTodo": [ { @@ -859,8 +777,8 @@ func TestSubscriptionAuth_SameQueryDifferentClaimsAndExpiry_ShouldExpireIndepend } addResult = add.ExecuteAsPost(t, common.GraphqlURL) - require.Nil(t, addResult.Errors) - time.Sleep(time.Second) + common.RequireNoGQLErrors(t, addResult) + time.Sleep(pollInterval) // 2nd subscription should get the empty response as subscription has expired res, err = subscriptionClient1.RecvMsg() @@ -869,23 +787,11 @@ func TestSubscriptionAuth_SameQueryDifferentClaimsAndExpiry_ShouldExpireIndepend } func TestSubscriptionAuthHeaderCaseInsensitive(t *testing.T) { - dg, err := testutil.DgraphClient(common.AlphagRPC) + dg, err := testutil.DgraphClient(common.Alpha1gRPC) require.NoError(t, err) testutil.DropAll(t, dg) - add := &common.GraphQLParams{ - Query: `mutation updateGQLSchema($sch: String!) { - updateGQLSchema(input: { set: { schema: $sch }}) { - gqlSchema { - schema - } - } - }`, - Variables: map[string]interface{}{"sch": schAuth}, - } - addResult := add.ExecuteAsPost(t, common.GraphqlAdminURL) - require.Nil(t, addResult.Errors) - time.Sleep(time.Second * 2) + common.SafelyUpdateGQLSchemaOnAlpha1(t, schAuth) metaInfo := &testutil.AuthMeta{ PublicKey: "secret", @@ -898,7 +804,7 @@ func TestSubscriptionAuthHeaderCaseInsensitive(t *testing.T) { "ROLE": "USER", } - add = &common.GraphQLParams{ + add := &common.GraphQLParams{ Query: `mutation{ addTodo(input: [ {text : "GraphQL is exciting!!", @@ -913,8 +819,8 @@ func TestSubscriptionAuthHeaderCaseInsensitive(t *testing.T) { }`, } - addResult = add.ExecuteAsPost(t, common.GraphqlURL) - require.Nil(t, addResult.Errors) + addResult := add.ExecuteAsPost(t, common.GraphqlURL) + common.RequireNoGQLErrors(t, addResult) jwtToken, err := metaInfo.GetSignedToken("secret", -1) require.NoError(t, err) @@ -937,7 +843,7 @@ func TestSubscriptionAuthHeaderCaseInsensitive(t *testing.T) { err = json.Unmarshal(res, &resp) require.NoError(t, err) - require.Nil(t, resp.Errors) + common.RequireNoGQLErrors(t, &resp) require.JSONEq(t, `{"queryTodo":[{"owner":"jatin","text":"GraphQL is exciting!!"}]}`, string(resp.Data)) @@ -946,24 +852,12 @@ func TestSubscriptionAuthHeaderCaseInsensitive(t *testing.T) { } func TestSubscriptionAuth_MultiSubscriptionResponses(t *testing.T) { - dg, err := testutil.DgraphClient(common.AlphagRPC) + dg, err := testutil.DgraphClient(common.Alpha1gRPC) require.NoError(t, err) testutil.DropAll(t, dg) // Upload schema - add := &common.GraphQLParams{ - Query: `mutation updateGQLSchema($sch: String!) { - updateGQLSchema(input: { set: { schema: $sch }}) { - gqlSchema { - schema - } - } - }`, - Variables: map[string]interface{}{"sch": schAuth}, - } - addResult := add.ExecuteAsPost(t, common.GraphqlAdminURL) - require.Nil(t, addResult.Errors) - time.Sleep(time.Second * 2) + common.SafelyUpdateGQLSchemaOnAlpha1(t, schAuth) metaInfo := &testutil.AuthMeta{ PublicKey: "secret", @@ -998,12 +892,12 @@ func TestSubscriptionAuth_MultiSubscriptionResponses(t *testing.T) { err = json.Unmarshal(res, &resp) require.NoError(t, err) - require.Nil(t, resp.Errors) + common.RequireNoGQLErrors(t, &resp) require.JSONEq(t, `{"queryTodo":[]}`, string(resp.Data)) - // Terminate subscription and wait for 1 second before starting new subscription + // Terminate subscription and wait for poll interval before starting new subscription subscriptionClient.Terminate() - time.Sleep(time.Second) + time.Sleep(pollInterval) jwtToken, err = metaInfo.GetSignedToken("secret", 3*time.Second) require.NoError(t, err) @@ -1026,11 +920,11 @@ func TestSubscriptionAuth_MultiSubscriptionResponses(t *testing.T) { err = json.Unmarshal(res, &resp) require.NoError(t, err) - require.Nil(t, resp.Errors) + common.RequireNoGQLErrors(t, &resp) require.JSONEq(t, `{"queryTodo":[]}`, string(resp.Data)) - add = &common.GraphQLParams{ + add := &common.GraphQLParams{ Query: `mutation{ addTodo(input: [ {text : "GraphQL is exciting!!", @@ -1045,9 +939,9 @@ func TestSubscriptionAuth_MultiSubscriptionResponses(t *testing.T) { }`, } - addResult = add.ExecuteAsPost(t, common.GraphqlURL) - require.Nil(t, addResult.Errors) - time.Sleep(time.Second) + addResult := add.ExecuteAsPost(t, common.GraphqlURL) + common.RequireNoGQLErrors(t, addResult) + time.Sleep(pollInterval) // 1st response res, err = subscriptionClient1.RecvMsg() @@ -1055,7 +949,7 @@ func TestSubscriptionAuth_MultiSubscriptionResponses(t *testing.T) { err = json.Unmarshal(res, &resp) require.NoError(t, err) - require.Nil(t, resp.Errors) + common.RequireNoGQLErrors(t, &resp) require.JSONEq(t, `{"queryTodo":[{"owner":"jatin","text":"GraphQL is exciting!!"}]}`, string(resp.Data)) diff --git a/testutil/client.go b/testutil/client.go index c2c56118708..5c5608ae063 100644 --- a/testutil/client.go +++ b/testutil/client.go @@ -34,6 +34,8 @@ import ( "testing" "time" + "github.com/dgraph-io/dgraph/gql" + "github.com/dgraph-io/dgo/v200" "github.com/dgraph-io/dgo/v200/protos/api" "github.com/dgraph-io/dgraph/x" @@ -463,6 +465,11 @@ func AssignUids(num uint64) error { return err } +func RequireUid(t *testing.T, uid string) { + _, err := gql.ParseUid(uid) + require.NoErrorf(t, err, "expecting a uid, got: %s", uid) +} + func CheckForGraphQLEndpointToReady(t *testing.T) error { var err error retries := 6 diff --git a/testutil/graphql.go b/testutil/graphql.go index 9040fe5039b..152583a281f 100644 --- a/testutil/graphql.go +++ b/testutil/graphql.go @@ -225,32 +225,28 @@ func (a *AuthMeta) AddClaimsToContext(ctx context.Context) (context.Context, err } func AppendAuthInfo(schema []byte, algo, publicKeyFile string, closedByDefault bool) ([]byte, error) { - authInfo := `# Dgraph.Authorization {"VerificationKey":"secretkey","Header":"X-Test-Auth","Namespace":"https://xyz.io/jwt/claims","Algo":"HS256","Audience":["aud1","63do0q16n6ebjgkumu05kkeian","aud5"],"ClosedByDefault":%s}` - if algo == "HS256" { - if closedByDefault { - authInfo = fmt.Sprintf(authInfo, "true") - } else { - authInfo = fmt.Sprintf(authInfo, "false") - } - return append(schema, []byte(authInfo)...), nil - } + authInfo := `# Dgraph.Authorization {"VerificationKey":"%s","Header":"X-Test-Auth","Namespace":"https://xyz.io/jwt/claims","Algo":"HS256","Audience":["aud1","63do0q16n6ebjgkumu05kkeian","aud5"],"ClosedByDefault":%s}` - if algo != "RS256" { - return schema, nil + closedByDefaultStr := "false" + if closedByDefault { + closedByDefaultStr = "true" } - _, err := ioutil.ReadFile(publicKeyFile) - if err != nil { - return nil, err + var verificationKey string + switch algo { + case "HS256": + verificationKey = "secretkey" + case "RS256": + keyData, err := ioutil.ReadFile(publicKeyFile) + if err != nil { + return nil, err + } + // Replacing ASCII newline with "\n" as the authorization information in the schema + // should be present in a single line. + verificationKey = string(bytes.ReplaceAll(keyData, []byte{10}, []byte{92, 110})) } - // Replacing ASCII newline with "\n" as the authorization information in the schema should be - // present in a single line. - if closedByDefault { - authInfo = fmt.Sprintf(authInfo, "true") - } else { - authInfo = fmt.Sprintf(authInfo, "false") - } + authInfo = fmt.Sprintf(authInfo, verificationKey, closedByDefaultStr) return append(schema, []byte(authInfo)...), nil } diff --git a/testutil/schema.go b/testutil/schema.go index 6def29cb608..e1aaf506619 100644 --- a/testutil/schema.go +++ b/testutil/schema.go @@ -132,7 +132,7 @@ func GetFullSchemaHTTPResponse(opts SchemaOptions) string { // VerifySchema verifies that the full schema generated using user provided predicates and types is // same as the response of the schema{} query. func VerifySchema(t *testing.T, dg *dgo.Dgraph, opts SchemaOptions) { - resp, err := dg.NewTxn().Query(context.Background(), `schema {}`) + resp, err := dg.NewReadOnlyTxn().Query(context.Background(), `schema {}`) require.NoError(t, err) CompareJSON(t, GetFullSchemaJSON(opts), string(resp.GetJson()))