fuel-qa/fuelweb_test/testrail/builds.py

189 lines
6.2 KiB
Python

# Copyright 2015 Mirantis, Inc.
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
from __future__ import unicode_literals
import json
import re
# pylint: disable=import-error
# noinspection PyUnresolvedReferences
from six.moves.urllib import request
# pylint: enable=import-error
from fuelweb_test.testrail.settings import JENKINS
from fuelweb_test.testrail.settings import logger
def get_jobs_for_view(view):
"""Return list of jobs from specified view
"""
view_url = "/".join([JENKINS["url"], 'view', view, 'api/json'])
logger.debug("Request view data from {}".format(view_url))
req = request.Request(view_url)
opener = request.build_opener(request.HTTPHandler)
s = opener.open(req).read()
opener.close()
view_data = json.loads(s)
jobs = [job["name"] for job in view_data["jobs"]]
return jobs
def get_downstream_builds_from_html(url):
"""Return list of downstream jobs builds from specified job
"""
url = "/".join([url, 'downstreambuildview/'])
logger.debug("Request downstream builds data from {}".format(url))
req = request.Request(url)
opener = request.build_opener(request.HTTPHandler)
s = opener.open(req).read()
opener.close()
jobs = []
raw_downstream_builds = re.findall(
'.*downstream-buildview.*href="(/job/\S+/[0-9]+/).*', s)
for raw_build in raw_downstream_builds:
sub_job_name = raw_build.split('/')[2]
sub_job_build = raw_build.split('/')[3]
build = Build(name=sub_job_name, number=sub_job_build)
jobs.append(
{
'name': build.name,
'number': build.number,
'result': build.build_data['result']
}
)
return jobs
def get_build_artifact(url, artifact):
"""Return content of job build artifact
"""
url = "/".join([url, 'artifact', artifact])
logger.debug("Request artifact content from {}".format(url))
req = request.Request(url)
opener = request.build_opener(request.HTTPHandler)
s = opener.open(req).read()
opener.close()
return s
class Build(object):
def __init__(self, name, number):
"""Get build info via Jenkins API, get test info via direct HTTP
request.
If number is 'latest', get latest completed build.
"""
self.name = name
if number == 'latest':
job_info = self.get_job_info(depth=0)
self.number = job_info["lastCompletedBuild"]["number"]
elif number == 'latest_started':
job_info = self.get_job_info(depth=0)
self.number = job_info["lastBuild"]["number"]
else:
self.number = int(number)
self.build_data = self.get_build_data(depth=0)
self.url = self.build_data["url"]
def get_job_info(self, depth=1):
job_url = "/".join([JENKINS["url"], 'job', self.name,
'api/json?depth={depth}'.format(depth=depth)])
logger.debug("Request job info from {}".format(job_url))
return json.load(request.urlopen(job_url))
def get_job_console(self):
job_url = "/".join([JENKINS["url"], 'job', self.name,
str(self.number), 'consoleText'])
logger.debug("Request job console from {}".format(job_url))
return request.urlopen(job_url)
def get_build_data(self, depth=1):
build_url = "/".join([JENKINS["url"], 'job',
self.name,
str(self.number),
'api/json?depth={depth}'.format(depth=depth)])
logger.debug("Request build data from {}".format(build_url))
return json.load(request.urlopen(build_url))
@staticmethod
def get_test_data(url, result_path=None):
if result_path:
test_url = "/".join(
[url.rstrip("/"), 'testReport'] + result_path + ['api/json'])
else:
test_url = "/".join([url.rstrip("/"), 'testReport', 'api/json'])
logger.debug("Request test data from {}".format(test_url))
response = request.urlopen(test_url)
return json.load(response)
def test_data(self, result_path=None):
try:
data = self.get_test_data(self.url, result_path)
except Exception as e:
logger.warning("No test data for {0}: {1}".format(
self.url,
e,
))
# If we failed to get any tests for the build, return
# meta test case 'jenkins' with status 'failed'.
data = {
"suites": [
{
"cases": [
{
"name": "jenkins",
"className": "jenkins",
"status": "failed",
"duration": 0
}
]
}
]
}
return data
def __str__(self):
string = "\n".join([
"{0}: {1}".format(*item) for item in self.build_record()
])
return string
def build_record(self):
"""Return list of pairs.
We cannot use dictionary, because columns are ordered.
"""
data = [
('number', str(self.number)),
('id', self.build_data["id"]),
('description', self.build_data["description"]),
('url', self.build_data["url"]),
]
test_data = self.test_data()
for suite in test_data['suites']:
for case in suite['cases']:
column_id = case['className'].lower().replace("_", "-")
data.append((column_id, case['status'].lower()))
return data