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  }