mirror of https://github.com/milvus-io/milvus.git
Add test cases for rename collection (#22339)
Signed-off-by: Binbin Lv <binbin.lv@zilliz.com>pull/22402/head
parent
7808bb518d
commit
62d0c2faad
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
||||
|
||||
|
|
|
@ -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],
|
||||
|
|
|
@ -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):
|
||||
"""
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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 """
|
||||
|
|
Loading…
Reference in New Issue