Spaces:
Sleeping
Sleeping
| // _ _ | |
| // __ _____ __ ___ ___ __ _| |_ ___ | |
| // \ \ /\ / / _ \/ _` \ \ / / |/ _` | __/ _ \ | |
| // \ V V / __/ (_| |\ V /| | (_| | || __/ | |
| // \_/\_/ \___|\__,_| \_/ |_|\__,_|\__\___| | |
| // | |
| // Copyright © 2016 - 2024 Weaviate B.V. All rights reserved. | |
| // | |
| // CONTACT: [email protected] | |
| // | |
| package acceptance_with_go_client | |
| import ( | |
| "context" | |
| "testing" | |
| "github.com/weaviate/weaviate-go-client/v4/weaviate/graphql" | |
| "github.com/weaviate/weaviate/entities/models" | |
| "github.com/stretchr/testify/assert" | |
| "github.com/stretchr/testify/require" | |
| client "github.com/weaviate/weaviate-go-client/v4/weaviate" | |
| ) | |
| func TestAutoschemaCasingClass(t *testing.T) { | |
| ctx := context.Background() | |
| c, err := client.NewClient(client.Config{Scheme: "http", Host: "localhost:8080"}) | |
| require.Nil(t, err) | |
| upperClassName := "RandomBlueTree" | |
| lowerClassName := "randomBlueTree" | |
| cases := []struct { | |
| className1 string | |
| className2 string | |
| }{ | |
| {className1: upperClassName, className2: upperClassName}, | |
| {className1: lowerClassName, className2: lowerClassName}, | |
| {className1: upperClassName, className2: lowerClassName}, | |
| {className1: lowerClassName, className2: upperClassName}, | |
| } | |
| for _, tt := range cases { | |
| t.Run(tt.className1+" "+tt.className2, func(t *testing.T) { | |
| c.Schema().ClassDeleter().WithClassName(tt.className1).Do(ctx) | |
| c.Schema().ClassDeleter().WithClassName(tt.className2).Do(ctx) | |
| creator := c.Data().Creator() | |
| _, err := creator.WithClassName(tt.className1).Do(ctx) | |
| require.Nil(t, err) | |
| _, err = creator.WithClassName(tt.className2).Do(ctx) | |
| require.Nil(t, err) | |
| // Regardless of whether a class exists or not, the delete operation will always return a success | |
| require.Nil(t, c.Schema().ClassDeleter().WithClassName(upperClassName).Do(ctx)) | |
| require.Nil(t, c.Schema().ClassDeleter().WithClassName(lowerClassName).Do(ctx)) | |
| }) | |
| } | |
| } | |
| func TestAutoschemaCasingProps(t *testing.T) { | |
| ctx := context.Background() | |
| c, err := client.NewClient(client.Config{Scheme: "http", Host: "localhost:8080"}) | |
| require.Nil(t, err) | |
| className := "RandomGreenBike" | |
| upperPropName := "SomeProp" | |
| lowerPropName := "someProp" | |
| cases := []struct { | |
| prop1 string | |
| prop2 string | |
| }{ | |
| {prop1: upperPropName, prop2: upperPropName}, | |
| {prop1: lowerPropName, prop2: lowerPropName}, | |
| {prop1: upperPropName, prop2: lowerPropName}, | |
| {prop1: lowerPropName, prop2: upperPropName}, | |
| } | |
| for _, tt := range cases { | |
| t.Run(tt.prop1+" "+tt.prop2, func(t *testing.T) { | |
| c.Schema().ClassDeleter().WithClassName(className).Do(ctx) | |
| creator := c.Data().Creator() | |
| _, err := creator.WithClassName(className).Do(ctx) | |
| require.Nil(t, err) | |
| creator1 := c.Data().Creator() | |
| _, err = creator1.WithClassName(className).WithProperties(map[string]string{tt.prop1: "something"}).Do(ctx) | |
| require.Nil(t, err) | |
| creator2 := c.Data().Creator() | |
| _, err = creator2.WithClassName(className).WithProperties(map[string]string{tt.prop2: "other value"}).Do(ctx) | |
| require.Nil(t, err) | |
| // three objects should have been added | |
| result, err := c.GraphQL().Aggregate().WithClassName(className).WithFields(graphql.Field{ | |
| Name: "meta", Fields: []graphql.Field{ | |
| {Name: "count"}, | |
| }, | |
| }).Do(ctx) | |
| require.Nil(t, err) | |
| require.Equal(t, result.Data["Aggregate"].(map[string]interface{})[className].([]interface{})[0].(map[string]interface{})["meta"].(map[string]interface{})["count"], 3.) | |
| require.Nil(t, c.Schema().ClassDeleter().WithClassName(className).Do(ctx)) | |
| }) | |
| } | |
| } | |
| func TestAutoschemaCasingUpdateProps(t *testing.T) { | |
| ctx := context.Background() | |
| c, err := client.NewClient(client.Config{Scheme: "http", Host: "localhost:8080"}) | |
| require.Nil(t, err) | |
| objId := "67b79643-cf8b-4b22-b206-6e63dbb4e57a" | |
| upperPropName := "SomeProp" | |
| lowerPropName := "someProp" | |
| cases := []struct { | |
| prop1 string | |
| prop2 string | |
| }{ | |
| {prop1: upperPropName, prop2: upperPropName}, | |
| {prop1: lowerPropName, prop2: lowerPropName}, | |
| {prop1: upperPropName, prop2: lowerPropName}, | |
| {prop1: lowerPropName, prop2: upperPropName}, | |
| } | |
| for _, tt := range cases { | |
| t.Run(tt.prop1+" "+tt.prop2, func(t *testing.T) { | |
| className := "RandomOliveTree" | |
| c.Schema().ClassDeleter().WithClassName(className).Do(ctx) | |
| creator := c.Data().Creator() | |
| _, err := creator.WithClassName(className).Do(ctx) | |
| require.Nil(t, err) | |
| creator1 := c.Data().Creator() | |
| _, err = creator1.WithClassName(className).WithID(objId).WithProperties(map[string]string{tt.prop1: "something"}).Do(ctx) | |
| require.Nil(t, err) | |
| updater := c.Data().Updater() | |
| err = updater.WithClassName(className).WithID(objId).WithProperties(map[string]string{tt.prop2: "other"}).Do(ctx) | |
| require.Nil(t, err) | |
| // two objects should have been added (with one update | |
| result, err := c.GraphQL().Aggregate().WithClassName(className).WithFields(graphql.Field{ | |
| Name: "meta", Fields: []graphql.Field{ | |
| {Name: "count"}, | |
| }, | |
| }).Do(ctx) | |
| require.Nil(t, err) | |
| require.Equal(t, result.Data["Aggregate"].(map[string]interface{})[className].([]interface{})[0].(map[string]interface{})["meta"].(map[string]interface{})["count"], 2.) | |
| require.Nil(t, c.Schema().ClassDeleter().WithClassName(className).Do(ctx)) | |
| }) | |
| } | |
| } | |
| func TestAutoschemaPanicOnUnregonizedDataType(t *testing.T) { | |
| ctx := context.Background() | |
| c, err := client.NewClient(client.Config{Scheme: "http", Host: "localhost:8080"}) | |
| require.Nil(t, err) | |
| tests := []struct { | |
| name string | |
| properties map[string]interface{} | |
| containsErrMessage string | |
| }{ | |
| { | |
| name: "unrecognized array property type", | |
| properties: map[string]interface{}{ | |
| "panicProperty": []interface{}{ | |
| []interface{}{ | |
| []interface{}{ | |
| "panic", | |
| }, | |
| }, | |
| }, | |
| }, | |
| containsErrMessage: "property 'panicProperty' on class 'BeautifulWeather': element [0]: unrecognized data type of value", | |
| }, | |
| { | |
| name: "unrecognized nil array property type", | |
| properties: map[string]interface{}{ | |
| "panicProperty": []interface{}{ | |
| []interface{}{ | |
| []interface{}{ | |
| nil, | |
| }, | |
| }, | |
| }, | |
| }, | |
| containsErrMessage: "property 'panicProperty' on class 'BeautifulWeather': element [0]: unrecognized data type of value", | |
| }, | |
| { | |
| name: "array property with nil", | |
| properties: map[string]interface{}{ | |
| "nilPropertyArray": []interface{}{nil}, | |
| }, | |
| containsErrMessage: "property 'nilPropertyArray' on class 'BeautifulWeather': element [0]: unrecognized data type of value '<nil>'", | |
| }, | |
| { | |
| name: "empty string array property", | |
| properties: map[string]interface{}{ | |
| "emptyPropertyArray": []string{}, | |
| }, | |
| }, | |
| { | |
| name: "empty interface array property", | |
| properties: map[string]interface{}{ | |
| "emptyPropertyArray": []interface{}{}, | |
| }, | |
| }, | |
| { | |
| name: "empty int array property", | |
| properties: map[string]interface{}{ | |
| "emptyPropertyArray": []int{}, | |
| }, | |
| }, | |
| { | |
| name: "array property with empty string", | |
| properties: map[string]interface{}{ | |
| "emptyPropertyArray": []string{""}, | |
| }, | |
| }, | |
| { | |
| name: "nil property", | |
| properties: map[string]interface{}{ | |
| "nilProperty": nil, | |
| }, | |
| }, | |
| } | |
| for _, tt := range tests { | |
| t.Run(tt.name, func(t *testing.T) { | |
| resp, err := c.Data(). | |
| Creator(). | |
| WithClassName("BeautifulWeather"). | |
| WithProperties(tt.properties). | |
| Do(ctx) | |
| if tt.containsErrMessage != "" { | |
| assert.Nil(t, resp) | |
| assert.NotNil(t, err) | |
| assert.ErrorContains(t, err, tt.containsErrMessage) | |
| } else { | |
| assert.NotNil(t, resp) | |
| assert.Nil(t, err) | |
| } | |
| err = c.Schema().ClassDeleter().WithClassName("BeautifulWeather").Do(ctx) | |
| require.Nil(t, err) | |
| }) | |
| } | |
| } | |
| func TestAutoschemaPanicOnUnregonizedDataTypeWithBatch(t *testing.T) { | |
| ctx := context.Background() | |
| c, err := client.NewClient(client.Config{Scheme: "http", Host: "localhost:8080"}) | |
| require.Nil(t, err) | |
| className := "Passage" | |
| t.Run("should not panic with properties defined as empty array, but just return error", func(t *testing.T) { | |
| obj := &models.Object{ | |
| Class: className, | |
| Properties: []interface{}{}, | |
| } | |
| resp, err := c.Batch().ObjectsBatcher().WithObject(obj).Do(ctx) | |
| require.Nil(t, err) | |
| require.Len(t, resp, 1) | |
| require.NotNil(t, resp[0].Result) | |
| require.NotNil(t, resp[0].Result.Errors) | |
| require.Len(t, resp[0].Result.Errors.Error, 1) | |
| assert.Equal(t, "could not recognize object's properties: []", resp[0].Result.Errors.Error[0].Message) | |
| objs, err := c.Data().ObjectsGetter().WithClassName(className).Do(ctx) | |
| require.Nil(t, err) | |
| require.Len(t, objs, 0) | |
| err = c.Schema().ClassDeleter().WithClassName(className).Do(ctx) | |
| require.Nil(t, err) | |
| }) | |
| t.Run("should create object in batch without problems", func(t *testing.T) { | |
| obj := &models.Object{ | |
| Class: className, | |
| Properties: map[string]interface{}{ | |
| "stringProperty": "value", | |
| }, | |
| } | |
| resp, err := c.Batch().ObjectsBatcher().WithObject(obj).Do(ctx) | |
| require.Nil(t, err) | |
| require.Len(t, resp, 1) | |
| require.NotNil(t, resp[0].Result) | |
| require.Nil(t, resp[0].Result.Errors) | |
| require.NotNil(t, resp[0].Object) | |
| assert.True(t, len(resp[0].Object.Vector) > 0) | |
| objs, err := c.Data().ObjectsGetter().WithClassName(className).Do(ctx) | |
| require.Nil(t, err) | |
| require.Len(t, objs, 1) | |
| err = c.Schema().ClassDeleter().WithClassName(className).Do(ctx) | |
| require.Nil(t, err) | |
| }) | |
| } | |