|
Pierre-Yves Chibon |
1e58be |
#!/bin/python3
|
|
Pierre-Yves Chibon |
1e58be |
|
|
Pierre-Yves Chibon |
d70640 |
from __future__ import print_function, unicode_literals
|
|
Pierre-Yves Chibon |
1e58be |
|
|
Pierre-Yves Chibon |
1e58be |
import argparse
|
|
Pierre-Yves Chibon |
1e58be |
import coverage
|
|
Pierre-Yves Chibon |
1e58be |
import json
|
|
Pierre-Yves Chibon |
1e58be |
import logging
|
|
Pierre-Yves Chibon |
1e58be |
import multiprocessing
|
|
Pierre-Yves Chibon |
1e58be |
import os
|
|
Pierre-Yves Chibon |
1e58be |
import shutil
|
|
Pierre-Yves Chibon |
1e58be |
import subprocess
|
|
Pierre-Yves Chibon |
1e58be |
import sys
|
|
Pierre-Yves Chibon |
1e58be |
import threading
|
|
Pierre-Yves Chibon |
1e58be |
import time
|
|
Pierre-Yves Chibon |
1e58be |
|
|
Pierre-Yves Chibon |
1e58be |
|
|
Pierre-Yves Chibon |
84e668 |
RUNNER_PY = "nosetests"
|
|
Pierre-Yves Chibon |
1e58be |
RUNNER_PY2 = "nosetests-2"
|
|
Pierre-Yves Chibon |
1e58be |
RUNNER_PY3 = "nosetests-3"
|
|
Pierre-Yves Chibon |
84e668 |
COVER_PY = "coverage"
|
|
Pierre-Yves Chibon |
1e58be |
COVER_PY2 = "coverage2"
|
|
Pierre-Yves Chibon |
1e58be |
COVER_PY3 = "coverage3"
|
|
Pierre-Yves Chibon |
1e58be |
|
|
Pierre-Yves Chibon |
1e58be |
LASTLEN = None
|
|
Pierre-Yves Chibon |
1e58be |
NUMREMAINING = None
|
|
Pierre-Yves Chibon |
1e58be |
PRINTLOCK = None
|
|
Pierre-Yves Chibon |
1e58be |
RUNNING = []
|
|
Pierre-Yves Chibon |
1e58be |
FAILED = []
|
|
Pierre-Yves Chibon |
1e58be |
NUMPROCS = multiprocessing.cpu_count() - 1
|
|
Pierre-Yves Chibon |
1e58be |
|
|
Pierre-Yves Chibon |
1e58be |
|
|
Pierre-Yves Chibon |
1e58be |
def setup_parser():
|
|
Pierre-Yves Chibon |
1e58be |
""" Set up the command line arguments supported and return the arguments
|
|
Pierre-Yves Chibon |
1e58be |
"""
|
|
Pierre-Yves Chibon |
1e58be |
|
|
Pierre-Yves Chibon |
1e58be |
parser = argparse.ArgumentParser(description="Run the Pagure tests")
|
|
Pierre-Yves Chibon |
1e58be |
parser.add_argument(
|
|
Pierre-Yves Chibon |
1e58be |
"--debug",
|
|
Pierre-Yves Chibon |
1e58be |
dest="debug",
|
|
Pierre-Yves Chibon |
1e58be |
action="store_true",
|
|
Pierre-Yves Chibon |
1e58be |
default=False,
|
|
Pierre-Yves Chibon |
1e58be |
help="Increase the level of data logged.",
|
|
Pierre-Yves Chibon |
1e58be |
)
|
|
Pierre-Yves Chibon |
1e58be |
|
|
Pierre-Yves Chibon |
1e58be |
subparsers = parser.add_subparsers(title="actions")
|
|
Pierre-Yves Chibon |
1e58be |
|
|
Pierre-Yves Chibon |
1e58be |
# RUN
|
|
Pierre-Yves Chibon |
1e58be |
parser_run = subparsers.add_parser("run", help="Run the tests")
|
|
Pierre-Yves Chibon |
1e58be |
parser_run.add_argument(
|
|
Pierre-Yves Chibon |
1e58be |
"--py2",
|
|
Pierre-Yves Chibon |
1e58be |
dest="py2",
|
|
Pierre-Yves Chibon |
1e58be |
action="store_true",
|
|
Pierre-Yves Chibon |
1e58be |
default=False,
|
|
Pierre-Yves Chibon |
1e58be |
help="Runs the tests only in python2 instead of both python2 and python3",
|
|
Pierre-Yves Chibon |
1e58be |
)
|
|
Pierre-Yves Chibon |
1e58be |
parser_run.add_argument(
|
|
Pierre-Yves Chibon |
1e58be |
"--py3",
|
|
Pierre-Yves Chibon |
1e58be |
dest="py3",
|
|
Pierre-Yves Chibon |
1e58be |
action="store_true",
|
|
Pierre-Yves Chibon |
1e58be |
default=False,
|
|
Pierre-Yves Chibon |
1e58be |
help="Runs the tests only in python3 instead of both python2 and python3",
|
|
Pierre-Yves Chibon |
1e58be |
)
|
|
Pierre-Yves Chibon |
1e58be |
parser_run.add_argument(
|
|
Pierre-Yves Chibon |
1e58be |
"--results",
|
|
Pierre-Yves Chibon |
1e58be |
default="results",
|
|
Pierre-Yves Chibon |
1e58be |
help="Specify a folder in which the results should be placed "
|
|
Pierre-Yves Chibon |
1e58be |
"(defaults to `results`)",
|
|
Pierre-Yves Chibon |
1e58be |
)
|
|
Pierre-Yves Chibon |
1e58be |
parser_run.add_argument(
|
|
Pierre-Yves Chibon |
1e58be |
"-f",
|
|
Pierre-Yves Chibon |
1e58be |
"--force",
|
|
Pierre-Yves Chibon |
1e58be |
default=False,
|
|
Pierre-Yves Chibon |
1e58be |
action="store_true",
|
|
Pierre-Yves Chibon |
1e58be |
help="Override the results and newfailed file without asking you",
|
|
Pierre-Yves Chibon |
1e58be |
)
|
|
Pierre-Yves Chibon |
1e58be |
parser_run.add_argument(
|
|
Pierre-Yves Chibon |
1e58be |
"--with-coverage",
|
|
Pierre-Yves Chibon |
1e58be |
default=False,
|
|
Pierre-Yves Chibon |
1e58be |
action="store_true",
|
|
Pierre-Yves Chibon |
1e58be |
help="Also build coverage report",
|
|
Pierre-Yves Chibon |
1e58be |
)
|
|
Pierre-Yves Chibon |
1e58be |
parser_run.add_argument(
|
|
Pierre-Yves Chibon |
1e58be |
"failed_tests",
|
|
Pierre-Yves Chibon |
1e58be |
nargs="?",
|
|
Pierre-Yves Chibon |
1e58be |
help="File containing a JSON list of the failed tests to run or "
|
|
Pierre-Yves Chibon |
1e58be |
"pointing to a test file to run.",
|
|
Pierre-Yves Chibon |
1e58be |
)
|
|
Pierre-Yves Chibon |
1e58be |
parser_run.set_defaults(func=do_run)
|
|
Pierre-Yves Chibon |
1e58be |
|
|
Pierre-Yves Chibon |
1e58be |
# RERUN
|
|
Pierre-Yves Chibon |
1e58be |
parser_run = subparsers.add_parser("rerun", help="Run failed tests")
|
|
Pierre-Yves Chibon |
1e58be |
parser_run.add_argument(
|
|
Pierre-Yves Chibon |
1e58be |
"--debug",
|
|
Pierre-Yves Chibon |
1e58be |
dest="debug",
|
|
Pierre-Yves Chibon |
1e58be |
action="store_true",
|
|
Pierre-Yves Chibon |
1e58be |
default=False,
|
|
Pierre-Yves Chibon |
1e58be |
help="Expand the level of data returned.",
|
|
Pierre-Yves Chibon |
1e58be |
)
|
|
Pierre-Yves Chibon |
1e58be |
parser_run.add_argument(
|
|
Pierre-Yves Chibon |
1e58be |
"--py2",
|
|
Pierre-Yves Chibon |
1e58be |
dest="py2",
|
|
Pierre-Yves Chibon |
1e58be |
action="store_true",
|
|
Pierre-Yves Chibon |
1e58be |
default=False,
|
|
Pierre-Yves Chibon |
1e58be |
help="Runs the tests only in python2 instead of both python2 and python3",
|
|
Pierre-Yves Chibon |
1e58be |
)
|
|
Pierre-Yves Chibon |
1e58be |
parser_run.add_argument(
|
|
Pierre-Yves Chibon |
1e58be |
"--py3",
|
|
Pierre-Yves Chibon |
1e58be |
dest="py3",
|
|
Pierre-Yves Chibon |
1e58be |
action="store_true",
|
|
Pierre-Yves Chibon |
1e58be |
default=False,
|
|
Pierre-Yves Chibon |
1e58be |
help="Runs the tests only in python3 instead of both python2 and python3",
|
|
Pierre-Yves Chibon |
1e58be |
)
|
|
Pierre-Yves Chibon |
1e58be |
parser_run.add_argument(
|
|
Pierre-Yves Chibon |
1e58be |
"--results",
|
|
Pierre-Yves Chibon |
1e58be |
default="results",
|
|
Pierre-Yves Chibon |
1e58be |
help="Specify a folder in which the results should be placed "
|
|
Pierre-Yves Chibon |
1e58be |
"(defaults to `results`)",
|
|
Pierre-Yves Chibon |
1e58be |
)
|
|
Pierre-Yves Chibon |
1e58be |
parser_run.add_argument(
|
|
Pierre-Yves Chibon |
1e58be |
"--with-coverage",
|
|
Pierre-Yves Chibon |
1e58be |
default=False,
|
|
Pierre-Yves Chibon |
1e58be |
action="store_true",
|
|
Pierre-Yves Chibon |
1e58be |
help="Also build coverage report",
|
|
Pierre-Yves Chibon |
1e58be |
)
|
|
Pierre-Yves Chibon |
1e58be |
parser_run.set_defaults(func=do_rerun)
|
|
Pierre-Yves Chibon |
1e58be |
|
|
Pierre-Yves Chibon |
1e58be |
# LIST
|
|
Pierre-Yves Chibon |
1e58be |
parser_run = subparsers.add_parser("list", help="List failed tests")
|
|
Pierre-Yves Chibon |
1e58be |
parser_run.add_argument(
|
|
Pierre-Yves Chibon |
1e58be |
"--results",
|
|
Pierre-Yves Chibon |
1e58be |
default="results",
|
|
Pierre-Yves Chibon |
1e58be |
help="Specify a folder in which the results should be placed "
|
|
Pierre-Yves Chibon |
1e58be |
"(defaults to `results`)",
|
|
Pierre-Yves Chibon |
1e58be |
)
|
|
Pierre-Yves Chibon |
1e58be |
parser_run.add_argument(
|
|
Pierre-Yves Chibon |
1e58be |
"--show",
|
|
Pierre-Yves Chibon |
1e58be |
default=False,
|
|
Pierre-Yves Chibon |
1e58be |
action="store_true",
|
|
Pierre-Yves Chibon |
1e58be |
help="Show the error files using `less`",
|
|
Pierre-Yves Chibon |
1e58be |
)
|
|
Pierre-Yves Chibon |
1e58be |
parser_run.add_argument(
|
|
Pierre-Yves Chibon |
1e58be |
"-n", default=None, nargs="?", type=int,
|
|
Pierre-Yves Chibon |
1e58be |
help="Number of failed test to show",
|
|
Pierre-Yves Chibon |
1e58be |
)
|
|
Pierre-Yves Chibon |
1e58be |
parser_run.set_defaults(func=do_list)
|
|
Pierre-Yves Chibon |
1e58be |
|
|
Pierre-Yves Chibon |
1e58be |
# SHOW-COVERAGE
|
|
Pierre-Yves Chibon |
1e58be |
parser_run = subparsers.add_parser(
|
|
Pierre-Yves Chibon |
1e58be |
"show-coverage",
|
|
Pierre-Yves Chibon |
1e58be |
help="Shows the coverage report from the data in the results folder")
|
|
Pierre-Yves Chibon |
1e58be |
parser_run.add_argument(
|
|
Pierre-Yves Chibon |
1e58be |
"--debug",
|
|
Pierre-Yves Chibon |
1e58be |
dest="debug",
|
|
Pierre-Yves Chibon |
1e58be |
action="store_true",
|
|
Pierre-Yves Chibon |
1e58be |
default=False,
|
|
Pierre-Yves Chibon |
1e58be |
help="Expand the level of data returned.",
|
|
Pierre-Yves Chibon |
1e58be |
)
|
|
Pierre-Yves Chibon |
1e58be |
parser_run.add_argument(
|
|
Pierre-Yves Chibon |
1e58be |
"--py2",
|
|
Pierre-Yves Chibon |
1e58be |
dest="py2",
|
|
Pierre-Yves Chibon |
1e58be |
action="store_true",
|
|
Pierre-Yves Chibon |
1e58be |
default=False,
|
|
Pierre-Yves Chibon |
1e58be |
help="Runs the tests only in python2 instead of both python2 and python3",
|
|
Pierre-Yves Chibon |
1e58be |
)
|
|
Pierre-Yves Chibon |
1e58be |
parser_run.add_argument(
|
|
Pierre-Yves Chibon |
1e58be |
"--py3",
|
|
Pierre-Yves Chibon |
1e58be |
dest="py3",
|
|
Pierre-Yves Chibon |
1e58be |
action="store_true",
|
|
Pierre-Yves Chibon |
1e58be |
default=False,
|
|
Pierre-Yves Chibon |
1e58be |
help="Runs the tests only in python3 instead of both python2 and python3",
|
|
Pierre-Yves Chibon |
1e58be |
)
|
|
Pierre-Yves Chibon |
1e58be |
parser_run.add_argument(
|
|
Pierre-Yves Chibon |
1e58be |
"--results",
|
|
Pierre-Yves Chibon |
1e58be |
default="results",
|
|
Pierre-Yves Chibon |
1e58be |
help="Specify a folder in which the results should be placed "
|
|
Pierre-Yves Chibon |
1e58be |
"(defaults to `results`)",
|
|
Pierre-Yves Chibon |
1e58be |
)
|
|
Pierre-Yves Chibon |
1e58be |
parser_run.set_defaults(func=do_show_coverage)
|
|
Pierre-Yves Chibon |
1e58be |
|
|
Pierre-Yves Chibon |
1e58be |
return parser
|
|
Pierre-Yves Chibon |
1e58be |
|
|
Pierre-Yves Chibon |
1e58be |
|
|
Pierre-Yves Chibon |
1e58be |
def clean_line():
|
|
Pierre-Yves Chibon |
1e58be |
global LASTLEN
|
|
Pierre-Yves Chibon |
1e58be |
|
|
Pierre-Yves Chibon |
1e58be |
with PRINTLOCK:
|
|
Pierre-Yves Chibon |
1e58be |
if LASTLEN is not None:
|
|
Pierre-Yves Chibon |
1e58be |
print(" " * LASTLEN, end="\r")
|
|
Pierre-Yves Chibon |
1e58be |
LASTLEN = None
|
|
Pierre-Yves Chibon |
1e58be |
|
|
Pierre-Yves Chibon |
1e58be |
|
|
Pierre-Yves Chibon |
1e58be |
def print_running():
|
|
Pierre-Yves Chibon |
1e58be |
global LASTLEN
|
|
Pierre-Yves Chibon |
1e58be |
|
|
Pierre-Yves Chibon |
1e58be |
with PRINTLOCK:
|
|
Pierre-Yves Chibon |
1e58be |
msg = "Running %d suites: %d remaining, %d failed" % (
|
|
Pierre-Yves Chibon |
1e58be |
len(RUNNING),
|
|
Pierre-Yves Chibon |
1e58be |
NUMREMAINING,
|
|
Pierre-Yves Chibon |
1e58be |
len(FAILED),
|
|
Pierre-Yves Chibon |
1e58be |
)
|
|
Pierre-Yves Chibon |
1e58be |
LASTLEN = len(msg)
|
|
Pierre-Yves Chibon |
1e58be |
print(msg, end="\r")
|
|
Pierre-Yves Chibon |
1e58be |
|
|
Pierre-Yves Chibon |
1e58be |
|
|
Pierre-Yves Chibon |
1e58be |
def add_running(suite):
|
|
Pierre-Yves Chibon |
1e58be |
global NUMREMAINING
|
|
Pierre-Yves Chibon |
1e58be |
|
|
Pierre-Yves Chibon |
1e58be |
with PRINTLOCK:
|
|
Pierre-Yves Chibon |
1e58be |
NUMREMAINING -= 1
|
|
Pierre-Yves Chibon |
1e58be |
RUNNING.append(suite)
|
|
Pierre-Yves Chibon |
1e58be |
clean_line()
|
|
Pierre-Yves Chibon |
1e58be |
print_running()
|
|
Pierre-Yves Chibon |
1e58be |
|
|
Pierre-Yves Chibon |
1e58be |
|
|
Pierre-Yves Chibon |
1e58be |
def remove_running(suite, failed):
|
|
Pierre-Yves Chibon |
1e58be |
with PRINTLOCK:
|
|
Pierre-Yves Chibon |
1e58be |
RUNNING.remove(suite)
|
|
Pierre-Yves Chibon |
1e58be |
clean_line()
|
|
Pierre-Yves Chibon |
1e58be |
status = 'passed'
|
|
Pierre-Yves Chibon |
1e58be |
if failed:
|
|
Pierre-Yves Chibon |
1e58be |
status = 'FAILED'
|
|
Pierre-Yves Chibon |
1e58be |
print("Test suite %s: %s" % (status, suite))
|
|
Pierre-Yves Chibon |
1e58be |
print_running()
|
|
Pierre-Yves Chibon |
1e58be |
|
|
Pierre-Yves Chibon |
1e58be |
|
|
Pierre-Yves Chibon |
1e58be |
class WorkerThread(threading.Thread):
|
|
Pierre-Yves Chibon |
1e58be |
def __init__(self, sem, pyver, suite, results, with_cover):
|
|
Pierre-Yves Chibon |
05cd04 |
name = "py%s-%s" % (pyver, suite)
|
|
Pierre-Yves Chibon |
1e58be |
super(WorkerThread, self).__init__(name="worker-%s" % name)
|
|
Pierre-Yves Chibon |
1e58be |
self.name = name
|
|
Pierre-Yves Chibon |
1e58be |
self.sem = sem
|
|
Pierre-Yves Chibon |
1e58be |
self.pyver = pyver
|
|
Pierre-Yves Chibon |
1e58be |
self.suite = suite
|
|
Pierre-Yves Chibon |
1e58be |
self.failed = None
|
|
Pierre-Yves Chibon |
1e58be |
self.results = results
|
|
Pierre-Yves Chibon |
1e58be |
self.with_cover = with_cover
|
|
Pierre-Yves Chibon |
1e58be |
|
|
Pierre-Yves Chibon |
1e58be |
def run(self):
|
|
Pierre-Yves Chibon |
1e58be |
with self.sem:
|
|
Pierre-Yves Chibon |
1e58be |
add_running(self.name)
|
|
Pierre-Yves Chibon |
1e58be |
with open(os.path.join(self.results, self.name), "w") as resfile:
|
|
Pierre-Yves Chibon |
1e58be |
if self.pyver == 2:
|
|
Pierre-Yves Chibon |
1e58be |
runner = RUNNER_PY2
|
|
Pierre-Yves Chibon |
1e58be |
elif self.pyver == 3:
|
|
Pierre-Yves Chibon |
1e58be |
runner = RUNNER_PY3
|
|
Pierre-Yves Chibon |
84e668 |
else:
|
|
Pierre-Yves Chibon |
84e668 |
runner = RUNNER_PY
|
|
Pierre-Yves Chibon |
1e58be |
cmd = [runner, "-v", "tests.%s" % self.suite]
|
|
Pierre-Yves Chibon |
1e58be |
if self.with_cover:
|
|
Pierre-Yves Chibon |
1e58be |
cmd.append("--with-cover")
|
|
Pierre-Yves Chibon |
ac5025 |
|
|
Pierre-Yves Chibon |
ac5025 |
env = os.environ.copy()
|
|
Pierre-Yves Chibon |
ac5025 |
env.update({
|
|
Pierre-Yves Chibon |
1e58be |
"PAGURE_CONFIG": "../tests/test_config",
|
|
Pierre-Yves Chibon |
1e58be |
"COVERAGE_FILE": os.path.join(
|
|
Pierre-Yves Chibon |
1e58be |
self.results, "%s.coverage" % self.name
|
|
Pierre-Yves Chibon |
1e58be |
),
|
|
Pierre-Yves Chibon |
1e58be |
"LANG": "en_US.UTF-8",
|
|
Pierre-Yves Chibon |
ac5025 |
})
|
|
Pierre-Yves Chibon |
1e58be |
proc = subprocess.Popen(
|
|
Pierre-Yves Chibon |
b75122 |
cmd, cwd=".", stdout=resfile, stderr=subprocess.STDOUT, env=env
|
|
Pierre-Yves Chibon |
1e58be |
)
|
|
Pierre-Yves Chibon |
1e58be |
res = proc.wait()
|
|
Pierre-Yves Chibon |
1e58be |
if res == 0:
|
|
Pierre-Yves Chibon |
1e58be |
self.failed = False
|
|
Pierre-Yves Chibon |
1e58be |
else:
|
|
Pierre-Yves Chibon |
1e58be |
self.failed = True
|
|
Pierre-Yves Chibon |
1e58be |
if not self.failed is not True:
|
|
Pierre-Yves Chibon |
1e58be |
with PRINTLOCK:
|
|
Pierre-Yves Chibon |
1e58be |
FAILED.append(self.name)
|
|
Pierre-Yves Chibon |
1e58be |
remove_running(self.name, self.failed)
|
|
Pierre-Yves Chibon |
1e58be |
|
|
Pierre-Yves Chibon |
1e58be |
|
|
Pierre-Yves Chibon |
1e58be |
def do_run(args):
|
|
Pierre-Yves Chibon |
1e58be |
""" Performs some checks and runs the tests.
|
|
Pierre-Yves Chibon |
1e58be |
"""
|
|
Pierre-Yves Chibon |
1e58be |
|
|
Pierre-Yves Chibon |
1e58be |
# Some pre-flight checks
|
|
Pierre-Yves Chibon |
b75122 |
if not os.path.exists("./.git") or not os.path.exists("./nosetests3"):
|
|
Pierre-Yves Chibon |
1e58be |
print("Please run from a single level into the Pagure codebase")
|
|
Pierre-Yves Chibon |
1e58be |
return 1
|
|
Pierre-Yves Chibon |
1e58be |
|
|
Pierre-Yves Chibon |
1e58be |
if os.path.exists(args.results):
|
|
Pierre-Yves Chibon |
1e58be |
if not args.force:
|
|
Pierre-Yves Chibon |
1e58be |
print(
|
|
Pierre-Yves Chibon |
1e58be |
"Results folder exists, please remove it so we do not clobber"
|
|
Pierre-Yves Chibon |
1e58be |
" or use --force"
|
|
Pierre-Yves Chibon |
1e58be |
)
|
|
Pierre-Yves Chibon |
1e58be |
return 1
|
|
Pierre-Yves Chibon |
1e58be |
else:
|
|
Pierre-Yves Chibon |
1e58be |
shutil.rmtree(args.results)
|
|
Pierre-Yves Chibon |
1e58be |
|
|
Pierre-Yves Chibon |
1e58be |
os.mkdir(args.results)
|
|
Pierre-Yves Chibon |
1e58be |
|
|
Pierre-Yves Chibon |
1e58be |
print("Pre-flight checks passed")
|
|
Pierre-Yves Chibon |
1e58be |
|
|
Pierre-Yves Chibon |
1e58be |
suites = []
|
|
Pierre-Yves Chibon |
1e58be |
|
|
Pierre-Yves Chibon |
1e58be |
if args.failed_tests:
|
|
Pierre-Yves Chibon |
1e58be |
here = os.path.join(os.path.dirname(os.path.abspath(__file__)))
|
|
Pierre-Yves Chibon |
1e58be |
failed_tests_fullpath = os.path.join(here, args.failed_tests)
|
|
Pierre-Yves Chibon |
1e58be |
if not os.path.exists(failed_tests_fullpath):
|
|
Pierre-Yves Chibon |
1e58be |
print("Could not find the specified file:%s" % failed_tests_fullpath)
|
|
Pierre-Yves Chibon |
1e58be |
return 1
|
|
Pierre-Yves Chibon |
1e58be |
print("Loading failed tests")
|
|
Pierre-Yves Chibon |
1e58be |
try:
|
|
Pierre-Yves Chibon |
1e58be |
with open(failed_tests_fullpath, "r") as ffile:
|
|
Pierre-Yves Chibon |
1e58be |
suites = json.loads(ffile.read())
|
|
Pierre-Yves Chibon |
1e58be |
except json.decoder.JSONDecodeError:
|
|
Pierre-Yves Chibon |
1e58be |
bname = os.path.basename(args.failed_tests)
|
|
Pierre-Yves Chibon |
1e58be |
if bname.endswith(".py") and bname.startswith("test_"):
|
|
Pierre-Yves Chibon |
1e58be |
suites.append(bname.replace(".py", ""))
|
|
Pierre-Yves Chibon |
1e58be |
|
|
Pierre-Yves Chibon |
1e58be |
if len(suites) == 0:
|
|
Pierre-Yves Chibon |
1e58be |
print("Loading all tests")
|
|
Pierre-Yves Chibon |
b75122 |
for fname in os.listdir("./tests"):
|
|
Pierre-Yves Chibon |
1e58be |
if not fname.endswith(".py"):
|
|
Pierre-Yves Chibon |
1e58be |
continue
|
|
Pierre-Yves Chibon |
1e58be |
if not fname.startswith("test_"):
|
|
Pierre-Yves Chibon |
1e58be |
continue
|
|
Pierre-Yves Chibon |
1e58be |
suites.append(fname.replace(".py", ""))
|
|
Pierre-Yves Chibon |
1e58be |
|
|
Pierre-Yves Chibon |
1e58be |
_run_test_suites(args, suites)
|
|
Pierre-Yves Chibon |
1e58be |
|
|
Pierre-Yves Chibon |
1e58be |
|
|
Pierre-Yves Chibon |
1e58be |
def do_rerun(args):
|
|
Pierre-Yves Chibon |
1e58be |
""" Re-run tests that failed the last/specified run.
|
|
Pierre-Yves Chibon |
1e58be |
"""
|
|
Pierre-Yves Chibon |
1e58be |
|
|
Pierre-Yves Chibon |
1e58be |
# Some pre-flight checks
|
|
Pierre-Yves Chibon |
b75122 |
if not os.path.exists("./.git") or not os.path.exists("./pagure"):
|
|
Pierre-Yves Chibon |
1e58be |
print("Please run from a single level into the Pagure codebase")
|
|
Pierre-Yves Chibon |
1e58be |
return 1
|
|
Pierre-Yves Chibon |
1e58be |
|
|
Pierre-Yves Chibon |
1e58be |
if not os.path.exists(args.results):
|
|
Pierre-Yves Chibon |
1e58be |
print("Could not find an existing results folder at: %s" % args.results)
|
|
Pierre-Yves Chibon |
1e58be |
return 1
|
|
Pierre-Yves Chibon |
1e58be |
|
|
Pierre-Yves Chibon |
1e58be |
if not os.path.exists(os.path.join(args.results, "newfailed")):
|
|
Pierre-Yves Chibon |
1e58be |
print(
|
|
Pierre-Yves Chibon |
1e58be |
"Could not find an failed tests in the results folder at: %s" % args.results
|
|
Pierre-Yves Chibon |
1e58be |
)
|
|
Pierre-Yves Chibon |
1e58be |
return 1
|
|
Pierre-Yves Chibon |
1e58be |
|
|
Pierre-Yves Chibon |
1e58be |
print("Pre-flight checks passed")
|
|
Pierre-Yves Chibon |
1e58be |
|
|
Pierre-Yves Chibon |
1e58be |
suites = []
|
|
Pierre-Yves Chibon |
1e58be |
tmp = []
|
|
Pierre-Yves Chibon |
1e58be |
|
|
Pierre-Yves Chibon |
1e58be |
print("Loading failed tests")
|
|
Pierre-Yves Chibon |
1e58be |
try:
|
|
Pierre-Yves Chibon |
1e58be |
with open(os.path.join(args.results, "newfailed"), "r") as ffile:
|
|
Pierre-Yves Chibon |
1e58be |
tmp = json.loads(ffile.read())
|
|
Pierre-Yves Chibon |
1e58be |
except json.decoder.JSONDecodeError:
|
|
Pierre-Yves Chibon |
1e58be |
print("File containing the failed tests is not JSON")
|
|
Pierre-Yves Chibon |
1e58be |
return 1
|
|
Pierre-Yves Chibon |
1e58be |
|
|
Pierre-Yves Chibon |
1e58be |
for suite in tmp:
|
|
Pierre-Yves Chibon |
1e58be |
if suite.startswith(("py2-", "py3-")):
|
|
Pierre-Yves Chibon |
1e58be |
suites.append(suite[4:])
|
|
Pierre-Yves Chibon |
1e58be |
|
|
Pierre-Yves Chibon |
1e58be |
_run_test_suites(args, set(suites))
|
|
Pierre-Yves Chibon |
1e58be |
|
|
Pierre-Yves Chibon |
1e58be |
|
|
Pierre-Yves Chibon |
84e668 |
def _get_pyvers(args):
|
|
Pierre-Yves Chibon |
84e668 |
pyvers = [2, 3]
|
|
Pierre-Yves Chibon |
84e668 |
if args.py2:
|
|
Pierre-Yves Chibon |
84e668 |
pyvers = [2,]
|
|
Pierre-Yves Chibon |
84e668 |
elif args.py3:
|
|
Pierre-Yves Chibon |
84e668 |
pyvers = [3,]
|
|
Pierre-Yves Chibon |
84e668 |
|
|
Pierre-Yves Chibon |
84e668 |
un_versioned = False
|
|
Pierre-Yves Chibon |
84e668 |
try:
|
|
Pierre-Yves Chibon |
84e668 |
subprocess.check_call(["which", RUNNER_PY])
|
|
Pierre-Yves Chibon |
84e668 |
un_versioned = True
|
|
Pierre-Yves Chibon |
84e668 |
except subprocess.CalledProcessError:
|
|
Pierre-Yves Chibon |
84e668 |
print("No %s found no unversioned runner" % RUNNER_PY)
|
|
Pierre-Yves Chibon |
84e668 |
|
|
Pierre-Yves Chibon |
84e668 |
if 2 in pyvers:
|
|
Pierre-Yves Chibon |
84e668 |
nopy2 = False
|
|
Pierre-Yves Chibon |
84e668 |
try:
|
|
Pierre-Yves Chibon |
84e668 |
subprocess.check_call(["which", RUNNER_PY2])
|
|
Pierre-Yves Chibon |
84e668 |
except subprocess.CalledProcessError:
|
|
Pierre-Yves Chibon |
84e668 |
print("No %s found, removing python 2" % RUNNER_PY2)
|
|
Pierre-Yves Chibon |
84e668 |
del pyvers[pyvers.index(2)]
|
|
Pierre-Yves Chibon |
84e668 |
|
|
Pierre-Yves Chibon |
84e668 |
if 3 in pyvers:
|
|
Pierre-Yves Chibon |
84e668 |
nopy3 = False
|
|
Pierre-Yves Chibon |
84e668 |
try:
|
|
Pierre-Yves Chibon |
84e668 |
subprocess.check_call(["which", RUNNER_PY3])
|
|
Pierre-Yves Chibon |
84e668 |
except subprocess.CalledProcessError:
|
|
Pierre-Yves Chibon |
84e668 |
print("No %s found, removing python 3" % RUNNER_PY3)
|
|
Pierre-Yves Chibon |
84e668 |
del pyvers[pyvers.index(3)]
|
|
Pierre-Yves Chibon |
84e668 |
|
|
Pierre-Yves Chibon |
84e668 |
if not pyvers and un_versioned:
|
|
Pierre-Yves Chibon |
84e668 |
pyvers = [""]
|
|
Pierre-Yves Chibon |
84e668 |
|
|
Pierre-Yves Chibon |
84e668 |
return pyvers
|
|
Pierre-Yves Chibon |
84e668 |
|
|
Pierre-Yves Chibon |
84e668 |
|
|
Pierre-Yves Chibon |
1e58be |
def _run_test_suites(args, suites):
|
|
Pierre-Yves Chibon |
1e58be |
print("Using %d processes" % NUMPROCS)
|
|
Pierre-Yves Chibon |
1e58be |
print("Start timing")
|
|
Pierre-Yves Chibon |
1e58be |
start = time.time()
|
|
Pierre-Yves Chibon |
1e58be |
|
|
Pierre-Yves Chibon |
1e58be |
global PRINTLOCK
|
|
Pierre-Yves Chibon |
1e58be |
PRINTLOCK = threading.RLock()
|
|
Pierre-Yves Chibon |
1e58be |
global NUMREMAINING
|
|
Pierre-Yves Chibon |
1e58be |
NUMREMAINING = 0
|
|
Pierre-Yves Chibon |
1e58be |
|
|
Pierre-Yves Chibon |
1e58be |
sem = threading.BoundedSemaphore(NUMPROCS)
|
|
Pierre-Yves Chibon |
1e58be |
|
|
Pierre-Yves Chibon |
1e58be |
# Create a worker per test
|
|
Pierre-Yves Chibon |
1e58be |
workers = {}
|
|
Pierre-Yves Chibon |
1e58be |
|
|
Pierre-Yves Chibon |
84e668 |
pyvers = _get_pyvers(args)
|
|
Pierre-Yves Chibon |
678713 |
|
|
Pierre-Yves Chibon |
c04da2 |
if not pyvers:
|
|
Pierre-Yves Chibon |
84e668 |
return 1
|
|
Pierre-Yves Chibon |
678713 |
|
|
Pierre-Yves Chibon |
1e58be |
for suite in suites:
|
|
Pierre-Yves Chibon |
1e58be |
for pyver in pyvers:
|
|
Pierre-Yves Chibon |
1e58be |
NUMREMAINING += 1
|
|
Pierre-Yves Chibon |
05cd04 |
workers["py%s-%s" % (pyver, suite)] = WorkerThread(
|
|
Pierre-Yves Chibon |
1e58be |
sem, pyver, suite, args.results, args.with_coverage
|
|
Pierre-Yves Chibon |
1e58be |
)
|
|
Pierre-Yves Chibon |
1e58be |
|
|
Pierre-Yves Chibon |
1e58be |
# Start the workers
|
|
Pierre-Yves Chibon |
1e58be |
print("Starting the workers")
|
|
Pierre-Yves Chibon |
1e58be |
print()
|
|
Pierre-Yves Chibon |
1e58be |
print()
|
|
Pierre-Yves Chibon |
1e58be |
for worker in workers.values():
|
|
Pierre-Yves Chibon |
1e58be |
worker.start()
|
|
Pierre-Yves Chibon |
1e58be |
|
|
Pierre-Yves Chibon |
1e58be |
# Wait for them to terminate
|
|
Pierre-Yves Chibon |
1e58be |
for worker in workers:
|
|
Pierre-Yves Chibon |
1e58be |
workers[worker].join()
|
|
Pierre-Yves Chibon |
1e58be |
print_running()
|
|
Pierre-Yves Chibon |
1e58be |
print()
|
|
Pierre-Yves Chibon |
1e58be |
print("All work done")
|
|
Pierre-Yves Chibon |
1e58be |
|
|
Pierre-Yves Chibon |
1e58be |
# Gather results
|
|
Pierre-Yves Chibon |
1e58be |
print()
|
|
Pierre-Yves Chibon |
1e58be |
print()
|
|
Pierre-Yves Chibon |
1e58be |
print("Failed tests:")
|
|
Pierre-Yves Chibon |
1e58be |
for worker in workers:
|
|
Pierre-Yves Chibon |
1e58be |
if not workers[worker].failed:
|
|
Pierre-Yves Chibon |
1e58be |
continue
|
|
Pierre-Yves Chibon |
1e58be |
print("FAILED test: %s" % (worker))
|
|
Pierre-Yves Chibon |
1e58be |
|
|
Pierre-Yves Chibon |
1e58be |
# Write failed
|
|
Pierre-Yves Chibon |
1e58be |
if FAILED:
|
|
Pierre-Yves Chibon |
1e58be |
with open(os.path.join(args.results, "newfailed"), "w") as ffile:
|
|
Pierre-Yves Chibon |
1e58be |
ffile.write(json.dumps(FAILED))
|
|
Pierre-Yves Chibon |
1e58be |
|
|
Pierre-Yves Chibon |
1e58be |
# Stats
|
|
Pierre-Yves Chibon |
1e58be |
end = time.time()
|
|
Pierre-Yves Chibon |
1e58be |
print()
|
|
Pierre-Yves Chibon |
1e58be |
print()
|
|
Pierre-Yves Chibon |
1e58be |
print(
|
|
Pierre-Yves Chibon |
1e58be |
"Ran %d tests in %f seconds, of which %d failed"
|
|
Pierre-Yves Chibon |
1e58be |
% (len(workers), (end - start), len(FAILED))
|
|
Pierre-Yves Chibon |
1e58be |
)
|
|
Pierre-Yves Chibon |
1e58be |
|
|
Pierre-Yves Chibon |
1e58be |
# Exit
|
|
Pierre-Yves Chibon |
1e58be |
if len(FAILED) == 0:
|
|
Pierre-Yves Chibon |
1e58be |
print("ALL PASSED! CONGRATULATIONS!")
|
|
Pierre-Yves Chibon |
1e58be |
else:
|
|
Pierre-Yves Chibon |
1e58be |
return 1
|
|
Pierre-Yves Chibon |
1e58be |
|
|
Pierre-Yves Chibon |
1e58be |
if args.with_coverage:
|
|
Pierre-Yves Chibon |
1e58be |
do_show_coverage(args)
|
|
Pierre-Yves Chibon |
1e58be |
|
|
Pierre-Yves Chibon |
1e58be |
return 0
|
|
Pierre-Yves Chibon |
1e58be |
|
|
Pierre-Yves Chibon |
1e58be |
|
|
Pierre-Yves Chibon |
1e58be |
def do_list(args):
|
|
Pierre-Yves Chibon |
1e58be |
""" List tests that failed the last/specified run.
|
|
Pierre-Yves Chibon |
1e58be |
"""
|
|
Pierre-Yves Chibon |
1e58be |
|
|
Pierre-Yves Chibon |
1e58be |
# Some pre-flight checks
|
|
Pierre-Yves Chibon |
b75122 |
if not os.path.exists("./.git") or not os.path.exists("./pagure"):
|
|
Pierre-Yves Chibon |
1e58be |
print("Please run from a single level into the Pagure codebase")
|
|
Pierre-Yves Chibon |
1e58be |
return 1
|
|
Pierre-Yves Chibon |
1e58be |
|
|
Pierre-Yves Chibon |
1e58be |
if not os.path.exists(args.results):
|
|
Pierre-Yves Chibon |
1e58be |
print("Could not find an existing results folder at: %s" % args.results)
|
|
Pierre-Yves Chibon |
1e58be |
return 1
|
|
Pierre-Yves Chibon |
1e58be |
|
|
Pierre-Yves Chibon |
1e58be |
if not os.path.exists(os.path.join(args.results, "newfailed")):
|
|
Pierre-Yves Chibon |
1e58be |
print(
|
|
Pierre-Yves Chibon |
1e58be |
"Could not find an failed tests in the results folder at: %s" % args.results
|
|
Pierre-Yves Chibon |
1e58be |
)
|
|
Pierre-Yves Chibon |
1e58be |
return 1
|
|
Pierre-Yves Chibon |
1e58be |
|
|
Pierre-Yves Chibon |
1e58be |
print("Pre-flight checks passed")
|
|
Pierre-Yves Chibon |
1e58be |
|
|
Pierre-Yves Chibon |
1e58be |
suites = []
|
|
Pierre-Yves Chibon |
1e58be |
tmp = []
|
|
Pierre-Yves Chibon |
1e58be |
|
|
Pierre-Yves Chibon |
1e58be |
print("Loading failed tests")
|
|
Pierre-Yves Chibon |
1e58be |
try:
|
|
Pierre-Yves Chibon |
1e58be |
with open(os.path.join(args.results, "newfailed"), "r") as ffile:
|
|
Pierre-Yves Chibon |
1e58be |
suites = json.loads(ffile.read())
|
|
Pierre-Yves Chibon |
1e58be |
except json.decoder.JSONDecodeError:
|
|
Pierre-Yves Chibon |
1e58be |
print("File containing the failed tests is not JSON")
|
|
Pierre-Yves Chibon |
1e58be |
return 1
|
|
Pierre-Yves Chibon |
1e58be |
|
|
Pierre-Yves Chibon |
1e58be |
print("Failed tests")
|
|
Pierre-Yves Chibon |
1e58be |
failed_tests = len(suites)
|
|
Pierre-Yves Chibon |
1e58be |
|
|
Pierre-Yves Chibon |
1e58be |
if args.n:
|
|
Pierre-Yves Chibon |
1e58be |
suites = suites[:args.n]
|
|
Pierre-Yves Chibon |
1e58be |
print("- " + "\n- ".join(suites))
|
|
Pierre-Yves Chibon |
1e58be |
print("Total: %s test failed" % failed_tests)
|
|
Pierre-Yves Chibon |
1e58be |
|
|
Pierre-Yves Chibon |
1e58be |
if args.show:
|
|
Pierre-Yves Chibon |
1e58be |
for suite in suites:
|
|
Pierre-Yves Chibon |
1e58be |
cmd = ["less", os.path.join(args.results, suite)]
|
|
Pierre-Yves Chibon |
1e58be |
subprocess.check_call(cmd)
|
|
Pierre-Yves Chibon |
1e58be |
|
|
Pierre-Yves Chibon |
1e58be |
|
|
Pierre-Yves Chibon |
1e58be |
def do_show_coverage(args):
|
|
Pierre-Yves Chibon |
1e58be |
print()
|
|
Pierre-Yves Chibon |
1e58be |
print("Combining coverage results...")
|
|
Pierre-Yves Chibon |
84e668 |
|
|
Pierre-Yves Chibon |
84e668 |
pyvers = _get_pyvers(args)
|
|
Pierre-Yves Chibon |
1e58be |
|
|
Pierre-Yves Chibon |
1e58be |
for pyver in pyvers:
|
|
Pierre-Yves Chibon |
1e58be |
coverfiles = []
|
|
Pierre-Yves Chibon |
1e58be |
for fname in os.listdir(args.results):
|
|
Pierre-Yves Chibon |
05cd04 |
if fname.endswith(".coverage") and fname.startswith("py%s-" % pyver):
|
|
Pierre-Yves Chibon |
1e58be |
coverfiles.append(os.path.join(args.results, fname))
|
|
Pierre-Yves Chibon |
1e58be |
|
|
Pierre-Yves Chibon |
1e58be |
cover = None
|
|
Pierre-Yves Chibon |
1e58be |
if pyver == 2:
|
|
Pierre-Yves Chibon |
1e58be |
cover = COVER_PY2
|
|
Pierre-Yves Chibon |
1e58be |
elif pyver == 3:
|
|
Pierre-Yves Chibon |
1e58be |
cover = COVER_PY3
|
|
Pierre-Yves Chibon |
84e668 |
else:
|
|
Pierre-Yves Chibon |
84e668 |
cover = COVER_PY
|
|
Pierre-Yves Chibon |
1e58be |
|
|
Pierre-Yves Chibon |
1e58be |
env = {"COVERAGE_FILE": os.path.join(args.results, "combined.coverage")}
|
|
Pierre-Yves Chibon |
1e58be |
cmd = [cover, "combine"] + coverfiles
|
|
Pierre-Yves Chibon |
1e58be |
subprocess.check_call(cmd, env=env)
|
|
Pierre-Yves Chibon |
1e58be |
print()
|
|
Pierre-Yves Chibon |
05cd04 |
print("Python %s coverage: " % pyver)
|
|
Pierre-Yves Chibon |
b75122 |
cmd = [cover, "report", "--include=./pagure/*"]
|
|
Pierre-Yves Chibon |
1e58be |
subprocess.check_call(cmd, env=env)
|
|
Pierre-Yves Chibon |
1e58be |
|
|
Pierre-Yves Chibon |
1e58be |
|
|
Pierre-Yves Chibon |
1e58be |
def main():
|
|
Pierre-Yves Chibon |
1e58be |
""" Main function """
|
|
Pierre-Yves Chibon |
1e58be |
# Set up parser for global args
|
|
Pierre-Yves Chibon |
1e58be |
parser = setup_parser()
|
|
Pierre-Yves Chibon |
1e58be |
# Parse the commandline
|
|
Pierre-Yves Chibon |
1e58be |
try:
|
|
Pierre-Yves Chibon |
1e58be |
arg = parser.parse_args()
|
|
Pierre-Yves Chibon |
1e58be |
except argparse.ArgumentTypeError as err:
|
|
Pierre-Yves Chibon |
1e58be |
print("\nError: {0}".format(err))
|
|
Pierre-Yves Chibon |
1e58be |
return 2
|
|
Pierre-Yves Chibon |
1e58be |
|
|
Pierre-Yves Chibon |
1e58be |
logging.basicConfig()
|
|
Pierre-Yves Chibon |
1e58be |
if arg.debug:
|
|
Pierre-Yves Chibon |
1e58be |
LOG.setLevel(logging.DEBUG)
|
|
Pierre-Yves Chibon |
1e58be |
|
|
Pierre-Yves Chibon |
1e58be |
if "func" not in arg:
|
|
Pierre-Yves Chibon |
1e58be |
parser.print_help()
|
|
Pierre-Yves Chibon |
1e58be |
return 1
|
|
Pierre-Yves Chibon |
1e58be |
|
|
Pierre-Yves Chibon |
1e58be |
arg.results = os.path.abspath(arg.results)
|
|
Pierre-Yves Chibon |
1e58be |
|
|
Pierre-Yves Chibon |
1e58be |
return_code = 0
|
|
Pierre-Yves Chibon |
1e58be |
|
|
Pierre-Yves Chibon |
1e58be |
try:
|
|
Pierre-Yves Chibon |
1e58be |
return_code = arg.func(arg)
|
|
Pierre-Yves Chibon |
1e58be |
except KeyboardInterrupt:
|
|
Pierre-Yves Chibon |
1e58be |
print("\nInterrupted by user.")
|
|
Pierre-Yves Chibon |
1e58be |
return_code = 1
|
|
Pierre-Yves Chibon |
1e58be |
except Exception as err:
|
|
Pierre-Yves Chibon |
1e58be |
print("Error: {0}".format(err))
|
|
Pierre-Yves Chibon |
1e58be |
logging.exception("Generic error caught:")
|
|
Pierre-Yves Chibon |
1e58be |
return_code = 5
|
|
Pierre-Yves Chibon |
1e58be |
|
|
Pierre-Yves Chibon |
1e58be |
return return_code
|
|
Pierre-Yves Chibon |
1e58be |
|
|
Pierre-Yves Chibon |
1e58be |
|
|
Pierre-Yves Chibon |
1e58be |
if __name__ == "__main__":
|
|
Pierre-Yves Chibon |
1e58be |
sys.exit(main())
|