github.com/dgraph-io/dgraph@v1.2.8/graphql/schema/schemagen_test.go (about) 1 /* 2 * Copyright 2017-2018 Dgraph Labs, Inc. and Contributors 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package schema 18 19 import ( 20 "io/ioutil" 21 "strings" 22 "testing" 23 24 dschema "github.com/dgraph-io/dgraph/schema" 25 "github.com/google/go-cmp/cmp" 26 "github.com/stretchr/testify/require" 27 "github.com/vektah/gqlparser/gqlerror" 28 "gopkg.in/yaml.v2" 29 ) 30 31 type Tests map[string][]TestCase 32 33 type TestCase struct { 34 Name string 35 Input string 36 Errlist gqlerror.List 37 Output string 38 } 39 40 func TestDGSchemaGen(t *testing.T) { 41 fileName := "schemagen_test.yml" 42 byts, err := ioutil.ReadFile(fileName) 43 require.NoError(t, err, "Unable to read file %s", fileName) 44 45 var tests Tests 46 err = yaml.Unmarshal(byts, &tests) 47 require.NoError(t, err, "Unable to unmarshal to yaml!") 48 49 for _, schemas := range tests { 50 for _, sch := range schemas { 51 t.Run(sch.Name, func(t *testing.T) { 52 53 schHandler, errs := NewHandler(sch.Input) 54 require.NoError(t, errs) 55 56 dgSchema := schHandler.DGSchema() 57 if diff := cmp.Diff(strings.Split(sch.Output, "\n"), 58 strings.Split(dgSchema, "\n")); diff != "" { 59 t.Errorf("schema mismatch (-want +got):\n%s", diff) 60 } 61 _, err := dschema.Parse(dgSchema) 62 require.NoError(t, err) 63 }) 64 } 65 } 66 } 67 68 func TestSchemaString(t *testing.T) { 69 inputDir := "testdata/schemagen/input/" 70 outputDir := "testdata/schemagen/output/" 71 72 files, err := ioutil.ReadDir(inputDir) 73 require.NoError(t, err) 74 75 for _, testFile := range files { 76 t.Run(testFile.Name(), func(t *testing.T) { 77 inputFileName := inputDir + testFile.Name() 78 str1, err := ioutil.ReadFile(inputFileName) 79 require.NoError(t, err) 80 81 schHandler, errs := NewHandler(string(str1)) 82 require.NoError(t, errs) 83 84 newSchemaStr := schHandler.GQLSchema() 85 86 _, err = FromString(newSchemaStr) 87 require.NoError(t, err) 88 89 outputFileName := outputDir + testFile.Name() 90 str2, err := ioutil.ReadFile(outputFileName) 91 require.NoError(t, err) 92 93 if diff := cmp.Diff(string(str2), newSchemaStr); diff != "" { 94 // fmt.Printf("Generated Schema (%s):\n%s\n", testFile.Name(), newSchemaStr) 95 t.Errorf("schema mismatch - diff (-want +got):\n%s", diff) 96 } 97 }) 98 } 99 } 100 101 func TestSchemas(t *testing.T) { 102 fileName := "gqlschema_test.yml" 103 byts, err := ioutil.ReadFile(fileName) 104 require.NoError(t, err, "Unable to read file %s", fileName) 105 106 var tests Tests 107 err = yaml.Unmarshal(byts, &tests) 108 require.NoError(t, err, "Error Unmarshalling to yaml!") 109 110 t.Run("Valid Schemas", func(t *testing.T) { 111 for _, sch := range tests["valid_schemas"] { 112 t.Run(sch.Name, func(t *testing.T) { 113 _, errlist := NewHandler(sch.Input) 114 require.NoError(t, errlist, sch.Name) 115 }) 116 } 117 }) 118 119 t.Run("Invalid Schemas", func(t *testing.T) { 120 for _, sch := range tests["invalid_schemas"] { 121 t.Run(sch.Name, func(t *testing.T) { 122 _, errlist := NewHandler(sch.Input) 123 if diff := cmp.Diff(sch.Errlist, errlist); diff != "" { 124 t.Errorf("error mismatch (-want +got):\n%s", diff) 125 } 126 }) 127 } 128 }) 129 } 130 131 // The other tests verify that @search works where it is expected to work, 132 // and show what the error messages look like. This test shows all the cases 133 // that shouldn't work - i.e. we'll never accept a search where we don't 134 // expect one. It's too annoying to have all the errors for this, so It just 135 // makes sure that there are as many errors as cases. 136 func TestOnlyCorrectSearchArgsWork(t *testing.T) { 137 tests := map[string]struct { 138 schema string 139 expectedErrors int 140 }{ 141 "String searches don't apply to Int": {schema: ` 142 type X { 143 str1: Int @search(by: [hash]) 144 str2: Int @search(by: [exact]) 145 str3: Int @search(by: [term]) 146 str4: Int @search(by: [fulltext]) 147 str5: Int @search(by: [trigram]) 148 str6: Int @search(by: [regexp]) 149 }`, 150 expectedErrors: 6}, 151 "String searches don't apply to Float": {schema: ` 152 type X { 153 str1: Float @search(by: [hash]) 154 str2: Float @search(by: [exact]) 155 str3: Float @search(by: [term]) 156 str4: Float @search(by: [fulltext]) 157 str5: Float @search(by: [trigram]) 158 str6: Float @search(by: [regexp]) 159 }`, 160 expectedErrors: 6}, 161 "String searches don't apply to Boolean": {schema: ` 162 type X { 163 str1: Boolean @search(by: [hash]) 164 str2: Boolean @search(by: [exact]) 165 str3: Boolean @search(by: [term]) 166 str4: Boolean @search(by: [fulltext]) 167 str5: Boolean @search(by: [trigram]) 168 str6: Boolean @search(by: [regexp]) 169 }`, 170 expectedErrors: 6}, 171 "String searches don't apply to DateTime": {schema: ` 172 type X { 173 str1: DateTime @search(by: [hash]) 174 str2: DateTime @search(by: [exact]) 175 str3: DateTime @search(by: [term]) 176 str4: DateTime @search(by: [fulltext]) 177 str5: DateTime @search(by: [trigram]) 178 str6: DateTime @search(by: [regexp]) 179 }`, 180 expectedErrors: 6}, 181 "DateTime searches don't apply to Int": {schema: ` 182 type X { 183 dt1: Int @search(by: [year]) 184 dt2: Int @search(by: [month]) 185 dt3: Int @search(by: [day]) 186 dt4: Int @search(by: [hour]) 187 }`, 188 expectedErrors: 4}, 189 "DateTime searches don't apply to Float": {schema: ` 190 type X { 191 dt1: Float @search(by: [year]) 192 dt2: Float @search(by: [month]) 193 dt3: Float @search(by: [day]) 194 dt4: Float @search(by: [hour]) 195 }`, 196 expectedErrors: 4}, 197 "DateTime searches don't apply to Boolean": {schema: ` 198 type X { 199 dt1: Boolean @search(by: [year]) 200 dt2: Boolean @search(by: [month]) 201 dt3: Boolean @search(by: [day]) 202 dt4: Boolean @search(by: [hour]) 203 }`, 204 expectedErrors: 4}, 205 "DateTime searches don't apply to String": {schema: ` 206 type X { 207 dt1: String @search(by: [year]) 208 dt2: String @search(by: [month]) 209 dt3: String @search(by: [day]) 210 dt4: String @search(by: [hour]) 211 }`, 212 expectedErrors: 4}, 213 "Int searches only appy to Int": {schema: ` 214 type X { 215 i1: Float @search(by: [int]) 216 i2: Boolean @search(by: [int]) 217 i3: String @search(by: [int]) 218 i4: DateTime @search(by: [int]) 219 }`, 220 expectedErrors: 4}, 221 "Float searches only appy to Float": {schema: ` 222 type X { 223 f1: Int @search(by: [float]) 224 f2: Boolean @search(by: [float]) 225 f3: String @search(by: [float]) 226 f4: DateTime @search(by: [float]) 227 }`, 228 expectedErrors: 4}, 229 "Boolean searches only appy to Boolean": {schema: ` 230 type X { 231 b1: Int @search(by: [bool]) 232 b2: Float @search(by: [bool]) 233 b3: String @search(by: [bool]) 234 b4: DateTime @search(by: [bool]) 235 }`, 236 expectedErrors: 4}, 237 "Enums can only have hash, exact, regexp and trigram": {schema: ` 238 type X { 239 e1: E @search(by: [int]) 240 e2: E @search(by: [float]) 241 e3: E @search(by: [bool]) 242 e4: E @search(by: [year]) 243 e5: E @search(by: [month]) 244 e6: E @search(by: [day]) 245 e7: E @search(by: [hour]) 246 e9: E @search(by: [term]) 247 e10: E @search(by: [fulltext]) 248 } 249 enum E { 250 A 251 }`, 252 expectedErrors: 9}, 253 } 254 255 for name, test := range tests { 256 t.Run(name, func(t *testing.T) { 257 _, errlist := NewHandler(test.schema) 258 require.Len(t, errlist, test.expectedErrors, 259 "every field in this test applies @search wrongly and should raise an error") 260 }) 261 } 262 }