mirror of
https://gitee.com/milvus-io/milvus.git
synced 2024-12-05 05:18:52 +08:00
7ac339ac64
Related issue: #32653 Signed-off-by: yanliang567 <yanliang.qiao@zilliz.com>
4520 lines
211 KiB
Python
4520 lines
211 KiB
Python
import random
|
|
|
|
import numpy
|
|
import pandas as pd
|
|
import pytest
|
|
|
|
from pymilvus import DataType
|
|
from base.client_base import TestcaseBase
|
|
from common import common_func as cf
|
|
from common import common_type as ct
|
|
from common.common_type import CaseLabel, CheckTasks
|
|
from utils.util_pymilvus import *
|
|
from utils.util_log import test_log as log
|
|
|
|
prefix = "collection"
|
|
exp_name = "name"
|
|
exp_schema = "schema"
|
|
exp_num = "num_entities"
|
|
exp_primary = "primary"
|
|
exp_shards_num = "shards_num"
|
|
default_term_expr = f'{ct.default_int64_field_name} in [0, 1]'
|
|
default_schema = cf.gen_default_collection_schema()
|
|
default_binary_schema = cf.gen_default_binary_collection_schema()
|
|
default_shards_num = 1
|
|
uid_count = "collection_count"
|
|
tag = "collection_count_tag"
|
|
uid_stats = "get_collection_stats"
|
|
uid_create = "create_collection"
|
|
uid_describe = "describe_collection"
|
|
uid_drop = "drop_collection"
|
|
uid_has = "has_collection"
|
|
uid_list = "list_collections"
|
|
uid_load = "load_collection"
|
|
partition1 = 'partition1'
|
|
partition2 = 'partition2'
|
|
field_name = default_float_vec_field_name
|
|
default_single_query = {
|
|
"data": gen_vectors(1, default_dim),
|
|
"anns_field": default_float_vec_field_name,
|
|
"param": {"metric_type": "L2", "params": {"nprobe": 10}},
|
|
"limit": default_top_k,
|
|
}
|
|
|
|
default_index_params = {"index_type": "IVF_SQ8", "metric_type": "L2", "params": {"nlist": 64}}
|
|
default_binary_index_params = {"index_type": "BIN_IVF_FLAT", "metric_type": "JACCARD", "params": {"nlist": 64}}
|
|
default_nq = ct.default_nq
|
|
default_search_exp = "int64 >= 0"
|
|
default_limit = ct.default_limit
|
|
vectors = [[random.random() for _ in range(default_dim)] for _ in range(default_nq)]
|
|
default_search_field = ct.default_float_vec_field_name
|
|
default_search_params = ct.default_search_params
|
|
max_vector_field_num = ct.max_vector_field_num
|
|
SPARSE_FLOAT_VECTOR_data_type = "SPARSE_FLOAT_VECTOR"
|
|
|
|
|
|
class TestCollectionParams(TestcaseBase):
|
|
""" Test case of collection interface """
|
|
|
|
@pytest.fixture(scope="function", params=cf.gen_all_type_fields())
|
|
def get_unsupported_primary_field(self, request):
|
|
if request.param.dtype == DataType.INT64 or request.param.dtype == DataType.VARCHAR:
|
|
pytest.skip("int64 type is valid primary key")
|
|
yield request.param
|
|
|
|
@pytest.fixture(scope="function", params=ct.invalid_dims)
|
|
def get_invalid_dim(self, request):
|
|
yield request.param
|
|
|
|
@pytest.mark.tags(CaseLabel.L0)
|
|
def test_collection(self):
|
|
"""
|
|
target: test collection with default schema
|
|
method: create collection with default schema
|
|
expected: assert collection property
|
|
"""
|
|
self._connect()
|
|
c_name = cf.gen_unique_str(prefix)
|
|
self.collection_wrap.init_collection(c_name, schema=default_schema,
|
|
check_task=CheckTasks.check_collection_property,
|
|
check_items={exp_name: c_name, exp_schema: default_schema, exp_num: 0,
|
|
exp_primary: ct.default_int64_field_name})
|
|
assert c_name in self.utility_wrap.list_collections()[0]
|
|
|
|
@pytest.mark.tags(CaseLabel.L2)
|
|
@pytest.mark.parametrize("name", ct.valid_resource_names)
|
|
def test_collection_naming_rules(self, name):
|
|
"""
|
|
target: test collection with valid name
|
|
method: 1. connect milvus
|
|
2. Create a field with a name which uses all the supported elements in the naming rules
|
|
3. Create a collection with a name which uses all the supported elements in the naming rules
|
|
expected: Collection created successfully
|
|
"""
|
|
self._connect()
|
|
fields = [cf.gen_int64_field(), cf.gen_int64_field("_1nt"), cf.gen_float_vec_field("f10at_")]
|
|
schema = cf.gen_collection_schema(fields=fields, primary_field=ct.default_int64_field_name)
|
|
self.collection_wrap.init_collection(name, schema=schema,
|
|
check_task=CheckTasks.check_collection_property,
|
|
check_items={exp_name: name, exp_schema: schema})
|
|
|
|
@pytest.mark.tags(CaseLabel.L2)
|
|
@pytest.mark.parametrize("name", ct.invalid_resource_names)
|
|
def test_collection_invalid_name(self, name):
|
|
"""
|
|
target: test collection with invalid name
|
|
method: create collection with invalid name
|
|
expected: raise exception
|
|
"""
|
|
self._connect()
|
|
error = {ct.err_code: 999, ct.err_msg: f"Invalid collection name: {name}"}
|
|
if name in [None, ""]:
|
|
error = {ct.err_code: 999, ct.err_msg: f"`collection_name` value {name} is illegal"}
|
|
if name in [" "]:
|
|
error = {ct.err_code: 999, ct.err_msg: f"collection name should not be empty"}
|
|
self.collection_wrap.init_collection(name, schema=default_schema, check_task=CheckTasks.err_res,
|
|
check_items=error)
|
|
|
|
@pytest.mark.tags(CaseLabel.L0)
|
|
def test_collection_dup_name(self):
|
|
"""
|
|
target: test collection with dup name
|
|
method: create collection with dup name and none schema and data
|
|
expected: collection properties consistent
|
|
"""
|
|
self._connect()
|
|
c_name = cf.gen_unique_str(prefix)
|
|
collection_w = self.init_collection_wrap(name=c_name, check_task=CheckTasks.check_collection_property,
|
|
check_items={exp_name: c_name, exp_schema: default_schema})
|
|
self.collection_wrap.init_collection(collection_w.name)
|
|
assert collection_w.name == self.collection_wrap.name
|
|
assert collection_w.schema == self.collection_wrap.schema
|
|
assert collection_w.num_entities == self.collection_wrap.num_entities
|
|
assert collection_w.name in self.utility_wrap.list_collections()[0]
|
|
|
|
@pytest.mark.tags(CaseLabel.L2)
|
|
def test_collection_dup_name_with_desc(self):
|
|
"""
|
|
target: test collection with dup name
|
|
method: 1. default schema with desc 2. dup name collection
|
|
expected: desc consistent
|
|
"""
|
|
self._connect()
|
|
c_name = cf.gen_unique_str(prefix)
|
|
schema = cf.gen_default_collection_schema(description=ct.collection_desc)
|
|
collection_w = self.init_collection_wrap(name=c_name, schema=schema,
|
|
check_task=CheckTasks.check_collection_property,
|
|
check_items={exp_name: c_name, exp_schema: schema})
|
|
self.collection_wrap.init_collection(c_name,
|
|
check_task=CheckTasks.check_collection_property,
|
|
check_items={exp_name: c_name, exp_schema: schema})
|
|
assert collection_w.description == self.collection_wrap.description
|
|
|
|
@pytest.mark.tags(CaseLabel.L1)
|
|
def test_collection_dup_name_new_schema(self):
|
|
"""
|
|
target: test collection with dup name and new schema
|
|
method: 1.create collection with default schema
|
|
2. collection with dup name and new schema
|
|
expected: raise exception
|
|
"""
|
|
self._connect()
|
|
c_name = cf.gen_unique_str(prefix)
|
|
self.init_collection_wrap(name=c_name, check_task=CheckTasks.check_collection_property,
|
|
check_items={exp_name: c_name, exp_schema: default_schema})
|
|
fields = [cf.gen_int64_field(is_primary=True)]
|
|
schema = cf.gen_collection_schema(fields=fields)
|
|
error = {ct.err_code: 999, ct.err_msg: "The collection already exist, but the schema is not the same as the "
|
|
"schema passed in."}
|
|
self.collection_wrap.init_collection(c_name, schema=schema, check_task=CheckTasks.err_res, check_items=error)
|
|
|
|
@pytest.mark.tags(CaseLabel.L2)
|
|
def test_collection_dup_name_new_primary(self):
|
|
"""
|
|
target: test collection with dup name and new primary_field schema
|
|
method: 1.collection with default schema
|
|
2. collection with same fields and new primary_field schema
|
|
expected: raise exception
|
|
"""
|
|
self._connect()
|
|
c_name = cf.gen_unique_str(prefix)
|
|
int_field_one = cf.gen_int64_field()
|
|
int_field_two = cf.gen_int64_field(name="int2")
|
|
fields = [int_field_one, int_field_two, cf.gen_float_vec_field()]
|
|
schema = cf.gen_collection_schema(fields, primary_field=int_field_one.name)
|
|
collection_w = self.init_collection_wrap(name=c_name, schema=schema,
|
|
check_task=CheckTasks.check_collection_property,
|
|
check_items={exp_name: c_name, exp_schema: schema,
|
|
exp_primary: int_field_one.name})
|
|
new_schema = cf.gen_collection_schema(fields, primary_field=int_field_two.name)
|
|
error = {ct.err_code: 0, ct.err_msg: "The collection already exist, but the schema is not the same as the "
|
|
"schema passed in."}
|
|
self.collection_wrap.init_collection(c_name, schema=new_schema, check_task=CheckTasks.err_res,
|
|
check_items=error)
|
|
assert collection_w.primary_field.name == int_field_one.name
|
|
|
|
@pytest.mark.tags(CaseLabel.L1)
|
|
def test_collection_dup_name_new_dim(self):
|
|
"""
|
|
target: test collection with dup name and new dim schema
|
|
method: 1. default schema 2. schema with new dim
|
|
expected: raise exception
|
|
"""
|
|
self._connect()
|
|
new_dim = 120
|
|
c_name = cf.gen_unique_str(prefix)
|
|
collection_w = self.init_collection_wrap(name=c_name, check_task=CheckTasks.check_collection_property,
|
|
check_items={exp_name: c_name, exp_schema: default_schema})
|
|
schema = cf.gen_default_collection_schema()
|
|
new_fields = cf.gen_float_vec_field(dim=new_dim)
|
|
schema.fields[-1] = new_fields
|
|
error = {ct.err_code: 0, ct.err_msg: "The collection already exist, but the schema is not the same as the "
|
|
"schema passed in."}
|
|
self.collection_wrap.init_collection(c_name, schema=schema, check_task=CheckTasks.err_res, check_items=error)
|
|
dim = collection_w.schema.fields[-1].params['dim']
|
|
assert dim == ct.default_dim
|
|
|
|
@pytest.mark.tags(CaseLabel.L2)
|
|
def test_collection_invalid_schema_multi_pk(self):
|
|
"""
|
|
target: test collection with a schema with 2 pk fields
|
|
method: create collection with non-CollectionSchema type schema
|
|
expected: raise exception
|
|
"""
|
|
self._connect()
|
|
c_name = cf.gen_unique_str(prefix)
|
|
field1, _ = self.field_schema_wrap.init_field_schema(name="field1", dtype=DataType.INT64, is_primary=True)
|
|
field2, _ = self.field_schema_wrap.init_field_schema(name="field2", dtype=DataType.INT64, is_primary=True)
|
|
vector_field = cf.gen_float_vec_field(dim=32)
|
|
error = {ct.err_code: 999, ct.err_msg: "Expected only one primary key field"}
|
|
self.collection_schema_wrap.init_collection_schema(fields=[field1, field2, vector_field],
|
|
check_task=CheckTasks.err_res, check_items=error)
|
|
|
|
@pytest.mark.tags(CaseLabel.L2)
|
|
def test_collection_invalid_schema_type(self):
|
|
"""
|
|
target: test collection with an invalid schema type
|
|
method: create collection with non-CollectionSchema type schema
|
|
expected: raise exception
|
|
"""
|
|
self._connect()
|
|
c_name = cf.gen_unique_str(prefix)
|
|
field, _ = self.field_schema_wrap.init_field_schema(name="field_name", dtype=DataType.INT64, is_primary=True)
|
|
error = {ct.err_code: 0, ct.err_msg: "Schema type must be schema.CollectionSchema"}
|
|
self.collection_wrap.init_collection(c_name, schema=field,
|
|
check_task=CheckTasks.err_res, check_items=error)
|
|
|
|
@pytest.mark.tags(CaseLabel.L1)
|
|
def test_collection_dup_name_same_schema(self):
|
|
"""
|
|
target: test collection with dup name and same schema
|
|
method: dup name and same schema
|
|
expected: two collection object is available
|
|
"""
|
|
self._connect()
|
|
c_name = cf.gen_unique_str(prefix)
|
|
collection_w = self.init_collection_wrap(name=c_name, schema=default_schema,
|
|
check_task=CheckTasks.check_collection_property,
|
|
check_items={exp_name: c_name, exp_schema: default_schema})
|
|
self.collection_wrap.init_collection(name=c_name, schema=default_schema,
|
|
check_task=CheckTasks.check_collection_property,
|
|
check_items={exp_name: c_name, exp_schema: default_schema})
|
|
assert collection_w.name == self.collection_wrap.name
|
|
|
|
@pytest.mark.tags(CaseLabel.L2)
|
|
def test_collection_none_schema(self):
|
|
"""
|
|
target: test collection with none schema
|
|
method: create collection with none schema
|
|
expected: raise exception
|
|
"""
|
|
self._connect()
|
|
c_name = cf.gen_unique_str(prefix)
|
|
error = {ct.err_code: 1, ct.err_msg: "Collection '%s' not exist, or you can pass in schema to create one."}
|
|
self.collection_wrap.init_collection(c_name, schema=None, check_task=CheckTasks.err_res, check_items=error)
|
|
|
|
@pytest.mark.tags(CaseLabel.L2)
|
|
@pytest.mark.parametrize("invalid_field_name", ct.invalid_resource_names)
|
|
def test_collection_invalid_field_name(self, invalid_field_name):
|
|
"""
|
|
target: test collection with invalid field name
|
|
method: invalid string name
|
|
expected: raise exception
|
|
"""
|
|
self._connect()
|
|
c_name = cf.gen_unique_str(prefix)
|
|
field, _ = self.field_schema_wrap.init_field_schema(name=invalid_field_name, dtype=DataType.INT64, is_primary=True)
|
|
vec_field = cf.gen_float_vec_field()
|
|
schema = cf.gen_collection_schema(fields=[field, vec_field])
|
|
error = {ct.err_code: 999, ct.err_msg: f"field name invalid"}
|
|
self.collection_wrap.init_collection(c_name, schema=schema, check_task=CheckTasks.err_res, check_items=error)
|
|
|
|
@pytest.mark.tags(CaseLabel.L2)
|
|
@pytest.mark.parametrize("dtype", [6, [[]], "int64", 5.1, (), "", "a", DataType.UNKNOWN])
|
|
def test_collection_invalid_field_type(self, dtype):
|
|
"""
|
|
target: test collection with invalid field type
|
|
method: invalid DataType
|
|
expected: raise exception
|
|
"""
|
|
self._connect()
|
|
error = {ct.err_code: 999, ct.err_msg: "Field dtype must be of DataType"}
|
|
self.field_schema_wrap.init_field_schema(name="test", dtype=dtype, is_primary=True,
|
|
check_task=CheckTasks.err_res, check_items=error)
|
|
|
|
@pytest.mark.tags(CaseLabel.L2)
|
|
def test_collection_empty_fields(self):
|
|
"""
|
|
target: test collection with empty fields
|
|
method: create collection with fields = []
|
|
expected: exception
|
|
"""
|
|
self._connect()
|
|
error = {ct.err_code: 999, ct.err_msg: "Schema must have a primary key field."}
|
|
self.collection_schema_wrap.init_collection_schema(fields=[], primary_field=ct.default_int64_field_name,
|
|
check_task=CheckTasks.err_res, check_items=error)
|
|
|
|
@pytest.mark.tags(CaseLabel.L1)
|
|
def test_collection_dup_field(self):
|
|
"""
|
|
target: test collection with dup field name
|
|
method: Two FieldSchema have same name
|
|
expected: raise exception
|
|
"""
|
|
self._connect()
|
|
c_name = cf.gen_unique_str(prefix)
|
|
field_one = cf.gen_int64_field(is_primary=True)
|
|
field_two = cf.gen_int64_field()
|
|
schema = cf.gen_collection_schema(fields=[field_one, field_two, cf.gen_float_vec_field()])
|
|
error = {ct.err_code: 1, ct.err_msg: "duplicated field name"}
|
|
self.collection_wrap.init_collection(c_name, schema=schema, check_task=CheckTasks.err_res, check_items=error)
|
|
assert not self.utility_wrap.has_collection(c_name)[0]
|
|
|
|
@pytest.mark.tags(CaseLabel.L0)
|
|
@pytest.mark.parametrize("field", [cf.gen_float_vec_field(), cf.gen_binary_vec_field()])
|
|
def test_collection_only_vector_field(self, field):
|
|
"""
|
|
target: test collection just with vec field
|
|
method: create with float-vec fields
|
|
expected: raise exception
|
|
"""
|
|
self._connect()
|
|
error = {ct.err_code: 1, ct.err_msg: "Schema must have a primary key field."}
|
|
self.collection_schema_wrap.init_collection_schema([field], check_task=CheckTasks.err_res, check_items=error)
|
|
|
|
@pytest.mark.tags(CaseLabel.L2)
|
|
def test_collection_multi_float_vectors(self):
|
|
"""
|
|
target: test collection with multi float vectors
|
|
method: create collection with two float-vec fields
|
|
expected: Collection created successfully
|
|
"""
|
|
# 1. connect
|
|
self._connect()
|
|
# 2. create collection with multiple vectors
|
|
c_name = cf.gen_unique_str(prefix)
|
|
fields = [cf.gen_int64_field(is_primary=True), cf.gen_float_field(),
|
|
cf.gen_float_vec_field(dim=default_dim), cf.gen_float_vec_field(name="tmp", dim=default_dim)]
|
|
schema = cf.gen_collection_schema(fields=fields)
|
|
self.collection_wrap.init_collection(c_name, schema=schema,
|
|
check_task=CheckTasks.check_collection_property,
|
|
check_items={exp_name: c_name, exp_schema: schema})
|
|
|
|
@pytest.mark.tags(CaseLabel.L1)
|
|
def test_collection_mix_vectors(self):
|
|
"""
|
|
target: test collection with mix vectors
|
|
method: create with float and binary vec
|
|
expected: Collection created successfully
|
|
"""
|
|
self._connect()
|
|
c_name = cf.gen_unique_str(prefix)
|
|
fields = [cf.gen_int64_field(is_primary=True), cf.gen_float_vec_field(), cf.gen_binary_vec_field()]
|
|
schema = cf.gen_collection_schema(fields=fields, auto_id=True)
|
|
self.collection_wrap.init_collection(c_name, schema=schema,
|
|
check_task=CheckTasks.check_collection_property,
|
|
check_items={exp_name: c_name, exp_schema: schema})
|
|
|
|
@pytest.mark.tags(CaseLabel.L0)
|
|
def test_collection_without_vectors(self):
|
|
"""
|
|
target: test collection without vectors
|
|
method: create collection only with int field
|
|
expected: raise exception
|
|
"""
|
|
self._connect()
|
|
c_name = cf.gen_unique_str(prefix)
|
|
schema = cf.gen_collection_schema([cf.gen_int64_field(is_primary=True)])
|
|
error = {ct.err_code: 999, ct.err_msg: "No vector field is found."}
|
|
self.collection_wrap.init_collection(c_name, schema=schema, check_task=CheckTasks.err_res, check_items=error)
|
|
|
|
@pytest.mark.tags(CaseLabel.L1)
|
|
def test_collection_without_primary_field(self):
|
|
"""
|
|
target: test collection without primary field
|
|
method: no primary field specified in collection schema and fields
|
|
expected: raise exception
|
|
"""
|
|
self._connect()
|
|
int_fields, _ = self.field_schema_wrap.init_field_schema(name=ct.default_int64_field_name, dtype=DataType.INT64)
|
|
vec_fields, _ = self.field_schema_wrap.init_field_schema(name=ct.default_float_vec_field_name,
|
|
dtype=DataType.FLOAT_VECTOR, dim=ct.default_dim)
|
|
error = {ct.err_code: 1, ct.err_msg: "Schema must have a primary key field."}
|
|
self.collection_schema_wrap.init_collection_schema([int_fields, vec_fields],
|
|
check_task=CheckTasks.err_res, check_items=error)
|
|
|
|
@pytest.mark.tags(CaseLabel.L2)
|
|
def test_collection_is_primary_false(self):
|
|
"""
|
|
target: test collection with all is_primary false
|
|
method: set all fields if_primary false
|
|
expected: raise exception
|
|
"""
|
|
self._connect()
|
|
fields = [cf.gen_int64_field(is_primary=False), cf.gen_float_field(is_primary=False),
|
|
cf.gen_float_vec_field(is_primary=False)]
|
|
error = {ct.err_code: 1, ct.err_msg: "Schema must have a primary key field."}
|
|
self.collection_schema_wrap.init_collection_schema(fields, check_task=CheckTasks.err_res, check_items=error)
|
|
|
|
@pytest.mark.tags(CaseLabel.L2)
|
|
@pytest.mark.parametrize("is_primary", [None, 2, "string"])
|
|
def test_collection_invalid_is_primary(self, is_primary):
|
|
"""
|
|
target: test collection with invalid primary
|
|
method: define field with is_primary=non-bool
|
|
expected: raise exception
|
|
"""
|
|
self._connect()
|
|
name = cf.gen_unique_str(prefix)
|
|
error = {ct.err_code: 999, ct.err_msg: "Param is_primary must be bool type"}
|
|
self.field_schema_wrap.init_field_schema(name=name, dtype=DataType.INT64, is_primary=is_primary,
|
|
check_task=CheckTasks.err_res, check_items=error)
|
|
|
|
@pytest.mark.tags(CaseLabel.L2)
|
|
@pytest.mark.parametrize("primary_field", ["12-s", "non_existing", "(mn)", "中文", None])
|
|
def test_collection_invalid_primary_field(self, primary_field):
|
|
"""
|
|
target: test collection with invalid primary_field
|
|
method: specify invalid string primary_field in collection schema
|
|
expected: raise exception
|
|
"""
|
|
self._connect()
|
|
fields = [cf.gen_int64_field(), cf.gen_float_vec_field()]
|
|
error = {ct.err_code: 999, ct.err_msg: "Schema must have a primary key field"}
|
|
self.collection_schema_wrap.init_collection_schema(fields=fields, primary_field=primary_field,
|
|
check_task=CheckTasks.err_res, check_items=error)
|
|
|
|
@pytest.mark.tags(CaseLabel.L2)
|
|
@pytest.mark.parametrize("primary_field", [[], 1, [1, "2", 3], (1,), {1: 1}])
|
|
def test_collection_non_string_primary_field(self, primary_field):
|
|
"""
|
|
target: test collection with non-string primary_field
|
|
method: primary_field type is not string
|
|
expected: raise exception
|
|
"""
|
|
self._connect()
|
|
fields = [cf.gen_int64_field(), cf.gen_float_vec_field()]
|
|
error = {ct.err_code: 999, ct.err_msg: "Param primary_field must be int or str type"}
|
|
self.collection_schema_wrap.init_collection_schema(fields, primary_field=primary_field,
|
|
check_task=CheckTasks.err_res, check_items=error)
|
|
|
|
@pytest.mark.tags(CaseLabel.L0)
|
|
def test_collection_primary_in_schema(self):
|
|
"""
|
|
target: test collection with primary field
|
|
method: specify primary field in CollectionSchema
|
|
expected: collection.primary_field
|
|
"""
|
|
self._connect()
|
|
c_name = cf.gen_unique_str(prefix)
|
|
schema = cf.gen_default_collection_schema(primary_field=ct.default_int64_field_name)
|
|
self.collection_wrap.init_collection(c_name, schema=schema)
|
|
assert self.collection_wrap.primary_field.name == ct.default_int64_field_name
|
|
|
|
@pytest.mark.tags(CaseLabel.L0)
|
|
def test_collection_primary_in_field(self):
|
|
"""
|
|
target: test collection with primary field
|
|
method: specify primary field in FieldSchema
|
|
expected: collection.primary_field
|
|
"""
|
|
self._connect()
|
|
fields = [cf.gen_int64_field(is_primary=True), cf.gen_float_field(), cf.gen_float_vec_field()]
|
|
schema, _ = self.collection_schema_wrap.init_collection_schema(fields)
|
|
self.collection_wrap.init_collection(cf.gen_unique_str(prefix), schema=schema)
|
|
assert self.collection_wrap.primary_field.name == ct.default_int64_field_name
|
|
|
|
@pytest.mark.tags(CaseLabel.L2)
|
|
def test_collection_unsupported_primary_field(self, get_unsupported_primary_field):
|
|
"""
|
|
target: test collection with unsupported primary field type
|
|
method: specify non-int64 as primary field
|
|
expected: raise exception
|
|
"""
|
|
self._connect()
|
|
field = get_unsupported_primary_field
|
|
vec_field = cf.gen_float_vec_field(name="vec")
|
|
error = {ct.err_code: 999, ct.err_msg: "Primary key type must be DataType.INT64 or DataType.VARCHAR."}
|
|
self.collection_schema_wrap.init_collection_schema(fields=[field, vec_field], primary_field=field.name,
|
|
check_task=CheckTasks.err_res, check_items=error)
|
|
|
|
@pytest.mark.tags(CaseLabel.L1)
|
|
def test_collection_multi_primary_fields(self):
|
|
"""
|
|
target: test collection with multi primary
|
|
method: collection with two primary fields
|
|
expected: raise exception
|
|
"""
|
|
self._connect()
|
|
int_field_one = cf.gen_int64_field(is_primary=True)
|
|
int_field_two = cf.gen_int64_field(name="int2", is_primary=True)
|
|
error = {ct.err_code: 999, ct.err_msg: "Expected only one primary key field"}
|
|
self.collection_schema_wrap.init_collection_schema(
|
|
fields=[int_field_one, int_field_two, cf.gen_float_vec_field()],
|
|
check_task=CheckTasks.err_res, check_items=error)
|
|
|
|
@pytest.mark.tags(CaseLabel.L2)
|
|
def test_collection_primary_inconsistent(self):
|
|
"""
|
|
target: test collection with different primary field setting
|
|
method: 1. set A field is_primary 2. set primary_field is B
|
|
expected: raise exception
|
|
"""
|
|
self._connect()
|
|
int_field_one = cf.gen_int64_field(is_primary=True)
|
|
int_field_two = cf.gen_int64_field(name="int2")
|
|
fields = [int_field_one, int_field_two, cf.gen_float_vec_field()]
|
|
error = {ct.err_code: 999, ct.err_msg: "Expected only one primary key field"}
|
|
self.collection_schema_wrap.init_collection_schema(fields, primary_field=int_field_two.name,
|
|
check_task=CheckTasks.err_res, check_items=error)
|
|
|
|
@pytest.mark.tags(CaseLabel.L1)
|
|
def test_collection_primary_consistent(self):
|
|
"""
|
|
target: test collection with both collection schema and field schema
|
|
method: 1. set A field is_primary 2.set primary_field is A
|
|
expected: verify primary field
|
|
"""
|
|
self._connect()
|
|
c_name = cf.gen_unique_str(prefix)
|
|
int_field_one = cf.gen_int64_field(is_primary=True)
|
|
schema = cf.gen_collection_schema(fields=[int_field_one, cf.gen_float_vec_field()],
|
|
primary_field=int_field_one.name)
|
|
self.collection_wrap.init_collection(c_name, schema=schema, check_task=CheckTasks.check_collection_property,
|
|
check_items={exp_name: c_name, exp_schema: schema})
|
|
|
|
@pytest.mark.tags(CaseLabel.L0)
|
|
@pytest.mark.parametrize("auto_id", [True, False])
|
|
def test_collection_auto_id_in_field_schema(self, auto_id):
|
|
"""
|
|
target: test collection with auto_id in field schema
|
|
method: specify auto_id True in field schema
|
|
expected: verify schema's auto_id
|
|
"""
|
|
self._connect()
|
|
c_name = cf.gen_unique_str(prefix)
|
|
int_field = cf.gen_int64_field(is_primary=True, auto_id=auto_id)
|
|
vec_field = cf.gen_float_vec_field(name='vec')
|
|
schema, _ = self.collection_schema_wrap.init_collection_schema([int_field, vec_field])
|
|
assert schema.auto_id == auto_id
|
|
self.collection_wrap.init_collection(c_name, schema=schema, check_task=CheckTasks.check_collection_property,
|
|
check_items={exp_name: c_name, exp_schema: schema})
|
|
|
|
@pytest.mark.tags(CaseLabel.L0)
|
|
@pytest.mark.parametrize("auto_id", [True, False])
|
|
def test_collection_auto_id_in_collection_schema(self, auto_id):
|
|
"""
|
|
target: test collection with auto_id in collection schema
|
|
method: specify auto_id True in collection schema
|
|
expected: verify schema auto_id and collection schema
|
|
"""
|
|
self._connect()
|
|
c_name = cf.gen_unique_str(prefix)
|
|
int_field = cf.gen_int64_field(is_primary=True)
|
|
vec_field = cf.gen_float_vec_field(name='vec')
|
|
schema, _ = self.collection_schema_wrap.init_collection_schema([int_field, vec_field], auto_id=auto_id)
|
|
assert schema.auto_id == auto_id
|
|
self.collection_wrap.init_collection(c_name, schema=schema, check_task=CheckTasks.check_collection_property,
|
|
check_items={exp_name: c_name, exp_schema: schema})
|
|
|
|
@pytest.mark.tags(CaseLabel.L2)
|
|
def test_collection_auto_id_non_primary_field(self):
|
|
"""
|
|
target: test collection set auto_id in non-primary field
|
|
method: set auto_id=True in non-primary field
|
|
expected: raise exception
|
|
"""
|
|
self._connect()
|
|
error = {ct.err_code: 999, ct.err_msg: "auto_id can only be specified on the primary key field"}
|
|
self.field_schema_wrap.init_field_schema(name=ct.default_int64_field_name, dtype=DataType.INT64, auto_id=True,
|
|
check_task=CheckTasks.err_res, check_items=error)
|
|
|
|
@pytest.mark.tags(CaseLabel.L2)
|
|
def test_collection_auto_id_false_non_primary(self):
|
|
"""
|
|
target: test collection set auto_id in non-primary field
|
|
method: set auto_id=True in non-primary field
|
|
expected: verify schema auto_id is False
|
|
"""
|
|
self._connect()
|
|
int_field_one = cf.gen_int64_field(is_primary=True)
|
|
int_field_two = cf.gen_int64_field(name='int2', auto_id=False)
|
|
fields = [int_field_one, int_field_two, cf.gen_float_vec_field()]
|
|
schema, _ = self.collection_schema_wrap.init_collection_schema(fields)
|
|
assert not schema.auto_id
|
|
|
|
@pytest.mark.tags(CaseLabel.L2)
|
|
@pytest.mark.xfail(reason="pymilvus issue, should use fieldschema as top priority")
|
|
@pytest.mark.parametrize("auto_id", [True, False])
|
|
def test_collection_auto_id_inconsistent(self, auto_id):
|
|
"""
|
|
target: test collection auto_id with both collection schema and field schema
|
|
method: 1.set primary field auto_id=True in field schema 2.set auto_id=False in collection schema
|
|
expected: raise exception
|
|
"""
|
|
self._connect()
|
|
int_field = cf.gen_int64_field(is_primary=True, auto_id=auto_id)
|
|
vec_field = cf.gen_float_vec_field(name='vec')
|
|
schema, _ = self.collection_schema_wrap.init_collection_schema([int_field, vec_field], auto_id=not auto_id)
|
|
collection_w = self.init_collection_wrap(cf.gen_unique_str(prefix), schema=schema)
|
|
|
|
assert collection_w.schema.auto_id is auto_id
|
|
|
|
@pytest.mark.tags(CaseLabel.L2)
|
|
@pytest.mark.parametrize("auto_id", [True, False])
|
|
def test_collection_auto_id_consistent(self, auto_id):
|
|
"""
|
|
target: test collection auto_id with both collection schema and field schema
|
|
method: set auto_id=True/False both field and schema
|
|
expected: verify auto_id
|
|
"""
|
|
self._connect()
|
|
int_field = cf.gen_int64_field(is_primary=True, auto_id=auto_id)
|
|
vec_field = cf.gen_float_vec_field(name='vec')
|
|
schema, _ = self.collection_schema_wrap.init_collection_schema([int_field, vec_field], auto_id=auto_id)
|
|
assert schema.auto_id == auto_id
|
|
|
|
@pytest.mark.tags(CaseLabel.L2)
|
|
def test_collection_auto_id_none_in_field(self):
|
|
"""
|
|
target: test collection with auto_id is None
|
|
method: set auto_id=None
|
|
expected: raise exception
|
|
"""
|
|
self._connect()
|
|
error = {ct.err_code: 0, ct.err_msg: "Param auto_id must be bool type"}
|
|
self.field_schema_wrap.init_field_schema(name=ct.default_int64_field_name, dtype=DataType.INT64,
|
|
is_primary=True,
|
|
auto_id=None, check_task=CheckTasks.err_res, check_items=error)
|
|
|
|
@pytest.mark.tags(CaseLabel.L2)
|
|
# @pytest.mark.xfail(reason="issue 24578")
|
|
@pytest.mark.parametrize("auto_id", [None, 1, "string"])
|
|
def test_collection_invalid_auto_id(self, auto_id):
|
|
"""
|
|
target: test collection with invalid auto_id
|
|
method: define field with auto_id=non-bool
|
|
expected: raise exception
|
|
"""
|
|
self._connect()
|
|
int_field = cf.gen_int64_field(is_primary=True)
|
|
vec_field = cf.gen_float_vec_field(name='vec')
|
|
error = {ct.err_code: 0, ct.err_msg: "Param auto_id must be bool type"}
|
|
self.collection_schema_wrap.init_collection_schema([int_field, vec_field], auto_id=auto_id,
|
|
check_task=CheckTasks.err_res, check_items=error)
|
|
|
|
@pytest.mark.tags(CaseLabel.L2)
|
|
def test_collection_multi_fields_auto_id(self):
|
|
"""
|
|
target: test collection auto_id with multi fields
|
|
method: specify auto_id=True for multi int64 fields
|
|
expected: todo raise exception
|
|
"""
|
|
self._connect()
|
|
error = {ct.err_code: 0, ct.err_msg: "auto_id can only be specified on the primary key field"}
|
|
cf.gen_int64_field(is_primary=True, auto_id=True)
|
|
self.field_schema_wrap.init_field_schema(name="int", dtype=DataType.INT64, auto_id=True,
|
|
check_task=CheckTasks.err_res, check_items=error)
|
|
|
|
@pytest.mark.tags(CaseLabel.L2)
|
|
@pytest.mark.parametrize("dtype", [DataType.FLOAT_VECTOR, DataType.BINARY_VECTOR])
|
|
def test_collection_vector_without_dim(self, dtype):
|
|
"""
|
|
target: test collection without dimension
|
|
method: define vector field without dim
|
|
expected: raise exception
|
|
"""
|
|
self._connect()
|
|
c_name = cf.gen_unique_str(prefix)
|
|
float_vec_field, _ = self.field_schema_wrap.init_field_schema(name="vec", dtype=dtype)
|
|
schema = cf.gen_collection_schema(fields=[cf.gen_int64_field(is_primary=True), float_vec_field])
|
|
error = {ct.err_code: 1, ct.err_msg: "dimension is not defined in field type params"}
|
|
self.collection_wrap.init_collection(c_name, schema=schema, check_task=CheckTasks.err_res, check_items=error)
|
|
|
|
@pytest.mark.tags(CaseLabel.L2)
|
|
@pytest.mark.skip(reason="issue #29796")
|
|
def test_collection_vector_invalid_dim(self, get_invalid_dim):
|
|
"""
|
|
target: test collection with invalid dimension
|
|
method: define float-vec field with invalid dimension
|
|
expected: raise exception
|
|
"""
|
|
self._connect()
|
|
c_name = cf.gen_unique_str(prefix)
|
|
error = {ct.err_code: 999, ct.err_msg: "invalid dimension"}
|
|
float_vec_field = cf.gen_float_vec_field(dim=get_invalid_dim)
|
|
schema = cf.gen_collection_schema(fields=[cf.gen_int64_field(is_primary=True), float_vec_field])
|
|
error = {ct.err_code: 65535, ct.err_msg: "strconv.ParseInt: parsing \"[]\": invalid syntax"}
|
|
self.collection_wrap.init_collection(c_name, schema=schema, check_task=CheckTasks.err_res, check_items=error)
|
|
|
|
@pytest.mark.tags(CaseLabel.L2)
|
|
@pytest.mark.parametrize("dim", [ct.min_dim-1, ct.max_dim+1])
|
|
def test_collection_vector_out_bounds_dim(self, dim):
|
|
"""
|
|
target: test collection with out of bounds dim
|
|
method: invalid dim -1 and 32759
|
|
expected: raise exception
|
|
"""
|
|
self._connect()
|
|
c_name = cf.gen_unique_str(prefix)
|
|
float_vec_field = cf.gen_float_vec_field(dim=dim)
|
|
schema = cf.gen_collection_schema(fields=[cf.gen_int64_field(is_primary=True), float_vec_field])
|
|
error = {ct.err_code: 65535, ct.err_msg: "invalid dimension: {}.".format(dim)}
|
|
self.collection_wrap.init_collection(c_name, schema=schema, check_task=CheckTasks.err_res, check_items=error)
|
|
|
|
@pytest.mark.tags(CaseLabel.L1)
|
|
def test_collection_non_vector_field_dim(self):
|
|
"""
|
|
target: test collection with dim for non-vector field
|
|
method: define int64 field with dim
|
|
expected: no exception
|
|
"""
|
|
self._connect()
|
|
c_name = cf.gen_unique_str(prefix)
|
|
int_field, _ = self.field_schema_wrap.init_field_schema(name=ct.default_int64_field_name, dtype=DataType.INT64,
|
|
dim=ct.default_dim)
|
|
float_vec_field = cf.gen_float_vec_field()
|
|
schema = cf.gen_collection_schema(fields=[int_field, float_vec_field],
|
|
primary_field=ct.default_int64_field_name)
|
|
self.collection_wrap.init_collection(c_name, schema=schema, check_task=CheckTasks.check_collection_property,
|
|
check_items={exp_name: c_name, exp_schema: schema})
|
|
|
|
@pytest.mark.tags(CaseLabel.L1)
|
|
def test_collection_desc(self):
|
|
"""
|
|
target: test collection with description
|
|
method: create with description
|
|
expected: assert default description
|
|
"""
|
|
self._connect()
|
|
c_name = cf.gen_unique_str(prefix)
|
|
schema = cf.gen_default_collection_schema(description=ct.collection_desc)
|
|
self.collection_wrap.init_collection(c_name, schema=schema, check_task=CheckTasks.check_collection_property,
|
|
check_items={exp_name: c_name, exp_schema: schema})
|
|
|
|
@pytest.mark.tags(CaseLabel.L2)
|
|
def test_collection_none_desc(self):
|
|
"""
|
|
target: test collection with none description
|
|
method: create with none description
|
|
expected: raise exception
|
|
"""
|
|
self._connect()
|
|
c_name = cf.gen_unique_str(prefix)
|
|
schema = cf.gen_default_collection_schema(description=None)
|
|
error = {ct.err_code: 1, ct.err_msg: "None has type NoneType, but expected one of: bytes, unicode"}
|
|
self.collection_wrap.init_collection(c_name, schema=schema, check_task=CheckTasks.err_res, check_items=error)
|
|
|
|
@pytest.mark.tags(CaseLabel.L2)
|
|
def test_collection_long_desc(self):
|
|
"""
|
|
target: test collection with long desc
|
|
method: create with long desc
|
|
expected:
|
|
"""
|
|
self._connect()
|
|
c_name = cf.gen_unique_str(prefix)
|
|
desc = "a".join("a" for _ in range(256))
|
|
schema = cf.gen_default_collection_schema(description=desc)
|
|
self.collection_wrap.init_collection(c_name, schema=schema,
|
|
check_task=CheckTasks.check_collection_property,
|
|
check_items={exp_name: c_name, exp_schema: schema})
|
|
|
|
@pytest.mark.tags(CaseLabel.L0)
|
|
def test_collection_binary(self):
|
|
"""
|
|
target: test collection with binary-vec
|
|
method: create collection with binary field
|
|
expected: assert binary field
|
|
"""
|
|
self._connect()
|
|
c_name = cf.gen_unique_str(prefix)
|
|
self.collection_wrap.init_collection(c_name, schema=default_binary_schema,
|
|
check_task=CheckTasks.check_collection_property,
|
|
check_items={exp_name: c_name, exp_schema: default_binary_schema})
|
|
assert c_name in self.utility_wrap.list_collections()[0]
|
|
|
|
@pytest.mark.tags(CaseLabel.L0)
|
|
def test_collection_shards_num_with_default_value(self):
|
|
"""
|
|
target:test collection with shards_num
|
|
method:create collection with shards_num
|
|
expected: no exception
|
|
"""
|
|
self._connect()
|
|
c_name = cf.gen_unique_str(prefix)
|
|
self.collection_wrap.init_collection(c_name, schema=default_schema, shards_num=default_shards_num,
|
|
check_task=CheckTasks.check_collection_property,
|
|
check_items={exp_name: c_name, exp_shards_num: default_shards_num})
|
|
assert c_name in self.utility_wrap.list_collections()[0]
|
|
|
|
@pytest.mark.tags(CaseLabel.L1)
|
|
@pytest.mark.parametrize("shards_num", [-256, 0, ct.max_shards_num // 2, ct.max_shards_num])
|
|
def test_collection_shards_num_with_not_default_value(self, shards_num):
|
|
"""
|
|
target:test collection with shards_num
|
|
method:create collection with not default shards_num
|
|
expected: no exception
|
|
"""
|
|
self._connect()
|
|
c_name = cf.gen_unique_str(prefix)
|
|
self.collection_wrap.init_collection(c_name, schema=default_schema, shards_num=shards_num,
|
|
check_task=CheckTasks.check_collection_property,
|
|
check_items={exp_name: c_name, exp_shards_num: shards_num})
|
|
assert c_name in self.utility_wrap.list_collections()[0]
|
|
|
|
@pytest.mark.tags(CaseLabel.L2)
|
|
@pytest.mark.parametrize("shards_num", [ct.max_shards_num + 1, 257])
|
|
def test_collection_shards_num_invalid(self, shards_num):
|
|
"""
|
|
target:test collection with invalid shards_num
|
|
method:create collection with shards_num out of [1, 16]
|
|
expected: raise exception
|
|
"""
|
|
self._connect()
|
|
c_name = cf.gen_unique_str(prefix)
|
|
error = {ct.err_code: 1, ct.err_msg: f"maximum shards's number should be limited to {ct.max_shards_num}"}
|
|
self.collection_wrap.init_collection(c_name, schema=default_schema, shards_num=shards_num,
|
|
check_task=CheckTasks.err_res, check_items=error)
|
|
|
|
@pytest.mark.tags(CaseLabel.L2)
|
|
@pytest.mark.parametrize("error_type_shards_num", [1.0, "2"])
|
|
def test_collection_shards_num_with_error_type(self, error_type_shards_num):
|
|
"""
|
|
target:test collection with error type shards_num
|
|
method:create collection with error type shards_num
|
|
expected: raise exception
|
|
"""
|
|
self._connect()
|
|
c_name = cf.gen_unique_str(prefix)
|
|
error = {ct.err_code: 1, ct.err_msg: f"expected one of: int, long"}
|
|
self.collection_wrap.init_collection(c_name, schema=default_schema, shards_num=error_type_shards_num,
|
|
check_task=CheckTasks.err_res,
|
|
check_items=error)
|
|
|
|
@pytest.mark.tags(CaseLabel.L1)
|
|
def test_create_collection_maximum_fields(self):
|
|
"""
|
|
target: test create collection with maximum fields
|
|
method: create collection with maximum field number
|
|
expected: no exception
|
|
"""
|
|
self._connect()
|
|
c_name = cf.gen_unique_str(prefix)
|
|
int_fields = []
|
|
limit_num = ct.max_field_num - 2
|
|
for i in range(limit_num):
|
|
int_field_name = cf.gen_unique_str("field_name")
|
|
field = cf.gen_int64_field(name=int_field_name)
|
|
int_fields.append(field)
|
|
int_fields.append(cf.gen_float_vec_field())
|
|
int_fields.append(cf.gen_int64_field(is_primary=True))
|
|
schema = cf.gen_collection_schema(fields=int_fields)
|
|
self.collection_wrap.init_collection(c_name, schema=schema, check_task=CheckTasks.check_collection_property,
|
|
check_items={exp_name: c_name, exp_schema: schema})
|
|
|
|
@pytest.mark.tags(CaseLabel.L1)
|
|
def test_create_collection_maximum_vector_fields(self):
|
|
"""
|
|
target: Test create collection with the maximum vector fields (default is 4)
|
|
method: create collection with the maximum vector field number
|
|
expected: no exception
|
|
"""
|
|
self._connect()
|
|
c_name = cf.gen_unique_str(prefix)
|
|
int_fields = []
|
|
limit_num = max_vector_field_num
|
|
for i in range(limit_num):
|
|
vector_field_name = cf.gen_unique_str("vector_field_name")
|
|
field = cf.gen_float_vec_field(name=vector_field_name)
|
|
int_fields.append(field)
|
|
int_fields.append(cf.gen_int64_field(is_primary=True))
|
|
schema = cf.gen_collection_schema(fields=int_fields)
|
|
self.collection_wrap.init_collection(c_name, schema=schema, check_task=CheckTasks.check_collection_property,
|
|
check_items={exp_name: c_name, exp_schema: schema})
|
|
|
|
@pytest.mark.tags(CaseLabel.L2)
|
|
@pytest.mark.parametrize("primary_key", [cf.gen_int64_field(is_primary=True), cf.gen_string_field(is_primary=True)])
|
|
def test_create_collection_multiple_vector_and_maximum_fields(self, primary_key):
|
|
"""
|
|
target: test create collection with multiple vector fields and maximum fields
|
|
method: create collection with multiple vector fields and maximum fields
|
|
expected: no exception
|
|
"""
|
|
self._connect()
|
|
c_name = cf.gen_unique_str(prefix)
|
|
int_fields = []
|
|
vector_limit_num = max_vector_field_num - 2
|
|
limit_num = ct.max_field_num - 2
|
|
# add maximum vector fields
|
|
for i in range(vector_limit_num):
|
|
int_field_name = cf.gen_unique_str("field_name")
|
|
field = cf.gen_int64_field(name=int_field_name)
|
|
int_fields.append(field)
|
|
# add other vector fields to maximum fields num
|
|
for i in range(limit_num - 2):
|
|
int_field_name = cf.gen_unique_str("field_name")
|
|
field = cf.gen_int64_field(name=int_field_name)
|
|
int_fields.append(field)
|
|
int_fields.append(cf.gen_float_vec_field())
|
|
int_fields.append(primary_key)
|
|
schema = cf.gen_collection_schema(fields=int_fields)
|
|
self.collection_wrap.init_collection(c_name, schema=schema, check_task=CheckTasks.check_collection_property,
|
|
check_items={exp_name: c_name, exp_schema: schema})
|
|
|
|
@pytest.mark.tags(CaseLabel.L2)
|
|
@pytest.mark.parametrize("primary_key", [cf.gen_int64_field(is_primary=True), cf.gen_string_field(is_primary=True)])
|
|
def test_create_collection_maximum_vector_and_all_fields(self, primary_key):
|
|
"""
|
|
target: test create collection with maximum vector fields and maximum fields
|
|
method: create collection with maximum vector fields and maximum fields
|
|
expected: no exception
|
|
"""
|
|
self._connect()
|
|
c_name = cf.gen_unique_str(prefix)
|
|
int_fields = []
|
|
vector_limit_num = max_vector_field_num
|
|
limit_num = ct.max_field_num - 2
|
|
# add maximum vector fields
|
|
for i in range(vector_limit_num):
|
|
int_field_name = cf.gen_unique_str("field_name")
|
|
field = cf.gen_int64_field(name=int_field_name)
|
|
int_fields.append(field)
|
|
# add other vector fields to maximum fields num
|
|
for i in range(limit_num - 4):
|
|
int_field_name = cf.gen_unique_str("field_name")
|
|
field = cf.gen_int64_field(name=int_field_name)
|
|
int_fields.append(field)
|
|
int_fields.append(cf.gen_float_vec_field())
|
|
int_fields.append(primary_key)
|
|
schema = cf.gen_collection_schema(fields=int_fields)
|
|
self.collection_wrap.init_collection(c_name, schema=schema, check_task=CheckTasks.check_collection_property,
|
|
check_items={exp_name: c_name, exp_schema: schema})
|
|
|
|
@pytest.mark.tags(CaseLabel.L2)
|
|
def test_create_collection_over_maximum_fields(self):
|
|
"""
|
|
target: Test create collection with more than the maximum fields
|
|
method: create collection with more than the maximum field number
|
|
expected: raise exception
|
|
"""
|
|
self._connect()
|
|
c_name = cf.gen_unique_str(prefix)
|
|
int_fields = []
|
|
limit_num = ct.max_field_num
|
|
for i in range(limit_num):
|
|
int_field_name = cf.gen_unique_str("field_name")
|
|
field = cf.gen_int64_field(name=int_field_name)
|
|
int_fields.append(field)
|
|
int_fields.append(cf.gen_float_vec_field())
|
|
int_fields.append(cf.gen_int64_field(is_primary=True))
|
|
schema = cf.gen_collection_schema(fields=int_fields)
|
|
error = {ct.err_code: 1, ct.err_msg: "maximum field's number should be limited to 64"}
|
|
self.collection_wrap.init_collection(c_name, schema=schema, check_task=CheckTasks.err_res, check_items=error)
|
|
|
|
@pytest.mark.tags(CaseLabel.L2)
|
|
def test_create_collection_over_maximum_vector_fields(self):
|
|
"""
|
|
target: Test create collection with more than the maximum vector fields (default is 4)
|
|
method: create collection with more than the maximum vector field number
|
|
expected: raise exception
|
|
"""
|
|
self._connect()
|
|
c_name = cf.gen_unique_str(prefix)
|
|
int_fields = []
|
|
limit_num = max_vector_field_num
|
|
for i in range(limit_num + 1):
|
|
vector_field_name = cf.gen_unique_str("vector_field_name")
|
|
field = cf.gen_float_vec_field(name=vector_field_name)
|
|
int_fields.append(field)
|
|
int_fields.append(cf.gen_int64_field(is_primary=True))
|
|
schema = cf.gen_collection_schema(fields=int_fields)
|
|
error = {ct.err_code: 65535, ct.err_msg: "maximum vector field's number should be limited to 4"}
|
|
self.collection_wrap.init_collection(c_name, schema=schema, check_task=CheckTasks.err_res, check_items=error)
|
|
|
|
@pytest.mark.tags(CaseLabel.L2)
|
|
def test_create_collection_multiple_vector_and_over_maximum_all_fields(self):
|
|
"""
|
|
target: test create collection with multiple vector fields and over maximum fields
|
|
method: create collection with multiple vector fields and over maximum fields
|
|
expected: raise exception
|
|
"""
|
|
self._connect()
|
|
c_name = cf.gen_unique_str(prefix)
|
|
int_fields = []
|
|
vector_limit_num = max_vector_field_num - 2
|
|
limit_num = ct.max_field_num
|
|
# add multiple vector fields
|
|
for i in range(vector_limit_num):
|
|
vector_field_name = cf.gen_unique_str("field_name")
|
|
field = cf.gen_float_vec_field(name=vector_field_name)
|
|
int_fields.append(field)
|
|
# add other vector fields to maximum fields num
|
|
for i in range(limit_num):
|
|
int_field_name = cf.gen_unique_str("field_name")
|
|
field = cf.gen_int64_field(name=int_field_name)
|
|
int_fields.append(field)
|
|
int_fields.append(cf.gen_int64_field(is_primary=True))
|
|
log.debug(len(int_fields))
|
|
schema = cf.gen_collection_schema(fields=int_fields)
|
|
error = {ct.err_code: 65535, ct.err_msg: "maximum field's number should be limited to 64"}
|
|
self.collection_wrap.init_collection(c_name, schema=schema, check_task=CheckTasks.err_res, check_items=error)
|
|
|
|
@pytest.mark.tags(CaseLabel.L2)
|
|
def test_create_collection_over_maximum_vector_and_all_fields(self):
|
|
"""
|
|
target: test create collection with over maximum vector fields and maximum fields
|
|
method: create collection with over maximum vector fields and maximum fields
|
|
expected: raise exception
|
|
"""
|
|
self._connect()
|
|
c_name = cf.gen_unique_str(prefix)
|
|
int_fields = []
|
|
vector_limit_num = max_vector_field_num
|
|
limit_num = ct.max_field_num - 2
|
|
# add maximum vector fields
|
|
for i in range(vector_limit_num + 1):
|
|
vector_field_name = cf.gen_unique_str("field_name")
|
|
field = cf.gen_float_vec_field(name=vector_field_name)
|
|
int_fields.append(field)
|
|
# add other vector fields to maximum fields num
|
|
for i in range(limit_num - 4):
|
|
int_field_name = cf.gen_unique_str("field_name")
|
|
field = cf.gen_int64_field(name=int_field_name)
|
|
int_fields.append(field)
|
|
int_fields.append(cf.gen_float_vec_field())
|
|
int_fields.append(cf.gen_int64_field(is_primary=True))
|
|
schema = cf.gen_collection_schema(fields=int_fields)
|
|
error = {ct.err_code: 65535, ct.err_msg: "maximum field's number should be limited to 64"}
|
|
self.collection_wrap.init_collection(c_name, schema=schema, check_task=CheckTasks.err_res, check_items=error)
|
|
|
|
@pytest.mark.tags(CaseLabel.L2)
|
|
def test_collection_multi_sparse_vectors(self):
|
|
"""
|
|
target: Test multiple sparse vectors in a collection
|
|
method: create 2 sparse vectors in a collection
|
|
expected: successful creation of a collection
|
|
"""
|
|
# 1. connect
|
|
self._connect()
|
|
# 2. create collection with multiple vectors
|
|
c_name = cf.gen_unique_str(prefix)
|
|
fields = [cf.gen_int64_field(is_primary=True), cf.gen_float_field(),
|
|
cf.gen_float_vec_field(vector_data_type=ct.sparse_vector), cf.gen_float_vec_field(name="vec_sparse", vector_data_type=ct.sparse_vector)]
|
|
schema = cf.gen_collection_schema(fields=fields)
|
|
self.collection_wrap.init_collection(c_name, schema=schema,
|
|
check_task=CheckTasks.check_collection_property,
|
|
check_items={exp_name: c_name, exp_schema: schema})
|
|
|
|
|
|
class TestCollectionOperation(TestcaseBase):
|
|
"""
|
|
******************************************************************
|
|
The following cases are used to test collection interface operations
|
|
******************************************************************
|
|
"""
|
|
|
|
@pytest.mark.tags(CaseLabel.L2)
|
|
def test_collection_without_connection(self):
|
|
"""
|
|
target: test collection without connection
|
|
method: 1.create collection after connection removed
|
|
expected: raise exception
|
|
"""
|
|
self._connect()
|
|
c_name = cf.gen_unique_str(prefix)
|
|
self.connection_wrap.remove_connection(ct.default_alias)
|
|
res_list, _ = self.connection_wrap.list_connections()
|
|
assert ct.default_alias not in res_list
|
|
error = {ct.err_code: 1, ct.err_msg: 'should create connect first'}
|
|
self.collection_wrap.init_collection(c_name, schema=default_schema,
|
|
check_task=CheckTasks.err_res, check_items=error)
|
|
assert self.collection_wrap.collection is None
|
|
|
|
@pytest.mark.tags(CaseLabel.L1)
|
|
def test_collection_multi_create_drop(self):
|
|
"""
|
|
target: test cycle creation and deletion of multiple collections
|
|
method: in a loop, collections are created and deleted sequentially
|
|
expected: no exception
|
|
"""
|
|
self._connect()
|
|
c_num = 20
|
|
for _ in range(c_num):
|
|
c_name = cf.gen_unique_str(prefix)
|
|
self.collection_wrap.init_collection(c_name, schema=default_schema,
|
|
check_task=CheckTasks.check_collection_property,
|
|
check_items={exp_name: c_name, exp_schema: default_schema})
|
|
self.collection_wrap.drop()
|
|
assert c_name not in self.utility_wrap.list_collections()[0]
|
|
|
|
@pytest.mark.tags(CaseLabel.L1)
|
|
def test_collection_dup_name_drop(self):
|
|
"""
|
|
target: test collection with dup name, and drop
|
|
method: 1. two dup name collection object
|
|
2. one object drop collection
|
|
expected: collection dropped
|
|
"""
|
|
self._connect()
|
|
c_name = cf.gen_unique_str(prefix)
|
|
collection_w = self.init_collection_wrap(name=c_name, check_task=CheckTasks.check_collection_property,
|
|
check_items={exp_name: c_name, exp_schema: default_schema})
|
|
self.collection_wrap.init_collection(c_name, check_task=CheckTasks.check_collection_property,
|
|
check_items={exp_name: c_name, exp_schema: default_schema})
|
|
self.collection_wrap.drop()
|
|
assert not self.utility_wrap.has_collection(c_name)[0]
|
|
error = {ct.err_code: 4, ct.err_msg: 'collection not found'}
|
|
collection_w.has_partition("p", check_task=CheckTasks.err_res, check_items=error)
|
|
|
|
@pytest.mark.tags(CaseLabel.L1)
|
|
def test_collection_after_drop(self):
|
|
"""
|
|
target: test create collection after create and drop
|
|
method: 1. create a 2. drop a 3, re-create a
|
|
expected: no exception
|
|
"""
|
|
c_name = cf.gen_unique_str(prefix)
|
|
collection_w = self.init_collection_wrap(name=c_name, check_task=CheckTasks.check_collection_property,
|
|
check_items={exp_name: c_name, exp_schema: default_schema})
|
|
collection_w.drop()
|
|
assert not self.utility_wrap.has_collection(collection_w.name)[0]
|
|
self.init_collection_wrap(name=c_name, check_task=CheckTasks.check_collection_property,
|
|
check_items={exp_name: c_name, exp_schema: default_schema})
|
|
assert self.utility_wrap.has_collection(c_name)[0]
|
|
|
|
@pytest.mark.tags(CaseLabel.L1)
|
|
def test_collection_all_datatype_fields(self):
|
|
"""
|
|
target: test create collection with all dataType fields
|
|
method: create collection with all dataType schema
|
|
expected: create successfully
|
|
"""
|
|
self._connect()
|
|
fields = []
|
|
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:
|
|
field, _ = self.field_schema_wrap.init_field_schema(name=k.lower(), dtype=v)
|
|
fields.append(field)
|
|
fields.append(cf.gen_float_vec_field())
|
|
schema, _ = self.collection_schema_wrap.init_collection_schema(fields,
|
|
primary_field=ct.default_int64_field_name)
|
|
log.info(schema)
|
|
c_name = cf.gen_unique_str(prefix)
|
|
self.collection_wrap.init_collection(c_name, schema=schema, check_task=CheckTasks.check_collection_property,
|
|
check_items={exp_name: c_name, exp_schema: schema})
|
|
|
|
@pytest.mark.tags(CaseLabel.L2)
|
|
def test_load_collection_after_load_partition(self):
|
|
"""
|
|
target: test release the partition after load collection
|
|
method: load collection and load the partition
|
|
expected: raise exception
|
|
"""
|
|
self._connect()
|
|
collection_w = self.init_collection_wrap()
|
|
partition_w1 = self.init_partition_wrap(collection_w)
|
|
partition_w1.insert(cf.gen_default_list_data())
|
|
collection_w.create_index(ct.default_float_vec_field_name, index_params=ct.default_flat_index)
|
|
collection_w.load()
|
|
partition_w1.load()
|
|
|
|
@pytest.mark.tags(CaseLabel.L2)
|
|
def test_load_collection_release_partition(self):
|
|
"""
|
|
target: test release the partition after load collection
|
|
method: load collection and release the partition
|
|
expected: raise exception
|
|
"""
|
|
self._connect()
|
|
collection_w = self.init_collection_wrap()
|
|
partition_w1 = self.init_partition_wrap(collection_w)
|
|
partition_w1.insert(cf.gen_default_list_data())
|
|
collection_w.create_index(ct.default_float_vec_field_name, index_params=ct.default_flat_index)
|
|
collection_w.load()
|
|
partition_w1.release()
|
|
|
|
@pytest.mark.tags(CaseLabel.L2)
|
|
def test_load_collection_after_release_collection(self):
|
|
"""
|
|
target: test release the collection after load collection
|
|
method: load collection and release the collection
|
|
expected: no exception
|
|
"""
|
|
self._connect()
|
|
c_name = cf.gen_unique_str(prefix)
|
|
collection_w = self.init_collection_wrap(name=c_name, check_task=CheckTasks.check_collection_property,
|
|
check_items={exp_name: c_name, exp_schema: default_schema})
|
|
collection_w.insert(cf.gen_default_list_data())
|
|
collection_w.create_index(ct.default_float_vec_field_name, index_params=ct.default_flat_index)
|
|
collection_w.load()
|
|
collection_w.release()
|
|
|
|
|
|
class TestCollectionDataframe(TestcaseBase):
|
|
"""
|
|
******************************************************************
|
|
The following cases are used to test construct_from_dataframe
|
|
******************************************************************
|
|
"""
|
|
|
|
@pytest.mark.tags(CaseLabel.L0)
|
|
def test_construct_from_dataframe(self):
|
|
"""
|
|
target: test collection with dataframe data
|
|
method: create collection and insert with dataframe
|
|
expected: collection num entities equal to nb
|
|
"""
|
|
self._connect()
|
|
c_name = cf.gen_unique_str(prefix)
|
|
df = cf.gen_default_dataframe_data(ct.default_nb)
|
|
self.collection_wrap.construct_from_dataframe(c_name, df, primary_field=ct.default_int64_field_name,
|
|
check_task=CheckTasks.check_collection_property,
|
|
check_items={exp_name: c_name, exp_schema: default_schema})
|
|
# flush
|
|
assert self.collection_wrap.num_entities == ct.default_nb
|
|
|
|
@pytest.mark.tags(CaseLabel.L0)
|
|
def test_construct_from_binary_dataframe(self):
|
|
"""
|
|
target: test binary collection with dataframe
|
|
method: create binary collection with dataframe
|
|
expected: collection num entities equal to nb
|
|
"""
|
|
self._connect()
|
|
c_name = cf.gen_unique_str(prefix)
|
|
df, _ = cf.gen_default_binary_dataframe_data(nb=ct.default_nb)
|
|
self.collection_wrap.construct_from_dataframe(c_name, df, primary_field=ct.default_int64_field_name,
|
|
check_task=CheckTasks.check_collection_property,
|
|
check_items={exp_name: c_name, exp_schema: default_binary_schema})
|
|
assert self.collection_wrap.num_entities == ct.default_nb
|
|
|
|
@pytest.mark.tags(CaseLabel.L2)
|
|
def test_construct_from_none_dataframe(self):
|
|
"""
|
|
target: test create collection by empty dataframe
|
|
method: invalid dataframe type create collection
|
|
expected: raise exception
|
|
"""
|
|
self._connect()
|
|
c_name = cf.gen_unique_str(prefix)
|
|
error = {ct.err_code: 1, ct.err_msg: "Dataframe can not be None."}
|
|
self.collection_wrap.construct_from_dataframe(c_name, None, check_task=CheckTasks.err_res, check_items=error)
|
|
|
|
@pytest.mark.tags(CaseLabel.L2)
|
|
def test_construct_from_dataframe_only_column(self):
|
|
"""
|
|
target: test collection with dataframe only columns
|
|
method: dataframe only has columns
|
|
expected: raise exception
|
|
"""
|
|
self._connect()
|
|
c_name = cf.gen_unique_str(prefix)
|
|
df = pd.DataFrame(columns=[ct.default_int64_field_name, ct.default_float_vec_field_name])
|
|
error = {ct.err_code: 0, ct.err_msg: "Cannot infer schema from empty dataframe"}
|
|
self.collection_wrap.construct_from_dataframe(c_name, df, primary_field=ct.default_int64_field_name,
|
|
check_task=CheckTasks.err_res, check_items=error)
|
|
|
|
@pytest.mark.tags(CaseLabel.L2)
|
|
def test_construct_from_inconsistent_dataframe(self):
|
|
"""
|
|
target: test collection with data inconsistent
|
|
method: create and insert with inconsistent data
|
|
expected: raise exception
|
|
"""
|
|
self._connect()
|
|
c_name = cf.gen_unique_str(prefix)
|
|
# one field different type df
|
|
mix_data = [(1, 2., [0.1, 0.2]), (2, 3., 4)]
|
|
df = pd.DataFrame(data=mix_data, columns=list("ABC"))
|
|
error = {ct.err_code: 1,
|
|
ct.err_msg: "The Input data type is inconsistent with defined schema, please check it."}
|
|
self.collection_wrap.construct_from_dataframe(c_name, df, primary_field='A', check_task=CheckTasks.err_res,
|
|
check_items=error)
|
|
|
|
@pytest.mark.tags(CaseLabel.L2)
|
|
def test_construct_from_non_dataframe(self):
|
|
"""
|
|
target: test create collection by invalid dataframe
|
|
method: non-dataframe type create collection
|
|
expected: raise exception
|
|
"""
|
|
self._connect()
|
|
c_name = cf.gen_unique_str(prefix)
|
|
error = {ct.err_code: 0, ct.err_msg: "Data type must be pandas.DataFrame."}
|
|
df = cf.gen_default_list_data(nb=10)
|
|
self.collection_wrap.construct_from_dataframe(c_name, df, check_task=CheckTasks.err_res, check_items=error)
|
|
|
|
@pytest.mark.tags(CaseLabel.L2)
|
|
def test_construct_from_data_type_dataframe(self):
|
|
"""
|
|
target: test collection with invalid dataframe
|
|
method: create with invalid dataframe
|
|
expected: raise exception
|
|
"""
|
|
self._connect()
|
|
c_name = cf.gen_unique_str(prefix)
|
|
df = pd.DataFrame({"date": pd.date_range('20210101', periods=3), ct.default_int64_field_name: [1, 2, 3]})
|
|
error = {ct.err_code: 0, ct.err_msg: "Cannot infer schema from empty dataframe."}
|
|
self.collection_wrap.construct_from_dataframe(c_name, df, primary_field=ct.default_int64_field_name,
|
|
check_task=CheckTasks.err_res, check_items=error)
|
|
|
|
@pytest.mark.tags(CaseLabel.L2)
|
|
def test_construct_from_invalid_field_name(self):
|
|
"""
|
|
target: test collection with invalid field name
|
|
method: create with invalid field name dataframe
|
|
expected: raise exception
|
|
"""
|
|
self._connect()
|
|
c_name = cf.gen_unique_str(prefix)
|
|
df = pd.DataFrame({'%$#': cf.gen_vectors(3, 2), ct.default_int64_field_name: [1, 2, 3]})
|
|
error = {ct.err_code: 1, ct.err_msg: "Invalid field name"}
|
|
self.collection_wrap.construct_from_dataframe(c_name, df, primary_field=ct.default_int64_field_name,
|
|
check_task=CheckTasks.err_res, check_items=error)
|
|
|
|
@pytest.mark.tags(CaseLabel.L2)
|
|
def test_construct_none_primary_field(self):
|
|
"""
|
|
target: test collection with none primary field
|
|
method: primary_field is none
|
|
expected: raise exception
|
|
"""
|
|
self._connect()
|
|
c_name = cf.gen_unique_str(prefix)
|
|
df = cf.gen_default_dataframe_data(ct.default_nb)
|
|
error = {ct.err_code: 0, ct.err_msg: "Schema must have a primary key field."}
|
|
self.collection_wrap.construct_from_dataframe(c_name, df, primary_field=None,
|
|
check_task=CheckTasks.err_res, check_items=error)
|
|
|
|
@pytest.mark.tags(CaseLabel.L2)
|
|
def test_construct_not_existed_primary_field(self):
|
|
"""
|
|
target: test collection with not existed primary field
|
|
method: primary field not existed
|
|
expected: raise exception
|
|
"""
|
|
self._connect()
|
|
c_name = cf.gen_unique_str(prefix)
|
|
df = cf.gen_default_dataframe_data(ct.default_nb)
|
|
error = {ct.err_code: 0, ct.err_msg: "Primary field must in dataframe."}
|
|
self.collection_wrap.construct_from_dataframe(c_name, df, primary_field=c_name,
|
|
check_task=CheckTasks.err_res, check_items=error)
|
|
|
|
@pytest.mark.tags(CaseLabel.L2)
|
|
def test_construct_with_none_auto_id(self):
|
|
"""
|
|
target: test construct with non-int64 as primary field
|
|
method: non-int64 as primary field
|
|
expected: raise exception
|
|
"""
|
|
self._connect()
|
|
c_name = cf.gen_unique_str(prefix)
|
|
df = cf.gen_default_dataframe_data(ct.default_nb)
|
|
error = {ct.err_code: 0, ct.err_msg: "Param auto_id must be bool type"}
|
|
self.collection_wrap.construct_from_dataframe(c_name, df, primary_field=ct.default_int64_field_name,
|
|
auto_id=None, check_task=CheckTasks.err_res, check_items=error)
|
|
|
|
@pytest.mark.tags(CaseLabel.L1)
|
|
def test_construct_auto_id_true_insert(self):
|
|
"""
|
|
target: test construct with true auto_id
|
|
method: auto_id=True and insert values
|
|
expected: raise exception
|
|
"""
|
|
self._connect()
|
|
c_name = cf.gen_unique_str(prefix)
|
|
df = cf.gen_default_dataframe_data(nb=100)
|
|
error = {ct.err_code: 0, ct.err_msg: "Auto_id is True, primary field should not have data."}
|
|
self.collection_wrap.construct_from_dataframe(c_name, df, primary_field=ct.default_int64_field_name,
|
|
auto_id=True, check_task=CheckTasks.err_res, check_items=error)
|
|
|
|
@pytest.mark.tags(CaseLabel.L1)
|
|
def test_construct_auto_id_true_no_insert(self):
|
|
"""
|
|
target: test construct with true auto_id
|
|
method: auto_id=True and not insert ids(primary fields all values are None)
|
|
expected: verify num entities
|
|
"""
|
|
self._connect()
|
|
c_name = cf.gen_unique_str(prefix)
|
|
df = cf.gen_default_dataframe_data()
|
|
# df.drop(ct.default_int64_field_name, axis=1, inplace=True)
|
|
df[ct.default_int64_field_name] = None
|
|
self.collection_wrap.construct_from_dataframe(c_name, df, primary_field=ct.default_int64_field_name,
|
|
auto_id=True)
|
|
assert self.collection_wrap.num_entities == ct.default_nb
|
|
|
|
@pytest.mark.tags(CaseLabel.L2)
|
|
def test_construct_none_value_auto_id_true(self):
|
|
"""
|
|
target: test construct with none value, auto_id
|
|
method: df primary field with none value, auto_id=true
|
|
expected: todo
|
|
"""
|
|
self._connect()
|
|
nb = 100
|
|
df = cf.gen_default_dataframe_data(nb)
|
|
df.iloc[:, 0] = numpy.NaN
|
|
res, _ = self.collection_wrap.construct_from_dataframe(cf.gen_unique_str(prefix), df,
|
|
primary_field=ct.default_int64_field_name, auto_id=True)
|
|
mutation_res = res[1]
|
|
assert cf._check_primary_keys(mutation_res.primary_keys, 100)
|
|
assert self.collection_wrap.num_entities == nb
|
|
|
|
@pytest.mark.tags(CaseLabel.L1)
|
|
def test_construct_auto_id_false(self):
|
|
"""
|
|
target: test construct with false auto_id
|
|
method: auto_id=False, primary_field correct
|
|
expected: verify auto_id
|
|
"""
|
|
self._connect()
|
|
c_name = cf.gen_unique_str(prefix)
|
|
df = cf.gen_default_dataframe_data(ct.default_nb)
|
|
self.collection_wrap.construct_from_dataframe(c_name, df, primary_field=ct.default_int64_field_name,
|
|
auto_id=False)
|
|
assert not self.collection_wrap.schema.auto_id
|
|
assert self.collection_wrap.num_entities == ct.default_nb
|
|
|
|
@pytest.mark.tags(CaseLabel.L2)
|
|
def test_construct_none_value_auto_id_false(self):
|
|
"""
|
|
target: test construct with none value, auto_id
|
|
method: df primary field with none value, auto_id=false
|
|
expected: raise exception
|
|
"""
|
|
self._connect()
|
|
nb = 100
|
|
df = cf.gen_default_dataframe_data(nb)
|
|
df.iloc[:, 0] = numpy.NaN
|
|
error = {ct.err_code: 0, ct.err_msg: "Primary key type must be DataType.INT64"}
|
|
self.collection_wrap.construct_from_dataframe(cf.gen_unique_str(prefix), df,
|
|
primary_field=ct.default_int64_field_name, auto_id=False,
|
|
check_task=CheckTasks.err_res, check_items=error)
|
|
|
|
@pytest.mark.tags(CaseLabel.L1)
|
|
def test_construct_auto_id_false_same_values(self):
|
|
"""
|
|
target: test construct with false auto_id and same value
|
|
method: auto_id=False, primary field same values
|
|
expected: verify num entities
|
|
"""
|
|
self._connect()
|
|
nb = 100
|
|
df = cf.gen_default_dataframe_data(nb)
|
|
df.iloc[1:, 0] = 1
|
|
res, _ = self.collection_wrap.construct_from_dataframe(cf.gen_unique_str(prefix), df,
|
|
primary_field=ct.default_int64_field_name, auto_id=False)
|
|
collection_w = res[0]
|
|
collection_w.flush()
|
|
assert collection_w.num_entities == nb
|
|
mutation_res = res[1]
|
|
assert mutation_res.primary_keys == df[ct.default_int64_field_name].values.tolist()
|
|
|
|
@pytest.mark.tags(CaseLabel.L1)
|
|
def test_construct_auto_id_false_negative_values(self):
|
|
"""
|
|
target: test construct with negative values
|
|
method: auto_id=False, primary field values is negative
|
|
expected: verify num entities
|
|
"""
|
|
self._connect()
|
|
nb = 100
|
|
df = cf.gen_default_dataframe_data(nb)
|
|
new_values = pd.Series(data=[i for i in range(0, -nb, -1)])
|
|
df[ct.default_int64_field_name] = new_values
|
|
self.collection_wrap.construct_from_dataframe(cf.gen_unique_str(prefix), df,
|
|
primary_field=ct.default_int64_field_name, auto_id=False)
|
|
assert self.collection_wrap.num_entities == nb
|
|
|
|
@pytest.mark.tags(CaseLabel.L1)
|
|
def test_construct_from_dataframe_dup_name(self):
|
|
"""
|
|
target: test collection with dup name and insert dataframe
|
|
method: create collection with dup name, none schema, dataframe
|
|
expected: two collection object is correct
|
|
"""
|
|
self._connect()
|
|
c_name = cf.gen_unique_str(prefix)
|
|
collection_w = self.init_collection_wrap(name=c_name, primary_field=ct.default_int64_field_name,
|
|
check_task=CheckTasks.check_collection_property,
|
|
check_items={exp_name: c_name, exp_schema: default_schema})
|
|
df = cf.gen_default_dataframe_data(ct.default_nb)
|
|
self.collection_wrap.construct_from_dataframe(c_name, df, primary_field=ct.default_int64_field_name,
|
|
check_task=CheckTasks.check_collection_property,
|
|
check_items={exp_name: c_name, exp_schema: default_schema})
|
|
# flush
|
|
assert collection_w.num_entities == ct.default_nb
|
|
assert collection_w.num_entities == self.collection_wrap.num_entities
|
|
|
|
|
|
class TestCollectionCount(TestcaseBase):
|
|
@pytest.mark.tags(CaseLabel.L2)
|
|
def test_collection_count_no_vectors(self):
|
|
"""
|
|
target: test collection rows_count is correct or not, if collection is empty
|
|
method: create collection and no vectors in it,
|
|
assert the value returned by num_entities attribute is equal to 0
|
|
expected: the count is equal to 0
|
|
"""
|
|
self._connect()
|
|
collection_w = self.init_collection_wrap()
|
|
assert collection_w.num_entities == 0
|
|
|
|
|
|
class TestCollectionCountIP(TestcaseBase):
|
|
"""
|
|
params means different nb, the nb value may trigger merge, or not
|
|
"""
|
|
|
|
@pytest.fixture(
|
|
scope="function",
|
|
params=[
|
|
1,
|
|
1000,
|
|
2001
|
|
],
|
|
)
|
|
def insert_count(self, request):
|
|
yield request.param
|
|
|
|
@pytest.mark.tags(CaseLabel.L1)
|
|
def test_collection_count_after_index_created(self, insert_count):
|
|
"""
|
|
target: test count_entities, after index have been created
|
|
method: add vectors in db, and create index, then calling num_entities with correct params
|
|
expected: count_entities raise exception
|
|
"""
|
|
self._connect()
|
|
collection_w = self.init_collection_wrap()
|
|
|
|
data = cf.gen_default_list_data(insert_count, ct.default_dim)
|
|
collection_w.insert(data)
|
|
|
|
collection_w.create_index(ct.default_float_vec_field_name, default_index_params,
|
|
index_name=ct.default_index_name)
|
|
assert collection_w.num_entities == insert_count
|
|
|
|
|
|
class TestCollectionCountBinary(TestcaseBase):
|
|
"""
|
|
params means different nb, the nb value may trigger merge, or not
|
|
"""
|
|
|
|
@pytest.fixture(
|
|
scope="function",
|
|
params=[
|
|
8,
|
|
1000,
|
|
2001
|
|
],
|
|
)
|
|
def insert_count(self, request):
|
|
yield request.param
|
|
|
|
# TODO: need to update and enable
|
|
@pytest.mark.tags(CaseLabel.L1)
|
|
def test_collection_count_after_index_created_binary(self, insert_count):
|
|
"""
|
|
target: test num_entities, after index have been created
|
|
method: add vectors in db, and create binary index, then calling num_entities with correct params
|
|
expected: num_entities equals entities count just inserted
|
|
"""
|
|
self._connect()
|
|
c_name = cf.gen_unique_str(prefix)
|
|
collection_w = self.init_collection_wrap(name=c_name, schema=default_binary_schema)
|
|
df, _ = cf.gen_default_binary_dataframe_data(insert_count)
|
|
mutation_res, _ = collection_w.insert(data=df)
|
|
collection_w.create_index(ct.default_binary_vec_field_name, default_binary_index_params)
|
|
assert collection_w.num_entities == insert_count
|
|
|
|
@pytest.mark.tags(CaseLabel.L1)
|
|
@pytest.mark.parametrize("auto_id", [True, False])
|
|
def test_binary_collection_with_min_dim(self, auto_id):
|
|
"""
|
|
target: test binary collection when dim=1
|
|
method: creat collection and set dim=1
|
|
expected: check error message successfully
|
|
"""
|
|
self._connect()
|
|
dim = ct.min_dim
|
|
c_schema = cf.gen_default_binary_collection_schema(auto_id=auto_id, dim=dim)
|
|
collection_w = self.init_collection_wrap(schema=c_schema,
|
|
check_task=CheckTasks.err_res,
|
|
check_items={"err_code": 1,
|
|
"err_msg": f"invalid dimension: {dim}. binary vector dimension should be multiple of 8."})
|
|
|
|
@pytest.mark.tags(CaseLabel.L2)
|
|
def test_collection_count_no_entities(self):
|
|
"""
|
|
target: test collection num_entities is correct or not, if collection is empty
|
|
method: create collection and no vectors in it,
|
|
assert the value returned by num_entities method is equal to 0
|
|
expected: the count is equal to 0
|
|
"""
|
|
self._connect()
|
|
c_name = cf.gen_unique_str(prefix)
|
|
collection_w = self.init_collection_wrap(name=c_name, schema=default_binary_schema)
|
|
assert collection_w.num_entities == 0
|
|
|
|
|
|
class TestCollectionMultiCollections(TestcaseBase):
|
|
"""
|
|
params means different nb, the nb value may trigger merge, or not
|
|
"""
|
|
|
|
@pytest.fixture(
|
|
scope="function",
|
|
params=[
|
|
1,
|
|
1000,
|
|
2001
|
|
],
|
|
)
|
|
def insert_count(self, request):
|
|
yield request.param
|
|
|
|
@pytest.mark.tags(CaseLabel.L0)
|
|
def test_collection_count_multi_collections_l2(self, insert_count):
|
|
"""
|
|
target: test collection rows_count is correct or not with multiple collections of L2
|
|
method: create collection and add entities in it,
|
|
assert the value returned by num_entities is equal to length of entities
|
|
expected: the count is equal to the length of entities
|
|
"""
|
|
self._connect()
|
|
data = cf.gen_default_list_data(insert_count)
|
|
collection_list = []
|
|
collection_num = 10
|
|
for i in range(collection_num):
|
|
collection_name = gen_unique_str(uid_count)
|
|
collection_w = self.init_collection_wrap(name=collection_name)
|
|
collection_w.insert(data)
|
|
collection_list.append(collection_name)
|
|
for i in range(collection_num):
|
|
res, _ = self.collection_wrap.init_collection(collection_list[i])
|
|
assert self.collection_wrap.num_entities == insert_count
|
|
|
|
@pytest.mark.tags(CaseLabel.L2)
|
|
def test_collection_count_multi_collections_binary(self, insert_count):
|
|
"""
|
|
target: test collection rows_count is correct or not with multiple collections of JACCARD
|
|
method: create collection and add entities in it,
|
|
assert the value returned by count_entities method is equal to length of entities
|
|
expected: the count is equal to the length of entities
|
|
"""
|
|
self._connect()
|
|
df, _ = cf.gen_default_binary_dataframe_data(insert_count)
|
|
collection_list = []
|
|
collection_num = 20
|
|
for i in range(collection_num):
|
|
c_name = cf.gen_unique_str(prefix)
|
|
collection_w = self.init_collection_wrap(name=c_name, schema=default_binary_schema)
|
|
mutation_res, _ = collection_w.insert(data=df)
|
|
collection_list.append(c_name)
|
|
for i in range(collection_num):
|
|
res, _ = self.collection_wrap.init_collection(collection_list[i])
|
|
assert self.collection_wrap.num_entities == insert_count
|
|
|
|
@pytest.mark.tags(CaseLabel.L2)
|
|
def test_collection_count_multi_collections_mix(self):
|
|
"""
|
|
target: test collection rows_count is correct or not with multiple collections of
|
|
method: create collection and add entities in it,
|
|
assert the value returned by count_entities method is equal to length of entities
|
|
expected: the count is equal to the length of entities
|
|
"""
|
|
self._connect()
|
|
collection_list = []
|
|
collection_num = 20
|
|
data = cf.gen_default_list_data()
|
|
df, _ = cf.gen_default_binary_dataframe_data(ct.default_nb)
|
|
for i in range(0, int(collection_num / 2)):
|
|
collection_name = gen_unique_str(uid_count)
|
|
collection_w = self.init_collection_wrap(name=collection_name)
|
|
collection_w.insert(data)
|
|
collection_list.append(collection_name)
|
|
for i in range(int(collection_num / 2), collection_num):
|
|
c_name = cf.gen_unique_str(prefix)
|
|
collection_w = self.init_collection_wrap(name=c_name, schema=default_binary_schema)
|
|
mutation_res, _ = collection_w.insert(data=df)
|
|
collection_list.append(c_name)
|
|
for i in range(collection_num):
|
|
res, _ = self.collection_wrap.init_collection(collection_list[i])
|
|
assert self.collection_wrap.num_entities == ct.default_nb
|
|
|
|
|
|
class TestCreateCollection(TestcaseBase):
|
|
|
|
@pytest.fixture(scope="function", params=[False, True])
|
|
def auto_id(self, request):
|
|
yield request.param
|
|
|
|
@pytest.mark.tags(CaseLabel.L1)
|
|
def test_create_collection_multithread(self):
|
|
"""
|
|
target: test create collection with multi-thread
|
|
method: create collection using multi-thread,
|
|
expected: collections are created
|
|
"""
|
|
self._connect()
|
|
threads_num = 8
|
|
threads = []
|
|
collection_names = []
|
|
|
|
def create():
|
|
collection_name = gen_unique_str(uid_create)
|
|
collection_names.append(collection_name)
|
|
self.init_collection_wrap(name=collection_name)
|
|
|
|
for i in range(threads_num):
|
|
t = MyThread(target=create, args=())
|
|
threads.append(t)
|
|
t.start()
|
|
time.sleep(0.2)
|
|
for t in threads:
|
|
t.join()
|
|
|
|
for item in collection_names:
|
|
assert item in self.utility_wrap.list_collections()[0]
|
|
|
|
@pytest.mark.tags(CaseLabel.L1)
|
|
@pytest.mark.skip("not support default_value now")
|
|
def test_create_collection_using_default_value(self, auto_id):
|
|
"""
|
|
target: test create collection with default_value
|
|
method: create a schema with all fields using default value
|
|
expected: collections are created
|
|
"""
|
|
fields = [
|
|
cf.gen_int64_field(name='pk', is_primary=True),
|
|
cf.gen_float_vec_field(),
|
|
cf.gen_int8_field(default_value=numpy.int8(8)),
|
|
cf.gen_int16_field(default_value=numpy.int16(16)),
|
|
cf.gen_int32_field(default_value=numpy.int32(32)),
|
|
cf.gen_int64_field(default_value=numpy.int64(64)),
|
|
cf.gen_float_field(default_value=numpy.float32(3.14)),
|
|
cf.gen_double_field(default_value=numpy.double(3.1415)),
|
|
cf.gen_bool_field(default_value=False),
|
|
cf.gen_string_field(default_value="abc")
|
|
]
|
|
schema = cf.gen_collection_schema(fields, auto_id=auto_id)
|
|
self.init_collection_wrap(schema=schema,
|
|
check_task=CheckTasks.check_collection_property,
|
|
check_items={"schema": schema})
|
|
|
|
|
|
class TestCreateCollectionInvalid(TestcaseBase):
|
|
"""
|
|
Test creating collections with invalid params
|
|
"""
|
|
|
|
@pytest.mark.tags(CaseLabel.L2)
|
|
def test_create_collection_limit_fields(self):
|
|
"""
|
|
target: test create collection with maximum fields
|
|
method: create collection with maximum field number
|
|
expected: raise exception
|
|
"""
|
|
self._connect()
|
|
c_name = cf.gen_unique_str(prefix)
|
|
limit_num = ct.max_field_num
|
|
field_schema_list = []
|
|
field_pr = cf.gen_int64_field(ct.default_int64_field_name, is_primary=True)
|
|
field_v = cf.gen_float_vec_field(ct.default_float_vec_field_name)
|
|
field_schema_list.append(field_pr)
|
|
field_schema_list.append(field_v)
|
|
|
|
for i in range(limit_num):
|
|
field_name_tmp = gen_unique_str("field_name")
|
|
field_schema_temp = cf.gen_int64_field(field_name_tmp)
|
|
field_schema_list.append(field_schema_temp)
|
|
error = {ct.err_code: 65535, ct.err_msg: "maximum field's number should be limited to 64"}
|
|
schema, _ = self.collection_schema_wrap.init_collection_schema(fields=field_schema_list)
|
|
self.init_collection_wrap(name=c_name, schema=schema, check_task=CheckTasks.err_res, check_items=error)
|
|
|
|
@pytest.mark.tags(CaseLabel.L2)
|
|
@pytest.mark.parametrize("invalid_name", ["中文", "español", "عربي", "हिंदी", "Русский"])
|
|
def test_create_schema_with_different_language(self, invalid_name):
|
|
"""
|
|
target: test create collection with maximum fields
|
|
method: create collection with maximum field number
|
|
expected: raise exception
|
|
"""
|
|
fields = [cf.gen_int64_field(is_primary=True), cf.gen_float_vec_field(),
|
|
cf.gen_string_field(name=invalid_name)]
|
|
schema = cf.gen_collection_schema(fields)
|
|
self.init_collection_wrap(schema=schema,
|
|
check_task=CheckTasks.err_res,
|
|
check_items={ct.err_code: 1701,
|
|
ct.err_msg: "Invalid field name: %s" % invalid_name})
|
|
|
|
@pytest.mark.tags(CaseLabel.L2)
|
|
@pytest.mark.parametrize("invalid_name", ["中文", "español", "عربي", "हिंदी", "Русский"])
|
|
def test_create_collection_with_different_language(self, invalid_name):
|
|
"""
|
|
target: test create collection with maximum fields
|
|
method: create collection with maximum field number
|
|
expected: raise exception
|
|
"""
|
|
schema = cf.gen_default_collection_schema()
|
|
self.init_collection_wrap(name=invalid_name, schema=schema,
|
|
check_task=CheckTasks.err_res,
|
|
check_items={ct.err_code: 1100,
|
|
ct.err_msg: "Invalid collection name: %s" % invalid_name})
|
|
|
|
@pytest.mark.tags(CaseLabel.L2)
|
|
@pytest.mark.parametrize("default_value", ["abc"])
|
|
@pytest.mark.skip(reason="issue #24634")
|
|
def test_create_collection_with_invalid_default_value_string(self, default_value):
|
|
"""
|
|
target: test create collection with maximum fields
|
|
method: create collection with maximum field number
|
|
expected: raise exception
|
|
"""
|
|
fields = [
|
|
cf.gen_int64_field(name='pk', is_primary=True),
|
|
cf.gen_float_vec_field(),
|
|
cf.gen_string_field(max_length=2, default_value=default_value)
|
|
]
|
|
schema = cf.gen_collection_schema(fields)
|
|
self.init_collection_wrap(schema=schema,
|
|
check_task=CheckTasks.check_collection_property,
|
|
check_items={"schema": schema})
|
|
|
|
@pytest.mark.tags(CaseLabel.L2)
|
|
@pytest.mark.skip("not support default_value now")
|
|
@pytest.mark.parametrize("default_value", ["abc", 9.09, 1, False])
|
|
def test_create_collection_with_invalid_default_value_float(self, default_value):
|
|
"""
|
|
target: test create collection with maximum fields
|
|
method: create collection with maximum field number
|
|
expected: raise exception
|
|
"""
|
|
fields = [
|
|
cf.gen_int64_field(name='pk', is_primary=True),
|
|
cf.gen_float_vec_field(),
|
|
cf.gen_float_field(default_value=default_value)
|
|
]
|
|
schema = cf.gen_collection_schema(fields)
|
|
self.init_collection_wrap(schema=schema, check_task=CheckTasks.err_res,
|
|
check_items={ct.err_code: 1,
|
|
ct.err_msg: "default value type mismatches field schema type"})
|
|
|
|
@pytest.mark.tags(CaseLabel.L2)
|
|
@pytest.mark.skip("not support default_value now")
|
|
@pytest.mark.parametrize("default_value", ["abc", 9.09, 1, False])
|
|
def test_create_collection_with_invalid_default_value_int8(self, default_value):
|
|
"""
|
|
target: test create collection with maximum fields
|
|
method: create collection with maximum field number
|
|
expected: raise exception
|
|
"""
|
|
fields = [
|
|
cf.gen_int64_field(name='pk', is_primary=True),
|
|
cf.gen_float_vec_field(),
|
|
cf.gen_int8_field(default_value=default_value)
|
|
]
|
|
schema = cf.gen_collection_schema(fields)
|
|
self.init_collection_wrap(schema=schema, check_task=CheckTasks.err_res,
|
|
check_items={ct.err_code: 1,
|
|
ct.err_msg: "default value type mismatches field schema type"})
|
|
|
|
@pytest.mark.tags(CaseLabel.L2)
|
|
@pytest.mark.skip("not support default_value now")
|
|
def test_create_collection_with_pk_field_using_default_value(self):
|
|
"""
|
|
target: test create collection with pk field using default value
|
|
method: create a pk field and set default value
|
|
expected: report error
|
|
"""
|
|
# 1. pk int64
|
|
fields = [
|
|
cf.gen_int64_field(name='pk', is_primary=True, default_value=np.int64(1)),
|
|
cf.gen_float_vec_field(), cf.gen_string_field(max_length=2)
|
|
]
|
|
schema = cf.gen_collection_schema(fields)
|
|
collection_w = self.init_collection_wrap(schema=schema)
|
|
collection_w.insert([[], [vectors[0]], ["a"]],
|
|
check_task=CheckTasks.err_res,
|
|
check_items={ct.err_code: 1,
|
|
ct.err_msg: "pk field schema can not set default value"})
|
|
# 2. pk string
|
|
fields = [
|
|
cf.gen_string_field(name='pk', is_primary=True, default_value="a"),
|
|
cf.gen_float_vec_field(), cf.gen_string_field(max_length=2)
|
|
]
|
|
schema = cf.gen_collection_schema(fields)
|
|
collection_w = self.init_collection_wrap(schema=schema)
|
|
collection_w.insert([[], [vectors[0]], ["a"]],
|
|
check_task=CheckTasks.err_res,
|
|
check_items={ct.err_code: 1,
|
|
ct.err_msg: "pk field schema can not set default value"})
|
|
|
|
@pytest.mark.tags(CaseLabel.L2)
|
|
@pytest.mark.skip("not support default_value now")
|
|
def test_create_collection_with_json_field_using_default_value(self):
|
|
"""
|
|
target: test create collection with json field using default value
|
|
method: create a json field and set default value
|
|
expected: report error
|
|
"""
|
|
json_default_value = {"number": 1, "float": 2.0, "string": "abc", "bool": True,
|
|
"list": [i for i in range(5)]}
|
|
cf.gen_json_field(default_value=json_default_value,
|
|
check_task=CheckTasks.err_res,
|
|
check_items={ct.err_code: 1,
|
|
ct.err_msg: "Default value unsupported data type: 999"})
|
|
|
|
|
|
class TestDropCollection(TestcaseBase):
|
|
"""
|
|
******************************************************************
|
|
The following cases are used to test `drop_collection` function
|
|
******************************************************************
|
|
"""
|
|
|
|
@pytest.mark.tags(CaseLabel.L0)
|
|
def test_drop_collection_A(self):
|
|
"""
|
|
target: test delete collection created with correct params
|
|
method: create collection and then delete,
|
|
assert the value returned by delete method
|
|
expected: status ok, and no collection in collections
|
|
"""
|
|
self._connect()
|
|
c_name = cf.gen_unique_str()
|
|
collection_wr = self.init_collection_wrap(name=c_name)
|
|
collection_wr.drop()
|
|
assert not self.utility_wrap.has_collection(c_name)[0]
|
|
|
|
@pytest.mark.tags(CaseLabel.L2)
|
|
def test_drop_collection_without_connection(self):
|
|
"""
|
|
target: test describe collection, without connection
|
|
method: drop collection with correct params, with a disconnected instance
|
|
expected: drop raise exception
|
|
"""
|
|
self._connect()
|
|
c_name = cf.gen_unique_str(prefix)
|
|
collection_wr = self.init_collection_wrap(c_name)
|
|
self.connection_wrap.remove_connection(ct.default_alias)
|
|
res_list, _ = self.connection_wrap.list_connections()
|
|
assert ct.default_alias not in res_list
|
|
error = {ct.err_code: 1, ct.err_msg: 'should create connect first'}
|
|
collection_wr.drop(check_task=CheckTasks.err_res, check_items=error)
|
|
|
|
@pytest.mark.tags(CaseLabel.L1)
|
|
def test_drop_collection_not_existed(self):
|
|
"""
|
|
target: test if collection not created
|
|
method: random a collection name, which not existed in db,
|
|
assert the exception raised returned by drp_collection method
|
|
expected: False
|
|
"""
|
|
self._connect()
|
|
c_name = cf.gen_unique_str()
|
|
self.init_collection_wrap(name=c_name)
|
|
c_name_2 = cf.gen_unique_str()
|
|
# error = {ct.err_code: 0, ct.err_msg: 'DescribeCollection failed: collection not found: %s' % c_name_2}
|
|
# self.utility_wrap.drop_collection(c_name_2, check_task=CheckTasks.err_res, check_items=error)
|
|
# @longjiquan: dropping collection should be idempotent.
|
|
self.utility_wrap.drop_collection(c_name_2)
|
|
|
|
@pytest.mark.tags(CaseLabel.L1)
|
|
def test_create_drop_collection_multithread(self):
|
|
"""
|
|
target: test create and drop collection with multi-thread
|
|
method: create and drop collection using multi-thread,
|
|
expected: collections are created, and dropped
|
|
"""
|
|
self._connect()
|
|
threads_num = 8
|
|
threads = []
|
|
collection_names = []
|
|
|
|
def create():
|
|
c_name = cf.gen_unique_str()
|
|
collection_names.append(c_name)
|
|
collection_wr = self.init_collection_wrap(name=c_name)
|
|
collection_wr.drop()
|
|
|
|
for i in range(threads_num):
|
|
t = MyThread(target=create, args=())
|
|
threads.append(t)
|
|
t.start()
|
|
time.sleep(0.2)
|
|
for t in threads:
|
|
t.join()
|
|
|
|
for item in collection_names:
|
|
assert not self.utility_wrap.has_collection(item)[0]
|
|
|
|
|
|
class TestDropCollectionInvalid(TestcaseBase):
|
|
"""
|
|
Test drop collection with invalid params
|
|
"""
|
|
|
|
@pytest.mark.tags(CaseLabel.L2)
|
|
@pytest.mark.parametrize("name", ["12-s", "12 s", "(mn)", "中文", "%$#", "a".join("a" for i in range(256))])
|
|
def test_drop_collection_with_invalid_collection_name(self, name):
|
|
"""
|
|
target: test drop invalid collection
|
|
method: drop collection with invalid collection name
|
|
expected: raise exception
|
|
"""
|
|
self._connect()
|
|
error = {ct.err_code: 1, ct.err_msg: "Invalid collection name: {}".format(name)}
|
|
self.utility_wrap.drop_collection(name, check_task=CheckTasks.err_res, check_items=error)
|
|
|
|
@pytest.mark.tags(CaseLabel.L2)
|
|
def test_drop_collection_with_empty_or_None_collection_name(self):
|
|
"""
|
|
target: test drop invalid collection
|
|
method: drop collection with empty or None collection name
|
|
expected: raise exception
|
|
"""
|
|
self._connect()
|
|
error = {ct.err_code: -1, ct.err_msg: '`collection_name` value is illegal'}
|
|
self.utility_wrap.drop_collection('', check_task=CheckTasks.err_res, check_items=error)
|
|
error_none = {ct.err_code: -1, ct.err_msg: '`collection_name` value None is illegal'}
|
|
self.utility_wrap.drop_collection(None, check_task=CheckTasks.err_res, check_items=error_none)
|
|
|
|
|
|
class TestHasCollection(TestcaseBase):
|
|
"""
|
|
******************************************************************
|
|
The following cases are used to test `has_collection` function
|
|
******************************************************************
|
|
"""
|
|
|
|
@pytest.mark.tags(CaseLabel.L2)
|
|
def test_has_collection_without_connection(self):
|
|
"""
|
|
target: test has collection, without connection
|
|
method: calling has collection with correct params, with a disconnected instance
|
|
expected: has collection raise exception
|
|
"""
|
|
self._connect()
|
|
c_name = cf.gen_unique_str(prefix)
|
|
self.init_collection_wrap(c_name)
|
|
self.connection_wrap.remove_connection(ct.default_alias)
|
|
res_list, _ = self.connection_wrap.list_connections()
|
|
assert ct.default_alias not in res_list
|
|
error = {ct.err_code: 1, ct.err_msg: 'should create connect first'}
|
|
self.utility_wrap.has_collection(c_name, check_task=CheckTasks.err_res, check_items=error)
|
|
|
|
@pytest.mark.tags(CaseLabel.L2)
|
|
def test_has_collection_not_existed(self):
|
|
"""
|
|
target: test if collection not created
|
|
method: random a collection name, create this collection then drop it,
|
|
assert the value returned by has_collection method
|
|
expected: False
|
|
"""
|
|
self._connect()
|
|
c_name = cf.gen_unique_str()
|
|
collection_wr = self.init_collection_wrap(name=c_name)
|
|
collection_wr.drop()
|
|
assert not self.utility_wrap.has_collection(c_name)[0]
|
|
|
|
@pytest.mark.tags(CaseLabel.L2)
|
|
def test_has_collection_multithread(self):
|
|
"""
|
|
target: test create collection with multi-thread
|
|
method: create collection using multi-thread,
|
|
expected: collections are created
|
|
"""
|
|
self._connect()
|
|
threads_num = 4
|
|
threads = []
|
|
c_name = cf.gen_unique_str()
|
|
self.init_collection_wrap(name=c_name)
|
|
|
|
def has():
|
|
assert self.utility_wrap.has_collection(c_name)
|
|
# assert not assert_collection(connect, collection_name)
|
|
|
|
for i in range(threads_num):
|
|
t = MyThread(target=has, args=())
|
|
threads.append(t)
|
|
t.start()
|
|
time.sleep(0.2)
|
|
for t in threads:
|
|
t.join()
|
|
|
|
|
|
class TestHasCollectionInvalid(TestcaseBase):
|
|
@pytest.mark.tags(CaseLabel.L2)
|
|
@pytest.mark.parametrize("name", ["12-s", "12 s", "(mn)", "中文", "%$#", "a".join("a" for i in range(256))])
|
|
def test_has_collection_with_invalid_collection_name(self, name):
|
|
"""
|
|
target: test list collections with invalid scenario
|
|
method: show collection with invalid collection name
|
|
expected: raise exception
|
|
"""
|
|
self._connect()
|
|
error = {ct.err_code: 1, ct.err_msg: "Invalid collection name: {}".format(name)}
|
|
self.utility_wrap.has_collection(name, check_task=CheckTasks.err_res, check_items=error)
|
|
|
|
@pytest.mark.tags(CaseLabel.L2)
|
|
def test_has_collection_with_empty_collection_name(self):
|
|
"""
|
|
target: test list collections with invalid scenario
|
|
method: show collection with empty collection name
|
|
expected: raise exception
|
|
"""
|
|
self._connect()
|
|
error = {ct.err_code: -1, ct.err_msg: '`collection_name` value is illegal'}
|
|
self.utility_wrap.has_collection('', check_task=CheckTasks.err_res, check_items=error)
|
|
|
|
@pytest.mark.tags(CaseLabel.L2)
|
|
def test_has_collection_with_none_collection_name(self):
|
|
"""
|
|
target: test list collections with invalid scenario
|
|
method: show collection with no collection name
|
|
expected: raise exception
|
|
"""
|
|
self._connect()
|
|
error = {ct.err_code: -1, ct.err_msg: '`collection_name` value None is illegal'}
|
|
self.utility_wrap.has_collection(None, check_task=CheckTasks.err_res, check_items=error)
|
|
|
|
|
|
class TestListCollections(TestcaseBase):
|
|
"""
|
|
******************************************************************
|
|
The following cases are used to test `utility.list_collections()` function
|
|
******************************************************************
|
|
"""
|
|
|
|
@pytest.mark.tags(CaseLabel.L0)
|
|
def test_list_collections_multi_collections(self):
|
|
"""
|
|
target: test list collections
|
|
method: create collection, assert the value returned by list_collections method
|
|
expected: True
|
|
"""
|
|
self._connect()
|
|
collection_num = 50
|
|
collection_names = []
|
|
for i in range(collection_num):
|
|
collection_name = cf.gen_unique_str()
|
|
collection_names.append(collection_name)
|
|
self.init_collection_wrap(name=collection_name)
|
|
for i in range(collection_num):
|
|
assert collection_names[i] in self.utility_wrap.list_collections()[0]
|
|
self.utility_wrap.drop_collection(collection_names[i])
|
|
|
|
@pytest.mark.tags(CaseLabel.L2)
|
|
def test_list_collections_without_connection(self):
|
|
"""
|
|
target: test list collections, without connection
|
|
method: calling list collections with correct params, with a disconnected instance
|
|
expected: list collections raise exception
|
|
"""
|
|
self._connect()
|
|
self.connection_wrap.remove_connection(ct.default_alias)
|
|
res_list, _ = self.connection_wrap.list_connections()
|
|
assert ct.default_alias not in res_list
|
|
error = {ct.err_code: 1, ct.err_msg: 'should create connect first'}
|
|
self.utility_wrap.list_collections(check_task=CheckTasks.err_res, check_items=error)
|
|
|
|
@pytest.mark.tags(CaseLabel.L2)
|
|
def test_list_collections_multithread(self):
|
|
"""
|
|
target: test list collection with multi-threads
|
|
method: list collection using multi-threads
|
|
expected: list collections correctly
|
|
"""
|
|
self._connect()
|
|
threads_num = 10
|
|
threads = []
|
|
collection_name = cf.gen_unique_str()
|
|
self.init_collection_wrap(name=collection_name)
|
|
|
|
def _list():
|
|
assert collection_name in self.utility_wrap.list_collections()[0]
|
|
|
|
for i in range(threads_num):
|
|
t = MyThread(target=_list)
|
|
threads.append(t)
|
|
t.start()
|
|
time.sleep(0.2)
|
|
for t in threads:
|
|
t.join()
|
|
|
|
|
|
class TestLoadCollection(TestcaseBase):
|
|
"""
|
|
******************************************************************
|
|
The following cases are used to test `collection.load()` function
|
|
******************************************************************
|
|
"""
|
|
|
|
@pytest.mark.tags(CaseLabel.L0)
|
|
def test_load_collection_after_index(self):
|
|
"""
|
|
target: test load collection, after index created
|
|
method: insert and create index, load collection with correct params
|
|
expected: no error raised
|
|
"""
|
|
self._connect()
|
|
collection_w = self.init_collection_wrap()
|
|
data = cf.gen_default_list_data()
|
|
collection_w.insert(data)
|
|
collection_w.create_index(ct.default_float_vec_field_name, default_index_params,
|
|
index_name=ct.default_index_name)
|
|
collection_w.load()
|
|
collection_w.release()
|
|
|
|
@pytest.mark.tags(CaseLabel.L1)
|
|
def test_load_collection_after_index_binary(self):
|
|
"""
|
|
target: test load binary_collection, after index created
|
|
method: insert and create index, load binary_collection with correct params
|
|
expected: no error raised
|
|
"""
|
|
self._connect()
|
|
c_name = cf.gen_unique_str(prefix)
|
|
collection_w = self.init_collection_wrap(name=c_name, schema=default_binary_schema)
|
|
df, _ = cf.gen_default_binary_dataframe_data(ct.default_nb)
|
|
mutation_res, _ = collection_w.insert(data=df)
|
|
collection_w.create_index(ct.default_binary_vec_field_name, default_binary_index_params)
|
|
collection_w.load()
|
|
collection_w.release()
|
|
|
|
@pytest.mark.tags(CaseLabel.L2)
|
|
def test_load_empty_collection(self):
|
|
"""
|
|
target: test load an empty collection with no data inserted
|
|
method: no entities in collection, load and release the collection
|
|
expected: load and release successfully
|
|
"""
|
|
self._connect()
|
|
collection_w = self.init_collection_wrap()
|
|
collection_w.create_index(ct.default_float_vec_field_name, index_params=ct.default_flat_index)
|
|
collection_w.load()
|
|
collection_w.release()
|
|
|
|
@pytest.mark.tags(CaseLabel.L2)
|
|
def test_load_collection_dis_connect(self):
|
|
"""
|
|
target: test load collection, without connection
|
|
method: load collection with correct params, with a disconnected instance
|
|
expected: load raise exception
|
|
"""
|
|
self._connect()
|
|
c_name = cf.gen_unique_str(prefix)
|
|
collection_wr = self.init_collection_wrap(c_name)
|
|
self.connection_wrap.remove_connection(ct.default_alias)
|
|
res_list, _ = self.connection_wrap.list_connections()
|
|
assert ct.default_alias not in res_list
|
|
error = {ct.err_code: 1, ct.err_msg: 'should create connect first'}
|
|
collection_wr.load(check_task=CheckTasks.err_res, check_items=error)
|
|
|
|
@pytest.mark.tags(CaseLabel.L2)
|
|
def test_release_collection_dis_connect(self):
|
|
"""
|
|
target: test release collection, without connection
|
|
method: release collection with correct params, with a disconnected instance
|
|
expected: release raise exception
|
|
"""
|
|
self._connect()
|
|
c_name = cf.gen_unique_str(prefix)
|
|
collection_wr = self.init_collection_wrap(c_name)
|
|
self.connection_wrap.remove_connection(ct.default_alias)
|
|
res_list, _ = self.connection_wrap.list_connections()
|
|
assert ct.default_alias not in res_list
|
|
error = {ct.err_code: 1, ct.err_msg: 'should create connect first'}
|
|
collection_wr.release(check_task=CheckTasks.err_res, check_items=error)
|
|
|
|
@pytest.mark.tags(CaseLabel.L2)
|
|
def test_load_collection_not_existed(self):
|
|
"""
|
|
target: test load invalid collection
|
|
method: load not existed collection
|
|
expected: raise exception
|
|
"""
|
|
self._connect()
|
|
c_name = cf.gen_unique_str()
|
|
collection_wr = self.init_collection_wrap(name=c_name)
|
|
collection_wr.drop()
|
|
error = {ct.err_code: 100,
|
|
ct.err_msg: "collection= : collection not found"}
|
|
collection_wr.load(check_task=CheckTasks.err_res, check_items=error)
|
|
|
|
@pytest.mark.tags(CaseLabel.L2)
|
|
def test_release_collection_not_existed(self):
|
|
"""
|
|
target: test release a not existed collection
|
|
method: release with a not existed collection name
|
|
expected: raise exception
|
|
"""
|
|
self._connect()
|
|
c_name = cf.gen_unique_str()
|
|
collection_wr = self.init_collection_wrap(name=c_name)
|
|
collection_wr.drop()
|
|
error = {ct.err_code: 100,
|
|
ct.err_msg: "collection= : collection not found"}
|
|
collection_wr.release(check_task=CheckTasks.err_res, check_items=error)
|
|
|
|
@pytest.mark.tags(CaseLabel.L2)
|
|
def test_release_collection_not_load(self):
|
|
"""
|
|
target: test release collection without load
|
|
method: release collection without load
|
|
expected: release successfully
|
|
"""
|
|
self._connect()
|
|
c_name = cf.gen_unique_str()
|
|
collection_wr = self.init_collection_wrap(name=c_name)
|
|
collection_wr.release()
|
|
|
|
@pytest.mark.tags(CaseLabel.L0)
|
|
def test_load_collection_after_load_release(self):
|
|
"""
|
|
target: test load collection after load and release
|
|
method: 1.load and release collection after entities flushed
|
|
2.re-load collection
|
|
expected: No exception
|
|
"""
|
|
self._connect()
|
|
collection_w = self.init_collection_wrap()
|
|
insert_data = cf.gen_default_list_data()
|
|
collection_w.insert(data=insert_data)
|
|
assert collection_w.num_entities == ct.default_nb
|
|
collection_w.create_index(ct.default_float_vec_field_name, index_params=ct.default_flat_index)
|
|
collection_w.load()
|
|
collection_w.release()
|
|
collection_w.load()
|
|
|
|
@pytest.mark.tags(CaseLabel.L2)
|
|
def test_load_collection_repeatedly(self):
|
|
"""
|
|
target: test load collection repeatedly
|
|
method: load collection twice
|
|
expected: No exception
|
|
"""
|
|
self._connect()
|
|
collection_w = self.init_collection_wrap()
|
|
insert_data = cf.gen_default_list_data()
|
|
collection_w.insert(data=insert_data)
|
|
assert collection_w.num_entities == ct.default_nb
|
|
collection_w.create_index(ct.default_float_vec_field_name, index_params=ct.default_flat_index)
|
|
collection_w.load()
|
|
collection_w.load()
|
|
|
|
@pytest.mark.tags(CaseLabel.L1)
|
|
def test_load_partitions_after_load_collection(self):
|
|
"""
|
|
target: test load partitions after load collection
|
|
method: 1. load collection
|
|
2. load partitions
|
|
3. search on one partition
|
|
expected: No exception
|
|
"""
|
|
collection_w = self.init_collection_general(prefix)[0]
|
|
self.init_partition_wrap(collection_w, partition1)
|
|
self.init_partition_wrap(collection_w, partition2)
|
|
collection_w.load()
|
|
collection_w.load(partition_names=[partition1, partition2])
|
|
res = collection_w.search(vectors, default_search_field, default_search_params,
|
|
default_limit, partition_names=[partition1])
|
|
|
|
@pytest.mark.tags(CaseLabel.L2)
|
|
def test_load_partitions_after_load_release_collection(self):
|
|
"""
|
|
target: test load partitions after load release collection
|
|
method: 1. load collection
|
|
2. release collection
|
|
3. load partitions
|
|
4. search on one partition
|
|
expected: No exception
|
|
"""
|
|
collection_w = self.init_collection_general(prefix)[0]
|
|
self.init_partition_wrap(collection_w, partition1)
|
|
self.init_partition_wrap(collection_w, partition2)
|
|
collection_w.load()
|
|
collection_w.release()
|
|
collection_w.load(partition_names=[partition1, partition2])
|
|
collection_w.search(vectors, default_search_field, default_search_params,
|
|
default_limit, partition_names=[partition1])
|
|
|
|
@pytest.mark.tags(CaseLabel.L2)
|
|
def test_load_collection_after_release_collection_partition(self):
|
|
"""
|
|
target: test load collection after release collection and partition
|
|
method: 1. load collection
|
|
2. release collection
|
|
3. release one partition
|
|
4. load collection
|
|
5. search on the partition
|
|
expected: No exception
|
|
"""
|
|
collection_w = self.init_collection_general(prefix)[0]
|
|
partition_w = self.init_partition_wrap(collection_w, partition1)
|
|
self.init_partition_wrap(collection_w, partition2)
|
|
collection_w.load()
|
|
collection_w.release()
|
|
partition_w.release()
|
|
collection_w.load()
|
|
collection_w.search(vectors, default_search_field, default_search_params,
|
|
default_limit, partition_names=[partition1])
|
|
|
|
@pytest.mark.tags(CaseLabel.L2)
|
|
def test_load_partitions_after_release_collection_partition(self):
|
|
"""
|
|
target: test load partitions after release collection and partition
|
|
method: 1. load collection
|
|
2. release collection
|
|
3. release partition
|
|
4. search on the partition and report error
|
|
5. load partitions
|
|
6. search on the partition
|
|
expected: No exception
|
|
"""
|
|
collection_w = self.init_collection_general(prefix)[0]
|
|
partition_w1 = self.init_partition_wrap(collection_w, partition1)
|
|
partition_w2 = self.init_partition_wrap(collection_w, partition2)
|
|
collection_w.load()
|
|
collection_w.release()
|
|
partition_w1.release()
|
|
collection_w.search(vectors, default_search_field, default_search_params,
|
|
default_limit, partition_names=[partition1],
|
|
check_task=CheckTasks.err_res,
|
|
check_items={ct.err_code: 1,
|
|
ct.err_msg: "not loaded"})
|
|
partition_w1.load()
|
|
partition_w2.load()
|
|
collection_w.search(vectors, default_search_field, default_search_params,
|
|
default_limit, partition_names=[partition1])
|
|
|
|
@pytest.mark.tags(CaseLabel.L2)
|
|
def test_load_collection_after_release_partition(self):
|
|
"""
|
|
target: test load collection after load collection and release partition
|
|
method: 1. load collection
|
|
2. release one partition
|
|
3. search on the released partition and report error
|
|
4. search on the non-released partition and raise no exception
|
|
3. load collection
|
|
expected: No exception
|
|
"""
|
|
collection_w = self.init_collection_general(prefix)[0]
|
|
partition_w1 = self.init_partition_wrap(collection_w, partition1)
|
|
partition_w2 = self.init_partition_wrap(collection_w, partition2)
|
|
collection_w.load()
|
|
partition_w1.release()
|
|
collection_w.search(vectors, default_search_field, default_search_params,
|
|
default_limit, partition_names=[partition1],
|
|
check_task=CheckTasks.err_res,
|
|
check_items={ct.err_code: 1,
|
|
ct.err_msg: "not loaded"})
|
|
collection_w.search(vectors, default_search_field, default_search_params,
|
|
default_limit, partition_names=[partition2])
|
|
collection_w.load()
|
|
|
|
@pytest.mark.tags(CaseLabel.L2)
|
|
def test_load_partitions_after_release_partition(self):
|
|
"""
|
|
target: test load collection after release partition and load partitions
|
|
method: 1. load collection
|
|
2. release partition
|
|
3. search on the released partition and report error
|
|
4. load partitions
|
|
expected: No exception
|
|
"""
|
|
collection_w = self.init_collection_general(prefix)[0]
|
|
partition_w1 = self.init_partition_wrap(collection_w, partition1)
|
|
partition_w2 = self.init_partition_wrap(collection_w, partition2)
|
|
collection_w.load()
|
|
partition_w1.release()
|
|
collection_w.search(vectors, default_search_field, default_search_params,
|
|
default_limit, partition_names=[partition1],
|
|
check_task=CheckTasks.err_res,
|
|
check_items={ct.err_code: 1,
|
|
ct.err_msg: "not loaded"})
|
|
partition_w1.load()
|
|
partition_w2.load()
|
|
|
|
@pytest.mark.tags(CaseLabel.L2)
|
|
def test_load_collection_after_release_partition_collection(self):
|
|
"""
|
|
target: test load collection after release partition and collection
|
|
method: 1. load collection
|
|
2. release partition
|
|
3. query on the released partition and report error
|
|
3. release collection
|
|
4. load collection
|
|
expected: No exception
|
|
"""
|
|
collection_w = self.init_collection_general(prefix)[0]
|
|
partition_w = self.init_partition_wrap(collection_w, partition1)
|
|
self.init_partition_wrap(collection_w, partition2)
|
|
collection_w.load()
|
|
partition_w.release()
|
|
error = {ct.err_code: 65538, ct.err_msg: 'partition not loaded'}
|
|
collection_w.query(default_term_expr, partition_names=[partition1],
|
|
check_task=CheckTasks.err_res, check_items=error)
|
|
collection_w.release()
|
|
collection_w.load()
|
|
|
|
@pytest.mark.tags(CaseLabel.L2)
|
|
def test_load_partitions_after_release_partition_collection(self):
|
|
"""
|
|
target: test load partitions after release partition and collection
|
|
method: 1. load collection
|
|
2. release partition
|
|
3. release collection
|
|
4. load one partition
|
|
5. query on the other partition and raise error
|
|
6. load the other partition
|
|
expected: No exception
|
|
"""
|
|
collection_w = self.init_collection_general(prefix)[0]
|
|
partition_w1 = self.init_partition_wrap(collection_w, partition1)
|
|
partition_w2 = self.init_partition_wrap(collection_w, partition2)
|
|
collection_w.load()
|
|
partition_w1.release()
|
|
collection_w.release()
|
|
partition_w1.load()
|
|
error = {ct.err_code: 65538, ct.err_msg: 'partition not loaded'}
|
|
collection_w.query(default_term_expr, partition_names=[partition2],
|
|
check_task=CheckTasks.err_res, check_items=error)
|
|
partition_w2.load()
|
|
|
|
@pytest.mark.tags(CaseLabel.L2)
|
|
def test_load_collection_after_release_partitions(self):
|
|
"""
|
|
target: test load collection after release partitions
|
|
method: 1. load collection
|
|
2. release partitions
|
|
3. load collection
|
|
expected: No exception
|
|
"""
|
|
collection_w = self.init_collection_general(prefix)[0]
|
|
partition_w1 = self.init_partition_wrap(collection_w, partition1)
|
|
partition_w2 = self.init_partition_wrap(collection_w, partition2)
|
|
collection_w.load()
|
|
partition_w1.release()
|
|
partition_w2.release()
|
|
collection_w.load()
|
|
|
|
@pytest.mark.tags(CaseLabel.L2)
|
|
def test_load_partitions_after_release_partitions(self):
|
|
"""
|
|
target: test load partitions after release partitions
|
|
method: 1. load collection
|
|
2. release partitions
|
|
3. load partitions
|
|
expected: No exception
|
|
"""
|
|
collection_w = self.init_collection_general(prefix)[0]
|
|
partition_w1 = self.init_partition_wrap(collection_w, partition1)
|
|
partition_w2 = self.init_partition_wrap(collection_w, partition2)
|
|
collection_w.load()
|
|
partition_w1.release()
|
|
partition_w2.release()
|
|
partition_w1.load()
|
|
partition_w2.load()
|
|
|
|
@pytest.mark.tags(CaseLabel.L2)
|
|
def test_load_collection_after_drop_partition_and_release_another(self):
|
|
"""
|
|
target: test load collection after drop a partition and release another
|
|
method: 1. load collection
|
|
2. drop a partition
|
|
3. release left partition
|
|
4. query on the left partition
|
|
5. load collection
|
|
expected: No exception
|
|
"""
|
|
collection_w = self.init_collection_general(prefix)[0]
|
|
partition_w1 = self.init_partition_wrap(collection_w, partition1)
|
|
partition_w2 = self.init_partition_wrap(collection_w, partition2)
|
|
collection_w.load()
|
|
partition_w1.release()
|
|
partition_w1.drop()
|
|
partition_w2.release()
|
|
error = {ct.err_code: 65538, ct.err_msg: 'partition not loaded'}
|
|
collection_w.query(default_term_expr, partition_names=[partition2],
|
|
check_task=CheckTasks.err_res, check_items=error)
|
|
collection_w.load()
|
|
|
|
@pytest.mark.tags(CaseLabel.L2)
|
|
def test_load_partition_after_drop_partition_and_release_another(self):
|
|
"""
|
|
target: test load partition after drop a partition and release another
|
|
method: 1. load collection
|
|
2. drop a partition
|
|
3. release left partition
|
|
4. load partition
|
|
5. query on the partition
|
|
expected: No exception
|
|
"""
|
|
collection_w = self.init_collection_general(prefix)[0]
|
|
partition_w1 = self.init_partition_wrap(collection_w, partition1)
|
|
partition_w2 = self.init_partition_wrap(collection_w, partition2)
|
|
collection_w.load()
|
|
partition_w1.release()
|
|
partition_w1.drop()
|
|
partition_w2.release()
|
|
partition_w2.load()
|
|
collection_w.query(default_term_expr, partition_names=[partition2])
|
|
|
|
@pytest.mark.tags(CaseLabel.L2)
|
|
def test_load_another_partition_after_drop_one_partition(self):
|
|
"""
|
|
target: test load another partition after drop a partition
|
|
method: 1. load collection
|
|
2. drop a partition
|
|
3. load another partition
|
|
4. query on the partition
|
|
expected: No exception
|
|
"""
|
|
collection_w = self.init_collection_general(prefix)[0]
|
|
partition_w1 = self.init_partition_wrap(collection_w, partition1)
|
|
partition_w2 = self.init_partition_wrap(collection_w, partition2)
|
|
collection_w.load()
|
|
partition_w1.release()
|
|
partition_w1.drop()
|
|
partition_w2.load()
|
|
collection_w.query(default_term_expr, partition_names=[partition2])
|
|
|
|
@pytest.mark.tags(CaseLabel.L2)
|
|
def test_load_collection_after_drop_one_partition(self):
|
|
"""
|
|
target: test load collection after drop a partition
|
|
method: 1. load collection
|
|
2. drop a partition
|
|
3. load collection
|
|
4. query on the partition
|
|
expected: No exception
|
|
"""
|
|
collection_w = self.init_collection_general(prefix)[0]
|
|
partition_w1 = self.init_partition_wrap(collection_w, partition1)
|
|
partition_w2 = self.init_partition_wrap(collection_w, partition2)
|
|
collection_w.load()
|
|
partition_w1.release()
|
|
partition_w1.drop()
|
|
collection_w.load()
|
|
collection_w.query(default_term_expr, partition_names=[partition2])
|
|
|
|
@pytest.mark.tags(CaseLabel.L2)
|
|
def test_load_release_collection(self):
|
|
"""
|
|
target: test load, release non-exist collection
|
|
method: 1. load, release and drop collection
|
|
2. load and release dropped collection
|
|
expected: raise exception
|
|
"""
|
|
self._connect()
|
|
c_name = cf.gen_unique_str()
|
|
collection_wr = self.init_collection_wrap(name=c_name)
|
|
collection_wr.create_index(ct.default_float_vec_field_name, index_params=ct.default_flat_index)
|
|
collection_wr.load()
|
|
collection_wr.release()
|
|
collection_wr.drop()
|
|
error = {ct.err_code: 100, ct.err_msg: "collection not found"}
|
|
collection_wr.load(check_task=CheckTasks.err_res, check_items=error)
|
|
collection_wr.release(check_task=CheckTasks.err_res, check_items=error)
|
|
|
|
@pytest.mark.tags(CaseLabel.L2)
|
|
def test_release_collection_after_drop(self):
|
|
"""
|
|
target: test release collection after drop
|
|
method: insert and flush, then release collection after load and drop
|
|
expected: raise exception
|
|
"""
|
|
self._connect()
|
|
c_name = cf.gen_unique_str()
|
|
collection_wr = self.init_collection_wrap(name=c_name)
|
|
collection_wr.create_index(ct.default_float_vec_field_name, index_params=ct.default_flat_index)
|
|
collection_wr.load()
|
|
collection_wr.drop()
|
|
error = {ct.err_code: 100, ct.err_msg: "collection not found"}
|
|
collection_wr.release(check_task=CheckTasks.err_res, check_items=error)
|
|
|
|
@pytest.mark.tags(CaseLabel.L1)
|
|
def test_load_partition_names_empty(self):
|
|
"""
|
|
target: test query another partition
|
|
method: 1. insert entities into two partitions
|
|
2.query on one partition and query result empty
|
|
expected: query result is empty
|
|
"""
|
|
self._connect()
|
|
collection_w = self.init_collection_wrap(name=cf.gen_unique_str(prefix))
|
|
partition_w = self.init_partition_wrap(collection_wrap=collection_w)
|
|
|
|
# insert [0, half) into partition_w
|
|
half = ct.default_nb // 2
|
|
df_partition = cf.gen_default_dataframe_data(nb=half)
|
|
partition_w.insert(df_partition)
|
|
# insert [half, nb) into _default
|
|
df_default = cf.gen_default_dataframe_data(nb=half, start=half)
|
|
collection_w.insert(df_default)
|
|
# flush
|
|
collection_w.num_entities
|
|
collection_w.create_index(ct.default_float_vec_field_name, index_params=ct.default_flat_index)
|
|
|
|
# load
|
|
error = {ct.err_code: 0, ct.err_msg: "due to no partition specified"}
|
|
collection_w.load(partition_names=[], check_task=CheckTasks.err_res, check_items=error)
|
|
|
|
@pytest.mark.tags(CaseLabel.L2)
|
|
@pytest.mark.parametrize("invalid_num_replica", [0.2, "not-int"])
|
|
def test_load_replica_non_number(self, invalid_num_replica):
|
|
"""
|
|
target: test load collection with non-number replicas
|
|
method: load with non-number replicas
|
|
expected: raise exceptions
|
|
"""
|
|
# create, insert
|
|
collection_w = self.init_collection_wrap(cf.gen_unique_str(prefix))
|
|
df = cf.gen_default_dataframe_data()
|
|
insert_res, _ = collection_w.insert(df)
|
|
assert collection_w.num_entities == ct.default_nb
|
|
collection_w.create_index(ct.default_float_vec_field_name, index_params=ct.default_flat_index)
|
|
|
|
# load with non-number replicas
|
|
error = {ct.err_code: 999, ct.err_msg: f"`replica_number` value {invalid_num_replica} is illegal"}
|
|
collection_w.load(replica_number=invalid_num_replica, check_task=CheckTasks.err_res, check_items=error)
|
|
|
|
@pytest.mark.tags(CaseLabel.L2)
|
|
@pytest.mark.parametrize("replicas", [-1, 0])
|
|
def test_load_replica_invalid_number(self, replicas):
|
|
"""
|
|
target: test load partition with invalid replica number
|
|
method: load with invalid replica number
|
|
expected: load successfully as replica = 1
|
|
"""
|
|
# create, insert
|
|
collection_w = self.init_collection_wrap(cf.gen_unique_str(prefix))
|
|
df = cf.gen_default_dataframe_data()
|
|
insert_res, _ = collection_w.insert(df)
|
|
assert collection_w.num_entities == ct.default_nb
|
|
collection_w.create_index(ct.default_float_vec_field_name, index_params=ct.default_flat_index)
|
|
|
|
collection_w.load(replica_number=replicas)
|
|
replicas = collection_w.get_replicas()[0]
|
|
groups = replicas.groups
|
|
assert len(groups) == 1
|
|
assert len(groups[0].shards) == 1
|
|
|
|
@pytest.mark.tags(CaseLabel.L2)
|
|
@pytest.mark.parametrize("replicas", [None])
|
|
def test_load_replica_number_none(self, replicas):
|
|
"""
|
|
target: test load partition with replica number none
|
|
method: load with replica number=None
|
|
expected: raise exceptions
|
|
"""
|
|
# create, insert
|
|
collection_w = self.init_collection_wrap(cf.gen_unique_str(prefix))
|
|
df = cf.gen_default_dataframe_data()
|
|
insert_res, _ = collection_w.insert(df)
|
|
assert collection_w.num_entities == ct.default_nb
|
|
collection_w.create_index(ct.default_float_vec_field_name, index_params=ct.default_flat_index)
|
|
|
|
collection_w.load(replica_number=replicas,
|
|
check_task=CheckTasks.err_res,
|
|
check_items={"err_code": 1,
|
|
"err_msg": "`replica_number` value None is illegal"})
|
|
|
|
@pytest.mark.tags(CaseLabel.L2)
|
|
def test_load_replica_greater_than_querynodes(self):
|
|
"""
|
|
target: test load with replicas that greater than querynodes
|
|
method: load with 3 replicas (2 querynode)
|
|
expected: Raise exception
|
|
"""
|
|
# create, insert
|
|
collection_w = self.init_collection_wrap(cf.gen_unique_str(prefix))
|
|
df = cf.gen_default_dataframe_data()
|
|
insert_res, _ = collection_w.insert(df)
|
|
assert collection_w.num_entities == ct.default_nb
|
|
collection_w.create_index(ct.default_float_vec_field_name, index_params=ct.default_flat_index)
|
|
|
|
error = {ct.err_code: 65535,
|
|
ct.err_msg: "failed to load collection: failed to spawn replica for collection: nodes not enough"}
|
|
collection_w.load(replica_number=3, check_task=CheckTasks.err_res, check_items=error)
|
|
|
|
@pytest.mark.tags(CaseLabel.ClusterOnly)
|
|
def test_load_replica_change(self):
|
|
"""
|
|
target: test load replica change
|
|
method: 1.load with replica 1
|
|
2.load with a new replica number
|
|
3.release collection
|
|
4.load with a new replica
|
|
5.create index is a must because get_query_segment_info could
|
|
only return indexed and loaded segment
|
|
expected: The second time successfully loaded with a new replica number
|
|
"""
|
|
# create, insert
|
|
collection_w = self.init_collection_wrap(cf.gen_unique_str(prefix))
|
|
df = cf.gen_default_dataframe_data()
|
|
insert_res, _ = collection_w.insert(df)
|
|
assert collection_w.num_entities == ct.default_nb
|
|
collection_w.create_index(ct.default_float_vec_field_name, ct.default_index)
|
|
collection_w.load(replica_number=1)
|
|
for seg in self.utility_wrap.get_query_segment_info(collection_w.name)[0]:
|
|
assert len(seg.nodeIds) == 1
|
|
|
|
collection_w.query(expr=f"{ct.default_int64_field_name} in [0]")
|
|
loading_progress, _ = self.utility_wrap.loading_progress(collection_w.name)
|
|
assert loading_progress == {'loading_progress': '100%'}
|
|
|
|
# verify load different replicas thrown an exception
|
|
error = {ct.err_code: 1100, ct.err_msg: "failed to load collection: can't change the replica number for "
|
|
"loaded collection: expected=1, actual=2: invalid parameter"}
|
|
collection_w.load(replica_number=2, check_task=CheckTasks.err_res, check_items=error)
|
|
one_replica, _ = collection_w.get_replicas()
|
|
assert len(one_replica.groups) == 1
|
|
|
|
collection_w.release()
|
|
collection_w.load(replica_number=2)
|
|
# replicas is not yet reflected in loading progress
|
|
loading_progress, _ = self.utility_wrap.loading_progress(collection_w.name)
|
|
assert loading_progress == {'loading_progress': '100%'}
|
|
two_replicas, _ = collection_w.get_replicas()
|
|
assert len(two_replicas.groups) == 2
|
|
collection_w.query(expr=f"{ct.default_int64_field_name} in [0]", check_task=CheckTasks.check_query_results,
|
|
check_items={'exp_res': [{'int64': 0}]})
|
|
|
|
# verify loaded segments included 2 replicas and twice num entities
|
|
seg_info = self.utility_wrap.get_query_segment_info(collection_w.name)[0]
|
|
num_entities = 0
|
|
for seg in seg_info:
|
|
assert len(seg.nodeIds) == 2
|
|
num_entities += seg.num_rows
|
|
assert num_entities == ct.default_nb
|
|
|
|
@pytest.mark.tags(CaseLabel.ClusterOnly)
|
|
def test_load_replica_multi(self):
|
|
"""
|
|
target: test load with multiple replicas
|
|
method: 1.create collection with one shards
|
|
2.insert multiple segments
|
|
3.load with multiple replicas
|
|
4.query and search
|
|
expected: Query and search successfully
|
|
"""
|
|
# create, insert
|
|
collection_w = self.init_collection_wrap(cf.gen_unique_str(prefix), shards_num=1)
|
|
tmp_nb = 1000
|
|
replica_number = 2
|
|
for i in range(replica_number):
|
|
df = cf.gen_default_dataframe_data(nb=tmp_nb, start=i * tmp_nb)
|
|
insert_res, _ = collection_w.insert(df)
|
|
assert collection_w.num_entities == (i + 1) * tmp_nb
|
|
|
|
collection_w.create_index(ct.default_float_vec_field_name, index_params=ct.default_flat_index)
|
|
collection_w.load(replica_number=replica_number)
|
|
replicas = collection_w.get_replicas()[0]
|
|
assert len(replicas.groups) == replica_number
|
|
|
|
for seg in self.utility_wrap.get_query_segment_info(collection_w.name)[0]:
|
|
assert len(seg.nodeIds) == replica_number
|
|
|
|
query_res, _ = collection_w.query(expr=f"{ct.default_int64_field_name} in [0, {tmp_nb}]")
|
|
assert len(query_res) == 2
|
|
search_res, _ = collection_w.search(vectors, default_search_field, default_search_params, default_limit)
|
|
assert len(search_res[0]) == ct.default_limit
|
|
|
|
@pytest.mark.tags(CaseLabel.ClusterOnly)
|
|
def test_load_replica_partitions(self):
|
|
"""
|
|
target: test load replica with partitions
|
|
method: 1.Create collection and one partition
|
|
2.Insert data into collection and partition
|
|
3.Load multi replicas with partition
|
|
4.Query
|
|
expected: Verify query result
|
|
"""
|
|
collection_w = self.init_collection_wrap(cf.gen_unique_str(prefix))
|
|
df_1 = cf.gen_default_dataframe_data(nb=ct.default_nb)
|
|
df_2 = cf.gen_default_dataframe_data(nb=ct.default_nb, start=ct.default_nb)
|
|
|
|
collection_w.insert(df_1)
|
|
partition_w = self.init_partition_wrap(collection_w, ct.default_tag)
|
|
partition_w.insert(df_2)
|
|
assert collection_w.num_entities == ct.default_nb * 2
|
|
collection_w.create_index(ct.default_float_vec_field_name, index_params=ct.default_flat_index)
|
|
|
|
collection_w.load([partition_w.name], replica_number=2)
|
|
for seg in self.utility_wrap.get_query_segment_info(collection_w.name)[0]:
|
|
assert len(seg.nodeIds) == 2
|
|
# default tag query 0 empty
|
|
collection_w.query(expr=f"{ct.default_int64_field_name} in [0]", partition_names=[ct.default_tag],
|
|
check_tasks=CheckTasks.check_query_empty)
|
|
# default query 0 empty
|
|
collection_w.query(expr=f"{ct.default_int64_field_name} in [2000]",
|
|
check_task=CheckTasks.check_query_results,
|
|
check_items={'exp_res': df_2.iloc[:1, :1].to_dict('records')})
|
|
|
|
error = {ct.err_code: 65538, ct.err_msg: "partition not loaded"}
|
|
collection_w.query(expr=f"{ct.default_int64_field_name} in [0]",
|
|
partition_names=[ct.default_partition_name, ct.default_tag],
|
|
check_task=CheckTasks.err_res, check_items=error)
|
|
|
|
@pytest.mark.tags(CaseLabel.L3)
|
|
def test_load_replica_non_shard_leader(self):
|
|
"""
|
|
target: test replica groups which one of QN is not shard leader
|
|
method: 1.deploy cluster with 5 QNs
|
|
2.create collection with 2 shards
|
|
3.insert and flush
|
|
4.load with 2 replica number
|
|
5.insert growing data
|
|
6.search and query
|
|
expected: Verify search and query results
|
|
"""
|
|
# create and insert entities
|
|
collection_w = self.init_collection_wrap(cf.gen_unique_str(prefix), shards_num=2)
|
|
df = cf.gen_default_dataframe_data()
|
|
collection_w.insert(df)
|
|
assert collection_w.num_entities == ct.default_nb
|
|
collection_w.create_index(ct.default_float_vec_field_name, index_params=ct.default_flat_index)
|
|
|
|
# load with multi replica and insert growing data
|
|
collection_w.load(replica_number=2)
|
|
df_growing = cf.gen_default_dataframe_data(100, start=ct.default_nb)
|
|
collection_w.insert(df_growing)
|
|
|
|
replicas = collection_w.get_replicas()[0]
|
|
# verify there are 2 groups (2 replicas)
|
|
assert len(replicas.groups) == 2
|
|
log.debug(replicas)
|
|
all_group_nodes = []
|
|
for group in replicas.groups:
|
|
# verify each group have 3 shards
|
|
assert len(group.shards) == 2
|
|
all_group_nodes.extend(group.group_nodes)
|
|
# verify all groups has 5 querynodes
|
|
assert len(all_group_nodes) == 5
|
|
|
|
# Verify 2 replicas segments loaded
|
|
seg_info, _ = self.utility_wrap.get_query_segment_info(collection_w.name)
|
|
for seg in seg_info:
|
|
assert len(seg.nodeIds) == 2
|
|
|
|
# verify search successfully
|
|
res, _ = collection_w.search(vectors, default_search_field, default_search_params, default_limit)
|
|
assert len(res[0]) == ct.default_limit
|
|
|
|
# verify query sealed and growing data successfully
|
|
collection_w.query(expr=f"{ct.default_int64_field_name} in [0, {ct.default_nb}]",
|
|
check_task=CheckTasks.check_query_results,
|
|
check_items={'exp_res': [{'int64': 0}, {'int64': 3000}]})
|
|
|
|
@pytest.mark.tags(CaseLabel.L3)
|
|
def test_load_replica_multiple_shard_leader(self):
|
|
"""
|
|
target: test replica groups which one of QN is shard leader of multiple shards
|
|
method: 1.deploy cluster with 5 QNs
|
|
2.create collection with 3 shards
|
|
3.insert and flush
|
|
4.load with 2 replica number
|
|
5.insert growng data
|
|
6.search and query
|
|
expected: Verify search and query results
|
|
"""
|
|
# craete and insert
|
|
collection_w = self.init_collection_wrap(cf.gen_unique_str(prefix), shards_num=3)
|
|
df = cf.gen_default_dataframe_data()
|
|
collection_w.insert(df)
|
|
assert collection_w.num_entities == ct.default_nb
|
|
collection_w.create_index(ct.default_float_vec_field_name, index_params=ct.default_flat_index)
|
|
|
|
# load with multi replicas and insert growing data
|
|
collection_w.load(replica_number=2)
|
|
df_growing = cf.gen_default_dataframe_data(100, start=ct.default_nb)
|
|
collection_w.insert(df_growing)
|
|
|
|
# verify replica infos
|
|
replicas, _ = collection_w.get_replicas()
|
|
log.debug(replicas)
|
|
assert len(replicas.groups) == 2
|
|
all_group_nodes = []
|
|
for group in replicas.groups:
|
|
# verify each group have 3 shards
|
|
assert len(group.shards) == 3
|
|
all_group_nodes.extend(group.group_nodes)
|
|
# verify all groups has 5 querynodes
|
|
assert len(all_group_nodes) == 5
|
|
|
|
# Verify 2 replicas segments loaded
|
|
seg_info, _ = self.utility_wrap.get_query_segment_info(collection_w.name)
|
|
for seg in seg_info:
|
|
assert len(seg.nodeIds) == 2
|
|
|
|
# Verify search successfully
|
|
res, _ = collection_w.search(vectors, default_search_field, default_search_params, default_limit)
|
|
assert len(res[0]) == ct.default_limit
|
|
|
|
# Verify query sealed and growing entities successfully
|
|
collection_w.query(expr=f"{ct.default_int64_field_name} in [0, {ct.default_nb}]",
|
|
check_task=CheckTasks.check_query_results,
|
|
check_items={'exp_res': [{'int64': 0}, {'int64': 3000}]})
|
|
|
|
@pytest.mark.tags(CaseLabel.L3)
|
|
def test_load_replica_sq_count_balance(self):
|
|
"""
|
|
target: test load with multi replicas, and sq request load balance cross replicas
|
|
method: 1.Deploy milvus with multi querynodes
|
|
2.Insert entities and load with replicas
|
|
3.Do query req many times
|
|
4.Verify the querynode sq_req_count metrics
|
|
expected: Infer whether the query request is load balanced.
|
|
"""
|
|
from utils.util_k8s import get_metrics_querynode_sq_req_count
|
|
collection_w = self.init_collection_wrap(name=cf.gen_unique_str(prefix))
|
|
df = cf.gen_default_dataframe_data(nb=5000)
|
|
mutation_res, _ = collection_w.insert(df)
|
|
assert collection_w.num_entities == 5000
|
|
total_sq_count = 20
|
|
collection_w.create_index(ct.default_float_vec_field_name, index_params=ct.default_flat_index)
|
|
|
|
collection_w.load(replica_number=3)
|
|
for i in range(total_sq_count):
|
|
ids = [random.randint(0, 100) for _ in range(5)]
|
|
collection_w.query(f"{ct.default_int64_field_name} in {ids}")
|
|
|
|
replicas, _ = collection_w.get_replicas()
|
|
log.debug(replicas)
|
|
sq_req_count = get_metrics_querynode_sq_req_count()
|
|
for group in replicas.groups:
|
|
group_nodes = group.group_nodes
|
|
group_sq_req_count = 0
|
|
for node in group_nodes:
|
|
group_sq_req_count += sq_req_count[node]
|
|
log.debug(f"Group nodes {group_nodes} with total sq_req_count {group_sq_req_count}")
|
|
|
|
@pytest.mark.tags(CaseLabel.L2)
|
|
def test_get_collection_replicas_not_loaded(self):
|
|
"""
|
|
target: test get replicas of not loaded collection
|
|
method: not loaded collection and get replicas
|
|
expected: raise an exception
|
|
"""
|
|
# create, insert
|
|
collection_w = self.init_collection_wrap(cf.gen_unique_str(prefix))
|
|
df = cf.gen_default_dataframe_data()
|
|
insert_res, _ = collection_w.insert(df)
|
|
assert collection_w.num_entities == ct.default_nb
|
|
|
|
res, _ = collection_w.get_replicas()
|
|
assert len(res.groups) == 0
|
|
|
|
@pytest.mark.tags(CaseLabel.L3)
|
|
def test_count_multi_replicas(self):
|
|
"""
|
|
target: test count multi replicas
|
|
method: 1. load data with multi replicas
|
|
2. count
|
|
expected: verify count
|
|
"""
|
|
# create -> insert -> flush
|
|
collection_w = self.init_collection_wrap(name=cf.gen_unique_str(prefix))
|
|
df = cf.gen_default_dataframe_data()
|
|
collection_w.insert(df)
|
|
collection_w.flush()
|
|
|
|
# index -> load replicas
|
|
collection_w.create_index(ct.default_float_vec_field_name, index_params=ct.default_flat_index)
|
|
collection_w.load(replica_number=2)
|
|
|
|
# count
|
|
collection_w.query(expr=f'{ct.default_int64_field_name} >= 0', output_fields=[ct.default_count_output],
|
|
check_task=CheckTasks.check_query_results,
|
|
check_items={'exp_res': [{"count(*)": ct.default_nb}]})
|
|
|
|
@pytest.mark.tags(CaseLabel.L1)
|
|
def test_load_collection_without_creating_index(self):
|
|
"""
|
|
target: test drop index after load without release
|
|
method: create a collection without index, then load
|
|
expected: raise exception
|
|
"""
|
|
collection_w = self.init_collection_general(prefix, True, is_index=False)[0]
|
|
collection_w.load(check_task=CheckTasks.err_res,
|
|
check_items={"err_code": 1,
|
|
"err_msg": "index not found"})
|
|
|
|
|
|
class TestDescribeCollection(TestcaseBase):
|
|
"""
|
|
******************************************************************
|
|
The following cases are used to test `collection.describe` function
|
|
******************************************************************
|
|
"""
|
|
|
|
@pytest.mark.tags(CaseLabel.L2)
|
|
def test_collection_describe(self):
|
|
"""
|
|
target: test describe collection
|
|
method: create a collection and check its information when describe
|
|
expected: return correct information
|
|
"""
|
|
self._connect()
|
|
c_name = cf.gen_unique_str(prefix)
|
|
collection_w = self.init_collection_wrap(name=c_name)
|
|
collection_w.create_index(ct.default_float_vec_field_name, index_params=ct.default_flat_index)
|
|
description = \
|
|
{'collection_name': c_name, 'auto_id': False, 'num_shards': ct.default_shards_num, 'description': '',
|
|
'fields': [
|
|
{'field_id': 100, 'name': 'int64', 'description': '', 'type': 5, 'params': {}, 'is_primary': True},
|
|
{'field_id': 101, 'name': 'float', 'description': '', 'type': 10, 'params': {}},
|
|
{'field_id': 102, 'name': 'varchar', 'description': '', 'type': 21, 'params': {'max_length': 65535}},
|
|
{'field_id': 103, 'name': 'json_field', 'description': '', 'type': 23, 'params': {}},
|
|
{'field_id': 104, 'name': 'float_vector', 'description': '', 'type': 101, 'params': {'dim': 128}}
|
|
],
|
|
'aliases': [], 'consistency_level': 0, 'properties': {}, 'num_partitions': 1, 'enable_dynamic_field': False}
|
|
res = collection_w.describe()[0]
|
|
del res['collection_id']
|
|
log.info(res)
|
|
assert description == res
|
|
|
|
|
|
class TestReleaseAdvanced(TestcaseBase):
|
|
@pytest.mark.tags(CaseLabel.L0)
|
|
def test_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
|
|
"""
|
|
self._connect()
|
|
data = cf.gen_default_list_data()
|
|
c_name = cf.gen_unique_str()
|
|
collection_wr = self.init_collection_wrap(name=c_name)
|
|
collection_wr.insert(data=data)
|
|
assert collection_wr.num_entities == ct.default_nb
|
|
collection_wr.create_index(ct.default_float_vec_field_name, index_params=ct.default_flat_index)
|
|
collection_wr.load()
|
|
search_res, _ = collection_wr.search(vectors, default_search_field, default_search_params,
|
|
default_limit, _async=True)
|
|
collection_wr.release()
|
|
error = {ct.err_code: 65535, ct.err_msg: "collection not loaded"}
|
|
collection_wr.search(vectors, default_search_field, default_search_params, default_limit,
|
|
check_task=CheckTasks.err_res, check_items=error)
|
|
|
|
@pytest.mark.tags(CaseLabel.L2)
|
|
def test_release_partition_during_searching(self):
|
|
"""
|
|
target: test release partition during searching
|
|
method: insert entities into partition, flush and load partition, release partition during searching
|
|
expected: raise exception
|
|
"""
|
|
self._connect()
|
|
partition_num = 1
|
|
collection_w = self.init_collection_general(prefix, True, 10, partition_num, is_index=False)[0]
|
|
collection_w.create_index(ct.default_float_vec_field_name, index_params=ct.default_flat_index)
|
|
par = collection_w.partitions
|
|
par_name = par[partition_num].name
|
|
par[partition_num].load()
|
|
limit = 10
|
|
collection_w.search(vectors, default_search_field,
|
|
default_search_params, limit, default_search_exp,
|
|
[par_name])
|
|
par[partition_num].release()
|
|
collection_w.search(vectors, default_search_field,
|
|
default_search_params, limit, default_search_exp,
|
|
[par_name],
|
|
check_task=CheckTasks.err_res,
|
|
check_items={"err_code": 65535,
|
|
"err_msg": "collection not loaded"})
|
|
|
|
@pytest.mark.tags(CaseLabel.L0)
|
|
def test_release_indexed_collection_during_searching(self):
|
|
"""
|
|
target: test release indexed collection during searching
|
|
method: insert entities into partition, flush and load partition, release collection during searching
|
|
expected: raise exception
|
|
"""
|
|
self._connect()
|
|
partition_num = 1
|
|
collection_w = self.init_collection_general(prefix, True, 10, partition_num, is_index=False)[0]
|
|
collection_w.create_index(ct.default_float_vec_field_name, index_params=ct.default_flat_index)
|
|
par = collection_w.partitions
|
|
par_name = par[partition_num].name
|
|
par[partition_num].load()
|
|
limit = 10
|
|
collection_w.search(vectors, default_search_field,
|
|
default_search_params, limit, default_search_exp,
|
|
[par_name], _async=True)
|
|
collection_w.release()
|
|
error = {ct.err_code: 65535, ct.err_msg: "collection not loaded"}
|
|
collection_w.search(vectors, default_search_field,
|
|
default_search_params, limit, default_search_exp,
|
|
[par_name],
|
|
check_task=CheckTasks.err_res,
|
|
check_items=error)
|
|
|
|
|
|
class TestLoadPartition(TestcaseBase):
|
|
"""
|
|
******************************************************************
|
|
The following cases are used to test `load_collection` function
|
|
******************************************************************
|
|
"""
|
|
|
|
@pytest.fixture(
|
|
scope="function",
|
|
params=gen_simple_index()
|
|
)
|
|
def get_simple_index(self, request, connect):
|
|
return request.param
|
|
|
|
@pytest.fixture(
|
|
scope="function",
|
|
params=gen_binary_index()
|
|
)
|
|
def get_binary_index(self, request):
|
|
log.info(request.param)
|
|
if request.param["index_type"] in ct.binary_support:
|
|
return request.param
|
|
else:
|
|
pytest.skip("Skip index Temporary")
|
|
|
|
@pytest.mark.tags(CaseLabel.L0)
|
|
@pytest.mark.parametrize('binary_index', gen_binary_index())
|
|
@pytest.mark.parametrize('metric_type', ct.binary_metrics)
|
|
def test_load_partition_after_index_binary(self, binary_index, metric_type):
|
|
"""
|
|
target: test load binary_collection, after index created
|
|
method: insert and create index, load binary_collection with correct params
|
|
expected: no error raised
|
|
"""
|
|
self._connect()
|
|
partition_num = 1
|
|
collection_w = self.init_collection_general(prefix, True, ct.default_nb, partition_num,
|
|
is_binary=True, is_index=False)[0]
|
|
|
|
# for metric_type in ct.binary_metrics:
|
|
binary_index["metric_type"] = metric_type
|
|
if binary_index["index_type"] == "BIN_IVF_FLAT" and metric_type in ct.structure_metrics:
|
|
error = {ct.err_code: 65535,
|
|
ct.err_msg: f"metric type {metric_type} not found or not supported, supported: [HAMMING JACCARD]"}
|
|
collection_w.create_index(ct.default_binary_vec_field_name, binary_index,
|
|
check_task=CheckTasks.err_res, check_items=error)
|
|
collection_w.create_index(ct.default_binary_vec_field_name, ct.default_bin_flat_index)
|
|
else:
|
|
collection_w.create_index(ct.default_binary_vec_field_name, binary_index)
|
|
par = collection_w.partitions
|
|
par[partition_num].load()
|
|
|
|
@pytest.mark.tags(CaseLabel.L2)
|
|
def test_load_partition_dis_connect(self):
|
|
"""
|
|
target: test load partition, without connection
|
|
method: load partition with correct params, with a disconnected instance
|
|
expected: load raise exception
|
|
"""
|
|
self._connect()
|
|
collection_w = self.init_collection_wrap()
|
|
partition_name = cf.gen_unique_str(prefix)
|
|
description = cf.gen_unique_str("desc_")
|
|
partition_w = self.init_partition_wrap(collection_w, partition_name,
|
|
description=description,
|
|
check_task=CheckTasks.check_partition_property,
|
|
check_items={"name": partition_name, "description": description,
|
|
"is_empty": True, "num_entities": 0}
|
|
)
|
|
collection_w.create_index(ct.default_float_vec_field_name, index_params=ct.default_flat_index)
|
|
partition_w.load()
|
|
self.connection_wrap.remove_connection(ct.default_alias)
|
|
res_list, _ = self.connection_wrap.list_connections()
|
|
assert ct.default_alias not in res_list
|
|
error = {ct.err_code: 1, ct.err_msg: 'should create connect first.'}
|
|
partition_w.load(check_task=CheckTasks.err_res, check_items=error)
|
|
|
|
@pytest.mark.tags(CaseLabel.L2)
|
|
def test_release_partition_dis_connect(self):
|
|
"""
|
|
target: test release collection, without connection
|
|
method: release collection with correct params, with a disconnected instance
|
|
expected: release raise exception
|
|
"""
|
|
self._connect()
|
|
collection_w = self.init_collection_wrap()
|
|
partition_name = cf.gen_unique_str(prefix)
|
|
description = cf.gen_unique_str("desc_")
|
|
partition_w = self.init_partition_wrap(collection_w, partition_name,
|
|
description=description,
|
|
check_task=CheckTasks.check_partition_property,
|
|
check_items={"name": partition_name, "description": description,
|
|
"is_empty": True, "num_entities": 0}
|
|
)
|
|
collection_w.create_index(ct.default_float_vec_field_name, index_params=ct.default_flat_index)
|
|
partition_w.load()
|
|
self.connection_wrap.remove_connection(ct.default_alias)
|
|
res_list, _ = self.connection_wrap.list_connections()
|
|
assert ct.default_alias not in res_list
|
|
error = {ct.err_code: 1, ct.err_msg: 'should create connect first.'}
|
|
partition_w.release(check_task=CheckTasks.err_res, check_items=error)
|
|
|
|
@pytest.mark.tags(CaseLabel.L2)
|
|
def test_load_partition_not_existed(self):
|
|
"""
|
|
target: test load partition for invalid scenario
|
|
method: load not existed partition
|
|
expected: raise exception and report the error
|
|
"""
|
|
self._connect()
|
|
collection_w = self.init_collection_wrap()
|
|
partition_name = cf.gen_unique_str(prefix)
|
|
description = cf.gen_unique_str("desc_")
|
|
partition_w = self.init_partition_wrap(collection_w, partition_name,
|
|
description=description,
|
|
check_task=CheckTasks.check_partition_property,
|
|
check_items={"name": partition_name, "description": description,
|
|
"is_empty": True, "num_entities": 0})
|
|
collection_w.create_index(ct.default_float_vec_field_name, index_params=ct.default_flat_index)
|
|
partition_w.drop()
|
|
error = {ct.err_code: 200, ct.err_msg: 'partition not found[partition=%s]' % partition_name}
|
|
partition_w.load(check_task=CheckTasks.err_res, check_items=error)
|
|
|
|
@pytest.mark.tags(CaseLabel.L0)
|
|
def test_release_partition_not_load(self):
|
|
"""
|
|
target: test release partition without load
|
|
method: release partition without load
|
|
expected: release success
|
|
"""
|
|
self._connect()
|
|
collection_w = self.init_collection_wrap()
|
|
partition_name = cf.gen_unique_str(prefix)
|
|
description = cf.gen_unique_str("desc_")
|
|
partition_w = self.init_partition_wrap(collection_w, partition_name,
|
|
description=description,
|
|
check_task=CheckTasks.check_partition_property,
|
|
check_items={"name": partition_name, "description": description,
|
|
"is_empty": True, "num_entities": 0})
|
|
partition_w.release()
|
|
|
|
@pytest.mark.tags(CaseLabel.L2)
|
|
def test_load_release_after_drop(self):
|
|
"""
|
|
target: test load and release partition after drop
|
|
method: drop partition and then load and release it
|
|
expected: raise exception
|
|
"""
|
|
self._connect()
|
|
collection_w = self.init_collection_wrap()
|
|
partition_name = cf.gen_unique_str(prefix)
|
|
description = cf.gen_unique_str("desc_")
|
|
partition_w = self.init_partition_wrap(collection_w, partition_name,
|
|
description=description,
|
|
check_task=CheckTasks.check_partition_property,
|
|
check_items={"name": partition_name, "description": description,
|
|
"is_empty": True, "num_entities": 0})
|
|
partition_w.drop()
|
|
collection_w.create_index(ct.default_float_vec_field_name)
|
|
error = {ct.err_code: 200, ct.err_msg: 'partition not found[partition=%s]' % partition_name}
|
|
partition_w.load(check_task=CheckTasks.err_res, check_items=error)
|
|
partition_w.release(check_task=CheckTasks.err_res, check_items=error)
|
|
|
|
@pytest.mark.tags(CaseLabel.L0)
|
|
def test_release_partition_after_drop(self):
|
|
"""
|
|
target: test release collection after drop
|
|
method: insert and flush, then release collection after load and drop
|
|
expected: raise exception
|
|
"""
|
|
self._connect()
|
|
collection_w = self.init_collection_wrap()
|
|
partition_name = cf.gen_unique_str(prefix)
|
|
description = cf.gen_unique_str("desc_")
|
|
partition_w = self.init_partition_wrap(collection_w, partition_name,
|
|
description=description,
|
|
check_task=CheckTasks.check_partition_property,
|
|
check_items={"name": partition_name, "description": description,
|
|
"is_empty": True, "num_entities": 0})
|
|
partition_w.drop()
|
|
error = {ct.err_code: 200, ct.err_msg: 'partition not found[partition=%s]' % partition_name}
|
|
partition_w.release(check_task=CheckTasks.err_res, check_items=error)
|
|
|
|
@pytest.mark.tags(CaseLabel.L0)
|
|
def test_load_release_after_collection_drop(self):
|
|
"""
|
|
target: test release collection after drop
|
|
method: insert and flush, then release collection after load and drop
|
|
expected: raise exception
|
|
"""
|
|
self._connect()
|
|
collection_w = self.init_collection_wrap()
|
|
name = collection_w.name
|
|
partition_name = cf.gen_unique_str(prefix)
|
|
description = cf.gen_unique_str("desc_")
|
|
partition_w = self.init_partition_wrap(collection_w, partition_name,
|
|
description=description,
|
|
check_task=CheckTasks.check_partition_property,
|
|
check_items={"name": partition_name, "description": description,
|
|
"is_empty": True, "num_entities": 0})
|
|
collection_w.drop()
|
|
error = {ct.err_code: 0, ct.err_msg: "collection not found"}
|
|
partition_w.load(check_task=CheckTasks.err_res, check_items=error)
|
|
partition_w.release(check_task=CheckTasks.err_res, check_items=error)
|
|
|
|
@pytest.mark.tags(CaseLabel.L2)
|
|
def test_load_collection_after_load_loaded_partition(self):
|
|
"""
|
|
target: test load partition after load partition
|
|
method: 1. load partition
|
|
2. load the partition again
|
|
3. query on the non-loaded partition
|
|
4. load collection
|
|
expected: No exception
|
|
"""
|
|
collection_w = self.init_collection_general(prefix, is_index=False)[0]
|
|
collection_w.create_index(default_search_field)
|
|
partition_w1 = self.init_partition_wrap(collection_w, partition1)
|
|
partition_w2 = self.init_partition_wrap(collection_w, partition2)
|
|
partition_w1.load()
|
|
partition_w1.load()
|
|
error = {ct.err_code: 65538, ct.err_msg: 'partition not loaded'}
|
|
collection_w.query(default_term_expr, partition_names=[partition2],
|
|
check_task=CheckTasks.err_res, check_items=error)
|
|
collection_w.load()
|
|
|
|
@pytest.mark.tags(CaseLabel.L2)
|
|
def test_load_collection_after_load_unloaded_partition(self):
|
|
"""
|
|
target: test load partition after load an unloaded partition
|
|
method: 1. load partition
|
|
2. load another partition
|
|
3. query on the collection
|
|
4. load collection
|
|
expected: No exception
|
|
"""
|
|
collection_w = self.init_collection_general(prefix, is_index=False)[0]
|
|
collection_w.create_index(default_search_field)
|
|
partition_w1 = self.init_partition_wrap(collection_w, partition1)
|
|
partition_w2 = self.init_partition_wrap(collection_w, partition2)
|
|
partition_w1.load()
|
|
partition_w2.load()
|
|
collection_w.query(default_term_expr)
|
|
collection_w.load()
|
|
|
|
@pytest.mark.tags(CaseLabel.L2)
|
|
def test_load_collection_after_load_one_partition(self):
|
|
"""
|
|
target: test load partition after load partition
|
|
method: 1. load partition
|
|
2. load collection
|
|
3. query on the partitions
|
|
expected: No exception
|
|
"""
|
|
collection_w = self.init_collection_general(prefix, is_index=False)[0]
|
|
collection_w.create_index(default_search_field)
|
|
partition_w1 = self.init_partition_wrap(collection_w, partition1)
|
|
partition_w2 = self.init_partition_wrap(collection_w, partition2)
|
|
partition_w1.load()
|
|
collection_w.load()
|
|
collection_w.query(default_term_expr, partition_names=[partition1, partition2])
|
|
|
|
@pytest.mark.tags(CaseLabel.L0)
|
|
def test_load_partitions_release_collection(self):
|
|
"""
|
|
target: test release collection after load partitions
|
|
method: 1. load partition
|
|
2. release collection
|
|
3. query on the partition
|
|
4. load partitions
|
|
5. query on the collection
|
|
expected: no exception
|
|
"""
|
|
collection_w = self.init_collection_general(prefix, is_index=False)[0]
|
|
collection_w.create_index(default_search_field)
|
|
partition_w1 = self.init_partition_wrap(collection_w, partition1)
|
|
partition_w2 = self.init_partition_wrap(collection_w, partition2)
|
|
partition_w1.load()
|
|
collection_w.release()
|
|
error = {ct.err_code: 65535, ct.err_msg: "collection not loaded"}
|
|
collection_w.query(default_term_expr, partition_names=[partition1],
|
|
check_task=CheckTasks.err_res, check_items=error)
|
|
partition_w1.load()
|
|
partition_w2.load()
|
|
collection_w.query(default_term_expr)
|
|
|
|
@pytest.mark.tags(CaseLabel.L2)
|
|
def test_load_collection_release_collection(self):
|
|
"""
|
|
target: test load collection after load partitions
|
|
method: 1. load partition
|
|
2. release collection
|
|
3. load collection
|
|
expected: no exception
|
|
"""
|
|
collection_w = self.init_collection_general(prefix, is_index=False)[0]
|
|
collection_w.create_index(default_search_field)
|
|
partition_w1 = self.init_partition_wrap(collection_w, partition1)
|
|
partition_w2 = self.init_partition_wrap(collection_w, partition2)
|
|
partition_w1.load()
|
|
collection_w.release()
|
|
collection_w.load()
|
|
|
|
@pytest.mark.tags(CaseLabel.L2)
|
|
def test_load_partitions_after_load_release_partition(self):
|
|
"""
|
|
target: test load partitions after load and release partition
|
|
method: 1. load partition
|
|
2. release partition
|
|
3. query on the partition
|
|
4. load partitions(include released partition and non-released partition)
|
|
5. query on the collection
|
|
expected: no exception
|
|
"""
|
|
collection_w = self.init_collection_general(prefix, is_index=False)[0]
|
|
collection_w.create_index(default_search_field)
|
|
partition_w1 = self.init_partition_wrap(collection_w, partition1)
|
|
partition_w2 = self.init_partition_wrap(collection_w, partition2)
|
|
partition_w1.load()
|
|
partition_w1.release()
|
|
error = {ct.err_code: 65535,
|
|
ct.err_msg: 'collection not loaded'}
|
|
collection_w.query(default_term_expr, partition_names=[partition1],
|
|
check_task=CheckTasks.err_res, check_items=error)
|
|
partition_w1.load()
|
|
partition_w2.load()
|
|
collection_w.query(default_term_expr)
|
|
|
|
@pytest.mark.tags(CaseLabel.L2)
|
|
def test_load_collection_after_load_release_partition(self):
|
|
"""
|
|
target: test load collection after load and release partition
|
|
method: 1. load partition
|
|
2. release partition
|
|
3. load collection
|
|
4. search on the collection
|
|
expected: no exception
|
|
"""
|
|
collection_w = self.init_collection_general(prefix, is_index=False)[0]
|
|
collection_w.create_index(default_search_field)
|
|
partition_w1 = self.init_partition_wrap(collection_w, partition1)
|
|
partition_w2 = self.init_partition_wrap(collection_w, partition2)
|
|
partition_w1.load()
|
|
partition_w1.release()
|
|
collection_w.load()
|
|
collection_w.search(vectors, default_search_field, default_search_params,
|
|
default_limit, partition_names=[partition1, partition2])
|
|
|
|
@pytest.mark.tags(CaseLabel.L2)
|
|
def test_load_partitions_after_load_partition_release_partitions(self):
|
|
"""
|
|
target: test load partitions after load partition and release partitions
|
|
method: 1. load partition
|
|
2. release partitions
|
|
3. load partitions
|
|
4. query on the partitions
|
|
expected: no exception
|
|
"""
|
|
collection_w = self.init_collection_general(prefix, is_index=False)[0]
|
|
collection_w.create_index(default_search_field)
|
|
partition_w1 = self.init_partition_wrap(collection_w, partition1)
|
|
partition_w2 = self.init_partition_wrap(collection_w, partition2)
|
|
partition_w1.load()
|
|
partition_w1.release()
|
|
partition_w2.release()
|
|
partition_w1.load()
|
|
partition_w2.load()
|
|
collection_w.query(default_term_expr, partition_names=[partition1, partition2])
|
|
|
|
@pytest.mark.tags(CaseLabel.L2)
|
|
def test_load_collection_after_load_partition_release_partitions(self):
|
|
"""
|
|
target: test load collection after load partition and release partitions
|
|
method: 1. load partition
|
|
2. release partitions
|
|
3. query on the partitions
|
|
4. load collection
|
|
5. query on the partitions
|
|
expected: no exception
|
|
"""
|
|
collection_w = self.init_collection_general(prefix, is_index=False)[0]
|
|
collection_w.create_index(default_search_field)
|
|
partition_w1 = self.init_partition_wrap(collection_w, partition1)
|
|
partition_w2 = self.init_partition_wrap(collection_w, partition2)
|
|
partition_w1.load()
|
|
partition_w1.release()
|
|
partition_w2.release()
|
|
error = {ct.err_code: 65535, ct.err_msg: 'collection not loaded'}
|
|
collection_w.query(default_term_expr, partition_names=[partition1, partition2],
|
|
check_task=CheckTasks.err_res, check_items=error)
|
|
collection_w.load()
|
|
collection_w.query(default_term_expr, partition_names=[partition1, partition2])
|
|
|
|
@pytest.mark.tags(CaseLabel.L2)
|
|
def test_load_partition_after_load_drop_partition(self):
|
|
"""
|
|
target: test load partition after load and drop partition
|
|
method: 1. load partition
|
|
2. drop the loaded partition
|
|
3. load the left partition
|
|
4. query on the partition
|
|
expected: no exception
|
|
"""
|
|
collection_w = self.init_collection_general(prefix, is_index=False)[0]
|
|
collection_w.create_index(default_search_field)
|
|
partition_w1 = self.init_partition_wrap(collection_w, partition1)
|
|
partition_w2 = self.init_partition_wrap(collection_w, partition2)
|
|
partition_w1.load()
|
|
partition_w1.release()
|
|
partition_w1.drop()
|
|
partition_w2.load()
|
|
collection_w.query(default_term_expr, partition_names=[partition2])
|
|
|
|
@pytest.mark.tags(CaseLabel.L2)
|
|
def test_load_collection_after_load_drop_partition(self):
|
|
"""
|
|
target: test load collection after load and drop partition
|
|
method: 1. load partition
|
|
2. drop the loaded partition
|
|
3. query on the partition
|
|
4. drop another partition
|
|
5. load collection
|
|
6. query on the collection
|
|
expected: no exception
|
|
"""
|
|
collection_w = self.init_collection_general(prefix, is_index=False)[0]
|
|
collection_w.create_index(default_search_field)
|
|
partition_w1 = self.init_partition_wrap(collection_w, partition1)
|
|
partition_w2 = self.init_partition_wrap(collection_w, partition2)
|
|
partition_w1.load()
|
|
partition_w1.release()
|
|
partition_w1.drop()
|
|
error = {ct.err_code: 65535, ct.err_msg: f'partition name {partition1} not found'}
|
|
collection_w.query(default_term_expr, partition_names=[partition1, partition2],
|
|
check_task=CheckTasks.err_res, check_items=error)
|
|
partition_w2.drop()
|
|
collection_w.load()
|
|
collection_w.query(default_term_expr)
|
|
|
|
@pytest.mark.tags(CaseLabel.L2)
|
|
def test_release_load_partition_after_load_drop_partition(self):
|
|
"""
|
|
target: test release load partition after load and drop partition
|
|
method: 1. load partition
|
|
2. drop the loaded partition
|
|
3. release another partition
|
|
4. load the partition
|
|
expected: no exception
|
|
"""
|
|
collection_w = self.init_collection_general(prefix, is_index=False)[0]
|
|
collection_w.create_index(default_search_field)
|
|
partition_w1 = self.init_partition_wrap(collection_w, partition1)
|
|
partition_w2 = self.init_partition_wrap(collection_w, partition2)
|
|
partition_w1.load()
|
|
partition_w1.release()
|
|
partition_w1.drop()
|
|
partition_w2.release()
|
|
partition_w2.load()
|
|
collection_w.query(default_term_expr, partition_names=[partition2])
|
|
|
|
@pytest.mark.tags(CaseLabel.L2)
|
|
def test_release_load_collection_after_load_drop_partition(self):
|
|
"""
|
|
target: test release load partition after load and drop partition
|
|
method: 1. load partition
|
|
2. drop the loaded partition
|
|
3. release another partition
|
|
4. load collection
|
|
expected: no exception
|
|
"""
|
|
collection_w = self.init_collection_general(prefix, is_index=False)[0]
|
|
collection_w.create_index(default_search_field)
|
|
partition_w1 = self.init_partition_wrap(collection_w, partition1)
|
|
partition_w2 = self.init_partition_wrap(collection_w, partition2)
|
|
partition_w1.load()
|
|
partition_w1.release()
|
|
partition_w1.drop()
|
|
partition_w2.release()
|
|
collection_w.load()
|
|
collection_w.query(default_term_expr)
|
|
|
|
@pytest.mark.tags(CaseLabel.L2)
|
|
def test_load_another_partition_after_load_drop_partition(self):
|
|
"""
|
|
target: test load another collection after load and drop one partition
|
|
method: 1. load partition
|
|
2. drop the unloaded partition
|
|
3. load the partition again
|
|
4. query on the partition
|
|
expected: no exception
|
|
"""
|
|
collection_w = self.init_collection_general(prefix, is_index=False)[0]
|
|
collection_w.create_index(default_search_field)
|
|
partition_w1 = self.init_partition_wrap(collection_w, partition1)
|
|
partition_w2 = self.init_partition_wrap(collection_w, partition2)
|
|
partition_w1.load()
|
|
partition_w2.drop()
|
|
partition_w1.load()
|
|
collection_w.query(default_term_expr, partition_names=[partition1])
|
|
|
|
@pytest.mark.tags(CaseLabel.L2)
|
|
def test_release_load_partition_after_load_partition_drop_another(self):
|
|
"""
|
|
target: test release load partition after load and drop partition
|
|
method: 1. load partition
|
|
2. drop the unloaded partition
|
|
3. release the loaded partition
|
|
4. query on the released partition
|
|
5. reload the partition
|
|
6. query on the partition
|
|
expected: no exception
|
|
"""
|
|
collection_w = self.init_collection_general(prefix, is_index=False)[0]
|
|
collection_w.create_index(default_search_field)
|
|
partition_w1 = self.init_partition_wrap(collection_w, partition1)
|
|
partition_w2 = self.init_partition_wrap(collection_w, partition2)
|
|
partition_w1.load()
|
|
partition_w2.drop()
|
|
partition_w1.release()
|
|
error = {ct.err_code: 65535,
|
|
ct.err_msg: 'collection not loaded'}
|
|
collection_w.query(default_term_expr, partition_names=[partition1],
|
|
check_task=CheckTasks.err_res, check_items=error)
|
|
partition_w1.load()
|
|
collection_w.query(default_term_expr, partition_names=[partition1])
|
|
|
|
@pytest.mark.tags(CaseLabel.L2)
|
|
def test_release_load_collection_after_load_partition_drop_another(self):
|
|
"""
|
|
target: test release load partition after load and drop partition
|
|
method: 1. load partition
|
|
2. drop the unloaded partition
|
|
3. release the loaded partition
|
|
4. load collection
|
|
5. query on the collection
|
|
expected: no exception
|
|
"""
|
|
collection_w = self.init_collection_general(prefix, is_index=False)[0]
|
|
collection_w.create_index(default_search_field)
|
|
partition_w1 = self.init_partition_wrap(collection_w, partition1)
|
|
partition_w2 = self.init_partition_wrap(collection_w, partition2)
|
|
partition_w1.load()
|
|
partition_w2.drop()
|
|
partition_w1.release()
|
|
collection_w.load()
|
|
collection_w.query(default_term_expr)
|
|
|
|
@pytest.mark.tags(CaseLabel.L2)
|
|
def test_release_unloaded_partition(self):
|
|
"""
|
|
target: test load collection after load and drop partition
|
|
method: 1. load partition
|
|
2. release the other partition
|
|
3. query on the first partition
|
|
expected: no exception
|
|
"""
|
|
collection_w = self.init_collection_general(prefix, is_index=False)[0]
|
|
collection_w.create_index(default_search_field)
|
|
partition_w1 = self.init_partition_wrap(collection_w, partition1)
|
|
partition_w2 = self.init_partition_wrap(collection_w, partition2)
|
|
partition_w1.load()
|
|
partition_w2.release()
|
|
collection_w.query(default_term_expr, partition_names=[partition1])
|
|
|
|
|
|
class TestCollectionString(TestcaseBase):
|
|
"""
|
|
******************************************************************
|
|
The following cases are used to test about string
|
|
******************************************************************
|
|
"""
|
|
|
|
@pytest.mark.tags(CaseLabel.L1)
|
|
def test_collection_string_field_is_primary(self):
|
|
"""
|
|
target: test create collection with string field
|
|
method: 1. create collection with string field and vector field
|
|
2. set string fields is_primary=True
|
|
expected: Create collection successfully
|
|
"""
|
|
self._connect()
|
|
c_name = cf.gen_unique_str(prefix)
|
|
schema = cf.gen_string_pk_default_collection_schema()
|
|
self.collection_wrap.init_collection(name=c_name, schema=schema,
|
|
check_task=CheckTasks.check_collection_property,
|
|
check_items={exp_name: c_name, exp_schema: schema})
|
|
|
|
@pytest.mark.tags(CaseLabel.L1)
|
|
def test_collection_with_muti_string_fields(self):
|
|
"""
|
|
target: test create collection with muti string fields
|
|
method: 1. create collection with primary string field and not primary string field
|
|
2. string fields is_primary=True
|
|
expected: Create collection successfully
|
|
"""
|
|
self._connect()
|
|
c_name = cf.gen_unique_str(prefix)
|
|
int_field = cf.gen_int64_field()
|
|
vec_field = cf.gen_float_vec_field()
|
|
string_field_1 = cf.gen_string_field(is_primary=True)
|
|
string_field_2 = cf.gen_string_field(name=c_name)
|
|
schema = cf.gen_collection_schema(fields=[int_field, string_field_1, string_field_2, vec_field])
|
|
self.collection_wrap.init_collection(name=c_name, schema=schema,
|
|
check_task=CheckTasks.check_collection_property,
|
|
check_items={exp_name: c_name, exp_schema: schema})
|
|
|
|
@pytest.mark.tags(CaseLabel.L1)
|
|
def test_collection_only_string_field(self):
|
|
"""
|
|
target: test create collection with one string field
|
|
method: create collection with only string field
|
|
expected: Raise exception
|
|
"""
|
|
self._connect()
|
|
string_field = cf.gen_string_field(is_primary=True)
|
|
schema = cf.gen_collection_schema([string_field])
|
|
error = {ct.err_code: 0, ct.err_msg: "No vector field is found"}
|
|
self.collection_wrap.init_collection(name=cf.gen_unique_str(prefix), schema=schema,
|
|
check_task=CheckTasks.err_res, check_items=error)
|
|
|
|
@pytest.mark.tags(CaseLabel.L1)
|
|
def test_collection_string_field_with_exceed_max_len(self):
|
|
"""
|
|
target: test create collection with string field
|
|
method: 1. create collection with string field
|
|
2. String field max_length exceeds maximum
|
|
expected: Raise exception
|
|
"""
|
|
self._connect()
|
|
c_name = cf.gen_unique_str(prefix)
|
|
int_field = cf.gen_int64_field(is_primary=True)
|
|
vec_field = cf.gen_float_vec_field()
|
|
max_length = 100000
|
|
string_field = cf.gen_string_field(max_length=max_length)
|
|
schema = cf.gen_collection_schema([int_field, string_field, vec_field])
|
|
error = {ct.err_code: 65535, ct.err_msg: "the maximum length specified for a VarChar should be in (0, 65535]"}
|
|
self.collection_wrap.init_collection(name=c_name, schema=schema,
|
|
check_task=CheckTasks.err_res, check_items=error)
|
|
|
|
@pytest.mark.tags(CaseLabel.L1)
|
|
def test_collection_invalid_string_field_dtype(self):
|
|
"""
|
|
target: test create collection with string field
|
|
method: create collection with string field, the string field datatype is invaild
|
|
expected: Raise exception
|
|
"""
|
|
self._connect()
|
|
string_field = self.field_schema_wrap.init_field_schema(name="string", dtype=DataType.STRING)[0]
|
|
int_field = cf.gen_int64_field(is_primary=True)
|
|
vec_field = cf.gen_float_vec_field()
|
|
schema = cf.gen_collection_schema(fields=[int_field, string_field, vec_field])
|
|
error = {ct.err_code: 0, ct.err_msg: "string data type not supported yet, please use VarChar type instead"}
|
|
self.collection_wrap.init_collection(name=cf.gen_unique_str(prefix), schema=schema,
|
|
check_task=CheckTasks.err_res, check_items=error)
|
|
|
|
@pytest.mark.tags(CaseLabel.L1)
|
|
def test_collection_string_field_is_primary_and_auto_id(self):
|
|
"""
|
|
target: test create collection with string field
|
|
method: create collection with string field, the string field primary and auto id are true
|
|
expected: Create collection successfully
|
|
"""
|
|
self._connect()
|
|
int_field = cf.gen_int64_field()
|
|
vec_field = cf.gen_float_vec_field()
|
|
string_field = cf.gen_string_field(is_primary=True, auto_id=True)
|
|
fields = [int_field, string_field, vec_field]
|
|
schema = self.collection_schema_wrap.init_collection_schema(fields=fields)[0]
|
|
self.init_collection_wrap(schema=schema, check_task=CheckTasks.check_collection_property,
|
|
check_items={"schema": schema, "primary": ct.default_string_field_name})
|
|
|
|
|
|
class TestCollectionJSON(TestcaseBase):
|
|
"""
|
|
******************************************************************
|
|
The following cases are used to test about json
|
|
******************************************************************
|
|
"""
|
|
@pytest.mark.tags(CaseLabel.L1)
|
|
@pytest.mark.parametrize("auto_id", [True, False])
|
|
def test_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 (not supported)
|
|
"""
|
|
self._connect()
|
|
int_field = cf.gen_int64_field()
|
|
vec_field = cf.gen_float_vec_field()
|
|
string_field = cf.gen_string_field()
|
|
# 1. create json field as primary key through field schema api
|
|
error = {ct.err_code: 1, ct.err_msg: "Primary key type must be DataType.INT64 or DataType.VARCHAR"}
|
|
json_field = cf.gen_json_field(is_primary=True, auto_id=auto_id)
|
|
fields = [int_field, string_field, json_field, vec_field]
|
|
self.collection_schema_wrap.init_collection_schema(fields=fields,
|
|
check_task=CheckTasks.err_res, check_items=error)
|
|
# 2. create json field as primary key through collection schema api
|
|
json_field = cf.gen_json_field()
|
|
fields = [int_field, string_field, json_field, vec_field]
|
|
self.collection_schema_wrap.init_collection_schema(fields=fields, primary_field=ct.default_json_field_name,
|
|
check_task=CheckTasks.err_res, check_items=error)
|
|
|
|
@pytest.mark.tags(CaseLabel.L2)
|
|
@pytest.mark.parametrize("primary_field", [ct.default_float_field_name, ct.default_json_field_name])
|
|
def test_collection_json_field_partition_key(self, primary_field):
|
|
"""
|
|
target: test create collection with multiple JSON fields
|
|
method: 1. create collection with multiple JSON fields, primary key field and vector field
|
|
2. set json field is_primary=false
|
|
expected: Raise exception
|
|
"""
|
|
self._connect()
|
|
cf.gen_unique_str(prefix)
|
|
error = {ct.err_code: 1, ct.err_msg: "Partition key field type must be DataType.INT64 or DataType.VARCHAR."}
|
|
cf.gen_json_default_collection_schema(primary_field=primary_field, is_partition_key=True,
|
|
check_task=CheckTasks.err_res, check_items=error)
|
|
|
|
@pytest.mark.tags(CaseLabel.L0)
|
|
@pytest.mark.parametrize("primary_field", [ct.default_int64_field_name, ct.default_string_field_name])
|
|
def test_collection_json_field_supported_primary_key(self, primary_field):
|
|
"""
|
|
target: test create collection with one JSON field
|
|
method: 1. create collection with one JSON field, primary key field and vector field
|
|
2. set json field is_primary=false
|
|
expected: Create collection successfully
|
|
"""
|
|
self._connect()
|
|
c_name = cf.gen_unique_str(prefix)
|
|
schema = cf.gen_json_default_collection_schema(primary_field=primary_field)
|
|
self.collection_wrap.init_collection(name=c_name, schema=schema,
|
|
check_task=CheckTasks.check_collection_property,
|
|
check_items={exp_name: c_name, exp_schema: schema})
|
|
|
|
@pytest.mark.tags(CaseLabel.L2)
|
|
@pytest.mark.parametrize("primary_field", [ct.default_int64_field_name, ct.default_string_field_name])
|
|
def test_collection_multiple_json_fields_supported_primary_key(self, primary_field):
|
|
"""
|
|
target: test create collection with multiple JSON fields
|
|
method: 1. create collection with multiple JSON fields, primary key field and vector field
|
|
2. set json field is_primary=false
|
|
expected: Create collection successfully
|
|
"""
|
|
self._connect()
|
|
c_name = cf.gen_unique_str(prefix)
|
|
schema = cf.gen_multiple_json_default_collection_schema(primary_field=primary_field)
|
|
self.collection_wrap.init_collection(name=c_name, schema=schema,
|
|
check_task=CheckTasks.check_collection_property,
|
|
check_items={exp_name: c_name, exp_schema: schema})
|
|
|
|
|
|
class TestCollectionARRAY(TestcaseBase):
|
|
"""
|
|
******************************************************************
|
|
The following cases are used to test about array
|
|
******************************************************************
|
|
"""
|
|
|
|
@pytest.mark.tags(CaseLabel.L2)
|
|
def test_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
|
|
"""
|
|
int_field = cf.gen_int64_field(is_primary=True)
|
|
vec_field = cf.gen_float_vec_field()
|
|
array_field = cf.gen_array_field(element_type=None)
|
|
array_schema = cf.gen_collection_schema([int_field, vec_field, array_field])
|
|
self.init_collection_wrap(schema=array_schema, check_task=CheckTasks.err_res,
|
|
check_items={ct.err_code: 65535, ct.err_msg: "element data type None is not valid"})
|
|
|
|
@pytest.mark.tags(CaseLabel.L2)
|
|
# @pytest.mark.skip("issue #27522")
|
|
@pytest.mark.parametrize("element_type", [1001, 'a', [], (), {1}, DataType.BINARY_VECTOR,
|
|
DataType.FLOAT_VECTOR, DataType.JSON, DataType.ARRAY])
|
|
def test_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
|
|
"""
|
|
int_field = cf.gen_int64_field(is_primary=True)
|
|
vec_field = cf.gen_float_vec_field()
|
|
array_field = cf.gen_array_field(element_type=element_type)
|
|
array_schema = cf.gen_collection_schema([int_field, vec_field, array_field])
|
|
error = {ct.err_code: 65535, ct.err_msg: "element data type None is not valid"}
|
|
if element_type in ['a', {1}]:
|
|
error = {ct.err_code: 1, ct.err_msg: "Unexpected error"}
|
|
self.init_collection_wrap(schema=array_schema, check_task=CheckTasks.err_res, check_items=error)
|
|
|
|
@pytest.mark.tags(CaseLabel.L2)
|
|
@pytest.mark.skip("https://github.com/milvus-io/pymilvus/issues/2041")
|
|
def test_collection_array_field_no_capacity(self):
|
|
"""
|
|
target: Create a field without giving max_capacity
|
|
method: Create a field without giving max_capacity
|
|
expected: Raise exception
|
|
"""
|
|
int_field = cf.gen_int64_field(is_primary=True)
|
|
vec_field = cf.gen_float_vec_field()
|
|
array_field = cf.gen_array_field(max_capacity=None)
|
|
array_schema = cf.gen_collection_schema([int_field, vec_field, array_field])
|
|
self.init_collection_wrap(schema=array_schema, check_task=CheckTasks.err_res,
|
|
check_items={ct.err_code: 65535,
|
|
ct.err_msg: "the value of max_capacity must be an integer"})
|
|
|
|
@pytest.mark.tags(CaseLabel.L2)
|
|
@pytest.mark.skip("https://github.com/milvus-io/pymilvus/issues/2041")
|
|
@pytest.mark.parametrize("max_capacity", [[], 'a', (), -1, 4097])
|
|
def test_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', ()
|
|
2. Value invalid: <0, >max_capacity(4096)
|
|
expected: Raise exception
|
|
"""
|
|
int_field = cf.gen_int64_field(is_primary=True)
|
|
vec_field = cf.gen_float_vec_field()
|
|
array_field = cf.gen_array_field(max_capacity=max_capacity)
|
|
array_schema = cf.gen_collection_schema([int_field, vec_field, array_field])
|
|
self.init_collection_wrap(schema=array_schema, check_task=CheckTasks.err_res,
|
|
check_items={ct.err_code: 65535,
|
|
ct.err_msg: "the maximum capacity specified for a "
|
|
"Array should be in (0, 4096]"})
|
|
|
|
@pytest.mark.tags(CaseLabel.L2)
|
|
def test_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
|
|
"""
|
|
int_field = cf.gen_int64_field(is_primary=True)
|
|
vec_field = cf.gen_float_vec_field()
|
|
array_field = cf.gen_array_field(element_type=DataType.VARCHAR)
|
|
array_schema = cf.gen_collection_schema([int_field, vec_field, array_field])
|
|
self.init_collection_wrap(schema=array_schema, check_task=CheckTasks.err_res,
|
|
check_items={ct.err_code: 65535,
|
|
ct.err_msg: "type param(max_length) should be specified for "
|
|
"varChar field of collection"})
|
|
|
|
@pytest.mark.tags(CaseLabel.L2)
|
|
@pytest.mark.skip("https://github.com/milvus-io/pymilvus/issues/2041")
|
|
@pytest.mark.parametrize("max_length", [[], 'a', (), -1, 65536])
|
|
def test_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
|
|
1. Type invalid: [], 'a', ()
|
|
2. Value invalid: <0, >max_length(65535)
|
|
expected: Raise exception
|
|
"""
|
|
int_field = cf.gen_int64_field(is_primary=True)
|
|
vec_field = cf.gen_float_vec_field()
|
|
array_field = cf.gen_array_field(element_type=DataType.VARCHAR, max_length=max_length)
|
|
array_schema = cf.gen_collection_schema([int_field, vec_field, array_field])
|
|
self.init_collection_wrap(schema=array_schema, check_task=CheckTasks.err_res,
|
|
check_items={ct.err_code: 65535,
|
|
ct.err_msg: "the maximum length specified for a VarChar "
|
|
"should be in (0, 65535]"})
|
|
|
|
@pytest.mark.tags(CaseLabel.L2)
|
|
def test_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: Raise exception
|
|
"""
|
|
# Create field respectively
|
|
nb = ct.default_nb
|
|
pk_field = cf.gen_int64_field(is_primary=True)
|
|
vec_field = cf.gen_float_vec_field()
|
|
int8_array = cf.gen_array_field(name="int8_array", element_type=DataType.INT8, max_capacity=nb)
|
|
int16_array = cf.gen_array_field(name="int16_array", element_type=DataType.INT16, max_capacity=nb)
|
|
int32_array = cf.gen_array_field(name="int32_array", element_type=DataType.INT32, max_capacity=nb)
|
|
int64_array = cf.gen_array_field(name="int64_array", element_type=DataType.INT64, max_capacity=nb)
|
|
bool_array = cf.gen_array_field(name="bool_array", element_type=DataType.BOOL, max_capacity=nb)
|
|
float_array = cf.gen_array_field(name="float_array", element_type=DataType.FLOAT, max_capacity=nb)
|
|
double_array = cf.gen_array_field(name="double_array", element_type=DataType.DOUBLE, max_capacity=nb)
|
|
string_array = cf.gen_array_field(name="string_array", element_type=DataType.VARCHAR, max_capacity=nb,
|
|
max_length=100)
|
|
array_schema = cf.gen_collection_schema([pk_field, vec_field, int8_array, int16_array, int32_array,
|
|
int64_array, bool_array, float_array, double_array, string_array])
|
|
collection_w = self.init_collection_wrap(schema=array_schema,
|
|
check_task=CheckTasks.check_collection_property,
|
|
check_items={exp_schema: array_schema})
|
|
|
|
# check array in collection.describe()
|
|
res = collection_w.describe()[0]
|
|
log.info(res)
|
|
fields = [
|
|
{"field_id": 100, "name": "int64", "description": "", "type": 5, "params": {},
|
|
"element_type": 0, "is_primary": True},
|
|
{"field_id": 101, "name": "float_vector", "description": "", "type": 101,
|
|
"params": {"dim": ct.default_dim}, "element_type": 0},
|
|
{"field_id": 102, "name": "int8_array", "description": "", "type": 22,
|
|
"params": {"max_capacity": 2000}, "element_type": 2},
|
|
{"field_id": 103, "name": "int16_array", "description": "", "type": 22,
|
|
"params": {"max_capacity": 2000}, "element_type": 3},
|
|
{"field_id": 104, "name": "int32_array", "description": "", "type": 22,
|
|
"params": {"max_capacity": 2000}, "element_type": 4},
|
|
{"field_id": 105, "name": "int64_array", "description": "", "type": 22,
|
|
"params": {"max_capacity": 2000}, "element_type": 5},
|
|
{"field_id": 106, "name": "bool_array", "description": "", "type": 22,
|
|
"params": {"max_capacity": 2000}, "element_type": 1},
|
|
{"field_id": 107, "name": "float_array", "description": "", "type": 22,
|
|
"params": {"max_capacity": 2000}, "element_type": 10},
|
|
{"field_id": 108, "name": "double_array", "description": "", "type": 22,
|
|
"params": {"max_capacity": 2000}, "element_type": 11},
|
|
{"field_id": 109, "name": "string_array", "description": "", "type": 22,
|
|
"params": {"max_length": 100, "max_capacity": 2000}, "element_type": 21}
|
|
]
|
|
# assert res["fields"] == fields
|
|
|
|
# Insert data respectively
|
|
nb = 10
|
|
pk_values = [i for i in range(nb)]
|
|
float_vec = cf.gen_vectors(nb, ct.default_dim)
|
|
int8_values = [[numpy.int8(j) for j in range(nb)] for i in range(nb)]
|
|
int16_values = [[numpy.int16(j) for j in range(nb)] for i in range(nb)]
|
|
int32_values = [[numpy.int32(j) for j in range(nb)] for i in range(nb)]
|
|
int64_values = [[numpy.int64(j) for j in range(nb)] for i in range(nb)]
|
|
bool_values = [[numpy.bool_(j) for j in range(nb)] for i in range(nb)]
|
|
float_values = [[numpy.float32(j) for j in range(nb)] for i in range(nb)]
|
|
double_values = [[numpy.double(j) for j in range(nb)] for i in range(nb)]
|
|
string_values = [[str(j) for j in range(nb)] for i in range(nb)]
|
|
data = [pk_values, float_vec, int8_values, int16_values, int32_values, int64_values,
|
|
bool_values, float_values, double_values, string_values]
|
|
collection_w.insert(data)
|
|
|
|
# check insert successfully
|
|
collection_w.flush()
|
|
collection_w.num_entities == nb
|
|
|
|
|
|
class TestCollectionMultipleVectorValid(TestcaseBase):
|
|
"""
|
|
******************************************************************
|
|
# The followings are valid cases
|
|
******************************************************************
|
|
"""
|
|
|
|
@pytest.mark.tags(CaseLabel.L1)
|
|
@pytest.mark.parametrize("primary_key", [cf.gen_int64_field(is_primary=True), cf.gen_string_field(is_primary=True)])
|
|
@pytest.mark.parametrize("auto_id", [True, False])
|
|
@pytest.mark.parametrize("shards_num", [1, 3])
|
|
def test_create_collection_multiple_vectors_all_supported_field_type(self, primary_key, auto_id, shards_num):
|
|
"""
|
|
target: test create collection with multiple vector fields
|
|
method: create collection with multiple vector fields
|
|
expected: no exception
|
|
"""
|
|
self._connect()
|
|
c_name = cf.gen_unique_str(prefix)
|
|
int_fields = []
|
|
vector_limit_num = max_vector_field_num - 2
|
|
# add multiple vector fields
|
|
for i in range(vector_limit_num):
|
|
vector_field_name = cf.gen_unique_str("field_name")
|
|
field = cf.gen_float_vec_field(name=vector_field_name)
|
|
int_fields.append(field)
|
|
# add other vector fields to maximum fields num
|
|
int_fields.append(cf.gen_int8_field())
|
|
int_fields.append(cf.gen_int16_field())
|
|
int_fields.append(cf.gen_int32_field())
|
|
int_fields.append(cf.gen_float_field())
|
|
int_fields.append(cf.gen_double_field())
|
|
int_fields.append(cf.gen_string_field(cf.gen_unique_str("vchar_field_name")))
|
|
int_fields.append(cf.gen_json_field())
|
|
int_fields.append(cf.gen_bool_field())
|
|
int_fields.append(cf.gen_array_field())
|
|
int_fields.append(cf.gen_binary_vec_field())
|
|
int_fields.append(primary_key)
|
|
schema = cf.gen_collection_schema(fields=int_fields, auto_id=auto_id, shards_num=shards_num)
|
|
self.collection_wrap.init_collection(c_name, schema=schema, check_task=CheckTasks.check_collection_property,
|
|
check_items={exp_name: c_name, exp_schema: schema})
|
|
self.collection_wrap.init_collection(c_name, schema=schema, check_task=CheckTasks.check_collection_property,
|
|
check_items={exp_name: c_name, exp_schema: schema})
|
|
|
|
@pytest.mark.tags(CaseLabel.L2)
|
|
@pytest.mark.parametrize("primary_key", [ct.default_int64_field_name, ct.default_string_field_name])
|
|
@pytest.mark.parametrize("auto_id", [True, False])
|
|
@pytest.mark.parametrize("enable_dynamic_field", [True, False])
|
|
def test_create_collection_multiple_vectors_different_dim(self, primary_key, auto_id, enable_dynamic_field):
|
|
"""
|
|
target: test create collection with multiple vector fields (different dim)
|
|
method: create collection with multiple vector fields
|
|
expected: no exception
|
|
"""
|
|
self._connect()
|
|
c_name = cf.gen_unique_str(prefix)
|
|
another_dim = ct.min_dim
|
|
schema = cf.gen_default_collection_schema(primary_field=primary_key, auto_id=auto_id, dim=ct.max_dim,
|
|
enable_dynamic_field=enable_dynamic_field,
|
|
multiple_dim_array=[another_dim])
|
|
self.collection_wrap.init_collection(c_name, schema=schema, check_task=CheckTasks.check_collection_property,
|
|
check_items={exp_name: c_name, exp_schema: schema})
|
|
|
|
@pytest.mark.tags(CaseLabel.L2)
|
|
@pytest.mark.parametrize("primary_key", [ct.default_int64_field_name, ct.default_string_field_name])
|
|
def test_create_collection_multiple_vectors_maximum_dim(self, primary_key):
|
|
"""
|
|
target: test create collection with multiple vector fields
|
|
method: create collection with multiple vector fields
|
|
expected: no exception
|
|
"""
|
|
self._connect()
|
|
c_name = cf.gen_unique_str(prefix)
|
|
schema = cf.gen_default_collection_schema(primary_field=primary_key, dim=ct.max_dim,
|
|
multiple_dim_array=[ct.max_dim])
|
|
self.collection_wrap.init_collection(c_name, schema=schema, check_task=CheckTasks.check_collection_property,
|
|
check_items={exp_name: c_name, exp_schema: schema})
|
|
|
|
@pytest.mark.tags(CaseLabel.L2)
|
|
@pytest.mark.parametrize("primary_key", [cf.gen_int64_field(is_primary=True), cf.gen_string_field(is_primary=True)])
|
|
@pytest.mark.parametrize("auto_id", [True, False])
|
|
@pytest.mark.parametrize("par_key_field", [ct.default_int64_field_name, ct.default_string_field_name])
|
|
def test_create_collection_multiple_vectors_partition_key(self, primary_key, auto_id, par_key_field):
|
|
"""
|
|
target: test create collection with multiple vector fields
|
|
method: create collection with multiple vector fields
|
|
expected: no exception
|
|
"""
|
|
self._connect()
|
|
c_name = cf.gen_unique_str(prefix)
|
|
int_fields = []
|
|
vector_limit_num = max_vector_field_num - 2
|
|
# add multiple vector fields
|
|
for i in range(vector_limit_num):
|
|
vector_field_name = cf.gen_unique_str("field_name")
|
|
field = cf.gen_float_vec_field(name=vector_field_name)
|
|
int_fields.append(field)
|
|
# add other vector fields to maximum fields num
|
|
int_fields.append(cf.gen_int8_field())
|
|
int_fields.append(cf.gen_int16_field())
|
|
int_fields.append(cf.gen_int32_field())
|
|
int_fields.append(cf.gen_int64_field(cf.gen_unique_str("int_field_name"),
|
|
is_partition_key=(par_key_field == ct.default_int64_field_name)))
|
|
int_fields.append(cf.gen_float_field())
|
|
int_fields.append(cf.gen_double_field())
|
|
int_fields.append(cf.gen_string_field(cf.gen_unique_str("vchar_field_name"),
|
|
is_partition_key=(par_key_field == ct.default_string_field_name)))
|
|
int_fields.append(cf.gen_json_field())
|
|
int_fields.append(cf.gen_bool_field())
|
|
int_fields.append(cf.gen_array_field())
|
|
int_fields.append(cf.gen_binary_vec_field())
|
|
int_fields.append(primary_key)
|
|
schema = cf.gen_collection_schema(fields=int_fields, auto_id=auto_id)
|
|
collection_w = \
|
|
self.collection_wrap.init_collection(c_name, schema=schema, check_task=CheckTasks.check_collection_property,
|
|
check_items={exp_name: c_name, exp_schema: schema})[0]
|
|
assert len(collection_w.partitions) == ct.default_partition_num
|
|
|
|
|
|
class TestCollectionMultipleVectorInvalid(TestcaseBase):
|
|
""" Test case of search interface """
|
|
|
|
@pytest.fixture(scope="function", params=ct.invalid_dims)
|
|
def get_invalid_dim(self, request):
|
|
yield request.param
|
|
|
|
"""
|
|
******************************************************************
|
|
# The followings are invalid cases
|
|
******************************************************************
|
|
"""
|
|
|
|
@pytest.mark.tags(CaseLabel.L1)
|
|
@pytest.mark.parametrize("primary_key", [cf.gen_int64_field(is_primary=True), cf.gen_string_field(is_primary=True)])
|
|
def test_create_collection_multiple_vectors_same_vector_field_name(self, primary_key):
|
|
"""
|
|
target: test create collection with multiple vector fields
|
|
method: create collection with multiple vector fields
|
|
expected: no exception
|
|
"""
|
|
self._connect()
|
|
c_name = cf.gen_unique_str(prefix)
|
|
int_fields = []
|
|
vector_limit_num = max_vector_field_num - 2
|
|
# add multiple vector fields
|
|
for i in range(vector_limit_num):
|
|
field = cf.gen_float_vec_field()
|
|
int_fields.append(field)
|
|
# add other vector fields to maximum fields num
|
|
int_fields.append(cf.gen_int8_field())
|
|
int_fields.append(cf.gen_int16_field())
|
|
int_fields.append(cf.gen_int32_field())
|
|
int_fields.append(cf.gen_float_field())
|
|
int_fields.append(cf.gen_double_field())
|
|
int_fields.append(cf.gen_string_field(cf.gen_unique_str("vchar_field_name")))
|
|
int_fields.append(cf.gen_json_field())
|
|
int_fields.append(cf.gen_bool_field())
|
|
int_fields.append(cf.gen_array_field())
|
|
int_fields.append(cf.gen_binary_vec_field())
|
|
int_fields.append(primary_key)
|
|
schema = cf.gen_collection_schema(fields=int_fields)
|
|
error = {ct.err_code: 65535, ct.err_msg: "duplicated field name"}
|
|
self.collection_wrap.init_collection(c_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_create_collection_multiple_vectors_invalid_part_vector_field_name(self, invalid_vector_name):
|
|
"""
|
|
target: test create collection with multiple vector fields
|
|
method: create collection with multiple vector fields
|
|
expected: no exception
|
|
"""
|
|
self._connect()
|
|
c_name = cf.gen_unique_str(prefix)
|
|
int_fields = []
|
|
# add multiple vector fields
|
|
vector_field_1 = cf.gen_float_vec_field(name=invalid_vector_name)
|
|
int_fields.append(vector_field_1)
|
|
vector_field_2 = cf.gen_float_vec_field(name="valid_field_name")
|
|
int_fields.append(vector_field_2)
|
|
# add other vector fields to maximum fields num
|
|
int_fields.append(cf.gen_int64_field(is_primary=True))
|
|
schema = cf.gen_collection_schema(fields=int_fields)
|
|
error = {ct.err_code: 1701, ct.err_msg: "Invalid field name: %s" % invalid_vector_name}
|
|
self.collection_wrap.init_collection(c_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_create_collection_multiple_vectors_invalid_all_vector_field_name(self, invalid_vector_name):
|
|
"""
|
|
target: test create collection with multiple vector fields
|
|
method: create collection with multiple vector fields
|
|
expected: no exception
|
|
"""
|
|
self._connect()
|
|
c_name = cf.gen_unique_str(prefix)
|
|
int_fields = []
|
|
# add multiple vector fields
|
|
vector_field_1 = cf.gen_float_vec_field(name=invalid_vector_name)
|
|
int_fields.append(vector_field_1)
|
|
vector_field_2 = cf.gen_float_vec_field(name=invalid_vector_name + " ")
|
|
int_fields.append(vector_field_2)
|
|
# add other vector fields to maximum fields num
|
|
int_fields.append(cf.gen_int64_field(is_primary=True))
|
|
schema = cf.gen_collection_schema(fields=int_fields)
|
|
error = {ct.err_code: 1701, ct.err_msg: "Invalid field name: %s" % invalid_vector_name}
|
|
self.collection_wrap.init_collection(c_name, schema=schema, check_task=CheckTasks.err_res, check_items=error)
|
|
|
|
@pytest.mark.tags(CaseLabel.L1)
|
|
@pytest.mark.skip(reason="issue #29796")
|
|
def test_create_collection_multiple_vectors_invalid_dim(self, get_invalid_dim):
|
|
"""
|
|
target: test create collection with multiple vector fields
|
|
method: create collection with multiple vector fields
|
|
expected: no exception
|
|
"""
|
|
self._connect()
|
|
c_name = cf.gen_unique_str(prefix)
|
|
int_fields = []
|
|
# add multiple vector fields
|
|
vector_field_1 = cf.gen_float_vec_field(dim=get_invalid_dim)
|
|
int_fields.append(vector_field_1)
|
|
vector_field_2 = cf.gen_float_vec_field(name="float_vec_field")
|
|
int_fields.append(vector_field_2)
|
|
# add other vector fields to maximum fields num
|
|
int_fields.append(cf.gen_int64_field(is_primary=True))
|
|
schema = cf.gen_collection_schema(fields=int_fields)
|
|
error = {ct.err_code: 65535, ct.err_msg: "Invalid dim"}
|
|
self.collection_wrap.init_collection(c_name, schema=schema, check_task=CheckTasks.err_res, check_items=error)
|
|
|
|
|
|
class TestCollectionMmap(TestcaseBase):
|
|
@pytest.mark.tags(CaseLabel.L1)
|
|
def test_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
|
|
"""
|
|
self._connect()
|
|
c_name = cf.gen_unique_str(prefix)
|
|
collection_w, _ = self.collection_wrap.init_collection(c_name, schema=default_schema)
|
|
collection_w.set_properties({'mmap.enabled': True})
|
|
pro = collection_w.describe().get("properties")
|
|
assert "mmap.enabled" in pro.keys()
|
|
assert pro["mmap.enabled"] == 'True'
|
|
collection_w.set_properties({'mmap.enabled': False})
|
|
pro = collection_w.describe().get("properties")
|
|
assert pro["mmap.enabled"] == 'False'
|
|
collection_w.set_properties({'mmap.enabled': True})
|
|
pro = collection_w.describe().get("properties")
|
|
assert pro["mmap.enabled"] == 'True'
|
|
|
|
@pytest.mark.tags(CaseLabel.L1)
|
|
def test_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
|
|
"""
|
|
c_name = cf.gen_unique_str(prefix)
|
|
collection_w = self.init_collection_wrap(c_name, schema=default_schema)
|
|
collection_w.insert(cf.gen_default_list_data())
|
|
collection_w.create_index(ct.default_float_vec_field_name, index_params=ct.default_flat_index,
|
|
index_name=ct.default_index_name)
|
|
collection_w.set_properties({'mmap.enabled': True})
|
|
pro = collection_w.describe()[0].get("properties")
|
|
assert pro["mmap.enabled"] == 'True'
|
|
collection_w.load()
|
|
collection_w.set_properties({'mmap.enabled': True},
|
|
check_task=CheckTasks.err_res,
|
|
check_items={ct.err_code: 104,
|
|
ct.err_msg: f"collection already loaded"})
|
|
|
|
@pytest.mark.tags(CaseLabel.L2)
|
|
def test_drop_mmap_collection(self):
|
|
"""
|
|
target: set mmap on collection
|
|
method: 1. set mmap on collection
|
|
2. drop collection
|
|
3. describe collection
|
|
expected: description information contains mmap
|
|
"""
|
|
self._connect()
|
|
c_name = "coll_rand"
|
|
collection_w, _ = self.collection_wrap.init_collection(c_name, schema=default_schema)
|
|
collection_w.set_properties({'mmap.enabled': True})
|
|
collection_w.drop()
|
|
collection_w, _ = self.collection_wrap.init_collection(c_name, schema=default_schema)
|
|
pro = collection_w.describe().get("properties")
|
|
assert "mmap.enabled" not in pro.keys()
|
|
|
|
@pytest.mark.tags(CaseLabel.L2)
|
|
def test_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
|
|
"""
|
|
self._connect()
|
|
c_name = "coll_1"
|
|
c_name2 = "coll_2"
|
|
c_name3 = "coll_3"
|
|
collection_w, _ = self.collection_wrap.init_collection(c_name, schema=default_schema)
|
|
collection_w2, _ = self.collection_wrap.init_collection(c_name2, schema=default_schema)
|
|
collection_w3, _ = self.collection_wrap.init_collection(c_name3, schema=default_schema)
|
|
collection_w.set_properties({'mmap.enabled': True})
|
|
collection_w2.set_properties({'mmap.enabled': True})
|
|
pro = collection_w.describe().get("properties")
|
|
pro2 = collection_w2.describe().get("properties")
|
|
assert pro["mmap.enabled"] == 'True'
|
|
assert pro2["mmap.enabled"] == 'True'
|
|
collection_w3.set_properties({'mmap.enabled': True})
|
|
pro3 = collection_w3.describe().get("properties")
|
|
assert pro3["mmap.enabled"] == 'True'
|
|
|
|
@pytest.mark.tags(CaseLabel.L2)
|
|
def test_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
|
|
"""
|
|
self._connect()
|
|
c_name = cf.gen_unique_str(prefix)
|
|
collection_w, _ = self.collection_wrap.init_collection(c_name, schema=default_schema)
|
|
collection_w.insert(cf.gen_default_list_data())
|
|
collection_w.create_index(ct.default_float_vec_field_name, index_params=ct.default_flat_index,
|
|
index_name=ct.default_index_name)
|
|
collection_w.alter_index(ct.default_index_name, {'mmap.enabled': False})
|
|
collection_w.flush()
|
|
collection_w.set_properties({'mmap.enabled': True})
|
|
pro = collection_w.describe().get("properties")
|
|
assert pro["mmap.enabled"] == 'True'
|
|
collection_w.alter_index(ct.default_index_name, {'mmap.enabled': True})
|
|
collection_w.load()
|
|
vectors = [[random.random() for _ in range(default_dim)] for _ in range(default_nq)]
|
|
collection_w.search(vectors[:default_nq], default_search_field,
|
|
default_search_params, default_limit,
|
|
default_search_exp,
|
|
check_task=CheckTasks.check_search_results,
|
|
check_items={"nq": default_nq,
|
|
"limit": default_limit})
|
|
|
|
@pytest.mark.tags(CaseLabel.L2)
|
|
def test_enable_mmap_after_drop_collection(self):
|
|
"""
|
|
target: enable mmap after deleting a collection
|
|
method: enable mmap after deleting a collection
|
|
expected: raise exception
|
|
"""
|
|
collection_w = self.init_collection_general(prefix, True, is_binary=True, is_index=False)[0]
|
|
collection_w.drop()
|
|
collection_w.set_properties({'mmap.enabled': True}, check_task=CheckTasks.err_res,
|
|
check_items={ct.err_code: 100,
|
|
ct.err_msg: f"collection not found"}) |