chore: import upstream snapshot with attribution
Build and test / Build and test AMD64 Ubuntu 22.04 (push) Failing after 0s
Publish Builder / amazonlinux2023 (push) Failing after 1s
Build and test / UT for Go (push) Has been skipped
Publish KRTE Images / KRTE (push) Failing after 1s
Build and test / Integration Test (push) Has been skipped
Build and test / Upload Code Coverage (push) Has been skipped
Publish Builder / rockylinux9 (push) Failing after 1s
Publish Builder / ubuntu22.04 (push) Failing after 0s
Publish Builder / ubuntu24.04 (push) Failing after 0s
Publish Gpu Builder / publish-gpu-builder (push) Failing after 1s
Publish Test Images / PyTest (push) Failing after 0s
Build and test / UT for Cpp (push) Has been cancelled

This commit is contained in:
wehub-resource-sync
2026-07-13 12:31:17 +08:00
commit 498b235461
5446 changed files with 2748612 additions and 0 deletions
@@ -0,0 +1,249 @@
import random
import time
import numpy as np
import pytest
import asyncio
from pymilvus.client.types import LoadState, DataType
from pymilvus import AnnSearchRequest, RRFRanker
from base.client_v2_base import TestMilvusClientV2Base
from common import common_func as cf
from common import common_type as ct
from common.common_type import CaseLabel, CheckTasks
from utils.util_log import test_log as log
pytestmark = pytest.mark.asyncio
prefix = "async"
partition_prefix = "async_partition"
async_default_nb = 5000
default_nb = ct.default_nb
default_dim = 2
default_limit = ct.default_limit
default_search_exp = "id >= 0"
exp_res = "exp_res"
default_primary_key_field_name = "id"
default_vector_field_name = "vector"
default_float_field_name = ct.default_float_field_name
default_string_field_name = ct.default_string_field_name
class TestAsyncMilvusClientCollectionInvalid(TestMilvusClientV2Base):
""" Test case of collection interface """
def teardown_method(self, method):
if self.async_milvus_client_wrap.async_milvus_client is not None:
asyncio.run(self.async_milvus_client_wrap.close())
super().teardown_method(method)
"""
******************************************************************
# The following are invalid base cases
******************************************************************
"""
@pytest.mark.tags(CaseLabel.L1)
@pytest.mark.parametrize("collection_name", ["12-s", "12 s", "(mn)", "中文", "%$#"])
async def test_async_milvus_client_create_collection_invalid_collection_name(self, collection_name):
"""
target: test fast create collection with invalid collection name
method: create collection with invalid collection
expected: raise exception
"""
self.init_async_milvus_client()
async_client = self.async_milvus_client_wrap
# 1. create collection
error = {ct.err_code: 1100, ct.err_msg: f"Invalid collection name: {collection_name}. the first character of a "
f"collection name must be an underscore or letter: invalid parameter"}
await async_client.create_collection(collection_name, default_dim,
check_task=CheckTasks.err_res, check_items=error)
@pytest.mark.tags(CaseLabel.L1)
async def test_async_milvus_client_create_collection_name_over_max_length(self):
"""
target: test fast create collection with over max collection name length
method: create collection with over max collection name length
expected: raise exception
"""
self.init_async_milvus_client()
async_client = self.async_milvus_client_wrap
# 1. create collection
collection_name = "a".join("a" for i in range(256))
error = {ct.err_code: 1100, ct.err_msg: f"the length of a collection name must be less than 255 characters"}
await async_client.create_collection(collection_name, default_dim,
check_task=CheckTasks.err_res, check_items=error)
@pytest.mark.tags(CaseLabel.L1)
@pytest.mark.parametrize("collection_name", ["12-s", "12 s", "(mn)", "中文", "%$#"])
async def test_async_milvus_client_release_collection_invalid_collection_name(self, collection_name):
"""
target: test release collection with invalid collection name
method: release collection with invalid collection name
expected: raise exception
"""
self.init_async_milvus_client()
async_client = self.async_milvus_client_wrap
# 1. release collection
error = {ct.err_code: 1100,
ct.err_msg: f"Invalid collection name: {collection_name}. "
f"the first character of a collection name must be an underscore or letter"}
await async_client.release_collection(collection_name, check_task=CheckTasks.err_res, check_items=error)
@pytest.mark.tags(CaseLabel.L2)
async def test_async_milvus_client_release_collection_not_existed(self):
"""
target: test release collection with nonexistent name
method: release collection with nonexistent name
expected: raise exception
"""
self.init_async_milvus_client()
async_client = self.async_milvus_client_wrap
# 1. release collection
collection_name = cf.gen_unique_str("nonexisted")
error = {ct.err_code: 1100, ct.err_msg: f"collection not found[database=default]"
f"[collection={collection_name}]"}
await async_client.release_collection(collection_name, check_task=CheckTasks.err_res, check_items=error)
@pytest.mark.tags(CaseLabel.L1)
async def test_async_milvus_client_release_collection_name_over_max_length(self):
"""
target: test fast create collection with over max collection name length
method: create collection with over max collection name length
expected: raise exception
"""
self.init_async_milvus_client()
async_client = self.async_milvus_client_wrap
# 1. release collection
collection_name = "a".join("a" for i in range(256))
error = {ct.err_code: 1100, ct.err_msg: f"the length of a collection name must be less than 255 characters"}
await async_client.release_collection(collection_name, check_task=CheckTasks.err_res, check_items=error)
class TestAsyncMilvusClientCollectionValid(TestMilvusClientV2Base):
""" Test case of collection interface """
def teardown_method(self, method):
if self.async_milvus_client_wrap.async_milvus_client is not None:
asyncio.run(self.async_milvus_client_wrap.close())
super().teardown_method(method)
"""
******************************************************************
# The following are valid base cases
******************************************************************
"""
@pytest.mark.tags(CaseLabel.L0)
async def test_async_milvus_client_release_collection_default(self):
self.init_async_milvus_client()
async_client = self.async_milvus_client_wrap
# 1. create collection
collection_name = cf.gen_unique_str(prefix)
await async_client.create_collection(collection_name, default_dim)
collections, _ = await async_client.list_collections()
assert collection_name in collections
desc, _ = await async_client.describe_collection(collection_name,
check_task=CheckTasks.check_describe_collection_property,
check_items={"collection_name": collection_name,
"dim": default_dim,
"consistency_level": 0})
# 2. create partition
partition_name = cf.gen_unique_str(partition_prefix)
await async_client.create_partition(collection_name, partition_name)
partitions, _ = await async_client.list_partitions(collection_name)
assert partition_name in partitions
# 3. insert
rng = np.random.default_rng(seed=19530)
rows = [{default_primary_key_field_name: i, default_vector_field_name: list(rng.random((1, default_dim))[0]),
default_float_field_name: i * 1.0, default_string_field_name: str(i)} for i in range(default_nb)]
await async_client.insert(collection_name, rows)
tasks = []
# 4. search
vectors_to_search = rng.random((1, default_dim))
search_task = async_client.search(collection_name, vectors_to_search,
check_task=CheckTasks.check_search_results,
check_items={"enable_milvus_client_api": True,
"nq": len(vectors_to_search),
"pk_name": default_primary_key_field_name,
"limit": default_limit})
tasks.append(search_task)
# 5. query
query_task = async_client.query(collection_name, 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})
tasks.append(query_task)
res = await asyncio.gather(*tasks)
# 6. release collection
await async_client.release_collection(collection_name)
# 7. search
error = {ct.err_code: 101, ct.err_msg: f"collection not loaded"}
await async_client.search(collection_name, vectors_to_search,
check_task=CheckTasks.err_res,
check_items=error)
# 8. query
await async_client.query(collection_name, filter=default_search_exp,
check_task=CheckTasks.err_res,
check_items=error)
# 9. load collection
await async_client.load_collection(collection_name)
# 10. search
await async_client.search(collection_name, vectors_to_search,
check_task=CheckTasks.check_search_results,
check_items={"enable_milvus_client_api": True,
"nq": len(vectors_to_search),
"limit": default_limit,
"pk_name": default_primary_key_field_name})
# 11. query
await async_client.query(collection_name, 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})
# 12. drop action
has_partition, _ = await async_client.has_partition(collection_name, partition_name)
if has_partition:
await async_client.release_partitions(collection_name, partition_name)
await async_client.drop_partition(collection_name, partition_name)
partitions, _ = await async_client.list_partitions(collection_name)
assert partition_name not in partitions
await async_client.drop_collection(collection_name)
@pytest.mark.tags(CaseLabel.L0)
async def test_async_milvus_client_truncate_collection(self):
"""
target: test truncate collection with strong consistency level
method: truncate collection with strong consistency level
expected: the collection is truncated
"""
self.init_async_milvus_client()
async_client = self.async_milvus_client_wrap
# 1. create collection
collection_name = cf.gen_collection_name_by_testcase_name()
await async_client.create_collection(collection_name, default_dim)
collections, _ = await async_client.list_collections()
assert collection_name in collections
# 2. insert
rng = np.random.default_rng(seed=19530)
rows = [{default_primary_key_field_name: i, default_vector_field_name: list(rng.random((1, default_dim))[0]),
default_float_field_name: i * 1.0, default_string_field_name: str(i)} for i in range(default_nb)]
await async_client.insert(collection_name, rows)
# 3. truncate collection
await async_client.truncate_collection(collection_name)
# 4. query
result = await async_client.query(collection_name, filter=default_search_exp, output_fields=["count(*)"])
assert result[0][0].get("count(*)", -1) == 0
seg = await async_client.list_persistent_segments(collection_name)
assert len(seg[0]) == 0
# 5. drop collection
await async_client.drop_collection(collection_name)
@@ -0,0 +1,512 @@
import random
import time
import pytest
import asyncio
from pymilvus.client.types import LoadState, DataType
from pymilvus import AnnSearchRequest, RRFRanker
from base.client_v2_base import TestMilvusClientV2Base
from common import common_func as cf
from common import common_type as ct
from common.common_type import CaseLabel, CheckTasks
from utils.util_log import test_log as log
pytestmark = pytest.mark.asyncio
prefix = "async"
async_default_nb = 5000
default_pk_name = "id"
default_vector_name = "vector"
class TestAsyncMilvusClient(TestMilvusClientV2Base):
def teardown_method(self, method):
if self.async_milvus_client_wrap.async_milvus_client is not None:
asyncio.run(self.async_milvus_client_wrap.close())
super().teardown_method(method)
@pytest.mark.tags(CaseLabel.L0)
async def test_async_client_default(self):
# init async client
self.init_async_milvus_client()
# create collection
c_name = cf.gen_unique_str(prefix)
await self.async_milvus_client_wrap.create_collection(c_name, dimension=ct.default_dim)
collections, _ = await self.async_milvus_client_wrap.list_collections()
assert c_name in collections
# insert entities
rows = [
{default_pk_name: i, default_vector_name: [random.random() for _ in range(ct.default_dim)]}
for i in range(async_default_nb)]
start_time = time.time()
tasks = []
step = 1000
for i in range(0, async_default_nb, step):
task = self.async_milvus_client_wrap.insert(c_name, rows[i:i + step])
tasks.append(task)
insert_res = await asyncio.gather(*tasks)
end_time = time.time()
log.info("Total time: {:.2f} seconds".format(end_time - start_time))
for r in insert_res:
assert r[0]['insert_count'] == step
# dql tasks
tasks = []
# search default
vector = cf.gen_vectors(ct.default_nq, ct.default_dim)
default_search_task = self.async_milvus_client_wrap.search(c_name, vector, limit=ct.default_limit,
check_task=CheckTasks.check_search_results,
check_items={"enable_milvus_client_api": True,
"nq": ct.default_nq,
"limit": ct.default_limit,
"pk_name": default_pk_name})
tasks.append(default_search_task)
# search with filter & search_params
sp = {"metric_type": "COSINE", "params": {"ef": "96"}}
filter_params_search_task = self.async_milvus_client_wrap.search(c_name, vector, limit=ct.default_limit,
filter=f"{default_pk_name} > 10",
search_params=sp,
check_task=CheckTasks.check_search_results,
check_items={"enable_milvus_client_api": True,
"nq": ct.default_nq,
"limit": ct.default_limit,
"pk_name": default_pk_name})
tasks.append(filter_params_search_task)
# search output fields
output_search_task = self.async_milvus_client_wrap.search(c_name, vector, limit=ct.default_limit,
output_fields=["*"],
check_task=CheckTasks.check_search_results,
check_items={"enable_milvus_client_api": True,
"nq": ct.default_nq,
"limit": ct.default_limit,
"pk_name": default_pk_name})
tasks.append(output_search_task)
# query with filter and default output "*"
exp_query_res = [{default_pk_name: i} for i in range(ct.default_limit)]
filter_query_task = self.async_milvus_client_wrap.query(c_name,
filter=f"{default_pk_name} < {ct.default_limit}",
output_fields=[default_pk_name],
check_task=CheckTasks.check_query_results,
check_items={"exp_res": exp_query_res,
"pk_name": default_pk_name})
tasks.append(filter_query_task)
# query with ids and output all fields
ids_query_task = self.async_milvus_client_wrap.query(c_name,
ids=[i for i in range(ct.default_limit)],
output_fields=["*"],
check_task=CheckTasks.check_query_results,
check_items={"exp_res": rows[:ct.default_limit],
"with_vec": True,
"pk_name": default_pk_name})
tasks.append(ids_query_task)
# get with ids
get_task = self.async_milvus_client_wrap.get(c_name,
ids=[0, 1],
output_fields=[default_pk_name, default_vector_name],
check_task=CheckTasks.check_query_results,
check_items={"exp_res": rows[:2], "with_vec": True,
"pk_name": default_pk_name})
tasks.append(get_task)
await asyncio.gather(*tasks)
@pytest.mark.tags(CaseLabel.L0)
async def test_async_client_partition(self):
# init async client
self.init_async_milvus_client()
# create collection & partition
c_name = cf.gen_unique_str(prefix)
p_name = cf.gen_unique_str("par")
await self.async_milvus_client_wrap.create_collection(c_name, dimension=ct.default_dim)
collections, _ = await self.async_milvus_client_wrap.list_collections()
assert c_name in collections
await self.async_milvus_client_wrap.create_partition(c_name, p_name)
partitions, _ = await self.async_milvus_client_wrap.list_partitions(c_name)
assert p_name in partitions
# insert entities
rows = [
{default_pk_name: i, default_vector_name: [random.random() for _ in range(ct.default_dim)]}
for i in range(async_default_nb)]
start_time = time.time()
tasks = []
step = 1000
for i in range(0, async_default_nb, step):
task = self.async_milvus_client_wrap.insert(c_name, rows[i:i + step], partition_name=p_name)
tasks.append(task)
insert_res = await asyncio.gather(*tasks)
end_time = time.time()
log.info("Total time: {:.2f} seconds".format(end_time - start_time))
for r in insert_res:
assert r[0]['insert_count'] == step
# count from default partition
count_res, _ = await self.async_milvus_client_wrap.query(c_name, output_fields=["count(*)"], partition_names=[ct.default_partition_name])
assert count_res[0]["count(*)"] == 0
# dql tasks
tasks = []
# search default
vector = cf.gen_vectors(ct.default_nq, ct.default_dim)
default_search_task = self.async_milvus_client_wrap.search(c_name, vector, limit=ct.default_limit,
partition_names=[p_name],
check_task=CheckTasks.check_search_results,
check_items={"enable_milvus_client_api": True,
"nq": ct.default_nq,
"limit": ct.default_limit,
"pk_name": default_pk_name})
tasks.append(default_search_task)
# search with filter & search_params
sp = {"metric_type": "COSINE", "params": {"ef": "96"}}
filter_params_search_task = self.async_milvus_client_wrap.search(c_name, vector, limit=ct.default_limit,
filter=f"{default_pk_name} > 10",
search_params=sp,
partition_names=[p_name],
check_task=CheckTasks.check_search_results,
check_items={"enable_milvus_client_api": True,
"nq": ct.default_nq,
"limit": ct.default_limit,
"pk_name": default_pk_name})
tasks.append(filter_params_search_task)
# search output fields
output_search_task = self.async_milvus_client_wrap.search(c_name, vector, limit=ct.default_limit,
output_fields=["*"],
partition_names=[p_name],
check_task=CheckTasks.check_search_results,
check_items={"enable_milvus_client_api": True,
"nq": ct.default_nq,
"limit": ct.default_limit,
"pk_name": default_pk_name})
tasks.append(output_search_task)
# query with filter and default output "*"
exp_query_res = [{default_pk_name: i} for i in range(ct.default_limit)]
filter_query_task = self.async_milvus_client_wrap.query(c_name,
filter=f"{default_pk_name} < {ct.default_limit}",
output_fields=[default_pk_name],
partition_names=[p_name],
check_task=CheckTasks.check_query_results,
check_items={"exp_res": exp_query_res,
"pk_name": default_pk_name})
tasks.append(filter_query_task)
# query with ids and output all fields
ids_query_task = self.async_milvus_client_wrap.query(c_name,
ids=[i for i in range(ct.default_limit)],
output_fields=["*"],
partition_names=[p_name],
check_task=CheckTasks.check_query_results,
check_items={"exp_res": rows[:ct.default_limit],
"with_vec": True,
"pk_name": default_pk_name})
tasks.append(ids_query_task)
# get with ids
get_task = self.async_milvus_client_wrap.get(c_name,
ids=[0, 1], partition_names=[p_name],
output_fields=[default_pk_name, default_vector_name],
check_task=CheckTasks.check_query_results,
check_items={"exp_res": rows[:2], "with_vec": True,
"pk_name": default_pk_name})
tasks.append(get_task)
await asyncio.gather(*tasks)
@pytest.mark.tags(CaseLabel.L0)
async def test_async_client_with_schema(self):
# init async client
pk_field_name = "id"
self.init_async_milvus_client()
# create collection
c_name = cf.gen_unique_str(prefix)
schema = self.async_milvus_client_wrap.create_schema(auto_id=False,
partition_key_field=ct.default_int64_field_name)
schema.add_field(pk_field_name, DataType.VARCHAR, max_length=100, is_primary=True)
schema.add_field(ct.default_int64_field_name, DataType.INT64, is_partition_key=True)
schema.add_field(ct.default_float_vec_field_name, DataType.FLOAT_VECTOR, dim=ct.default_dim)
schema.add_field(default_vector_name, DataType.FLOAT_VECTOR, dim=ct.default_dim)
await self.async_milvus_client_wrap.create_collection(c_name, schema=schema)
collections, _ = await self.async_milvus_client_wrap.list_collections()
assert c_name in collections
# insert entities
rows = [
{pk_field_name: str(i),
ct.default_int64_field_name: i,
ct.default_float_vec_field_name: [random.random() for _ in range(ct.default_dim)],
default_vector_name: [random.random() for _ in range(ct.default_dim)],
} for i in range(async_default_nb)]
start_time = time.time()
tasks = []
step = 1000
for i in range(0, async_default_nb, step):
task = self.async_milvus_client_wrap.insert(c_name, rows[i:i + step])
tasks.append(task)
insert_res = await asyncio.gather(*tasks)
end_time = time.time()
log.info("Total time: {:.2f} seconds".format(end_time - start_time))
for r in insert_res:
assert r[0]['insert_count'] == step
# flush
await self.async_milvus_client_wrap.flush(c_name)
stats, _ = await self.async_milvus_client_wrap.get_collection_stats(c_name)
assert stats["row_count"] == async_default_nb
# create index -> load
index_params = self.async_milvus_client_wrap.prepare_index_params()[0]
index_params.add_index(field_name=ct.default_float_vec_field_name,
index_type="HNSW", metric_type="COSINE", M=30,
efConstruction=200)
index_params.add_index(field_name=default_vector_name, index_type="IVF_SQ8",
metric_type="L2", nlist=32)
await self.async_milvus_client_wrap.create_index(c_name, index_params)
await self.async_milvus_client_wrap.load_collection(c_name)
_index, _ = await self.async_milvus_client_wrap.describe_index(c_name, default_vector_name)
assert _index["indexed_rows"] == async_default_nb
assert _index["state"] == "Finished"
_load, _ = await self.async_milvus_client_wrap.get_load_state(c_name)
assert _load['state'] == LoadState.Loaded
# dql tasks
tasks = []
# search default
vector = cf.gen_vectors(ct.default_nq, ct.default_dim)
default_search_task = self.async_milvus_client_wrap.search(c_name, vector, limit=ct.default_limit,
anns_field=ct.default_float_vec_field_name,
search_params={"metric_type": "COSINE",
"params": {"ef": "96"}},
check_task=CheckTasks.check_search_results,
check_items={"enable_milvus_client_api": True,
"nq": ct.default_nq,
"limit": ct.default_limit,
"pk_name": default_pk_name})
tasks.append(default_search_task)
# hybrid_search
search_param = {
"data": cf.gen_vectors(ct.default_nq, ct.default_dim, vector_data_type=DataType.FLOAT_VECTOR),
"anns_field": ct.default_float_vec_field_name,
"param": {"metric_type": "COSINE", "params": {"ef": "96"}},
"limit": ct.default_limit,
"expr": f"{ct.default_int64_field_name} > 10"}
req = AnnSearchRequest(**search_param)
search_param2 = {
"data": cf.gen_vectors(ct.default_nq, ct.default_dim, vector_data_type=DataType.FLOAT_VECTOR),
"anns_field": default_vector_name,
"param": {"metric_type": "L2", "params": {"nprobe": "32"}},
"limit": ct.default_limit
}
req2 = AnnSearchRequest(**search_param2)
_output_fields = [ct.default_int64_field_name, ct.default_string_field_name]
filter_params_search_task = self.async_milvus_client_wrap.hybrid_search(c_name, [req, req2], RRFRanker(),
limit=5,
check_task=CheckTasks.check_search_results,
check_items={
"enable_milvus_client_api": True,
"nq": ct.default_nq,
"limit": 5,
"pk_name": default_pk_name})
tasks.append(filter_params_search_task)
# get with ids
get_task = self.async_milvus_client_wrap.get(c_name, ids=['0', '1'], output_fields=[ct.default_int64_field_name,
pk_field_name])
tasks.append(get_task)
await asyncio.gather(*tasks)
@pytest.mark.tags(CaseLabel.L0)
async def test_async_client_dml(self):
# init async client
self.init_async_milvus_client()
# create collection
c_name = cf.gen_unique_str(prefix)
await self.async_milvus_client_wrap.create_collection(c_name, dimension=ct.default_dim)
collections, _ = await self.async_milvus_client_wrap.list_collections()
assert c_name in collections
# insert entities
rows = [
{default_pk_name: i, default_vector_name: [random.random() for _ in range(ct.default_dim)]}
for i in range(ct.default_nb)]
start_time = time.time()
tasks = []
step = 1000
for i in range(0, ct.default_nb, step):
task = self.async_milvus_client_wrap.insert(c_name, rows[i:i + step])
tasks.append(task)
insert_res = await asyncio.gather(*tasks)
end_time = time.time()
log.info("Total time: {:.2f} seconds".format(end_time - start_time))
for r in insert_res:
assert r[0]['insert_count'] == step
# dml tasks
# query id -> upsert id -> query id -> delete id -> query id
_id = 10
get_res, _ = await self.async_milvus_client_wrap.get(c_name, ids=[_id],
output_fields=[default_pk_name, default_vector_name])
assert len(get_res) == 1
# upsert
upsert_row = [{
default_pk_name: _id, default_vector_name: [random.random() for _ in range(ct.default_dim)]
}]
upsert_res, _ = await self.async_milvus_client_wrap.upsert(c_name, upsert_row)
assert upsert_res["upsert_count"] == 1
# get _id after upsert
get_res, _ = await self.async_milvus_client_wrap.get(c_name, ids=[_id],
output_fields=[default_pk_name, default_vector_name])
for j in range(5):
assert abs(get_res[0][default_vector_name][j] - upsert_row[0][default_vector_name][j]) < ct.epsilon
# delete
del_res, _ = await self.async_milvus_client_wrap.delete(c_name, ids=[_id])
assert del_res["delete_count"] == 1
# query after delete
get_res, _ = await self.async_milvus_client_wrap.get(c_name, ids=[_id],
output_fields=[default_pk_name, default_vector_name])
assert len(get_res) == 0
@pytest.mark.tags(CaseLabel.L2)
async def test_async_client_with_db(self):
# init async client
self.init_async_milvus_client()
db_name = cf.gen_unique_str("db")
await self.async_milvus_client_wrap.create_database(db_name)
await self.async_milvus_client_wrap.close()
uri = cf.param_info.param_uri or f"http://{cf.param_info.param_host}:{cf.param_info.param_port}"
self.async_milvus_client_wrap.init_async_client(uri, token=cf.param_info.param_token, db_name=db_name)
# create collection
c_name = cf.gen_unique_str(prefix)
await self.async_milvus_client_wrap.create_collection(c_name, dimension=ct.default_dim)
collections, _ = await self.async_milvus_client_wrap.list_collections()
assert c_name in collections
# insert entities
rows = [
{default_pk_name: i, default_vector_name: [random.random() for _ in range(ct.default_dim)]}
for i in range(async_default_nb)]
start_time = time.time()
tasks = []
step = 1000
for i in range(0, async_default_nb, step):
task = self.async_milvus_client_wrap.insert(c_name, rows[i:i + step])
tasks.append(task)
insert_res = await asyncio.gather(*tasks)
end_time = time.time()
log.info("Total time: {:.2f} seconds".format(end_time - start_time))
for r in insert_res:
assert r[0]['insert_count'] == step
# dql tasks
tasks = []
# search default
vector = cf.gen_vectors(ct.default_nq, ct.default_dim)
default_search_task = self.async_milvus_client_wrap.search(c_name, vector, limit=ct.default_limit,
check_task=CheckTasks.check_search_results,
check_items={"enable_milvus_client_api": True,
"nq": ct.default_nq,
"limit": ct.default_limit,
"pk_name": default_pk_name})
tasks.append(default_search_task)
# query with filter and default output "*"
exp_query_res = [{default_pk_name: i} for i in range(ct.default_limit)]
filter_query_task = self.async_milvus_client_wrap.query(c_name,
filter=f"{default_pk_name} < {ct.default_limit}",
output_fields=[default_pk_name],
check_task=CheckTasks.check_query_results,
check_items={"exp_res": exp_query_res,
"pk_name": default_pk_name})
tasks.append(filter_query_task)
# get with ids
get_task = self.async_milvus_client_wrap.get(c_name,
ids=[0, 1],
output_fields=[default_pk_name, default_vector_name],
check_task=CheckTasks.check_query_results,
check_items={"exp_res": rows[:2], "with_vec": True,
"pk_name": default_pk_name})
tasks.append(get_task)
await asyncio.gather(*tasks)
@pytest.mark.tags(CaseLabel.L0)
async def test_async_client_close(self):
# init async client
uri = cf.param_info.param_uri or f"http://{cf.param_info.param_host}:{cf.param_info.param_port}"
self.async_milvus_client_wrap.init_async_client(uri, token=cf.param_info.param_token)
# create collection
c_name = cf.gen_unique_str(prefix)
await self.async_milvus_client_wrap.create_collection(c_name, dimension=ct.default_dim)
# close -> search raise error
await self.async_milvus_client_wrap.close()
vector = cf.gen_vectors(1, ct.default_dim)
error = {ct.err_code: 1, ct.err_msg: "should create connection first"}
await self.async_milvus_client_wrap.search(c_name, vector, check_task=CheckTasks.err_res, check_items=error)
@pytest.mark.tags(CaseLabel.L3)
@pytest.mark.skip("connect with zilliz cloud")
async def test_async_client_with_token(self):
# init async client
uri = cf.param_info.param_uri or f"http://{cf.param_info.param_host}:{cf.param_info.param_port}"
token = cf.param_info.param_token
self.async_milvus_client_wrap.init_async_client(uri, token=token)
# create collection
c_name = cf.gen_unique_str(prefix)
await self.async_milvus_client_wrap.create_collection(c_name, dimension=ct.default_dim)
collections, _ = await self.async_milvus_client_wrap.list_collections()
assert c_name in collections
# insert entities
rows = [
{default_pk_name: i, default_vector_name: [random.random() for _ in range(ct.default_dim)]}
for i in range(ct.default_nb)]
start_time = time.time()
tasks = []
step = 1000
for i in range(0, ct.default_nb, step):
task = self.async_milvus_client_wrap.insert(c_name, rows[i:i + step])
tasks.append(task)
insert_res = await asyncio.gather(*tasks)
end_time = time.time()
log.info("Total time: {:.2f} seconds".format(end_time - start_time))
for r in insert_res:
assert r[0]['insert_count'] == step
# dql tasks
tasks = []
# search default
vector = cf.gen_vectors(ct.default_nq, ct.default_dim)
default_search_task = self.async_milvus_client_wrap.search(c_name, vector, limit=ct.default_limit,
check_task=CheckTasks.check_search_results,
check_items={"enable_milvus_client_api": True,
"nq": ct.default_nq,
"limit": ct.default_limit,
"pk_name": default_pk_name})
tasks.append(default_search_task)
# query with filter and default output "*"
exp_query_res = [{default_pk_name: i} for i in range(ct.default_limit)]
filter_query_task = self.async_milvus_client_wrap.query(c_name,
filter=f"{default_pk_name} < {ct.default_limit}",
output_fields=[default_pk_name],
check_task=CheckTasks.check_query_results,
check_items={"exp_res": exp_query_res,
"pk_name": default_pk_name})
tasks.append(filter_query_task)
await asyncio.gather(*tasks)
@@ -0,0 +1,288 @@
import random
import time
import numpy as np
import pytest
import asyncio
from pymilvus.client.types import LoadState, DataType
from pymilvus import AnnSearchRequest, RRFRanker
from base.client_v2_base import TestMilvusClientV2Base
from common import common_func as cf
from common import common_type as ct
from common.common_type import CaseLabel, CheckTasks
from utils.util_log import test_log as log
pytestmark = pytest.mark.asyncio
prefix = "async"
partition_prefix = "async_partition"
async_default_nb = 5000
default_nb = ct.default_nb
default_dim = 128
default_limit = ct.default_limit
default_search_exp = "id >= 0"
exp_res = "exp_res"
default_primary_key_field_name = "id"
default_vector_field_name = "vector"
default_float_field_name = ct.default_float_field_name
default_string_field_name = ct.default_string_field_name
class TestAsyncMilvusClientIndexInvalid(TestMilvusClientV2Base):
""" Test case of index interface """
def teardown_method(self, method):
if self.async_milvus_client_wrap.async_milvus_client is not None:
asyncio.run(self.async_milvus_client_wrap.close())
super().teardown_method(method)
"""
******************************************************************
# The following are invalid base cases
******************************************************************
"""
@pytest.mark.tags(CaseLabel.L1)
@pytest.mark.parametrize("name", ["12-s", "12 s", "(mn)", "中文", "%$#"])
async def test_async_milvus_client_create_index_invalid_collection_name(self, name):
"""
target: test create index with invalid collection name
method: create index with invalid collection name
expected: raise exception
"""
self.init_async_milvus_client()
async_client = self.async_milvus_client_wrap
# 1. create collection
collection_name = cf.gen_unique_str(prefix)
await async_client.create_collection(collection_name, default_dim, consistency_level="Strong")
await async_client.release_collection(collection_name)
await async_client.drop_index(collection_name, "vector")
# 2. prepare index params
index_params = async_client.prepare_index_params()[0]
index_params.add_index(field_name="vector")
# 3. create index
error = {ct.err_code: 1100, ct.err_msg: f"collection not found[database=default][collection={name}]"}
await async_client.create_index(name, index_params,
check_task=CheckTasks.err_res,
check_items=error)
# 4. drop action
await async_client.drop_collection(collection_name)
@pytest.mark.tags(CaseLabel.L1)
@pytest.mark.parametrize("name", ["a".join("a" for i in range(256))])
async def test_async_milvus_client_create_index_collection_name_over_max_length(self, name):
"""
target: test create index with over max collection name length
method: create index with over max collection name length
expected: raise exception
"""
self.init_async_milvus_client()
async_client = self.async_milvus_client_wrap
# 1. create collection
collection_name = cf.gen_unique_str(prefix)
await async_client.create_collection(collection_name, default_dim, consistency_level="Strong")
await async_client.release_collection(collection_name)
await async_client.drop_index(collection_name, "vector")
# 2. prepare index params
index_params = async_client.prepare_index_params()[0]
index_params.add_index(field_name="vector")
# 3. create index
error = {ct.err_code: 1100, ct.err_msg: f"collection not found[database=default][collection={name}]"}
await async_client.create_index(name, index_params,
check_task=CheckTasks.err_res,
check_items=error)
# 4. drop action
await async_client.drop_collection(collection_name)
@pytest.mark.tags(CaseLabel.L1)
async def test_async_milvus_client_create_index_collection_name_not_existed(self):
"""
target: test create index with nonexistent collection name
method: create index with nonexistent collection name
expected: raise exception
"""
self.init_async_milvus_client()
async_client = self.async_milvus_client_wrap
collection_name = cf.gen_unique_str(prefix)
not_existed_collection_name = cf.gen_unique_str("not_existed_collection")
# 1. create collection
await async_client.create_collection(collection_name, default_dim, consistency_level="Strong")
await async_client.release_collection(collection_name)
await async_client.drop_index(collection_name, "vector")
# 2. prepare index params
index_params = async_client.prepare_index_params()[0]
index_params.add_index(field_name="vector")
# 3. create index
error = {ct.err_code: 100,
ct.err_msg: f"collection not found[database=default][collection={not_existed_collection_name}]"}
await async_client.create_index(not_existed_collection_name, index_params,
check_task=CheckTasks.err_res,
check_items=error)
# 4. drop action
await async_client.drop_collection(collection_name)
@pytest.mark.tags(CaseLabel.L1)
@pytest.mark.parametrize("index", ["12-s", "12 s", "(mn)", "中文", "%$#", "a".join("a" for i in range(256))])
async def test_async_milvus_client_create_index_invalid_index_type(self, index):
"""
target: test create index with invalid index type name
method: create index with invalid index type name
expected: raise exception
"""
self.init_async_milvus_client()
async_client = self.async_milvus_client_wrap
collection_name = cf.gen_unique_str(prefix)
# 1. create collection
await async_client.create_collection(collection_name, default_dim, consistency_level="Strong")
await async_client.release_collection(collection_name)
await async_client.drop_index(collection_name, "vector")
# 2. prepare index params
index_params = async_client.prepare_index_params()[0]
index_params.add_index(field_name="vector", index_type=index)
# 3. create index
error = {ct.err_code: 1100, ct.err_msg: f"invalid parameter[expected=valid index][actual=invalid index type: {index}"}
# It's good to show what the valid indexes are
await async_client.create_index(collection_name, index_params,
check_task=CheckTasks.err_res,
check_items=error)
# 4. drop action
await async_client.drop_collection(collection_name)
@pytest.mark.tags(CaseLabel.L1)
@pytest.mark.parametrize("metric", ["12-s", "12 s", "(mn)", "中文", "%$#", "a".join("a" for i in range(256))])
async def test_async_milvus_client_create_index_invalid_metric_type(self, metric):
"""
target: test create index with invalid metric type
method: create index with invalid metric type
expected: raise exception
"""
self.init_async_milvus_client()
async_client = self.async_milvus_client_wrap
collection_name = cf.gen_unique_str(prefix)
# 1. create collection
await async_client.create_collection(collection_name, default_dim, consistency_level="Strong")
await async_client.release_collection(collection_name)
await async_client.drop_index(collection_name, "vector")
# 2. prepare index params
index_params = async_client.prepare_index_params()[0]
index_params.add_index(field_name="vector", metric_type=metric)
# 3. create index
error = {ct.err_code: 1100, ct.err_msg: f"float vector index does not support metric type: {metric}"}
# It's good to show what the valid index params are
await async_client.create_index(collection_name, index_params,
check_task=CheckTasks.err_res,
check_items=error)
# 4. drop action
await async_client.drop_collection(collection_name)
@pytest.mark.tags(CaseLabel.L1)
async def test_async_milvus_client_drop_index_before_release(self):
"""
target: test drop index when collection are not released
method: drop index when collection are not released
expected: raise exception
"""
self.init_async_milvus_client()
async_client = self.async_milvus_client_wrap
collection_name = cf.gen_unique_str(prefix)
# 1. create collection
await async_client.create_collection(collection_name, default_dim, consistency_level="Strong")
# 2. drop index
error = {ct.err_code: 1100, ct.err_msg: f"vector index cannot be dropped on loaded collection"}
await async_client.drop_index(collection_name, "vector", check_task=CheckTasks.err_res, check_items=error)
# 3. drop action
await async_client.drop_collection(collection_name)
class TestAsyncMilvusClientIndexValid(TestMilvusClientV2Base):
""" Test case of index interface """
def teardown_method(self, method):
if self.async_milvus_client_wrap.async_milvus_client is not None:
asyncio.run(self.async_milvus_client_wrap.close())
super().teardown_method(method)
@pytest.fixture(scope="function", params=["COSINE", "L2", "IP"])
def metric_type(self, request):
yield request.param
"""
******************************************************************
# The following are valid base cases
******************************************************************
"""
@pytest.mark.tags(CaseLabel.L0)
@pytest.mark.parametrize("index, params",
zip(ct.all_index_types[:8],
ct.default_all_indexes_params[:8]))
async def test_async_milvus_client_create_drop_index_default(self, index, params, metric_type):
"""
target: test create and drop index normal case
method: create collection, index; insert; search and query; drop index
expected: search/query successfully; create/drop index successfully
"""
self.init_async_milvus_client()
async_client = self.async_milvus_client_wrap
# 1. create collection
collection_name = cf.gen_unique_str(prefix)
await async_client.create_collection(collection_name, default_dim)
collections, _ = await async_client.list_collections()
assert collection_name in collections
desc, _ = await async_client.describe_collection(collection_name,
check_task=CheckTasks.check_describe_collection_property,
check_items={"collection_name": collection_name,
"dim": default_dim,
"consistency_level": 0})
await async_client.release_collection(collection_name)
await async_client.drop_index(collection_name, "vector")
res, _ = await async_client.list_indexes(collection_name)
assert res == []
# 2. prepare index params
index_params = async_client.prepare_index_params()[0]
index_params.add_index(field_name="vector", index_type=index, metric_type=metric_type, params=params)
# 3. create index
await async_client.create_index(collection_name, index_params)
# 4. insert
rng = np.random.default_rng(seed=19530)
rows = [{default_primary_key_field_name: i, default_vector_field_name: list(rng.random((1, default_dim))[0]),
default_float_field_name: i * 1.0, default_string_field_name: str(i)} for i in range(default_nb)]
await async_client.insert(collection_name, rows)
await async_client.load_collection(collection_name)
tasks = []
# 5. search
vectors_to_search = rng.random((1, default_dim))
search_task = self.async_milvus_client_wrap. \
search(collection_name, vectors_to_search,
check_task=CheckTasks.check_search_results,
check_items={"enable_milvus_client_api": True,
"nq": len(vectors_to_search),
"limit": default_limit,
"pk_name": default_primary_key_field_name})
tasks.append(search_task)
# 6. query
query_task = self.async_milvus_client_wrap. \
query(collection_name, 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})
tasks.append(query_task)
res = await asyncio.gather(*tasks)
# 7. drop index
await async_client.release_collection(collection_name)
await async_client.drop_index(collection_name, "vector")
res, _ = await async_client.list_indexes(collection_name)
assert res == []
# 8. drop action
await async_client.drop_collection(collection_name)
@@ -0,0 +1,141 @@
import numpy as np
import pytest
import asyncio
from base.client_v2_base import TestMilvusClientV2Base
from common import common_func as cf
from common import common_type as ct
from common.common_type import CaseLabel, CheckTasks
pytestmark = pytest.mark.asyncio
default_nb = ct.default_nb
default_dim = 128
default_limit = ct.default_limit
default_search_exp = "id >= 0"
exp_res = "exp_res"
default_primary_key_field_name = "id"
default_vector_field_name = "vector"
default_float_field_name = ct.default_float_field_name
default_string_field_name = ct.default_string_field_name
class TestAsyncMilvusClientInsert(TestMilvusClientV2Base):
"""
******************************************************************
The following cases are used to test insert async
******************************************************************
"""
def teardown_method(self, method):
"""
Clean up async client connection after each test method.
This ensures proper resource cleanup and prevents connection leaks.
"""
if self.async_milvus_client_wrap.async_milvus_client is not None:
asyncio.run(self.async_milvus_client_wrap.close())
super().teardown_method(method)
@pytest.mark.tags(CaseLabel.L1)
async def test_async_milvus_client_insert(self):
"""
target: test async insert via Milvus async client
method: insert with async milvus client
expected: verify insert_count / row_count
"""
self.init_async_milvus_client()
async_client = self.async_milvus_client_wrap
collection_name = cf.gen_collection_name_by_testcase_name()
# 1. create collection
await async_client.create_collection(collection_name, default_dim)
# 2. prepare data
rng = np.random.default_rng(seed=19530)
rows = [{default_primary_key_field_name: i, default_vector_field_name: list(rng.random((1, default_dim))[0]),
default_float_field_name: i * 1.0, default_string_field_name: str(i)} for i in range(default_nb)]
# 3. insert
res, _ = await async_client.insert(collection_name, rows)
assert res["insert_count"] == ct.default_nb
# 4. verify count
await async_client.flush(collection_name)
num_entities, _ = await async_client.get_collection_stats(collection_name)
assert num_entities["row_count"] == ct.default_nb
await async_client.drop_collection(collection_name)
@pytest.mark.tags(CaseLabel.L2)
async def test_async_milvus_client_insert_large(self):
"""
target: test insert with async
method: insert 5w entities
expected: verify num entities
"""
self.init_async_milvus_client()
async_client = self.async_milvus_client_wrap
nb = 50000
collection_name = cf.gen_collection_name_by_testcase_name()
await async_client.create_collection(collection_name, default_dim)
rng = np.random.default_rng(seed=19530)
rows = [{default_primary_key_field_name: i, default_vector_field_name: list(rng.random((1, default_dim))[0]),
default_float_field_name: i * 1.0, default_string_field_name: str(i)} for i in range(nb)]
res, _ = await async_client.insert(collection_name, rows)
assert res["insert_count"] == nb
await async_client.flush(collection_name)
num_entities, _ = await async_client.get_collection_stats(collection_name)
assert num_entities["row_count"] == nb
await async_client.drop_collection(collection_name)
@pytest.mark.tags(CaseLabel.L2)
async def test_async_milvus_client_insert_invalid_data(self):
"""
target: test insert async with invalid data
method: insert async with invalid data
expected: raise exception
"""
self.init_async_milvus_client()
async_client = self.async_milvus_client_wrap
collection_name = cf.gen_collection_name_by_testcase_name()
await async_client.create_collection(collection_name, default_dim)
# missing vector field
rows = [{ct.default_primary_key_field_name: 1}]
error = {ct.err_code: 1, ct.err_msg: "Insert missed an field `vector` to collection without set nullable==true or set default_value"}
await async_client.insert(collection_name, rows, check_task=CheckTasks.err_res, check_items=error)
await async_client.drop_collection(collection_name)
@pytest.mark.tags(CaseLabel.L2)
async def test_async_milvus_client_insert_invalid_partition(self):
"""
target: test insert async with invalid partition
method: insert async with invalid partition
expected: raise exception
"""
self.init_async_milvus_client()
async_client = self.async_milvus_client_wrap
collection_name = cf.gen_collection_name_by_testcase_name()
partition_name = cf.gen_unique_str("partition")
await async_client.create_collection(collection_name, default_dim)
rng = np.random.default_rng(seed=19530)
rows = [{default_primary_key_field_name: i, default_vector_field_name: list(rng.random((1, default_dim))[0]),
default_float_field_name: i * 1.0, default_string_field_name: str(i)} for i in range(default_nb)]
error = {ct.err_code: 200, ct.err_msg: f"partition not found[partition={partition_name}]"}
await async_client.insert(collection_name, data=rows, partition_name=partition_name,
check_task=CheckTasks.err_res, check_items=error)
await async_client.drop_collection(collection_name)
@@ -0,0 +1,782 @@
import random
import time
import numpy as np
import pytest
import asyncio
from pymilvus.client.types import LoadState, DataType
from pymilvus import AnnSearchRequest, RRFRanker
from base.client_v2_base import TestMilvusClientV2Base
from common import common_func as cf
from common import common_type as ct
from common.common_type import CaseLabel, CheckTasks
from utils.util_log import test_log as log
pytestmark = pytest.mark.asyncio
prefix = "async"
partition_prefix = "async_partition"
async_default_nb = 5000
default_nb = ct.default_nb
default_dim = 2
default_limit = ct.default_limit
default_search_exp = "id >= 0"
exp_res = "exp_res"
default_primary_key_field_name = "id"
default_vector_field_name = "vector"
default_float_field_name = ct.default_float_field_name
default_string_field_name = ct.default_string_field_name
class TestAsyncMilvusClientPartitionInvalid(TestMilvusClientV2Base):
""" Test case of partition interface """
def teardown_method(self, method):
if self.async_milvus_client_wrap.async_milvus_client is not None:
asyncio.run(self.async_milvus_client_wrap.close())
super().teardown_method(method)
"""
******************************************************************
# The following are invalid base cases
******************************************************************
"""
@pytest.mark.tags(CaseLabel.L1)
@pytest.mark.parametrize("collection_name", ["12-s", "12 s", "(mn)", "中文", "%$#"])
async def test_async_milvus_client_create_partition_invalid_collection_name(self, collection_name):
"""
target: test create partition with invalid collection name
method: create partition with invalid collection name
expected: raise exception
"""
self.init_async_milvus_client()
async_client = self.async_milvus_client_wrap
partition_name = cf.gen_unique_str(partition_prefix)
# 1. create partition
error = {ct.err_code: 1100, ct.err_msg: f"Invalid collection name: {collection_name}. the first character of a "
f"collection name must be an underscore or letter: invalid parameter"}
await async_client.create_partition(collection_name, partition_name,
check_task=CheckTasks.err_res, check_items=error)
@pytest.mark.tags(CaseLabel.L1)
async def test_async_milvus_client_create_partition_collection_name_over_max_length(self):
"""
target: test create partition with collection name over max length 255
method: create partition with collection name over max length 255
expected: raise exception
"""
self.init_async_milvus_client()
async_client = self.async_milvus_client_wrap
collection_name = "a".join("a" for i in range(256))
partition_name = cf.gen_unique_str(partition_prefix)
# 1. create partition
error = {ct.err_code: 1100,
ct.err_msg: f"Invalid collection name: {collection_name}. the length of a collection name "
f"must be less than 255 characters: invalid parameter"}
await async_client.create_partition(collection_name, partition_name,
check_task=CheckTasks.err_res, check_items=error)
@pytest.mark.tags(CaseLabel.L1)
async def test_async_milvus_client_create_partition_collection_name_not_existed(self):
"""
target: test create partition with nonexistent collection name
method: create partition with nonexistent collection name
expected: raise exception
"""
self.init_async_milvus_client()
async_client = self.async_milvus_client_wrap
collection_name = cf.gen_unique_str("partition_not_exist")
partition_name = cf.gen_unique_str(partition_prefix)
# 1. create partition
error = {ct.err_code: 100, ct.err_msg: f"collection not found[database=default]"
f"[collection={collection_name}]"}
await async_client.create_partition(collection_name, partition_name,
check_task=CheckTasks.err_res, check_items=error)
@pytest.mark.tags(CaseLabel.L1)
@pytest.mark.parametrize("partition_name", ["12 s", "(mn)", "中文", "%$#"])
async def test_async_milvus_client_create_partition_invalid_partition_name(self, partition_name):
"""
target: test create partition with invalid partition name
method: create partition with invalid partition name
expected: raise exception
"""
self.init_async_milvus_client()
async_client = self.async_milvus_client_wrap
collection_name = cf.gen_unique_str(prefix)
# 1. create collection
await async_client.create_collection(collection_name, default_dim)
desc, _ = await async_client.describe_collection(collection_name,
check_task=CheckTasks.check_describe_collection_property,
check_items={"collection_name": collection_name,
"dim": default_dim,
"consistency_level": 0})
# 2. create partition
error = {ct.err_code: 65535, ct.err_msg: f"Invalid partition name: {partition_name}"}
await async_client.create_partition(collection_name, partition_name,
check_task=CheckTasks.err_res, check_items=error)
# 3. drop action
await async_client.drop_collection(collection_name)
@pytest.mark.tags(CaseLabel.L1)
async def test_async_milvus_client_create_partition_partition_name_over_max_length(self):
"""
target: test create partition with partition name over max length 255
method: create partition with partition name over max length 255
expected: raise exception
"""
self.init_async_milvus_client()
async_client = self.async_milvus_client_wrap
collection_name = cf.gen_unique_str(prefix)
# 1. create collection
await async_client.create_collection(collection_name, default_dim)
partition_name = "a".join("a" for i in range(256))
# 2. create partition
error = {ct.err_code: 65535,
ct.err_msg: f"Invalid partition name: {partition_name}. The length of a partition name "
f"must be less than 255 characters."}
await async_client.create_partition(collection_name, partition_name,
check_task=CheckTasks.err_res, check_items=error)
# 3. drop action
await async_client.drop_collection(collection_name)
@pytest.mark.tags(CaseLabel.L1)
async def test_async_milvus_client_create_partition_name_lists(self):
"""
target: test create partition with wrong partition name format list
method: create partition with wrong partition name format list
expected: raise exception
"""
self.init_async_milvus_client()
async_client = self.async_milvus_client_wrap
collection_name = cf.gen_unique_str(prefix)
partition_names = [cf.gen_unique_str(partition_prefix), cf.gen_unique_str(partition_prefix)]
# 1. create collection
await async_client.create_collection(collection_name, default_dim)
# 2. create partition
error = {ct.err_code: 999, ct.err_msg: f"`partition_name` value {partition_names} is illegal"}
await async_client.create_partition(collection_name, partition_names,
check_task=CheckTasks.err_res, check_items=error)
# 3. drop action
await async_client.drop_collection(collection_name)
@pytest.mark.tags(CaseLabel.L1)
@pytest.mark.parametrize("collection_name", ["12-s", "12 s", "(mn)", "中文", "%$#"])
async def test_async_milvus_client_drop_partition_invalid_collection_name(self, collection_name):
"""
target: test drop partition with invalid collection name
method: drop partition with invalid collection name
expected: raise exception
"""
self.init_async_milvus_client()
async_client = self.async_milvus_client_wrap
partition_name = cf.gen_unique_str(partition_prefix)
# 1. create partition
error = {ct.err_code: 1100, ct.err_msg: f"Invalid collection name: {collection_name}. the first character of a "
f"collection name must be an underscore or letter: invalid parameter"}
await async_client.drop_partition(collection_name, partition_name,
check_task=CheckTasks.err_res, check_items=error)
@pytest.mark.tags(CaseLabel.L1)
async def test_async_milvus_client_drop_partition_collection_name_over_max_length(self):
"""
target: test drop partition with collection name over max length 255
method: drop partition with collection name over max length 255
expected: raise exception
"""
self.init_async_milvus_client()
async_client = self.async_milvus_client_wrap
collection_name = "a".join("a" for i in range(256))
partition_name = cf.gen_unique_str(partition_prefix)
# 1. create partition
error = {ct.err_code: 1100,
ct.err_msg: f"Invalid collection name: {collection_name}. the length of a collection name "
f"must be less than 255 characters: invalid parameter"}
await async_client.drop_partition(collection_name, partition_name,
check_task=CheckTasks.err_res, check_items=error)
@pytest.mark.tags(CaseLabel.L1)
async def test_async_milvus_client_drop_partition_collection_name_not_existed(self):
"""
target: test drop partition with nonexistent collection name
method: drop partition with nonexistent collection name
expected: raise exception
"""
self.init_async_milvus_client()
async_client = self.async_milvus_client_wrap
collection_name = cf.gen_unique_str("partition_not_exist")
partition_name = cf.gen_unique_str(partition_prefix)
# 1. create partition
error = {ct.err_code: 100, ct.err_msg: f"collection not found[database=default]"
f"[collection={collection_name}]"}
await async_client.drop_partition(collection_name, partition_name,
check_task=CheckTasks.err_res, check_items=error)
@pytest.mark.tags(CaseLabel.L1)
@pytest.mark.parametrize("partition_name", ["12 s", "(mn)", "中文", "%$#"])
async def test_async_milvus_client_drop_partition_invalid_partition_name(self, partition_name):
"""
target: test drop partition with invalid partition name
method: drop partition with invalid partition name
expected: raise exception
"""
self.init_async_milvus_client()
async_client = self.async_milvus_client_wrap
collection_name = cf.gen_unique_str(prefix)
# 1. create collection
await async_client.create_collection(collection_name, default_dim)
# 2. create partition
error = {ct.err_code: 65535, ct.err_msg: f"Invalid partition name: {partition_name}."}
await async_client.drop_partition(collection_name, partition_name,
check_task=CheckTasks.err_res, check_items=error)
# 3. drop action
await async_client.drop_collection(collection_name)
@pytest.mark.tags(CaseLabel.L1)
async def test_async_milvus_client_drop_partition_name_lists(self):
"""
target: test drop partition with wrong partition name format list
method: drop partition with wrong partition name format list
expected: raise exception
"""
self.init_async_milvus_client()
async_client = self.async_milvus_client_wrap
collection_name = cf.gen_unique_str(prefix)
partition_names = [cf.gen_unique_str(partition_prefix), cf.gen_unique_str(partition_prefix)]
# 1. create collection
await async_client.create_collection(collection_name, default_dim)
# 2. create partition
error = {ct.err_code: 1, ct.err_msg: f"`partition_name` value {partition_names} is illegal"}
await async_client.drop_partition(collection_name, partition_names,
check_task=CheckTasks.err_res, check_items=error)
# 3. drop action
await async_client.drop_collection(collection_name)
@pytest.mark.tags(CaseLabel.L1)
@pytest.mark.parametrize("name", ["12-s", "12 s", "(mn)", "中文", "%$#"])
async def test_async_milvus_client_load_partitions_invalid_collection_name(self, name):
"""
target: test load partitions with invalid collection name
method: load partitions with invalid collection name
expected: raise exception
"""
self.init_async_milvus_client()
async_client = self.async_milvus_client_wrap
# 1. load partitions
partition_name = cf.gen_unique_str(prefix)
error = {ct.err_code: 1100, ct.err_msg: f"Invalid collection name: {name}. the first character of a collection name "
f"must be an underscore or letter: invalid parameter"}
await async_client.load_partitions(name, partition_name,
check_task=CheckTasks.err_res, check_items=error)
@pytest.mark.tags(CaseLabel.L2)
async def test_async_milvus_client_load_partitions_collection_not_existed(self):
"""
target: test load partitions with nonexistent collection name
method: load partitions with nonexistent collection name
expected: raise exception
"""
self.init_async_milvus_client()
async_client = self.async_milvus_client_wrap
# 1. load partitions
collection_name = cf.gen_unique_str("nonexisted")
partition_name = cf.gen_unique_str(prefix)
error = {ct.err_code: 1100, ct.err_msg: f"collection not found[database=default]"
f"[collection={collection_name}]"}
await async_client.load_partitions(collection_name, partition_name,
check_task=CheckTasks.err_res, check_items=error)
@pytest.mark.tags(CaseLabel.L2)
async def test_async_milvus_client_load_partitions_collection_name_over_max_length(self):
"""
target: test load partitions with collection name over max length 255
method: load partitions with collection name over max length 255
expected: raise exception
"""
self.init_async_milvus_client()
async_client = self.async_milvus_client_wrap
# 1. load partitions
collection_name = "a".join("a" for i in range(256))
partition_name = cf.gen_unique_str(prefix)
error = {ct.err_code: 1100, ct.err_msg: f"Invalid collection name: {collection_name}. "
f"the length of a collection name must be less than 255 characters: "
f"invalid parameter"}
await async_client.load_partitions(collection_name, partition_name,
check_task=CheckTasks.err_res, check_items=error)
@pytest.mark.tags(CaseLabel.L1)
@pytest.mark.parametrize("name", ["12 s", "(mn)", "中文", "%$#"])
async def test_async_milvus_client_load_partitions_invalid_partition_name(self, name):
"""
target: test load partitions with invalid partition name
method: load partitions with invalid partition name
expected: raise exception
"""
self.init_async_milvus_client()
async_client = self.async_milvus_client_wrap
collection_name = cf.gen_unique_str(prefix)
# 1. create collection
await async_client.create_collection(collection_name, default_dim, consistency_level="Strong")
# 2. load partition
error = {ct.err_code: 1100, ct.err_msg: f"partition not found"}
await async_client.load_partitions(collection_name, name,
check_task=CheckTasks.err_res, check_items=error)
# 3. drop action
await async_client.drop_collection(collection_name)
@pytest.mark.tags(CaseLabel.L2)
async def test_async_milvus_client_load_partitions_partition_not_existed(self):
"""
target: test load partitions with nonexistent partition name
method: load partitions with nonexistent partition name
expected: raise exception
"""
self.init_async_milvus_client()
async_client = self.async_milvus_client_wrap
collection_name = cf.gen_unique_str(prefix)
partition_name = cf.gen_unique_str("nonexisted")
# 1. create collection
await async_client.create_collection(collection_name, default_dim, consistency_level="Strong")
# 2. load partition
error = {ct.err_code: 1100, ct.err_msg: f"partition not found"}
await async_client.load_partitions(collection_name, partition_name,
check_task=CheckTasks.err_res, check_items=error)
# 3. drop action
await async_client.drop_collection(collection_name)
@pytest.mark.tags(CaseLabel.L2)
async def test_async_milvus_client_load_partitions_partition_name_over_max_length(self):
"""
target: test load partitions with partition name over max length 255
method: load partitions with partition name over max length 255
expected: raise exception
"""
self.init_async_milvus_client()
async_client = self.async_milvus_client_wrap
collection_name = cf.gen_unique_str(prefix)
partition_name = "a".join("a" for i in range(256))
# 1. create collection
await async_client.create_collection(collection_name, default_dim, consistency_level="Strong")
# 2. load partition
error = {ct.err_code: 1100, ct.err_msg: f"partition not found"}
await async_client.load_partitions(collection_name, partition_name,
check_task=CheckTasks.err_res, check_items=error)
# 3. drop action
await async_client.drop_collection(collection_name)
@pytest.mark.tags(CaseLabel.L2)
async def test_async_milvus_client_load_partitions_without_index(self):
"""
target: test load partitions after drop index
method: load partitions after drop index
expected: raise exception
"""
self.init_async_milvus_client()
async_client = self.async_milvus_client_wrap
collection_name = cf.gen_unique_str(prefix)
partition_name = cf.gen_unique_str(partition_prefix)
# 1. create collection
await async_client.create_collection(collection_name, default_dim, consistency_level="Strong")
# 2. drop index
await async_client.release_collection(collection_name)
await async_client.drop_index(collection_name, "vector")
# 3. load partition
error = {ct.err_code: 700, ct.err_msg: f"index not found[collection={collection_name}]"}
await async_client.load_partitions(collection_name, partition_name,
check_task=CheckTasks.err_res, check_items=error)
# 4. drop action
await async_client.drop_collection(collection_name)
@pytest.mark.tags(CaseLabel.L2)
@pytest.mark.parametrize("collection_name", ["12-s", "12 s", "(mn)", "中文", "%$#"])
async def test_async_milvus_client_release_partitions_invalid_collection_name(self, collection_name):
"""
target: test release partitions with invalid collection name
method: release partitions with invalid collection name
expected: raise exception
"""
self.init_async_milvus_client()
async_client = self.async_milvus_client_wrap
partition_name = cf.gen_unique_str(partition_prefix)
# 1. release partitions
error = {ct.err_code: 1100, ct.err_msg: f"Invalid collection name: {collection_name}. the first character of a "
f"collection name must be an underscore or letter: invalid parameter"}
await async_client.release_partitions(collection_name, partition_name,
check_task=CheckTasks.err_res, check_items=error)
@pytest.mark.tags(CaseLabel.L2)
async def test_async_milvus_client_release_partitions_collection_name_over_max_length(self):
"""
target: test release partitions with collection name over max length 255
method: release partitions with collection name over max length 255
expected: raise exception
"""
self.init_async_milvus_client()
async_client = self.async_milvus_client_wrap
collection_name = "a".join("a" for i in range(256))
partition_name = cf.gen_unique_str(partition_prefix)
# 1. release partitions
error = {ct.err_code: 999,
ct.err_msg: f"Invalid collection name: {collection_name}. the length of a collection name "
f"must be less than 255 characters: invalid parameter"}
await async_client.release_partitions(collection_name, partition_name,
check_task=CheckTasks.err_res, check_items=error)
@pytest.mark.tags(CaseLabel.L2)
async def test_async_milvus_client_release_partitions_collection_name_not_existed(self):
"""
target: test release partitions with nonexistent collection name
method: release partitions with nonexistent collection name
expected: raise exception
"""
self.init_async_milvus_client()
async_client = self.async_milvus_client_wrap
collection_name = cf.gen_unique_str("collection_not_exist")
partition_name = cf.gen_unique_str(partition_prefix)
# 1. release partitions
error = {ct.err_code: 999, ct.err_msg: f"collection not found[database=default]"
f"[collection={collection_name}]"}
await async_client.release_partitions(collection_name, partition_name,
check_task=CheckTasks.err_res, check_items=error)
@pytest.mark.tags(CaseLabel.L1)
@pytest.mark.parametrize("partition_name", ["12 s", "(mn)", "中文", "%$#"])
async def test_async_milvus_client_release_partitions_invalid_partition_name(self, partition_name):
"""
target: test release partitions with invalid partition name
method: release partitions with invalid partition name
expected: raise exception
"""
self.init_async_milvus_client()
async_client = self.async_milvus_client_wrap
collection_name = cf.gen_unique_str(prefix)
# 1. create collection
await async_client.create_collection(collection_name, default_dim)
# 2. release partitions
error = {ct.err_code: 65535, ct.err_msg: f"partition not found"}
await async_client.release_partitions(collection_name, partition_name,
check_task=CheckTasks.err_res, check_items=error)
# 3. drop action
await async_client.drop_collection(collection_name)
@pytest.mark.tags(CaseLabel.L1)
async def test_async_milvus_client_release_partitions_invalid_partition_name_list(self):
"""
target: test release partitions with invalid partition name list
method: release partitions with invalid partition name list
expected: raise exception
"""
self.init_async_milvus_client()
async_client = self.async_milvus_client_wrap
collection_name = cf.gen_unique_str(prefix)
# 1. create collection
await async_client.create_collection(collection_name, default_dim)
# 2. release partition
partition_name = ["12-s"]
error = {ct.err_code: 65535, ct.err_msg: f"partition not found"}
await async_client.release_partitions(collection_name, partition_name,
check_task=CheckTasks.err_res, check_items=error)
# 3. drop action
await async_client.drop_collection(collection_name)
@pytest.mark.tags(CaseLabel.L2)
async def test_async_milvus_client_release_partitions_name_lists_empty(self):
"""
target: test release partitions with partition name list empty
method: release partitions with partition name list empty
expected: raise exception
"""
self.init_async_milvus_client()
async_client = self.async_milvus_client_wrap
collection_name = cf.gen_unique_str(prefix)
partition_names = []
# 1. create collection
await async_client.create_collection(collection_name, default_dim)
# 2. release partition
error = {ct.err_code: 999, ct.err_msg: f"invalid parameter[expected=any partition][actual=empty partition list"}
await async_client.release_partitions(collection_name, partition_names,
check_task=CheckTasks.err_res, check_items=error)
# 3. drop action
await async_client.drop_collection(collection_name)
@pytest.mark.tags(CaseLabel.L2)
async def test_async_milvus_client_release_partitions_name_lists_not_all_exists(self):
"""
target: test release partitions with partition name lists not all exists
method: release partitions with partition name lists not all exists
expected: raise exception
"""
self.init_async_milvus_client()
async_client = self.async_milvus_client_wrap
collection_name = cf.gen_unique_str(prefix)
not_exist_partition = cf.gen_unique_str("partition_not_exist")
partition_names = ["_default", not_exist_partition]
# 1. create collection
await async_client.create_collection(collection_name, default_dim)
# 2. release partitions
error = {ct.err_code: 999, ct.err_msg: f"partition not found[partition={not_exist_partition}]"}
await async_client.release_partitions(collection_name, partition_names,
check_task=CheckTasks.err_res, check_items=error)
# 3. drop action
await async_client.drop_collection(collection_name)
@pytest.mark.tags(CaseLabel.L2)
async def test_async_milvus_client_release_partitions_partition_name_not_existed(self):
"""
target: test release partitions with nonexistent partition name
method: release partitions with nonexistent partition name
expected: raise exception
"""
self.init_async_milvus_client()
async_client = self.async_milvus_client_wrap
collection_name = cf.gen_unique_str(prefix)
partition_name = cf.gen_unique_str("partition_not_exist")
# 1. create collection
await async_client.create_collection(collection_name, default_dim)
# 2. release partitions
error = {ct.err_code: 200, ct.err_msg: f"partition not found[partition={partition_name}]"}
await async_client.release_partitions(collection_name, partition_name,
check_task=CheckTasks.err_res, check_items=error)
partition_name = ""
error = {ct.err_code: 200, ct.err_msg: f"partition not found[partition={partition_name}]"}
# await async_client.release_partitions(collection_name, partition_name,
# check_task=CheckTasks.err_res, check_items=error)
# https://github.com/milvus-io/milvus/issues/38223
# 3. drop action
await async_client.drop_collection(collection_name)
class TestAsyncMilvusClientPartitionValid(TestMilvusClientV2Base):
""" Test case of partition interface """
def teardown_method(self, method):
if self.async_milvus_client_wrap.async_milvus_client is not None:
asyncio.run(self.async_milvus_client_wrap.close())
super().teardown_method(method)
"""
******************************************************************
# The following are valid base cases
******************************************************************
"""
@pytest.mark.tags(CaseLabel.L0)
async def test_async_milvus_client_create_drop_partition_default(self):
"""
target: test create and drop partition normal case
method: 1. create collection, partition 2. insert to partition 3. search and query 4. drop partition, collection
expected: run successfully
"""
self.init_async_milvus_client()
async_client = self.async_milvus_client_wrap
# 1. create collection
collection_name = cf.gen_unique_str(prefix)
await async_client.create_collection(collection_name, default_dim)
collections, _ = await async_client.list_collections()
assert collection_name in collections
desc, _ = await async_client.describe_collection(collection_name,
check_task=CheckTasks.check_describe_collection_property,
check_items={"collection_name": collection_name,
"dim": default_dim,
"consistency_level": 0})
# 2. create partition
partition_name = cf.gen_unique_str(partition_prefix)
await async_client.create_partition(collection_name, partition_name)
partitions, _ = await async_client.list_partitions(collection_name)
assert partition_name in partitions
# 3. insert
rng = np.random.default_rng(seed=19530)
rows = [{default_primary_key_field_name: i, default_vector_field_name: list(rng.random((1, default_dim))[0]),
default_float_field_name: i * 1.0, default_string_field_name: str(i)} for i in range(default_nb)]
await async_client.insert(collection_name, rows, partition_name=partition_name)
tasks = []
# 4. search
vectors_to_search = rng.random((1, default_dim))
search_task = async_client.search(collection_name, vectors_to_search,
partition_names=[partition_name],
check_task=CheckTasks.check_search_results,
check_items={"enable_milvus_client_api": True,
"nq": len(vectors_to_search),
"limit": default_limit,
"pk_name": default_primary_key_field_name})
tasks.append(search_task)
# 5. query
query_task = async_client.query(collection_name, filter=default_search_exp,
partition_names=[partition_name],
check_task=CheckTasks.check_query_results,
check_items={"exp_res": rows,
"with_vec": True,
"pk_name": default_primary_key_field_name})
tasks.append(query_task)
res = await asyncio.gather(*tasks)
# 6. drop action
has_partition, _ = await async_client.has_partition(collection_name, partition_name)
if has_partition:
await async_client.release_partitions(collection_name, partition_name)
await async_client.drop_partition(collection_name, partition_name)
partitions, _ = await async_client.list_partitions(collection_name)
assert partition_name not in partitions
await async_client.drop_collection(collection_name)
@pytest.mark.tags(CaseLabel.L0)
async def test_async_milvus_client_load_release_partitions(self):
"""
target: test load and release partitions normal case
method: 1. create collection, two partitions
2. insert different data to two partitions
3. search and query
4. release partitions, search and query
5. load partitions, search and query
4. drop partition, collection
expected: run successfully
"""
self.init_async_milvus_client()
async_client = self.async_milvus_client_wrap
# 1. create collection
collection_name = cf.gen_unique_str(prefix)
await async_client.create_collection(collection_name, default_dim)
collections, _ = await async_client.list_collections()
assert collection_name in collections
desc, _ = await async_client.describe_collection(collection_name,
check_task=CheckTasks.check_describe_collection_property,
check_items={"collection_name": collection_name,
"dim": default_dim,
"consistency_level": 0})
# 2. create partition
partition_name_1 = cf.gen_unique_str(partition_prefix)
await async_client.create_partition(collection_name, partition_name_1)
partition_name_2 = cf.gen_unique_str(partition_prefix)
await async_client.create_partition(collection_name, partition_name_2)
partitions, _ = await async_client.list_partitions(collection_name)
assert partition_name_1 in partitions
assert partition_name_2 in partitions
# 3. insert
rng = np.random.default_rng(seed=19530)
rows_default = [{default_primary_key_field_name: i, default_vector_field_name: list(rng.random((1, default_dim))[0]),
default_float_field_name: i * 1.0, default_string_field_name: str(i)} for i in range(default_nb)]
await async_client.insert(collection_name, rows_default)
rows_1 = [{default_primary_key_field_name: i, default_vector_field_name: list(rng.random((1, default_dim))[0]),
default_float_field_name: i * 1.0, default_string_field_name: str(i)} for i in range(default_nb, 2 * default_nb)]
await async_client.insert(collection_name, rows_1, partition_name=partition_name_1)
rows_2 = [{default_primary_key_field_name: i, default_vector_field_name: list(rng.random((1, default_dim))[0]),
default_float_field_name: i * 1.0, default_string_field_name: str(i)} for i in range(2 * default_nb, 3 * default_nb)]
await async_client.insert(collection_name, rows_2, partition_name=partition_name_2)
tasks = []
# 4. search and query
vectors_to_search = rng.random((1, default_dim))
# search single partition
search_task = async_client.search(collection_name, vectors_to_search,
partition_names=[partition_name_1],
check_task=CheckTasks.check_search_results,
check_items={"enable_milvus_client_api": True,
"nq": len(vectors_to_search),
"limit": default_limit,
"pk_name": default_primary_key_field_name})
tasks.append(search_task)
# search multi partition
search_task_multi = async_client.search(collection_name, vectors_to_search,
partition_names=[partition_name_1, partition_name_2],
check_task=CheckTasks.check_search_results,
check_items={"enable_milvus_client_api": True,
"nq": len(vectors_to_search),
"limit": default_limit,
"pk_name": default_primary_key_field_name})
tasks.append(search_task_multi)
# query single partition
query_task = async_client.query(collection_name, filter=default_search_exp,
partition_names=[partition_name_1],
check_task=CheckTasks.check_query_results,
check_items={"exp_res": rows_1,
"with_vec": True,
"pk_name": default_primary_key_field_name})
tasks.append(query_task)
# query multi partition
query_task_multi = async_client.query(collection_name, filter=default_search_exp,
partition_names=[partition_name_1, partition_name_2],
check_task=CheckTasks.check_query_results,
check_items={"exp_res": rows_1 + rows_2,
"with_vec": True,
"pk_name": default_primary_key_field_name})
tasks.append(query_task_multi)
res = await asyncio.gather(*tasks)
# 5. release partitions, search and query
await async_client.release_partitions(collection_name, partition_name_1)
error = {ct.err_code: 201, ct.err_msg: "partition not loaded"}
await async_client.search(collection_name, vectors_to_search,
partition_names=[partition_name_1],
check_task=CheckTasks.err_res,
check_items=error)
await async_client.query(collection_name, filter=default_search_exp,
partition_names=[partition_name_1],
check_task=CheckTasks.err_res,
check_items=error)
await async_client.search(collection_name, vectors_to_search,
partition_names=[partition_name_2],
check_task=CheckTasks.check_search_results,
check_items={"enable_milvus_client_api": True,
"nq": len(vectors_to_search),
"limit": default_limit,
"pk_name": default_primary_key_field_name})
await async_client.query(collection_name, filter=default_search_exp,
partition_names=[partition_name_2],
check_task=CheckTasks.check_query_results,
check_items={"exp_res": rows_2,
"with_vec": True,
"pk_name": default_primary_key_field_name})
# 6. load partitions, search and query
tasks_after_load = []
await async_client.load_partitions(collection_name, [partition_name_1, partition_name_2])
search_task = async_client.search(collection_name, vectors_to_search,
check_task=CheckTasks.check_search_results,
check_items={"enable_milvus_client_api": True,
"nq": len(vectors_to_search),
"limit": default_limit,
"pk_name": default_primary_key_field_name})
tasks_after_load.append(search_task)
query_task = async_client.query(collection_name, filter=default_search_exp,
check_task=CheckTasks.check_query_results,
check_items={"exp_res": rows_default + rows_1 + rows_2,
"with_vec": True,
"pk_name": default_primary_key_field_name})
tasks_after_load.append(query_task)
res = await asyncio.gather(*tasks_after_load)
# 7. drop action
await async_client.drop_collection(collection_name)