Merge "Adding GS clenaup for Apex"
[releng.git] / utils / test / reporting / functest / reporting-status.py
1 from urllib2 import Request, urlopen, URLError
2 import json
3 import jinja2
4 import os
5 import re
6 import requests
7 import sys
8 import time
9 import yaml
10
11 # Declaration of the variables
12 functest_test_list = ['vPing', 'vPing_userdata',
13                       'Tempest', 'Rally',
14                       'ODL', 'ONOS', 'vIMS']
15 # functest_test_list = ['vPing']
16 companion_test_list = ['doctor/doctor-notification', 'promise/promise']
17 # companion_test_list = []
18 installers = ["apex", "compass", "fuel", "joid"]
19 # installers = ["fuel"]
20 versions = ["brahmaputra", "master"]
21 # versions = ["master"]
22 PERIOD = 10
23
24 # Correspondance between the name of the test case and the name in the DB
25 # ideally we should modify the DB to avoid such interface....
26 # '<name in the DB':'<name in the config'>
27 # I know it is uggly...
28 test_match_matrix = {'vPing': 'vping_ssh',
29                      'vPing_userdata': 'vping_userdata',
30                      'ODL': 'odl',
31                      'ONOS': 'onos',
32                      'Tempest': 'tempest',
33                      'Rally': 'rally',
34                      'vIMS': 'vims',
35                      'doctor-notification': 'doctor',
36                      'promise': 'promise'}
37
38
39 class TestCase(object):
40     def __init__(self, name, project, criteria=-1, isRunnable=True):
41         self.name = name
42         self.project = project
43         self.criteria = criteria
44         self.isRunnable = isRunnable
45
46     def getName(self):
47         return self.name
48
49     def getProject(self):
50         return self.project
51
52     def getCriteria(self):
53         return self.criteria
54
55     def setCriteria(self, criteria):
56         self.criteria = criteria
57
58     def setIsRunnable(self, isRunnable):
59         self.isRunnable = isRunnable
60
61     def checkRunnable(self, installer, scenario, config):
62         # Re-use Functest declaration
63         # Retrieve Functest configuration file functest_config.yaml
64         is_runnable = True
65         config_test = ""
66         TEST_ENV = functest_yaml_config.get("test-dependencies")
67
68         # print " *********************** "
69         # print TEST_ENV
70         # print " ---------------------- "
71         # print "case = " + self.name
72         # print "installer = " + installer
73         # print "scenario = " + scenario
74         # print "project = " + self.project
75
76         # Retrieve test constraints
77         case_name_formated = test_match_matrix[self.name]
78
79         try:
80             config_test = TEST_ENV[self.project][case_name_formated]
81         except KeyError:
82             # if not defined in dependencies => no dependencies
83             config_test = TEST_ENV[case_name_formated]
84         except Exception, e:
85             print "Error [getTestEnv]:", e
86
87         # Retrieve test execution param
88         test_execution_context = {"installer": installer,
89                                   "scenario": scenario}
90         # By default we assume that all the tests are always runnable...
91         # if test_env not empty => dependencies to be checked
92         if config_test is not None and len(config_test) > 0:
93             # possible criteria = ["installer", "scenario"]
94             # consider test criteria from config file
95             # compare towards CI env through CI en variable
96             for criteria in config_test:
97                 if re.search(config_test[criteria],
98                              test_execution_context[criteria]) is None:
99                     # print "Test "+ test + " cannot be run on the environment"
100                     is_runnable = False
101         # print is_runnable
102         self.isRunnable = is_runnable
103
104
105 def getApiResults(case, installer, scenario, version):
106     case = case.getName()
107     results = json.dumps([])
108     # to remove proxy (to be removed at the end for local test only)
109     # proxy_handler = urllib2.ProxyHandler({})
110     # opener = urllib2.build_opener(proxy_handler)
111     # urllib2.install_opener(opener)
112     # url = "http://127.0.0.1:8000/results?case=" + case + \
113     #       "&period=30&installer=" + installer
114     url = ("http://testresults.opnfv.org/testapi/results?case=" + case +
115            "&period=" + str(PERIOD) + "&installer=" + installer +
116            "&scenario=" + scenario + "&version=" + version)
117     request = Request(url)
118
119     try:
120         response = urlopen(request)
121         k = response.read()
122         results = json.loads(k)
123     except URLError, e:
124         print 'No kittez. Got an error code:', e
125
126     return results
127
128
129 def getScenarios(case, installer, version):
130
131     case = case.getName()
132     url = "http://testresults.opnfv.org/testapi/results?case=" + case + \
133           "&period=" + str(PERIOD) + "&installer=" + installer + \
134           "&version=" + version
135     request = Request(url)
136
137     try:
138         response = urlopen(request)
139         k = response.read()
140         results = json.loads(k)
141     except URLError, e:
142         print 'Got an error code:', e
143
144     test_results = results['test_results']
145
146     if test_results is not None:
147         test_results.reverse()
148
149         scenario_results = {}
150
151         for r in test_results:
152             # Retrieve all the scenarios per installer
153             if not r['scenario'] in scenario_results.keys():
154                 scenario_results[r['scenario']] = []
155             scenario_results[r['scenario']].append(r)
156
157     return scenario_results
158
159
160 def getScenarioStats(scenario_results):
161     scenario_stats = {}
162     for k, v in scenario_results.iteritems():
163         scenario_stats[k] = len(v)
164
165     return scenario_stats
166
167
168 def getNbtestOk(results):
169     nb_test_ok = 0
170     for r in results:
171         for k, v in r.iteritems():
172             try:
173                 if "passed" in v:
174                     nb_test_ok += 1
175             except:
176                 print "Cannot retrieve test status"
177     return nb_test_ok
178
179
180 def getResult(testCase, installer, scenario, version):
181
182     # retrieve raw results
183     results = getApiResults(testCase, installer, scenario, version)
184     # let's concentrate on test results only
185     test_results = results['test_results']
186
187     # if results found, analyze them
188     if test_results is not None:
189         test_results.reverse()
190
191         scenario_results = []
192
193         # print " ---------------- "
194         # print test_results
195         # print " ---------------- "
196         # print "nb of results:" + str(len(test_results))
197
198         for r in test_results:
199             # print r["creation_date"]
200             # print r["criteria"]
201             scenario_results.append({r["creation_date"]: r["criteria"]})
202         # sort results
203         scenario_results.sort()
204         # 4 levels for the results
205         # 3: 4+ consecutive runs passing the success criteria
206         # 2: <4 successful consecutive runs but passing the criteria
207         # 1: close to pass the success criteria
208         # 0: 0% success, not passing
209         test_result_indicator = 0
210         nbTestOk = getNbtestOk(scenario_results)
211         # print "Nb test OK:"+ str(nbTestOk)
212         # check that we have at least 4 runs
213         if nbTestOk < 1:
214             test_result_indicator = 0
215         elif nbTestOk < 2:
216             test_result_indicator = 1
217         else:
218             # Test the last 4 run
219             if (len(scenario_results) > 3):
220                 last4runResults = scenario_results[-4:]
221                 if getNbtestOk(last4runResults):
222                     test_result_indicator = 3
223                 else:
224                     test_result_indicator = 2
225             else:
226                 test_result_indicator = 2
227     print "        >>>> Test indicator:" + str(test_result_indicator)
228     return test_result_indicator
229
230 # ******************************************************************************
231 # ******************************************************************************
232 # ******************************************************************************
233 # ******************************************************************************
234 # ******************************************************************************
235
236 # init just tempest to get the list of scenarios
237 # as all the scenarios run Tempest
238 tempest = TestCase("Tempest", "functest", -1)
239
240 # Retrieve the Functest configuration to detect which tests are relevant
241 # according to the installer, scenario
242 cf = "https://git.opnfv.org/cgit/functest/plain/testcases/config_functest.yaml"
243 response = requests.get(cf)
244 functest_yaml_config = yaml.load(response.text)
245
246 print "****************************************"
247 print "*   Generating reporting.....          *"
248 print "****************************************"
249 # For all the versions
250 for version in versions:
251     # For all the installers
252     for installer in installers:
253         # get scenarios
254         scenario_results = getScenarios(tempest, installer, version)
255         scenario_stats = getScenarioStats(scenario_results)
256
257         items = {}
258         # For all the scenarios get results
259         for s, s_result in scenario_results.items():
260             testCases = []
261             # For each scenario declare the test cases
262             # Functest cases
263             for test_case in functest_test_list:
264                 testCases.append(TestCase(test_case, "functest"))
265
266             # project/case
267             for test_case in companion_test_list:
268                 test_split = test_case.split("/")
269                 test_project = test_split[0]
270                 test_case = test_split[1]
271                 testCases.append(TestCase(test_case, test_project))
272
273             # Check if test case is runnable / installer, scenario
274             try:
275                 for test_case in testCases:
276                     test_case.checkRunnable(installer, s, functest_yaml_config)
277                     # print "testcase %s is %s" % (test_case.getName(),
278                     #                              test_case.isRunnable)
279                 print "--------------------------"
280                 print ("installer %s, version %s, scenario %s:" %
281                        (installer, version, s))
282                 for testCase in testCases:
283                     time.sleep(1)
284                     if testCase.isRunnable:
285                         print (" Searching results for case %s " %
286                                (testCase.getName()))
287                         result = getResult(testCase, installer, s, version)
288                         testCase.setCriteria(result)
289                         items[s] = testCases
290                 print "--------------------------"
291             except:
292                 print ("installer %s, version %s, scenario %s" %
293                        (installer, version, s))
294                 print "No data available , error %s " % (sys.exc_info()[0])
295
296         print "****************************************"
297         templateLoader = jinja2.FileSystemLoader(os.path.dirname(os.path.abspath(__file__)))
298         templateEnv = jinja2.Environment(loader=templateLoader)
299
300         TEMPLATE_FILE = "./template/index-status-tmpl.html"
301         template = templateEnv.get_template(TEMPLATE_FILE)
302
303         outputText = template.render(scenario_stats=scenario_stats,
304                                      items=items,
305                                      installer=installer,
306                                      period=PERIOD,
307                                      version=version)
308
309         with open("./release/" + version +
310                   "/index-status-" + installer + ".html", "wb") as fh:
311             fh.write(outputText)