3 # This program and the accompanying materials
4 # are made available under the terms of the Apache License, Version 2.0
5 # which accompanies this distribution, and is available at
7 # http://www.apache.org/licenses/LICENSE-2.0
16 from urllib2 import Request, urlopen, URLError
19 # ----------------------------------------------------------
23 # -----------------------------------------------------------
24 def get_parameter_from_yaml(parameter, config_file):
26 Returns the value of a given parameter in file.yaml
27 parameter must be given in string format with dots
28 Example: general.openstack.image_name
30 with open(config_file) as my_file:
31 file_yaml = yaml.safe_load(my_file)
34 for element in parameter.split("."):
35 value = value.get(element)
37 raise ValueError("The parameter %s is not defined in"
38 " reporting.yaml" % parameter)
42 def get_config(parameter):
44 Get configuration parameter from yaml configuration file
46 yaml_ = os.environ["CONFIG_REPORTING_YAML"]
47 return get_parameter_from_yaml(parameter, yaml_)
50 # ----------------------------------------------------------
54 # -----------------------------------------------------------
55 def getLogger(module):
59 log_formatter = logging.Formatter("%(asctime)s [" +
61 "] [%(levelname)-5.5s] %(message)s")
62 logger = logging.getLogger()
63 log_file = get_config('general.log.log_file')
64 log_level = get_config('general.log.log_level')
66 file_handler = logging.FileHandler("{0}/{1}".format('.', log_file))
67 file_handler.setFormatter(log_formatter)
68 logger.addHandler(file_handler)
70 console_handler = logging.StreamHandler()
71 console_handler.setFormatter(log_formatter)
72 logger.addHandler(console_handler)
73 logger.setLevel(log_level)
77 # ----------------------------------------------------------
81 # -----------------------------------------------------------
82 def getApiResults(case, installer, scenario, version):
84 Get Results by calling the API
86 results = json.dumps([])
87 # to remove proxy (to be removed at the end for local test only)
88 # proxy_handler = urllib2.ProxyHandler({})
89 # opener = urllib2.build_opener(proxy_handler)
90 # urllib2.install_opener(opener)
91 # url = "http://127.0.0.1:8000/results?case=" + case + \
92 # "&period=30&installer=" + installer
93 period = get_config('general.period')
94 url_base = get_config('testapi.url')
95 nb_tests = get_config('general.nb_iteration_tests_success_criteria')
97 url = ("http://" + url_base + "?case=" + case +
98 "&period=" + str(period) + "&installer=" + installer +
99 "&scenario=" + scenario + "&version=" + version +
100 "&last=" + str(nb_tests))
101 request = Request(url)
104 response = urlopen(request)
106 results = json.loads(k)
108 print "Error when retrieving results form API"
113 def getScenarios(project, case, installer, version):
115 Get the list of Scenarios
118 scenario_results = None
119 period = get_config('general.period')
120 url_base = get_config('testapi.url')
122 url = ("http://" + url_base +
123 "?installer=" + installer +
124 "&period=" + str(period))
126 if version is not None:
127 url += "&version=" + version
129 if project is not None:
130 url += "&project=" + project
133 url += "&case=" + case
136 request = Request(url)
137 response = urlopen(request)
139 results = json.loads(k)
140 test_results = results['results']
142 page = results['pagination']['total_pages']
145 for i in range(1, page + 1):
146 url_page = url + "&page=" + str(i)
147 request = Request(url_page)
148 response = urlopen(request)
150 results = json.loads(k)
151 test_results += results['results']
153 print "No pagination detected"
154 except URLError as err:
155 print 'Got an error code: {}'.format(err)
157 if test_results is not None:
158 test_results.reverse()
159 scenario_results = {}
161 for my_result in test_results:
162 # Retrieve all the scenarios per installer
163 if not my_result['scenario'] in scenario_results.keys():
164 scenario_results[my_result['scenario']] = []
165 # Do we consider results from virtual pods ...
166 # Do we consider results for non HA scenarios...
167 exclude_virtual_pod = get_config('functest.exclude_virtual')
168 exclude_noha = get_config('functest.exclude_noha')
169 if ((exclude_virtual_pod and "virtual" in my_result['pod_name']) or
170 (exclude_noha and "noha" in my_result['scenario'])):
171 print "exclude virtual pod results..."
173 scenario_results[my_result['scenario']].append(my_result)
175 return scenario_results
178 def getScenarioStats(scenario_results):
180 Get the number of occurence of scenarios over the defined PERIOD
183 for res_k, res_v in scenario_results.iteritems():
184 scenario_stats[res_k] = len(res_v)
185 return scenario_stats
188 def getScenarioStatus(installer, version):
190 Get the status of a scenariofor Yardstick
192 period = get_config('general.period')
193 url_base = get_config('testapi.url')
195 url = ("http://" + url_base + "?case=scenario_status" +
196 "&installer=" + installer +
197 "&version=" + version + "&period=" + str(period))
198 request = Request(url)
201 response = urlopen(request)
204 results = json.loads(k)
205 test_results = results['results']
207 print "GetScenarioStatus: error when calling the API"
211 scenario_results = {x86: {}, aarch64: {}}
212 result_dict = {x86: {}, aarch64: {}}
213 if test_results is not None:
214 for test_r in test_results:
215 if (test_r['stop_date'] != 'None' and
216 test_r['criteria'] is not None):
217 scenario_name = test_r['scenario']
218 if 'arm' in test_r['pod_name']:
219 if not test_r['scenario'] in scenario_results[aarch64]:
220 scenario_results[aarch64][scenario_name] = []
221 scenario_results[aarch64][scenario_name].append(test_r)
223 if not test_r['scenario'] in scenario_results[x86]:
224 scenario_results[x86][scenario_name] = []
225 scenario_results[x86][scenario_name].append(test_r)
227 for key in scenario_results:
228 for scen_k, scen_v in scenario_results[key].items():
229 # scenario_results[k] = v[:LASTEST_TESTS]
231 for element in scen_v:
232 if element['criteria'] == 'PASS':
236 result_dict[key][scen_k] = s_list
238 # return scenario_results
242 def getQtipResults(version, installer):
246 period = get_config('qtip.period')
247 url_base = get_config('testapi.url')
249 url = ("http://" + url_base + "?project=qtip" +
250 "&installer=" + installer +
251 "&version=" + version + "&period=" + str(period))
252 request = Request(url)
255 response = urlopen(request)
258 results = json.loads(k)['results']
259 except URLError as err:
260 print 'Got an error code: {}'.format(err)
265 key = '{}/{}'.format(r['pod_name'], r['scenario'])
266 if key not in result_dict.keys():
267 result_dict[key] = []
268 result_dict[key].append(r['details']['score'])
270 # return scenario_results
274 def getNbtestOk(results):
276 based on default value (PASS) count the number of test OK
279 for my_result in results:
280 for res_k, res_v in my_result.iteritems():
285 print "Cannot retrieve test status"
289 def getCaseScore(testCase, installer, scenario, version):
291 Get Result for a given Functest Testcase
293 # retrieve raw results
294 results = getApiResults(testCase, installer, scenario, version)
295 # let's concentrate on test results only
296 test_results = results['results']
298 # if results found, analyze them
299 if test_results is not None:
300 test_results.reverse()
302 scenario_results = []
304 # print " ---------------- "
306 # print " ---------------- "
307 # print "nb of results:" + str(len(test_results))
309 for res_r in test_results:
310 # print r["start_date"]
311 # print r["criteria"]
312 scenario_results.append({res_r["start_date"]: res_r["criteria"]})
314 scenario_results.sort()
315 # 4 levels for the results
316 # 3: 4+ consecutive runs passing the success criteria
317 # 2: <4 successful consecutive runs but passing the criteria
318 # 1: close to pass the success criteria
319 # 0: 0% success, not passing
320 # -1: no run available
321 test_result_indicator = 0
322 nbTestOk = getNbtestOk(scenario_results)
324 # print "Nb test OK (last 10 days):"+ str(nbTestOk)
325 # check that we have at least 4 runs
326 if len(scenario_results) < 1:
327 # No results available
328 test_result_indicator = -1
330 test_result_indicator = 0
332 test_result_indicator = 1
334 # Test the last 4 run
335 if len(scenario_results) > 3:
336 last4runResults = scenario_results[-4:]
337 nbTestOkLast4 = getNbtestOk(last4runResults)
338 # print "Nb test OK (last 4 run):"+ str(nbTestOkLast4)
339 if nbTestOkLast4 > 3:
340 test_result_indicator = 3
342 test_result_indicator = 2
344 test_result_indicator = 2
345 return test_result_indicator
348 def getCaseScoreFromBuildTag(testCase, s_results):
350 Get Results for a given Functest Testcase with arch filtering
352 url_base = get_config('testapi.url')
353 nb_tests = get_config('general.nb_iteration_tests_success_criteria')
354 test_result_indicator = 0
355 # architecture is not a result field...so we cannot use getResult as it is
358 for s_result in s_results:
359 build_tag = s_result['build_tag']
360 d = s_result['start_date']
361 res_matrix.append({'date': d,
362 'build_tag': build_tag})
364 filter_res_matrix = sorted(res_matrix, key=lambda k: k['date'],
365 reverse=True)[:nb_tests]
366 for my_res in filter_res_matrix:
367 url = ("http://" + url_base + "?case=" + testCase +
368 "&build_tag=" + my_res['build_tag'])
369 request = Request(url)
370 response = urlopen(request)
372 results = json.loads(k)
373 if "PASS" in results['results'][0]['criteria']:
374 test_result_indicator += 1
376 print "No results found for this case"
377 if test_result_indicator > 2:
378 test_result_indicator = test_result_indicator - 1
380 return test_result_indicator
383 def getJenkinsUrl(build_tag):
385 Get Jenkins url_base corespoding to the last test CI run
386 e.g. jenkins-functest-apex-apex-daily-colorado-daily-colorado-246
388 jenkins-functest-compass-huawei-pod5-daily-master-136
390 note it is linked to jenkins format
391 if this format changes...function to be adapted....
393 url_base = get_config('functest.jenkins_url')
395 build_id = [int(s) for s in build_tag.split("-") if s.isdigit()]
396 url_id = (build_tag[8:-(len(str(build_id[0])) + 1)] +
397 "/" + str(build_id[0]))
398 jenkins_url = url_base + url_id + "/console"
400 print 'Impossible to get jenkins url:'
402 if "jenkins-" not in build_tag:
408 def getScenarioPercent(scenario_score, scenario_criteria):
410 Get success rate of the scenario (in %)
414 score = float(scenario_score) / float(scenario_criteria) * 100
416 print 'Impossible to calculate the percentage score'
423 def getFunctestConfig(version=""):
425 Get Functest configuration
427 config_file = get_config('functest.test_conf') + version
428 response = requests.get(config_file)
429 return yaml.safe_load(response.text)
432 def getArchitectures(scenario_results):
434 Get software architecture (x86 or Aarch64)
436 supported_arch = ['x86']
437 if len(scenario_results) > 0:
438 for scenario_result in scenario_results.values():
439 for value in scenario_result:
440 if "armband" in value['build_tag']:
441 supported_arch.append('aarch64')
442 return supported_arch
443 return supported_arch
446 def filterArchitecture(results, architecture):
448 Restrict the list of results based on given architecture
450 filtered_results = {}
451 for name, res in results.items():
454 if architecture is "x86":
455 # drop aarch64 results
456 if ("armband" not in value['build_tag']):
457 filtered_values.append(value)
458 elif architecture is "aarch64":
460 if ("armband" in value['build_tag']):
461 filtered_values.append(value)
462 if (len(filtered_values) > 0):
463 filtered_results[name] = filtered_values
464 return filtered_results
470 def subfind(given_list, pattern_list):
472 Yardstick util function
474 LASTEST_TESTS = get_config('general.nb_iteration_tests_success_criteria')
475 for i in range(len(given_list)):
476 if given_list[i] == pattern_list[0] and \
477 given_list[i:i + LASTEST_TESTS] == pattern_list:
482 def _get_percent(status):
484 Yardstick util function to calculate success rate
487 return round(float(status) * 100 / 6, 1)
489 return status * 100 / 6
492 def get_percent(four_list, ten_list):
494 Yardstick util function to calculate success rate
499 for res_v in four_list:
501 for res_v in ten_list:
504 LASTEST_TESTS = get_config('general.nb_iteration_tests_success_criteria')
505 if four_score == LASTEST_TESTS:
507 elif subfind(ten_list, [1, 1, 1, 1]):
512 status = four_score + 1
514 return _get_percent(status)
519 Yardstick util function (test)
521 status = getScenarioStatus("compass", "master")
522 print "status:++++++++++++++++++++++++"
523 print json.dumps(status, indent=4)
526 # ----------------------------------------------------------
530 # -----------------------------------------------------------
532 def export_csv(scenario_file_name, installer, version):
534 Generate sub files based on scenario_history.txt
536 scenario_installer_file_name = ("./display/" + version +
537 "/functest/scenario_history_" +
539 scenario_installer_file = open(scenario_installer_file_name, "a")
540 with open(scenario_file_name, "r") as scenario_file:
541 scenario_installer_file.write("date,scenario,installer,detail,score\n")
542 for line in scenario_file:
543 if installer in line:
544 scenario_installer_file.write(line)
545 scenario_installer_file.close
548 def generate_csv(scenario_file):
550 Generate sub files based on scenario_history.txt
553 csv_file = scenario_file.replace('txt', 'csv')
554 shutil.copy2(scenario_file, csv_file)
557 def export_pdf(pdf_path, pdf_doc_name):
559 Export results to pdf
562 pdfkit.from_file(pdf_path, pdf_doc_name)
564 print "Error but pdf generated anyway..."
566 print "impossible to generate PDF"