Spaces:
Sleeping
Sleeping
| // _ _ | |
| // __ _____ __ ___ ___ __ _| |_ ___ | |
| // \ \ /\ / / _ \/ _` \ \ / / |/ _` | __/ _ \ | |
| // \ V V / __/ (_| |\ V /| | (_| | || __/ | |
| // \_/\_/ \___|\__,_| \_/ |_|\__,_|\__\___| | |
| // | |
| // Copyright © 2016 - 2024 Weaviate B.V. All rights reserved. | |
| // | |
| // CONTACT: [email protected] | |
| // | |
| package objects | |
| import ( | |
| "context" | |
| "errors" | |
| "testing" | |
| "time" | |
| "github.com/go-openapi/strfmt" | |
| "github.com/stretchr/testify/assert" | |
| "github.com/stretchr/testify/mock" | |
| "github.com/stretchr/testify/require" | |
| "github.com/weaviate/weaviate/entities/additional" | |
| "github.com/weaviate/weaviate/entities/models" | |
| "github.com/weaviate/weaviate/entities/schema" | |
| "github.com/weaviate/weaviate/entities/schema/crossref" | |
| "github.com/weaviate/weaviate/entities/search" | |
| "github.com/weaviate/weaviate/entities/vectorindex/hnsw" | |
| ) | |
| func Test_ReferencesAddDeprecated(t *testing.T) { | |
| cls := "Zoo" | |
| id := strfmt.UUID("my-id") | |
| t.Run("without prior refs", func(t *testing.T) { | |
| req := AddReferenceInput{ | |
| ID: id, | |
| Property: "hasAnimals", | |
| Ref: models.SingleRef{ | |
| Beacon: strfmt.URI("weaviate://localhost/d18c8e5e-a339-4c15-8af6-56b0cfe33ce7"), | |
| }, | |
| } | |
| m := newFakeGetManager(zooAnimalSchemaForTest()) | |
| m.repo.On("Exists", "Animal", mock.Anything).Return(true, nil) | |
| m.repo.On("ObjectByID", mock.Anything, mock.Anything, mock.Anything).Return(&search.Result{ | |
| ClassName: cls, | |
| Schema: map[string]interface{}{ | |
| "name": "MyZoo", | |
| }, | |
| }, nil) | |
| expectedRefProperty := "hasAnimals" | |
| source := crossref.NewSource(schema.ClassName(cls), schema.PropertyName(expectedRefProperty), id) | |
| target := crossref.New("localhost", "Animal", "d18c8e5e-a339-4c15-8af6-56b0cfe33ce7") | |
| m.repo.On("AddReference", source, target).Return(nil) | |
| m.modulesProvider.On("UsingRef2Vec", mock.Anything).Return(false) | |
| err := m.AddObjectReference(context.Background(), nil, &req, nil, "") | |
| require.Nil(t, err) | |
| m.repo.AssertExpectations(t) | |
| }) | |
| t.Run("source object missing", func(t *testing.T) { | |
| req := AddReferenceInput{ | |
| ID: strfmt.UUID("my-id"), | |
| Property: "hasAnimals", | |
| Ref: models.SingleRef{ | |
| Beacon: strfmt.URI("weaviate://localhost/d18c8e5e-a339-4c15-8af6-56b0cfe33ce7"), | |
| }, | |
| } | |
| m := newFakeGetManager(zooAnimalSchemaForTest()) | |
| m.repo.On("ObjectByID", mock.Anything, mock.Anything, mock.Anything).Return(nil, nil) | |
| err := m.AddObjectReference(context.Background(), nil, &req, nil, "") | |
| require.NotNil(t, err) | |
| if !err.BadRequest() { | |
| t.Errorf("error expected: not found error got: %v", err) | |
| } | |
| }) | |
| t.Run("source object missing", func(t *testing.T) { | |
| req := AddReferenceInput{ | |
| ID: strfmt.UUID("my-id"), | |
| Property: "hasAnimals", | |
| Ref: models.SingleRef{ | |
| Beacon: strfmt.URI("weaviate://localhost/d18c8e5e-a339-4c15-8af6-56b0cfe33ce7"), | |
| }, | |
| } | |
| m := newFakeGetManager(zooAnimalSchemaForTest()) | |
| m.repo.On("ObjectByID", mock.Anything, mock.Anything, mock.Anything).Return(nil, errors.New("any")) | |
| err := m.AddObjectReference(context.Background(), nil, &req, nil, "") | |
| require.NotNil(t, err) | |
| if err.Code != StatusInternalServerError { | |
| t.Errorf("error expected: internal error, got: %v", err) | |
| } | |
| }) | |
| } | |
| func Test_ReferenceAdd(t *testing.T) { | |
| t.Parallel() | |
| var ( | |
| cls = "Zoo" | |
| prop = "hasAnimals" | |
| id = strfmt.UUID("d18c8e5e-000-0000-0000-56b0cfe33ce7") | |
| refID = strfmt.UUID("d18c8e5e-a339-4c15-8af6-56b0cfe33ce7") | |
| uri = strfmt.URI("weaviate://localhost/d18c8e5e-a339-4c15-8af6-56b0cfe33ce7") | |
| anyErr = errors.New("any") | |
| ref = models.SingleRef{Beacon: uri} | |
| req = AddReferenceInput{ | |
| Class: cls, | |
| ID: id, | |
| Property: prop, | |
| Ref: ref, | |
| } | |
| source = crossref.NewSource(schema.ClassName(cls), schema.PropertyName(prop), id) | |
| target = crossref.New("localhost", "Animal", refID) | |
| ) | |
| tests := []struct { | |
| Name string | |
| // inputs | |
| Req AddReferenceInput | |
| // outputs | |
| ExpectedRef models.SingleRef | |
| WantCode int | |
| WantErr error | |
| SrcNotFound bool | |
| // control errors | |
| ErrAddRef error | |
| ErrTargetExists error | |
| ErrSrcExists error | |
| ErrAuth error | |
| ErrLock error | |
| ErrSchema error | |
| // Stage: 1 -> validation(), 2 -> target exists(), 3 -> source exists(), 4 -> AddReference() | |
| Stage int | |
| }{ | |
| { | |
| Name: "locking", Req: req, Stage: 0, | |
| WantCode: StatusInternalServerError, WantErr: anyErr, ErrLock: anyErr, | |
| }, | |
| { | |
| Name: "authorization", Req: req, Stage: 0, | |
| WantCode: StatusForbidden, WantErr: anyErr, ErrAuth: anyErr, | |
| }, | |
| { | |
| Name: "get schema", | |
| Req: req, Stage: 1, | |
| ErrSchema: anyErr, | |
| WantCode: StatusBadRequest, | |
| }, | |
| { | |
| Name: "empty data type", | |
| Req: AddReferenceInput{Class: cls, ID: id, Property: "emptyType", Ref: ref}, Stage: 1, | |
| WantCode: StatusBadRequest, | |
| }, | |
| { | |
| Name: "primitive data type", | |
| Req: AddReferenceInput{Class: cls, ID: id, Property: "name", Ref: ref}, Stage: 1, | |
| WantCode: StatusBadRequest, | |
| }, | |
| { | |
| Name: "unknown property", | |
| Req: AddReferenceInput{Class: cls, ID: id, Property: "unknown", Ref: ref}, Stage: 1, | |
| WantCode: StatusBadRequest, | |
| }, | |
| { | |
| Name: "valid class name", | |
| Req: AddReferenceInput{Class: "-", ID: id, Property: prop}, Stage: 1, | |
| WantCode: StatusBadRequest, | |
| }, | |
| { | |
| Name: "reserved property name", | |
| Req: AddReferenceInput{Class: cls, ID: id, Property: "_id"}, Stage: 1, | |
| WantCode: StatusBadRequest, | |
| }, | |
| { | |
| Name: "valid property name", | |
| Req: AddReferenceInput{Class: cls, ID: id, Property: "-"}, Stage: 1, | |
| WantCode: StatusBadRequest, | |
| }, | |
| {Name: "add valid reference", Req: req, Stage: 4}, | |
| { | |
| Name: "referenced class not found", Req: req, Stage: 2, | |
| WantCode: StatusBadRequest, | |
| ErrTargetExists: anyErr, | |
| WantErr: anyErr, | |
| }, | |
| { | |
| Name: "source object internal error", Req: req, Stage: 3, | |
| WantCode: StatusInternalServerError, | |
| ErrSrcExists: anyErr, | |
| WantErr: anyErr, | |
| }, | |
| { | |
| Name: "source object missing", Req: req, Stage: 3, | |
| WantCode: StatusNotFound, | |
| SrcNotFound: true, | |
| }, | |
| { | |
| Name: "internal error", Req: req, Stage: 4, | |
| WantCode: StatusInternalServerError, | |
| ErrAddRef: anyErr, | |
| WantErr: anyErr, | |
| }, | |
| } | |
| for _, tc := range tests { | |
| t.Run(tc.Name, func(t *testing.T) { | |
| m := newFakeGetManager(zooAnimalSchemaForTest()) | |
| m.authorizer.Err = tc.ErrAuth | |
| m.locks.Err = tc.ErrLock | |
| m.schemaManager.(*fakeSchemaManager).GetschemaErr = tc.ErrSchema | |
| m.modulesProvider.On("UsingRef2Vec", mock.Anything).Return(false) | |
| if tc.Stage >= 2 { | |
| m.repo.On("Exists", "Animal", refID).Return(true, tc.ErrTargetExists).Once() | |
| } | |
| if tc.Stage >= 3 { | |
| m.repo.On("Exists", tc.Req.Class, tc.Req.ID).Return(!tc.SrcNotFound, tc.ErrSrcExists).Once() | |
| } | |
| if tc.Stage >= 4 { | |
| m.repo.On("AddReference", source, target).Return(tc.ErrAddRef).Once() | |
| } | |
| err := m.AddObjectReference(context.Background(), nil, &tc.Req, nil, "") | |
| if tc.WantCode != 0 { | |
| code := 0 | |
| if err != nil { | |
| code = err.Code | |
| } | |
| if code != tc.WantCode { | |
| t.Fatalf("code expected: %v, got %v", tc.WantCode, code) | |
| } | |
| if tc.WantErr != nil && !errors.Is(err, tc.WantErr) { | |
| t.Errorf("wrapped error expected: %v, got %v", tc.WantErr, err.Err) | |
| } | |
| } | |
| m.repo.AssertExpectations(t) | |
| }) | |
| } | |
| } | |
| func Test_ReferenceUpdate(t *testing.T) { | |
| t.Parallel() | |
| var ( | |
| cls = "Zoo" | |
| prop = "hasAnimals" | |
| id = strfmt.UUID("d18c8e5e-000-0000-0000-56b0cfe33ce7") | |
| refID = strfmt.UUID("d18c8e5e-a339-4c15-8af6-56b0cfe33ce7") | |
| uri = strfmt.URI("weaviate://localhost/Animals/d18c8e5e-a339-4c15-8af6-56b0cfe33ce7") | |
| anyErr = errors.New("any") | |
| refs = models.MultipleRef{&models.SingleRef{Beacon: uri, Class: "Animals"}} | |
| req = PutReferenceInput{ | |
| Class: cls, | |
| ID: id, | |
| Property: prop, | |
| Refs: refs, | |
| } | |
| ) | |
| tests := []struct { | |
| Name string | |
| // inputs | |
| Req PutReferenceInput | |
| // outputs | |
| ExpectedRef models.SingleRef | |
| WantCode int | |
| WantErr error | |
| SrcNotFound bool | |
| // control errors | |
| ErrPutRefs error | |
| ErrTargetExists error | |
| ErrSrcExists error | |
| ErrAuth error | |
| ErrLock error | |
| ErrSchema error | |
| // Stage: 1 -> validation(), 2 -> target exists(), 3 -> PutObject() | |
| Stage int | |
| }{ | |
| { | |
| Name: "source object internal error", Req: req, | |
| WantCode: StatusInternalServerError, | |
| ErrSrcExists: anyErr, | |
| WantErr: NewErrInternal("repo: object by id: %v", anyErr), | |
| Stage: 1, | |
| }, | |
| { | |
| Name: "source object missing", Req: req, | |
| WantCode: StatusNotFound, | |
| SrcNotFound: true, | |
| Stage: 1, | |
| }, | |
| { | |
| Name: "locking", Req: req, | |
| WantCode: StatusInternalServerError, WantErr: anyErr, ErrLock: anyErr, | |
| Stage: 1, | |
| }, | |
| { | |
| Name: "authorization", Req: req, | |
| WantCode: StatusForbidden, WantErr: anyErr, ErrAuth: anyErr, | |
| Stage: 1, | |
| }, | |
| { | |
| Name: "get schema", | |
| Req: req, Stage: 1, | |
| ErrSchema: anyErr, | |
| WantCode: StatusBadRequest, | |
| }, | |
| { | |
| Name: "empty data type", | |
| Req: PutReferenceInput{Class: cls, ID: id, Property: "emptyType", Refs: refs}, Stage: 1, | |
| WantCode: StatusBadRequest, | |
| }, | |
| { | |
| Name: "primitive data type", | |
| Req: PutReferenceInput{Class: cls, ID: id, Property: "name", Refs: refs}, Stage: 1, | |
| WantCode: StatusBadRequest, | |
| }, | |
| { | |
| Name: "unknown property", | |
| Req: PutReferenceInput{Class: cls, ID: id, Property: "unknown", Refs: refs}, Stage: 1, | |
| WantCode: StatusBadRequest, | |
| }, | |
| { | |
| Name: "reserved property name", | |
| Req: PutReferenceInput{Class: cls, ID: id, Property: "_id", Refs: refs}, Stage: 1, | |
| WantCode: StatusBadRequest, | |
| }, | |
| { | |
| Name: "valid property name", | |
| Req: PutReferenceInput{Class: cls, ID: id, Property: "-", Refs: refs}, Stage: 1, | |
| WantCode: StatusBadRequest, | |
| }, | |
| {Name: "update valid reference", Req: req, Stage: 3}, | |
| { | |
| Name: "referenced class not found", Req: req, Stage: 2, | |
| WantCode: StatusBadRequest, | |
| ErrTargetExists: anyErr, | |
| WantErr: anyErr, | |
| }, | |
| { | |
| Name: "internal error", Req: req, Stage: 3, | |
| WantCode: StatusInternalServerError, | |
| ErrPutRefs: anyErr, | |
| WantErr: anyErr, | |
| }, | |
| } | |
| for _, tc := range tests { | |
| t.Run(tc.Name, func(t *testing.T) { | |
| m := newFakeGetManager(zooAnimalSchemaForTest()) | |
| m.authorizer.Err = tc.ErrAuth | |
| m.locks.Err = tc.ErrLock | |
| m.schemaManager.(*fakeSchemaManager).GetschemaErr = tc.ErrSchema | |
| srcObj := &search.Result{ | |
| ClassName: cls, | |
| Schema: map[string]interface{}{ | |
| "name": "MyZoo", | |
| }, | |
| } | |
| if tc.SrcNotFound { | |
| srcObj = nil | |
| } | |
| if tc.Stage >= 1 { | |
| m.repo.On("Object", cls, id, mock.Anything, mock.Anything, "").Return(srcObj, tc.ErrSrcExists) | |
| } | |
| if tc.Stage >= 2 { | |
| m.repo.On("Exists", "Animals", refID).Return(true, tc.ErrTargetExists).Once() | |
| } | |
| if tc.Stage >= 3 { | |
| m.repo.On("PutObject", mock.Anything, mock.Anything).Return(tc.ErrPutRefs).Once() | |
| } | |
| err := m.UpdateObjectReferences(context.Background(), nil, &tc.Req, nil, "") | |
| if tc.WantCode != 0 { | |
| code := 0 | |
| if err != nil { | |
| code = err.Code | |
| } | |
| if code != tc.WantCode { | |
| t.Fatalf("code expected: %v, got %v", tc.WantCode, code) | |
| } | |
| if tc.WantErr != nil && !errors.Is(err, tc.WantErr) { | |
| t.Errorf("wrapped error expected: %v, got %v", tc.WantErr, err.Err) | |
| } | |
| } | |
| m.repo.AssertExpectations(t) | |
| }) | |
| } | |
| } | |
| func Test_ReferenceDelete(t *testing.T) { | |
| t.Parallel() | |
| var ( | |
| cls = "Zoo" | |
| prop = "hasAnimals" | |
| id = strfmt.UUID("d18c8e5e-000-0000-0000-56b0cfe33ce7") | |
| uri = strfmt.URI("weaviate://localhost/Animal/d18c8e5e-a339-4c15-8af6-56b0cfe33ce7") | |
| anyErr = errors.New("any") | |
| ref = models.SingleRef{Beacon: uri} | |
| ref2 = &models.SingleRef{Beacon: strfmt.URI("weaviate://localhost/d18c8e5e-a339-4c15-8af6-56b0cfe33ce5")} | |
| ref3 = &models.SingleRef{Beacon: strfmt.URI("weaviate://localhost/d18c8e5e-a339-4c15-8af6-56b0cfe33ce6")} | |
| req = DeleteReferenceInput{ | |
| Class: cls, | |
| ID: id, | |
| Property: prop, | |
| Reference: ref, | |
| } | |
| ) | |
| fakeProperties := func(refs ...*models.SingleRef) map[string]interface{} { | |
| mrefs := make(models.MultipleRef, len(refs)) | |
| copy(mrefs, refs) | |
| return map[string]interface{}{ | |
| "name": "MyZoo", | |
| prop: mrefs, | |
| } | |
| } | |
| tests := []struct { | |
| Name string | |
| // inputs | |
| Req DeleteReferenceInput | |
| properties interface{} | |
| NewSrcRefsLen int | |
| // outputs | |
| ExpectedRef models.SingleRef | |
| WantCode int | |
| WantErr error | |
| SrcNotFound bool | |
| // control errors | |
| ErrPutRefs error | |
| ErrTargetExists error | |
| ErrSrcExists error | |
| ErrAuth error | |
| ErrLock error | |
| ErrSchema error | |
| // Stage: 1 -> validation(), 2 -> target exists(), 3 -> PutObject() | |
| Stage int | |
| }{ | |
| { | |
| Name: "source object internal error", Req: req, | |
| WantCode: StatusInternalServerError, | |
| ErrSrcExists: anyErr, | |
| WantErr: NewErrInternal("repo: object by id: %v", anyErr), Stage: 2, | |
| }, | |
| { | |
| Name: "source object missing", Req: req, | |
| WantCode: StatusNotFound, | |
| SrcNotFound: true, Stage: 2, | |
| }, | |
| { | |
| Name: "locking", Req: req, | |
| WantCode: StatusInternalServerError, WantErr: anyErr, ErrLock: anyErr, Stage: 2, | |
| }, | |
| { | |
| Name: "authorization", Req: req, | |
| WantCode: StatusForbidden, WantErr: anyErr, ErrAuth: anyErr, Stage: 2, | |
| }, | |
| { | |
| Name: "get schema", | |
| Req: req, Stage: 2, | |
| ErrSchema: anyErr, | |
| WantCode: StatusBadRequest, | |
| }, | |
| { | |
| Name: "empty data type", | |
| Req: DeleteReferenceInput{Class: cls, ID: id, Property: "emptyType", Reference: ref}, Stage: 2, | |
| WantCode: StatusBadRequest, | |
| }, | |
| { | |
| Name: "primitive data type", | |
| Req: DeleteReferenceInput{Class: cls, ID: id, Property: "name", Reference: ref}, Stage: 2, | |
| WantCode: StatusBadRequest, | |
| }, | |
| { | |
| Name: "unknown property", | |
| Req: DeleteReferenceInput{Class: cls, ID: id, Property: "unknown", Reference: ref}, Stage: 2, | |
| WantCode: StatusBadRequest, | |
| }, | |
| { | |
| Name: "reserved property name", | |
| Req: DeleteReferenceInput{Class: cls, ID: id, Property: "_id"}, Stage: 1, | |
| WantCode: StatusBadRequest, | |
| }, | |
| { | |
| Name: "valid property name", | |
| Req: DeleteReferenceInput{Class: cls, ID: id, Property: "-"}, Stage: 1, | |
| WantCode: StatusBadRequest, | |
| }, | |
| { | |
| Name: "delete one reference", | |
| Req: req, | |
| properties: fakeProperties(ref2, &ref, ref3), NewSrcRefsLen: 2, | |
| Stage: 3, | |
| }, | |
| { | |
| Name: "delete two references", | |
| Req: req, | |
| properties: fakeProperties(&ref, ref2, &ref), NewSrcRefsLen: 1, | |
| Stage: 3, | |
| }, | |
| { | |
| Name: "delete all references", | |
| Req: req, | |
| properties: fakeProperties(&ref, &ref), NewSrcRefsLen: 0, | |
| Stage: 3, | |
| }, | |
| { | |
| Name: "reference not found", | |
| Req: req, | |
| properties: fakeProperties(ref2, ref3), NewSrcRefsLen: 2, | |
| Stage: 2, | |
| }, | |
| { | |
| Name: "wrong reference type", | |
| Req: req, | |
| properties: map[string]interface{}{prop: "wrong reference type"}, NewSrcRefsLen: 0, | |
| Stage: 2, | |
| }, | |
| { | |
| Name: "empty properties list", | |
| Req: req, | |
| properties: nil, NewSrcRefsLen: 0, | |
| Stage: 2, | |
| }, | |
| { | |
| Name: "internal error", | |
| Req: req, | |
| properties: fakeProperties(ref2, &ref, ref3), NewSrcRefsLen: 3, | |
| Stage: 3, | |
| WantCode: StatusInternalServerError, | |
| ErrPutRefs: anyErr, | |
| WantErr: anyErr, | |
| }, | |
| } | |
| for _, tc := range tests { | |
| t.Run(tc.Name, func(t *testing.T) { | |
| m := newFakeGetManager(zooAnimalSchemaForTest()) | |
| m.authorizer.Err = tc.ErrAuth | |
| m.locks.Err = tc.ErrLock | |
| m.schemaManager.(*fakeSchemaManager).GetschemaErr = tc.ErrSchema | |
| srcObj := &search.Result{ | |
| ClassName: cls, | |
| Schema: tc.properties, | |
| } | |
| if tc.SrcNotFound { | |
| srcObj = nil | |
| } | |
| if tc.Stage >= 2 { | |
| m.repo.On("Object", cls, id, mock.Anything, mock.Anything, "").Return(srcObj, tc.ErrSrcExists) | |
| m.modulesProvider.On("UsingRef2Vec", mock.Anything).Return(false) | |
| } | |
| if tc.Stage >= 3 { | |
| m.repo.On("PutObject", mock.Anything, mock.Anything).Return(tc.ErrPutRefs).Once() | |
| } | |
| err := m.DeleteObjectReference(context.Background(), nil, &tc.Req, nil, "") | |
| if tc.WantCode != 0 { | |
| code := 0 | |
| if err != nil { | |
| code = err.Code | |
| } | |
| if code != tc.WantCode { | |
| t.Fatalf("code expected: %v, got %v", tc.WantCode, code) | |
| } | |
| if tc.WantErr != nil && !errors.Is(err, tc.WantErr) { | |
| t.Errorf("wrapped error expected: %v, got %v", tc.WantErr, err.Err) | |
| } | |
| } else if tc.properties != nil { | |
| refs, ok := srcObj.Schema.(map[string]interface{})[prop].(models.MultipleRef) | |
| if g, w := len(refs), tc.NewSrcRefsLen; ok && g != w { | |
| t.Errorf("length of source reference after deletion got:%v, want:%v", g, w) | |
| } | |
| } | |
| m.repo.AssertExpectations(t) | |
| }) | |
| } | |
| } | |
| func Test_ReferenceAdd_Ref2Vec(t *testing.T) { | |
| t.Parallel() | |
| ctx, cancel := context.WithTimeout(context.Background(), time.Minute) | |
| defer cancel() | |
| m := newFakeGetManager(articleSchemaForTest()) | |
| req := AddReferenceInput{ | |
| Class: "Article", | |
| ID: strfmt.UUID("e1a60252-c38c-496d-8e54-306e1cedc5c4"), | |
| Property: "hasParagraphs", | |
| Ref: models.SingleRef{ | |
| Beacon: strfmt.URI("weaviate://localhost/Paragraph/494a2fe5-3e4c-4e9a-a47e-afcd9814f5ea"), | |
| }, | |
| } | |
| source := crossref.NewSource(schema.ClassName(req.Class), schema.PropertyName(req.Property), req.ID) | |
| target := crossref.New("localhost", "Paragraph", "494a2fe5-3e4c-4e9a-a47e-afcd9814f5ea") | |
| tenant := "randomTenant" | |
| parent := &search.Result{ | |
| ID: strfmt.UUID("e1a60252-c38c-496d-8e54-306e1cedc5c4"), | |
| ClassName: "Article", | |
| Schema: map[string]interface{}{}, | |
| } | |
| ref1 := &search.Result{ | |
| ID: strfmt.UUID("494a2fe5-3e4c-4e9a-a47e-afcd9814f5ea"), | |
| ClassName: "Paragraph", | |
| Vector: []float32{2, 4, 6}, | |
| } | |
| m.repo.On("Exists", "Article", parent.ID).Return(true, nil) | |
| m.repo.On("Exists", "Paragraph", ref1.ID).Return(true, nil) | |
| m.repo.On("Object", "Article", parent.ID, search.SelectProperties{}, additional.Properties{}, tenant).Return(parent, nil) | |
| m.repo.On("Object", "Paragraph", ref1.ID, search.SelectProperties{}, additional.Properties{}, tenant).Return(ref1, nil) | |
| m.repo.On("AddReference", source, target).Return(nil) | |
| m.modulesProvider.On("UsingRef2Vec", mock.Anything).Return(true) | |
| m.modulesProvider.On("UpdateVector", mock.Anything, mock.AnythingOfType(FindObjectFn)). | |
| Return(ref1.Vector, nil) | |
| m.repo.On("PutObject", mock.Anything, ref1.Vector).Return(nil) | |
| err := m.Manager.AddObjectReference(ctx, nil, &req, nil, tenant) | |
| assert.Nil(t, err) | |
| } | |
| func Test_ReferenceDelete_Ref2Vec(t *testing.T) { | |
| t.Parallel() | |
| ctx, cancel := context.WithTimeout(context.Background(), time.Minute) | |
| defer cancel() | |
| m := newFakeGetManager(articleSchemaForTest()) | |
| req := DeleteReferenceInput{ | |
| Class: "Article", | |
| ID: strfmt.UUID("e1a60252-c38c-496d-8e54-306e1cedc5c4"), | |
| Property: "hasParagraphs", | |
| Reference: models.SingleRef{ | |
| Beacon: strfmt.URI("weaviate://localhost/Paragraph/494a2fe5-3e4c-4e9a-a47e-afcd9814f5ea"), | |
| }, | |
| } | |
| tenant := "randomTenant" | |
| parent := &search.Result{ | |
| ID: strfmt.UUID("e1a60252-c38c-496d-8e54-306e1cedc5c4"), | |
| ClassName: "Article", | |
| Schema: map[string]interface{}{}, | |
| } | |
| ref1 := &search.Result{ | |
| ID: strfmt.UUID("494a2fe5-3e4c-4e9a-a47e-afcd9814f5ea"), | |
| ClassName: "Paragraph", | |
| Vector: []float32{2, 4, 6}, | |
| } | |
| m.repo.On("Exists", "Article", parent.ID).Return(true, nil) | |
| m.repo.On("Exists", "Paragraph", ref1.ID).Return(true, nil) | |
| m.repo.On("Object", req.Class, req.ID, search.SelectProperties{}, additional.Properties{}, tenant).Return(parent, nil) | |
| m.repo.On("PutObject", parent.Object(), []float32(nil)).Return(nil) | |
| m.modulesProvider.On("UsingRef2Vec", mock.Anything).Return(true) | |
| err := m.Manager.DeleteObjectReference(ctx, nil, &req, nil, tenant) | |
| assert.Nil(t, err) | |
| } | |
| func articleSchemaForTest() schema.Schema { | |
| return schema.Schema{ | |
| Objects: &models.Schema{ | |
| Classes: []*models.Class{ | |
| { | |
| Class: "Paragraph", | |
| VectorIndexConfig: hnsw.UserConfig{}, | |
| Properties: []*models.Property{ | |
| { | |
| Name: "contents", | |
| DataType: []string{"text"}, | |
| }, | |
| }, | |
| }, | |
| { | |
| Class: "Article", | |
| VectorIndexConfig: hnsw.UserConfig{}, | |
| Properties: []*models.Property{ | |
| { | |
| Name: "title", | |
| DataType: schema.DataTypeText.PropString(), | |
| Tokenization: models.PropertyTokenizationWhitespace, | |
| }, | |
| { | |
| Name: "hasParagraphs", | |
| DataType: []string{"Paragraph"}, | |
| }, | |
| }, | |
| Vectorizer: "ref2vec-centroid", | |
| ModuleConfig: map[string]interface{}{ | |
| "ref2vec-centroid": map[string]interface{}{ | |
| "referenceProperties": []string{"hasParagraphs"}, | |
| "method": "mean", | |
| }, | |
| }, | |
| }, | |
| }, | |
| }, | |
| } | |
| } | |
| func zooAnimalSchemaForTest() schema.Schema { | |
| return schema.Schema{ | |
| Objects: &models.Schema{ | |
| Classes: []*models.Class{ | |
| { | |
| Class: "ZooAction", | |
| VectorIndexConfig: hnsw.UserConfig{}, | |
| Properties: []*models.Property{ | |
| { | |
| Name: "name", | |
| DataType: schema.DataTypeText.PropString(), | |
| Tokenization: models.PropertyTokenizationWhitespace, | |
| }, | |
| { | |
| Name: "area", | |
| DataType: []string{"number"}, | |
| }, | |
| { | |
| Name: "employees", | |
| DataType: []string{"int"}, | |
| }, | |
| { | |
| Name: "located", | |
| DataType: []string{"geoCoordinates"}, | |
| }, | |
| { | |
| Name: "foundedIn", | |
| DataType: []string{"date"}, | |
| }, | |
| { | |
| Name: "hasAnimals", | |
| DataType: []string{"AnimalAction"}, | |
| }, | |
| }, | |
| }, | |
| { | |
| Class: "AnimalAction", | |
| VectorIndexConfig: hnsw.UserConfig{}, | |
| Properties: []*models.Property{ | |
| { | |
| Name: "name", | |
| DataType: schema.DataTypeText.PropString(), | |
| Tokenization: models.PropertyTokenizationWhitespace, | |
| }, | |
| }, | |
| }, | |
| { | |
| Class: "Zoo", | |
| VectorIndexConfig: hnsw.UserConfig{}, | |
| Properties: []*models.Property{ | |
| { | |
| Name: "name", | |
| DataType: schema.DataTypeText.PropString(), | |
| Tokenization: models.PropertyTokenizationWhitespace, | |
| }, | |
| { | |
| Name: "area", | |
| DataType: []string{"number"}, | |
| }, | |
| { | |
| Name: "employees", | |
| DataType: []string{"int"}, | |
| }, | |
| { | |
| Name: "located", | |
| DataType: []string{"geoCoordinates"}, | |
| }, | |
| { | |
| Name: "foundedIn", | |
| DataType: []string{"date"}, | |
| }, | |
| { | |
| Name: "hasAnimals", | |
| DataType: []string{"Animal"}, | |
| }, | |
| { | |
| Name: "emptyType", | |
| DataType: []string{""}, | |
| }, | |
| }, | |
| }, | |
| { | |
| Class: "Animal", | |
| VectorIndexConfig: hnsw.UserConfig{}, | |
| Properties: []*models.Property{ | |
| { | |
| Name: "name", | |
| DataType: schema.DataTypeText.PropString(), | |
| Tokenization: models.PropertyTokenizationWhitespace, | |
| }, | |
| }, | |
| }, | |
| { | |
| Class: "NotVectorized", | |
| VectorIndexConfig: hnsw.UserConfig{}, | |
| Properties: []*models.Property{ | |
| { | |
| Name: "description", | |
| DataType: []string{"text"}, | |
| }, | |
| }, | |
| Vectorizer: "none", | |
| }, | |
| }, | |
| }, | |
| } | |
| } | |