Implement test runner

This commit is contained in:
jpic 2020-02-13 03:27:14 +01:00
parent e7b059ab44
commit be8460b372
7 changed files with 121 additions and 35 deletions

View File

@ -9,11 +9,75 @@ import os
import sys
from .container import Container
from .pod import Pod
from .exceptions import Mistake, WrongResult
from .pod import Pod
from .podfile import Podfile
from .proc import output
from .service import Service
@cli2.option('debug', alias='d', help='Display debug output.')
async def test(*args, **kwargs):
"""Run podctl test over a bunch of paths."""
report = []
for arg in args:
candidates = [
os.path.join(os.getcwd(), arg, 'pod.py'),
os.path.join(os.getcwd(), arg, 'pod_test.py'),
]
for candidate in candidates:
if not os.path.exists(candidate):
continue
podfile = Podfile.factory(candidate)
for name, test in podfile.tests.items():
name = '::'.join([podfile.path, name])
output.print(
'\n\x1b[1;38;5;160;48;5;118m TEST START \x1b[0m'
+ ' ' + name + '\n'
)
try:
await test(podfile.pod)
except Exception as e:
report.append((name, False))
output.print('\x1b[1;38;5;15;48;5;196m TEST FAIL \x1b[0m' + name)
else:
report.append((name, True))
output.print('\x1b[1;38;5;200;48;5;44m TEST SUCCESS \x1b[0m' + name)
output.print('\n')
print('\n')
for name, success in report:
if success:
output.print('\n\x1b[1;38;5;200;48;5;44m TEST SUCCESS \x1b[0m' + name)
else:
output.print('\n\x1b[1;38;5;15;48;5;196m TEST FAIL \x1b[0m' + name)
print('\n')
success = [*filter(lambda i: i[1], report)]
failures = [*filter(lambda i: not i[1], report)]
output.print(
'\n\x1b[1;38;5;200;48;5;44m TEST TOTAL: \x1b[0m'
+ str(len(report))
)
output.print(
'\n\x1b[1;38;5;15;48;5;196m TEST FAIL: \x1b[0m'
+ str(len(failures))
)
output.print(
'\n\x1b[1;38;5;200;48;5;44m TEST SUCCESS: \x1b[0m'
+ str(len(success))
)
if failures:
console_script.exit_code = 1
class ConsoleScript(cli2.ConsoleScript):
class Parser(cli2.Parser):
def parse(self):
@ -38,18 +102,18 @@ class ConsoleScript(cli2.ConsoleScript):
self.options = dict()
def __call__(self, *args, **kwargs):
import inspect
from podctl.podfile import Podfile
self.podfile = Podfile.factory(os.getenv('PODFILE', 'pod.py'))
for name, script in self.podfile.pod.scripts.items():
cb = self.podfile.pod.script(name)
cb.__doc__ = inspect.getdoc(script) or script.doc
self[name] = cli2.Callable(
name,
cb,
options={o.name: o for o in script.options},
color=getattr(script, 'color', cli2.YELLOW),
)
podfile = os.getenv('PODFILE', 'pod.py')
if os.path.exists(podfile):
self.podfile = Podfile.factory(podfile)
for name, script in self.podfile.pod.scripts.items():
cb = self.podfile.pod.script(name)
cb.__doc__ = inspect.getdoc(script) or script.doc
self[name] = cli2.Callable(
name,
cb,
options={o.name: o for o in script.options},
color=getattr(script, 'color', cli2.YELLOW),
)
return super().__call__(*args, **kwargs)
def call(self, command):
@ -59,10 +123,10 @@ class ConsoleScript(cli2.ConsoleScript):
return super().call(command)
except Mistake as e:
print(e)
sys.exit(1)
self.exit_code = 1
except WrongResult as e:
print(e)
sys.exit(e.proc.rc)
self.exit_code = e.proc.rc
console_script = ConsoleScript(__doc__).add_module('podctl.console_script')

View File

