BossZou f10f6cd5f4
Support run dev test with http handler in python SDK (#1116)
* refactoring(create_table done)

* refactoring

* refactor server delivery (insert done)

* refactoring server module (count_table done)

* server refactor done

* cmake pass

* refactor server module done.

* set grpc response status correctly

* format done.

* fix redefine ErrorMap()

* optimize insert reducing ids data copy

* optimize grpc request with reducing data copy

* clang format

* [skip ci] Refactor server module done. update changlog. prepare for PR

* remove explicit and change int32_t to int64_t

* add web server

* [skip ci] add license in web module

* modify header include & comment oatpp environment config

* add port configure & create table in handler

* modify web url

* simple url complation done & add swagger

* make sure web url

* web functionality done. debuging

* add web unittest

* web test pass

* add web server port

* add web server port in template

* update unittest cmake file

* change web server default port to 19121

* rename method in web module & unittest pass

* add search case in unittest for web module

* rename some variables

* fix bug

* unittest pass

* web prepare

* fix cmd bug(check server status)

* update changlog

* add web port validate & default set

* clang-format pass

* add web port test in unittest

* add CORS & redirect root to swagger ui

* add web status

* web table method func cascade test pass

* add config url in web module

* modify thirdparty cmake to avoid building oatpp test

* clang format

* update changlog

* add constants in web module

* reserve Config.cpp

* fix constants reference bug

* replace web server with async module

* modify component to support async

* format

* developing controller & add test clent into unittest

* add web port into demo/server_config

* modify thirdparty cmake to allow build test

* remove  unnecessary comment

* add endpoint info in controller

* finish web test(bug here)

* clang format

* add web test cpp to lint exclusions

* check null field in GetConfig

* add macro RETURN STATUS DTo

* fix cmake conflict

* fix crash when exit server

* remove surplus comments & add http param check

* add uri /docs to direct swagger

* format

* change cmd to system

* add default value & unittest in web module

* add macros to judge if GPU supported

* add macros in unit & add default in index dto & print error message when bind http port fail

* format (fix #788)

* fix cors bug (not completed)

* comment cors

* change web framework to simple api

* comments optimize

* change to simple API

* remove comments in controller.hpp

* remove EP_COMMON_CMAKE_ARGS in oatpp and oatpp-swagger

* add ep cmake args to sqlite

* clang-format

* change a format

* test pass

* change name to

* fix compiler issue(oatpp-swagger depend on oatpp)

* add & in start_server.h

* specify lib location with oatpp and oatpp-swagger

* add comments

* add swagger definition

* [skip ci] change http method options status code

* remove oatpp swagger(fix #970)

* remove comments

* check Start web behavior

* add default to cpu_cache_capacity

* remove swagger component.hpp & /docs url

* remove /docs info

* remove /docs in unittest

* remove space in test rpc

* remove repeate info in CHANGLOG

* change cache_insert_data default value as a constant

* [skip ci] Fix some broken links (#960)

* [skip ci] Fix broken link

* [skip ci] Fix broken link

* [skip ci] Fix broken link

* [skip ci] Fix broken links

* fix issue 373 (#964)

* fix issue 373

* Adjustment format

* Adjustment format

* Adjustment format

* change readme

* #966 update NOTICE.md (#967)

* remove comments

* check Start web behavior

* add default to cpu_cache_capacity

* remove swagger component.hpp & /docs url

* remove /docs info

* remove /docs in unittest

* remove space in test rpc

* remove repeate info in CHANGLOG

* change cache_insert_data default value as a constant

* adjust web port cofig place

* rename web_port variable

* change gpu resources invoke way to cmd()

* set advanced config name add DEFAULT

* change config setting to cmd

* modify ..

* optimize code

* assign TableDto' count default value 0 (fix #995)

* check if table exists when show partitions (fix #1028)

* check table exists when drop partition (fix #1029)

* check if partition name is legal (fix #1022)

* modify status code when partition tag is illegal

* update changlog

* add info to /system url

* add binary index and add bin uri & handler method(not completed)

* optimize http insert and search time(fix #1066) | add binary vectors support(fix #1067)

* fix test partition bug

* fix test bug when check insert records

* add binary vectors test

* add default for offset and page_size

* fix uinttest bug

* [skip ci] remove comments

* optimize web code for PR comments

* add new folder named utils

* check offset and pagesize (fix #1082)

* improve error message if offset or page_size is not legal (fix #1075)

* add log into web module

* update changlog

* check gpu sources setting when assign repeated value (fix #990)

* update changlog

* clang-format pass

* add default handler in http handler

* [skip ci] improve error msg when check gpu resources

* change check offset way

* remove func IsIntStr

* add case

* change int32 to int64 when check number str

* add log in we module(doing)

* update test case

* add log in web controller

* remove surplus dot

* add preload into /system/

* change get_milvus() to get_milvus(args['handler'])

* support load table into memory with http server (fix #1115)

* [skip ci] comment surplus dto in VectorDto

Co-authored-by: jielinxu <52057195+jielinxu@users.noreply.github.com>
Co-authored-by: JackLCL <53512883+JackLCL@users.noreply.github.com>
Co-authored-by: Cai Yudong <yudong.cai@zilliz.com>
2020-02-14 11:07:09 +08:00

1051 lines
38 KiB
Python

import random
import pdb
import pytest
import logging
import itertools
import numpy
from time import sleep
from multiprocessing import Process
from milvus import IndexType, MetricType
from utils import *
dim = 128
delete_table_interval_time = 3
index_file_size = 10
vectors = gen_vectors(100, dim)
class TestTable:
"""
******************************************************************
The following cases are used to test `create_table` function
******************************************************************
"""
def test_create_table(self, connect):
'''
target: test create normal table
method: create table with corrent params
expected: create status return ok
'''
table_name = gen_unique_str("test_table")
param = {'table_name': table_name,
'dimension': dim,
'index_file_size': index_file_size,
'metric_type': MetricType.L2}
status = connect.create_table(param)
assert status.OK()
def test_create_table_ip(self, connect):
'''
target: test create normal table
method: create table with corrent params
expected: create status return ok
'''
table_name = gen_unique_str("test_table")
param = {'table_name': table_name,
'dimension': dim,
'index_file_size': index_file_size,
'metric_type': MetricType.IP}
status = connect.create_table(param)
assert status.OK()
def test_create_table_jaccard(self, connect):
'''
target: test create normal table
method: create table with corrent params
expected: create status return ok
'''
table_name = gen_unique_str("test_table")
param = {'table_name': table_name,
'dimension': dim,
'index_file_size': index_file_size,
'metric_type': MetricType.JACCARD}
status = connect.create_table(param)
assert status.OK()
def test_create_table_hamming(self, connect):
'''
target: test create normal table
method: create table with corrent params
expected: create status return ok
'''
table_name = gen_unique_str("test_table")
param = {'table_name': table_name,
'dimension': dim,
'index_file_size': index_file_size,
'metric_type': MetricType.HAMMING}
status = connect.create_table(param)
assert status.OK()
@pytest.mark.level(2)
def test_create_table_without_connection(self, dis_connect):
'''
target: test create table, without connection
method: create table with correct params, with a disconnected instance
expected: create raise exception
'''
table_name = gen_unique_str("test_table")
param = {'table_name': table_name,
'dimension': dim,
'index_file_size': index_file_size,
'metric_type': MetricType.L2}
with pytest.raises(Exception) as e:
status = dis_connect.create_table(param)
def test_create_table_existed(self, connect):
'''
target: test create table but the table name have already existed
method: create table with the same table_name
expected: create status return not ok
'''
table_name = gen_unique_str("test_table")
param = {'table_name': table_name,
'dimension': dim,
'index_file_size': index_file_size,
'metric_type': MetricType.L2}
status = connect.create_table(param)
status = connect.create_table(param)
assert not status.OK()
@pytest.mark.level(2)
def test_create_table_existed_ip(self, connect):
'''
target: test create table but the table name have already existed
method: create table with the same table_name
expected: create status return not ok
'''
table_name = gen_unique_str("test_table")
param = {'table_name': table_name,
'dimension': dim,
'index_file_size': index_file_size,
'metric_type': MetricType.IP}
status = connect.create_table(param)
status = connect.create_table(param)
assert not status.OK()
def test_create_table_None(self, connect):
'''
target: test create table but the table name is None
method: create table, param table_name is None
expected: create raise error
'''
param = {'table_name': None,
'dimension': dim,
'index_file_size': index_file_size,
'metric_type': MetricType.L2}
with pytest.raises(Exception) as e:
status = connect.create_table(param)
def test_create_table_no_dimension(self, connect):
'''
target: test create table with no dimension params
method: create table with corrent params
expected: create status return ok
'''
table_name = gen_unique_str("test_table")
param = {'table_name': table_name,
'index_file_size': index_file_size,
'metric_type': MetricType.L2}
with pytest.raises(Exception) as e:
status = connect.create_table(param)
def test_create_table_no_file_size(self, connect):
'''
target: test create table with no index_file_size params
method: create table with corrent params
expected: create status return ok, use default 1024
'''
table_name = gen_unique_str("test_table")
param = {'table_name': table_name,
'dimension': dim,
'metric_type': MetricType.L2}
status = connect.create_table(param)
logging.getLogger().info(status)
status, result = connect.describe_table(table_name)
logging.getLogger().info(result)
assert result.index_file_size == 1024
def test_create_table_no_metric_type(self, connect):
'''
target: test create table with no metric_type params
method: create table with corrent params
expected: create status return ok, use default L2
'''
table_name = gen_unique_str("test_table")
param = {'table_name': table_name,
'dimension': dim,
'index_file_size': index_file_size}
status = connect.create_table(param)
status, result = connect.describe_table(table_name)
logging.getLogger().info(result)
assert result.metric_type == MetricType.L2
"""
******************************************************************
The following cases are used to test `describe_table` function
******************************************************************
"""
def test_table_describe_result(self, connect):
'''
target: test describe table created with correct params
method: create table, assert the value returned by describe method
expected: table_name equals with the table name created
'''
table_name = gen_unique_str("test_table")
param = {'table_name': table_name,
'dimension': dim,
'index_file_size': index_file_size,
'metric_type': MetricType.L2}
connect.create_table(param)
status, res = connect.describe_table(table_name)
assert res.table_name == table_name
assert res.metric_type == MetricType.L2
@pytest.mark.level(2)
def test_table_describe_table_name_ip(self, connect):
'''
target: test describe table created with correct params
method: create table, assert the value returned by describe method
expected: table_name equals with the table name created
'''
table_name = gen_unique_str("test_table")
param = {'table_name': table_name,
'dimension': dim,
'index_file_size': index_file_size,
'metric_type': MetricType.IP}
connect.create_table(param)
status, res = connect.describe_table(table_name)
assert res.table_name == table_name
assert res.metric_type == MetricType.IP
@pytest.mark.level(2)
def test_table_describe_table_name_jaccard(self, connect):
'''
target: test describe table created with correct params
method: create table, assert the value returned by describe method
expected: table_name equals with the table name created
'''
table_name = gen_unique_str("test_table")
param = {'table_name': table_name,
'dimension': dim,
'index_file_size': index_file_size,
'metric_type': MetricType.JACCARD}
connect.create_table(param)
status, res = connect.describe_table(table_name)
assert res.table_name == table_name
assert res.metric_type == MetricType.JACCARD
@pytest.mark.level(2)
def test_table_describe_table_name_hamming(self, connect):
'''
target: test describe table created with correct params
method: create table, assert the value returned by describe method
expected: table_name equals with the table name created
'''
table_name = gen_unique_str("test_table")
param = {'table_name': table_name,
'dimension': dim,
'index_file_size': index_file_size,
'metric_type': MetricType.HAMMING}
connect.create_table(param)
status, res = connect.describe_table(table_name)
assert res.table_name == table_name
assert res.metric_type == MetricType.HAMMING
# TODO: enable
@pytest.mark.level(2)
def _test_table_describe_table_name_multiprocessing(self, connect, args):
'''
target: test describe table created with multiprocess
method: create table, assert the value returned by describe method
expected: table_name equals with the table name created
'''
table_name = gen_unique_str("test_table")
uri = "tcp://%s:%s" % (args["ip"], args["port"])
param = {'table_name': table_name,
'dimension': dim,
'index_file_size': index_file_size,
'metric_type': MetricType.L2}
connect.create_table(param)
def describetable(milvus):
status, res = milvus.describe_table(table_name)
assert res.table_name == table_name
process_num = 4
processes = []
for i in range(process_num):
milvus = get_milvus(args["handler"])
milvus.connect(uri=uri)
p = Process(target=describetable, args=(milvus,))
processes.append(p)
p.start()
for p in processes:
p.join()
@pytest.mark.level(2)
def test_table_describe_without_connection(self, table, dis_connect):
'''
target: test describe table, without connection
method: describe table with correct params, with a disconnected instance
expected: describe raise exception
'''
with pytest.raises(Exception) as e:
status = dis_connect.describe_table(table)
def test_table_describe_dimension(self, connect):
'''
target: test describe table created with correct params
method: create table, assert the dimention value returned by describe method
expected: dimention equals with dimention when created
'''
table_name = gen_unique_str("test_table")
param = {'table_name': table_name,
'dimension': dim+1,
'index_file_size': index_file_size,
'metric_type': MetricType.L2}
connect.create_table(param)
status, res = connect.describe_table(table_name)
assert res.dimension == dim+1
"""
******************************************************************
The following cases are used to test `delete_table` function
******************************************************************
"""
def test_delete_table(self, connect, table):
'''
target: test delete table created with correct params
method: create table and then delete,
assert the value returned by delete method
expected: status ok, and no table in tables
'''
status = connect.delete_table(table)
assert not assert_has_table(connect, table)
@pytest.mark.level(2)
def test_delete_table_ip(self, connect, ip_table):
'''
target: test delete table created with correct params
method: create table and then delete,
assert the value returned by delete method
expected: status ok, and no table in tables
'''
status = connect.delete_table(ip_table)
assert not assert_has_table(connect, ip_table)
@pytest.mark.level(2)
def test_delete_table_jaccard(self, connect, jac_table):
'''
target: test delete table created with correct params
method: create table and then delete,
assert the value returned by delete method
expected: status ok, and no table in tables
'''
status = connect.delete_table(jac_table)
assert not assert_has_table(connect, jac_table)
@pytest.mark.level(2)
def test_delete_table_hamming(self, connect, ham_table):
'''
target: test delete table created with correct params
method: create table and then delete,
assert the value returned by delete method
expected: status ok, and no table in tables
'''
status = connect.delete_table(ham_table)
assert not assert_has_table(connect, ham_table)
@pytest.mark.level(2)
def test_table_delete_without_connection(self, table, dis_connect):
'''
target: test describe table, without connection
method: describe table with correct params, with a disconnected instance
expected: describe raise exception
'''
with pytest.raises(Exception) as e:
status = dis_connect.delete_table(table)
def test_delete_table_not_existed(self, connect):
'''
target: test delete table not in index
method: delete all tables, and delete table again,
assert the value returned by delete method
expected: status not ok
'''
table_name = gen_unique_str("test_table")
status = connect.delete_table(table_name)
assert not status.OK()
def test_delete_table_repeatedly(self, connect):
'''
target: test delete table created with correct params
method: create table and delete new table repeatedly,
assert the value returned by delete method
expected: create ok and delete ok
'''
loops = 1
for i in range(loops):
table_name = gen_unique_str("test_table")
param = {'table_name': table_name,
'dimension': dim,
'index_file_size': index_file_size,
'metric_type': MetricType.L2}
connect.create_table(param)
status = connect.delete_table(table_name)
time.sleep(1)
assert not assert_has_table(connect, table_name)
def test_delete_create_table_repeatedly(self, connect):
'''
target: test delete and create the same table repeatedly
method: try to create the same table and delete repeatedly,
assert the value returned by delete method
expected: create ok and delete ok
'''
loops = 5
for i in range(loops):
table_name = "test_table"
param = {'table_name': table_name,
'dimension': dim,
'index_file_size': index_file_size,
'metric_type': MetricType.L2}
connect.create_table(param)
status = connect.delete_table(table_name)
time.sleep(2)
assert status.OK()
def test_delete_create_table_repeatedly_ip(self, connect):
'''
target: test delete and create the same table repeatedly
method: try to create the same table and delete repeatedly,
assert the value returned by delete method
expected: create ok and delete ok
'''
loops = 5
for i in range(loops):
table_name = "test_table"
param = {'table_name': table_name,
'dimension': dim,
'index_file_size': index_file_size,
'metric_type': MetricType.IP}
connect.create_table(param)
status = connect.delete_table(table_name)
time.sleep(2)
assert status.OK()
# TODO: enable
@pytest.mark.level(2)
def _test_delete_table_multiprocessing(self, args):
'''
target: test delete table with multiprocess
method: create table and then delete,
assert the value returned by delete method
expected: status ok, and no table in tables
'''
process_num = 6
processes = []
uri = "tcp://%s:%s" % (args["ip"], args["port"])
def deletetable(milvus):
status = milvus.delete_table(table)
# assert not status.code==0
assert assert_has_table(milvus, table)
assert status.OK()
for i in range(process_num):
milvus = get_milvus(args["handler"])
milvus.connect(uri=uri)
p = Process(target=deletetable, args=(milvus,))
processes.append(p)
p.start()
for p in processes:
p.join()
# TODO: enable
@pytest.mark.level(2)
def _test_delete_table_multiprocessing_multitable(self, connect):
'''
target: test delete table with multiprocess
method: create table and then delete,
assert the value returned by delete method
expected: status ok, and no table in tables
'''
process_num = 5
loop_num = 2
processes = []
table = []
j = 0
while j < (process_num*loop_num):
table_name = gen_unique_str("test_delete_table_with_multiprocessing")
table.append(table_name)
param = {'table_name': table_name,
'dimension': dim,
'index_file_size': index_file_size,
'metric_type': MetricType.L2}
connect.create_table(param)
j = j + 1
def delete(connect,ids):
i = 0
while i < loop_num:
status = connect.delete_table(table[ids*process_num+i])
time.sleep(2)
assert status.OK()
assert not assert_has_table(connect, table[ids*process_num+i])
i = i + 1
for i in range(process_num):
ids = i
p = Process(target=delete, args=(connect,ids))
processes.append(p)
p.start()
for p in processes:
p.join()
"""
******************************************************************
The following cases are used to test `has_table` function
******************************************************************
"""
def test_has_table(self, connect):
'''
target: test if the created table existed
method: create table, assert the value returned by has_table method
expected: True
'''
table_name = gen_unique_str("test_table")
param = {'table_name': table_name,
'dimension': dim,
'index_file_size': index_file_size,
'metric_type': MetricType.L2}
connect.create_table(param)
assert assert_has_table(connect, table_name)
def test_has_table_ip(self, connect):
'''
target: test if the created table existed
method: create table, assert the value returned by has_table method
expected: True
'''
table_name = gen_unique_str("test_table")
param = {'table_name': table_name,
'dimension': dim,
'index_file_size': index_file_size,
'metric_type': MetricType.IP}
connect.create_table(param)
assert assert_has_table(connect, table_name)
def test_has_table_jaccard(self, connect):
'''
target: test if the created table existed
method: create table, assert the value returned by has_table method
expected: True
'''
table_name = gen_unique_str("test_table")
param = {'table_name': table_name,
'dimension': dim,
'index_file_size': index_file_size,
'metric_type': MetricType.JACCARD}
connect.create_table(param)
assert assert_has_table(connect, table_name)
def test_has_table_hamming(self, connect):
'''
target: test if the created table existed
method: create table, assert the value returned by has_table method
expected: True
'''
table_name = gen_unique_str("test_table")
param = {'table_name': table_name,
'dimension': dim,
'index_file_size': index_file_size,
'metric_type': MetricType.HAMMING}
connect.create_table(param)
assert assert_has_table(connect, table_name)
@pytest.mark.level(2)
def test_has_table_without_connection(self, table, dis_connect):
'''
target: test has table, without connection
method: calling has table with correct params, with a disconnected instance
expected: has table raise exception
'''
with pytest.raises(Exception) as e:
assert_has_table(dis_connect, table)
def test_has_table_not_existed(self, connect):
'''
target: test if table not created
method: random a table name, which not existed in db,
assert the value returned by has_table method
expected: False
'''
table_name = gen_unique_str("test_table")
assert not assert_has_table(connect, table_name)
"""
******************************************************************
The following cases are used to test `show_tables` function
******************************************************************
"""
def test_show_tables(self, connect):
'''
target: test show tables is correct or not, if table created
method: create table, assert the value returned by show_tables method is equal to 0
expected: table_name in show tables
'''
table_name = gen_unique_str("test_table")
param = {'table_name': table_name,
'dimension': dim,
'index_file_size': index_file_size,
'metric_type': MetricType.L2}
connect.create_table(param)
status, result = connect.show_tables()
assert status.OK()
assert table_name in result
def test_show_tables_ip(self, connect):
'''
target: test show tables is correct or not, if table created
method: create table, assert the value returned by show_tables method is equal to 0
expected: table_name in show tables
'''
table_name = gen_unique_str("test_table")
param = {'table_name': table_name,
'dimension': dim,
'index_file_size': index_file_size,
'metric_type': MetricType.IP}
connect.create_table(param)
status, result = connect.show_tables()
assert status.OK()
assert table_name in result
def test_show_tables_jaccard(self, connect):
'''
target: test show tables is correct or not, if table created
method: create table, assert the value returned by show_tables method is equal to 0
expected: table_name in show tables
'''
table_name = gen_unique_str("test_table")
param = {'table_name': table_name,
'dimension': dim,
'index_file_size': index_file_size,
'metric_type': MetricType.JACCARD}
connect.create_table(param)
status, result = connect.show_tables()
assert status.OK()
assert table_name in result
def test_show_tables_hamming(self, connect):
'''
target: test show tables is correct or not, if table created
method: create table, assert the value returned by show_tables method is equal to 0
expected: table_name in show tables
'''
table_name = gen_unique_str("test_table")
param = {'table_name': table_name,
'dimension': dim,
'index_file_size': index_file_size,
'metric_type': MetricType.HAMMING}
connect.create_table(param)
status, result = connect.show_tables()
assert status.OK()
assert table_name in result
@pytest.mark.level(2)
def test_show_tables_without_connection(self, dis_connect):
'''
target: test show_tables, without connection
method: calling show_tables with correct params, with a disconnected instance
expected: show_tables raise exception
'''
with pytest.raises(Exception) as e:
status = dis_connect.show_tables()
def test_show_tables_no_table(self, connect):
'''
target: test show tables is correct or not, if no table in db
method: delete all tables,
assert the value returned by show_tables method is equal to []
expected: the status is ok, and the result is equal to []
'''
status, result = connect.show_tables()
if result:
for table_name in result:
connect.delete_table(table_name)
time.sleep(delete_table_interval_time)
status, result = connect.show_tables()
assert status.OK()
assert len(result) == 0
# TODO: enable
@pytest.mark.level(2)
def _test_show_tables_multiprocessing(self, connect, args):
'''
target: test show tables is correct or not with processes
method: create table, assert the value returned by show_tables method is equal to 0
expected: table_name in show tables
'''
table_name = gen_unique_str("test_table")
uri = "tcp://%s:%s" % (args["ip"], args["port"])
param = {'table_name': table_name,
'dimension': dim,
'index_file_size': index_file_size,
'metric_type': MetricType.L2}
connect.create_table(param)
def showtables(milvus):
status, result = milvus.show_tables()
assert status.OK()
assert table_name in result
process_num = 8
processes = []
for i in range(process_num):
milvus = get_milvus(args["handler"])
milvus.connect(uri=uri)
p = Process(target=showtables, args=(milvus,))
processes.append(p)
p.start()
for p in processes:
p.join()
"""
******************************************************************
The following cases are used to test `preload_table` function
******************************************************************
"""
"""
generate valid create_index params
"""
@pytest.fixture(
scope="function",
params=gen_simple_index_params()
)
def get_simple_index_params(self, request, connect):
if str(connect._cmd("mode")[1]) == "CPU":
if request.param["index_type"] == IndexType.IVF_SQ8H:
pytest.skip("sq8h not support in open source")
if request.param["index_type"] == IndexType.IVF_PQ:
pytest.skip("Skip PQ Temporary")
return request.param
@pytest.mark.level(1)
def test_preload_table(self, connect, table, get_simple_index_params):
index_params = get_simple_index_params
status, ids = connect.add_vectors(table, vectors)
status = connect.create_index(table, index_params)
status = connect.preload_table(table)
assert status.OK()
@pytest.mark.level(1)
def test_preload_table_ip(self, connect, ip_table, get_simple_index_params):
index_params = get_simple_index_params
status, ids = connect.add_vectors(ip_table, vectors)
status = connect.create_index(ip_table, index_params)
status = connect.preload_table(ip_table)
assert status.OK()
@pytest.mark.level(1)
def test_preload_table_jaccard(self, connect, jac_table, get_simple_index_params):
index_params = get_simple_index_params
status, ids = connect.add_vectors(jac_table, vectors)
status = connect.create_index(jac_table, index_params)
status = connect.preload_table(jac_table)
assert status.OK()
@pytest.mark.level(1)
def test_preload_table_hamming(self, connect, ham_table, get_simple_index_params):
index_params = get_simple_index_params
status, ids = connect.add_vectors(ham_table, vectors)
status = connect.create_index(ham_table, index_params)
status = connect.preload_table(ham_table)
assert status.OK()
@pytest.mark.level(1)
def test_preload_table_not_existed(self, connect, table):
table_name = gen_unique_str()
nlist = 16384
index_param = {"index_type": IndexType.IVF_SQ8, "nlist": nlist}
status, ids = connect.add_vectors(table, vectors)
status = connect.create_index(table, index_param)
status = connect.preload_table(table_name)
assert not status.OK()
@pytest.mark.level(2)
def test_preload_table_not_existed_ip(self, connect, ip_table):
table_name = gen_unique_str()
nlist = 16384
index_param = {"index_type": IndexType.IVF_SQ8, "nlist": nlist}
status, ids = connect.add_vectors(ip_table, vectors)
status = connect.create_index(ip_table, index_param)
status = connect.preload_table(table_name)
assert not status.OK()
@pytest.mark.level(1)
def test_preload_table_no_vectors(self, connect, table):
status = connect.preload_table(table)
assert status.OK()
@pytest.mark.level(2)
def test_preload_table_no_vectors_ip(self, connect, ip_table):
status = connect.preload_table(ip_table)
assert status.OK()
# TODO: psutils get memory usage
@pytest.mark.level(1)
def test_preload_table_memory_usage(self, connect, table):
pass
class TestTableInvalid(object):
"""
Test creating table with invalid table names
"""
@pytest.fixture(
scope="function",
params=gen_invalid_table_names()
)
def get_table_name(self, request):
yield request.param
@pytest.mark.level(2)
def test_create_table_with_invalid_tablename(self, connect, get_table_name):
table_name = get_table_name
param = {'table_name': table_name,
'dimension': dim,
'index_file_size': index_file_size,
'metric_type': MetricType.L2}
status = connect.create_table(param)
assert not status.OK()
def test_create_table_with_empty_tablename(self, connect):
table_name = ''
param = {'table_name': table_name,
'dimension': dim,
'index_file_size': index_file_size,
'metric_type': MetricType.L2}
with pytest.raises(Exception) as e:
status = connect.create_table(param)
def test_preload_table_with_invalid_tablename(self, connect):
table_name = ''
with pytest.raises(Exception) as e:
status = connect.preload_table(table_name)
class TestCreateTableDimInvalid(object):
"""
Test creating table with invalid dimension
"""
@pytest.fixture(
scope="function",
params=gen_invalid_dims()
)
def get_dim(self, request):
yield request.param
@pytest.mark.level(2)
@pytest.mark.timeout(5)
def test_create_table_with_invalid_dimension(self, connect, get_dim):
dimension = get_dim
table = gen_unique_str("test_create_table_with_invalid_dimension")
param = {'table_name': table,
'dimension': dimension,
'index_file_size': index_file_size,
'metric_type': MetricType.L2}
if isinstance(dimension, int):
status = connect.create_table(param)
assert not status.OK()
else:
with pytest.raises(Exception) as e:
status = connect.create_table(param)
# TODO: max / min index file size
class TestCreateTableIndexSizeInvalid(object):
"""
Test creating tables with invalid index_file_size
"""
@pytest.fixture(
scope="function",
params=gen_invalid_file_sizes()
)
def get_file_size(self, request):
yield request.param
@pytest.mark.level(2)
def test_create_table_with_invalid_file_size(self, connect, table, get_file_size):
file_size = get_file_size
param = {'table_name': table,
'dimension': dim,
'index_file_size': file_size,
'metric_type': MetricType.L2}
if isinstance(file_size, int):
status = connect.create_table(param)
assert not status.OK()
else:
with pytest.raises(Exception) as e:
status = connect.create_table(param)
class TestCreateMetricTypeInvalid(object):
"""
Test creating tables with invalid metric_type
"""
@pytest.fixture(
scope="function",
params=gen_invalid_metric_types()
)
def get_metric_type(self, request):
yield request.param
@pytest.mark.level(2)
def test_create_table_with_invalid_file_size(self, connect, table, get_metric_type):
metric_type = get_metric_type
param = {'table_name': table,
'dimension': dim,
'index_file_size': 10,
'metric_type': metric_type}
with pytest.raises(Exception) as e:
status = connect.create_table(param)
def create_table(connect, **params):
param = {'table_name': params["table_name"],
'dimension': params["dimension"],
'index_file_size': index_file_size,
'metric_type': MetricType.L2}
status = connect.create_table(param)
return status
def search_table(connect, **params):
status, result = connect.search_vectors(
params["table_name"],
params["top_k"],
params["nprobe"],
params["query_vectors"])
return status
def preload_table(connect, **params):
status = connect.preload_table(params["table_name"])
return status
def has(connect, **params):
status, result = connect.has_table(params["table_name"])
return status
def show(connect, **params):
status, result = connect.show_tables()
return status
def delete(connect, **params):
status = connect.delete_table(params["table_name"])
return status
def describe(connect, **params):
status, result = connect.describe_table(params["table_name"])
return status
def rowcount(connect, **params):
status, result = connect.get_table_row_count(params["table_name"])
return status
def create_index(connect, **params):
status = connect.create_index(params["table_name"], params["index_params"])
return status
func_map = {
# 0:has,
1:show,
10:create_table,
11:describe,
12:rowcount,
13:search_table,
14:preload_table,
15:create_index,
30:delete
}
def gen_sequence():
raw_seq = func_map.keys()
result = itertools.permutations(raw_seq)
for x in result:
yield x
class TestTableLogic(object):
@pytest.mark.parametrize("logic_seq", gen_sequence())
@pytest.mark.level(2)
def test_logic(self, connect, logic_seq):
if self.is_right(logic_seq):
self.execute(logic_seq, connect)
else:
self.execute_with_error(logic_seq, connect)
def is_right(self, seq):
if sorted(seq) == seq:
return True
not_created = True
has_deleted = False
for i in range(len(seq)):
if seq[i] > 10 and not_created:
return False
elif seq [i] > 10 and has_deleted:
return False
elif seq[i] == 10:
not_created = False
elif seq[i] == 30:
has_deleted = True
return True
def execute(self, logic_seq, connect):
basic_params = self.gen_params()
for i in range(len(logic_seq)):
# logging.getLogger().info(logic_seq[i])
f = func_map[logic_seq[i]]
status = f(connect, **basic_params)
assert status.OK()
def execute_with_error(self, logic_seq, connect):
basic_params = self.gen_params()
error_flag = False
for i in range(len(logic_seq)):
f = func_map[logic_seq[i]]
status = f(connect, **basic_params)
if not status.OK():
# logging.getLogger().info(logic_seq[i])
error_flag = True
break
assert error_flag == True
def gen_params(self):
table_name = gen_unique_str("test_table")
top_k = 1
vectors = gen_vectors(2, dim)
param = {'table_name': table_name,
'dimension': dim,
'index_type': IndexType.IVFLAT,
'metric_type': MetricType.L2,
'nprobe': 1,
'top_k': top_k,
'index_params': {
'index_type': IndexType.IVF_SQ8,
'nlist': 16384
},
'query_vectors': vectors}
return param