#!{{runTestSuite_py}}
from __future__ import print_function
import argparse, os, re, subprocess, sys
from time import gmtime, strftime, time
from erp5.util import taskdistribution
from erp5.util.testsuite import SubprocessError, TestSuite
from pkg_resources import get_distribution
from zc.buildout.buildout import Buildout

if str is bytes:
  str2bytes = lambda s: s
else:
  str2bytes = lambda s: s.encode()

slapos_buildout = {{repr(slapos_buildout)}}
test_dict = {
  'zc.buildout': slapos_buildout,
  'zc.recipe.egg': os.path.join(slapos_buildout, 'zc.recipe.egg_'),
}

class DummyTestResult:

  class DummyTestResultLine:
    def stop(self, **kw):
      pass

  done = 0

  def __init__(self, test_name_list):
    self.test_name_list = test_name_list

  def start(self):
    test_result_line = self.DummyTestResultLine()
    try:
      test_result_line.name = self.test_name_list[self.done]
    except IndexError:
      return
    self.done += 1
    return test_result_line

class BuildoutTestSuite(TestSuite):

  RUN_RE = re.compile(
    br'Ran (?P<all_tests>\d+) tests with'
    br' (?P<failures>\d+) failures,'
    br' (?P<errors>\d+) errors and'
    br' (?P<skips>\d+) skipped in')

  def run(self, test):
    start = time()
    try:
      status_dict = self.spawn(os.path.join('bin', 'zope-testrunner'),
        '--test-path', os.path.join(test_dict[test], 'src'))
    except SubprocessError as e:
      status_dict = e.status_dict
    end = time()
    status_dict.update(
      date = strftime("%Y/%m/%d %H:%M:%S", gmtime(end)),
      duration = end - start)
    search = self.RUN_RE.search(status_dict['stdout'])
    if search:
      groupdict = search.groupdict()
      status_dict.update(
        test_count = int(groupdict['all_tests']),
        error_count = int(groupdict['errors']),
        failure_count = int(groupdict['failures']),
        skip_count = int(groupdict['skips']))
    return status_dict

def main():
  os.environ['TEMP'] = {{repr(temp_directory)}}
  parser = argparse.ArgumentParser(description='Run a test suite.')
  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_node_title', help='The test node title')
  parser.add_argument('--project_title', help='The project title')
  parser.add_argument('--revision', help='The revision to test',
                      default='dummy_revision')
  parser.add_argument('--master_url',
                      help='The Url of Master controling many suites')

  args = parser.parse_args()

  test_title = args.test_suite_title or args.test_suite
  if args.master_url:
    tool = taskdistribution.TaskDistributor(args.master_url)
    test_result = tool.createTestResult(args.revision,
                                        list(test_dict),
                                        args.test_node_title,
                                        test_title=test_title,
                                        project_title=args.project_title)
    if test_result is None:
      return
  else:
    test_result = DummyTestResult(list(test_dict))

  fd = os.open('buildout.cfg', os.O_CREAT | os.O_EXCL | os.O_WRONLY, 0o666)
  try:
    os.write(fd, str2bytes("""\
[buildout]
develop =%s
parts = testrunner
newest = false
versions = versions

[versions]
%s
zope.exceptions = 4.3
zope.interface = 4.7.2
zope.testing = 4.7

[testrunner]
recipe = zc.recipe.egg
eggs =
  ${:recipe}
  zope.testing
  zope.testrunner
scripts =
  zope-testrunner
extra-paths =
  %s
""" % (''.join('\n  ' + x for x in test_dict.values()),
       '\n'.join(x + ' =' for x in test_dict),
       get_distribution('manuel').location,
       )))
  finally:
    os.close(fd)
  Buildout('buildout.cfg', {}).install(None)

  test_suite = BuildoutTestSuite(1)
  while 1:
    test_result_line = test_result.start()
    if not test_result_line:
      break
    test_result_line.stop(**test_suite.run(test_result_line.name))

if __name__ == "__main__":
    main()
