yanliang567 70b311735b
test: [E2e Refactor] use vector datatype instead of hard code dataype names (#41497)
related issue: #40698 
1. use vector datat types instead of hard code datatpe names
2. update search pagination tests
3. remove checking distances in search results checking, for knowhere
customize the distances for different metrics and indexes. Now only
assert the distances are sorted correct.

---------

Signed-off-by: yanliang567 <yanliang.qiao@zilliz.com>
2025-04-25 10:46:38 +08:00

776 lines
36 KiB
Python

from pymilvus.client.types import CompactionPlans
from pymilvus import Role
from utils.util_log import test_log as log
from common import common_type as ct
from common import common_func as cf
from common.common_type import CheckTasks, Connect_Object_Name
# from common.code_mapping import ErrorCode, ErrorMessage
from pymilvus import Collection, Partition, ResourceGroupInfo
import check.param_check as pc
class Error:
def __init__(self, error):
self.code = getattr(error, 'code', -1)
self.message = getattr(error, 'message', str(error))
def __str__(self):
return f"Error(code={self.code}, message={self.message})"
def __repr__(self):
return f"Error(code={self.code}, message={self.message})"
class ResponseChecker:
def __init__(self, response, func_name, check_task, check_items, is_succ=True, **kwargs):
self.response = response # response of api request
self.func_name = func_name # api function name
self.check_task = check_task # task to check response of the api request
self.check_items = check_items # check items and expectations that to be checked in check task
self.succ = is_succ # api responses successful or not
self.kwargs_dict = {} # not used for now, just for extension
for key, value in kwargs.items():
self.kwargs_dict[key] = value
self.keys = self.kwargs_dict.keys()
def run(self):
"""
Method: start response checking for milvus API call
"""
result = True
if self.check_task is None:
# Interface normal return check
result = self.assert_succ(self.succ, True)
elif self.check_task == CheckTasks.err_res:
# Interface return error code and error message check
result = self.assert_exception(self.response, self.succ, self.check_items)
elif self.check_task == CheckTasks.check_nothing:
return self.succ
elif self.check_task == CheckTasks.ccr:
# Connection interface response check
result = self.check_value_equal(self.response, self.func_name, self.check_items)
elif self.check_task == CheckTasks.check_collection_property:
# Collection interface response check
result = self.check_collection_property(self.response, self.func_name, self.check_items)
elif self.check_task == CheckTasks.check_partition_property:
# Partition interface response check
result = self.check_partition_property(self.response, self.func_name, self.check_items)
elif self.check_task == CheckTasks.check_search_results:
# Search interface of collection and partition that response check
result = self.check_search_results(self.response, self.func_name, self.check_items)
elif self.check_task == CheckTasks.check_search_iterator:
# Search iterator interface of collection and partition that response check
result = self.check_search_iterator(self.response, self.func_name, self.check_items)
elif self.check_task == CheckTasks.check_query_results:
# Query interface of collection and partition that response check
result = self.check_query_results(self.response, self.func_name, self.check_items)
elif self.check_task == CheckTasks.check_query_iterator:
# query iterator interface of collection and partition that response check
result = self.check_query_iterator(self.response, self.func_name, self.check_items)
elif self.check_task == CheckTasks.check_query_empty:
result = self.check_query_empty(self.response, self.func_name)
elif self.check_task == CheckTasks.check_query_empty:
result = self.check_query_not_empty(self.response, self.func_name)
elif self.check_task == CheckTasks.check_distance:
# Calculate distance interface that response check
result = self.check_distance(self.response, self.func_name, self.check_items)
elif self.check_task == CheckTasks.check_delete_compact:
result = self.check_delete_compact_plan(self.response, self.func_name, self.check_items)
elif self.check_task == CheckTasks.check_merge_compact:
result = self.check_merge_compact_plan(self.response, self.func_name, self.check_items)
elif self.check_task == CheckTasks.check_role_property:
# Collection interface response check
result = self.check_role_property(self.response, self.func_name, self.check_items)
elif self.check_task == CheckTasks.check_permission_deny:
# Collection interface response check
result = self.check_permission_deny(self.response, self.succ)
elif self.check_task == CheckTasks.check_auth_failure:
# connection interface response check
result = self.check_auth_failure(self.response, self.succ)
elif self.check_task == CheckTasks.check_rg_property:
# describe resource group interface response check
result = self.check_rg_property(self.response, self.func_name, self.check_items)
elif self.check_task == CheckTasks.check_describe_collection_property:
# describe collection interface(high level api) response check
result = self.check_describe_collection_property(self.response, self.func_name, self.check_items)
elif self.check_task == CheckTasks.check_collection_fields_properties:
# check field properties in describe collection response
result = self.check_collection_fields_properties(self.response, self.func_name, self.check_items)
elif self.check_task == CheckTasks.check_describe_database_property:
# describe database interface(high level api) response check
result = self.check_describe_database_property(self.response, self.func_name, self.check_items)
elif self.check_task == CheckTasks.check_insert_result:
# check `insert` interface response
result = self.check_insert_response(check_items=self.check_items)
elif self.check_task == CheckTasks.check_describe_index_property:
# describe collection interface(high level api) response check
result = self.check_describe_index_property(self.response, self.func_name, self.check_items)
# Add check_items here if something new need verify
return result
def assert_succ(self, actual, expect):
assert actual is expect, f"Response of API {self.func_name} expect {expect}, but got {actual}"
return True
def assert_exception(self, res, actual=True, error_dict=None):
assert actual is False, f"Response of API {self.func_name} expect get error, but success"
assert len(error_dict) > 0
if isinstance(res, Error):
error_code = error_dict[ct.err_code]
# assert res.code == error_code or error_dict[ct.err_msg] in res.message, (
# f"Response of API {self.func_name} "
# f"expect get error code {error_dict[ct.err_code]} or error message {error_dict[ct.err_code]}, "
# f"but got {res.code} {res.message}")
assert error_dict[ct.err_msg] in res.message, (
f"Response of API {self.func_name} "
f"expect get error message {error_dict[ct.err_code]}, "
f"but got {res.code} {res.message}")
else:
log.error("[CheckFunc] Response of API is not an error: %s" % str(res))
assert False, (f"Response of API expect get error code {error_dict[ct.err_code]} or "
f"error message {error_dict[ct.err_code]}"
f"but success")
return True
@staticmethod
def check_value_equal(res, func_name, params):
""" check response of connection interface that result is normal """
if func_name == "list_connections":
if not isinstance(res, list):
log.error("[CheckFunc] Response of list_connections is not a list: %s" % str(res))
assert False
list_content = params.get(ct.list_content, None)
if not isinstance(list_content, list):
log.error("[CheckFunc] Check param of list_content is not a list: %s" % str(list_content))
assert False
new_res = pc.get_connect_object_name(res)
assert pc.list_equal_check(new_res, list_content)
if func_name == "get_connection_addr":
dict_content = params.get(ct.dict_content, None)
assert pc.dict_equal_check(res, dict_content)
if func_name == "connect":
type_name = type(res).__name__
assert not type_name.lower().__contains__("error")
if func_name == "has_connection":
value_content = params.get(ct.value_content, False)
res_obj = res if res is not None else False
assert res_obj == value_content
return True
@staticmethod
def check_collection_property(res, func_name, check_items):
"""
According to the check_items to check collection properties of res, which return from func_name
:param res: actual response of init collection
:type res: Collection
:param func_name: init collection API
:type func_name: str
:param check_items: which items expected to be checked, including name, schema, num_entities, primary
:type check_items: dict, {check_key: expected_value}
"""
exp_func_name = "init_collection"
exp_func_name_2 = "construct_from_dataframe"
if func_name != exp_func_name and func_name != exp_func_name_2:
log.warning("The function name is {} rather than {}".format(func_name, exp_func_name))
if isinstance(res, Collection):
collection = res
elif isinstance(res, tuple):
collection = res[0]
log.debug(collection.schema)
else:
raise Exception("The result to check isn't collection type object")
if len(check_items) == 0:
raise Exception("No expect values found in the check task")
if check_items.get("name", None):
assert collection.name == check_items.get("name")
if check_items.get("schema", None):
assert collection.schema == check_items.get("schema")
if check_items.get("num_entities", None):
if check_items.get("num_entities") == 0:
assert collection.is_empty
assert collection.num_entities == check_items.get("num_entities")
if check_items.get("primary", None):
assert collection.primary_field.name == check_items.get("primary")
return True
@staticmethod
def check_describe_collection_property(res, func_name, check_items):
"""
According to the check_items to check collection properties of res, which return from func_name
:param res: actual response of init collection
:type res: Collection
:param func_name: init collection API
:type func_name: str
:param check_items: which items expected to be checked, including name, schema, num_entities, primary
:type check_items: dict, {check_key: expected_value}
"""
exp_func_name = "describe_collection"
if func_name != exp_func_name:
log.warning("The function name is {} rather than {}".format(func_name, exp_func_name))
if len(check_items) == 0:
raise Exception("No expect values found in the check task")
if check_items.get("collection_name", None) is not None:
assert res["collection_name"] == check_items.get("collection_name")
if check_items.get("auto_id", False):
assert res["auto_id"] == check_items.get("auto_id")
if check_items.get("num_shards", 1):
assert res["num_shards"] == check_items.get("num_shards", 1)
if check_items.get("consistency_level", 2):
assert res["consistency_level"] == check_items.get("consistency_level", 2)
if check_items.get("enable_dynamic_field", True):
assert res["enable_dynamic_field"] == check_items.get("enable_dynamic_field", True)
if check_items.get("num_partitions", 1):
assert res["num_partitions"] == check_items.get("num_partitions", 1)
if check_items.get("id_name", "id"):
assert res["fields"][0]["name"] == check_items.get("id_name", "id")
if check_items.get("vector_name", "vector"):
assert res["fields"][1]["name"] == check_items.get("vector_name", "vector")
if check_items.get("dim", None) is not None:
assert res["fields"][1]["params"]["dim"] == check_items.get("dim")
if check_items.get("nullable_fields", None) is not None:
nullable_fields = check_items.get("nullable_fields")
if not isinstance(nullable_fields, list):
log.error("nullable_fields should be a list including all the nullable fields name")
assert False
for field in res["fields"]:
if field["name"] in nullable_fields:
assert field["nullable"] is True
assert res["fields"][0]["is_primary"] is True
assert res["fields"][0]["field_id"] == 100 and (res["fields"][0]["type"] == 5 or 21)
assert res["fields"][1]["field_id"] == 101 and res["fields"][1]["type"] == 101
return True
@staticmethod
def check_collection_fields_properties(res, func_name, check_items):
"""
According to the check_items to check collection field properties of res, which return from func_name
:param res: actual response of client.describe_collection()
:type res: Collection
:param func_name: describe_collection
:type func_name: str
:param check_items: which field properties expected to be checked, like max_length etc.
:type check_items: dict, {field_name: {field_properties}, ...}
"""
exp_func_name = "describe_collection"
if func_name != exp_func_name:
log.warning("The function name is {} rather than {}".format(func_name, exp_func_name))
if len(check_items) == 0:
raise Exception("No expect values found in the check task")
if check_items.get("collection_name", None) is not None:
assert res["collection_name"] == check_items.get("collection_name")
for key in check_items.keys():
for field in res["fields"]:
if field["name"] == key:
assert field['params'].items() >= check_items[key].items()
return True
@staticmethod
def check_describe_database_property(res, func_name, check_items):
"""
According to the check_items to check database properties of res, which return from func_name
:param res: actual response of init database
:type res: Database
:param func_name: init database API
:type func_name: str
:param check_items: which items expected to be checked
:type check_items: dict, {check_key: expected_value}
"""
exp_func_name = "describe_database"
if func_name != exp_func_name:
log.warning("The function name is {} rather than {}".format(func_name, exp_func_name))
if len(check_items) == 0:
raise Exception("No expect values found in the check task")
if check_items.get("db_name", None) is not None:
assert res["name"] == check_items.get("db_name")
if check_items.get("database.force.deny.writing", None) is not None:
if check_items.get("database.force.deny.writing") == "Missing":
assert "database.force.deny.writing" not in res
else:
assert res["database.force.deny.writing"] == check_items.get("database.force.deny.writing")
if check_items.get("database.force.deny.reading", None) is not None:
if check_items.get("database.force.deny.reading") == "Missing":
assert "database.force.deny.reading" not in res
else:
assert res["database.force.deny.reading"] == check_items.get("database.force.deny.reading")
if check_items.get("database.replica.number", None) is not None:
if check_items.get("database.replica.number") == "Missing":
assert "database.replica.number" not in res
else:
assert res["database.replica.number"] == check_items.get("database.replica.number")
if check_items.get("properties_length", None) is not None:
assert len(res) == check_items.get("properties_length")
return True
@staticmethod
def check_partition_property(partition, func_name, check_items):
exp_func_name = "init_partition"
if func_name != exp_func_name:
log.warning("The function name is {} rather than {}".format(func_name, exp_func_name))
if not isinstance(partition, Partition):
raise Exception("The result to check isn't partition type object")
if len(check_items) == 0:
raise Exception("No expect values found in the check task")
if check_items.get("name", None):
assert partition.name == check_items["name"]
if check_items.get("description", None):
assert partition.description == check_items["description"]
if check_items.get("is_empty", None):
assert partition.is_empty == check_items["is_empty"]
if check_items.get("num_entities", None):
assert partition.num_entities == check_items["num_entities"]
return True
@staticmethod
def check_rg_property(rg, func_name, check_items):
exp_func_name = "describe_resource_group"
if func_name != exp_func_name:
log.warning("The function name is {} rather than {}".format(func_name, exp_func_name))
if not isinstance(rg, ResourceGroupInfo):
raise Exception("The result to check isn't ResourceGroupInfo type object")
if len(check_items) == 0:
raise Exception("No expect values found in the check task")
if check_items.get("name", None):
assert rg.name == check_items["name"]
if check_items.get("capacity", None):
assert rg.capacity == check_items["capacity"]
if check_items.get("num_available_node", None):
assert rg.num_available_node == check_items["num_available_node"]
if check_items.get("num_loaded_replica", None):
assert dict(rg.num_loaded_replica).items() >= check_items["num_loaded_replica"].items()
if check_items.get("num_outgoing_node", None):
assert dict(rg.num_outgoing_node).items() >= check_items["num_outgoing_node"].items()
if check_items.get("num_incoming_node", None):
assert dict(rg.num_incoming_node).items() >= check_items["num_incoming_node"].items()
return True
@staticmethod
def check_search_results(search_res, func_name, check_items):
"""
target: check the search results
method: 1. check the query number
2. check the limit(topK) and ids
3. check the distance
expected: check the search is ok
"""
log.info("search_results_check: checking the searching results")
if func_name != 'search' and func_name != 'hybrid_search':
log.warning("The function name is {} rather than {} or {}".format(func_name, "search", "hybrid_search"))
if len(check_items) == 0:
raise Exception("No expect values found in the check task")
if check_items.get("_async", None):
if check_items["_async"]:
search_res.done()
search_res = search_res.result()
if check_items.get("output_fields", None):
assert set(search_res[0][0].entity.fields) == set(check_items["output_fields"])
log.info('search_results_check: Output fields of query searched is correct')
if check_items.get("original_entities", None):
original_entities = check_items["original_entities"][0]
pc.output_field_value_check(search_res, original_entities)
if len(search_res) != check_items["nq"]:
log.error("search_results_check: Numbers of query searched (%d) "
"is not equal with expected (%d)"
% (len(search_res), check_items["nq"]))
assert len(search_res) == check_items["nq"]
else:
log.info("search_results_check: Numbers of query searched is correct")
enable_milvus_client_api = check_items.get("enable_milvus_client_api", False)
# log.debug(search_res)
nq_i = 0
for hits in search_res:
searched_original_vectors = []
ids = []
distances = []
if enable_milvus_client_api:
for hit in hits:
ids.append(hit['id'])
distances.append(hit['distance'])
else:
ids = list(hits.ids)
distances = list(hits.distances)
if (len(hits) != check_items["limit"]) \
or (len(ids) != check_items["limit"]):
log.error("search_results_check: limit(topK) searched (%d) "
"is not equal with expected (%d)"
% (len(hits), check_items["limit"]))
assert len(hits) == check_items["limit"]
assert len(ids) == check_items["limit"]
else:
if check_items.get("ids", None) is not None:
ids_match = pc.list_contain_check(ids,
list(check_items["ids"]))
if not ids_match:
log.error("search_results_check: ids searched not match")
assert ids_match
elif check_items.get("metric", None) is not None:
# verify the distances are already sorted
if check_items.get("metric").upper() in ["IP", "COSINE", "BM25"]:
assert distances == sorted(distances, reverse=True)
else:
assert distances == sorted(distances, reverse=False)
if check_items.get("vector_nq") is None or check_items.get("original_vectors") is None:
log.debug("skip distance check for knowhere does not return the precise distances")
else:
# for id in ids:
# searched_original_vectors.append(check_items["original_vectors"][id])
# cf.compare_distance_vector_and_vector_list(check_items["vector_nq"][nq_i],
# searched_original_vectors,
# check_items["metric"], distances)
# log.info("search_results_check: Checked the distances for one nq: OK")
pass
else:
pass # just check nq and topk, not specific ids need check
nq_i += 1
log.info("search_results_check: limit (topK) and "
"ids searched for %d queries are correct" % len(search_res))
return True
@staticmethod
def check_search_iterator(search_res, func_name, check_items):
"""
target: check the search iterator results
method: 1. check the iterator number
2. check the limit(topK) and ids
3. check the distance
expected: check the search is ok
"""
log.info("search_iterator_results_check: checking the searching results")
if func_name != 'search_iterator':
log.warning("The function name is {} rather than {}".format(func_name, "search_iterator"))
search_iterator = search_res
expected_batch_size = check_items.get("batch_size", None)
expected_iterate_times = check_items.get("iterate_times", None)
pk_list = []
iterate_times = 0
while True:
try:
res = search_iterator.next()
iterate_times += 1
if not res:
log.info("search iteration finished, close")
search_iterator.close()
break
if expected_batch_size is not None:
assert len(res) <= expected_batch_size
if check_items.get("radius", None):
for distance in res.distances():
if check_items["metric_type"] == "L2":
assert distance < check_items["radius"]
else:
assert distance > check_items["radius"]
if check_items.get("range_filter", None):
for distance in res.distances():
if check_items["metric_type"] == "L2":
assert distance >= check_items["range_filter"]
else:
assert distance <= check_items["range_filter"]
pk_list.extend(res.ids())
except Exception as e:
assert check_items["err_msg"] in str(e)
return False
if expected_iterate_times is not None:
assert iterate_times <= expected_iterate_times
if expected_iterate_times == 1:
assert len(pk_list) == 0 # expected batch size =0 if external filter all
assert iterate_times == 1
return True
log.debug(f"check: total {len(pk_list)} results, set len: {len(set(pk_list))}, iterate_times: {iterate_times}")
assert len(pk_list) == len(set(pk_list)) != 0
return True
@staticmethod
def check_query_results(query_res, func_name, check_items):
"""
According to the check_items to check actual query result, which return from func_name.
:param: query_res: A list that contains all results
:type: list
:param func_name: Query API name
:type func_name: str
:param check_items: The items expected to be checked, including exp_res, with_vec
The type of exp_res value is as same as query_res
The type of with_vec value is bool, True value means check vector field, False otherwise
:type check_items: dict
"""
if func_name != 'query':
log.warning("The function name is {} rather than {}".format(func_name, "query"))
if not isinstance(query_res, list):
raise Exception("The query result to check isn't list type object")
if len(check_items) == 0:
raise Exception("No expect values found in the check task")
exp_res = check_items.get("exp_res", None)
with_vec = check_items.get("with_vec", False)
primary_field = check_items.get("primary_field", None)
if exp_res is not None:
if isinstance(query_res, list):
assert pc.equal_entities_list(exp=exp_res, actual=query_res, primary_field=primary_field,
with_vec=with_vec)
return True
else:
log.error(f"Query result {query_res} is not list")
return False
log.warning(f'Expected query result is {exp_res}')
@staticmethod
def check_query_iterator(query_res, func_name, check_items):
"""
target: check the query results
method: 1. check the query number
2. check the limit(topK) and ids
3. check the distance
expected: check the search is ok
"""
log.info("query_iterator_results_check: checking the query results")
if func_name != 'query_iterator':
log.warning("The function name is {} rather than {}".format(func_name, "query_iterator"))
query_iterator = query_res
pk_list = []
while True:
res = query_iterator.next()
if len(res) == 0:
log.info("search iteration finished, close")
query_iterator.close()
break
pk_name = ct.default_int64_field_name if res[0].get(ct.default_int64_field_name, None) is not None \
else ct.default_string_field_name
for i in range(len(res)):
pk_list.append(res[i][pk_name])
if check_items.get("limit", None):
assert len(res) <= check_items["limit"]
assert len(pk_list) == len(set(pk_list))
if check_items.get("count", None):
log.info(len(pk_list))
assert len(pk_list) == check_items["count"]
if check_items.get("exp_ids", None):
assert pk_list == check_items["exp_ids"]
log.info("check: total %d results" % len(pk_list))
return True
@staticmethod
def check_query_empty(query_res, func_name):
"""
Verify that the query result is empty
:param: query_res: A list that contains all results
:type: list
:param func_name: Query API name
:type func_name: str
"""
if func_name != 'query':
log.warning("The function name is {} rather than {}".format(func_name, "query"))
if not isinstance(query_res, list):
raise Exception("The query result to check isn't list type object")
assert len(query_res) == 0, "Query result is not empty"
@staticmethod
def check_query_not_empty(query_res, func_name):
"""
Verify that the query result is not empty
:param: query_res: A list that contains all results
:type: list
:param func_name: Query API name
:type func_name: str
"""
if func_name != 'query':
log.warning("The function name is {} rather than {}".format(func_name, "query"))
if not isinstance(query_res, list):
raise Exception("The query result to check isn't list type object")
assert len(query_res) > 0
@staticmethod
def check_distance(distance_res, func_name, check_items):
if func_name != 'calc_distance':
log.warning("The function name is {} rather than {}".format(func_name, "calc_distance"))
if not isinstance(distance_res, list):
raise Exception("The distance result to check isn't list type object")
if len(check_items) == 0:
raise Exception("No expect values found in the check task")
vectors_l = check_items["vectors_l"]
vectors_r = check_items["vectors_r"]
metric = check_items.get("metric", "L2")
sqrt = check_items.get("sqrt", False)
cf.compare_distance_2d_vector(vectors_l, vectors_r,
distance_res,
metric, sqrt)
return True
@staticmethod
def check_delete_compact_plan(compaction_plans, func_name, check_items):
"""
Verify that the delete type compaction plan
:param: compaction_plans: A compaction plan
:type: CompactionPlans
:param func_name: get_compaction_plans API name
:type func_name: str
:param check_items: which items you wish to check
plans_num represent the delete compact plans number
:type: dict
"""
to_check_func = 'get_compaction_plans'
if func_name != to_check_func:
log.warning("The function name is {} rather than {}".format(func_name, to_check_func))
if not isinstance(compaction_plans, CompactionPlans):
raise Exception("The compaction_plans result to check isn't CompactionPlans type object")
plans_num = check_items.get("plans_num", 1)
assert len(compaction_plans.plans) == plans_num
for plan in compaction_plans.plans:
assert len(plan.sources) == 1
assert plan.sources[0] != plan.target
@staticmethod
def check_merge_compact_plan(compaction_plans, func_name, check_items):
"""
Verify that the merge type compaction plan
:param: compaction_plans: A compaction plan
:type: CompactionPlans
:param func_name: get_compaction_plans API name
:type func_name: str
:param check_items: which items you wish to check
segment_num represent how many segments are expected to be merged, default is 2
:type: dict
"""
to_check_func = 'get_compaction_plans'
if func_name != to_check_func:
log.warning("The function name is {} rather than {}".format(func_name, to_check_func))
if not isinstance(compaction_plans, CompactionPlans):
raise Exception("The compaction_plans result to check isn't CompactionPlans type object")
segment_num = check_items.get("segment_num", 2)
assert len(compaction_plans.plans) == 1
assert len(compaction_plans.plans[0].sources) == segment_num
assert compaction_plans.plans[0].target not in compaction_plans.plans[0].sources
@staticmethod
def check_role_property(role, func_name, check_items):
exp_func_name = "create_role"
if func_name != exp_func_name:
log.warning("The function name is {} rather than {}".format(func_name, exp_func_name))
if not isinstance(role, Role):
raise Exception("The result to check isn't role type object")
if check_items is None:
raise Exception("No expect values found in the check task")
if check_items.get("name", None):
assert role.name == check_items["name"]
return True
@staticmethod
def check_permission_deny(res, actual=True):
assert actual is False
if isinstance(res, Error):
assert "permission deny" in res.message
else:
log.error("[CheckFunc] Response of API is not an error: %s" % str(res))
assert False
return True
@staticmethod
def check_auth_failure(res, actual=True):
assert actual is False
if isinstance(res, Error):
assert "auth check failure" in res.message
else:
log.error("[CheckFunc] Response of API is not an error: %s" % str(res))
assert False
return True
def check_insert_response(self, check_items):
# check request successful
self.assert_succ(self.succ, True)
# get insert count
real = check_items.get("insert_count", None) if isinstance(check_items, dict) else None
if real is None:
real = len(self.kwargs_dict.get("data", [[]])[0])
# check insert count
error_message = "[CheckFunc] Insert count does not meet expectations, response:{0} != expected:{1}"
assert self.response.insert_count == real, error_message.format(self.response.insert_count, real)
return True
@staticmethod
def check_describe_index_property(res, func_name, check_items):
"""
According to the check_items to check collection properties of res, which return from func_name
:param res: actual response of init collection
:type res: Collection
:param func_name: init collection API
:type func_name: str
:param check_items: which items expected to be checked, including name, schema, num_entities, primary
:type check_items: dict, {check_key: expected_value}
"""
exp_func_name = "describe_index"
if func_name != exp_func_name:
log.warning("The function name is {} rather than {}".format(func_name, exp_func_name))
if len(check_items) == 0:
raise Exception("No expect values found in the check task")
if check_items.get("json_cast_type", None) is not None:
assert res["json_cast_type"] == check_items.get("json_cast_type")
if check_items.get("index_type", None) is not None:
assert res["index_type"] == check_items.get("index_type")
if check_items.get("json_path", None) is not None:
assert res["json_path"] == check_items.get("json_path")
if check_items.get("field_name", None) is not None:
assert res["field_name"] == check_items.get("field_name")
if check_items.get("index_name", None) is not None:
assert res["index_name"] == check_items.get("index_name")
return True