mirror of
https://github.com/aljazceru/plugins.git
synced 2025-12-25 08:54:20 +01:00
183 lines
5.2 KiB
Python
183 lines
5.2 KiB
Python
from pathlib import Path
|
|
import subprocess
|
|
from pprint import pprint
|
|
from collections import namedtuple
|
|
from typing import Generator
|
|
import sys
|
|
import tempfile
|
|
import shlex
|
|
import os
|
|
|
|
|
|
# Directories that are not plugins
|
|
exclude = [
|
|
'.ci',
|
|
'.git',
|
|
'.github',
|
|
'lightning',
|
|
'feeadjuster'
|
|
]
|
|
global_dependencies = [
|
|
'pytest==5.*',
|
|
'pytest-xdist',
|
|
'pytest-timeout',
|
|
'pyln-testing',
|
|
'pytest-rerunfailures',
|
|
]
|
|
|
|
Plugin = namedtuple('Plugin', ['name', 'path', 'requirements', 'devrequirements'])
|
|
|
|
|
|
def enumerate_plugins(basedir: Path) -> Generator[Plugin, None, None]:
|
|
plugins = [x for x in basedir.iterdir() if x.is_dir() and x.name not in exclude]
|
|
pytests = [x for x in plugins if (x / Path('requirements.txt')).exists()]
|
|
|
|
for p in sorted(pytests):
|
|
yield Plugin(
|
|
name=p.name,
|
|
path=p,
|
|
requirements=p/Path('requirements.txt'),
|
|
devrequirements=p/Path('requirements-dev.txt'),
|
|
)
|
|
|
|
|
|
def run_one(p: Plugin) -> bool:
|
|
print("Running tests on plugin {p.name}".format(p=p))
|
|
|
|
testfiles = [
|
|
x for x in p.path.iterdir()
|
|
if (x.is_dir() and x.name == 'tests')
|
|
or (x.name.startswith("test_") and x.name.endswith('.py'))
|
|
]
|
|
|
|
if len(testfiles) == 0:
|
|
print("No test files found, skipping plugin {p.name}".format(p=p))
|
|
return True
|
|
|
|
print("Found {ctestfiles} test files, creating virtualenv and running tests".format(ctestfiles=len(testfiles)))
|
|
print("##[group]{p.name}".format(p=p))
|
|
|
|
# Create a virtual env
|
|
vdir = tempfile.TemporaryDirectory()
|
|
vpath = Path(vdir.name)
|
|
|
|
subprocess.check_output(['virtualenv', '--clear', '-q', vpath])
|
|
bin_path = vpath / 'bin'
|
|
pip_path = vpath / 'bin' / 'pip3'
|
|
python_path = vpath / 'bin' / 'python'
|
|
pytest_path = vpath / 'bin' / 'pytest'
|
|
pip_opts = ['-qq']
|
|
|
|
# Install pytest (eventually we'd want plugin authors to include
|
|
# it in their requirements-dev.txt, but for now let's help them a
|
|
# bit).
|
|
subprocess.check_output(
|
|
[pip_path, 'install', *pip_opts, *global_dependencies],
|
|
stderr=subprocess.STDOUT,
|
|
)
|
|
|
|
# Now install all the requirements
|
|
print("Installing requirements from {p.requirements}".format(p=p))
|
|
subprocess.check_output(
|
|
[pip_path, 'install', '-U', *pip_opts, '-r', p.requirements],
|
|
stderr=subprocess.STDOUT,
|
|
)
|
|
|
|
if p.devrequirements.exists():
|
|
print("Installing requirements from {p.devrequirements}".format(p=p))
|
|
subprocess.check_output(
|
|
[pip_path, 'install', '-U', *pip_opts, '-r', p.devrequirements],
|
|
stderr=subprocess.STDOUT,
|
|
)
|
|
|
|
if os.environ.get("PYLN_MASTER", "0") == "1":
|
|
pass
|
|
|
|
assert pytest_path.exists()
|
|
|
|
# Update pyln-testing to master since we're running against c-lightning master.
|
|
install_pyln_testing(pip_path)
|
|
|
|
print("Running tests")
|
|
try:
|
|
env = os.environ.copy()
|
|
env.update({
|
|
# Need to customize PATH so lightningd can find the correct python3
|
|
'PATH': "{}:{}".format(bin_path, os.environ['PATH']),
|
|
# Some plugins require a valid locale to be set
|
|
'LC_ALL': 'C.UTF-8',
|
|
'LANG': 'C.UTF-8',
|
|
})
|
|
subprocess.check_call(
|
|
[
|
|
pytest_path,
|
|
p.path,
|
|
'-vvv',
|
|
'--timeout=600',
|
|
'--timeout-method=thread',
|
|
'--junitxml=report-{}.xml'.format(p.name),
|
|
'--reruns=2',
|
|
'--color=no',
|
|
'-o', 'junit_family=xunit2',
|
|
'-n=5',
|
|
],
|
|
stderr=subprocess.STDOUT,
|
|
env=env,
|
|
)
|
|
return True
|
|
except:
|
|
return False
|
|
finally:
|
|
print("##[endgroup]")
|
|
|
|
|
|
def install_pyln_testing(pip_path):
|
|
# Update pyln-testing to master since we're running against c-lightning master.
|
|
dest = Path('/tmp/lightning')
|
|
repo = 'https://github.com/ElementsProject/lightning.git'
|
|
if not dest.exists():
|
|
subprocess.check_output([
|
|
'git', 'clone', repo, dest
|
|
])
|
|
|
|
subprocess.check_output([
|
|
pip_path, 'install', '-U', f'{dest}/contrib/pyln-testing'
|
|
])
|
|
|
|
subprocess.check_output([
|
|
pip_path, 'install', '-U', f'{dest}/contrib/pyln-client'
|
|
])
|
|
|
|
subprocess.check_output([
|
|
pip_path, 'install', '-U', f'{dest}/contrib/pyln-proto'
|
|
])
|
|
|
|
|
|
def run_all(args):
|
|
root_path = subprocess.check_output([
|
|
'git',
|
|
'rev-parse',
|
|
'--show-toplevel'
|
|
]).decode('ASCII').strip()
|
|
|
|
root = Path(root_path)
|
|
|
|
plugins = list(enumerate_plugins(root))
|
|
if args != []:
|
|
plugins = [p for p in plugins if p.name in args]
|
|
print("Testing the following plugins: {names}".format(names=[p.name for p in plugins]))
|
|
else:
|
|
print("Testing all plugins in {root}".format(root=root))
|
|
|
|
results = [(p, run_one(p)) for p in plugins]
|
|
success = all([t[1] for t in results])
|
|
|
|
if not success:
|
|
print("The following tests failed:")
|
|
for t in filter(lambda t: not t[1], results):
|
|
print(" - {p.name} ({p.path})".format(p=t[0]))
|
|
sys.exit(1)
|
|
|
|
if __name__ == "__main__":
|
|
run_all(sys.argv[1:])
|