mirror of
https://gitee.com/milvus-io/milvus.git
synced 2024-12-01 03:18:29 +08:00
0323aa1aad
* #1910 C++ SDK GetIDsInSegment could not work for large dataset (#1911) Signed-off-by: groot <yihua.mo@zilliz.com> * #1903 Fix invalid annoy result (#1912) Signed-off-by: shengjun.li <shengjun.li@zilliz.com> * #1914: Partition max size should be 4096 (#1915) Signed-off-by: jinhai <hai.jin@zilliz.com> * add log (#1913) * add log Signed-off-by: groot <yihua.mo@zilliz.com> * add log Signed-off-by: groot <yihua.mo@zilliz.com> * fix ut Signed-off-by: groot <yihua.mo@zilliz.com> * partition limit 4096 Signed-off-by: groot <yihua.mo@zilliz.com> * fix py test Signed-off-by: groot <yihua.mo@zilliz.com> * update server version (#1916) Signed-off-by: zw <zw@zilliz.com> * Update to 0.8.0 (#1918) * Create new branch 0.8.0 and change preload_table to preload_collection Signed-off-by: jinhai <hai.jin@zilliz.com> * Fix format Signed-off-by: JinHai-CN <hai.jin@zilliz.com> * Update CHANGELOG Signed-off-by: jinhai <hai.jin@zilliz.com> * Update CHANGELOG Signed-off-by: jinhai <hai.jin@zilliz.com> * update helm version Signed-off-by: zw <zw@zilliz.com> * Update CHANGELOG Signed-off-by: jinhai <hai.jin@zilliz.com> Co-authored-by: zw <zw@zilliz.com> * fix issue 1901 (#1920) * fix issue 1901 Signed-off-by: cmli <chengming.li@zilliz.com> * update change log Signed-off-by: cmli <chengming.li@zilliz.com> Co-authored-by: cmli <chengming.li@zilliz.com> * #1900 (#1923) * add log Signed-off-by: yhmo <yihua.mo@zilliz.com> * fix #1900 Signed-off-by: groot <yihua.mo@zilliz.com> * Upgrade mishards to 0.8.0 (#1933) * update grpc server of milvus & rename table name to collection Signed-off-by: Yhz <yinghao.zou@zilliz.com> * update changlog Signed-off-by: Yhz <yinghao.zou@zilliz.com> * [skip ci] Skip CI Signed-off-by: Yhz <yinghao.zou@zilliz.com> * [skip ci] Update changlog Signed-off-by: Yhz <yinghao.zou@zilliz.com> * Caiyd 1883 fix rw (#1926) * #1883 use DiskIO Signed-off-by: yudong.cai <yudong.cai@zilliz.com> * fix logic error Signed-off-by: yudong.cai <yudong.cai@zilliz.com> * update changelog Signed-off-by: yudong.cai <yudong.cai@zilliz.com> * retry CI Signed-off-by: yudong.cai <yudong.cai@zilliz.com> * Update CHANGELOG Signed-off-by: JinHai-CN <hai.jin@zilliz.com> * update changelog Signed-off-by: yudong.cai <yudong.cai@zilliz.com> Co-authored-by: JinHai-CN <hai.jin@zilliz.com> * #1928 Too many data and uid copies when loading files (#1931) Signed-off-by: shengjun.li <shengjun.li@zilliz.com> Co-authored-by: Jin Hai <hai.jin@zilliz.com> * Update mishards configure files (#1938) * Update web readme Signed-off-by: Yhz <yinghao.zou@zilliz.com> * [skip ci] update configure files Signed-off-by: Yhz <yinghao.zou@zilliz.com> * [skip ci] rename table to collection Signed-off-by: Yhz <yinghao.zou@zilliz.com> * Update test.groovy Signed-off-by: jinhai <hai.jin@zilliz.com> * Update test.groovy Signed-off-by: jinhai <hai.jin@zilliz.com> * Fix lint Signed-off-by: JinHai-CN <hai.jin@zilliz.com> * Fix compiling error Signed-off-by: jinhai <hai.jin@zilliz.com> Co-authored-by: groot <yhmo@zeronedata.com> Co-authored-by: shengjun.li <49774184+shengjun1985@users.noreply.github.com> Co-authored-by: del-zhenwu <56623710+del-zhenwu@users.noreply.github.com> Co-authored-by: zw <zw@zilliz.com> Co-authored-by: op-hunter <ophunter52@gmail.com> Co-authored-by: cmli <chengming.li@zilliz.com> Co-authored-by: BossZou <40255591+BossZou@users.noreply.github.com> Co-authored-by: Cai Yudong <yudong.cai@zilliz.com>
281 lines
12 KiB
Python
281 lines
12 KiB
Python
import logging
|
|
import pytest
|
|
import mock
|
|
import datetime
|
|
import random
|
|
import faker
|
|
import inspect
|
|
from milvus import Milvus
|
|
from milvus.client.types import Status, IndexType, MetricType
|
|
from milvus.client.abstract import IndexParam, CollectionSchema
|
|
from milvus.grpc_gen import status_pb2, milvus_pb2
|
|
from mishards import db, create_app, settings
|
|
from mishards.service_handler import ServiceHandler
|
|
from mishards.grpc_utils.grpc_args_parser import GrpcArgsParser as Parser
|
|
from mishards.factories import TableFilesFactory, TablesFactory, TableFiles, Tables
|
|
from mishards.router import RouterMixin
|
|
from mishards.connections import (ConnectionMgr, Connection,
|
|
ConnectionPool, ConnectionTopology, ConnectionGroup)
|
|
|
|
logger = logging.getLogger(__name__)
|
|
|
|
OK = Status(code=Status.SUCCESS, message='Success')
|
|
BAD = Status(code=Status.PERMISSION_DENIED, message='Fail')
|
|
|
|
|
|
@pytest.mark.usefixtures('started_app')
|
|
class TestServer:
|
|
|
|
@property
|
|
def client(self):
|
|
m = Milvus()
|
|
m.connect(host='localhost', port=settings.SERVER_TEST_PORT)
|
|
return m
|
|
|
|
def test_cmd(self, started_app):
|
|
ServiceHandler._get_server_version = mock.MagicMock(return_value=(OK,
|
|
''))
|
|
status, _ = self.client.server_version()
|
|
assert status.OK()
|
|
|
|
Parser.parse_proto_Command = mock.MagicMock(return_value=(BAD, 'cmd'))
|
|
status, _ = self.client.server_version()
|
|
assert not status.OK()
|
|
|
|
def test_drop_index(self, started_app):
|
|
collection_name = inspect.currentframe().f_code.co_name
|
|
ServiceHandler._drop_index = mock.MagicMock(return_value=OK)
|
|
status = self.client.drop_index(collection_name)
|
|
assert status.OK()
|
|
|
|
Parser.parse_proto_CollectionName = mock.MagicMock(
|
|
return_value=(BAD, collection_name))
|
|
status = self.client.drop_index(collection_name)
|
|
assert not status.OK()
|
|
|
|
def test_describe_index(self, started_app):
|
|
collection_name = inspect.currentframe().f_code.co_name
|
|
index_type = IndexType.FLAT
|
|
params = {'nlist': 1}
|
|
index_param = IndexParam(collection_name=collection_name,
|
|
index_type=index_type,
|
|
params=params)
|
|
Parser.parse_proto_CollectionName = mock.MagicMock(
|
|
return_value=(OK, collection_name))
|
|
ServiceHandler._describe_index = mock.MagicMock(
|
|
return_value=(OK, index_param))
|
|
status, ret = self.client.describe_index(collection_name)
|
|
assert status.OK()
|
|
assert ret._collection_name == index_param._collection_name
|
|
|
|
Parser.parse_proto_CollectionName = mock.MagicMock(
|
|
return_value=(BAD, collection_name))
|
|
status, _ = self.client.describe_index(collection_name)
|
|
assert not status.OK()
|
|
|
|
def test_preload(self, started_app):
|
|
collection_name = inspect.currentframe().f_code.co_name
|
|
|
|
Parser.parse_proto_CollectionName = mock.MagicMock(
|
|
return_value=(OK, collection_name))
|
|
ServiceHandler._preload_collection = mock.MagicMock(return_value=OK)
|
|
status = self.client.preload_collection(collection_name)
|
|
assert status.OK()
|
|
|
|
Parser.parse_proto_CollectionName = mock.MagicMock(
|
|
return_value=(BAD, collection_name))
|
|
status = self.client.preload_collection(collection_name)
|
|
assert not status.OK()
|
|
|
|
@pytest.mark.skip
|
|
def test_delete_by_range(self, started_app):
|
|
collection_name = inspect.currentframe().f_code.co_name
|
|
|
|
unpacked = collection_name, datetime.datetime.today(
|
|
), datetime.datetime.today()
|
|
|
|
Parser.parse_proto_DeleteByRangeParam = mock.MagicMock(
|
|
return_value=(OK, unpacked))
|
|
ServiceHandler._delete_by_range = mock.MagicMock(return_value=OK)
|
|
status = self.client.delete_vectors_by_range(
|
|
*unpacked)
|
|
assert status.OK()
|
|
|
|
Parser.parse_proto_DeleteByRangeParam = mock.MagicMock(
|
|
return_value=(BAD, unpacked))
|
|
status = self.client.delete_vectors_by_range(
|
|
*unpacked)
|
|
assert not status.OK()
|
|
|
|
def test_count_collection(self, started_app):
|
|
collection_name = inspect.currentframe().f_code.co_name
|
|
count = random.randint(100, 200)
|
|
|
|
Parser.parse_proto_CollectionName = mock.MagicMock(
|
|
return_value=(OK, collection_name))
|
|
ServiceHandler._count_collection = mock.MagicMock(return_value=(OK, count))
|
|
status, ret = self.client.count_collection(collection_name)
|
|
assert status.OK()
|
|
assert ret == count
|
|
|
|
Parser.parse_proto_CollectionName = mock.MagicMock(
|
|
return_value=(BAD, collection_name))
|
|
status, _ = self.client.count_collection(collection_name)
|
|
assert not status.OK()
|
|
|
|
def test_show_collections(self, started_app):
|
|
collections = ['t1', 't2']
|
|
ServiceHandler._show_collections = mock.MagicMock(return_value=(OK, collections))
|
|
status, ret = self.client.show_collections()
|
|
assert status.OK()
|
|
assert ret == collections
|
|
|
|
def test_describe_collection(self, started_app):
|
|
collection_name = inspect.currentframe().f_code.co_name
|
|
dimension = 128
|
|
nlist = 1
|
|
collection_schema = CollectionSchema(collection_name=collection_name,
|
|
index_file_size=100,
|
|
metric_type=MetricType.L2,
|
|
dimension=dimension)
|
|
Parser.parse_proto_CollectionName = mock.MagicMock(
|
|
return_value=(OK, collection_schema.collection_name))
|
|
ServiceHandler._describe_collection = mock.MagicMock(
|
|
return_value=(OK, collection_schema))
|
|
status, _ = self.client.describe_collection(collection_name)
|
|
assert status.OK()
|
|
|
|
ServiceHandler._describe_collection = mock.MagicMock(
|
|
return_value=(BAD, collection_schema))
|
|
status, _ = self.client.describe_collection(collection_name)
|
|
assert not status.OK()
|
|
|
|
Parser.parse_proto_CollectionName = mock.MagicMock(return_value=(BAD,
|
|
'cmd'))
|
|
status, ret = self.client.describe_collection(collection_name)
|
|
assert not status.OK()
|
|
|
|
def test_insert(self, started_app):
|
|
collection_name = inspect.currentframe().f_code.co_name
|
|
vectors = [[random.random() for _ in range(16)] for _ in range(10)]
|
|
ids = [random.randint(1000000, 20000000) for _ in range(10)]
|
|
ServiceHandler._add_vectors = mock.MagicMock(return_value=(OK, ids))
|
|
status, ret = self.client.add_vectors(
|
|
collection_name=collection_name, records=vectors)
|
|
assert status.OK()
|
|
assert ids == ret
|
|
|
|
def test_create_index(self, started_app):
|
|
collection_name = inspect.currentframe().f_code.co_name
|
|
unpacks = collection_name, None
|
|
Parser.parse_proto_IndexParam = mock.MagicMock(return_value=(OK,
|
|
unpacks))
|
|
ServiceHandler._create_index = mock.MagicMock(return_value=OK)
|
|
status = self.client.create_index(collection_name=collection_name)
|
|
assert status.OK()
|
|
|
|
Parser.parse_proto_IndexParam = mock.MagicMock(return_value=(BAD,
|
|
None))
|
|
status = self.client.create_index(collection_name=collection_name)
|
|
assert not status.OK()
|
|
|
|
def test_drop_collection(self, started_app):
|
|
collection_name = inspect.currentframe().f_code.co_name
|
|
|
|
Parser.parse_proto_CollectionName = mock.MagicMock(
|
|
return_value=(OK, collection_name))
|
|
ServiceHandler._drop_collection = mock.MagicMock(return_value=OK)
|
|
status = self.client.drop_collection(collection_name=collection_name)
|
|
assert status.OK()
|
|
|
|
Parser.parse_proto_CollectionName = mock.MagicMock(
|
|
return_value=(BAD, collection_name))
|
|
status = self.client.drop_collection(collection_name=collection_name)
|
|
assert not status.OK()
|
|
|
|
def test_has_collection(self, started_app):
|
|
collection_name = inspect.currentframe().f_code.co_name
|
|
|
|
Parser.parse_proto_CollectionName = mock.MagicMock(
|
|
return_value=(OK, collection_name))
|
|
ServiceHandler._has_collection = mock.MagicMock(return_value=(OK, True))
|
|
has = self.client.has_collection(collection_name=collection_name)
|
|
assert has
|
|
|
|
Parser.parse_proto_CollectionName = mock.MagicMock(
|
|
return_value=(BAD, collection_name))
|
|
status, has = self.client.has_collection(collection_name=collection_name)
|
|
assert not status.OK()
|
|
assert not has
|
|
|
|
def test_create_collection(self, started_app):
|
|
collection_name = inspect.currentframe().f_code.co_name
|
|
dimension = 128
|
|
collection_schema = dict(collection_name=collection_name,
|
|
index_file_size=100,
|
|
metric_type=MetricType.L2,
|
|
dimension=dimension)
|
|
|
|
ServiceHandler._create_collection = mock.MagicMock(return_value=OK)
|
|
status = self.client.create_collection(collection_schema)
|
|
assert status.OK()
|
|
|
|
Parser.parse_proto_CollectionSchema = mock.MagicMock(return_value=(BAD,
|
|
None))
|
|
status = self.client.create_collection(collection_schema)
|
|
assert not status.OK()
|
|
|
|
def random_data(self, n, dimension):
|
|
return [[random.random() for _ in range(dimension)] for _ in range(n)]
|
|
|
|
@pytest.mark.skip
|
|
def test_search(self, started_app):
|
|
collection_name = inspect.currentframe().f_code.co_name
|
|
to_index_cnt = random.randint(10, 20)
|
|
collection = TablesFactory(collection_id=collection_name, state=Tables.NORMAL)
|
|
to_index_files = TableFilesFactory.create_batch(
|
|
to_index_cnt, collection=collection, file_type=TableFiles.FILE_TYPE_TO_INDEX)
|
|
topk = random.randint(5, 10)
|
|
nq = random.randint(5, 10)
|
|
param = {
|
|
'collection_name': collection_name,
|
|
'query_records': self.random_data(nq, collection.dimension),
|
|
'top_k': topk,
|
|
'params': {'nprobe': 2049}
|
|
}
|
|
|
|
result = [
|
|
milvus_pb2.TopKQueryResult(query_result_arrays=[
|
|
milvus_pb2.QueryResult(id=i, distance=random.random())
|
|
for i in range(topk)
|
|
]) for i in range(nq)
|
|
]
|
|
|
|
mock_results = milvus_pb2.TopKQueryResultList(status=status_pb2.Status(
|
|
error_code=status_pb2.SUCCESS, reason="Success"),
|
|
topk_query_result=result)
|
|
|
|
collection_schema = CollectionSchema(collection_name=collection_name,
|
|
index_file_size=collection.index_file_size,
|
|
metric_type=collection.metric_type,
|
|
dimension=collection.dimension)
|
|
|
|
status, _ = self.client.search_vectors(**param)
|
|
assert status.code == Status.ILLEGAL_ARGUMENT
|
|
|
|
param['params']['nprobe'] = 2048
|
|
RouterMixin.connection = mock.MagicMock(return_value=Milvus())
|
|
RouterMixin.query_conn.conn = mock.MagicMock(return_value=Milvus())
|
|
Milvus.describe_collection = mock.MagicMock(return_value=(BAD,
|
|
collection_schema))
|
|
status, ret = self.client.search_vectors(**param)
|
|
assert status.code == Status.COLLECTION_NOT_EXISTS
|
|
|
|
Milvus.describe_collection = mock.MagicMock(return_value=(OK, collection_schema))
|
|
Milvus.search_vectors_in_files = mock.MagicMock(
|
|
return_value=mock_results)
|
|
|
|
status, ret = self.client.search_vectors(**param)
|
|
assert status.OK()
|
|
assert len(ret) == nq
|