github.com/weaviate/weaviate@v1.24.6/usecases/classification/validation_test.go (about) 1 // _ _ 2 // __ _____ __ ___ ___ __ _| |_ ___ 3 // \ \ /\ / / _ \/ _` \ \ / / |/ _` | __/ _ \ 4 // \ V V / __/ (_| |\ V /| | (_| | || __/ 5 // \_/\_/ \___|\__,_| \_/ |_|\__,_|\__\___| 6 // 7 // Copyright © 2016 - 2024 Weaviate B.V. All rights reserved. 8 // 9 // CONTACT: hello@weaviate.io 10 // 11 12 package classification 13 14 import ( 15 "fmt" 16 "testing" 17 18 "github.com/stretchr/testify/assert" 19 "github.com/weaviate/weaviate/entities/models" 20 ) 21 22 func Test_ValidateUserInput(t *testing.T) { 23 type testcase struct { 24 name string 25 input models.Classification 26 expectedError error 27 } 28 29 // knn or general 30 tests := []testcase{ 31 { 32 name: "missing class", 33 input: models.Classification{ 34 BasedOnProperties: []string{"description"}, 35 ClassifyProperties: []string{"exactCategory"}, 36 }, 37 expectedError: fmt.Errorf("invalid classification: class must be set"), 38 }, 39 40 { 41 name: "missing basedOnProperty (nil)", 42 input: models.Classification{ 43 Class: "Article", 44 BasedOnProperties: nil, 45 ClassifyProperties: []string{"exactCategory"}, 46 }, 47 expectedError: fmt.Errorf("invalid classification: basedOnProperties must have at least one property"), 48 }, 49 { 50 name: "missing basedOnProperty (len=0)", 51 input: models.Classification{ 52 Class: "Article", 53 BasedOnProperties: []string{}, 54 ClassifyProperties: []string{"exactCategory"}, 55 }, 56 expectedError: fmt.Errorf("invalid classification: basedOnProperties must have at least one property"), 57 }, 58 59 { 60 name: "more than one basedOnProperty", 61 input: models.Classification{ 62 Class: "Article", 63 BasedOnProperties: []string{"description", "name"}, 64 ClassifyProperties: []string{"exactCategory"}, 65 }, 66 expectedError: fmt.Errorf("invalid classification: only a single property in basedOnProperties " + 67 "supported at the moment, got [description name]"), 68 }, 69 70 { 71 name: "basedOnProperty does not exist", 72 input: models.Classification{ 73 Class: "Article", 74 BasedOnProperties: []string{"doesNotExist"}, 75 ClassifyProperties: []string{"exactCategory"}, 76 }, 77 expectedError: fmt.Errorf("invalid classification: basedOnProperties: property 'doesNotExist' does not exist"), 78 }, 79 80 { 81 name: "basedOnProperty is not of type text", 82 input: models.Classification{ 83 Class: "Article", 84 BasedOnProperties: []string{"words"}, 85 ClassifyProperties: []string{"exactCategory"}, 86 }, 87 expectedError: fmt.Errorf("invalid classification: basedOnProperties: property 'words' must be of type 'text'"), 88 }, 89 90 { 91 name: "missing classifyProperties (nil)", 92 input: models.Classification{ 93 Class: "Article", 94 BasedOnProperties: []string{"description"}, 95 ClassifyProperties: nil, 96 }, 97 expectedError: fmt.Errorf("invalid classification: classifyProperties must have at least one property"), 98 }, 99 100 { 101 name: "missing classifyProperties (len=0)", 102 input: models.Classification{ 103 Class: "Article", 104 BasedOnProperties: []string{"description"}, 105 ClassifyProperties: []string{}, 106 }, 107 expectedError: fmt.Errorf("invalid classification: classifyProperties must have at least one property"), 108 }, 109 110 { 111 name: "classifyProperties does not exist", 112 input: models.Classification{ 113 Class: "Article", 114 BasedOnProperties: []string{"description"}, 115 ClassifyProperties: []string{"doesNotExist"}, 116 }, 117 expectedError: fmt.Errorf("invalid classification: classifyProperties: property 'doesNotExist' does not exist"), 118 }, 119 120 { 121 name: "classifyProperties is not of reference type", 122 input: models.Classification{ 123 Class: "Article", 124 BasedOnProperties: []string{"description"}, 125 ClassifyProperties: []string{"name"}, 126 }, 127 expectedError: fmt.Errorf("invalid classification: classifyProperties: property 'name' must be of reference type (cref)"), 128 }, 129 130 { 131 name: "multiple missing fields (aborts early as we can't validate properties if class is not set)", 132 input: models.Classification{}, 133 expectedError: fmt.Errorf("invalid classification: class must be set"), 134 }, 135 136 // specific for knn 137 { 138 name: "targetWhere is set", 139 input: models.Classification{ 140 Class: "Article", 141 BasedOnProperties: []string{"description"}, 142 ClassifyProperties: []string{"exactCategory"}, 143 Filters: &models.ClassificationFilters{ 144 TargetWhere: &models.WhereFilter{Operator: "Equal", Path: []string{"foo"}, ValueText: ptString("bar")}, 145 }, 146 Type: "knn", 147 }, 148 expectedError: fmt.Errorf("invalid classification: type is 'knn', but 'targetWhere' filter is set, for 'knn' you cannot limit target data directly, instead limit training data through setting 'trainingSetWhere'"), 149 }, 150 151 // specific for text2vec-contextionary-contextual 152 { 153 name: "classifyProperty has more than one target class", 154 input: models.Classification{ 155 Class: "Article", 156 BasedOnProperties: []string{"description"}, 157 ClassifyProperties: []string{"anyCategory"}, 158 Type: "text2vec-contextionary-contextual", 159 }, 160 expectedError: fmt.Errorf("invalid classification: classifyProperties: property 'anyCategory' has more than one target class, classification of type 'text2vec-contextionary-contextual' requires exactly one target class"), 161 }, 162 163 { 164 name: "trainingSetWhere is set", 165 input: models.Classification{ 166 Class: "Article", 167 BasedOnProperties: []string{"description"}, 168 ClassifyProperties: []string{"exactCategory"}, 169 Filters: &models.ClassificationFilters{ 170 TrainingSetWhere: &models.WhereFilter{Operator: "Equal", Path: []string{"foo"}, ValueText: ptString("bar")}, 171 }, 172 Type: "text2vec-contextionary-contextual", 173 }, 174 expectedError: fmt.Errorf("invalid classification: type is 'text2vec-contextionary-contextual', but 'trainingSetWhere' filter is set, for 'text2vec-contextionary-contextual' there is no training data, instead limit possible target data directly through setting 'targetWhere'"), 175 }, 176 } 177 178 for _, test := range tests { 179 t.Run(test.name, func(t *testing.T) { 180 validator := NewValidator(&fakeSchemaGetter{testSchema()}, test.input) 181 err := validator.Do() 182 assert.Equal(t, test.expectedError, err) 183 }) 184 } 185 } 186 187 func ptString(in string) *string { 188 return &in 189 }