Add test cases for rename collection (#22339)

Signed-off-by: Binbin Lv <binbin.lv@zilliz.com>
pull/22402/head
binbin 2023-02-24 08:55:49 +08:00 committed by GitHub
parent 7808bb518d
commit 62d0c2faad
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 317 additions and 1 deletions

View File

@ -71,6 +71,10 @@ class ApiCollectionWrapper:
def _shards_num(self):
return self.collection._shards_num
@property
def aliases(self):
return self.collection.aliases
@trace()
def construct_from_dataframe(self, name, dataframe, check_task=None, check_items=None, **kwargs):
func_name = sys._getframe().f_code.co_name

View File

@ -505,3 +505,13 @@ class ApiUtilityWrapper:
check_result = ResponseChecker(res, func_name, check_task, check_items, check, **kwargs).run()
return res, check_result
def rename_collection(self, old_collection_name, new_collection_name, timeout=None, check_task=None,
check_items=None, **kwargs):
func_name = sys._getframe().f_code.co_name
res, check = api_request([self.ut.rename_collection, old_collection_name, new_collection_name, timeout], **kwargs)
check_result = ResponseChecker(res, func_name, check_task, check_items, check,
old_collection_name=old_collection_name, new_collection_name=new_collection_name,
timeout=timeout, **kwargs).run()
return res, check_result

View File

@ -104,6 +104,16 @@ get_not_string = [
[1, "2", 3]
]
get_not_string_value = [
" ",
"12-s",
"12 s",
"(mn)",
"中文",
"%$#",
"a".join("a" for i in range(256))
]
get_invalid_vectors = [
"1*2",
[1],

View File

@ -441,6 +441,40 @@ class TestDeleteOperation(TestcaseBase):
# since the search requests arrived query nodes earlier than query nodes consume the delete requests.
assert len(inter) == 0
@pytest.mark.tags(CaseLabel.L2)
def test_delete_search_rename_collection(self):
"""
target: test delete and search in the renamed collection
method: search entities after it was deleted
expected: deleted entity is not in the search result
"""
# init collection with nb default data
collection_w, _, _, ids = self.init_collection_general(prefix, insert_data=True)[0:4]
entity, _ = collection_w.query(tmp_expr, output_fields=["%"])
search_res, _ = collection_w.search([entity[0][ct.default_float_vec_field_name]],
ct.default_float_vec_field_name,
ct.default_search_params, ct.default_limit)
# assert search results contains entity
assert 0 in search_res[0].ids
# rename collection
old_collection_name = collection_w.name
new_collection_name = cf.gen_unique_str(prefix + "new")
self.utility_wrap.rename_collection(old_collection_name, new_collection_name)
collection_w = self.init_collection_wrap(name=new_collection_name)
# delete entities
expr = f'{ct.default_int64_field_name} in {ids[:ct.default_nb // 2]}'
collection_w.delete(expr)
search_res_2, _ = collection_w.search([entity[0][ct.default_float_vec_field_name]],
ct.default_float_vec_field_name,
ct.default_search_params, ct.default_limit)
# assert search result is not equal to entity
log.debug(f"Second search result ids: {search_res_2[0].ids}")
inter = set(ids[:ct.default_nb // 2]
).intersection(set(search_res_2[0].ids))
# Using bounded staleness, we could still search the "deleted" entities,
# since the search requests arrived query nodes earlier than query nodes consume the delete requests.
assert len(inter) == 0
@pytest.mark.tags(CaseLabel.L1)
def test_delete_expr_repeated_values(self):
"""

View File

@ -1078,7 +1078,11 @@ class TestCollectionSearch(TestcaseBase):
# 1. initialize with data
collection_w, _, _, insert_ids = \
self.init_collection_general(prefix, True, auto_id=auto_id, dim=dim)[0:4]
# 2. search
# 2. rename collection
new_collection_name = cf.gen_unique_str(prefix + "new")
self.utility_wrap.rename_collection(collection_w.name, new_collection_name)
collection_w = self.init_collection_general(auto_id=auto_id, dim=dim, name=new_collection_name)[0]
# 3. search
log.info("test_search_normal_default_params: searching collection %s" % collection_w.name)
vectors = [[random.random() for _ in range(dim)] for _ in range(default_nq)]
collection_w.search(vectors[:default_nq], default_search_field,
@ -1394,12 +1398,20 @@ class TestCollectionSearch(TestcaseBase):
expected: search successfully with the non_default shards_num
"""
self._connect()
# 1. create collection
name = cf.gen_unique_str(prefix)
collection_w = self.init_collection_wrap(name=name, shards_num=shards_num)
# 2. rename collection
new_collection_name = cf.gen_unique_str(prefix + "new")
self.utility_wrap.rename_collection(collection_w.name, new_collection_name)
collection_w = self.init_collection_wrap(name=new_collection_name, shards_num=shards_num)
# 3. insert
dataframe = cf.gen_default_dataframe_data()
collection_w.insert(dataframe)
# 4. create index and load
collection_w.create_index(ct.default_float_vec_field_name, index_params=ct.default_flat_index)
collection_w.load()
# 5. search
vectors = [[random.random() for _ in range(default_dim)] for _ in range(default_nq)]
collection_w.search(vectors[:default_nq], default_search_field,
default_search_params, default_limit,

View File

@ -27,6 +27,7 @@ loading_progress = "loading_progress"
num_loaded_partitions = "num_loaded_partitions"
not_loaded_partitions = "not_loaded_partitions"
exp_name = "name"
exp_schema = "schema"
class TestUtilityParams(TestcaseBase):
@ -65,6 +66,14 @@ class TestUtilityParams(TestcaseBase):
pytest.skip("None is valid for partition")
yield request.param
@pytest.fixture(scope="function", params=ct.get_not_string)
def get_invalid_type_collection_name(self, request):
yield request.param
@pytest.fixture(scope="function", params=ct.get_not_string_value)
def get_invalid_value_collection_name(self, request):
yield request.param
"""
******************************************************************
# The followings are invalid cases
@ -511,6 +520,122 @@ class TestUtilityParams(TestcaseBase):
"err_msg": "collection {} was not "
"loaded into memory)".format(collection_w.name)})
@pytest.mark.tags(CaseLabel.L1)
def test_rename_collection_old_invalid_type(self, get_invalid_type_collection_name):
"""
target: test rename_collection when the type of old collection name is not valid
method: input not invalid collection name
expected: raise exception
"""
self._connect()
collection_w, vectors, _, insert_ids, _ = self.init_collection_general(prefix)
old_collection_name = get_invalid_type_collection_name
new_collection_name = cf.gen_unique_str(prefix)
self.utility_wrap.rename_collection(old_collection_name, new_collection_name,
check_task=CheckTasks.err_res,
check_items={"err_code": 1,
"err_msg": "`collection_name` value {} is illegal".format(old_collection_name)})
@pytest.mark.tags(CaseLabel.L1)
def test_rename_collection_old_invalid_value(self, get_invalid_value_collection_name):
"""
target: test rename_collection when the value of old collection name is not valid
method: input not invalid collection name
expected: raise exception
"""
self._connect()
collection_w, vectors, _, insert_ids, _ = self.init_collection_general(prefix)
old_collection_name = get_invalid_value_collection_name
new_collection_name = cf.gen_unique_str(prefix)
self.utility_wrap.rename_collection(old_collection_name, new_collection_name,
check_task=CheckTasks.err_res,
check_items={"err_code": 1,
"err_msg": "collection {} was not "
"loaded into memory)".format(collection_w.name)})
@pytest.mark.tags(CaseLabel.L2)
def test_rename_collection_new_invalid_type(self, get_invalid_type_collection_name):
"""
target: test rename_collection when the type of new collection name is not valid
method: input not invalid collection name
expected: raise exception
"""
self._connect()
collection_w, vectors, _, insert_ids, _ = self.init_collection_general(prefix)
old_collection_name = collection_w.name
new_collection_name = get_invalid_type_collection_name
self.utility_wrap.rename_collection(old_collection_name, new_collection_name,
check_task=CheckTasks.err_res,
check_items={"err_code": 1,
"err_msg": "`collection_name` value {} is "
"illegal".format(new_collection_name)})
@pytest.mark.tags(CaseLabel.L2)
def test_rename_collection_new_invalid_value(self, get_invalid_value_collection_name):
"""
target: test rename_collection when the value of new collection name is not valid
method: input not invalid collection name
expected: raise exception
"""
self._connect()
collection_w, vectors, _, insert_ids, _ = self.init_collection_general(prefix)
old_collection_name = collection_w.name
new_collection_name = get_invalid_value_collection_name
self.utility_wrap.rename_collection(old_collection_name, new_collection_name,
check_task=CheckTasks.err_res,
check_items={"err_code": 9,
"err_msg": "collection {} was not "
"loaded into memory)".format(collection_w.name)})
@pytest.mark.tags(CaseLabel.L2)
def test_rename_collection_not_existed_collection(self):
"""
target: test rename_collection when the collection name is not existed
method: input not existing collection name
expected: raise exception
"""
self._connect()
collection_w, vectors, _, insert_ids, _ = self.init_collection_general(prefix)
old_collection_name = "test_collection_non_exist"
new_collection_name = cf.gen_unique_str(prefix)
self.utility_wrap.rename_collection(old_collection_name, new_collection_name,
check_task=CheckTasks.err_res,
check_items={"err_code": 1,
"err_msg": "can't find collection: {}".format(collection_w.name)})
@pytest.mark.tags(CaseLabel.L1)
def test_rename_collection_existed_collection_name(self):
"""
target: test rename_collection when the collection name is existed
method: input existing collection name
expected: raise exception
"""
self._connect()
collection_w, vectors, _, insert_ids, _ = self.init_collection_general(prefix)
old_collection_name = collection_w.name
self.utility_wrap.rename_collection(old_collection_name, old_collection_name,
check_task=CheckTasks.err_res,
check_items={"err_code": 1,
"err_msg": "duplicated new collection name :{} with other "
"collection name or alias".format(collection_w.name)})
@pytest.mark.tags(CaseLabel.L1)
def test_rename_collection_existed_collection_alias(self):
"""
target: test rename_collection when the collection alias is existed
method: input existing collection alias
expected: raise exception
"""
self._connect()
collection_w, vectors, _, insert_ids, _ = self.init_collection_general(prefix)
old_collection_name = collection_w.name
alias = "test_alias"
self.utility_wrap.create_alias(old_collection_name, alias)
self.utility_wrap.rename_collection(old_collection_name, alias,
check_task=CheckTasks.err_res,
check_items={"err_code": 1,
"err_msg": "duplicated new collection name :{} with "
"other collection name or alias".format(alias)})
class TestUtilityBase(TestcaseBase):
""" Test case of index interface """
@ -1376,6 +1501,127 @@ class TestUtilityBase(TestcaseBase):
"metric": metric,
"sqrt": sqrt})
@pytest.mark.tags(CaseLabel.L1)
def test_rename_collection(self):
"""
target: test rename collection function to single collection
method: call rename_collection API to rename collection
expected: collection renamed successfully without any change on aliases
"""
self._connect()
collection_w, vectors, _, insert_ids, _ = self.init_collection_general(prefix)
old_collection_name = collection_w.name
new_collection_name = cf.gen_unique_str(prefix + "new")
alias = cf.gen_unique_str(prefix + "alias")
self.utility_wrap.create_alias(old_collection_name, alias)
collection_alias = collection_w.aliases
self.utility_wrap.rename_collection(old_collection_name, new_collection_name)
collection_w = self.init_collection_wrap(name=new_collection_name,
check_task=CheckTasks.check_collection_property,
check_items={exp_name: new_collection_name,
exp_schema: default_schema})
collections = self.utility_wrap.list_collections()[0]
assert new_collection_name in collections
assert old_collection_name not in collections
assert collection_alias == collection_w.aliases
@pytest.mark.tags(CaseLabel.L2)
def test_rename_collections(self):
"""
target: test rename collection function to multiple collections
method: call rename_collection API to rename collections
expected: collections renamed successfully without any change on aliases
"""
self._connect()
# create two collections
collection_w_1 = self.init_collection_general(prefix)[0]
old_collection_name_1 = collection_w_1.name
collection_w_2 = self.init_collection_general(prefix)[0]
old_collection_name_2 = collection_w_2.name
tmp_collection_name = cf.gen_unique_str(prefix + "tmp")
# create alias to each collection
alias_1 = cf.gen_unique_str(prefix + "alias1")
alias_2 = cf.gen_unique_str(prefix + "alias2")
self.utility_wrap.create_alias(old_collection_name_1, alias_1)
self.utility_wrap.create_alias(old_collection_name_2, alias_2)
# switch name of the existing collections
self.utility_wrap.rename_collection(old_collection_name_1, tmp_collection_name)
self.utility_wrap.rename_collection(old_collection_name_2, old_collection_name_1)
self.utility_wrap.rename_collection(tmp_collection_name, old_collection_name_2)
# check collection renamed successfully
collection_w_1 = self.init_collection_wrap(name=old_collection_name_1,
check_task=CheckTasks.check_collection_property,
check_items={exp_name: old_collection_name_1,
exp_schema: default_schema})
collection_w_2 = self.init_collection_wrap(name=old_collection_name_2,
check_task=CheckTasks.check_collection_property,
check_items={exp_name: old_collection_name_2,
exp_schema: default_schema})
collections = self.utility_wrap.list_collections()[0]
assert old_collection_name_1 in collections
assert old_collection_name_2 in collections
assert tmp_collection_name not in collections
# check alias not changed
assert collection_w_1.aliases[0] == alias_2
assert collection_w_2.aliases[0] == alias_1
@pytest.mark.tags(CaseLabel.L2)
def test_rename_back_old_collection(self):
"""
target: test rename collection function to single collection
method: rename back to old collection name
expected: collection renamed successfully without any change on aliases
"""
# 1. connect
self._connect()
# 2. create a collection
collection_w, vectors, _, insert_ids, _ = self.init_collection_general(prefix)
old_collection_name = collection_w.name
new_collection_name = cf.gen_unique_str(prefix + "new")
alias = cf.gen_unique_str(prefix + "alias")
# 3. create an alias
self.utility_wrap.create_alias(old_collection_name, alias)
collection_alias = collection_w.aliases
# 4. rename collection
self.utility_wrap.rename_collection(old_collection_name, new_collection_name)
# 5. rename back to old collection name
self.utility_wrap.rename_collection(new_collection_name, old_collection_name)
collection_w = self.init_collection_wrap(name=old_collection_name,
check_task=CheckTasks.check_collection_property,
check_items={exp_name: old_collection_name,
exp_schema: default_schema})
collections = self.utility_wrap.list_collections()[0]
assert old_collection_name in collections
assert new_collection_name not in collections
assert collection_alias == collection_w.aliases
@pytest.mark.tags(CaseLabel.L2)
def test_rename_back_old_alias(self):
"""
target: test rename collection function to single collection
method: rename back to old collection alias
expected: collection renamed successfully without any change on aliases
"""
# 1. connect
self._connect()
# 2. create a collection
collection_w, vectors, _, insert_ids, _ = self.init_collection_general(prefix)
old_collection_name = collection_w.name
alias = cf.gen_unique_str(prefix + "alias")
# 3. create an alias
self.utility_wrap.create_alias(old_collection_name, alias)
collection_alias = collection_w.aliases
# 4. drop the alias
self.utility_wrap.drop_alias(collection_alias[0])
# 5. rename collection to the dropped alias name
self.utility_wrap.rename_collection(old_collection_name, collection_alias[0])
self.init_collection_wrap(name=collection_alias[0],
check_task=CheckTasks.check_collection_property,
check_items={exp_name: collection_alias[0],
exp_schema: default_schema})
collections = self.utility_wrap.list_collections()[0]
assert collection_alias[0] in collections
assert old_collection_name not in collections
class TestUtilityAdvanced(TestcaseBase):
""" Test case of index interface """