add qtip reporting
[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 getQtipResults(version, installer):
202     period = get_config('qtip.period')
203     url_base = get_config('testapi.url')
204
205     url = ("http://" + url_base + "?project=qtip" +
206            "&installer=" + installer +
207            "&version=" + version + "&period=" + str(period))
208     request = Request(url)
209
210     try:
211         response = urlopen(request)
212         k = response.read()
213         response.close()
214         results = json.loads(k)['results']
215     except URLError as e:
216         print('Got an error code:', e)
217
218     result_dict = {}
219     if results:
220         for r in results:
221             key = '{}/{}'.format(r['pod_name'], r['scenario'])
222             if key not in result_dict.keys():
223                 result_dict[key] = []
224             result_dict[key].append(r['details']['score'])
225
226     # return scenario_results
227     return result_dict
228
229
230 def getNbtestOk(results):
231     nb_test_ok = 0
232     for r in results:
233         for k, v in r.iteritems():
234             try:
235                 if "PASS" in v:
236                     nb_test_ok += 1
237             except:
238                 print("Cannot retrieve test status")
239     return nb_test_ok
240
241
242 def getResult(testCase, installer, scenario, version):
243
244     # retrieve raw results
245     results = getApiResults(testCase, installer, scenario, version)
246     # let's concentrate on test results only
247     test_results = results['results']
248
249     # if results found, analyze them
250     if test_results is not None:
251         test_results.reverse()
252
253         scenario_results = []
254
255         # print " ---------------- "
256         # print test_results
257         # print " ---------------- "
258         # print "nb of results:" + str(len(test_results))
259
260         for r in test_results:
261             # print r["start_date"]
262             # print r["criteria"]
263             scenario_results.append({r["start_date"]: r["criteria"]})
264         # sort results
265         scenario_results.sort()
266         # 4 levels for the results
267         # 3: 4+ consecutive runs passing the success criteria
268         # 2: <4 successful consecutive runs but passing the criteria
269         # 1: close to pass the success criteria
270         # 0: 0% success, not passing
271         # -1: no run available
272         test_result_indicator = 0
273         nbTestOk = getNbtestOk(scenario_results)
274
275         # print "Nb test OK (last 10 days):"+ str(nbTestOk)
276         # check that we have at least 4 runs
277         if len(scenario_results) < 1:
278             # No results available
279             test_result_indicator = -1
280         elif nbTestOk < 1:
281             test_result_indicator = 0
282         elif nbTestOk < 2:
283             test_result_indicator = 1
284         else:
285             # Test the last 4 run
286             if (len(scenario_results) > 3):
287                 last4runResults = scenario_results[-4:]
288                 nbTestOkLast4 = getNbtestOk(last4runResults)
289                 # print "Nb test OK (last 4 run):"+ str(nbTestOkLast4)
290                 if nbTestOkLast4 > 3:
291                     test_result_indicator = 3
292                 else:
293                     test_result_indicator = 2
294             else:
295                 test_result_indicator = 2
296     return test_result_indicator
297
298
299 def getJenkinsUrl(build_tag):
300     # e.g. jenkins-functest-apex-apex-daily-colorado-daily-colorado-246
301     # id = 246
302     # jenkins-functest-compass-huawei-pod5-daily-master-136
303     # id = 136
304     # note it is linked to jenkins format
305     # if this format changes...function to be adapted....
306     url_base = get_config('functest.jenkins_url')
307     try:
308         build_id = [int(s) for s in build_tag.split("-") if s.isdigit()]
309         url_id = (build_tag[8:-(len(str(build_id[0])) + 1)] +
310                   "/" + str(build_id[0]))
311         jenkins_url = url_base + url_id + "/console"
312     except:
313         print('Impossible to get jenkins url:')
314
315     if "jenkins-" not in build_tag:
316         jenkins_url = None
317
318     return jenkins_url
319
320
321 def getScenarioPercent(scenario_score, scenario_criteria):
322     score = 0.0
323     try:
324         score = float(scenario_score) / float(scenario_criteria) * 100
325     except:
326         print('Impossible to calculate the percentage score')
327     return score
328
329
330 # *********
331 # Yardstick
332 # *********
333 def subfind(given_list, pattern_list):
334     LASTEST_TESTS = get_config('general.nb_iteration_tests_success_criteria')
335     for i in range(len(given_list)):
336         if given_list[i] == pattern_list[0] and \
337                 given_list[i:i + LASTEST_TESTS] == pattern_list:
338             return True
339     return False
340
341
342 def _get_percent(status):
343
344     if status * 100 % 6:
345         return round(float(status) * 100 / 6, 1)
346     else:
347         return status * 100 / 6
348
349
350 def get_percent(four_list, ten_list):
351     four_score = 0
352     ten_score = 0
353
354     for v in four_list:
355         four_score += v
356     for v in ten_list:
357         ten_score += v
358
359     LASTEST_TESTS = get_config('general.nb_iteration_tests_success_criteria')
360     if four_score == LASTEST_TESTS:
361         status = 6
362     elif subfind(ten_list, [1, 1, 1, 1]):
363         status = 5
364     elif ten_score == 0:
365         status = 0
366     else:
367         status = four_score + 1
368
369     return _get_percent(status)
370
371
372 def _test():
373     status = getScenarioStatus("compass", "master")
374     print("status:++++++++++++++++++++++++")
375     print(json.dumps(status, indent=4))
376
377
378 # ----------------------------------------------------------
379 #
380 #               Export
381 #
382 # -----------------------------------------------------------
383
384 def export_csv(scenario_file_name, installer, version):
385     # csv
386     # generate sub files based on scenario_history.txt
387     scenario_installer_file_name = ("./display/" + version +
388                                     "/functest/scenario_history_" +
389                                     installer + ".csv")
390     scenario_installer_file = open(scenario_installer_file_name, "a")
391     with open(scenario_file_name, "r") as f:
392         scenario_installer_file.write("date,scenario,installer,detail,score\n")
393         for line in f:
394             if installer in line:
395                 scenario_installer_file.write(line)
396         scenario_installer_file.close
397
398
399 def generate_csv(scenario_file):
400     import shutil
401     # csv
402     # generate sub files based on scenario_history.txt
403     csv_file = scenario_file.replace('txt', 'csv')
404     shutil.copy2(scenario_file, csv_file)
405
406
407 def export_pdf(pdf_path, pdf_doc_name):
408     try:
409         pdfkit.from_file(pdf_path, pdf_doc_name)
410     except IOError:
411         print("Error but pdf generated anyway...")
412     except:
413         print("impossible to generate PDF")