d1d3ea7c19
For some reason, when Tobiko retries many times ssh connection and logs a lot of data in the log file, pytest may fail with "Too many open files" exception raised. To avoid that lets try to configure soft ulimit for opened files to be as high as possible (same as hard limit). Change-Id: I6fb8977d7909798a5ab6be499044cc74ac34dfa2
205 lines
5.5 KiB
Python
Executable File
205 lines
5.5 KiB
Python
Executable File
#!/usr/bin/env python3
|
|
# Copyright 2018 Red Hat
|
|
#
|
|
# 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 absolute_import
|
|
|
|
import os
|
|
import psutil
|
|
import resource
|
|
import signal
|
|
import sys
|
|
import subprocess
|
|
|
|
|
|
TOP_DIR = os.path.dirname(os.path.dirname(__file__))
|
|
if TOP_DIR not in sys.path:
|
|
sys.path.insert(0, TOP_DIR)
|
|
|
|
from tools import common # noqa
|
|
|
|
LOG = common.get_logger(__name__)
|
|
|
|
# Root tests dir
|
|
TEST_PATH = common.normalize_path(
|
|
os.environ.get('TOBIKO_TEST_PATH') or
|
|
os.environ.get('OS_TEST_PATH') or
|
|
os.path.join(TOP_DIR, 'tobiko', 'tests', 'unit'))
|
|
|
|
# Output dirs
|
|
REPORT_DIR = common.normalize_path(
|
|
os.environ.get('TOBIKO_REPORT_DIR') or
|
|
os.environ.get('TOX_REPORT_DIR') or
|
|
os.getcwd())
|
|
|
|
REPORT_NAME = (
|
|
os.environ.get('TOBIKO_REPORT_NAME') or
|
|
os.environ.get('TOX_REPORT_NAME') or
|
|
'tobiko_results')
|
|
|
|
REPORT_PREFIX = os.path.join(REPORT_DIR, REPORT_NAME)
|
|
|
|
REPORT_LOG = (
|
|
os.environ.get('TOBIKO_REPORT_LOG') or
|
|
os.environ.get('TOX_REPORT_LOG') or
|
|
REPORT_PREFIX + '.log')
|
|
|
|
REPORT_HTML = (
|
|
os.environ.get('TOBIKO_REPORT_HTML') or
|
|
os.environ.get('TOX_REPORT_HTML') or
|
|
REPORT_PREFIX + '.html')
|
|
|
|
REPORT_XML = (
|
|
os.environ.get('TOBIKO_REPORT_XML') or
|
|
os.environ.get('TOX_REPORT_XML') or
|
|
REPORT_PREFIX + '.xml')
|
|
|
|
NUM_PROCESSES = (
|
|
os.environ.get('TOBIKO_NUM_PROCESSES') or
|
|
os.environ.get('TOX_NUM_PROCESSES') or
|
|
'auto')
|
|
|
|
RUN_TESTS_TIMEOUT = float(
|
|
os.environ.get('TOBIKO_RUN_TESTS_TIMEOUT') or
|
|
os.environ.get('TOX_RUN_TESTS_TIMEOUT') or
|
|
0.)
|
|
|
|
RERUNS = int(
|
|
os.environ.get('TOBIKO_RERUNS') or
|
|
os.environ.get('TOX_RERUNS') or
|
|
0)
|
|
|
|
RERUNS_DELAY = int(
|
|
os.environ.get('TOBIKO_RERUNS_DELAY') or
|
|
os.environ.get('TOX_RERUNS_DELAY') or
|
|
5)
|
|
|
|
COVER = (
|
|
os.environ.get('TOBIKO_COVER') or
|
|
os.environ.get('TOX_COVER') or
|
|
'false') in ['1', 'yes', 'true']
|
|
|
|
|
|
def main():
|
|
common.setup_logging()
|
|
try:
|
|
succeeded = run_tests()
|
|
if succeeded:
|
|
LOG.info('SUCCEEDED')
|
|
sys.exit(0)
|
|
else:
|
|
LOG.info('FAILED')
|
|
sys.exit(1)
|
|
|
|
except Exception:
|
|
LOG.exception('ERROR')
|
|
sys.exit(2)
|
|
|
|
|
|
def run_tests():
|
|
setup_ulimits()
|
|
setup_timeout()
|
|
cleanup_report_dir()
|
|
log_environ()
|
|
|
|
succeeded = True
|
|
try:
|
|
run_test_cases()
|
|
except (subprocess.CalledProcessError,
|
|
subprocess.TimeoutExpired,
|
|
ProcessLookupError) as ex:
|
|
LOG.error(f"Error while running test cases.\n{ex}")
|
|
succeeded = False
|
|
|
|
return succeeded
|
|
|
|
|
|
def setup_ulimits():
|
|
try:
|
|
hard_nofile_limit = resource.getrlimit(resource.RLIMIT_NOFILE)[1]
|
|
resource.setrlimit(
|
|
resource.RLIMIT_NOFILE,
|
|
(hard_nofile_limit, hard_nofile_limit))
|
|
except ValueError:
|
|
pass
|
|
|
|
|
|
def setup_timeout():
|
|
|
|
if RUN_TESTS_TIMEOUT > 0.:
|
|
|
|
def handle_timeout(_signum, _frame):
|
|
LOG.error(
|
|
f"run_tests.py timeout out after {RUN_TESTS_TIMEOUT} "
|
|
"seconds")
|
|
terminate_childs()
|
|
raise subprocess.TimeoutExpired("run_tests.py",
|
|
RUN_TESTS_TIMEOUT)
|
|
|
|
signal.setitimer(signal.ITIMER_REAL, RUN_TESTS_TIMEOUT)
|
|
signal.signal(signal.SIGALRM, handle_timeout)
|
|
LOG.debug(f'Run tests timeout set as {RUN_TESTS_TIMEOUT} seconds')
|
|
|
|
|
|
def terminate_childs():
|
|
current_process = psutil.Process()
|
|
children = current_process.children(recursive=False)
|
|
for child in children:
|
|
LOG.debug(f"Interrupt child process execution (pid={child.pid})")
|
|
os.kill(child.pid, signal.SIGINT)
|
|
for child in children:
|
|
LOG.debug("Wait for top-child process termination "
|
|
f"(pid={child.pid})...")
|
|
os.waitpid(child.pid, 0)
|
|
|
|
|
|
def cleanup_report_dir():
|
|
for report_file in [REPORT_LOG, REPORT_HTML, REPORT_XML]:
|
|
if not common.make_dir(os.path.dirname(report_file)):
|
|
common.remove_file(report_file)
|
|
|
|
|
|
def log_environ():
|
|
common.execute('env | sort >> "{log_file}"',
|
|
log_file=REPORT_LOG,
|
|
capture_stdout=False)
|
|
|
|
|
|
def run_test_cases():
|
|
xdist_options = ''
|
|
if NUM_PROCESSES != '1':
|
|
xdist_options = f"--numprocesses '{NUM_PROCESSES}' --dist loadscope"
|
|
rerun_options = ''
|
|
if RERUNS:
|
|
rerun_options = f"--reruns '{RERUNS}' --reruns-delay '{RERUNS_DELAY}'"
|
|
cover_options = ''
|
|
if COVER:
|
|
cover_options = f"--cov=tobiko"
|
|
|
|
# Pass environment variables to pytest command
|
|
environ = dict(os.environ, TOBIKO_REPORT_NAME=REPORT_NAME)
|
|
common.execute("pytest -v "
|
|
f"{xdist_options} "
|
|
f"{rerun_options} "
|
|
f"{cover_options} "
|
|
f"--log-file={REPORT_LOG} "
|
|
f"--junitxml={REPORT_XML} "
|
|
f"--html={REPORT_HTML} --self-contained-html "
|
|
f"{common.get_posargs()}",
|
|
environ=environ,
|
|
capture_stdout=False)
|
|
|
|
|
|
if __name__ == '__main__':
|
|
main()
|