@ -18,6 +18,13 @@ class Pod(Visitable):
),
)
def script(self, name):
async def cb(*args, **kwargs):
asyncio.events.get_event_loop()
kwargs['pod'] = self
return await self.scripts[name].run(*args, **kwargs)
return cb
async def down(self, script):
try:
await script.exec('podman', 'pod', 'inspect', self.name)
@ -47,12 +54,5 @@ class Pod(Visitable):
def containers(self):
return [i for i in self.visitors if type(i) == Container]
def script(self, name):
async def cb(*args, **kwargs):
asyncio.events.get_event_loop()
kwargs['pod'] = self
return await self.scripts[name].run(*args, **kwargs)
return cb
def __repr__(self):
return self.name

View File

@ -6,9 +6,11 @@ from .pod import Pod
class Podfile:
def __init__(self, pods, containers):
def __init__(self, pods, containers, path, tests):
self.pods = pods
self.containers = containers
self.path = path
self.tests = tests
if not self.pods:
self.pods['pod'] = Pod(*containers.values())
@ -25,6 +27,7 @@ class Podfile:
def factory(cls, path):
containers = dict()
pods = dict()
tests = dict()
spec = importlib.util.spec_from_file_location('pod', path)
pod = importlib.util.module_from_spec(spec)
spec.loader.exec_module(pod)
@ -35,5 +38,7 @@ class Podfile:
elif isinstance(value, Pod):
pods[name] = value
value.name = name
elif callable(value) and value.__name__.startswith('test_'):
tests[value.__name__] = value
return cls(pods, containers)
return cls(pods, containers, path, tests)

View File

@ -29,21 +29,18 @@ class Output:
self.prefix_length = 0
def __call__(self, line, prefix, highlight=True):
if prefix not in self.prefixes:
if prefix and prefix not in self.prefixes:
self.prefixes[prefix] = (
self.colors[len([*self.prefixes.keys()]) - 1]
)
if len(prefix) > self.prefix_length:
self.prefix_length = len(prefix)
prefix_color = self.prefixes[prefix]
prefix_padding = '.' * (self.prefix_length - len(prefix) - 2)
prefix_color = self.prefixes[prefix] if prefix else ''
prefix_padding = '.' * (self.prefix_length - len(prefix) - 2) if prefix else ''
if prefix_padding:
prefix_padding = ' ' + prefix_padding + ' '
if not prefix:
breakpoint()
#breakpoint()
sys.stdout.buffer.write((
(
prefix_color
@ -71,6 +68,13 @@ class Output:
highlight=False
)
def print(self, content):
self(
content,
prefix=None,
highlight=False
)
def highlight(self, line, highlight=True):
if not highlight:
return line

View File

@ -3,6 +3,7 @@ import copy
import cli2
import os
import textwrap
import subprocess
import sys
from .proc import output, Proc
@ -94,9 +95,20 @@ class Script:
async def run(self, *args, **kwargs):
if self.unshare and os.getuid() != 0:
import sys
# restart under buildah unshare environment !
os.execvp('buildah', ['buildah', 'unshare'] + sys.argv)
argv = [
'buildah', 'unshare',
sys.argv[0], # current podctl location
type(self).__name__.lower() # script name ?
] + list(args)
pp = subprocess.Popen(
argv,
stderr=sys.stderr,
stdin=sys.stdin,
stdout=sys.stdout,
)
pp.communicate()
return pp.returncode
for key, value in kwargs.items():
setattr(self, key, value)
@ -122,4 +134,4 @@ class Script:
)
for container in containers
]
return await asyncio.gather(*procs)
await asyncio.gather(*procs)

View File

@ -6,7 +6,7 @@ import sys
from .build import Build
from .exceptions import WrongResult
from .proc import Proc
from .proc import output, Proc
from .script import Script

View File

@ -136,7 +136,8 @@ class Packages:
return cachedir
async def dnf_setup(self, script):
await script.mount(self.cache, f'/var/cache/{self.mgr}')
cachedir = os.path.join(self.cache_root, self.mgr)
await script.mount(cachedir, f'/var/cache/{self.mgr}')
await script.run('echo keepcache=True >> /etc/dnf/dnf.conf')
async def apt_setup(self, script):