import re
import sys
import pathlib
import subprocess
from configparser import ConfigParser
CONFIG_PATH: pathlib.Path = pathlib.Path(__file__).parent.parent.parent / "setup.cfg"
STD_OUT_LOG = pathlib.Path("./zdevelop/tests/_reports/test_stdout.txt")
STD_ERR_LOG = pathlib.Path("./zdevelop/tests/_reports/test_stderr.txt")
FULL_LOG = pathlib.Path("./zdevelop/tests/_reports/test_full.txt")
COVERAGE_LOG = pathlib.Path("./zdevelop/tests/_reports/coverage.out")
TEST_REPORT = pathlib.Path("./zdevelop/tests/_reports/test_results.html")
COVERAGE_REPORT = pathlib.Path("./zdevelop/tests/_reports/coverage/index.html")
COVERAGE_REGEX = re.compile(r"total:\s+\(statements\)\s+(\d+\.\d)%")
def load_cfg() -> ConfigParser:
config = ConfigParser()
config.read(CONFIG_PATH)
return config
def run_test() -> None:
config = load_cfg()
coverage_required = config.getfloat("testing", "coverage_required") * 100
test_package = config.get("testing", "test_package", fallback="./...")
exclude_string = config.get("testing", "exclude", fallback="")
exclude_list = [e for e in exclude_string.split("\n") if e]
race_detection = config.getboolean("testing", "race_detection", fallback=True)
multi_process = config.getboolean("testing", "multi_process", fallback=True)
timeout = config.getint("testing", "timeout", fallback=60)
list_process = subprocess.Popen(
["go", "list", test_package], stdout=subprocess.PIPE, universal_newlines=True
)
grep_command = ["grep", "-v"]
for this_exclude in exclude_list:
grep_command += ["-e", this_exclude]
sys.stdout.write(f"grep: {' '.join(grep_command)}\n")
grep_process = subprocess.Popen(
grep_command,
stdin=list_process.stdout,
stdout=subprocess.PIPE,
stderr=subprocess.PIPE,
universal_newlines=True,
)
assert list_process.stdout is not None
list_process.stdout.close()
packages_str, _ = grep_process.communicate()
packages = packages_str.split("\n")
if not packages:
packages = ["./..."]
sys.stdout.write(f"COVERAGE REQUIRED: {coverage_required}\n")
command = [
"go",
"test",
"-v",
"-failfast",
f"-timeout={timeout}s",
]
if race_detection:
command.append("-race")
if not multi_process:
command.extend(("-p", "1"))
command.extend(
[
"-covermode=atomic",
f"-coverprofile={COVERAGE_LOG}",
f"-coverpkg={','.join(packages)}",
]
)
command = command + ["./..."]
sys.stdout.write(f"command: {' '.join(command)}\n")
proc = subprocess.Popen(
command, stdout=subprocess.PIPE, stderr=subprocess.PIPE, universal_newlines=True
)
stdout, stderr = proc.communicate()
sys.stdout.write(stdout)
sys.stderr.write(stderr)
STD_OUT_LOG.write_text(stdout)
STD_ERR_LOG.write_text(stderr)
FULL_LOG.write_text(stdout + stderr)
if proc.returncode != 0:
sys.exit(proc.returncode)
command = [
"go",
"tool",
"cover",
"--func",
str(COVERAGE_LOG),
]
proc = subprocess.Popen(
command, stdout=subprocess.PIPE, stderr=subprocess.PIPE, universal_newlines=True
)
stdout, stderr = proc.communicate()
sys.stdout.write(stdout)
sys.stderr.write(stderr)
with STD_OUT_LOG.open("a") as f:
f.write(stdout)
with STD_ERR_LOG.open("a") as f:
f.write(stderr)
if proc.returncode != 0:
sys.exit(proc.returncode)
coverage_str = [x for x in COVERAGE_REGEX.finditer(stdout)][-1].group(1)
coverage = float(coverage_str)
if coverage < coverage_required:
sys.stderr.write(
f"Coverage {coverage} is less than required {coverage_required}\n"
)
sys.exit(1)
else:
sys.stderr.write(
f"Coverage {coverage}% passes requirement of {coverage_required}%\n"
)
if __name__ == "__main__":
run_test()