github.com/weaviate/weaviate@v1.24.6/usecases/objects/references_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 objects 13 14 import ( 15 "context" 16 "errors" 17 "testing" 18 "time" 19 20 "github.com/go-openapi/strfmt" 21 "github.com/stretchr/testify/assert" 22 "github.com/stretchr/testify/mock" 23 "github.com/stretchr/testify/require" 24 "github.com/weaviate/weaviate/entities/additional" 25 "github.com/weaviate/weaviate/entities/models" 26 "github.com/weaviate/weaviate/entities/schema" 27 "github.com/weaviate/weaviate/entities/schema/crossref" 28 "github.com/weaviate/weaviate/entities/search" 29 "github.com/weaviate/weaviate/entities/vectorindex/hnsw" 30 ) 31 32 func Test_ReferencesAddDeprecated(t *testing.T) { 33 cls := "Zoo" 34 id := strfmt.UUID("my-id") 35 t.Run("without prior refs", func(t *testing.T) { 36 req := AddReferenceInput{ 37 ID: id, 38 Property: "hasAnimals", 39 Ref: models.SingleRef{ 40 Beacon: strfmt.URI("weaviate://localhost/d18c8e5e-a339-4c15-8af6-56b0cfe33ce7"), 41 }, 42 } 43 m := newFakeGetManager(zooAnimalSchemaForTest()) 44 m.repo.On("Exists", "Animal", mock.Anything).Return(true, nil) 45 m.repo.On("ObjectByID", mock.Anything, mock.Anything, mock.Anything).Return(&search.Result{ 46 ClassName: cls, 47 Schema: map[string]interface{}{ 48 "name": "MyZoo", 49 }, 50 }, nil) 51 expectedRefProperty := "hasAnimals" 52 source := crossref.NewSource(schema.ClassName(cls), schema.PropertyName(expectedRefProperty), id) 53 target := crossref.New("localhost", "Animal", "d18c8e5e-a339-4c15-8af6-56b0cfe33ce7") 54 m.repo.On("AddReference", source, target).Return(nil) 55 m.modulesProvider.On("UsingRef2Vec", mock.Anything).Return(false) 56 57 err := m.AddObjectReference(context.Background(), nil, &req, nil, "") 58 require.Nil(t, err) 59 m.repo.AssertExpectations(t) 60 }) 61 t.Run("source object missing", func(t *testing.T) { 62 req := AddReferenceInput{ 63 ID: strfmt.UUID("my-id"), 64 Property: "hasAnimals", 65 Ref: models.SingleRef{ 66 Beacon: strfmt.URI("weaviate://localhost/d18c8e5e-a339-4c15-8af6-56b0cfe33ce7"), 67 }, 68 } 69 m := newFakeGetManager(zooAnimalSchemaForTest()) 70 m.repo.On("ObjectByID", mock.Anything, mock.Anything, mock.Anything).Return(nil, nil) 71 err := m.AddObjectReference(context.Background(), nil, &req, nil, "") 72 require.NotNil(t, err) 73 if !err.BadRequest() { 74 t.Errorf("error expected: not found error got: %v", err) 75 } 76 }) 77 t.Run("source object missing", func(t *testing.T) { 78 req := AddReferenceInput{ 79 ID: strfmt.UUID("my-id"), 80 Property: "hasAnimals", 81 Ref: models.SingleRef{ 82 Beacon: strfmt.URI("weaviate://localhost/d18c8e5e-a339-4c15-8af6-56b0cfe33ce7"), 83 }, 84 } 85 m := newFakeGetManager(zooAnimalSchemaForTest()) 86 m.repo.On("ObjectByID", mock.Anything, mock.Anything, mock.Anything).Return(nil, errors.New("any")) 87 err := m.AddObjectReference(context.Background(), nil, &req, nil, "") 88 require.NotNil(t, err) 89 if err.Code != StatusInternalServerError { 90 t.Errorf("error expected: internal error, got: %v", err) 91 } 92 }) 93 } 94 95 func Test_ReferenceAdd(t *testing.T) { 96 t.Parallel() 97 var ( 98 cls = "Zoo" 99 prop = "hasAnimals" 100 id = strfmt.UUID("d18c8e5e-000-0000-0000-56b0cfe33ce7") 101 refID = strfmt.UUID("d18c8e5e-a339-4c15-8af6-56b0cfe33ce7") 102 uri = strfmt.URI("weaviate://localhost/d18c8e5e-a339-4c15-8af6-56b0cfe33ce7") 103 anyErr = errors.New("any") 104 ref = models.SingleRef{Beacon: uri} 105 req = AddReferenceInput{ 106 Class: cls, 107 ID: id, 108 Property: prop, 109 Ref: ref, 110 } 111 source = crossref.NewSource(schema.ClassName(cls), schema.PropertyName(prop), id) 112 target = crossref.New("localhost", "Animal", refID) 113 ) 114 115 tests := []struct { 116 Name string 117 // inputs 118 Req AddReferenceInput 119 120 // outputs 121 ExpectedRef models.SingleRef 122 WantCode int 123 WantErr error 124 SrcNotFound bool 125 // control errors 126 ErrAddRef error 127 ErrTargetExists error 128 ErrSrcExists error 129 ErrAuth error 130 ErrLock error 131 ErrSchema error 132 // Stage: 1 -> validation(), 2 -> target exists(), 3 -> source exists(), 4 -> AddReference() 133 Stage int 134 }{ 135 { 136 Name: "locking", Req: req, Stage: 0, 137 WantCode: StatusInternalServerError, WantErr: anyErr, ErrLock: anyErr, 138 }, 139 { 140 Name: "authorization", Req: req, Stage: 0, 141 WantCode: StatusForbidden, WantErr: anyErr, ErrAuth: anyErr, 142 }, 143 { 144 Name: "get schema", 145 Req: req, Stage: 1, 146 ErrSchema: anyErr, 147 WantCode: StatusBadRequest, 148 }, 149 { 150 Name: "empty data type", 151 Req: AddReferenceInput{Class: cls, ID: id, Property: "emptyType", Ref: ref}, Stage: 1, 152 WantCode: StatusBadRequest, 153 }, 154 { 155 Name: "primitive data type", 156 Req: AddReferenceInput{Class: cls, ID: id, Property: "name", Ref: ref}, Stage: 1, 157 WantCode: StatusBadRequest, 158 }, 159 { 160 Name: "unknown property", 161 Req: AddReferenceInput{Class: cls, ID: id, Property: "unknown", Ref: ref}, Stage: 1, 162 WantCode: StatusBadRequest, 163 }, 164 { 165 Name: "valid class name", 166 Req: AddReferenceInput{Class: "-", ID: id, Property: prop}, Stage: 1, 167 WantCode: StatusBadRequest, 168 }, 169 { 170 Name: "reserved property name", 171 Req: AddReferenceInput{Class: cls, ID: id, Property: "_id"}, Stage: 1, 172 WantCode: StatusBadRequest, 173 }, 174 { 175 Name: "valid property name", 176 Req: AddReferenceInput{Class: cls, ID: id, Property: "-"}, Stage: 1, 177 WantCode: StatusBadRequest, 178 }, 179 180 {Name: "add valid reference", Req: req, Stage: 4}, 181 { 182 Name: "referenced class not found", Req: req, Stage: 2, 183 WantCode: StatusBadRequest, 184 ErrTargetExists: anyErr, 185 WantErr: anyErr, 186 }, 187 { 188 Name: "source object internal error", Req: req, Stage: 3, 189 WantCode: StatusInternalServerError, 190 ErrSrcExists: anyErr, 191 WantErr: anyErr, 192 }, 193 { 194 Name: "source object missing", Req: req, Stage: 3, 195 WantCode: StatusNotFound, 196 SrcNotFound: true, 197 }, 198 { 199 Name: "internal error", Req: req, Stage: 4, 200 WantCode: StatusInternalServerError, 201 ErrAddRef: anyErr, 202 WantErr: anyErr, 203 }, 204 } 205 206 for _, tc := range tests { 207 t.Run(tc.Name, func(t *testing.T) { 208 m := newFakeGetManager(zooAnimalSchemaForTest()) 209 m.authorizer.Err = tc.ErrAuth 210 m.locks.Err = tc.ErrLock 211 m.schemaManager.(*fakeSchemaManager).GetschemaErr = tc.ErrSchema 212 m.modulesProvider.On("UsingRef2Vec", mock.Anything).Return(false) 213 if tc.Stage >= 2 { 214 m.repo.On("Exists", "Animal", refID).Return(true, tc.ErrTargetExists).Once() 215 } 216 if tc.Stage >= 3 { 217 m.repo.On("Exists", tc.Req.Class, tc.Req.ID).Return(!tc.SrcNotFound, tc.ErrSrcExists).Once() 218 } 219 if tc.Stage >= 4 { 220 m.repo.On("AddReference", source, target).Return(tc.ErrAddRef).Once() 221 } 222 223 err := m.AddObjectReference(context.Background(), nil, &tc.Req, nil, "") 224 if tc.WantCode != 0 { 225 code := 0 226 if err != nil { 227 code = err.Code 228 } 229 if code != tc.WantCode { 230 t.Fatalf("code expected: %v, got %v", tc.WantCode, code) 231 } 232 233 if tc.WantErr != nil && !errors.Is(err, tc.WantErr) { 234 t.Errorf("wrapped error expected: %v, got %v", tc.WantErr, err.Err) 235 } 236 237 } 238 m.repo.AssertExpectations(t) 239 }) 240 } 241 } 242 243 func Test_ReferenceUpdate(t *testing.T) { 244 t.Parallel() 245 var ( 246 cls = "Zoo" 247 prop = "hasAnimals" 248 id = strfmt.UUID("d18c8e5e-000-0000-0000-56b0cfe33ce7") 249 refID = strfmt.UUID("d18c8e5e-a339-4c15-8af6-56b0cfe33ce7") 250 uri = strfmt.URI("weaviate://localhost/Animals/d18c8e5e-a339-4c15-8af6-56b0cfe33ce7") 251 anyErr = errors.New("any") 252 refs = models.MultipleRef{&models.SingleRef{Beacon: uri, Class: "Animals"}} 253 req = PutReferenceInput{ 254 Class: cls, 255 ID: id, 256 Property: prop, 257 Refs: refs, 258 } 259 ) 260 261 tests := []struct { 262 Name string 263 // inputs 264 Req PutReferenceInput 265 266 // outputs 267 ExpectedRef models.SingleRef 268 WantCode int 269 WantErr error 270 SrcNotFound bool 271 // control errors 272 ErrPutRefs error 273 ErrTargetExists error 274 ErrSrcExists error 275 ErrAuth error 276 ErrLock error 277 ErrSchema error 278 // Stage: 1 -> validation(), 2 -> target exists(), 3 -> PutObject() 279 Stage int 280 }{ 281 { 282 Name: "source object internal error", Req: req, 283 WantCode: StatusInternalServerError, 284 ErrSrcExists: anyErr, 285 WantErr: NewErrInternal("repo: object by id: %v", anyErr), 286 Stage: 1, 287 }, 288 { 289 Name: "source object missing", Req: req, 290 WantCode: StatusNotFound, 291 SrcNotFound: true, 292 Stage: 1, 293 }, 294 { 295 Name: "locking", Req: req, 296 WantCode: StatusInternalServerError, WantErr: anyErr, ErrLock: anyErr, 297 Stage: 1, 298 }, 299 { 300 Name: "authorization", Req: req, 301 WantCode: StatusForbidden, WantErr: anyErr, ErrAuth: anyErr, 302 Stage: 1, 303 }, 304 { 305 Name: "get schema", 306 Req: req, Stage: 1, 307 ErrSchema: anyErr, 308 WantCode: StatusBadRequest, 309 }, 310 { 311 Name: "empty data type", 312 Req: PutReferenceInput{Class: cls, ID: id, Property: "emptyType", Refs: refs}, Stage: 1, 313 WantCode: StatusBadRequest, 314 }, 315 { 316 Name: "primitive data type", 317 Req: PutReferenceInput{Class: cls, ID: id, Property: "name", Refs: refs}, Stage: 1, 318 WantCode: StatusBadRequest, 319 }, 320 { 321 Name: "unknown property", 322 Req: PutReferenceInput{Class: cls, ID: id, Property: "unknown", Refs: refs}, Stage: 1, 323 WantCode: StatusBadRequest, 324 }, 325 { 326 Name: "reserved property name", 327 Req: PutReferenceInput{Class: cls, ID: id, Property: "_id", Refs: refs}, Stage: 1, 328 WantCode: StatusBadRequest, 329 }, 330 { 331 Name: "valid property name", 332 Req: PutReferenceInput{Class: cls, ID: id, Property: "-", Refs: refs}, Stage: 1, 333 WantCode: StatusBadRequest, 334 }, 335 336 {Name: "update valid reference", Req: req, Stage: 3}, 337 { 338 Name: "referenced class not found", Req: req, Stage: 2, 339 WantCode: StatusBadRequest, 340 ErrTargetExists: anyErr, 341 WantErr: anyErr, 342 }, 343 { 344 Name: "internal error", Req: req, Stage: 3, 345 WantCode: StatusInternalServerError, 346 ErrPutRefs: anyErr, 347 WantErr: anyErr, 348 }, 349 } 350 351 for _, tc := range tests { 352 t.Run(tc.Name, func(t *testing.T) { 353 m := newFakeGetManager(zooAnimalSchemaForTest()) 354 m.authorizer.Err = tc.ErrAuth 355 m.locks.Err = tc.ErrLock 356 m.schemaManager.(*fakeSchemaManager).GetschemaErr = tc.ErrSchema 357 srcObj := &search.Result{ 358 ClassName: cls, 359 Schema: map[string]interface{}{ 360 "name": "MyZoo", 361 }, 362 } 363 if tc.SrcNotFound { 364 srcObj = nil 365 } 366 if tc.Stage >= 1 { 367 m.repo.On("Object", cls, id, mock.Anything, mock.Anything, "").Return(srcObj, tc.ErrSrcExists) 368 } 369 370 if tc.Stage >= 2 { 371 m.repo.On("Exists", "Animals", refID).Return(true, tc.ErrTargetExists).Once() 372 } 373 374 if tc.Stage >= 3 { 375 m.repo.On("PutObject", mock.Anything, mock.Anything).Return(tc.ErrPutRefs).Once() 376 } 377 378 err := m.UpdateObjectReferences(context.Background(), nil, &tc.Req, nil, "") 379 if tc.WantCode != 0 { 380 code := 0 381 if err != nil { 382 code = err.Code 383 } 384 if code != tc.WantCode { 385 t.Fatalf("code expected: %v, got %v", tc.WantCode, code) 386 } 387 388 if tc.WantErr != nil && !errors.Is(err, tc.WantErr) { 389 t.Errorf("wrapped error expected: %v, got %v", tc.WantErr, err.Err) 390 } 391 392 } 393 m.repo.AssertExpectations(t) 394 }) 395 } 396 } 397 398 func Test_ReferenceDelete(t *testing.T) { 399 t.Parallel() 400 var ( 401 cls = "Zoo" 402 prop = "hasAnimals" 403 id = strfmt.UUID("d18c8e5e-000-0000-0000-56b0cfe33ce7") 404 uri = strfmt.URI("weaviate://localhost/Animal/d18c8e5e-a339-4c15-8af6-56b0cfe33ce7") 405 anyErr = errors.New("any") 406 ref = models.SingleRef{Beacon: uri} 407 ref2 = &models.SingleRef{Beacon: strfmt.URI("weaviate://localhost/d18c8e5e-a339-4c15-8af6-56b0cfe33ce5")} 408 ref3 = &models.SingleRef{Beacon: strfmt.URI("weaviate://localhost/d18c8e5e-a339-4c15-8af6-56b0cfe33ce6")} 409 req = DeleteReferenceInput{ 410 Class: cls, 411 ID: id, 412 Property: prop, 413 Reference: ref, 414 } 415 ) 416 417 fakeProperties := func(refs ...*models.SingleRef) map[string]interface{} { 418 mrefs := make(models.MultipleRef, len(refs)) 419 copy(mrefs, refs) 420 return map[string]interface{}{ 421 "name": "MyZoo", 422 prop: mrefs, 423 } 424 } 425 426 tests := []struct { 427 Name string 428 // inputs 429 Req DeleteReferenceInput 430 properties interface{} 431 NewSrcRefsLen int 432 // outputs 433 ExpectedRef models.SingleRef 434 WantCode int 435 WantErr error 436 SrcNotFound bool 437 // control errors 438 ErrPutRefs error 439 ErrTargetExists error 440 ErrSrcExists error 441 ErrAuth error 442 ErrLock error 443 ErrSchema error 444 // Stage: 1 -> validation(), 2 -> target exists(), 3 -> PutObject() 445 Stage int 446 }{ 447 { 448 Name: "source object internal error", Req: req, 449 WantCode: StatusInternalServerError, 450 ErrSrcExists: anyErr, 451 WantErr: NewErrInternal("repo: object by id: %v", anyErr), Stage: 2, 452 }, 453 { 454 Name: "source object missing", Req: req, 455 WantCode: StatusNotFound, 456 SrcNotFound: true, Stage: 2, 457 }, 458 { 459 Name: "locking", Req: req, 460 WantCode: StatusInternalServerError, WantErr: anyErr, ErrLock: anyErr, Stage: 2, 461 }, 462 { 463 Name: "authorization", Req: req, 464 WantCode: StatusForbidden, WantErr: anyErr, ErrAuth: anyErr, Stage: 2, 465 }, 466 { 467 Name: "get schema", 468 Req: req, Stage: 2, 469 ErrSchema: anyErr, 470 WantCode: StatusBadRequest, 471 }, 472 { 473 Name: "empty data type", 474 Req: DeleteReferenceInput{Class: cls, ID: id, Property: "emptyType", Reference: ref}, Stage: 2, 475 WantCode: StatusBadRequest, 476 }, 477 { 478 Name: "primitive data type", 479 Req: DeleteReferenceInput{Class: cls, ID: id, Property: "name", Reference: ref}, Stage: 2, 480 WantCode: StatusBadRequest, 481 }, 482 { 483 Name: "unknown property", 484 Req: DeleteReferenceInput{Class: cls, ID: id, Property: "unknown", Reference: ref}, Stage: 2, 485 WantCode: StatusBadRequest, 486 }, 487 { 488 Name: "reserved property name", 489 Req: DeleteReferenceInput{Class: cls, ID: id, Property: "_id"}, Stage: 1, 490 WantCode: StatusBadRequest, 491 }, 492 { 493 Name: "valid property name", 494 Req: DeleteReferenceInput{Class: cls, ID: id, Property: "-"}, Stage: 1, 495 WantCode: StatusBadRequest, 496 }, 497 { 498 Name: "delete one reference", 499 Req: req, 500 properties: fakeProperties(ref2, &ref, ref3), NewSrcRefsLen: 2, 501 Stage: 3, 502 }, 503 { 504 Name: "delete two references", 505 Req: req, 506 properties: fakeProperties(&ref, ref2, &ref), NewSrcRefsLen: 1, 507 Stage: 3, 508 }, 509 { 510 Name: "delete all references", 511 Req: req, 512 properties: fakeProperties(&ref, &ref), NewSrcRefsLen: 0, 513 Stage: 3, 514 }, 515 { 516 Name: "reference not found", 517 Req: req, 518 properties: fakeProperties(ref2, ref3), NewSrcRefsLen: 2, 519 Stage: 2, 520 }, 521 { 522 Name: "wrong reference type", 523 Req: req, 524 properties: map[string]interface{}{prop: "wrong reference type"}, NewSrcRefsLen: 0, 525 Stage: 2, 526 }, 527 { 528 Name: "empty properties list", 529 Req: req, 530 properties: nil, NewSrcRefsLen: 0, 531 Stage: 2, 532 }, 533 { 534 Name: "internal error", 535 Req: req, 536 properties: fakeProperties(ref2, &ref, ref3), NewSrcRefsLen: 3, 537 Stage: 3, 538 WantCode: StatusInternalServerError, 539 ErrPutRefs: anyErr, 540 WantErr: anyErr, 541 }, 542 } 543 544 for _, tc := range tests { 545 t.Run(tc.Name, func(t *testing.T) { 546 m := newFakeGetManager(zooAnimalSchemaForTest()) 547 m.authorizer.Err = tc.ErrAuth 548 m.locks.Err = tc.ErrLock 549 m.schemaManager.(*fakeSchemaManager).GetschemaErr = tc.ErrSchema 550 srcObj := &search.Result{ 551 ClassName: cls, 552 Schema: tc.properties, 553 } 554 if tc.SrcNotFound { 555 srcObj = nil 556 } 557 if tc.Stage >= 2 { 558 m.repo.On("Object", cls, id, mock.Anything, mock.Anything, "").Return(srcObj, tc.ErrSrcExists) 559 m.modulesProvider.On("UsingRef2Vec", mock.Anything).Return(false) 560 } 561 562 if tc.Stage >= 3 { 563 m.repo.On("PutObject", mock.Anything, mock.Anything).Return(tc.ErrPutRefs).Once() 564 } 565 566 err := m.DeleteObjectReference(context.Background(), nil, &tc.Req, nil, "") 567 if tc.WantCode != 0 { 568 code := 0 569 if err != nil { 570 code = err.Code 571 } 572 if code != tc.WantCode { 573 t.Fatalf("code expected: %v, got %v", tc.WantCode, code) 574 } 575 576 if tc.WantErr != nil && !errors.Is(err, tc.WantErr) { 577 t.Errorf("wrapped error expected: %v, got %v", tc.WantErr, err.Err) 578 } 579 580 } else if tc.properties != nil { 581 refs, ok := srcObj.Schema.(map[string]interface{})[prop].(models.MultipleRef) 582 if g, w := len(refs), tc.NewSrcRefsLen; ok && g != w { 583 t.Errorf("length of source reference after deletion got:%v, want:%v", g, w) 584 } 585 586 } 587 588 m.repo.AssertExpectations(t) 589 }) 590 } 591 } 592 593 func Test_ReferenceAdd_Ref2Vec(t *testing.T) { 594 t.Parallel() 595 596 ctx, cancel := context.WithTimeout(context.Background(), time.Minute) 597 defer cancel() 598 599 m := newFakeGetManager(articleSchemaForTest()) 600 601 req := AddReferenceInput{ 602 Class: "Article", 603 ID: strfmt.UUID("e1a60252-c38c-496d-8e54-306e1cedc5c4"), 604 Property: "hasParagraphs", 605 Ref: models.SingleRef{ 606 Beacon: strfmt.URI("weaviate://localhost/Paragraph/494a2fe5-3e4c-4e9a-a47e-afcd9814f5ea"), 607 }, 608 } 609 610 source := crossref.NewSource(schema.ClassName(req.Class), schema.PropertyName(req.Property), req.ID) 611 target := crossref.New("localhost", "Paragraph", "494a2fe5-3e4c-4e9a-a47e-afcd9814f5ea") 612 tenant := "randomTenant" 613 614 parent := &search.Result{ 615 ID: strfmt.UUID("e1a60252-c38c-496d-8e54-306e1cedc5c4"), 616 ClassName: "Article", 617 Schema: map[string]interface{}{}, 618 } 619 620 ref1 := &search.Result{ 621 ID: strfmt.UUID("494a2fe5-3e4c-4e9a-a47e-afcd9814f5ea"), 622 ClassName: "Paragraph", 623 Vector: []float32{2, 4, 6}, 624 } 625 626 m.repo.On("Exists", "Article", parent.ID).Return(true, nil) 627 m.repo.On("Exists", "Paragraph", ref1.ID).Return(true, nil) 628 m.repo.On("Object", "Article", parent.ID, search.SelectProperties{}, additional.Properties{}, tenant).Return(parent, nil) 629 m.repo.On("Object", "Paragraph", ref1.ID, search.SelectProperties{}, additional.Properties{}, tenant).Return(ref1, nil) 630 m.repo.On("AddReference", source, target).Return(nil) 631 m.modulesProvider.On("UsingRef2Vec", mock.Anything).Return(true) 632 m.modulesProvider.On("UpdateVector", mock.Anything, mock.AnythingOfType(FindObjectFn)). 633 Return(ref1.Vector, nil) 634 m.repo.On("PutObject", mock.Anything, ref1.Vector).Return(nil) 635 err := m.Manager.AddObjectReference(ctx, nil, &req, nil, tenant) 636 assert.Nil(t, err) 637 } 638 639 func Test_ReferenceDelete_Ref2Vec(t *testing.T) { 640 t.Parallel() 641 642 ctx, cancel := context.WithTimeout(context.Background(), time.Minute) 643 defer cancel() 644 645 m := newFakeGetManager(articleSchemaForTest()) 646 647 req := DeleteReferenceInput{ 648 Class: "Article", 649 ID: strfmt.UUID("e1a60252-c38c-496d-8e54-306e1cedc5c4"), 650 Property: "hasParagraphs", 651 Reference: models.SingleRef{ 652 Beacon: strfmt.URI("weaviate://localhost/Paragraph/494a2fe5-3e4c-4e9a-a47e-afcd9814f5ea"), 653 }, 654 } 655 656 tenant := "randomTenant" 657 658 parent := &search.Result{ 659 ID: strfmt.UUID("e1a60252-c38c-496d-8e54-306e1cedc5c4"), 660 ClassName: "Article", 661 Schema: map[string]interface{}{}, 662 } 663 664 ref1 := &search.Result{ 665 ID: strfmt.UUID("494a2fe5-3e4c-4e9a-a47e-afcd9814f5ea"), 666 ClassName: "Paragraph", 667 Vector: []float32{2, 4, 6}, 668 } 669 670 m.repo.On("Exists", "Article", parent.ID).Return(true, nil) 671 m.repo.On("Exists", "Paragraph", ref1.ID).Return(true, nil) 672 m.repo.On("Object", req.Class, req.ID, search.SelectProperties{}, additional.Properties{}, tenant).Return(parent, nil) 673 m.repo.On("PutObject", parent.Object(), []float32(nil)).Return(nil) 674 m.modulesProvider.On("UsingRef2Vec", mock.Anything).Return(true) 675 676 err := m.Manager.DeleteObjectReference(ctx, nil, &req, nil, tenant) 677 assert.Nil(t, err) 678 } 679 680 func articleSchemaForTest() schema.Schema { 681 return schema.Schema{ 682 Objects: &models.Schema{ 683 Classes: []*models.Class{ 684 { 685 Class: "Paragraph", 686 VectorIndexConfig: hnsw.UserConfig{}, 687 Properties: []*models.Property{ 688 { 689 Name: "contents", 690 DataType: []string{"text"}, 691 }, 692 }, 693 }, 694 { 695 Class: "Article", 696 VectorIndexConfig: hnsw.UserConfig{}, 697 Properties: []*models.Property{ 698 { 699 Name: "title", 700 DataType: schema.DataTypeText.PropString(), 701 Tokenization: models.PropertyTokenizationWhitespace, 702 }, 703 { 704 Name: "hasParagraphs", 705 DataType: []string{"Paragraph"}, 706 }, 707 }, 708 Vectorizer: "ref2vec-centroid", 709 ModuleConfig: map[string]interface{}{ 710 "ref2vec-centroid": map[string]interface{}{ 711 "referenceProperties": []string{"hasParagraphs"}, 712 "method": "mean", 713 }, 714 }, 715 }, 716 }, 717 }, 718 } 719 } 720 721 func zooAnimalSchemaForTest() schema.Schema { 722 return schema.Schema{ 723 Objects: &models.Schema{ 724 Classes: []*models.Class{ 725 { 726 Class: "ZooAction", 727 VectorIndexConfig: hnsw.UserConfig{}, 728 Properties: []*models.Property{ 729 { 730 Name: "name", 731 DataType: schema.DataTypeText.PropString(), 732 Tokenization: models.PropertyTokenizationWhitespace, 733 }, 734 { 735 Name: "area", 736 DataType: []string{"number"}, 737 }, 738 { 739 Name: "employees", 740 DataType: []string{"int"}, 741 }, 742 { 743 Name: "located", 744 DataType: []string{"geoCoordinates"}, 745 }, 746 { 747 Name: "foundedIn", 748 DataType: []string{"date"}, 749 }, 750 { 751 Name: "hasAnimals", 752 DataType: []string{"AnimalAction"}, 753 }, 754 }, 755 }, 756 { 757 Class: "AnimalAction", 758 VectorIndexConfig: hnsw.UserConfig{}, 759 Properties: []*models.Property{ 760 { 761 Name: "name", 762 DataType: schema.DataTypeText.PropString(), 763 Tokenization: models.PropertyTokenizationWhitespace, 764 }, 765 }, 766 }, 767 { 768 Class: "Zoo", 769 VectorIndexConfig: hnsw.UserConfig{}, 770 Properties: []*models.Property{ 771 { 772 Name: "name", 773 DataType: schema.DataTypeText.PropString(), 774 Tokenization: models.PropertyTokenizationWhitespace, 775 }, 776 { 777 Name: "area", 778 DataType: []string{"number"}, 779 }, 780 { 781 Name: "employees", 782 DataType: []string{"int"}, 783 }, 784 { 785 Name: "located", 786 DataType: []string{"geoCoordinates"}, 787 }, 788 { 789 Name: "foundedIn", 790 DataType: []string{"date"}, 791 }, 792 { 793 Name: "hasAnimals", 794 DataType: []string{"Animal"}, 795 }, 796 { 797 Name: "emptyType", 798 DataType: []string{""}, 799 }, 800 }, 801 }, 802 { 803 Class: "Animal", 804 VectorIndexConfig: hnsw.UserConfig{}, 805 Properties: []*models.Property{ 806 { 807 Name: "name", 808 DataType: schema.DataTypeText.PropString(), 809 Tokenization: models.PropertyTokenizationWhitespace, 810 }, 811 }, 812 }, 813 { 814 Class: "NotVectorized", 815 VectorIndexConfig: hnsw.UserConfig{}, 816 Properties: []*models.Property{ 817 { 818 Name: "description", 819 DataType: []string{"text"}, 820 }, 821 }, 822 Vectorizer: "none", 823 }, 824 }, 825 }, 826 } 827 }