diff --git a/tests/python_client/milvus_client/test_milvus_client_alias.py b/tests/python_client/milvus_client/test_milvus_client_alias.py index b156723fc1..84eef11252 100644 --- a/tests/python_client/milvus_client/test_milvus_client_alias.py +++ b/tests/python_client/milvus_client/test_milvus_client_alias.py @@ -31,6 +31,8 @@ default_bool_field_name = ct.default_bool_field_name default_string_field_name = ct.default_string_field_name default_int32_array_field_name = ct.default_int32_array_field_name default_string_array_field_name = ct.default_string_array_field_name +default_schema = cf.gen_default_collection_schema() +default_binary_schema = cf.gen_default_binary_collection_schema() class TestMilvusClientAliasInvalid(TestMilvusClientV2Base): @@ -363,7 +365,171 @@ class TestMilvusClientAliasInvalid(TestMilvusClientV2Base): check_task=CheckTasks.err_res, check_items=error) self.drop_alias(client, alias) self.drop_collection(client, collection_name) + + @pytest.mark.tags(CaseLabel.L1) + def test_milvus_client_alias_create_duplication_alias(self): + """ + target: test two collections creating alias with same name + method: + 1.create a collection_1 with alias name alias_a + 2.create a collection_2 also with alias name alias_a + expected: + in step 2, creating alias with a duplication name is not allowed + """ + # step 1: create collection with alias name + client = self._client() + collection_1 = cf.gen_collection_name_by_testcase_name(module_index=1) + alias_a = cf.gen_unique_str("collection_alias") + self.create_collection(client, collection_1, default_dim, consistency_level="Strong") + self.create_alias(client, collection_1, alias_a) + + # step 2: create a collection_2 also with alias name alias_a + collection_2 = cf.gen_collection_name_by_testcase_name(module_index=1) + self.create_collection(client, collection_2, default_dim, consistency_level="Strong") + error = {ct.err_code: 1602, ct.err_msg: f"{alias_a} is alias to another collection: {collection_1}: " + f"alias already exist[database=default][alias={alias_a}]"} + self.create_alias(client, collection_2, alias_a, + check_task=CheckTasks.err_res, + check_items=error) + self.drop_alias(client, alias_a) + self.drop_collection(client, collection_1) + self.drop_collection(client, collection_2) + + @pytest.mark.tags(CaseLabel.L2) + def test_milvus_client_drop_same_alias_twice(self): + """ + target: test drop same alias twice + method: + 1.create a collection with alias + 2.collection drop alias + 3.collection drop alias again + expected: drop alias succ + """ + # step 1: create a collection with alias + client = self._client() + collection_name = cf.gen_collection_name_by_testcase_name(module_index=1) + alias = cf.gen_unique_str("collection_alias") + self.create_collection(client, collection_name, default_dim, consistency_level="Strong") + self.create_alias(client, collection_name, alias) + + # step 2: drop alias + self.drop_alias(client, alias) + + # step 3: drop alias again + self.drop_alias(client, alias) + self.drop_collection(client, collection_name) + + @pytest.mark.tags(CaseLabel.L2) + def test_milvus_client_alias_create_dup_name_collection(self): + """ + target: test creating a collection with a same name as alias, but a different schema + method: + 1.create a collection with alias + 2.create a collection with same name as alias, but a different schema + expected: in step 2, create collection failed + """ + # step 1: create a collection with alias + client = self._client() + collection_name = cf.gen_collection_name_by_testcase_name(module_index=1) + alias = cf.gen_unique_str("collection_alias") + self.create_collection(client, collection_name, default_dim, consistency_level="Strong") + self.create_alias(client, collection_name, alias) + + # step 2: create a collection with same name as alias, but a different schema + error = {ct.err_code: 65535, + ct.err_msg: f"collection name [{alias}] conflicts with an existing alias, please choose a unique name"} + self.create_collection(client, alias, default_dim, + consistency_level="Strong", + schema=default_schema, + check_task=CheckTasks.err_res, + check_items=error) + self.drop_alias(client, alias) + self.drop_collection(client, collection_name) + @pytest.mark.tags(CaseLabel.L2) + def test_milvus_client_alias_drop_collection_by_alias(self): + """ + target: test dropping a collection by alias + method: + 1.create a collection with alias + 2.drop a collection by alias + expected: in step 2, drop collection by alias failed by design + """ + # step 1: create a collection with alias + client = self._client() + collection_name = cf.gen_collection_name_by_testcase_name(module_index=1) + alias = cf.gen_unique_str("collection_alias") + self.create_collection(client, collection_name, default_dim, consistency_level="Strong") + self.create_alias(client, collection_name, alias) + + # step 2: drop collection by alias + error = {ct.err_code: 1600, ct.err_msg: f"cannot drop the collection via alias = {alias}"} + self.drop_collection(client, alias, check_task=CheckTasks.err_res, check_items=error) + self.drop_alias(client, alias) + self.drop_collection(client, collection_name) + + @pytest.mark.tags(CaseLabel.L2) + def test_milvus_client_alias_reuse_alias_name_from_dropped_collection(self): + """ + target: test dropping a collection which has a alias + method: + 1.create a collection + 2.create an alias for the collection + 3.drop the collection + 4.create a new collection + 5.create an alias with the same alias name for the new collection + expected: in step 5, create alias with the same name for the new collection succ + """ + # step 1: create a collection + client = self._client() + collection_name = cf.gen_collection_name_by_testcase_name(module_index=1) + self.create_collection(client, collection_name, default_dim, consistency_level="Strong") + + # step 2: create an alias for the collection + alias = cf.gen_unique_str("collection_alias") + self.create_alias(client, collection_name, alias) + res, _ = self.list_aliases(client, collection_name) + assert len(res['aliases']) == 1 + + # step 3: drop the collection + self.drop_alias(client, alias) + res, _ = self.list_aliases(client, collection_name) + assert len(res['aliases']) == 0 + self.drop_collection(client, collection_name) + + # step 4: create a new collection + collection_name_2 = cf.gen_collection_name_by_testcase_name(module_index=1) + self.create_collection(client, collection_name_2, default_dim, consistency_level="Strong") + + # step 5: create an alias with the same alias name for the new collection + self.create_alias(client, collection_name_2, alias) + res, _ = self.list_aliases(client, collection_name_2) + assert len(res['aliases']) == 1 + self.drop_alias(client, alias) + self.drop_collection(client, collection_name_2) + + @pytest.mark.tags(CaseLabel.L2) + def test_milvus_client_alias_rename_collection_to_alias_name(self): + """ + target: test renaming a collection to a alias name + method: + 1.create a collection + 2.create an alias for the collection + 3.rename the collection to the alias name + expected: in step 3, rename collection to alias name failed + """ + # step 1: create a collection + client = self._client() + collection_name = cf.gen_collection_name_by_testcase_name(module_index=1) + self.create_collection(client, collection_name, default_dim, consistency_level="Strong") + + # step 2: create an alias for the collection + alias = cf.gen_unique_str("collection_alias") + self.create_alias(client, collection_name, alias) + error = {ct.err_code: 65535, + ct.err_msg: f"cannot rename collection to an existing alias: {alias}"} + self.rename_collection(client, collection_name, alias, + check_task=CheckTasks.err_res, check_items=error) class TestMilvusClientAliasValid(TestMilvusClientV2Base): """ Test case of search interface """ @@ -498,6 +664,84 @@ class TestMilvusClientAliasValid(TestMilvusClientV2Base): class TestMilvusClientAliasOperation(TestMilvusClientV2Base): """ This is a migration test case for alias operation """ + @pytest.fixture(scope="function", params=[False, True]) + def auto_id(self, request): + yield request.param + + @pytest.fixture(scope="function", params=["COSINE", "L2"]) + def metric_type(self, request): + yield request.param + + @pytest.mark.tags(CaseLabel.L0) + def test_milvus_client_alias_alter_operation_default(self): + """ + target: test collection altering alias + method: + 1. create collection_1, bind alias to collection_1 and insert 2000 entities + 2. search on alias verify num_entities=2000 + 3. create collection_2 with 1500 entities + 4. alter alias to collection_2 and search on alias + verify num_entities=1500 + expected: + after step 2, collection_1 num_entities == alias num_entities == 2000 + after step 3, collection_2 num_entities == alias num_entities == 1500 + """ + # step 1: create collection and create alias + client = self._client() + c_name1 = cf.gen_collection_name_by_testcase_name(module_index=1) + self.create_collection(client, c_name1, default_dim, consistency_level="Strong") + + alias = cf.gen_unique_str("collection_alias") + # create a collection alias and bind to collection_1 + self.create_alias(client, c_name1, alias) + + # step 2: insert 2000 entities and search on alias + # default nb is 2000 + c_info = self.describe_collection(client, c_name1)[0] + rows = cf.gen_row_data_by_schema(nb=default_nb, schema=c_info) + self.insert(client, c_name1, rows) + + # pymilvus does not support num_entities yet, so we use query to check the number of entities + # assert self.num_entities(client, alias) == default_nb == self.num_entities(client, c_name1) + res1 = self.query(client, c_name1, filter=default_search_exp, + check_task=CheckTasks.check_query_results, + check_items={exp_res: rows, + "with_vec": True, + "pk_name": default_primary_key_field_name})[0] + res1_alias = self.query(client, alias, filter=default_search_exp, + check_task=CheckTasks.check_query_results, + check_items={exp_res: rows, + "with_vec": True, + "pk_name": default_primary_key_field_name})[0] + assert len(res1) == len(res1_alias) == default_nb + + # step 3: create collection 2 with 1500 entities + nb2 = 1500 + c_name2 = cf.gen_collection_name_by_testcase_name(module_index=2) + self.create_collection(client, c_name2, default_dim, consistency_level="Strong") + c_info2 = self.describe_collection(client, c_name2)[0] + rows = cf.gen_row_data_by_schema(nb=nb2, schema=c_info2) + self.insert(client, c_name2, rows) + + # step 4: alter the collection alias to collection2 + self.alter_alias(client, c_name2, alias) + #assert self.num_entities(client, alias) == nb2 == self.num_entities(client, c_name2) + res2 = self.query(client, c_name2, filter=default_search_exp, + check_task=CheckTasks.check_query_results, + check_items={exp_res: rows, + "with_vec": True, + "pk_name": default_primary_key_field_name})[0] + res2_alias = self.query(client, alias, filter=default_search_exp, + check_task=CheckTasks.check_query_results, + check_items={exp_res: rows, + "with_vec": True, + "pk_name": default_primary_key_field_name})[0] + assert len(res2) == len(res2_alias) == nb2 + + self.drop_alias(client, alias) + self.drop_collection(client, c_name1) + self.drop_collection(client, c_name2) + @pytest.mark.tags(CaseLabel.L1) def test_milvus_client_alias_create_operation_default(self): """ @@ -507,24 +751,137 @@ class TestMilvusClientAliasOperation(TestMilvusClientV2Base): 2.collection create an alias, then init a collection with this alias but not create partitions expected: collection is equal to alias """ + # step 1: create partitions and check the partition exists client = self._client() - collection_name = cf.gen_unique_str(prefix) - - # Create the collection before creating partitions + collection_name = cf.gen_collection_name_by_testcase_name(module_index=1) self.create_collection(client, collection_name, default_dim, consistency_level="Strong") - # method 1: create partitions and check the partition exists for _ in range(10): partition_name = cf.gen_unique_str("partition") # create partition with different names and check the partition exists self.create_partition(client, collection_name, partition_name) - # method 2: create alias from collection, then init a collection with this alias but not create partitions - alias = cf.gen_unique_str(prefix) + # step 2: create alias from collection, then init a collection with this alias but not create partitions + alias = cf.gen_unique_str("collection_alias") self.create_alias(client, collection_name, alias) # assert collection is equal to alias according to partitions partition_name_list = self.list_partitions(client, collection_name)[0] partition_name_list_alias = self.list_partitions(client, alias)[0] assert partition_name_list == partition_name_list_alias + + self.drop_alias(client, alias) + self.drop_collection(client, collection_name) + + @pytest.mark.tags(CaseLabel.L1) + def test_milvus_client_alias_drop_operation_default(self): + """ + target: test collection dropping alias + method: + 1.create a collection with 10 partitions + 2.collection create an alias + 3.collection drop the alias + expected: + after step 2, collection is equal to alias + after step 3, collection with alias name is not exist + """ + # step 1: create collection with 10 partitions + client = self._client() + collection_name = cf.gen_collection_name_by_testcase_name(module_index=1) + self.create_collection(client, collection_name, default_dim, consistency_level="Strong") + + for _ in range(10): + partition_name = cf.gen_unique_str("partition") + self.create_partition(client, collection_name, partition_name) + assert self.has_partition(client, collection_name, partition_name)[0] + + # step 2: create alias and drop the alias + alias = cf.gen_unique_str("collection_alias") + self.create_alias(client, collection_name, alias) + collection_partitions = self.list_partitions(client, collection_name)[0] + alias_partitions = self.list_partitions(client, alias)[0] + assert collection_partitions == alias_partitions + + # step 3: check the alias does not exist + self.drop_alias(client, alias) + error = {ct.err_code: 1600, ct.err_msg: f"alias not found[database=default][alias={alias}]"} + # check if error is raised, if raised, function is True and test passed, vise versa + self.describe_alias(client, alias, check_task=CheckTasks.err_res, check_items=error) + + self.drop_collection(client, collection_name) + + @pytest.mark.tags(CaseLabel.L2) + def test_milvus_client_alias_has_collection_partition(self): + """ + target: test utility has collection by alias + method: + 1.create collection with alias and partition + 2.call has_collection function with alias as param + 3.call has_partition function with alias as param + expected: result is True + """ + # step 1: create collection with alias and partition + client = self._client() + collection_name = cf.gen_collection_name_by_testcase_name(module_index=1) + self.create_collection(client, collection_name, default_dim, consistency_level="Strong") + alias = cf.gen_unique_str("collection_alias") + self.create_alias(client, collection_name, alias) + partition_name = cf.gen_unique_str("partition") + self.create_partition(client, collection_name, partition_name) + + # step 2: call has_collection function with alias as param and assert True + exists_a, _ = self.has_collection(client, alias) + assert exists_a + exists_p, _ = self.has_partition(client, alias, partition_name) + assert exists_p + + self.drop_alias(client, alias) + self.drop_collection(client, collection_name) + + @pytest.mark.tags(CaseLabel.L2) + def test_milvus_client_alias_drop_collection(self): + """ + target: test utility drop collection by alias + method: + 1.create collection with alias + 2.call drop_collection function with alias as param + expected: Got error: collection cannot be dropped via alias. + """ + # step 1: create collection with alias + client = self._client() + collection_name = cf.gen_collection_name_by_testcase_name(module_index=1) + self.create_collection(client, collection_name, default_dim, consistency_level="Strong") + alias = cf.gen_unique_str("collection_alias") + self.create_alias(client, collection_name, alias) + + # step 2: call drop_collection function with alias as param and assert error + error = {ct.err_code: 1600, ct.err_msg: f"cannot drop the collection via alias = {alias}"} + # check if error is raised, if raised, function is True and test passed, vise versa + self.drop_collection(client, alias, check_task=CheckTasks.err_res, check_items=error) + + self.drop_alias(client, alias) + self.drop_collection(client, collection_name) + + @pytest.mark.tags(CaseLabel.L2) + def test_milvus_client_alias_enable_mmap_by_alias(self): + """ + target: test utility enable mmap by alias + method: + 1.create collection with alias + 2.call enable_mmap function with alias as param + expected: result is True + """ + # step 1: create collection with alias + client = self._client() + collection_name = cf.gen_collection_name_by_testcase_name(module_index=1) + self.create_collection(client, collection_name, default_dim, consistency_level="Strong") + alias = cf.gen_unique_str("collection_alias") + self.create_alias(client, collection_name, alias) + + # step 2: enable mmap via alias and verify + self.release_collection(client, collection_name) + self.alter_collection_properties(client, alias, properties={"mmap.enabled": True}) + res = self.describe_collection(client, collection_name)[0].get("properties") + assert res["mmap.enabled"] == 'True' + self.drop_alias(client, alias) self.drop_collection(client, collection_name) \ No newline at end of file diff --git a/tests/python_client/testcases/test_alias.py b/tests/python_client/testcases/test_alias.py index 18e1766b54..dd5819b906 100644 --- a/tests/python_client/testcases/test_alias.py +++ b/tests/python_client/testcases/test_alias.py @@ -1,3 +1,7 @@ +################################################################## +# All test cases in this file have been migrated to milvus_client# +################################################################## +''' import pytest import random @@ -43,7 +47,6 @@ class TestAliasParamsInvalid(TestcaseBase): check_task=CheckTasks.err_res, check_items=error) - class TestAliasOperation(TestcaseBase): """ Test cases of alias interface operations""" @@ -100,9 +103,6 @@ class TestAliasOperation(TestcaseBase): res1 = collection_alias.query(expr="", output_fields=["count(*)"])[0] assert res1[0].get("count(*)") == nb2 - ######################################################### - # test_alias_create_operation_default() migrated to milvus_client - ######################################################### @pytest.mark.tags(CaseLabel.L1) def test_alias_create_operation_default(self): """ @@ -280,7 +280,9 @@ class TestAliasOperation(TestcaseBase): pro = collection_alias.describe().get("properties") assert pro["mmap.enabled"] == 'False' - +########################################################## +# class TestAliasOperationInvalid() has been migrated to milvus_client +########################################################## class TestAliasOperationInvalid(TestcaseBase): """ Negative test cases of alias interface operations""" @@ -484,3 +486,4 @@ class TestAliasOperationInvalid(TestcaseBase): ct.err_msg: f"cannot rename collection to an existing alias: {alias_name}"} self.utility_wrap.rename_collection(collection_w.name, alias_name, check_task=CheckTasks.err_res, check_items=error) +''' \ No newline at end of file