github.com/dgraph-io/dgraph@v1.2.8/graphql/resolve/mutation_test.go (about) 1 /* 2 * Copyright 2019 Dgraph Labs, Inc. and Contributors 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package resolve 18 19 import ( 20 "encoding/json" 21 "io/ioutil" 22 "strings" 23 "testing" 24 25 "github.com/dgraph-io/dgraph/graphql/dgraph" 26 "github.com/dgraph-io/dgraph/graphql/schema" 27 "github.com/dgraph-io/dgraph/graphql/test" 28 "github.com/dgraph-io/dgraph/x" 29 "github.com/stretchr/testify/require" 30 "gopkg.in/yaml.v2" 31 ) 32 33 // Tests showing that GraphQL mutations -> Dgraph mutations 34 // is working as expected. 35 // 36 // Note: this doesn't include GQL validation errors! The rewriting code assumes 37 // it's rewriting a mutation that's valid (with valid variables) for the schema. 38 // So can't test GQL errors here - that's integration testing on the pipeline to 39 // ensure that those errors get caught before they reach rewriting. 40 41 type testCase struct { 42 Name string 43 GQLMutation string 44 GQLVariables string 45 Explanation string 46 DGMutations []*dgraphMutation 47 DGQuery string 48 Error *x.GqlError 49 ValidationError *x.GqlError 50 } 51 52 type dgraphMutation struct { 53 SetJSON string 54 DeleteJSON string 55 Cond string 56 } 57 58 func TestMutationRewriting(t *testing.T) { 59 t.Run("Validate Mutations", func(t *testing.T) { 60 mutationValidation(t, "validate_mutation_test.yaml", NewAddRewriter) 61 }) 62 t.Run("Add Mutation Rewriting", func(t *testing.T) { 63 mutationRewriting(t, "add_mutation_test.yaml", NewAddRewriter) 64 }) 65 t.Run("Update Mutation Rewriting", func(t *testing.T) { 66 mutationRewriting(t, "update_mutation_test.yaml", NewUpdateRewriter) 67 }) 68 t.Run("Delete Mutation Rewriting", func(t *testing.T) { 69 mutationRewriting(t, "delete_mutation_test.yaml", NewDeleteRewriter) 70 }) 71 } 72 73 func mutationValidation(t *testing.T, file string, rewriterFactory func() MutationRewriter) { 74 b, err := ioutil.ReadFile(file) 75 require.NoError(t, err, "Unable to read test file") 76 77 var tests []testCase 78 err = yaml.Unmarshal(b, &tests) 79 require.NoError(t, err, "Unable to unmarshal tests to yaml.") 80 81 gqlSchema := test.LoadSchemaFromFile(t, "schema.graphql") 82 83 for _, tcase := range tests { 84 t.Run(tcase.Name, func(t *testing.T) { 85 // -- Arrange -- 86 var vars map[string]interface{} 87 if tcase.GQLVariables != "" { 88 err := json.Unmarshal([]byte(tcase.GQLVariables), &vars) 89 require.NoError(t, err) 90 } 91 92 _, err := gqlSchema.Operation( 93 &schema.Request{ 94 Query: tcase.GQLMutation, 95 Variables: vars, 96 }) 97 require.NotNil(t, err) 98 require.Equal(t, err.Error(), tcase.ValidationError.Error()) 99 }) 100 } 101 } 102 103 func mutationRewriting(t *testing.T, file string, rewriterFactory func() MutationRewriter) { 104 b, err := ioutil.ReadFile(file) 105 require.NoError(t, err, "Unable to read test file") 106 107 var tests []testCase 108 err = yaml.Unmarshal(b, &tests) 109 require.NoError(t, err, "Unable to unmarshal tests to yaml.") 110 111 gqlSchema := test.LoadSchemaFromFile(t, "schema.graphql") 112 113 for _, tcase := range tests { 114 t.Run(tcase.Name, func(t *testing.T) { 115 // -- Arrange -- 116 var vars map[string]interface{} 117 if tcase.GQLVariables != "" { 118 err := json.Unmarshal([]byte(tcase.GQLVariables), &vars) 119 require.NoError(t, err) 120 } 121 122 op, err := gqlSchema.Operation( 123 &schema.Request{ 124 Query: tcase.GQLMutation, 125 Variables: vars, 126 }) 127 require.NoError(t, err) 128 mut := test.GetMutation(t, op) 129 rewriterToTest := rewriterFactory() 130 131 // -- Act -- 132 q, muts, err := rewriterToTest.Rewrite(mut) 133 134 // -- Assert -- 135 if tcase.Error != nil || err != nil { 136 require.Equal(t, tcase.Error.Error(), err.Error()) 137 } else { 138 require.Equal(t, tcase.DGQuery, dgraph.AsString(q)) 139 require.Len(t, muts, len(tcase.DGMutations)) 140 for i, expected := range tcase.DGMutations { 141 require.Equal(t, expected.Cond, muts[i].Cond) 142 if len(muts[i].SetJson) > 0 || expected.SetJSON != "" { 143 require.JSONEq(t, expected.SetJSON, string(muts[i].SetJson)) 144 } 145 if len(muts[i].DeleteJson) > 0 || expected.DeleteJSON != "" { 146 require.JSONEq(t, expected.DeleteJSON, string(muts[i].DeleteJson)) 147 } 148 } 149 } 150 }) 151 } 152 } 153 154 func TestMutationQueryRewriting(t *testing.T) { 155 testTypes := map[string]struct { 156 mut string 157 rewriter func() MutationRewriter 158 assigned map[string]string 159 result map[string]interface{} 160 }{ 161 "Add Post ": { 162 mut: `addPost(input: [{title: "A Post", author: {id: "0x1"}}])`, 163 rewriter: NewAddRewriter, 164 assigned: map[string]string{"Post1": "0x4"}, 165 }, 166 "Update Post ": { 167 mut: `updatePost(input: {filter: {postID 168 : ["0x4"]}, set: {text: "Updated text"} }) `, 169 rewriter: NewUpdateRewriter, 170 result: map[string]interface{}{ 171 "updatePost": []interface{}{map[string]interface{}{"uid": "0x4"}}}, 172 }, 173 } 174 175 allowedTestTypes := map[string][]string{ 176 "UPDATE_MUTATION": []string{"Update Post "}, 177 "ADD_UPDATE_MUTATION": []string{"Add Post ", "Update Post "}, 178 } 179 180 b, err := ioutil.ReadFile("mutation_query_test.yaml") 181 require.NoError(t, err, "Unable to read test file") 182 183 var tests map[string][]QueryRewritingCase 184 err = yaml.Unmarshal(b, &tests) 185 require.NoError(t, err, "Unable to unmarshal tests to yaml.") 186 187 gqlSchema := test.LoadSchemaFromFile(t, "schema.graphql") 188 189 for testType := range tests { 190 for _, name := range allowedTestTypes[testType] { 191 tt := testTypes[name] 192 for _, tcase := range tests[testType] { 193 t.Run(name+testType+tcase.Name, func(t *testing.T) { 194 rewriter := tt.rewriter() 195 // -- Arrange -- 196 gqlMutationStr := strings.Replace(tcase.GQLQuery, testType, tt.mut, 1) 197 op, err := gqlSchema.Operation( 198 &schema.Request{ 199 Query: gqlMutationStr, 200 Variables: tcase.Variables, 201 }) 202 require.NoError(t, err) 203 gqlMutation := test.GetMutation(t, op) 204 _, _, err = rewriter.Rewrite(gqlMutation) 205 require.Nil(t, err) 206 207 // -- Act -- 208 dgQuery, err := rewriter.FromMutationResult( 209 gqlMutation, tt.assigned, tt.result) 210 211 // -- Assert -- 212 require.Nil(t, err) 213 require.Equal(t, tcase.DGQuery, dgraph.AsString(dgQuery)) 214 }) 215 } 216 } 217 } 218 }