test: add collection V2 cases for milvus client (#43919)

issue: #43590
Migrate collection test cases from TestcaseBase to
TestMilvusClientV2Base

---------

Signed-off-by: Orpheus Wang <orpheus.wang@zilliz.com>
This commit is contained in:
9Eurydice9 2025-08-21 10:35:45 +08:00 committed by GitHub
parent 7963b17ac1
commit eec58c3bb5
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 1019 additions and 1152 deletions

View File

@ -780,40 +780,6 @@ class TestMilvusClientCollectionValid(TestMilvusClientV2Base):
if self.has_collection(client, collection_name)[0]: if self.has_collection(client, collection_name)[0]:
self.drop_collection(client, collection_name) self.drop_collection(client, collection_name)
@pytest.mark.tags(CaseLabel.L1)
def test_milvus_client_collection_all_datatype_fields(self):
"""
target: Test create collection with all supported dataType fields
method: Create collection with schema containing all supported dataTypes
expected: Collection created successfully with all field types
"""
client = self._client()
collection_name = cf.gen_collection_name_by_testcase_name()
schema = self.create_schema(client, enable_dynamic_field=False)[0]
schema.add_field(ct.default_int64_field_name, DataType.INT64, is_primary=True)
schema.add_field(default_vector_field_name, DataType.FLOAT_VECTOR, dim=default_dim)
# Add all supported scalar data types (excluding vectors and unsupported types)
supported_types = []
for k, v in DataType.__members__.items():
if (v and v != DataType.UNKNOWN and v != DataType.STRING
and v != DataType.VARCHAR and v != DataType.FLOAT_VECTOR
and v != DataType.BINARY_VECTOR and v != DataType.ARRAY
and v != DataType.FLOAT16_VECTOR and v != DataType.BFLOAT16_VECTOR
and v != DataType.INT8_VECTOR):
supported_types.append((k.lower(), v))
for field_name, data_type in supported_types:
if data_type != DataType.INT64: # Skip INT64 as it's already added as primary key
schema.add_field(field_name, data_type)
self.create_collection(client, collection_name, schema=schema)
expected_field_count = len([name for name in supported_types]) + 2
self.describe_collection(client, collection_name,
check_task=CheckTasks.check_describe_collection_property,
check_items={"collection_name": collection_name,
"enable_dynamic_field": False,
"fields_num": expected_field_count})
self.drop_collection(client, collection_name)
@pytest.mark.tags(CaseLabel.L2) @pytest.mark.tags(CaseLabel.L2)
def test_milvus_client_collection_self_creation_multiple_vectors(self): def test_milvus_client_collection_self_creation_multiple_vectors(self):
""" """
@ -1882,37 +1848,6 @@ class TestMilvusClientReleaseCollectionValid(TestMilvusClientV2Base):
self.drop_collection(client, collection_name) self.drop_collection(client, collection_name)
class TestMilvusClientReleaseAdvanced(TestMilvusClientV2Base):
"""
******************************************************************
The following cases are used to test release during search operations
******************************************************************
"""
@pytest.mark.tags(CaseLabel.L0)
def test_milvus_client_release_collection_during_searching(self):
"""
target: test release collection during searching
method: insert entities into collection, flush and load collection, release collection during searching
expected: raise exception
"""
client = self._client()
collection_name = cf.gen_collection_name_by_testcase_name()
self.create_collection(client, collection_name, default_dim)
self.load_collection(client, collection_name)
load_state = self.get_load_state(client, collection_name)[0]
assert load_state["state"] == LoadState.Loaded, f"Expected Loaded, but got {load_state['state']}"
vectors_to_search = np.random.default_rng(seed=19530).random((1, default_dim))
self.search(client, collection_name, vectors_to_search, limit=default_limit, _async=True)
self.release_collection(client, collection_name)
load_state = self.get_load_state(client, collection_name)[0]
assert load_state["state"] == LoadState.NotLoad, f"Expected NotLoad after release, but got {load_state['state']}"
error = {ct.err_code: 65535, ct.err_msg: "collection not loaded"}
self.search(client, collection_name, vectors_to_search, limit=default_limit,
check_task=CheckTasks.err_res, check_items=error)
self.drop_collection(client, collection_name)
class TestMilvusClientLoadCollectionInvalid(TestMilvusClientV2Base): class TestMilvusClientLoadCollectionInvalid(TestMilvusClientV2Base):
""" Test case of search interface """ """ Test case of search interface """
""" """
@ -2712,6 +2647,41 @@ class TestMilvusClientLoadCollectionValid(TestMilvusClientV2Base):
self.drop_collection(client, collection_name) self.drop_collection(client, collection_name)
class TestMilvusClientLoadPartition(TestMilvusClientV2Base):
""" Test case of load partition interface """
@pytest.mark.tags(CaseLabel.L2)
def test_milvus_client_load_collection_after_load_loaded_partition(self):
"""
target: test load partition after load partition
method: 1. create collection and two partitions
4. release collection and load one partition twice
5. query on the non-loaded partition (should fail)
6. load the whole collection (should succeed)
expected: No exception on repeated partition load, error on querying non-loaded partition, success on collection load
"""
client = self._client()
collection_name = cf.gen_collection_name_by_testcase_name()
partition_name_1 = cf.gen_unique_str("partition1")
partition_name_2 = cf.gen_unique_str("partition2")
# 1. create collection
self.create_collection(client, collection_name, default_dim)
self.release_collection(client, collection_name)
# 2. create partitions
self.create_partition(client, collection_name, partition_name_1)
self.create_partition(client, collection_name, partition_name_2)
# 5. load partition1 twice
self.load_partitions(client, collection_name, [partition_name_1])
self.load_partitions(client, collection_name, [partition_name_1])
# 6. query on the non-loaded partition2 (should fail)
error = {ct.err_code: 65538, ct.err_msg: 'partition not loaded'}
self.query(client, collection_name, filter=default_search_exp, partition_names=[partition_name_2],
check_task=CheckTasks.err_res, check_items=error)
# 7. load the whole collection (should succeed)
self.load_collection(client, collection_name)
self.drop_collection(client, collection_name)
class TestMilvusClientDescribeCollectionInvalid(TestMilvusClientV2Base): class TestMilvusClientDescribeCollectionInvalid(TestMilvusClientV2Base):
""" Test case of search interface """ """ Test case of search interface """
""" """
@ -3879,3 +3849,826 @@ class TestMilvusClientCollectionMultiCollections(TestMilvusClientV2Base):
self.drop_collection(client, collection_name) self.drop_collection(client, collection_name)
class TestMilvusClientCollectionString(TestMilvusClientV2Base):
"""
******************************************************************
# The following cases are used to test about string fields
******************************************************************
"""
@pytest.mark.tags(CaseLabel.L1)
def test_milvus_client_collection_string_field_is_primary(self):
"""
target: test create collection with string field as primary key
method: create collection with id_type="string" using fast creation method
expected: Create collection successfully
"""
client = self._client()
collection_name = cf.gen_collection_name_by_testcase_name()
# Use fast creation method with string primary key
self.create_collection(client, collection_name, default_dim, id_type="string", max_length=100)
# Verify collection properties
self.describe_collection(client, collection_name,
check_task=CheckTasks.check_describe_collection_property,
check_items={"collection_name": collection_name,
"id_name": "id"})
self.drop_collection(client, collection_name)
@pytest.mark.tags(CaseLabel.L1)
def test_milvus_client_collection_string_field_primary_auto_id(self):
"""
target: test create collection with string primary field and auto_id=True
method: create collection with string field, the string field primary and auto id are true
expected: Create collection successfully
"""
client = self._client()
collection_name = cf.gen_collection_name_by_testcase_name()
# Create schema with VARCHAR primary key and auto_id=True
schema = self.create_schema(client, enable_dynamic_field=False)[0]
schema.add_field("string_pk", DataType.VARCHAR, max_length=100, is_primary=True, auto_id=True)
schema.add_field("vector", DataType.FLOAT_VECTOR, dim=default_dim)
# Create collection
self.create_collection(client, collection_name, schema=schema)
# Verify collection properties
self.describe_collection(client, collection_name,
check_task=CheckTasks.check_describe_collection_property,
check_items={"collection_name": collection_name,
"id_name": "string_pk",
"auto_id": True,
"enable_dynamic_field": False})
self.drop_collection(client, collection_name)
@pytest.mark.tags(CaseLabel.L1)
def test_milvus_client_collection_only_string_field(self):
"""
target: test create collection with only string field (no vector field)
method: create collection with only string field
expected: Raise exception
"""
client = self._client()
collection_name = cf.gen_collection_name_by_testcase_name()
# Create schema with only string field
schema = self.create_schema(client, enable_dynamic_field=False)[0]
schema.add_field("string_pk", DataType.VARCHAR, max_length=100, is_primary=True, auto_id=False)
# Try to create collection
error = {ct.err_code: 1100, ct.err_msg: "schema does not contain vector field: invalid parameter"}
self.create_collection(client, collection_name, schema=schema,
check_task=CheckTasks.err_res, check_items=error)
@pytest.mark.tags(CaseLabel.L1)
def test_milvus_client_collection_string_field_over_max_length(self):
"""
target: test create collection with string field exceeding max length
method: 1. create collection with string field
2. String field max_length exceeds maximum (65535)
expected: Raise exception
"""
client = self._client()
collection_name = cf.gen_collection_name_by_testcase_name()
# Create schema with string field exceeding max length
schema = self.create_schema(client, enable_dynamic_field=False)[0]
schema.add_field("int64_pk", DataType.INT64, is_primary=True, auto_id=False)
schema.add_field("vector", DataType.FLOAT_VECTOR, dim=default_dim)
# Try to add string field with max_length > 65535
max_length = 65535 + 1
schema.add_field("string_field", DataType.VARCHAR, max_length=max_length)
error = {ct.err_code: 1100, ct.err_msg: f"the maximum length specified for the field(string_field) should be in (0, 65535], "
f"but got {max_length} instead: invalid parameter"}
self.create_collection(client, collection_name, schema=schema,
check_task=CheckTasks.err_res, check_items=error)
@pytest.mark.tags(CaseLabel.L1)
def test_milvus_client_collection_invalid_string_field_dtype(self):
"""
target: test create collection with invalid string field datatype
method: create collection with string field using DataType.STRING (deprecated)
expected: Raise exception
"""
client = self._client()
collection_name = cf.gen_collection_name_by_testcase_name()
# Create schema
schema = self.create_schema(client, enable_dynamic_field=False)[0]
schema.add_field("int64_pk", DataType.INT64, is_primary=True, auto_id=False)
schema.add_field("vector", DataType.FLOAT_VECTOR, dim=default_dim)
# Try to add field with deprecated DataType.STRING
error = {ct.err_code: 1100, ct.err_msg: "string data type not supported yet, please use VarChar type instead"}
schema.add_field("string_field", DataType.STRING)
self.create_collection(client, collection_name, schema=schema,
check_task=CheckTasks.err_res, check_items=error)
class TestMilvusClientCollectionJSON(TestMilvusClientV2Base):
"""
******************************************************************
# The following cases are used to test about JSON fields
******************************************************************
"""
@pytest.mark.tags(CaseLabel.L1)
@pytest.mark.parametrize("auto_id", [True, False])
def test_milvus_client_collection_json_field_as_primary_key(self, auto_id):
"""
target: test create collection with JSON field as primary key
method: 1. create collection with one JSON field, and vector field
2. set json field is_primary=true
3. set auto_id as true
expected: Raise exception
"""
client = self._client()
collection_name = cf.gen_collection_name_by_testcase_name()
# Test 1: create json field as primary key through field
schema1 = self.create_schema(client, enable_dynamic_field=False)[0]
schema1.add_field("json_field", DataType.JSON, is_primary=True, auto_id=auto_id)
schema1.add_field("vector_field", DataType.FLOAT_VECTOR, dim=default_dim)
error = {ct.err_code: 1100, ct.err_msg: "Primary key type must be DataType.INT64 or DataType.VARCHAR"}
self.create_collection(client, collection_name, schema=schema1,
check_task=CheckTasks.err_res, check_items=error)
# Test 2: create json field as primary key through schema
schema2 = self.create_schema(client, enable_dynamic_field=False, primary_field="json_field", auto_id=auto_id)[0]
schema2.add_field("json_field", DataType.JSON)
schema2.add_field("vector_field", DataType.FLOAT_VECTOR, dim=default_dim)
self.create_collection(client, collection_name, schema=schema2, primary_field="json_field",
check_task=CheckTasks.err_res, check_items=error)
class TestMilvusClientCollectionARRAY(TestMilvusClientV2Base):
"""
******************************************************************
# The following cases are used to test about ARRAY fields
******************************************************************
"""
@pytest.mark.tags(CaseLabel.L2)
def test_milvus_client_collection_array_field_element_type_not_exist(self):
"""
target: test create collection with ARRAY field without element type
method: create collection with one array field without element type
expected: Raise exception
"""
client = self._client()
collection_name = cf.gen_collection_name_by_testcase_name()
schema = self.create_schema(client, enable_dynamic_field=False)[0]
schema.add_field("int64_pk", DataType.INT64, is_primary=True, auto_id=False)
schema.add_field("vector_field", DataType.FLOAT_VECTOR, dim=default_dim)
schema.add_field("array_field", DataType.ARRAY, element_type=None)
# Try to add array field without element_type
error = {ct.err_code: 1100, ct.err_msg: "element data type None is not valid"}
self.create_collection(client, collection_name, schema=schema,
check_task=CheckTasks.err_res, check_items=error)
@pytest.mark.tags(CaseLabel.L2)
@pytest.mark.parametrize("element_type", [1001, 'a', [], (), {1}, DataType.BINARY_VECTOR,
DataType.FLOAT_VECTOR, DataType.JSON, DataType.ARRAY])
def test_milvus_client_collection_array_field_element_type_invalid(self, element_type):
"""
target: Create a field with invalid element_type
method: Create a field with invalid element_type
1. Type not in DataType: 1, 'a', ...
2. Type in DataType: binary_vector, float_vector, json_field, array_field
expected: Raise exception
"""
client = self._client()
collection_name = cf.gen_collection_name_by_testcase_name()
schema = self.create_schema(client, enable_dynamic_field=False)[0]
schema.add_field("int64_pk", DataType.INT64, is_primary=True, auto_id=False)
schema.add_field("vector_field", DataType.FLOAT_VECTOR, dim=default_dim)
# Determine expected error based on element_type
error = {ct.err_code: 1100, ct.err_msg: f"element type {element_type} is not supported"}
if element_type in ['a', {1}]:
error = {ct.err_code: 1100, ct.err_msg: "Unexpected error"}
elif element_type == []:
error = {ct.err_code: 1100, ct.err_msg: "'list' object cannot be interpreted as an integer"}
elif element_type == ():
error = {ct.err_code: 1100, ct.err_msg: "'tuple' object cannot be interpreted as an integer"}
elif element_type in [DataType.BINARY_VECTOR, DataType.FLOAT_VECTOR, DataType.JSON, DataType.ARRAY]:
data_type = element_type.name
if element_type == DataType.BINARY_VECTOR:
data_type = "BinaryVector"
elif element_type == DataType.FLOAT_VECTOR:
data_type = "FloatVector"
elif element_type == DataType.ARRAY:
data_type = "Array"
error = {ct.err_code: 1100, ct.err_msg: f"element type {data_type} is not supported"}
# Try to add array field with invalid element_type
schema.add_field("array_field", DataType.ARRAY, element_type=element_type)
self.create_collection(client, collection_name, schema=schema,
check_task=CheckTasks.err_res, check_items=error)
@pytest.mark.tags(CaseLabel.L2)
@pytest.mark.parametrize("max_capacity", [None, [], 'a', (), -1, 4097])
def test_milvus_client_collection_array_field_invalid_capacity(self, max_capacity):
"""
target: Create a field with invalid max_capacity
method: Create a field with invalid max_capacity
1. Type invalid: [], 'a', (), None
2. Value invalid: <0, >max_capacity(4096)
expected: Raise exception
"""
client = self._client()
collection_name = cf.gen_collection_name_by_testcase_name()
schema = self.create_schema(client, enable_dynamic_field=False)[0]
schema.add_field("int64_pk", DataType.INT64, is_primary=True, auto_id=False)
schema.add_field("vector_field", DataType.FLOAT_VECTOR, dim=default_dim)
# Determine expected error based on max_capacity type and value
if max_capacity in [[], 'a', (), None]:
error = {ct.err_code: 1100, ct.err_msg: "the value for max_capacity of field array_field must be an integer"}
else:
error = {ct.err_code: 1100, ct.err_msg: "the maximum capacity specified for a Array should be in (0, 4096]"}
# Try to add array field with invalid max_capacity
schema.add_field("array_field", DataType.ARRAY, element_type=DataType.INT64, max_capacity=max_capacity)
self.create_collection(client, collection_name, schema=schema,
check_task=CheckTasks.err_res, check_items=error)
@pytest.mark.tags(CaseLabel.L2)
def test_milvus_client_collection_string_array_without_max_length(self):
"""
target: Create string array without giving max length
method: Create string array without giving max length
expected: Raise exception
"""
client = self._client()
collection_name = cf.gen_collection_name_by_testcase_name()
schema = self.create_schema(client, enable_dynamic_field=False)[0]
schema.add_field("int64_pk", DataType.INT64, is_primary=True, auto_id=False)
schema.add_field("vector_field", DataType.FLOAT_VECTOR, dim=default_dim)
# Try to add string array field without max_length - should fail at add_field stage
error = {ct.err_code: 1100, ct.err_msg: "type param(max_length) should be specified for the field(array_field)"}
schema.add_field("array_field", DataType.ARRAY, element_type=DataType.VARCHAR)
self.create_collection(client, collection_name, schema=schema,
check_task=CheckTasks.err_res, check_items=error)
@pytest.mark.tags(CaseLabel.L2)
@pytest.mark.parametrize("max_length", [-1, 65536])
def test_milvus_client_collection_string_array_max_length_invalid(self, max_length):
"""
target: Create string array with invalid max length
method: Create string array with invalid max length
Value invalid: <0, >max_length(65535)
expected: Raise exception
"""
client = self._client()
collection_name = cf.gen_collection_name_by_testcase_name()
schema = self.create_schema(client, enable_dynamic_field=False)[0]
schema.add_field("int64_pk", DataType.INT64, is_primary=True, auto_id=False)
schema.add_field("vector_field", DataType.FLOAT_VECTOR, dim=default_dim)
# Try to add string array field with invalid max_length
schema.add_field("array_field", DataType.ARRAY, element_type=DataType.VARCHAR, max_length=max_length)
error = {ct.err_code: 1100, ct.err_msg: f"the maximum length specified for the field(array_field) should be in (0, 65535], "
f"but got {max_length} instead: invalid parameter"}
self.create_collection(client, collection_name, schema=schema,
check_task=CheckTasks.err_res, check_items=error)
@pytest.mark.tags(CaseLabel.L2)
def test_milvus_client_collection_array_field_all_datatype(self):
"""
target: test create collection with ARRAY field all data type
method: 1. Create field respectively: int8, int16, int32, int64, varchar, bool, float, double
2. Insert data respectively: int8, int16, int32, int64, varchar, bool, float, double
expected: Create collection successfully and insert data successfully
"""
client = self._client()
collection_name = cf.gen_collection_name_by_testcase_name()
# Create schema with all supported array data types
nb = default_nb
schema = self.create_schema(client, enable_dynamic_field=False)[0]
schema.add_field("int64", DataType.INT64, is_primary=True, auto_id=False)
schema.add_field("vector", DataType.FLOAT_VECTOR, dim=default_dim)
schema.add_field("int8_array", DataType.ARRAY, element_type=DataType.INT8, max_capacity=nb)
schema.add_field("int16_array", DataType.ARRAY, element_type=DataType.INT16, max_capacity=nb)
schema.add_field("int32_array", DataType.ARRAY, element_type=DataType.INT32, max_capacity=nb)
schema.add_field("int64_array", DataType.ARRAY, element_type=DataType.INT64, max_capacity=nb)
schema.add_field("bool_array", DataType.ARRAY, element_type=DataType.BOOL, max_capacity=nb)
schema.add_field("float_array", DataType.ARRAY, element_type=DataType.FLOAT, max_capacity=nb)
schema.add_field("double_array", DataType.ARRAY, element_type=DataType.DOUBLE, max_capacity=nb)
schema.add_field("string_array", DataType.ARRAY, element_type=DataType.VARCHAR, max_capacity=nb, max_length=100)
# Create collection
self.create_collection(client, collection_name, schema=schema)
# Verify collection properties and all fields
expected_fields = [
{"field_id": 100, "name": "int64", "description": "", "type": DataType.INT64, "params": {}, "element_type": 0, "is_primary": True},
{"field_id": 101, "name": "vector", "description": "", "type": DataType.FLOAT_VECTOR, "params": {"dim": default_dim}, "element_type": 0},
{"field_id": 102, "name": "int8_array", "description": "", "type": DataType.ARRAY, "params": {"max_capacity": nb}, "element_type": DataType.INT8},
{"field_id": 103, "name": "int16_array", "description": "", "type": DataType.ARRAY, "params": {"max_capacity": nb}, "element_type": DataType.INT16},
{"field_id": 104, "name": "int32_array", "description": "", "type": DataType.ARRAY, "params": {"max_capacity": nb}, "element_type": DataType.INT32},
{"field_id": 105, "name": "int64_array", "description": "", "type": DataType.ARRAY, "params": {"max_capacity": nb}, "element_type": DataType.INT64},
{"field_id": 106, "name": "bool_array", "description": "", "type": DataType.ARRAY, "params": {"max_capacity": nb}, "element_type": DataType.BOOL},
{"field_id": 107, "name": "float_array", "description": "", "type": DataType.ARRAY, "params": {"max_capacity": nb}, "element_type": DataType.FLOAT},
{"field_id": 108, "name": "double_array", "description": "", "type": DataType.ARRAY, "params": {"max_capacity": nb}, "element_type": DataType.DOUBLE},
{"field_id": 109, "name": "string_array", "description": "", "type": DataType.ARRAY, "params": {"max_length": 100, "max_capacity": nb}, "element_type": DataType.VARCHAR}
]
self.describe_collection(client, collection_name,
check_task=CheckTasks.check_describe_collection_property,
check_items={"collection_name": collection_name,
"id_name": "int64",
"enable_dynamic_field": False,
"fields": expected_fields})
# Generate and insert test data manually
insert_nb = 10
pk_values = [i for i in range(insert_nb)]
float_vec = cf.gen_vectors(insert_nb, default_dim)
int8_values = [[numpy.int8(j) for j in range(insert_nb)] for i in range(insert_nb)]
int16_values = [[numpy.int16(j) for j in range(insert_nb)] for i in range(insert_nb)]
int32_values = [[numpy.int32(j) for j in range(insert_nb)] for i in range(insert_nb)]
int64_values = [[numpy.int64(j) for j in range(insert_nb)] for i in range(insert_nb)]
bool_values = [[numpy.bool_(j) for j in range(insert_nb)] for i in range(insert_nb)]
float_values = [[numpy.float32(j) for j in range(insert_nb)] for i in range(insert_nb)]
double_values = [[numpy.double(j) for j in range(insert_nb)] for i in range(insert_nb)]
string_values = [[str(j) for j in range(insert_nb)] for i in range(insert_nb)]
# Prepare data as list format
data = []
for i in range(insert_nb):
row = {
"int64": pk_values[i],
"vector": float_vec[i],
"int8_array": int8_values[i],
"int16_array": int16_values[i],
"int32_array": int32_values[i],
"int64_array": int64_values[i],
"bool_array": bool_values[i],
"float_array": float_values[i],
"double_array": double_values[i],
"string_array": string_values[i]
}
data.append(row)
self.insert(client, collection_name, data)
self.flush(client, collection_name)
stats = self.get_collection_stats(client, collection_name)[0]
assert stats['row_count'] == insert_nb
self.drop_collection(client, collection_name)
class TestMilvusClientCollectionMultipleVectorValid(TestMilvusClientV2Base):
"""
******************************************************************
# Test case for collection with multiple vector fields - Valid cases
******************************************************************
"""
@pytest.mark.tags(CaseLabel.L1)
@pytest.mark.parametrize("primary_key_type", ["int64", "varchar"])
@pytest.mark.parametrize("auto_id", [True, False])
@pytest.mark.parametrize("shards_num", [1, 3])
def test_milvus_client_collection_multiple_vectors_all_supported_field_type(self, primary_key_type, auto_id, shards_num):
"""
target: test create collection with multiple vector fields and all supported field types
method: create collection with multiple vector fields and all supported field types
expected: collection created successfully with all field types
"""
client = self._client()
collection_name = cf.gen_collection_name_by_testcase_name()
# Create schema with multiple vector fields and all supported scalar types
schema = self.create_schema(client, enable_dynamic_field=False, auto_id=auto_id)[0]
# Add primary key field
if primary_key_type == "int64":
schema.add_field("id", DataType.INT64, is_primary=True, auto_id=auto_id)
else:
schema.add_field("id", DataType.VARCHAR, max_length=100, is_primary=True, auto_id=auto_id)
# Add multiple vector fields
schema.add_field(default_vector_field_name, DataType.FLOAT_VECTOR, dim=default_dim)
schema.add_field(ct.default_binary_vec_field_name, DataType.BINARY_VECTOR, dim=default_dim)
schema.add_field(ct.default_float16_vec_field_name, DataType.FLOAT16_VECTOR, dim=default_dim)
schema.add_field(ct.default_bfloat16_vec_field_name, DataType.BFLOAT16_VECTOR, dim=default_dim)
# Add all supported scalar data types from DataType.__members__
supported_types = []
for k, v in DataType.__members__.items():
if (v and v != DataType.UNKNOWN and v != DataType.STRING
and v != DataType.VARCHAR and v != DataType.FLOAT_VECTOR
and v != DataType.BINARY_VECTOR and v != DataType.ARRAY
and v != DataType.FLOAT16_VECTOR and v != DataType.BFLOAT16_VECTOR
and v != DataType.INT8_VECTOR and v != DataType.SPARSE_FLOAT_VECTOR):
supported_types.append((k.lower(), v))
for field_name, data_type in supported_types:
# Skip INT64 and VARCHAR as they're already added as primary key
if data_type != DataType.INT64 and data_type != DataType.VARCHAR:
schema.add_field(field_name, data_type)
# Add ARRAY field separately with required parameters
schema.add_field("array_field", DataType.ARRAY, element_type=DataType.INT64, max_capacity=10)
# Create collection
self.create_collection(client, collection_name, schema=schema, shards_num=shards_num)
# Verify collection properties
expected_field_count = len([name for name in supported_types]) + 5
self.describe_collection(client, collection_name,
check_task=CheckTasks.check_describe_collection_property,
check_items={"collection_name": collection_name,
"enable_dynamic_field": False,
"auto_id": auto_id,
"num_shards": shards_num,
"fields_num": expected_field_count})
# Create same collection again
self.create_collection(client, collection_name, schema=schema, shards_num=shards_num)
self.drop_collection(client, collection_name)
@pytest.mark.tags(CaseLabel.L2)
@pytest.mark.parametrize("primary_key_type", ["int64", "varchar"])
@pytest.mark.parametrize("auto_id", [True, False])
@pytest.mark.parametrize("enable_dynamic_field", [True, False])
def test_milvus_client_collection_multiple_vectors_different_dim(self, primary_key_type, auto_id, enable_dynamic_field):
"""
target: test create collection with multiple vector fields having different dimensions
method: create collection with multiple vector fields with different dims
expected: collection created successfully with different vector dimensions
"""
client = self._client()
collection_name = cf.gen_collection_name_by_testcase_name()
# Create schema with different vector dimensions
schema = self.create_schema(client, enable_dynamic_field=enable_dynamic_field, auto_id=auto_id)[0]
# Add primary key field
if primary_key_type == "int64":
schema.add_field("id", DataType.INT64, is_primary=True, auto_id=auto_id)
else:
schema.add_field("id", DataType.VARCHAR, max_length=100, is_primary=True, auto_id=auto_id)
# Add vector fields with different dimensions
schema.add_field("float_vec_max_dim", DataType.FLOAT_VECTOR, dim=ct.max_dim)
schema.add_field("float_vec_min_dim", DataType.FLOAT_VECTOR, dim=ct.min_dim)
schema.add_field("float_vec_default_dim", DataType.FLOAT_VECTOR, dim=default_dim)
# Create collection
self.create_collection(client, collection_name, schema=schema)
# Verify collection properties
expected_dims = [ct.max_dim, ct.min_dim, default_dim]
expected_vector_names = ["float_vec_max_dim", "float_vec_min_dim", "float_vec_default_dim"]
self.describe_collection(client, collection_name,
check_task=CheckTasks.check_describe_collection_property,
check_items={"collection_name": collection_name,
"auto_id": auto_id,
"enable_dynamic_field": enable_dynamic_field,
"dim": expected_dims,
"vector_name": expected_vector_names})
self.drop_collection(client, collection_name)
@pytest.mark.tags(CaseLabel.L2)
@pytest.mark.parametrize("primary_key_type", ["int64", "varchar"])
def test_milvus_client_collection_multiple_vectors_maximum_dim(self, primary_key_type):
"""
target: test create collection with multiple vector fields at maximum dimension
method: create collection with multiple vector fields all using max dimension
expected: collection created successfully with maximum dimensions
"""
client = self._client()
collection_name = cf.gen_collection_name_by_testcase_name()
# Create schema with maximum dimension vectors
schema = self.create_schema(client, enable_dynamic_field=False)[0]
# Add primary key field
if primary_key_type == "int64":
schema.add_field("id", DataType.INT64, is_primary=True)
else:
schema.add_field("id", DataType.VARCHAR, max_length=100, is_primary=True)
# Add multiple vector fields with maximum dimension (up to max_vector_field_num)
vector_field_names = []
for i in range(ct.max_vector_field_num):
vector_field_name = f"float_vec_{i+1}"
vector_field_names.append(vector_field_name)
schema.add_field(vector_field_name, DataType.FLOAT_VECTOR, dim=ct.max_dim)
# Create collection
self.create_collection(client, collection_name, schema=schema)
# Verify collection properties
expected_dims = [ct.max_dim] * ct.max_vector_field_num
expected_vector_names = vector_field_names
self.describe_collection(client, collection_name,
check_task=CheckTasks.check_describe_collection_property,
check_items={"collection_name": collection_name,
"enable_dynamic_field": False,
"dim": expected_dims,
"vector_name": expected_vector_names})
self.drop_collection(client, collection_name)
@pytest.mark.tags(CaseLabel.L2)
@pytest.mark.parametrize("primary_key_type", ["int64", "varchar"])
@pytest.mark.parametrize("auto_id", [True, False])
@pytest.mark.parametrize("partition_key_type", ["int64", "varchar"])
def test_milvus_client_collection_multiple_vectors_partition_key(self, primary_key_type, auto_id, partition_key_type):
"""
target: test create collection with multiple vector fields and partition key
method: create collection with multiple vector fields and partition key
expected: collection created successfully with partition key and multiple partitions
"""
client = self._client()
collection_name = cf.gen_collection_name_by_testcase_name()
# Create schema with multiple vector fields and partition key
schema = self.create_schema(client, enable_dynamic_field=False, auto_id=auto_id)[0]
# Add primary key field
if primary_key_type == "int64":
schema.add_field("id", DataType.INT64, is_primary=True, auto_id=auto_id)
else:
schema.add_field("id", DataType.VARCHAR, max_length=100, is_primary=True, auto_id=auto_id)
schema.add_field(default_vector_field_name, DataType.FLOAT_VECTOR, dim=default_dim)
schema.add_field("vector_2", DataType.FLOAT_VECTOR, dim=default_dim)
# Add scalar fields
schema.add_field("int8_field", DataType.INT8)
schema.add_field("int16_field", DataType.INT16)
schema.add_field("int32_field", DataType.INT32)
schema.add_field("float_field", DataType.FLOAT)
schema.add_field("double_field", DataType.DOUBLE)
schema.add_field("json_field", DataType.JSON)
schema.add_field("bool_field", DataType.BOOL)
schema.add_field("array_field", DataType.ARRAY, element_type=DataType.INT64, max_capacity=10)
schema.add_field("binary_vec_field", DataType.BINARY_VECTOR, dim=default_dim)
# Add partition key field
if partition_key_type == "int64":
schema.add_field("partition_key_int", DataType.INT64, is_partition_key=True)
else:
schema.add_field("partition_key_varchar", DataType.VARCHAR, max_length=100, is_partition_key=True)
# Create collection
self.create_collection(client, collection_name, schema=schema)
# Verify collection properties
self.describe_collection(client, collection_name,
check_task=CheckTasks.check_describe_collection_property,
check_items={"collection_name": collection_name,
"auto_id": auto_id,
"enable_dynamic_field": False,
"num_partitions": ct.default_partition_num})
self.drop_collection(client, collection_name)
class TestMilvusClientCollectionMultipleVectorInvalid(TestMilvusClientV2Base):
"""
******************************************************************
# Test case for collection with multiple vector fields - Invalid cases
******************************************************************
"""
@pytest.fixture(scope="function", params=ct.invalid_dims)
def get_invalid_dim(self, request):
yield request.param
@pytest.mark.tags(CaseLabel.L1)
@pytest.mark.parametrize("primary_key_type", ["int64", "varchar"])
def test_milvus_client_collection_multiple_vectors_same_vector_field_name(self, primary_key_type):
"""
target: test create collection with multiple vector fields having duplicate names
method: create collection with multiple vector fields using same field name
expected: raise exception for duplicated field name
"""
client = self._client()
collection_name = cf.gen_collection_name_by_testcase_name()
# Create schema with duplicate vector field names
schema = self.create_schema(client, enable_dynamic_field=False)[0]
# Add primary key field
if primary_key_type == "int64":
schema.add_field("id", DataType.INT64, is_primary=True)
else:
schema.add_field("id", DataType.VARCHAR, max_length=100, is_primary=True)
# Add multiple vector fields with same name
schema.add_field("vector_field", DataType.FLOAT_VECTOR, dim=default_dim)
schema.add_field("vector_field", DataType.FLOAT_VECTOR, dim=default_dim)
# Add other fields
schema.add_field("int8_field", DataType.INT8)
schema.add_field("int16_field", DataType.INT16)
schema.add_field("int32_field", DataType.INT32)
schema.add_field("float_field", DataType.FLOAT)
schema.add_field("double_field", DataType.DOUBLE)
schema.add_field("varchar_field", DataType.VARCHAR, max_length=100)
schema.add_field("json_field", DataType.JSON)
schema.add_field("bool_field", DataType.BOOL)
schema.add_field("array_field", DataType.ARRAY, element_type=DataType.INT64, max_capacity=10)
schema.add_field("binary_vec_field", DataType.BINARY_VECTOR, dim=default_dim)
# Try to create collection with duplicate field names
error = {ct.err_code: 1100, ct.err_msg: "duplicated field name"}
self.create_collection(client, collection_name, schema=schema,
check_task=CheckTasks.err_res, check_items=error)
@pytest.mark.tags(CaseLabel.L1)
@pytest.mark.parametrize("invalid_vector_name", ["12-s", "12 s", "(mn)", "中文", "%$#", "a".join("a" for i in range(256))])
def test_milvus_client_collection_multiple_vectors_invalid_all_vector_field_name(self, invalid_vector_name):
"""
target: test create collection with multiple vector fields where all have invalid names
method: create collection with multiple vector fields, all with invalid names
expected: raise exception for invalid field name
"""
client = self._client()
collection_name = cf.gen_collection_name_by_testcase_name()
# Create schema with all invalid vector field names
schema = self.create_schema(client, enable_dynamic_field=False)[0]
schema.add_field("id", DataType.INT64, is_primary=True)
# Add vector fields - all with invalid names
schema.add_field(invalid_vector_name, DataType.FLOAT_VECTOR, dim=default_dim)
schema.add_field(invalid_vector_name + " ", DataType.FLOAT_VECTOR, dim=default_dim)
# Try to create collection with invalid field names
error = {ct.err_code: 1100, ct.err_msg: f"Invalid field name: {invalid_vector_name}"}
self.create_collection(client, collection_name, schema=schema,
check_task=CheckTasks.err_res, check_items=error)
@pytest.mark.tags(CaseLabel.L1)
@pytest.mark.skip("issue #37543")
def test_milvus_client_collection_multiple_vectors_invalid_dim(self, get_invalid_dim):
"""
target: test create collection with multiple vector fields where one has invalid dimension
method: create collection with multiple vector fields, one with invalid dimension
expected: raise exception for invalid dimension
"""
client = self._client()
collection_name = cf.gen_collection_name_by_testcase_name()
# Create schema with one invalid vector dimension
schema = self.create_schema(client, enable_dynamic_field=False)[0]
schema.add_field("id", DataType.INT64, is_primary=True)
# Add vector fields - one with invalid dimension, one with valid dimension
schema.add_field("vector_field_1", DataType.FLOAT_VECTOR, dim=get_invalid_dim)
schema.add_field("vector_field_2", DataType.FLOAT_VECTOR, dim=default_dim)
# Try to create collection with invalid dimension
error = {ct.err_code: 65535, ct.err_msg: "invalid dimension"}
self.create_collection(client, collection_name, schema=schema,
check_task=CheckTasks.err_res, check_items=error)
class TestMilvusClientCollectionMmap(TestMilvusClientV2Base):
"""
******************************************************************
# Test case for collection mmap functionality
******************************************************************
"""
@pytest.mark.tags(CaseLabel.L1)
def test_milvus_client_describe_collection_mmap(self):
"""
target: enable or disable mmap in the collection
method: enable or disable mmap in the collection
expected: description information contains mmap
"""
client = self._client()
collection_name = cf.gen_collection_name_by_testcase_name()
self.create_collection(client, collection_name, default_dim)
self.release_collection(client, collection_name)
# Test enable mmap
self.alter_collection_properties(client, collection_name, properties={"mmap.enabled": True})
describe_res = self.describe_collection(client, collection_name)[0]
properties = describe_res.get("properties")
assert "mmap.enabled" in properties.keys()
assert properties["mmap.enabled"] == 'True'
# Test disable mmap
self.alter_collection_properties(client, collection_name, properties={"mmap.enabled": False})
describe_res = self.describe_collection(client, collection_name)[0]
properties = describe_res.get("properties")
assert properties["mmap.enabled"] == 'False'
# Test enable mmap again
self.alter_collection_properties(client, collection_name, properties={"mmap.enabled": True})
describe_res = self.describe_collection(client, collection_name)[0]
properties = describe_res.get("properties")
assert properties["mmap.enabled"] == 'True'
self.drop_collection(client, collection_name)
@pytest.mark.tags(CaseLabel.L1)
def test_milvus_client_load_mmap_collection(self):
"""
target: after loading, enable mmap for the collection
method: 1. data preparation and create index
2. load collection
3. enable mmap on collection
expected: raise exception
"""
client = self._client()
collection_name = cf.gen_collection_name_by_testcase_name()
# Create collection with data and index
self.create_collection(client, collection_name, default_dim)
self.release_collection(client, collection_name)
self.drop_index(client, collection_name, "vector")
# Get collection schema to generate compatible data
collection_info = self.describe_collection(client, collection_name)[0]
data = cf.gen_row_data_by_schema(nb=ct.default_nb, schema=collection_info)
self.insert(client, collection_name, data)
self.flush(client, collection_name)
index_params = self.prepare_index_params(client)[0]
index_params.add_index(field_name="vector", index_type="HNSW", metric_type="L2")
self.create_index(client, collection_name, index_params)
self.release_collection(client, collection_name)
# Set mmap enabled before loading
self.alter_collection_properties(client, collection_name, properties={"mmap.enabled": True})
describe_res = self.describe_collection(client, collection_name)[0]
properties = describe_res.get("properties")
assert properties["mmap.enabled"] == 'True'
# Load collection
self.load_collection(client, collection_name)
# Try to alter mmap after loading - should raise exception
error = {ct.err_code: 999, ct.err_msg: "can not alter mmap properties if collection loaded"}
self.alter_collection_properties(client, collection_name, properties={"mmap.enabled": True},
check_task=CheckTasks.err_res, check_items=error)
self.drop_collection(client, collection_name)
@pytest.mark.tags(CaseLabel.L2)
def test_milvus_client_drop_mmap_collection(self):
"""
target: set mmap on collection and then drop it
method: 1. set mmap on collection
2. drop collection
3. recreate collection with same name
expected: new collection doesn't inherit mmap settings
"""
client = self._client()
collection_name = "coll_mmap_test"
# Create collection and set mmap
self.create_collection(client, collection_name, default_dim)
self.release_collection(client, collection_name)
self.alter_collection_properties(client, collection_name, properties={"mmap.enabled": True})
describe_res = self.describe_collection(client, collection_name)[0]
properties = describe_res.get("properties")
assert properties["mmap.enabled"] == 'True'
# Drop collection
self.drop_collection(client, collection_name)
# Recreate collection with same name
self.create_collection(client, collection_name, default_dim)
describe_res = self.describe_collection(client, collection_name)[0]
properties = describe_res.get("properties")
assert "mmap.enabled" not in properties.keys()
self.drop_collection(client, collection_name)
@pytest.mark.tags(CaseLabel.L2)
def test_milvus_client_multiple_collections_enable_mmap(self):
"""
target: enabling mmap for multiple collections in a single instance
method: enabling mmap for multiple collections in a single instance
expected: the collection description message for mmap is normal
"""
client = self._client()
collection_name_1 = cf.gen_collection_name_by_testcase_name() + "_1"
collection_name_2 = cf.gen_collection_name_by_testcase_name() + "_2"
collection_name_3 = cf.gen_collection_name_by_testcase_name() + "_3"
# Create multiple collections
self.create_collection(client, collection_name_1, default_dim)
self.create_collection(client, collection_name_2, default_dim)
self.create_collection(client, collection_name_3, default_dim)
# Release collections before setting mmap
self.release_collection(client, collection_name_1)
self.release_collection(client, collection_name_2)
self.release_collection(client, collection_name_3)
# Enable mmap for first two collections
self.alter_collection_properties(client, collection_name_1, properties={"mmap.enabled": True})
self.alter_collection_properties(client, collection_name_2, properties={"mmap.enabled": True})
# Verify mmap settings
describe_res_1 = self.describe_collection(client, collection_name_1)[0]
describe_res_2 = self.describe_collection(client, collection_name_2)[0]
properties_1 = describe_res_1.get("properties")
properties_2 = describe_res_2.get("properties")
assert properties_1["mmap.enabled"] == 'True'
assert properties_2["mmap.enabled"] == 'True'
# Enable mmap for third collection
self.alter_collection_properties(client, collection_name_3, properties={"mmap.enabled": True})
describe_res_3 = self.describe_collection(client, collection_name_3)[0]
properties_3 = describe_res_3.get("properties")
assert properties_3["mmap.enabled"] == 'True'
# Clean up
self.drop_collection(client, collection_name_1)
self.drop_collection(client, collection_name_2)
self.drop_collection(client, collection_name_3)
@pytest.mark.tags(CaseLabel.L2)
def test_milvus_client_flush_collection_mmap(self):
"""
target: after flush, collection enables mmap
method: after flush, collection enables mmap
expected: the collection description message for mmap is normal
"""
client = self._client()
collection_name = cf.gen_collection_name_by_testcase_name()
# Create collection and insert data
self.create_collection(client, collection_name, default_dim)
# Get collection schema to generate compatible data
collection_info = self.describe_collection(client, collection_name)[0]
data = cf.gen_row_data_by_schema(nb=ct.default_nb, schema=collection_info)
self.insert(client, collection_name, data)
# Create index
self.release_collection(client, collection_name)
self.drop_index(client, collection_name, "vector")
index_params = self.prepare_index_params(client)[0]
index_params.add_index(field_name="vector", index_type="FLAT", metric_type="L2")
self.create_index(client, collection_name, index_params)
# Set index mmap to False
self.alter_index_properties(client, collection_name, "vector", properties={"mmap.enabled": False})
# Flush data
self.flush(client, collection_name)
# Set collection mmap to True
self.alter_collection_properties(client, collection_name, properties={"mmap.enabled": True})
describe_res = self.describe_collection(client, collection_name)[0]
properties = describe_res.get("properties")
assert properties["mmap.enabled"] == 'True'
# Set index mmap to True
self.alter_index_properties(client, collection_name, "vector", properties={"mmap.enabled": True})
# Load collection and perform search to verify functionality
self.load_collection(client, collection_name)
# Generate search vectors
search_data = cf.gen_vectors(default_nq, default_dim)
self.search(client, collection_name, search_data,
check_task=CheckTasks.check_search_results,
check_items={"nq": default_nq, "limit": default_limit})
self.drop_collection(client, collection_name)
@pytest.mark.tags(CaseLabel.L2)
def test_milvus_client_enable_mmap_after_drop_collection(self):
"""
target: enable mmap after deleting a collection
method: enable mmap after deleting a collection
expected: raise exception
"""
client = self._client()
collection_name = cf.gen_collection_name_by_testcase_name()
# Create and drop collection
self.create_collection(client, collection_name, default_dim)
self.drop_collection(client, collection_name)
# Try to enable mmap on dropped collection - should raise exception
error = {ct.err_code: 100, ct.err_msg: "collection not found"}
self.alter_collection_properties(client, collection_name, properties={"mmap.enabled": True},
check_task=CheckTasks.err_res, check_items=error)

View File

@ -6,6 +6,8 @@ from common import common_func as cf
from common import common_type as ct from common import common_type as ct
from common.common_type import CaseLabel, CheckTasks from common.common_type import CaseLabel, CheckTasks
from utils.util_pymilvus import * from utils.util_pymilvus import *
from pymilvus.client.types import LoadState
prefix = "milvus_client_api_partition" prefix = "milvus_client_api_partition"
partition_prefix = "milvus_client_api_partition" partition_prefix = "milvus_client_api_partition"
@ -560,6 +562,52 @@ class TestMilvusClientReleasePartitionInvalid(TestMilvusClientV2Base):
self.release_partitions(client, collection_name, partition_name, self.release_partitions(client, collection_name, partition_name,
check_task=CheckTasks.err_res, check_items=error) check_task=CheckTasks.err_res, check_items=error)
@pytest.mark.tags(CaseLabel.L2)
def test_milvus_client_release_partition_after_disconnect(self):
"""
target: test release partition without connection
method: release partition with correct params, with a disconnected instance
expected: release raise exception
"""
client_temp = self._client(alias="client_release_partition")
collection_name = cf.gen_collection_name_by_testcase_name()
partition_name = cf.gen_unique_str("partition")
# Create collection and partition
self.create_collection(client_temp, collection_name, default_dim)
self.create_partition(client_temp, collection_name, partition_name)
# Load partition first
self.load_partitions(client_temp, collection_name, [partition_name])
# Close the client connection
self.close(client_temp)
# Try to release partition after disconnect - should raise exception
error = {ct.err_code: 1, ct.err_msg: 'should create connection first'}
self.release_partitions(client_temp, collection_name, partition_name,
check_task=CheckTasks.err_res, check_items=error)
@pytest.mark.tags(CaseLabel.L0)
def test_milvus_client_load_release_partition_after_collection_drop(self):
"""
target: test load and release partition after collection drop
method: load and release the partition after the collection has been dropped
expected: raise exception
"""
client = self._client()
collection_name = cf.gen_collection_name_by_testcase_name()
partition_name = cf.gen_unique_str(partition_prefix)
description = cf.gen_unique_str("desc_")
# 1. Create collection and partition
self.create_collection(client, collection_name, default_dim)
self.create_partition(client, collection_name, partition_name, description=description)
# 2. Drop the collection
self.drop_collection(client, collection_name)
# 3. Try to load partition after collection drop - should raise exception
error = {ct.err_code: 100, ct.err_msg: "collection not found"}
self.load_partitions(client, collection_name, partition_name,
check_task=CheckTasks.err_res, check_items=error)
# 4. Try to release partition after collection drop - should raise exception
self.release_partitions(client, collection_name, partition_name,
check_task=CheckTasks.err_res, check_items=error)
class TestMilvusClientReleasePartitionValid(TestMilvusClientV2Base): class TestMilvusClientReleasePartitionValid(TestMilvusClientV2Base):
""" Test case of search interface """ """ Test case of search interface """
@ -600,9 +648,9 @@ class TestMilvusClientReleasePartitionValid(TestMilvusClientV2Base):
@pytest.mark.tags(CaseLabel.L2) @pytest.mark.tags(CaseLabel.L2)
def test_milvus_client_partition_release_unloaded_partition(self): def test_milvus_client_partition_release_unloaded_partition(self):
""" """
target: test fast create collection normal case target: test releasing a partition that has not been loaded
method: create collection method: create a collection and a partition, do not load the partition, then release the partition twice
expected: create collection with default schema, index, and load successfully expected: releasing an unloaded partition should succeed and be idempotent
""" """
client = self._client() client = self._client()
collection_name = cf.gen_unique_str(prefix) collection_name = cf.gen_unique_str(prefix)
@ -618,9 +666,11 @@ class TestMilvusClientReleasePartitionValid(TestMilvusClientV2Base):
@pytest.mark.tags(CaseLabel.L2) @pytest.mark.tags(CaseLabel.L2)
def test_milvus_client_partition_release_unloaded_collection(self): def test_milvus_client_partition_release_unloaded_collection(self):
""" """
target: test fast create collection normal case target: Test releasing partitions after the collection has been released (unloaded)
method: create collection method: 1. Create a collection and a partition
expected: create collection with default schema, index, and load successfully 2. Release the entire collection (unload)
3. Attempt to release the partition after the collection is unloaded
expected: Releasing a partition after the collection is unloaded should succeed and be idempotent
""" """
client = self._client() client = self._client()
collection_name = cf.gen_unique_str(prefix) collection_name = cf.gen_unique_str(prefix)
@ -942,9 +992,9 @@ class TestMilvusClientLoadPartitionInvalid(TestMilvusClientV2Base):
@pytest.mark.tags(CaseLabel.L2) @pytest.mark.tags(CaseLabel.L2)
def test_milvus_client_load_partitions_partition_not_existed(self): def test_milvus_client_load_partitions_partition_not_existed(self):
""" """
target: test fast create collection normal case target: test loading a non-existent partition
method: create collection method: create a collection, then attempt to load a partition that does not exist
expected: drop successfully expected: returns an error indicating the partition is not found
""" """
client = self._client() client = self._client()
collection_name = cf.gen_unique_str(prefix) collection_name = cf.gen_unique_str(prefix)
@ -996,15 +1046,58 @@ class TestMilvusClientLoadPartitionInvalid(TestMilvusClientV2Base):
self.load_partitions(client, collection_name, partition_name, self.load_partitions(client, collection_name, partition_name,
check_task=CheckTasks.err_res, check_items=error) check_task=CheckTasks.err_res, check_items=error)
@pytest.mark.tags(CaseLabel.L2)
def test_milvus_client_load_partition_after_disconnect(self):
"""
target: test load partition without connection
method: load partition with correct params, with a disconnected instance
expected: load raises exception
"""
client_temp = self._client(alias="client_load_partition")
collection_name = cf.gen_collection_name_by_testcase_name()
partition_name = cf.gen_unique_str("partition")
# Create collection and partition
self.create_collection(client_temp, collection_name, default_dim)
self.create_partition(client_temp, collection_name, partition_name)
# Load partition first
self.load_partitions(client_temp, collection_name, [partition_name])
# Close the client connection
self.close(client_temp)
# Try to release partition after disconnect - should raise exception
error = {ct.err_code: 1, ct.err_msg: 'should create connection first'}
self.load_partitions(client_temp, collection_name, partition_name,
check_task=CheckTasks.err_res, check_items=error)
class TestMilvusClientLoadPartitionInvalid(TestMilvusClientV2Base): @pytest.mark.tags(CaseLabel.L2)
""" Test case of search interface """ def test_milvus_client_load_release_partition_after_drop(self):
"""
target: test load and release partition after drop
method: drop partition and then load and release it
expected: raise exception
"""
client = self._client()
collection_name = cf.gen_collection_name_by_testcase_name()
partition_name = cf.gen_unique_str(partition_prefix)
description = cf.gen_unique_str("desc_")
# 1. Create collection and partition
self.create_collection(client, collection_name, default_dim)
self.create_partition(client, collection_name, partition_name, description=description)
# 2. Drop the partition
self.load_collection(client, collection_name)
self.release_partitions(client, collection_name, partition_name)
self.drop_partition(client, collection_name, partition_name)
# 3. Try to load partition after drop - should raise exception
error = {ct.err_code: 200, ct.err_msg: f'partition not found[partition={partition_name}]'}
self.load_partitions(client, collection_name, partition_name,
check_task=CheckTasks.err_res, check_items=error)
# 4. Try to release partition after drop - should also raise exception
self.release_partitions(client, collection_name, partition_name,
check_task=CheckTasks.err_res, check_items=error)
self.drop_collection(client, collection_name)
"""
****************************************************************** class TestMilvusClientLoadPartitionValid(TestMilvusClientV2Base):
# The following are invalid base cases """ Test case of load partition valid cases """
******************************************************************
"""
@pytest.mark.tags(CaseLabel.L1) @pytest.mark.tags(CaseLabel.L1)
def test_milvus_client_load_multiple_partition(self): def test_milvus_client_load_multiple_partition(self):
@ -1061,3 +1154,55 @@ class TestMilvusClientLoadPartitionInvalid(TestMilvusClientV2Base):
self.load_partitions(client, collection_name, partition_name) self.load_partitions(client, collection_name, partition_name)
self.load_collection(client, collection_name) self.load_collection(client, collection_name)
self.load_partitions(client, collection_name, partition_name) self.load_partitions(client, collection_name, partition_name)
@pytest.mark.tags(CaseLabel.L0)
@pytest.mark.parametrize('binary_index_type', ct.binary_supported_index_types)
@pytest.mark.parametrize('metric_type', ct.binary_metrics)
def test_milvus_client_load_partition_after_index_binary(self, binary_index_type, metric_type):
"""
target: test load binary collection partition after index created
method: insert and create index, load binary collection partition with correct params
expected: no error raised
"""
client = self._client()
collection_name = cf.gen_collection_name_by_testcase_name()
partition_name = cf.gen_unique_str(partition_prefix)
# 1. Create collection with binary vector
schema = self.create_schema(client, enable_dynamic_field=False)[0]
schema.add_field(ct.default_int64_field_name, DataType.INT64, is_primary=True, auto_id=False)
schema.add_field(ct.default_float_field_name, DataType.FLOAT)
schema.add_field(ct.default_binary_vec_field_name, DataType.BINARY_VECTOR, dim=default_dim)
self.create_collection(client, collection_name, schema=schema)
# 2. Create partition
self.create_partition(client, collection_name, partition_name)
# 3. Insert some data
schema_info = self.describe_collection(client, collection_name)[0]
data = cf.gen_row_data_by_schema(nb=default_nb, schema=schema_info)
self.insert(client, collection_name, data, partition_name=partition_name)
self.flush(client, collection_name)
# 4. Create binary index
index_params = self.prepare_index_params(client)[0]
binary_index = {"index_type": binary_index_type, "metric_type": metric_type, "params": {"nlist": 128}}
# Handle special case for BIN_IVF_FLAT with structure metrics
if binary_index_type == "BIN_IVF_FLAT" and metric_type in ct.structure_metrics:
# This combination should raise an error, so create with default instead
error = {ct.err_code: 65535,
ct.err_msg: f"metric type {metric_type} not found or not supported, supported: [HAMMING JACCARD]"}
index_params.add_index(field_name=ct.default_binary_vec_field_name,
index_type=binary_index_type, metric_type=metric_type, params={"nlist": 128})
self.create_index(client, collection_name, index_params,
check_task=CheckTasks.err_res, check_items=error)
# Create with default binary index instead
index_params = self.prepare_index_params(client)[0]
index_params.add_index(field_name=ct.default_binary_vec_field_name, **ct.default_bin_flat_index)
self.create_index(client, collection_name, index_params)
else:
index_params.add_index(field_name=ct.default_binary_vec_field_name, **binary_index)
self.create_index(client, collection_name, index_params)
# 5. Load the partition
self.release_collection(client, collection_name)
self.load_partitions(client, collection_name, [partition_name])
# 6. Verify partition is loaded by checking load state
load_state = self.get_load_state(client, collection_name)[0]
assert load_state["state"] == LoadState.Loaded
self.drop_collection(client, collection_name)

File diff suppressed because it is too large Load Diff