from __future__ import print_function
import argparse
import os
import glob
from time import gmtime, strftime, time, sleep
from erp5.util import taskdistribution


class DummyTestResult:

  class DummyTestResultLine:

    def stop(self, duration, stdout='', **kw):
      print('stop:')
      print('\n' + stdout)
      print('stop: %s' % (kw,))
      print('Ran in %.3fs' % duration)

  done = 0

  def __init__(self, test_name_list):
    print("init: Tests to run: %s" % (','.join(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
    print("start: %s" % (test_result_line.name,))
    return test_result_line


def main():
  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('--node_quantity', type=int,
                      help='Number of CPUs to use for the VM')
  parser.add_argument('--master_url',
                      help='The Url of Master controlling test suites')
  # SlapOS and ERP5TestNode specific
  parser.add_argument(
      '--partition_path',
      help="Path of a partition",
      default=os.path.abspath(os.getcwd()))
  parser.add_argument(
      '--test_reference',
      help="Reference of the test",
      default="missing"
  )

  args = parser.parse_args()
  test_list = [args.test_reference]
  test_title = args.test_suite_title or args.test_suite
  if args.master_url:
    tool = taskdistribution.TaskDistributionTool(args.master_url)
    test_result = tool.createTestResult(args.revision,
                                        test_list,
                                        args.test_node_title,
                                        test_title=test_title,
                                        project_title=args.project_title)
    if test_result is None:
      return
  else:
    test_result = DummyTestResult(test_list)

  while 1:
    test_result_line = test_result.start()
    if not test_result_line:
      break
    status_dict = {'command': 'file not found'}

    # find test result, wait 10h
    sleep_time = 10
    try_amount = (3600 * 10) / sleep_time
    try_num = 1
    result_path = None
    start = time()
    while 1:
      result_list = glob.glob(
          os.path.join(
              args.partition_path,
              '..',
              '*',
              'srv',
              'public',
              'test-script-result',
          ))
      if len(result_list) > 0:
        result_path = result_list[0]
        break
      if try_num > try_amount:
        break
      sleep(10)
    if result_path is None:
      status_dict['stdout'] = 'Test timed out and no result found.'
      status_dict.update(
          test_count=0,
          skip_count=0,
          failure_count=0,
          error_count=0
      )
    else:
      oldest_result = min(
          (os.path.join(dirname, filename)
           for dirname, dirnames, filenames in os.walk(result_path)
           for filename in filenames
           ),
          key=lambda fn: os.stat(fn).st_mtime)
      if oldest_result is None:
        status_dict['stdout'] = 'Test finished but no result found.'
        status_dict.update(
            test_count=1,
            skip_count=0,
            failure_count=0,
            error_count=1
        )
      else:
        oldest_result = os.path.abspath(oldest_result)
        status_dict['command'] = oldest_result
        result = open(oldest_result).read()
        if 'FATAL: all hosts have already failed -- aborting' in result:
          # failed
          status_dict.update(
              test_count=1,
              skip_count=0,
              failure_count=1,
              error_count=0
          )
        elif "\"msg\": \"[u'Build successful, connect to:', u'" in result:
          # success
          status_dict.update(
              test_count=1,
              skip_count=0,
              failure_count=0,
              error_count=0
          )
        else:
          # unknown
          status_dict.update(
              test_count=1,
              skip_count=0,
              failure_count=0,
              error_count=1
          )
          status_dict['stdout'] = \
              'Cannot find success or failure result in the output'
        # send only part of the result
        status_dict['stderr'] = result[-8192:]

    end = time()

    test_result_line.stop(
        date=strftime("%Y/%m/%d %H:%M:%S", gmtime(end)),
        duration=end - start,
        **status_dict)

if __name__ == "__main__":
    main()
