Merge "Add untracked files to ignore"
[functest.git] / testcases / functest_utils.py
1 #!/usr/bin/env python
2 #
3 # jose.lausuch@ericsson.com
4 # valentin.boucher@orange.com
5 # All rights reserved. This program and the accompanying materials
6 # are made available under the terms of the Apache License, Version 2.0
7 # which accompanies this distribution, and is available at
8 # http://www.apache.org/licenses/LICENSE-2.0
9 #
10
11 import json
12 import os
13 import os.path
14 import re
15 import requests
16 import shutil
17 import socket
18 import subprocess
19 import urllib2
20 from git import Repo
21
22
23 # ----------------------------------------------------------
24 #
25 #               INTERNET UTILS
26 #
27 # -----------------------------------------------------------
28 def check_internet_connectivity(url='http://www.opnfv.org/'):
29     """
30     Check if there is access to the internet
31     """
32     try:
33         urllib2.urlopen(url, timeout=5)
34         return True
35     except urllib2.URLError:
36         return False
37
38
39 def download_url(url, dest_path):
40     """
41     Download a file to a destination path given a URL
42     """
43     name = url.rsplit('/')[-1]
44     dest = dest_path + "/" + name
45     try:
46         response = urllib2.urlopen(url)
47     except (urllib2.HTTPError, urllib2.URLError):
48         return False
49
50     with open(dest, 'wb') as f:
51         shutil.copyfileobj(response, f)
52     return True
53
54
55 # ----------------------------------------------------------
56 #
57 #               CI UTILS
58 #
59 # -----------------------------------------------------------
60 def get_git_branch(repo_path):
61     """
62     Get git branch name
63     """
64     repo = Repo(repo_path)
65     branch = repo.active_branch
66     return branch.name
67
68
69 def get_installer_type(logger=None):
70     """
71     Get installer type (fuel, apex, joid, compass)
72     """
73     try:
74         installer = os.environ['INSTALLER_TYPE']
75     except KeyError:
76         if logger:
77             logger.error("Impossible to retrieve the installer type")
78         installer = "Unknown_installer"
79
80     return installer
81
82
83 def get_scenario(logger=None):
84     """
85     Get scenario
86     """
87     try:
88         scenario = os.environ['DEPLOY_SCENARIO']
89     except KeyError:
90         if logger:
91             logger.error("Impossible to retrieve the scenario")
92         scenario = "Unknown_scenario"
93
94     return scenario
95
96
97 def get_version(logger=None):
98     """
99     Get version
100     """
101     # Use the build tag to retrieve the version
102     # By default version is unknown
103     # if launched through CI the build tag has the following format
104     # jenkins-<project>-<installer>-<pod>-<job>-<branch>-<id>
105     # e.g. jenkins-functest-fuel-opnfv-jump-2-daily-master-190
106     # use regex to match branch info
107     rule = "daily-(.+?)-[0-9]*"
108     build_tag = get_build_tag(logger)
109     m = re.search(rule, build_tag)
110     if m:
111         return m.group(1)
112     else:
113         return "unknown"
114
115
116 def get_pod_name(logger=None):
117     """
118     Get PoD Name from env variable NODE_NAME
119     """
120     try:
121         return os.environ['NODE_NAME']
122     except KeyError:
123         if logger:
124             logger.error(
125                 "Unable to retrieve the POD name from environment. " +
126                 "Using pod name 'unknown-pod'")
127         return "unknown-pod"
128
129
130 def get_build_tag(logger=None):
131     """
132     Get build tag of jenkins jobs
133     """
134     try:
135         build_tag = os.environ['BUILD_TAG']
136     except KeyError:
137         if logger:
138             logger.error("Impossible to retrieve the build tag")
139         build_tag = "unknown_build_tag"
140
141     return build_tag
142
143
144 def push_results_to_db(db_url, project, case_name, logger, pod_name,
145                        version, scenario, criteria, build_tag, payload):
146     """
147     POST results to the Result target DB
148     """
149     url = db_url + "/results"
150     installer = get_installer_type(logger)
151     params = {"project_name": project, "case_name": case_name,
152               "pod_name": pod_name, "installer": installer,
153               "version": version, "scenario": scenario, "criteria": criteria,
154               "build_tag": build_tag, "details": payload}
155
156     headers = {'Content-Type': 'application/json'}
157     try:
158         r = requests.post(url, data=json.dumps(params), headers=headers)
159         if logger:
160             logger.debug(r)
161         return True
162     except Exception, e:
163         print ("Error [push_results_to_db('%s', '%s', '%s', " +
164                "'%s', '%s', '%s', '%s', '%s', '%s')]:" %
165                (db_url, project, case_name, pod_name, version,
166                 scenario, criteria, build_tag, payload), e)
167         return False
168
169
170 def get_resolvconf_ns():
171     """
172     Get nameservers from current resolv.conf
173     """
174     nameservers = []
175     rconf = open("/etc/resolv.conf", "r")
176     line = rconf.readline()
177     while line:
178         ip = re.search(r"\b(?:[0-9]{1,3}\.){3}[0-9]{1,3}\b", line)
179         sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
180         if ip:
181             result = sock.connect_ex((ip.group(), 53))
182             if result == 0:
183                 nameservers.append(ip.group())
184         line = rconf.readline()
185     return nameservers
186
187
188 def getTestEnv(test, functest_yaml):
189     """
190     Get the config of the testcase based on functest_config.yaml
191       2 options
192         - test = test project e.g; ovno
193         - test = testcase e.g. functest/odl
194        look for the / to see if it is a test project or a testcase
195     """
196     try:
197         TEST_ENV = functest_yaml.get("test-dependencies")
198
199         if test.find("/") < 0:
200             config_test = TEST_ENV[test]
201         else:
202             test_split = test.split("/")
203             testproject = test_split[0]
204             testcase = test_split[1]
205             config_test = TEST_ENV[testproject][testcase]
206     except KeyError:
207         # if not defined in dependencies => no dependencies
208         config_test = ""
209     except Exception, e:
210         print "Error [getTestEnv]:", e
211
212     return config_test
213
214
215 def get_ci_envvars():
216     """
217     Get the CI env variables
218     """
219     ci_env_var = {
220         "installer": os.environ.get('INSTALLER_TYPE'),
221         "scenario": os.environ.get('DEPLOY_SCENARIO')}
222     return ci_env_var
223
224
225 def isTestRunnable(test, functest_yaml):
226     """
227     Return True if the test is runnable in the current scenario
228     """
229     # By default we assume that all the tests are always runnable...
230     is_runnable = True
231     # Retrieve CI environment
232     ci_env = get_ci_envvars()
233     # Retrieve test environement from config file
234     test_env = getTestEnv(test, functest_yaml)
235
236     # if test_env not empty => dependencies to be checked
237     if test_env is not None and len(test_env) > 0:
238         # possible criteria = ["installer", "scenario"]
239         # consider test criteria from config file
240         # compare towards CI env through CI en variable
241         for criteria in test_env:
242             if re.search(test_env[criteria], ci_env[criteria]) is None:
243                 # print "Test "+ test + " cannot be run on the environment"
244                 is_runnable = False
245     return is_runnable
246
247
248 def generateTestcaseList(functest_yaml):
249     """
250     Generate a test file with the runnable test according to
251     the current scenario
252     """
253     test_list = ""
254     # get testcases
255     testcase_list = functest_yaml.get("test-dependencies")
256     projects = testcase_list.keys()
257
258     for project in projects:
259         testcases = testcase_list[project]
260         # 1 or 2 levels for testcases project[/case]l
261         # if only project name without controller or scenario
262         # => shall be runnable on any controller/scenario
263         if testcases is None:
264             test_list += project + " "
265         else:
266             for testcase in testcases:
267                 if testcase == "installer" or testcase == "scenario":
268                     # project (1 level)
269                     if isTestRunnable(project, functest_yaml):
270                         test_list += project + " "
271                 else:
272                     # project/testcase (2 levels)
273                     thetest = project + "/" + testcase
274                     if isTestRunnable(thetest, functest_yaml):
275                         test_list += testcase + " "
276
277     # sort the list to execute the test in the right order
278     test_order_list = functest_yaml.get("test_exec_priority")
279     test_sorted_list = ""
280     for test in test_order_list:
281         if test_order_list[test] in test_list:
282             test_sorted_list += test_order_list[test] + " "
283
284     # create a file that could be consumed by run-test.sh
285     # this method is used only for CI
286     # so it can be run only in container
287     # reuse default conf directory to store the list of runnable tests
288     file = open("/home/opnfv/functest/conf/testcase-list.txt", 'w')
289     file.write(test_sorted_list)
290     file.close()
291
292     return test_sorted_list
293
294
295 def execute_command(cmd, logger=None, exit_on_error=True):
296     """
297     Execute Linux command
298         prints stdout to a file and depending on if there
299         is a logger defined, it will print it or not.
300     """
301     if logger:
302         logger.debug('Executing command : {}'.format(cmd))
303     output_file = "output.txt"
304     f = open(output_file, 'w+')
305     p = subprocess.call(cmd, shell=True, stdout=f, stderr=subprocess.STDOUT)
306     f.close()
307     f = open(output_file, 'r')
308     result = f.read()
309     if result != "" and logger:
310         logger.debug(result)
311     if p == 0:
312         return True
313     else:
314         if logger:
315             logger.error("Error when executing command %s" % cmd)
316         if exit_on_error:
317             exit(-1)
318         return False