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