mirror of
https://gitee.com/milvus-io/milvus.git
synced 2025-12-07 17:48:29 +08:00
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:
parent
7963b17ac1
commit
eec58c3bb5
@ -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)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@ -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
Loading…
x
Reference in New Issue
Block a user