599a938184393aaf4c986938bced3b1ec0157fb5
[releng.git] / utils / test / reporting / utils / reporting_utils.py
1 #!/usr/bin/python
2 #
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
6 #
7 # http://www.apache.org/licenses/LICENSE-2.0
8 #
9 from urllib2 import Request, urlopen, URLError
10 import logging
11 import json
12 import os
13 import requests
14 import pdfkit
15 import yaml
16
17
18 # ----------------------------------------------------------
19 #
20 #               YAML UTILS
21 #
22 # -----------------------------------------------------------
23 def get_parameter_from_yaml(parameter, file):
24     """
25     Returns the value of a given parameter in file.yaml
26     parameter must be given in string format with dots
27     Example: general.openstack.image_name
28     """
29     with open(file) as f:
30         file_yaml = yaml.safe_load(f)
31     f.close()
32     value = file_yaml
33     for element in parameter.split("."):
34         value = value.get(element)
35         if value is None:
36             raise ValueError("The parameter %s is not defined in"
37                              " reporting.yaml" % parameter)
38     return value
39
40
41 def get_config(parameter):
42     yaml_ = os.environ["CONFIG_REPORTING_YAML"]
43     return get_parameter_from_yaml(parameter, yaml_)
44
45
46 # ----------------------------------------------------------
47 #
48 #               LOGGER UTILS
49 #
50 # -----------------------------------------------------------
51 def getLogger(module):
52     logFormatter = logging.Formatter("%(asctime)s [" +
53                                      module +
54                                      "] [%(levelname)-5.5s]  %(message)s")
55     logger = logging.getLogger()
56     log_file = get_config('general.log.log_file')
57     log_level = get_config('general.log.log_level')
58
59     fileHandler = logging.FileHandler("{0}/{1}".format('.', log_file))
60     fileHandler.setFormatter(logFormatter)
61     logger.addHandler(fileHandler)
62
63     consoleHandler = logging.StreamHandler()
64     consoleHandler.setFormatter(logFormatter)
65     logger.addHandler(consoleHandler)
66     logger.setLevel(log_level)
67     return logger
68
69
70 # ----------------------------------------------------------
71 #
72 #               REPORTING UTILS
73 #
74 # -----------------------------------------------------------
75 def getApiResults(case, installer, scenario, version):
76     results = json.dumps([])
77     # to remove proxy (to be removed at the end for local test only)
78     # proxy_handler = urllib2.ProxyHandler({})
79     # opener = urllib2.build_opener(proxy_handler)
80     # urllib2.install_opener(opener)
81     # url = "http://127.0.0.1:8000/results?case=" + case + \
82     #       "&period=30&installer=" + installer
83     period = get_config('general.period')
84     url_base = get_config('testapi.url')
85     nb_tests = get_config('general.nb_iteration_tests_success_criteria')
86
87     url = ("http://" + url_base + "?case=" + case +
88            "&period=" + str(period) + "&installer=" + installer +
89            "&scenario=" + scenario + "&version=" + version +
90            "&last=" + str(nb_tests))
91     request = Request(url)
92
93     try:
94         response = urlopen(request)
95         k = response.read()
96         results = json.loads(k)
97     except URLError as e:
98         print('No kittez. Got an error code:', e)
99
100     return results
101
102
103 def getScenarios(case, installer, version):
104
105     try:
106         case = case.getName()
107     except:
108         # if case is not an object test case, try the string
109         if type(case) == str:
110             case = case
111         else:
112             raise ValueError("Case cannot be evaluated")
113
114     period = get_config('general.period')
115     url_base = get_config('testapi.url')
116
117     url = ("http://" + url_base + "?case=" + case +
118            "&period=" + str(period) + "&installer=" + installer +
119            "&version=" + version)
120     request = Request(url)
121
122     try:
123         response = urlopen(request)
124         k = response.read()
125         results = json.loads(k)
126         test_results = results['results']
127     except URLError as e:
128         print('Got an error code:', e)
129
130     if test_results is not None:
131         test_results.reverse()
132
133         scenario_results = {}
134
135         for r in test_results:
136             # Retrieve all the scenarios per installer
137             if not r['scenario'] in scenario_results.keys():
138                 scenario_results[r['scenario']] = []
139             # Do we consider results from virtual pods ...
140             # Do we consider results for non HA scenarios...
141             exclude_virtual_pod = get_config('functest.exclude_virtual')
142             exclude_noha = get_config('functest.exclude_noha')
143             if ((exclude_virtual_pod and "virtual" in r['pod_name']) or
144                     (exclude_noha and "noha" in r['scenario'])):
145                 print("exclude virtual pod results...")
146             else:
147                 scenario_results[r['scenario']].append(r)
148
149     return scenario_results
150
151
152 def getScenarioStats(scenario_results):
153     scenario_stats = {}
154     for k, v in scenario_results.iteritems():
155         scenario_stats[k] = len(v)
156
157     return scenario_stats
158
159
160 # TODO convergence with above function getScenarios
161 def getScenarioStatus(installer, version):
162     period = get_config('general.period')
163     url_base = get_config('testapi.url')
164
165     url = ("http://" + url_base + "?case=scenario_status" +
166            "&installer=" + installer +
167            "&version=" + version + "&period=" + str(period))
168     request = Request(url)
169
170     try:
171         response = urlopen(request)
172         k = response.read()
173         response.close()
174         results = json.loads(k)
175         test_results = results['results']
176     except URLError as e:
177         print('Got an error code:', e)
178
179     scenario_results = {}
180     result_dict = {}
181     if test_results is not None:
182         for r in test_results:
183             if r['stop_date'] != 'None' and r['criteria'] is not None:
184                 if not r['scenario'] in scenario_results.keys():
185                     scenario_results[r['scenario']] = []
186                 scenario_results[r['scenario']].append(r)
187
188         for k, v in scenario_results.items():
189             # scenario_results[k] = v[:LASTEST_TESTS]
190             s_list = []
191             for element in v:
192                 if element['criteria'] == 'SUCCESS':
193                     s_list.append(1)
194                 else:
195                     s_list.append(0)
196             result_dict[k] = s_list
197
198     # return scenario_results
199     return result_dict
200
201
202 def getQtipResults(version, installer):
203     period = get_config('qtip.period')
204     url_base = get_config('testapi.url')
205
206     url = ("http://" + url_base + "?project=qtip" +
207            "&installer=" + installer +
208            "&version=" + version + "&period=" + str(period))
209     request = Request(url)
210
211     try:
212         response = urlopen(request)
213         k = response.read()
214         response.close()
215         results = json.loads(k)['results']
216     except URLError as e:
217         print('Got an error code:', e)
218
219     result_dict = {}
220     if results:
221         for r in results:
222             key = '{}/{}'.format(r['pod_name'], r['scenario'])
223             if key not in result_dict.keys():
224                 result_dict[key] = []
225             result_dict[key].append(r['details']['score'])
226
227     # return scenario_results
228     return result_dict
229
230
231 def getNbtestOk(results):
232     nb_test_ok = 0
233     for r in results:
234         for k, v in r.iteritems():
235             try:
236                 if "PASS" in v:
237                     nb_test_ok += 1
238             except:
239                 print("Cannot retrieve test status")
240     return nb_test_ok
241
242
243 def getResult(testCase, installer, scenario, version):
244
245     # retrieve raw results
246     results = getApiResults(testCase, installer, scenario, version)
247     # let's concentrate on test results only
248     test_results = results['results']
249
250     # if results found, analyze them
251     if test_results is not None:
252         test_results.reverse()
253
254         scenario_results = []
255
256         # print " ---------------- "
257         # print test_results
258         # print " ---------------- "
259         # print "nb of results:" + str(len(test_results))
260
261         for r in test_results:
262             # print r["start_date"]
263             # print r["criteria"]
264             scenario_results.append({r["start_date"]: r["criteria"]})
265         # sort results
266         scenario_results.sort()
267         # 4 levels for the results
268         # 3: 4+ consecutive runs passing the success criteria
269         # 2: <4 successful consecutive runs but passing the criteria
270         # 1: close to pass the success criteria
271         # 0: 0% success, not passing
272         # -1: no run available
273         test_result_indicator = 0
274         nbTestOk = getNbtestOk(scenario_results)
275
276         # print "Nb test OK (last 10 days):"+ str(nbTestOk)
277         # check that we have at least 4 runs
278         if len(scenario_results) < 1:
279             # No results available
280             test_result_indicator = -1
281         elif nbTestOk < 1:
282             test_result_indicator = 0
283         elif nbTestOk < 2:
284             test_result_indicator = 1
285         else:
286             # Test the last 4 run
287             if (len(scenario_results) > 3):
288                 last4runResults = scenario_results[-4:]
289                 nbTestOkLast4 = getNbtestOk(last4runResults)
290                 # print "Nb test OK (last 4 run):"+ str(nbTestOkLast4)
291                 if nbTestOkLast4 > 3:
292                     test_result_indicator = 3
293                 else:
294                     test_result_indicator = 2
295             else:
296                 test_result_indicator = 2
297     return test_result_indicator
298
299
300 def getJenkinsUrl(build_tag):
301     # e.g. jenkins-functest-apex-apex-daily-colorado-daily-colorado-246
302     # id = 246
303     # jenkins-functest-compass-huawei-pod5-daily-master-136
304     # id = 136
305     # note it is linked to jenkins format
306     # if this format changes...function to be adapted....
307     url_base = get_config('functest.jenkins_url')
308     try:
309         build_id = [int(s) for s in build_tag.split("-") if s.isdigit()]
310         url_id = (build_tag[8:-(len(str(build_id[0])) + 1)] +
311                   "/" + str(build_id[0]))
312         jenkins_url = url_base + url_id + "/console"
313     except:
314         print('Impossible to get jenkins url:')
315
316     if "jenkins-" not in build_tag:
317         jenkins_url = None
318
319     return jenkins_url
320
321
322 def getScenarioPercent(scenario_score, scenario_criteria):
323     score = 0.0
324     try:
325         score = float(scenario_score) / float(scenario_criteria) * 100
326     except:
327         print('Impossible to calculate the percentage score')
328     return score
329
330
331 # *********
332 # Functest
333 # *********
334 def getFunctestConfig(version=""):
335     config_file = get_config('functest.test_conf') + version
336     response = requests.get(config_file)
337     return yaml.safe_load(response.text)
338
339
340 def getArchitectures(scenario_results):
341     supported_arch = ['x86']
342     if (len(scenario_results) > 0):
343         for scenario_result in scenario_results.values():
344             for value in scenario_result:
345                 if ("armband" in value['build_tag']):
346                     supported_arch.append('aarch64')
347                     return supported_arch
348     return supported_arch
349
350
351 def filterArchitecture(results, architecture):
352     filtered_results = {}
353     for name, results in results.items():
354         filtered_values = []
355         for value in results:
356             if (architecture is "x86"):
357                 # drop aarch64 results
358                 if ("armband" not in value['build_tag']):
359                     filtered_values.append(value)
360             elif(architecture is "aarch64"):
361                 # drop x86 results
362                 if ("armband" in value['build_tag']):
363                     filtered_values.append(value)
364         if (len(filtered_values) > 0):
365             filtered_results[name] = filtered_values
366     return filtered_results
367
368
369 # *********
370 # Yardstick
371 # *********
372 def subfind(given_list, pattern_list):
373     LASTEST_TESTS = get_config('general.nb_iteration_tests_success_criteria')
374     for i in range(len(given_list)):
375         if given_list[i] == pattern_list[0] and \
376                 given_list[i:i + LASTEST_TESTS] == pattern_list:
377             return True
378     return False
379
380
381 def _get_percent(status):
382
383     if status * 100 % 6:
384         return round(float(status) * 100 / 6, 1)
385     else:
386         return status * 100 / 6
387
388
389 def get_percent(four_list, ten_list):
390     four_score = 0
391     ten_score = 0
392
393     for v in four_list:
394         four_score += v
395     for v in ten_list:
396         ten_score += v
397
398     LASTEST_TESTS = get_config('general.nb_iteration_tests_success_criteria')
399     if four_score == LASTEST_TESTS:
400         status = 6
401     elif subfind(ten_list, [1, 1, 1, 1]):
402         status = 5
403     elif ten_score == 0:
404         status = 0
405     else:
406         status = four_score + 1
407
408     return _get_percent(status)
409
410
411 def _test():
412     status = getScenarioStatus("compass", "master")
413     print("status:++++++++++++++++++++++++")
414     print(json.dumps(status, indent=4))
415
416
417 # ----------------------------------------------------------
418 #
419 #               Export
420 #
421 # -----------------------------------------------------------
422
423 def export_csv(scenario_file_name, installer, version):
424     # csv
425     # generate sub files based on scenario_history.txt
426     scenario_installer_file_name = ("./display/" + version +
427                                     "/functest/scenario_history_" +
428                                     installer + ".csv")
429     scenario_installer_file = open(scenario_installer_file_name, "a")
430     with open(scenario_file_name, "r") as f:
431         scenario_installer_file.write("date,scenario,installer,detail,score\n")
432         for line in f:
433             if installer in line:
434                 scenario_installer_file.write(line)
435         scenario_installer_file.close
436
437
438 def generate_csv(scenario_file):
439     import shutil
440     # csv
441     # generate sub files based on scenario_history.txt
442     csv_file = scenario_file.replace('txt', 'csv')
443     shutil.copy2(scenario_file, csv_file)
444
445
446 def export_pdf(pdf_path, pdf_doc_name):
447     try:
448         pdfkit.from_file(pdf_path, pdf_doc_name)
449     except IOError:
450         print("Error but pdf generated anyway...")
451     except:
452         print("impossible to generate PDF")