def json_same(check_value, expect_value): """ 接口响应-json完全匹配校验 : 校验, 预期结果 :desc: 说明: 验证待校验内容作为json是否和期望值json完全一致 :param check_value: 待校验内容: 指定待校验的内容,支持多层级,例如 content,content.demoList.0.code,headers :param expect_value: 期望值: 例如 {"code": "000","desc":"成功!", "msg": "$my_var"} :return: """ dict_check = transfer_json_string_to_dict(check_value) dict_expect = transfer_json_string_to_dict(expect_value) # dict_check和dict_expect是字符串/数字的情况 if isinstance(dict_expect, (str, int)) and isinstance(dict_check, (str, int)): if str(dict_expect) == str(dict_check): return True else: return False, '预期结果是"{0}", 实际结果是"{1}"'.format(str(dict_expect), str(dict_check)) # 返回True和False或者(False, 'err_msg'),关联测试报告success和fail try: # assert is_json_contains(dict_check, dict_expect) res = is_json_contains(dict_check, dict_expect) if res is not True: return res res = is_json_contains(dict_expect, dict_check) return res except Exception as err: return False, err.args[0]
def db_operation_to_json_cycle(sql, db_connect, expect_value, wait_time=30): """数据库json校验 轮询""" step_time = 5 t = 0 return_value = None dict_expect = transfer_json_string_to_dict(expect_value) # 如果期望值非json格式,直接报错 if not isinstance(dict_expect, dict): raise Exception('结果校验中期望结果非json格式,期望结果内容为{0}({1})'.format( dict_expect, type(dict_expect).__name__)) dict_expect_lower_key = { key.lower(): dict_expect[key] for key in dict_expect } while t <= wait_time: try: return_value = db_operation_to_json(sql, db_connect) dict_check = transfer_json_string_to_dict(return_value) dict_check_lower_key = { key.lower(): dict_check[key] for key in dict_check } if not dict_check_lower_key: hr_logger.log_info("【轮询SQL】: {0} 表中无数据,等待5秒后重试".format( sql.replace('\n', ''))) else: res = is_json_contains(dict_check_lower_key, dict_expect_lower_key) if res is True: hr_logger.log_info('【轮询SQL】: {0} 结果为 {1}'.format( sql.replace('\n', ''), dict_check)) return return_value else: hr_logger.log_info('【轮询SQL】: {0} 结果为 {1},等待5秒后重试'.format( sql.replace('\n', ''), dict_check)) time.sleep(step_time) t += step_time except Exception as err: logger.error(traceback.format_exc()) raise Exception("【轮询SQL】: 数据库操作失败, {0}".format(err)) hr_logger.log_info('【轮询SQL】: 超过{0}秒表中仍无预期数据'.format(wait_time)) return return_value
def json_contains(check_value, expect_value): """ 接口响应-json包含校验 : 校验, 预期结果 :desc: 说明: 验证待校验内容作为json是否包含期望值json :param check_value: 待校验内容: 指定待校验的内容,支持多层级,例如 content,content.demoList.0.code,headers :param expect_value: 期望值: 例如 {"code": "000","desc":"成功!", "msg": "$my_var"} :return: """ try: if isinstance(check_value, bytes): # bytes转str str_content = check_value.decode('utf-8') # str转dict dict_check = json.loads(str_content) elif isinstance(check_value, str): dict_check = json.loads(check_value) else: # dict dict_check = check_value except json.decoder.JSONDecodeError: dict_check = check_value # assert isinstance(expect_value, basestring) try: dict_expect = json.loads(expect_value) except json.decoder.JSONDecodeError: # json.loads异常时替换布尔类型后再次尝试,False => false , True => true expect_value = expect_value.replace('False', 'false').replace('True', 'true') try: dict_expect = json.loads(expect_value) except json.decoder.JSONDecodeError: dict_expect = expect_value except TypeError: dict_expect = expect_value # dict_check和dict_expect是字符串/数字/布尔的情况 if isinstance(dict_expect, (str, int, bool)) and isinstance(dict_check, (str, int, bool)): if str(dict_expect) == str(dict_check): return True else: return False, '预期结果是"{0}", 实际结果是"{1}"'.format(str(dict_expect), str(dict_check)) # 返回True和False或者(False, 'err_msg'),关联测试报告success和fail try: # assert is_json_contains(dict_check, dict_expect) res = is_json_contains(dict_check, dict_expect) return res except Exception as err: return False, err.args[0]
def redis_validate(check_value, expect_value): """ redis-key值包含校验 : 查询key, 预期结果 :desc: 说明: 根据指定的key和db_num查询值,并同预期结果比对 :param check_value:待校验内容: 需要查询的db_num和key,以json格式,如{"db_num": 2, "redis_key": "user_token_9998742"},支持使用变量 :param expect_value:期望值: 例如 "abc" 或 {"a": 123, "b": "xxx"},支持使用变量 :return: """ # 返回ture和flase,关联测试报告success和fail if isinstance(check_value, dict) and isinstance(expect_value, dict): return is_json_contains(check_value, expect_value) if check_value == expect_value: return True elif str(check_value) == str(expect_value): return True else: return False, '预期结果和实际结果不一致。预期结果是"{0}", 实际结果是"{1}"'.format(expect_value, check_value)
def mq_validate(check_value, expect_value): """ mq-消息内容包含校验 : topic+tag+system_name, 预期结果 :desc: 说明: 根据topic+tag+system_name查询消息,同预期结果匹配 :param check_value:待校验内容: 需要查询的消息topic和tag,以json格式,如{"topic": "TP_MIME_UNION_FINANCE", "tag": "TAG_capital-mgmt-core_createCashLoan", "system_name": "user-core"},支持使用变量 :param expect_value:期望值: 例如 "abc" 或 {"a": 123, "b": "xxx"},支持使用变量 :return: """ # 返回ture和flase,关联测试报告success和fail if not check_value: return False, '根据topic和tag获取不到最近10分钟的MQ消息' # hr_logger.log_info(str(len(check_value))) for index, item in enumerate(check_value): hr_logger.log_info('消息({0})内容:{1}'.format(str(index+1), item)) try: dict_check = json.loads(item) # hr_logger.log_info(type(dict_check).__name__) if not isinstance(expect_value, dict): return False, '预期结果和实际结果类型不一致,预期结果是"{0}",期望结果是"{1}"'.format(type(dict_check).__name__, type(expect_value).__name__) is_ok = is_json_contains(dict_check, expect_value) # hr_logger.log_info(type(is_ok).__name__) if is_ok is True: return True else: continue except Exception as err: hr_logger.log_error(traceback.format_exc()) dict_check = item if dict_check == expect_value: return True elif str(dict_check) == str(expect_value): return True else: continue return False, '找不到同预期结果匹配的MQ消息'
def db_json_validate(dict_check, dict_expect): """ 数据库-多字段校验(轮询) : 校验sql, 预期结果 :desc: 说明: 30s内轮询验证查询SQL的多字段结果和期望值是否一致 :param dict_check: 待校验内容: 查询多字段的SQL语句,支持在SQL结束符';'后填一个正整数指定轮询超时时间,例如 select merchant_no,term_total from accounting.fss_loans WHERE loan_id='$loan_id';15 :param dict_expect: 期望值: 必须json格式,其中key和查询SQL中的字段名对应,例如 {"merchant_no": $my_var, "term_total": 12} :return: """ dict_check = transfer_json_string_to_dict(dict_check) dict_expect = transfer_json_string_to_dict(dict_expect) dict_check_lower_key = {key.lower(): dict_check[key] for key in dict_check} dict_expect_lower_key = {key.lower(): dict_expect[key] for key in dict_expect} # for key in dict_check: # dict_check_lower_key[key.lower()] = dict_check[key] # for key in dict_expect: # dict_expect_lower_key[key.lower()] = dict_expect[key] # 返回True和False或者(False, 'err_msg'),关联测试报告success和fail try: return is_json_contains(dict_check_lower_key, dict_expect_lower_key) except: return False
def db_validate_cycle(check_value, expect_value): """ 数据库-单字段校验(轮询) : 校验sql, 预期结果 :desc: 说明: 30s内轮询验证查询SQL的单字段结果和期望值是否一致, 当查询SQL结果和期望值都是json时,自动转为json包含校验 :param check_value: 待校验内容: 查询单字段的SQL语句,支持在SQL结束符';'后填一个正整数指定轮询超时时间,例如 select merchant_no from accounting.fss_loans WHERE loan_id='$loan_id';15 :param expect_value: 期望值: 例如 023 或 {"a": "b", "c": "d"} :return: """ dict_expect = transfer_json_string_to_dict(expect_value) if isinstance(dict_expect, (dict, list)): dict_check = transfer_json_string_to_dict(check_value) try: return is_json_contains(dict_check, dict_expect) except Exception as e: return False, format(e) else: try: if check_value == expect_value: return True elif str(check_value) == str(expect_value): return True else: return False, '预期结果是"{0}", 实际结果是"{1}"'.format(expect_value, check_value) except Exception as e: return False, format(e)
def sql_execute_cycle(sql, db_connect, expect_value, wait_time=30): """ 定时执行某条查询sql,用于特定场景,如检查贷款表中贷款数据是否生成,默认每5秒检查一次,1分钟超时退出 \n :param expect_value: :param db_connect: :param sql: 待执行的查询sql \n :param wait_time: 超时时长,超过该时间自动退出 ,默认60秒 \n :return: 返回查询结果 \n """ expect_is_json = False step_time = 5 t = 0 return_value = None dict_expect = transfer_json_string_to_dict(expect_value) if isinstance(dict_expect, dict): expect_is_json = True while t <= wait_time: try: return_info = sql_execute(sql, db_connect=db_connect) if expect_is_json: return_value = return_info[0][0] if return_info else None dict_check = transfer_json_string_to_dict(return_value) # dict_check_lower_key = {key.lower(): dict_check[key] for key in dict_check} if not dict_check: hr_logger.log_info("【轮询SQL】: {0} 表中无数据,等待5秒后重试".format( sql.replace('\n', ''))) else: res = is_json_contains(dict_check, dict_expect) if res is True: hr_logger.log_info('【轮询SQL】: {0} 结果为 {1}'.format( sql.replace('\n', ''), dict_check)) return return_value else: hr_logger.log_info( '【轮询SQL】: {0} 结果为 {1},{2},等待5秒后重试'.format( sql.replace('\n', ''), dict_check, res[1])) else: if not return_info: hr_logger.log_info("【轮询SQL】: {0} 表中无数据,等待5秒后重试".format( sql.replace('\n', ''))) else: return_value = str(return_info[0][0]) if return_value == str(expect_value): hr_logger.log_info('【轮询SQL】: {0} 结果为 {1}'.format( sql.replace('\n', ''), return_value)) return return_info[0][0] else: hr_logger.log_info( '【轮询SQL】: {0} 结果为 {1},等待5秒后重试'.format( sql.replace('\n', ''), return_value)) time.sleep(step_time) t += step_time except Exception as err: logger.error(traceback.format_exc()) raise Exception("【轮询SQL】: 数据库操作失败, {0}".format(err)) hr_logger.log_info('【轮询SQL】: 超过{0}秒表中仍无预期数据'.format(wait_time)) return return_value
def teardown_compare_log_content(app_name, ssh_cmd, start_with, end_with, expect_kwargs, server_app_map, server_default_user): """ 日志-检查日志中是否包含期望内容 : 应用名, grep命令, 起始字符, 结束字符, 期望内容 :desc: 说明: 根据条件检索日志内容,并与期望内容比较 :param app_name: 应用名: 如loan-web,同环境配置中IP-应用映射表中应用名称保持一致 :param ssh_cmd: 过滤命令:使用grep xxx 过滤出符合条件的日志,如grep "成功发送通知消息" "/usr/local/src/logs/ups-service-cell01-node01/sys.log" :param start_with: 起始字符: 从日志中筛选起始字符后的内容 :param end_with: 结束字符: 从日志中筛选结束字符前的内容 :param expect_kwargs: 期望内容:json格式,用于同日志中筛选出的内容做json包含比较,如果包含则返回true,否则返回false :return: """ server_app_map = json.loads(server_app_map) server_default_user = json.loads(server_default_user) app_server_ip = "" for k, v in server_app_map.items(): if app_name in v: app_server_ip = k break if not app_server_ip: raise Exception("根据应用名找不到匹配的服务器IP") if not ssh_cmd.startswith("grep"): raise Exception("为了安全考虑,目前暂只支持grep命令") ssh_server_info = [app_server_ip, "22", server_default_user['user'], server_default_user['password']] try: with SSHClient(ssh_server_info) as sc: logs = sc.exec_cmd(ssh_cmd) except Exception as e: logger.error(traceback.format_exc()) raise Exception('出现未知错误: {0}'.format(repr(e))) if not logs: raise Exception("日志中未找到匹配的内容") des_logs = logs.split("\n")[:-1] if len(des_logs) > 1: raise Exception("日志中找到超过一条匹配记录,请增加过滤条件!") glc = GetLogContent(des_logs[0], start_with, end_with) actual_value = glc.get_log_content() if not actual_value and not expect_kwargs: return True elif actual_value and expect_kwargs: try: if isinstance(actual_value, bytes): # bytes转str str_content = actual_value.decode('utf-8') # str转dict dict_check = json.loads(str_content) elif isinstance(actual_value, str): dict_check = json.loads(actual_value) else: # dict dict_check = actual_value except json.decoder.JSONDecodeError: dict_check = actual_value try: dict_expect = json.loads(expect_kwargs) except json.decoder.JSONDecodeError: # json.loads异常时替换布尔类型后再次尝试,False => false , True => true expect_value = expect_kwargs.replace('False', 'false').replace('True', 'true') try: dict_expect = json.loads(expect_value) except json.decoder.JSONDecodeError: dict_expect = expect_value except TypeError: dict_expect = expect_kwargs # dict_check和dict_expect是字符串/数字的情况 if isinstance(dict_expect, (str, int)) and isinstance(dict_check, (str, int)): if str(dict_expect) == str(dict_check): return True else: return False, "实际日志内容同期望不匹配,实际日志内容为 %s" % (str(actual_value)) try: res = is_json_contains(dict_check, dict_expect) return res except Exception as e: return False, "json比对出现未知异常,%s" % traceback.format_exc() else: return False, "实际日志内容同期望不匹配,实际日志内容为 %s" % (str(actual_value))