KevinStephenson
Adding in weaviate code
b110593
raw
history blame
33.3 kB
// _ _
// __ _____ __ ___ ___ __ _| |_ ___
// \ \ /\ / / _ \/ _` \ \ / / |/ _` | __/ _ \
// \ V V / __/ (_| |\ V /| | (_| | || __/
// \_/\_/ \___|\__,_| \_/ |_|\__,_|\__\___|
//
// Copyright © 2016 - 2024 Weaviate B.V. All rights reserved.
//
// CONTACT: [email protected]
//
package objects
import (
"context"
"errors"
"testing"
"github.com/go-openapi/strfmt"
"github.com/sirupsen/logrus/hooks/test"
"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/filters"
"github.com/weaviate/weaviate/entities/models"
"github.com/weaviate/weaviate/entities/schema"
"github.com/weaviate/weaviate/entities/search"
"github.com/weaviate/weaviate/usecases/config"
)
func Test_GetAction(t *testing.T) {
var (
vectorRepo *fakeVectorRepo
manager *Manager
extender *fakeExtender
projectorFake *fakeProjector
metrics *fakeMetrics
)
schema := schema.Schema{
Objects: &models.Schema{
Classes: []*models.Class{
{
Class: "ActionClass",
},
},
},
}
reset := func() {
vectorRepo = &fakeVectorRepo{}
schemaManager := &fakeSchemaManager{
GetSchemaResponse: schema,
}
locks := &fakeLocks{}
cfg := &config.WeaviateConfig{}
cfg.Config.QueryDefaults.Limit = 20
cfg.Config.QueryMaximumResults = 200
authorizer := &fakeAuthorizer{}
logger, _ := test.NewNullLogger()
extender = &fakeExtender{}
projectorFake = &fakeProjector{}
metrics = &fakeMetrics{}
manager = NewManager(locks, schemaManager, cfg, logger,
authorizer, vectorRepo,
getFakeModulesProviderWithCustomExtenders(extender, projectorFake), metrics)
}
t.Run("get non-existing action by id", func(t *testing.T) {
reset()
id := strfmt.UUID("99ee9968-22ec-416a-9032-cff80f2f7fdf")
vectorRepo.On("ObjectByID", id, mock.Anything, mock.Anything).Return((*search.Result)(nil), nil).Once()
_, err := manager.GetObject(context.Background(), &models.Principal{}, "",
id, additional.Properties{}, nil, "")
assert.Equal(t, NewErrNotFound("no object with id '99ee9968-22ec-416a-9032-cff80f2f7fdf'"), err)
})
t.Run("get existing action by id", func(t *testing.T) {
reset()
id := strfmt.UUID("99ee9968-22ec-416a-9032-cff80f2f7fdf")
result := &search.Result{
ID: id,
ClassName: "ActionClass",
Schema: map[string]interface{}{"foo": "bar"},
}
vectorRepo.On("ObjectByID", id, mock.Anything, mock.Anything).Return(result, nil).Once()
expected := &models.Object{
ID: id,
Class: "ActionClass",
Properties: map[string]interface{}{"foo": "bar"},
VectorWeights: (map[string]string)(nil),
}
res, err := manager.GetObject(context.Background(), &models.Principal{}, "",
id, additional.Properties{}, nil, "")
require.Nil(t, err)
assert.Equal(t, expected, res)
})
t.Run("get existing object by id with vector without classname (deprecated)", func(t *testing.T) {
reset()
id := strfmt.UUID("99ee9968-22ec-416a-9032-cff80f2f7fdf")
result := &search.Result{
ID: id,
ClassName: "ActionClass",
Schema: map[string]interface{}{"foo": "bar"},
Vector: []float32{1, 2, 3},
Dims: 3,
}
vectorRepo.On("ObjectByID", id, mock.Anything, mock.Anything).Return(result, nil).Once()
expected := &models.Object{
ID: id,
Class: "ActionClass",
Properties: map[string]interface{}{"foo": "bar"},
VectorWeights: (map[string]string)(nil),
Vector: []float32{1, 2, 3},
}
metrics.On("AddUsageDimensions", "ActionClass", "get_rest", "single_include_vector", 3)
res, err := manager.GetObject(context.Background(), &models.Principal{}, "",
id, additional.Properties{Vector: true}, nil, "")
require.Nil(t, err)
assert.Equal(t, expected, res)
})
t.Run("get existing object by id with vector with classname", func(t *testing.T) {
reset()
id := strfmt.UUID("99ee9968-22ec-416a-9032-cff80f2f7fdf")
result := &search.Result{
ID: id,
ClassName: "ActionClass",
Schema: map[string]interface{}{"foo": "bar"},
Vector: []float32{1, 2, 3},
Dims: 3,
}
vectorRepo.On("Object", "ActionClass", id, mock.Anything, mock.Anything, "").
Return(result, nil).Once()
expected := &models.Object{
ID: id,
Class: "ActionClass",
Properties: map[string]interface{}{"foo": "bar"},
VectorWeights: (map[string]string)(nil),
Vector: []float32{1, 2, 3},
}
metrics.On("AddUsageDimensions", "ActionClass", "get_rest", "single_include_vector", 3)
res, err := manager.GetObject(context.Background(), &models.Principal{},
"ActionClass", id, additional.Properties{Vector: true}, nil, "")
require.Nil(t, err)
assert.Equal(t, expected, res)
})
t.Run("list all existing actions with all default pagination settings", func(t *testing.T) {
reset()
id := strfmt.UUID("99ee9968-22ec-416a-9032-cff80f2f7fdf")
results := []search.Result{
{
ID: id,
ClassName: "ActionClass",
Schema: map[string]interface{}{"foo": "bar"},
},
}
vectorRepo.On("ObjectSearch", 0, 20, mock.Anything, mock.Anything, mock.Anything,
mock.Anything).Return(results, nil).Once()
expected := []*models.Object{
{
ID: id,
Class: "ActionClass",
Properties: map[string]interface{}{"foo": "bar"},
VectorWeights: (map[string]string)(nil),
},
}
res, err := manager.GetObjects(context.Background(), &models.Principal{}, nil, nil, nil, nil, nil, additional.Properties{}, "")
require.Nil(t, err)
assert.Equal(t, expected, res)
})
t.Run("list all existing objects with vectors", func(t *testing.T) {
reset()
id := strfmt.UUID("99ee9968-22ec-416a-9032-cff80f2f7fdf")
results := []search.Result{
{
ID: id,
ClassName: "ActionClass",
Schema: map[string]interface{}{"foo": "bar"},
Vector: []float32{1, 2, 3},
Dims: 3,
},
}
vectorRepo.On("ObjectSearch", 0, 20, mock.Anything, mock.Anything, mock.Anything,
mock.Anything).Return(results, nil).Once()
metrics.On("AddUsageDimensions", "ActionClass", "get_rest", "list_include_vector", 3)
expected := []*models.Object{
{
ID: id,
Class: "ActionClass",
Properties: map[string]interface{}{"foo": "bar"},
VectorWeights: (map[string]string)(nil),
Vector: []float32{1, 2, 3},
},
}
res, err := manager.GetObjects(context.Background(), &models.Principal{}, nil, nil, nil, nil, nil, additional.Properties{Vector: true}, "")
require.Nil(t, err)
assert.Equal(t, expected, res)
})
t.Run("list all existing actions with all explicit offset and limit", func(t *testing.T) {
reset()
id := strfmt.UUID("99ee9968-22ec-416a-9032-cff80f2f7fdf")
results := []search.Result{
{
ID: id,
ClassName: "ActionClass",
Schema: map[string]interface{}{"foo": "bar"},
},
}
vectorRepo.On("ObjectSearch", 7, 2, mock.Anything, mock.Anything, mock.Anything,
mock.Anything).Return(results, nil).Once()
expected := []*models.Object{
{
ID: id,
Class: "ActionClass",
Properties: map[string]interface{}{"foo": "bar"},
VectorWeights: (map[string]string)(nil),
},
}
res, err := manager.GetObjects(context.Background(), &models.Principal{}, ptInt64(7), ptInt64(2), nil, nil, nil, additional.Properties{}, "")
require.Nil(t, err)
assert.Equal(t, expected, res)
})
t.Run("with an offset greater than the maximum", func(t *testing.T) {
reset()
_, err := manager.GetObjects(context.Background(), &models.Principal{}, ptInt64(201), ptInt64(2), nil, nil, nil, additional.Properties{}, "")
require.NotNil(t, err)
assert.Contains(t, err.Error(), "query maximum results exceeded")
})
t.Run("with a limit greater than the minimum", func(t *testing.T) {
reset()
_, err := manager.GetObjects(context.Background(), &models.Principal{}, ptInt64(0), ptInt64(202), nil, nil, nil, additional.Properties{}, "")
require.NotNil(t, err)
assert.Contains(t, err.Error(), "query maximum results exceeded")
})
t.Run("with limit and offset individually smaller, but combined greater", func(t *testing.T) {
reset()
_, err := manager.GetObjects(context.Background(), &models.Principal{}, ptInt64(150), ptInt64(150), nil, nil, nil, additional.Properties{}, "")
require.NotNil(t, err)
assert.Contains(t, err.Error(), "query maximum results exceeded")
})
t.Run("additional props", func(t *testing.T) {
t.Run("on get single requests", func(t *testing.T) {
t.Run("feature projection", func(t *testing.T) {
reset()
id := strfmt.UUID("99ee9968-22ec-416a-9032-cff80f2f7fdf")
result := &search.Result{
ID: id,
ClassName: "ActionClass",
Schema: map[string]interface{}{"foo": "bar"},
}
vectorRepo.On("ObjectByID", id, mock.Anything, mock.Anything).Return(result, nil).Once()
_, err := manager.GetObject(context.Background(), &models.Principal{}, "",
id, additional.Properties{
ModuleParams: map[string]interface{}{
"featureProjection": getDefaultParam("featureProjection"),
},
}, nil, "")
assert.Equal(t, errors.New("get extend: unknown capability: featureProjection"), err)
})
t.Run("semantic path", func(t *testing.T) {
reset()
id := strfmt.UUID("99ee9968-22ec-416a-9032-cff80f2f7fdf")
result := &search.Result{
ID: id,
ClassName: "ActionClass",
Schema: map[string]interface{}{"foo": "bar"},
}
vectorRepo.On("ObjectByID", id, mock.Anything, mock.Anything).Return(result, nil).Once()
_, err := manager.GetObject(context.Background(), &models.Principal{}, "",
id, additional.Properties{
ModuleParams: map[string]interface{}{
"semanticPath": getDefaultParam("semanticPath"),
},
}, nil, "")
assert.Equal(t, errors.New("get extend: unknown capability: semanticPath"), err)
})
t.Run("nearest neighbors", func(t *testing.T) {
reset()
id := strfmt.UUID("99ee9968-22ec-416a-9032-cff80f2f7fdf")
result := &search.Result{
ID: id,
ClassName: "ActionClass",
Schema: map[string]interface{}{"foo": "bar"},
}
vectorRepo.On("ObjectByID", id, mock.Anything, mock.Anything).Return(result, nil).Once()
extender.multi = []search.Result{
{
ID: id,
ClassName: "ActionClass",
Schema: map[string]interface{}{"foo": "bar"},
AdditionalProperties: models.AdditionalProperties{
"nearestNeighbors": &NearestNeighbors{
Neighbors: []*NearestNeighbor{
{
Concept: "foo",
Distance: 0.3,
},
},
},
},
},
}
expected := &models.Object{
ID: id,
Class: "ActionClass",
Properties: map[string]interface{}{"foo": "bar"},
VectorWeights: (map[string]string)(nil),
Additional: models.AdditionalProperties{
"nearestNeighbors": &NearestNeighbors{
Neighbors: []*NearestNeighbor{
{
Concept: "foo",
Distance: 0.3,
},
},
},
},
}
res, err := manager.GetObject(context.Background(), &models.Principal{}, "",
id, additional.Properties{
ModuleParams: map[string]interface{}{
"nearestNeighbors": true,
},
}, nil, "")
require.Nil(t, err)
assert.Equal(t, expected, res)
})
})
t.Run("on list requests", func(t *testing.T) {
t.Run("nearest neighbors", func(t *testing.T) {
reset()
id := strfmt.UUID("99ee9968-22ec-416a-9032-cff80f2f7fdf")
result := []search.Result{
{
ID: id,
ClassName: "ActionClass",
Schema: map[string]interface{}{"foo": "bar"},
},
}
vectorRepo.On("ObjectSearch", mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything,
mock.Anything).Return(result, nil).Once()
extender.multi = []search.Result{
{
ID: id,
ClassName: "ActionClass",
Schema: map[string]interface{}{"foo": "bar"},
AdditionalProperties: models.AdditionalProperties{
"nearestNeighbors": &NearestNeighbors{
Neighbors: []*NearestNeighbor{
{
Concept: "foo",
Distance: 0.3,
},
},
},
},
},
}
expected := []*models.Object{
{
ID: id,
Class: "ActionClass",
Properties: map[string]interface{}{"foo": "bar"},
VectorWeights: (map[string]string)(nil),
Additional: models.AdditionalProperties{
"nearestNeighbors": &NearestNeighbors{
Neighbors: []*NearestNeighbor{
{
Concept: "foo",
Distance: 0.3,
},
},
},
},
},
}
res, err := manager.GetObjects(context.Background(), &models.Principal{}, nil, ptInt64(10), nil, nil, nil, additional.Properties{
ModuleParams: map[string]interface{}{
"nearestNeighbors": true,
},
}, "")
require.Nil(t, err)
assert.Equal(t, expected, res)
})
t.Run("feature projection", func(t *testing.T) {
reset()
id := strfmt.UUID("99ee9968-22ec-416a-9032-cff80f2f7fdf")
result := []search.Result{
{
ID: id,
ClassName: "ActionClass",
Schema: map[string]interface{}{"foo": "bar"},
},
}
vectorRepo.On("ObjectSearch", mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything,
mock.Anything).Return(result, nil).Once()
projectorFake.multi = []search.Result{
{
ID: id,
ClassName: "ActionClass",
Schema: map[string]interface{}{"foo": "bar"},
AdditionalProperties: models.AdditionalProperties{
"featureProjection": &FeatureProjection{
Vector: []float32{1, 2, 3},
},
},
},
}
expected := []*models.Object{
{
ID: id,
Class: "ActionClass",
Properties: map[string]interface{}{"foo": "bar"},
VectorWeights: (map[string]string)(nil),
Additional: models.AdditionalProperties{
"featureProjection": &FeatureProjection{
Vector: []float32{1, 2, 3},
},
},
},
}
res, err := manager.GetObjects(context.Background(), &models.Principal{}, nil, ptInt64(10), nil, nil, nil, additional.Properties{
ModuleParams: map[string]interface{}{
"featureProjection": getDefaultParam("featureProjection"),
},
}, "")
require.Nil(t, err)
assert.Equal(t, expected, res)
})
})
})
t.Run("sort props", func(t *testing.T) {
t.Run("sort=foo,number&order=asc,desc", func(t *testing.T) {
reset()
id := strfmt.UUID("99ee9968-22ec-416a-9032-cff80f2f7fdf")
sort := "foo,number"
asc := "asc,desc"
expectedSort := []filters.Sort{
{Path: []string{"foo"}, Order: "asc"},
{Path: []string{"number"}, Order: "desc"},
}
result := []search.Result{
{
ID: id,
ClassName: "ActionClass",
Schema: map[string]interface{}{
"foo": "bar",
"number": float64(1),
},
},
}
vectorRepo.On("ObjectSearch", mock.AnythingOfType("int"), mock.AnythingOfType("int"), expectedSort,
mock.Anything, mock.Anything, mock.Anything).Return(result, nil).Once()
projectorFake.multi = []search.Result{
{
ID: id,
ClassName: "ActionClass",
Schema: map[string]interface{}{
"foo": "bar",
"number": float64(1),
},
},
}
expected := []*models.Object{
{
ID: id,
Class: "ActionClass",
Properties: map[string]interface{}{
"foo": "bar",
"number": float64(1),
},
VectorWeights: (map[string]string)(nil),
},
}
res, err := manager.GetObjects(context.Background(), &models.Principal{}, nil, ptInt64(10), &sort, &asc, nil, additional.Properties{}, "")
require.Nil(t, err)
assert.Equal(t, expected, res)
})
t.Run("sort=foo,number,prop1,prop2&order=desc", func(t *testing.T) {
reset()
id := strfmt.UUID("99ee9968-22ec-416a-9032-cff80f2f7fdf")
sort := "foo,number,prop1,prop2"
asc := "desc"
expectedSort := []filters.Sort{
{Path: []string{"foo"}, Order: "desc"},
{Path: []string{"number"}, Order: "asc"},
{Path: []string{"prop1"}, Order: "asc"},
{Path: []string{"prop2"}, Order: "asc"},
}
result := []search.Result{
{
ID: id,
ClassName: "ActionClass",
Schema: map[string]interface{}{
"foo": "bar",
"number": float64(1),
},
},
}
vectorRepo.On("ObjectSearch", mock.Anything, mock.Anything, expectedSort, mock.Anything, mock.Anything,
mock.Anything).Return(result, nil).Once()
projectorFake.multi = []search.Result{
{
ID: id,
ClassName: "ActionClass",
Schema: map[string]interface{}{
"foo": "bar",
"number": float64(1),
},
},
}
expected := []*models.Object{
{
ID: id,
Class: "ActionClass",
Properties: map[string]interface{}{
"foo": "bar",
"number": float64(1),
},
VectorWeights: (map[string]string)(nil),
},
}
res, err := manager.GetObjects(context.Background(), &models.Principal{}, nil, ptInt64(10), &sort, &asc, nil, additional.Properties{}, "")
require.Nil(t, err)
assert.Equal(t, expected, res)
})
t.Run("sort=foo,number", func(t *testing.T) {
reset()
sort := "foo,number"
expectedSort := []filters.Sort{
{Path: []string{"foo"}, Order: "asc"},
{Path: []string{"number"}, Order: "asc"},
}
result := []search.Result{
{
ID: "uuid",
ClassName: "ActionClass",
Schema: map[string]interface{}{
"foo": "bar",
"number": float64(1),
},
},
}
vectorRepo.On("ObjectSearch", mock.Anything, mock.Anything, expectedSort, mock.Anything, mock.Anything,
mock.Anything).Return(result, nil).Once()
_, err := manager.GetObjects(context.Background(), &models.Principal{}, nil, ptInt64(10), &sort, nil, nil, additional.Properties{}, "")
require.Nil(t, err)
})
t.Run("sort=foo,number,prop", func(t *testing.T) {
reset()
sort := "foo,number,prop"
expectedSort := []filters.Sort{
{Path: []string{"foo"}, Order: "asc"},
{Path: []string{"number"}, Order: "asc"},
{Path: []string{"prop"}, Order: "asc"},
}
result := []search.Result{
{
ID: "uuid",
ClassName: "ActionClass",
Schema: map[string]interface{}{
"foo": "bar",
"number": float64(1),
},
},
}
vectorRepo.On("ObjectSearch", mock.Anything, mock.Anything, expectedSort, mock.Anything, mock.Anything,
mock.Anything).Return(result, nil).Once()
_, err := manager.GetObjects(context.Background(), &models.Principal{}, nil, ptInt64(10), &sort, nil, nil, additional.Properties{}, "")
require.Nil(t, err)
})
t.Run("order=asc", func(t *testing.T) {
reset()
order := "asc"
var expectedSort []filters.Sort
result := []search.Result{
{
ID: "uuid",
ClassName: "ActionClass",
Schema: map[string]interface{}{
"foo": "bar",
"number": float64(1),
},
},
}
vectorRepo.On("ObjectSearch", mock.Anything, mock.Anything, expectedSort, mock.Anything, mock.Anything,
mock.Anything).Return(result, nil).Once()
_, err := manager.GetObjects(context.Background(), &models.Principal{}, nil, ptInt64(10), nil, &order, nil, additional.Properties{}, "")
require.Nil(t, err)
})
})
}
func Test_GetThing(t *testing.T) {
var (
vectorRepo *fakeVectorRepo
manager *Manager
extender *fakeExtender
projectorFake *fakeProjector
)
schema := schema.Schema{
Objects: &models.Schema{
Classes: []*models.Class{
{
Class: "ThingClass",
},
},
},
}
reset := func() {
vectorRepo = &fakeVectorRepo{}
schemaManager := &fakeSchemaManager{
GetSchemaResponse: schema,
}
locks := &fakeLocks{}
cfg := &config.WeaviateConfig{}
cfg.Config.QueryDefaults.Limit = 20
cfg.Config.QueryMaximumResults = 200
authorizer := &fakeAuthorizer{}
logger, _ := test.NewNullLogger()
extender = &fakeExtender{}
projectorFake = &fakeProjector{}
metrics := &fakeMetrics{}
manager = NewManager(locks, schemaManager, cfg, logger,
authorizer, vectorRepo,
getFakeModulesProviderWithCustomExtenders(extender, projectorFake), metrics)
}
t.Run("get non-existing thing by id", func(t *testing.T) {
reset()
id := strfmt.UUID("99ee9968-22ec-416a-9032-cff80f2f7fdf")
vectorRepo.On("ObjectByID", id, mock.Anything, mock.Anything).Return((*search.Result)(nil), nil).Once()
_, err := manager.GetObject(context.Background(), &models.Principal{}, "", id,
additional.Properties{}, nil, "")
assert.Equal(t, NewErrNotFound("no object with id '99ee9968-22ec-416a-9032-cff80f2f7fdf'"), err)
})
t.Run("get existing thing by id", func(t *testing.T) {
reset()
id := strfmt.UUID("99ee9968-22ec-416a-9032-cff80f2f7fdf")
result := &search.Result{
ID: id,
ClassName: "ThingClass",
Schema: map[string]interface{}{"foo": "bar"},
}
vectorRepo.On("ObjectByID", id, mock.Anything, mock.Anything).Return(result, nil).Once()
expected := &models.Object{
ID: id,
Class: "ThingClass",
Properties: map[string]interface{}{"foo": "bar"},
VectorWeights: (map[string]string)(nil),
}
res, err := manager.GetObject(context.Background(), &models.Principal{}, "", id,
additional.Properties{}, nil, "")
require.Nil(t, err)
assert.Equal(t, expected, res)
})
t.Run("list all existing things", func(t *testing.T) {
reset()
id := strfmt.UUID("99ee9968-22ec-416a-9032-cff80f2f7fdf")
results := []search.Result{
{
ID: id,
ClassName: "ThingClass",
Schema: map[string]interface{}{"foo": "bar"},
},
}
vectorRepo.On("ObjectSearch", mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything,
mock.Anything).Return(results, nil).Once()
expected := []*models.Object{
{
ID: id,
Class: "ThingClass",
Properties: map[string]interface{}{"foo": "bar"},
VectorWeights: (map[string]string)(nil),
},
}
res, err := manager.GetObjects(context.Background(), &models.Principal{}, nil, nil, nil, nil, nil, additional.Properties{}, "")
require.Nil(t, err)
assert.Equal(t, expected, res)
})
t.Run("additional props", func(t *testing.T) {
t.Run("on get single requests", func(t *testing.T) {
t.Run("feature projection", func(t *testing.T) {
reset()
id := strfmt.UUID("99ee9968-22ec-416a-9032-cff80f2f7fdf")
result := &search.Result{
ID: id,
ClassName: "ThingClass",
Schema: map[string]interface{}{"foo": "bar"},
}
vectorRepo.On("ObjectByID", id, mock.Anything, mock.Anything).Return(result, nil).Once()
_, err := manager.GetObject(context.Background(), &models.Principal{}, "",
id, additional.Properties{
ModuleParams: map[string]interface{}{
"featureProjection": getDefaultParam("featureProjection"),
},
}, nil, "")
assert.Equal(t, errors.New("get extend: unknown capability: featureProjection"), err)
})
t.Run("nearest neighbors", func(t *testing.T) {
reset()
id := strfmt.UUID("99ee9968-22ec-416a-9032-cff80f2f7fdf")
result := &search.Result{
ID: id,
ClassName: "ThingClass",
Schema: map[string]interface{}{"foo": "bar"},
}
vectorRepo.On("ObjectByID", id, mock.Anything, mock.Anything).Return(result, nil).Once()
extender.multi = []search.Result{
{
ID: id,
ClassName: "ThingClass",
Schema: map[string]interface{}{"foo": "bar"},
AdditionalProperties: models.AdditionalProperties{
"nearestNeighbors": &NearestNeighbors{
Neighbors: []*NearestNeighbor{
{
Concept: "foo",
Distance: 0.3,
},
},
},
},
},
}
expected := &models.Object{
ID: id,
Class: "ThingClass",
Properties: map[string]interface{}{"foo": "bar"},
VectorWeights: (map[string]string)(nil),
Additional: models.AdditionalProperties{
"nearestNeighbors": &NearestNeighbors{
Neighbors: []*NearestNeighbor{
{
Concept: "foo",
Distance: 0.3,
},
},
},
},
}
res, err := manager.GetObject(context.Background(), &models.Principal{}, "",
id, additional.Properties{
ModuleParams: map[string]interface{}{
"nearestNeighbors": true,
},
}, nil, "")
require.Nil(t, err)
assert.Equal(t, expected, res)
})
})
t.Run("on list requests", func(t *testing.T) {
t.Run("nearest neighbors", func(t *testing.T) {
reset()
id := strfmt.UUID("99ee9968-22ec-416a-9032-cff80f2f7fdf")
result := []search.Result{
{
ID: id,
ClassName: "ThingClass",
Schema: map[string]interface{}{"foo": "bar"},
},
}
vectorRepo.On("ObjectSearch", mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything,
mock.Anything).Return(result, nil).Once()
extender.multi = []search.Result{
{
ID: id,
ClassName: "ThingClass",
Schema: map[string]interface{}{"foo": "bar"},
AdditionalProperties: models.AdditionalProperties{
"nearestNeighbors": &NearestNeighbors{
Neighbors: []*NearestNeighbor{
{
Concept: "foo",
Distance: 0.3,
},
},
},
},
},
}
expected := []*models.Object{
{
ID: id,
Class: "ThingClass",
Properties: map[string]interface{}{"foo": "bar"},
VectorWeights: (map[string]string)(nil),
Additional: models.AdditionalProperties{
"nearestNeighbors": &NearestNeighbors{
Neighbors: []*NearestNeighbor{
{
Concept: "foo",
Distance: 0.3,
},
},
},
},
},
}
res, err := manager.GetObjects(context.Background(), &models.Principal{}, nil, ptInt64(10), nil, nil, nil, additional.Properties{
ModuleParams: map[string]interface{}{
"nearestNeighbors": true,
},
}, "")
require.Nil(t, err)
assert.Equal(t, expected, res)
})
t.Run("feature projection", func(t *testing.T) {
reset()
id := strfmt.UUID("99ee9968-22ec-416a-9032-cff80f2f7fdf")
result := []search.Result{
{
ID: id,
ClassName: "ThingClass",
Schema: map[string]interface{}{"foo": "bar"},
},
}
vectorRepo.On("ObjectSearch", mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything,
mock.Anything).Return(result, nil).Once()
projectorFake.multi = []search.Result{
{
ID: id,
ClassName: "ThingClass",
Schema: map[string]interface{}{"foo": "bar"},
AdditionalProperties: models.AdditionalProperties{
"featureProjection": &FeatureProjection{
Vector: []float32{1, 2, 3},
},
},
},
}
expected := []*models.Object{
{
ID: id,
Class: "ThingClass",
Properties: map[string]interface{}{"foo": "bar"},
VectorWeights: (map[string]string)(nil),
Additional: models.AdditionalProperties{
"featureProjection": &FeatureProjection{
Vector: []float32{1, 2, 3},
},
},
},
}
res, err := manager.GetObjects(context.Background(), &models.Principal{}, nil, ptInt64(10), nil, nil, nil, additional.Properties{
ModuleParams: map[string]interface{}{
"featureProjection": getDefaultParam("featureProjection"),
},
}, "")
require.Nil(t, err)
assert.Equal(t, expected, res)
})
})
})
}
func Test_GetObject(t *testing.T) {
var (
principal = models.Principal{}
adds = additional.Properties{}
className = "MyClass"
id = strfmt.UUID("99ee9968-22ec-416a-9032-cff80f2f7fdf")
schema = schema.Schema{
Objects: &models.Schema{
Classes: []*models.Class{
{
Class: className,
},
},
},
}
result = &search.Result{
ID: id,
ClassName: className,
Schema: map[string]interface{}{"foo": "bar"},
}
)
t.Run("without projection", func(t *testing.T) {
m := newFakeGetManager(schema)
m.repo.On("Object", className, id, mock.Anything, mock.Anything, "").Return((*search.Result)(nil), nil).Once()
_, err := m.GetObject(context.Background(), &principal, className, id, adds, nil, "")
if err == nil {
t.Errorf("GetObject() must return an error for non existing object")
}
m.repo.On("Object", className, id, mock.Anything, mock.Anything, "").Return(result, nil).Once()
expected := &models.Object{
ID: id,
Class: className,
Properties: map[string]interface{}{"foo": "bar"},
VectorWeights: (map[string]string)(nil),
}
got, err := m.GetObject(context.Background(), &principal, className, id, adds, nil, "")
require.Nil(t, err)
assert.Equal(t, expected, got)
})
t.Run("with projection", func(t *testing.T) {
m := newFakeGetManager(schema)
m.extender.multi = []search.Result{
{
ID: id,
ClassName: className,
Schema: map[string]interface{}{"foo": "bar"},
AdditionalProperties: models.AdditionalProperties{
"nearestNeighbors": &NearestNeighbors{
Neighbors: []*NearestNeighbor{
{
Concept: "foo",
Distance: 0.3,
},
},
},
},
},
}
m.repo.On("Object", className, id, mock.Anything, mock.Anything, "").Return(result, nil).Once()
_, err := m.GetObject(context.Background(), &principal, className, id,
additional.Properties{
ModuleParams: map[string]interface{}{
"Unknown": getDefaultParam("Unknown"),
},
}, nil, "")
if err == nil {
t.Errorf("GetObject() must return unknown feature projection error")
}
m.repo.On("Object", className, id, mock.Anything, mock.Anything, "").Return(result, nil).Once()
expected := &models.Object{
ID: id,
Class: className,
Properties: map[string]interface{}{"foo": "bar"},
VectorWeights: (map[string]string)(nil),
Additional: models.AdditionalProperties{
"nearestNeighbors": &NearestNeighbors{
Neighbors: []*NearestNeighbor{
{
Concept: "foo",
Distance: 0.3,
},
},
},
},
}
res, err := m.GetObject(context.Background(), &principal, className, id,
additional.Properties{
ModuleParams: map[string]interface{}{
"nearestNeighbors": true,
},
}, nil, "")
require.Nil(t, err)
assert.Equal(t, expected, res)
})
}
func ptInt64(in int64) *int64 {
return &in
}
type fakeGetManager struct {
*Manager
repo *fakeVectorRepo
extender *fakeExtender
projector *fakeProjector
authorizer *fakeAuthorizer
locks *fakeLocks
metrics *fakeMetrics
modulesProvider *fakeModulesProvider
}
func newFakeGetManager(schema schema.Schema, opts ...func(*fakeGetManager)) fakeGetManager {
r := fakeGetManager{
repo: new(fakeVectorRepo),
extender: new(fakeExtender),
projector: new(fakeProjector),
authorizer: new(fakeAuthorizer),
locks: new(fakeLocks),
metrics: new(fakeMetrics),
modulesProvider: new(fakeModulesProvider),
}
for _, opt := range opts {
opt(&r)
}
schemaManager := &fakeSchemaManager{
GetSchemaResponse: schema,
}
cfg := &config.WeaviateConfig{}
cfg.Config.QueryDefaults.Limit = 20
cfg.Config.QueryMaximumResults = 200
cfg.Config.TrackVectorDimensions = true
logger, _ := test.NewNullLogger()
r.modulesProvider = getFakeModulesProviderWithCustomExtenders(r.extender, r.projector)
r.Manager = NewManager(r.locks, schemaManager, cfg, logger,
r.authorizer, r.repo, r.modulesProvider, r.metrics)
return r
}