Spaces:
Running
Running
// _ _ | |
// __ _____ __ ___ ___ __ _| |_ ___ | |
// \ \ /\ / / _ \/ _` \ \ / / |/ _` | __/ _ \ | |
// \ 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 | |
} | |