Commit 0153635b authored by Kirill Smelkov's avatar Kirill Smelkov

Teach nxdtest to run tests locally

It is very handy to debug both .nxdtest and nxdtest tool itself, and to
be able to run tests locally during development instead of (in addition
to) waiting for the test result from test nodes.

-> Teach nxdtest to run and report tests locally if no --master_url was
provided.

Idea is taken from runTestSuite.in from NEO, Cython+, Buildout and Rina:

https://lab.nexedi.com/nexedi/slapos/blob/3b14e028/software/neoppod/runTestSuite.in#L95-105
https://lab.nexedi.com/nexedi/slapos/blob/3b14e028/software/neoppod/runTestSuite.in#L55-75
https://lab.nexedi.com/nexedi/slapos/blob/3b14e028/software/neoppod/stress-testing/runTestSuite.in#L17-37
https://lab.nexedi.com/nexedi/slapos/blob/3b14e028/software/cython-test/runTestSuite.in#L38-58
https://lab.nexedi.com/nexedi/slapos/blob/3b14e028/software/buildout-testing/runTestSuite.in#L21-39
https://lab.nexedi.com/nexedi/slapos/blob/3b14e028/software/build-rina/runTestSuite.in#L29-49

Instead of copying code over and over again, let's stick to UNIX
approach and make it to be in one tool only that does its job
(hopefully) good.
parent 9640d0fe
...@@ -46,6 +46,11 @@ step handled by SlapOS. ...@@ -46,6 +46,11 @@ step handled by SlapOS.
(*) https://www.erp5.com/NXD-Presentation.ci.testing.system.buildout (*) https://www.erp5.com/NXD-Presentation.ci.testing.system.buildout
https://www.erp5.com/erp5-Guideline.Nexedi.Testing.Extended https://www.erp5.com/erp5-Guideline.Nexedi.Testing.Extended
https://stack.nexedi.com/test_status https://stack.nexedi.com/test_status
Local mode
----------
Tests are run locally if --master_url option is not specified.
""" """
from __future__ import print_function, absolute_import from __future__ import print_function, absolute_import
...@@ -90,7 +95,7 @@ def main(): ...@@ -90,7 +95,7 @@ def main():
# testnode executes us giving URL to master results collecting instance and other details # testnode executes us giving URL to master results collecting instance and other details
# https://lab.nexedi.com/nexedi/erp5/blob/744f3fde/erp5/util/testnode/UnitTestRunner.py#L137 # https://lab.nexedi.com/nexedi/erp5/blob/744f3fde/erp5/util/testnode/UnitTestRunner.py#L137
parser = argparse.ArgumentParser(description=__doc__, formatter_class=argparse.RawDescriptionHelpFormatter) parser = argparse.ArgumentParser(description=__doc__, formatter_class=argparse.RawDescriptionHelpFormatter)
parser.add_argument('--master_url', help='The URL of Master controling many suites') parser.add_argument('--master_url', help='The URL of Master controlling many suites (local run if not specified)')
parser.add_argument('--revision', help='The revision to test', default='dummy_revision') parser.add_argument('--revision', help='The revision to test', default='dummy_revision')
parser.add_argument('--test_suite', help='The test suite name') parser.add_argument('--test_suite', help='The test suite name')
parser.add_argument('--test_suite_title', help='The test suite title') parser.add_argument('--test_suite_title', help='The test suite title')
...@@ -110,18 +115,24 @@ def main(): ...@@ -110,18 +115,24 @@ def main():
# load list of tests to run # load list of tests to run
tenv = loadNXDTestFile('.nxdtest') tenv = loadNXDTestFile('.nxdtest')
# connect to master and create 'test result' object with list of tests to run # master_url provided -> run tests under master control
tool = TaskDistributor(portal_url = args.master_url, logger = logger) if args.master_url is not None:
test_result = tool.createTestResult( # connect to master and create 'test result' object with list of tests to run
revision = args.revision, tool = TaskDistributor(portal_url = args.master_url, logger = logger)
test_name_list = [t.name for t in tenv.testv], test_result = tool.createTestResult(
node_title = args.test_node_title, revision = args.revision,
test_title = args.test_suite_title or args.test_suite, test_name_list = [t.name for t in tenv.testv],
project_title = args.project_title) node_title = args.test_node_title,
test_title = args.test_suite_title or args.test_suite,
if test_result is None: project_title = args.project_title)
# a test run for given name and revision has already been completed
return if test_result is None:
# a test run for given name and revision has already been completed
return
# master_url not provided -> run tests locally
else:
test_result = LocalTestResult(tenv)
# make sure we get output from subprocesses without delay. # make sure we get output from subprocesses without delay.
# go does not buffer stdout/stderr by default, but python does for stdout. # go does not buffer stdout/stderr by default, but python does for stdout.
...@@ -230,6 +241,38 @@ def tee(fin, fout, buf): ...@@ -230,6 +241,38 @@ def tee(fin, fout, buf):
# LocalTestResult* handle tests runs, when master_url was not provided and tests are run locally.
class LocalTestResult:
def __init__(self, tenv):
assert isinstance(tenv, TestEnv)
self.tenv = tenv
self.next = 0 # tenv.testv[next] is next test to execute
def start(self): # -> test_result_line
if self.next >= len(self.tenv.testv):
return None # all tests are done
test_result_line = LocalTestResultLine()
test_result_line.name = self.tenv.testv[self.next].name
self.next += 1
return test_result_line
class LocalTestResultLine:
def stop(self, **kw):
def v(name):
return kw.get(name, '?')
_ = v('error_count')
if _ == '?':
st = '?'
elif _ == 0:
st = 'ok'
else:
st = 'fail'
print('%s\t%s\t%.3fs\t# %st %se %sf %ss' % (st, self.name, kw['duration'], v('test_count'), v('error_count'), v('failure_count'), v('skip_count')))
# XXX + dump .json ?
if __name__ == '__main__': if __name__ == '__main__':
main() main()
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment