Spaces:
				
			
			
	
			
			
		Sleeping
		
	
	
	
			
			
	
	
	
	
		
		
		Sleeping
		
	| // _ _ | |
| // __ _____ __ ___ ___ __ _| |_ ___ | |
| // \ \ /\ / / _ \/ _` \ \ / / |/ _` | __/ _ \ | |
| // \ V V / __/ (_| |\ V /| | (_| | || __/ | |
| // \_/\_/ \___|\__,_| \_/ |_|\__,_|\__\___| | |
| // | |
| // Copyright © 2016 - 2024 Weaviate B.V. All rights reserved. | |
| // | |
| // CONTACT: [email protected] | |
| // | |
| package test | |
| import ( | |
| "fmt" | |
| "strings" | |
| "testing" | |
| "time" | |
| "github.com/go-openapi/strfmt" | |
| "github.com/stretchr/testify/assert" | |
| "github.com/weaviate/weaviate/client/objects" | |
| clschema "github.com/weaviate/weaviate/client/schema" | |
| "github.com/weaviate/weaviate/entities/models" | |
| "github.com/weaviate/weaviate/entities/schema" | |
| "github.com/weaviate/weaviate/test/helper" | |
| ) | |
| // This aims to prevent a regression on | |
| // https://github.com/weaviate/weaviate/issues/1016 | |
| // The issue was that rapid POST .../references/... request in succession would | |
| // overwrite each other due to the eventual consistency nature of the used | |
| // backend (esvector). This bug is considered fix if n items can be rapidly | |
| // added and a subsequent GET request of the source resource contains all | |
| // previously added references. | |
| func Test_RapidlyAddingReferences(t *testing.T) { | |
| sourceClass := "SequenceReferenceTestSource" | |
| targetClass := "SequenceReferenceTestTarget" | |
| sourceID := strfmt.UUID("96ce03ca-58ed-48e1-a0f1-51f63fa9aa12") | |
| targetIDs := []strfmt.UUID{ | |
| "ce1a4756-b7ce-44fa-b079-45a7ec400882", | |
| "e1edb4ff-570c-4f0b-a1a1-18af118369aa", | |
| "25d22c70-3df0-4e5c-b8c1-a88d4d2771ef", | |
| "6f2a0708-3e8e-4a68-9763-26c465d8bf83", | |
| "c4dfae47-ebcf-4808-9122-1c67898ec140", | |
| "754bd925-1900-4f93-9f5d-27631eb618bb", | |
| "babba820-e3f5-4e8d-a354-76f2cb13fdba", | |
| "270942da-1999-40cd-a580-a91aa144b6c0", | |
| "a7a06618-6d50-4654-be75-2c9f639a6368", | |
| "47ba1d2b-6b8c-4b3b-92a8-46574a069ae8", | |
| } | |
| t.Run("adding the required schema", func(t *testing.T) { | |
| t.Run("target class", func(t *testing.T) { | |
| params := clschema.NewSchemaObjectsCreateParams().WithObjectClass( | |
| &models.Class{ | |
| Class: targetClass, | |
| Properties: []*models.Property{ | |
| { | |
| DataType: schema.DataTypeText.PropString(), | |
| Tokenization: models.PropertyTokenizationWhitespace, | |
| Name: "name", | |
| }, | |
| }, | |
| }, | |
| ) | |
| resp, err := helper.Client(t).Schema.SchemaObjectsCreate(params, nil) | |
| helper.AssertRequestOk(t, resp, err, nil) | |
| }) | |
| t.Run("source class", func(t *testing.T) { | |
| params := clschema.NewSchemaObjectsCreateParams().WithObjectClass( | |
| &models.Class{ | |
| Class: sourceClass, | |
| Properties: []*models.Property{ | |
| { | |
| DataType: []string{targetClass}, | |
| Name: "toTarget", | |
| }, | |
| { | |
| DataType: schema.DataTypeText.PropString(), | |
| Tokenization: models.PropertyTokenizationWhitespace, | |
| Name: "name", | |
| }, | |
| }, | |
| }, | |
| ) | |
| resp, err := helper.Client(t).Schema.SchemaObjectsCreate(params, nil) | |
| helper.AssertRequestOk(t, resp, err, nil) | |
| }) | |
| }) | |
| t.Run("adding all objects (without referencing)", func(t *testing.T) { | |
| t.Run("source object", func(t *testing.T) { | |
| assertCreateObjectWithID(t, sourceClass, "", sourceID, map[string]interface{}{ | |
| "name": "Source Object", | |
| }) | |
| }) | |
| t.Run("target objects", func(t *testing.T) { | |
| for i, id := range targetIDs { | |
| assertCreateObjectWithID(t, targetClass, "", id, map[string]interface{}{ | |
| "name": fmt.Sprintf("target object %d", i), | |
| }) | |
| } | |
| }) | |
| }) | |
| t.Run("waiting for the last added object to be present", func(t *testing.T) { | |
| assertGetObjectEventually(t, targetIDs[len(targetIDs)-1]) | |
| }) | |
| t.Run("placing all references in succession", func(t *testing.T) { | |
| for _, id := range targetIDs { | |
| params := objects.NewObjectsReferencesCreateParams(). | |
| WithID(sourceID). | |
| WithPropertyName("toTarget"). | |
| WithBody( | |
| &models.SingleRef{ | |
| Beacon: strfmt.URI(fmt.Sprintf("weaviate://localhost/%s", id)), | |
| }, | |
| ) | |
| res, err := helper.Client(t).Objects.ObjectsReferencesCreate(params, nil) | |
| helper.AssertRequestOk(t, res, err, nil) | |
| } | |
| }) | |
| // wait for index refresh | |
| time.Sleep(2 * time.Second) // TODO: improve through polling | |
| t.Run("checking which refs were set", func(t *testing.T) { | |
| source := assertGetObject(t, sourceID) | |
| var foundIDs []strfmt.UUID | |
| // extract IDs | |
| for _, ref := range source.Properties.(map[string]interface{})["toTarget"].([]interface{}) { | |
| beacon := ref.(map[string]interface{})["beacon"].(string) | |
| chunks := strings.Split(beacon, "/") | |
| foundIDs = append(foundIDs, strfmt.UUID(chunks[len(chunks)-1])) | |
| } | |
| assert.ElementsMatch(t, targetIDs, foundIDs) | |
| }) | |
| // cleanup | |
| helper.Client(t).Schema.SchemaObjectsDelete( | |
| clschema.NewSchemaObjectsDeleteParams().WithClassName(sourceClass), nil) | |
| helper.Client(t).Schema.SchemaObjectsDelete( | |
| clschema.NewSchemaObjectsDeleteParams().WithClassName(targetClass), nil) | |
| } | |