initRelevance.py 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347
  1. #!/usr/bin/env python
  2. # -*- coding:utf-8 -*-
  3. """
  4. 根据依赖case的结果更改参数
  5. Author: songjian at <songjian12@baidu.com>
  6. Created: 2020/6/12
  7. """
  8. import sys
  9. import logging
  10. import json
  11. from readYaml import read_yaml
  12. import os
  13. import time
  14. import datetime
  15. import subprocess
  16. import random
  17. import uuid
  18. work_path = os.path.dirname(os.path.abspath(__file__))
  19. sdk_path = os.path.dirname(os.path.dirname(work_path))
  20. reload(sys)
  21. sys.setdefaultencoding('utf-8')
  22. func_list = ['to_timestamp', 'bw_date', 'bw_week', 'func_get_faq_list', 'get_index',
  23. 'compatible_api', 'timestamp_index', 'random_str', 'func_get_pattern_id',
  24. 'func_get_tree_node_list', 'random_id', 'date_index']
  25. def random_id():
  26. """
  27. 生成随机id
  28. :return:
  29. """
  30. dataid = str(uuid.uuid1()).replace("-", '')
  31. return {"dataid": dataid}
  32. def random_str():
  33. """
  34. 生成随机字符串
  35. :return:
  36. """
  37. num = random.randint(4, 12)
  38. name = random.sample('zyxwvutsrqponmlkjihgfedcba', num)
  39. name = ''.join(name)
  40. now = datetime.datetime.now()
  41. name = name + str(now.second)
  42. return {"random_name": name}
  43. def str_to_int(index):
  44. """
  45. 字符串转数字
  46. """
  47. for ch in index:
  48. if ch < '0' or ch > '9':
  49. return index
  50. return int(index)
  51. def func_get_faq_list(case_result):
  52. """
  53. 设置修改faq的参数
  54. """
  55. item = case_result["get_faq_list"]["data"]["items"][0]
  56. item["title"] = item["title"]
  57. item["answer"] = "China"
  58. now = int(time.time()*1000)
  59. item["updateTime"] = now
  60. item["@updateTime"] = now
  61. return {"item": item}
  62. def bw_date():
  63. """
  64. 获取 间隔30天的日期整数 例如 2020-07-27 00:00:00 对应的时间戳
  65. """
  66. now = datetime.datetime.now()
  67. en_date = datetime.date(now.year, now.month, now.day)
  68. be_date = en_date + datetime.timedelta(days=-30)
  69. return {"beginDate": int(time.mktime(be_date.timetuple())*1000),
  70. "endDate": int(time.mktime(en_date.timetuple())*1000)}
  71. def bw_week():
  72. """
  73. 获取间隔7天的日期整数,包括当天
  74. """
  75. now = datetime.datetime.now()
  76. en_date = datetime.datetime(now.year, now.month, now.day, 23, 59, 59)
  77. be_date = en_date + datetime.timedelta(days=-8)
  78. return {"beginDate": int(time.mktime(be_date.timetuple()) * 1000),
  79. "endDate": int(time.mktime(en_date.timetuple()) * 1000)}
  80. def get_index(case_data, indice):
  81. """
  82. 获取指定类目的索引
  83. """
  84. host = case_data['host']
  85. url = host + "/_cat/indices"
  86. cmd = "curl %s |grep %s |awk '{print $3}'" % (url, indice)
  87. ret = subprocess.Popen(cmd, shell=True, stdout=subprocess.PIPE)
  88. out, err = ret.communicate()
  89. indices = out.split()[-1]
  90. return {"index": indices}
  91. def to_timestamp():
  92. """
  93. 返回时间戳
  94. """
  95. return {"to_timestamp": int(round(time.time() * 1000))}
  96. def date_index(n, k):
  97. """
  98. 返回当前日期前后几天的时间格式
  99. 假设今天是21号,n=-3,k=3则返回16-18号的时间格式,2022-01-16 00:00:00 2022-01-18 23:59:59
  100. :param n: 可填正负数,正数为往后推日期,负数为往前推日期,0为当天
  101. :param k: 可填正整数,表示时间间隔
  102. :return:
  103. """
  104. now = datetime.datetime.now()
  105. en_date = datetime.datetime(now.year, now.month, now.day, 23, 59, 59) + datetime.timedelta(days=n)
  106. be_date = datetime.datetime(now.year, now.month, now.day, 0, 0, 0) + datetime.timedelta(days=n - k + 1)
  107. return {"beginDate": str(be_date), "endDate": str(en_date)}
  108. def timestamp_index(n, k):
  109. """
  110. 返回当前日期前后几天的时间戳
  111. 假设今天是21号,n=-3,k=3则返回16-18号的时间戳
  112. :param n: 可填正负数,正数为往后推日期,负数为往前推日期,0为当天
  113. :param k: 可填正整数,表示时间间隔
  114. :return:
  115. """
  116. now = datetime.datetime.now()
  117. en_date = datetime.datetime(now.year, now.month, now.day, 23, 59, 59) + datetime.timedelta(days=n)
  118. be_date = datetime.datetime(now.year, now.month, now.day, 0, 0, 0) + datetime.timedelta(days=n - k + 1)
  119. return {"beginDate": int(time.mktime(be_date.timetuple()) * 1000),
  120. "endDate": int(time.mktime(en_date.timetuple()) * 1000)}
  121. def compatible_api(case_name, case_result):
  122. """
  123. 兼容api列表
  124. :param case_name:
  125. :param case_result:
  126. :return:
  127. """
  128. result = case_result[case_name]
  129. if isinstance(result['data'], list):
  130. temp = result['data']
  131. del result['data']
  132. result['data'] = {}
  133. result['data']['list'] = temp
  134. return result
  135. def find_key(data_list, reg):
  136. """
  137. 在数组中寻找符合要求的键值
  138. """
  139. # reg = reg.strip('[').strip(']')
  140. reg = reg[1:-1]
  141. tree_node = reg.split('#')
  142. for data in data_list:
  143. key = []
  144. temp = data
  145. for node in tree_node:
  146. if ':' in node:
  147. key = node.split(':', 1)
  148. else:
  149. try:
  150. temp = temp[str_to_int(node)]
  151. except Exception as e:
  152. logging.info('该条结果缺少该字段:%s' % e)
  153. break
  154. if len(key) != 2 or key[0] not in temp.keys():
  155. continue
  156. elif temp[key[0]] == str_to_int(key[1]):
  157. return data
  158. return None
  159. def func_get_pattern_id(case_name, case_result, pattern_string):
  160. """
  161. 从上一个case 里获取 pattern_id
  162. """
  163. result = case_result[case_name]
  164. pattern_string = unicode(pattern_string, 'utf-8')
  165. for part in result['result']['pattern_body']:
  166. if pattern_string == part['pattern_string']:
  167. return part['pattern_id'], True
  168. return 0, False
  169. def func_get_tree_node_list(case_name, case_result):
  170. """
  171. 从之前 case 的结果里,获取知识树节点叶子节点 list
  172. """
  173. result = case_result[case_name]
  174. result_list = []
  175. for part in result['data']['list']:
  176. result_list.append(part['id'])
  177. return result_list, False
  178. def get_prop_map(case_name, pre_prop, back_prop, case_result, cache_data):
  179. """
  180. 获取替换的参数值映射表
  181. # 本文件测试用例存储在case_result
  182. # 其他文件的结果存储在cache_data
  183. """
  184. prop_map = {}
  185. case_name_list = case_name.split('||')
  186. pre_props = pre_prop.split('||')
  187. back_props = back_prop.split('||')
  188. if len(case_name_list) != len(pre_props) or len(case_name_list) != len(back_props):
  189. logging.error('parameter length not equal')
  190. return prop_map, False
  191. for n in range(len(case_name_list)):
  192. func_name = case_name_list[n].split('(')[0]
  193. if case_name_list[n] not in case_result.keys() and func_name not in func_list:
  194. # 模式2:外部输入的方式
  195. conf_list = func_name.split('.')
  196. if conf_list[0] == 'input':
  197. try:
  198. result = cache_data[".".join(conf_list[1:])]
  199. except Exception as e:
  200. logging.info('case_name:%s is not exist or input para by conf file' % case_name_list[n])
  201. continue
  202. else:
  203. logging.error('case_name:%s is not exist' % case_name_list[n])
  204. return prop_map, False
  205. elif func_name in func_list: # 模式1:自定义函数
  206. func = case_name_list[n]
  207. if case_name_list[n].find('(') < 0:
  208. func = '%s()' % case_name_list[n]
  209. result = eval(func)
  210. else: # 模式2:本文件测试用例来源
  211. result = case_result[case_name_list[n]]
  212. # 生成替换的dict
  213. pre_prop_list = pre_props[n].split('|')
  214. back_prop_list = back_props[n].split('|')
  215. if len(pre_prop_list) != len(back_prop_list):
  216. logging.error('pre_prop and back_prop length not equal')
  217. return prop_map, False
  218. for i in range(len(pre_prop_list)):
  219. try:
  220. temp = result
  221. tree_list = pre_prop_list[i].split('>')
  222. for item in tree_list:
  223. if '[' in item:
  224. temp = find_key(temp, item)
  225. else:
  226. temp = temp[str_to_int(item)]
  227. prop_map[back_prop_list[i]] = temp
  228. except Exception as e:
  229. logging.error(e)
  230. logging.error("无法替换对应的参数,请检查测试用例替换部分")
  231. return prop_map, False
  232. return prop_map, True
  233. def init_relevance(case_data, case_result, cache_data):
  234. """
  235. 支持2个模式,
  236. 模式1:自定义函数
  237. 模式2:直接依赖其他case的结果;
  238. 1)依赖本文件的测试用例结果,case_name直接写明即可,由case_result传入
  239. 2)依赖其他case文件结果,以input为开头;由cache_data结果传入
  240. 模式1:可以将case_result传入,随意处理
  241. 模式2:不支持嵌套的获取值,若想复杂情况,请直接func函数
  242. 根据依赖case结果替换当前case参数
  243. eg. {"error":0,"data":[{"id":1},{"id":2, "name":"demo"},{"id":3, "test":{"id_in":33}, "name":"demo2"}]}
  244. 得到demo的值:data>[id:2]>name
  245. 得到demo2的值:data>[test#id_in:33]>name
  246. 支持通过index位置获取,得到demo2的值:data>2>name
  247. >表示dict进入下一层
  248. #表示列表进入下一层
  249. """
  250. # step1: get_para
  251. # 若不依赖多余的参数
  252. if 'precondition' not in case_data.keys():
  253. return case_data, True
  254. try:
  255. # 判断参数是否预期
  256. case_name = case_data['precondition']['case_name'].split(';')
  257. pre_prop = case_data['precondition']['pre_prop'].split(';')
  258. back_prop = case_data['precondition']['back_prop'].split(';')
  259. if 'replace_key' not in case_data['precondition'].keys() \
  260. or not case_data['precondition']['replace_key']:
  261. replace_key = ['parameter']
  262. else:
  263. replace_key = case_data['precondition']['replace_key'].split(';')
  264. except Exception as e:
  265. logging.error(e)
  266. return case_data, False
  267. if len(case_name) != len(pre_prop) or len(case_name) != len(back_prop) \
  268. or len(case_name) != len(replace_key):
  269. logging.error('precondition parameter length not equal')
  270. return case_data, False
  271. replace_list = case_data
  272. for round in range(len(case_name)):
  273. # STEP2: get prop_map
  274. prop_map, code = get_prop_map(case_name[round], pre_prop[round], back_prop[round], case_result, cache_data)
  275. if code is False:
  276. logging.error('无法获取正确的参数替换映射')
  277. return case_data, False
  278. # Step3: replace para
  279. try:
  280. parameter = ""
  281. if not isinstance(replace_list[replace_key[round]], dict) \
  282. and not isinstance(replace_list[replace_key[round]], list):
  283. parameter = replace_list[replace_key[round]]
  284. else:
  285. parameter = json.dumps(replace_list[replace_key[round]], ensure_ascii=False)
  286. for back_prop_key, back_prop_value in prop_map.items():
  287. if isinstance(back_prop_value, str) or isinstance(back_prop_value, unicode) \
  288. or replace_key[round] == 'check' or replace_key[round] == 'skip':
  289. parameter = parameter.replace('%s' % back_prop_key, str(back_prop_value))
  290. elif isinstance(back_prop_value, int):
  291. if '\\"%s\\"' % back_prop_key in parameter:
  292. parameter = parameter.replace('\\"%s\\"' % back_prop_key, str(back_prop_value))
  293. else:
  294. parameter = parameter.replace('"%s"' % back_prop_key, str(back_prop_value))
  295. else:
  296. parameter = parameter.replace('"%s"' % back_prop_key,
  297. json.dumps(back_prop_value, ensure_ascii=False))
  298. if not isinstance(replace_list[replace_key[round]], dict) \
  299. and not isinstance(replace_list[replace_key[round]], list):
  300. replace_list[replace_key[round]] = parameter
  301. else:
  302. replace_list[replace_key[round]] = json.loads(parameter, strict=False)
  303. except Exception as e:
  304. logging.error(e)
  305. return case_data, False
  306. return replace_list, True