Spaces:
Running
Running
// _ _ | |
// __ _____ __ ___ ___ __ _| |_ ___ | |
// \ \ /\ / / _ \/ _` \ \ / / |/ _` | __/ _ \ | |
// \ V V / __/ (_| |\ V /| | (_| | || __/ | |
// \_/\_/ \___|\__,_| \_/ |_|\__,_|\__\___| | |
// | |
// Copyright © 2016 - 2024 Weaviate B.V. All rights reserved. | |
// | |
// CONTACT: [email protected] | |
// | |
package classification | |
import ( | |
"fmt" | |
"testing" | |
"github.com/stretchr/testify/assert" | |
"github.com/weaviate/weaviate/entities/models" | |
) | |
func Test_ValidateUserInput(t *testing.T) { | |
type testcase struct { | |
name string | |
input models.Classification | |
expectedError error | |
} | |
// knn or general | |
tests := []testcase{ | |
{ | |
name: "missing class", | |
input: models.Classification{ | |
BasedOnProperties: []string{"description"}, | |
ClassifyProperties: []string{"exactCategory"}, | |
}, | |
expectedError: fmt.Errorf("invalid classification: class must be set"), | |
}, | |
{ | |
name: "missing basedOnProperty (nil)", | |
input: models.Classification{ | |
Class: "Article", | |
BasedOnProperties: nil, | |
ClassifyProperties: []string{"exactCategory"}, | |
}, | |
expectedError: fmt.Errorf("invalid classification: basedOnProperties must have at least one property"), | |
}, | |
{ | |
name: "missing basedOnProperty (len=0)", | |
input: models.Classification{ | |
Class: "Article", | |
BasedOnProperties: []string{}, | |
ClassifyProperties: []string{"exactCategory"}, | |
}, | |
expectedError: fmt.Errorf("invalid classification: basedOnProperties must have at least one property"), | |
}, | |
{ | |
name: "more than one basedOnProperty", | |
input: models.Classification{ | |
Class: "Article", | |
BasedOnProperties: []string{"description", "name"}, | |
ClassifyProperties: []string{"exactCategory"}, | |
}, | |
expectedError: fmt.Errorf("invalid classification: only a single property in basedOnProperties " + | |
"supported at the moment, got [description name]"), | |
}, | |
{ | |
name: "basedOnProperty does not exist", | |
input: models.Classification{ | |
Class: "Article", | |
BasedOnProperties: []string{"doesNotExist"}, | |
ClassifyProperties: []string{"exactCategory"}, | |
}, | |
expectedError: fmt.Errorf("invalid classification: basedOnProperties: property 'doesNotExist' does not exist"), | |
}, | |
{ | |
name: "basedOnProperty is not of type text", | |
input: models.Classification{ | |
Class: "Article", | |
BasedOnProperties: []string{"words"}, | |
ClassifyProperties: []string{"exactCategory"}, | |
}, | |
expectedError: fmt.Errorf("invalid classification: basedOnProperties: property 'words' must be of type 'text'"), | |
}, | |
{ | |
name: "missing classifyProperties (nil)", | |
input: models.Classification{ | |
Class: "Article", | |
BasedOnProperties: []string{"description"}, | |
ClassifyProperties: nil, | |
}, | |
expectedError: fmt.Errorf("invalid classification: classifyProperties must have at least one property"), | |
}, | |
{ | |
name: "missing classifyProperties (len=0)", | |
input: models.Classification{ | |
Class: "Article", | |
BasedOnProperties: []string{"description"}, | |
ClassifyProperties: []string{}, | |
}, | |
expectedError: fmt.Errorf("invalid classification: classifyProperties must have at least one property"), | |
}, | |
{ | |
name: "classifyProperties does not exist", | |
input: models.Classification{ | |
Class: "Article", | |
BasedOnProperties: []string{"description"}, | |
ClassifyProperties: []string{"doesNotExist"}, | |
}, | |
expectedError: fmt.Errorf("invalid classification: classifyProperties: property 'doesNotExist' does not exist"), | |
}, | |
{ | |
name: "classifyProperties is not of reference type", | |
input: models.Classification{ | |
Class: "Article", | |
BasedOnProperties: []string{"description"}, | |
ClassifyProperties: []string{"name"}, | |
}, | |
expectedError: fmt.Errorf("invalid classification: classifyProperties: property 'name' must be of reference type (cref)"), | |
}, | |
{ | |
name: "multiple missing fields (aborts early as we can't validate properties if class is not set)", | |
input: models.Classification{}, | |
expectedError: fmt.Errorf("invalid classification: class must be set"), | |
}, | |
// specific for knn | |
{ | |
name: "targetWhere is set", | |
input: models.Classification{ | |
Class: "Article", | |
BasedOnProperties: []string{"description"}, | |
ClassifyProperties: []string{"exactCategory"}, | |
Filters: &models.ClassificationFilters{ | |
TargetWhere: &models.WhereFilter{Operator: "Equal", Path: []string{"foo"}, ValueText: ptString("bar")}, | |
}, | |
Type: "knn", | |
}, | |
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'"), | |
}, | |
// specific for text2vec-contextionary-contextual | |
{ | |
name: "classifyProperty has more than one target class", | |
input: models.Classification{ | |
Class: "Article", | |
BasedOnProperties: []string{"description"}, | |
ClassifyProperties: []string{"anyCategory"}, | |
Type: "text2vec-contextionary-contextual", | |
}, | |
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"), | |
}, | |
{ | |
name: "trainingSetWhere is set", | |
input: models.Classification{ | |
Class: "Article", | |
BasedOnProperties: []string{"description"}, | |
ClassifyProperties: []string{"exactCategory"}, | |
Filters: &models.ClassificationFilters{ | |
TrainingSetWhere: &models.WhereFilter{Operator: "Equal", Path: []string{"foo"}, ValueText: ptString("bar")}, | |
}, | |
Type: "text2vec-contextionary-contextual", | |
}, | |
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'"), | |
}, | |
} | |
for _, test := range tests { | |
t.Run(test.name, func(t *testing.T) { | |
validator := NewValidator(&fakeSchemaGetter{testSchema()}, test.input) | |
err := validator.Do() | |
assert.Equal(t, test.expectedError, err) | |
}) | |
} | |
} | |
func ptString(in string) *string { | |
return &in | |
} | |