mirror of
https://github.com/truenas/core-build.git
synced 2026-02-21 02:18:52 +00:00
180 lines
6.7 KiB
Python
Executable File
180 lines
6.7 KiB
Python
Executable File
#+
|
|
# Copyright 2016 iXsystems, Inc.
|
|
# All rights reserved
|
|
#
|
|
# Redistribution and use in source and binary forms, with or without
|
|
# modification, are permitted providing that the following conditions
|
|
# are met:
|
|
# 1. Redistributions of source code must retain the above copyright
|
|
# notice, this list of conditions and the following disclaimer.
|
|
# 2. Redistributions in binary form must reproduce the above copyright
|
|
# notice, this list of conditions and the following disclaimer in the
|
|
# documentation and/or other materials provided with the distribution.
|
|
#
|
|
# THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
|
# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
|
# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
|
# ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
|
|
# DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
|
# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
|
# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
|
# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
|
|
# STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
|
|
# IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
|
# POSSIBILITY OF SUCH DAMAGE.
|
|
#
|
|
|
|
import os
|
|
import json
|
|
import time
|
|
import argparse
|
|
import shutil
|
|
import subprocess
|
|
from utils import e, sh, objdir, info
|
|
from xml.etree.ElementTree import Element, SubElement, tostring, parse
|
|
from distutils.core import run_setup
|
|
from xml.dom import minidom
|
|
|
|
|
|
EXCLUDES = ['os', 'objs', 'ports', 'release', 'release.build.log', 'repo-manifest']
|
|
|
|
|
|
venvdir = objdir('tests/venv')
|
|
output_root = objdir('test-output')
|
|
|
|
|
|
class Main(object):
|
|
def __init__(self):
|
|
self.test_suites = []
|
|
self.output_path = None
|
|
self.excluded = ['os', 'objs', 'ports', 'release']
|
|
|
|
def find_tests(self):
|
|
info('Looking for test manifests in ${{BE_ROOT}}')
|
|
for dir in os.listdir(e('${BE_ROOT}')):
|
|
if dir not in self.excluded:
|
|
for root, _, files in os.walk(os.path.join(e('${BE_ROOT}'), dir)):
|
|
if os.path.split(root)[1] == 'tests' and 'MANIFEST.json' in files:
|
|
info('Found test manifest at {0}', root)
|
|
self.test_suites.append(root)
|
|
|
|
def load_manifest(self, path):
|
|
with open(os.path.join(path, 'MANIFEST.json'), 'r') as manifest_file:
|
|
return json.load(manifest_file)
|
|
|
|
def run(self):
|
|
for s in self.test_suites:
|
|
script = os.path.join(s, 'run.py')
|
|
start_time = time.time()
|
|
manifest = self.load_manifest(s)
|
|
os.chdir(s)
|
|
|
|
info("Running tests from {0}".format(s))
|
|
|
|
args = [e('${venvdir}/bin/python'), script]
|
|
test = None
|
|
try:
|
|
test = subprocess.Popen(
|
|
args,
|
|
stdout=subprocess.PIPE,
|
|
stderr=subprocess.STDOUT,
|
|
close_fds=True
|
|
)
|
|
test.wait(timeout=manifest['timeout'])
|
|
except subprocess.TimeoutExpired as err:
|
|
self.generate_suite_error(
|
|
os.path.join(s, 'results.xml'),
|
|
manifest['name'],
|
|
time.time() - start_time,
|
|
'Test timeout reached',
|
|
err
|
|
)
|
|
except subprocess.SubprocessError as err:
|
|
self.generate_suite_error(
|
|
os.path.join(s, 'results.xml'),
|
|
manifest['name'],
|
|
time.time() - start_time,
|
|
'Test could not be started',
|
|
err
|
|
)
|
|
|
|
out, err = test.communicate()
|
|
|
|
if test and test.returncode:
|
|
self.generate_suite_error(
|
|
os.path.join(s, 'results.xml'),
|
|
manifest['name'],
|
|
time.time() - start_time,
|
|
'Test process has returned an error',
|
|
out
|
|
)
|
|
|
|
info("{0} error:".format(script))
|
|
print(out.decode('utf-8'))
|
|
|
|
def aggregate_results(self):
|
|
sh('mkdir -p ${output_root}')
|
|
for s in self.test_suites:
|
|
manifest = self.load_manifest(s)
|
|
try:
|
|
shutil.move(
|
|
os.path.join(s, 'results.xml'),
|
|
os.path.join(output_root, '{}-results.xml'.format(manifest['name']))
|
|
)
|
|
except FileNotFoundError as e:
|
|
self.generate_suite_error(
|
|
os.path.join(output_root, '{}-results.xml'.format(manifest['name'])),
|
|
manifest['name'],
|
|
0,
|
|
'Results file not found',
|
|
e
|
|
)
|
|
|
|
results = Element('testsuites')
|
|
for r in os.listdir(output_root):
|
|
if r.endswith('results.xml'):
|
|
single_result = parse(os.path.join(output_root, r))
|
|
results.append(single_result.getroot())
|
|
|
|
with open(os.path.join(output_root, 'aggregated_results.xml'), 'w') as output_file:
|
|
output_file.write(self.print_xml(results))
|
|
|
|
def generate_suite_error(self, out_path, name, test_time, text, err):
|
|
top = Element('testsuite', errors="1", failures="0", name=name, skipped="0", tests='0', time=str(test_time))
|
|
case = SubElement(top, 'testcase', classname="UNDEFINED", name="UNDEFINED", time=str(test_time))
|
|
error = SubElement(case, 'error', message=text)
|
|
error.text = str(err)
|
|
SubElement(case, 'system-err')
|
|
with open(out_path, 'w') as output_file:
|
|
output_file.write(self.print_xml(top))
|
|
|
|
def print_xml(self, elem):
|
|
rough_string = tostring(elem, 'utf-8')
|
|
reparsed = minidom.parseString(rough_string)
|
|
return reparsed.toprettyxml(indent=" ")
|
|
|
|
def main(self):
|
|
parser = argparse.ArgumentParser()
|
|
parser.add_argument('-a', metavar='ADDRESS', required=True, help='FreeNAS box address')
|
|
parser.add_argument('-u', metavar='USERNAME', required=True, help='Username')
|
|
parser.add_argument('-p', metavar='PASSWORD', required=True, help='Password')
|
|
args = parser.parse_args()
|
|
|
|
os.environ['TEST_HOST'] = args.a
|
|
os.environ['TEST_USERNAME'] = args.u
|
|
os.environ['TEST_PASSWORD'] = args.p
|
|
os.environ['TEST_XML'] = 'yes'
|
|
|
|
print('Test VM address: {0}'.format(args.a))
|
|
print('Test VM username: {0}'.format(args.u))
|
|
print('Test VM password: {0}'.format(args.p))
|
|
|
|
self.find_tests()
|
|
self.run()
|
|
self.aggregate_results()
|
|
|
|
|
|
if __name__ == '__main__':
|
|
m = Main()
|
|
m.main()
|