diff --git a/tests/python_client/base/collection_wrapper.py b/tests/python_client/base/collection_wrapper.py index 7203e6a12f74eb4709f599d64a5cc84d7929aa8d..9998b3e80cee2575f0c8e35d5ce00badbeedc647 100644 --- a/tests/python_client/base/collection_wrapper.py +++ b/tests/python_client/base/collection_wrapper.py @@ -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 diff --git a/tests/python_client/base/utility_wrapper.py b/tests/python_client/base/utility_wrapper.py index 7548ee3b31472661bf5a5105d5214b3587ce9438..62894eb5a2c5e90618b82e4be1398ae30270db67 100644 --- a/tests/python_client/base/utility_wrapper.py +++ b/tests/python_client/base/utility_wrapper.py @@ -487,3 +487,12 @@ 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 + diff --git a/tests/python_client/common/common_type.py b/tests/python_client/common/common_type.py index 19a28507a5773730542142dcb130310b94a3ca4b..78c1baccc03ee132f6b45cbd81f8c88e14a58961 100644 --- a/tests/python_client/common/common_type.py +++ b/tests/python_client/common/common_type.py @@ -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], diff --git a/tests/python_client/testcases/test_search.py b/tests/python_client/testcases/test_search.py index 00511348ca9da37802493cec6f843c35c2b3a3d2..ec8e67d02f6de6ae732d2579391e10860e70fe4a 100644 --- a/tests/python_client/testcases/test_search.py +++ b/tests/python_client/testcases/test_search.py @@ -1139,7 +1139,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, @@ -1455,12 +1459,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, diff --git a/tests/python_client/testcases/test_utility.py b/tests/python_client/testcases/test_utility.py index 4f5beb9ae5d1a139a43fb6de63a43089b7fca594..ba7b26ee59d1fe6dc9f6fa2deb2809940b063c36 100644 --- a/tests/python_client/testcases/test_utility.py +++ b/tests/python_client/testcases/test_utility.py @@ -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,123 @@ 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 +1502,70 @@ 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 + class TestUtilityAdvanced(TestcaseBase): """ Test case of index interface """