github.com/weaviate/weaviate@v1.24.6/test/acceptance/objects/rapid_updates_add_reference_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 test
    13  
    14  import (
    15  	"fmt"
    16  	"strings"
    17  	"testing"
    18  	"time"
    19  
    20  	"github.com/go-openapi/strfmt"
    21  	"github.com/stretchr/testify/assert"
    22  	"github.com/weaviate/weaviate/client/objects"
    23  	clschema "github.com/weaviate/weaviate/client/schema"
    24  	"github.com/weaviate/weaviate/entities/models"
    25  	"github.com/weaviate/weaviate/entities/schema"
    26  	"github.com/weaviate/weaviate/test/helper"
    27  )
    28  
    29  // This aims to prevent a regression on
    30  // https://github.com/weaviate/weaviate/issues/1016
    31  // The issue was that rapid POST .../references/... request in succession would
    32  // overwrite each other due to the eventual consistency nature of the used
    33  // backend (esvector). This bug is considered fix if n items can be rapidly
    34  // added and a subsequent GET request of the source resource contains all
    35  // previously added references.
    36  func Test_RapidlyAddingReferences(t *testing.T) {
    37  	sourceClass := "SequenceReferenceTestSource"
    38  	targetClass := "SequenceReferenceTestTarget"
    39  
    40  	sourceID := strfmt.UUID("96ce03ca-58ed-48e1-a0f1-51f63fa9aa12")
    41  
    42  	targetIDs := []strfmt.UUID{
    43  		"ce1a4756-b7ce-44fa-b079-45a7ec400882",
    44  		"e1edb4ff-570c-4f0b-a1a1-18af118369aa",
    45  		"25d22c70-3df0-4e5c-b8c1-a88d4d2771ef",
    46  		"6f2a0708-3e8e-4a68-9763-26c465d8bf83",
    47  		"c4dfae47-ebcf-4808-9122-1c67898ec140",
    48  		"754bd925-1900-4f93-9f5d-27631eb618bb",
    49  		"babba820-e3f5-4e8d-a354-76f2cb13fdba",
    50  		"270942da-1999-40cd-a580-a91aa144b6c0",
    51  		"a7a06618-6d50-4654-be75-2c9f639a6368",
    52  		"47ba1d2b-6b8c-4b3b-92a8-46574a069ae8",
    53  	}
    54  
    55  	t.Run("adding the required schema", func(t *testing.T) {
    56  		t.Run("target class", func(t *testing.T) {
    57  			params := clschema.NewSchemaObjectsCreateParams().WithObjectClass(
    58  				&models.Class{
    59  					Class: targetClass,
    60  					Properties: []*models.Property{
    61  						{
    62  							DataType:     schema.DataTypeText.PropString(),
    63  							Tokenization: models.PropertyTokenizationWhitespace,
    64  							Name:         "name",
    65  						},
    66  					},
    67  				},
    68  			)
    69  			resp, err := helper.Client(t).Schema.SchemaObjectsCreate(params, nil)
    70  			helper.AssertRequestOk(t, resp, err, nil)
    71  		})
    72  
    73  		t.Run("source class", func(t *testing.T) {
    74  			params := clschema.NewSchemaObjectsCreateParams().WithObjectClass(
    75  				&models.Class{
    76  					Class: sourceClass,
    77  					Properties: []*models.Property{
    78  						{
    79  							DataType: []string{targetClass},
    80  							Name:     "toTarget",
    81  						},
    82  						{
    83  							DataType:     schema.DataTypeText.PropString(),
    84  							Tokenization: models.PropertyTokenizationWhitespace,
    85  							Name:         "name",
    86  						},
    87  					},
    88  				},
    89  			)
    90  			resp, err := helper.Client(t).Schema.SchemaObjectsCreate(params, nil)
    91  			helper.AssertRequestOk(t, resp, err, nil)
    92  		})
    93  	})
    94  
    95  	t.Run("adding all objects (without referencing)", func(t *testing.T) {
    96  		t.Run("source object", func(t *testing.T) {
    97  			assertCreateObjectWithID(t, sourceClass, "", sourceID, map[string]interface{}{
    98  				"name": "Source Object",
    99  			})
   100  		})
   101  
   102  		t.Run("target objects", func(t *testing.T) {
   103  			for i, id := range targetIDs {
   104  				assertCreateObjectWithID(t, targetClass, "", id, map[string]interface{}{
   105  					"name": fmt.Sprintf("target object %d", i),
   106  				})
   107  			}
   108  		})
   109  	})
   110  
   111  	t.Run("waiting for the last added object to be present", func(t *testing.T) {
   112  		assertGetObjectEventually(t, targetIDs[len(targetIDs)-1])
   113  	})
   114  
   115  	t.Run("placing all references in succession", func(t *testing.T) {
   116  		for _, id := range targetIDs {
   117  			params := objects.NewObjectsReferencesCreateParams().
   118  				WithID(sourceID).
   119  				WithPropertyName("toTarget").
   120  				WithBody(
   121  					&models.SingleRef{
   122  						Beacon: strfmt.URI(fmt.Sprintf("weaviate://localhost/%s", id)),
   123  					},
   124  				)
   125  
   126  			res, err := helper.Client(t).Objects.ObjectsReferencesCreate(params, nil)
   127  			helper.AssertRequestOk(t, res, err, nil)
   128  		}
   129  	})
   130  
   131  	// wait for index refresh
   132  	time.Sleep(2 * time.Second) // TODO: improve through polling
   133  
   134  	t.Run("checking which refs were set", func(t *testing.T) {
   135  		source := assertGetObject(t, sourceID)
   136  
   137  		var foundIDs []strfmt.UUID
   138  		// extract IDs
   139  		for _, ref := range source.Properties.(map[string]interface{})["toTarget"].([]interface{}) {
   140  			beacon := ref.(map[string]interface{})["beacon"].(string)
   141  			chunks := strings.Split(beacon, "/")
   142  			foundIDs = append(foundIDs, strfmt.UUID(chunks[len(chunks)-1]))
   143  		}
   144  
   145  		assert.ElementsMatch(t, targetIDs, foundIDs)
   146  	})
   147  
   148  	// cleanup
   149  	helper.Client(t).Schema.SchemaObjectsDelete(
   150  		clschema.NewSchemaObjectsDeleteParams().WithClassName(sourceClass), nil)
   151  	helper.Client(t).Schema.SchemaObjectsDelete(
   152  		clschema.NewSchemaObjectsDeleteParams().WithClassName(targetClass), nil)
   153  }