# Copyright (c) 2014 The Chromium Authors. All rights reserved.
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.


"""Utility script to launch browser-tests on the Chromoting bot."""
import argparse
import time

from chromoting_test_utilities import CleanupUserProfileDir
from chromoting_test_utilities import GetJidListFromTestResults
from chromoting_test_utilities import InitialiseTestMachineForLinux
from chromoting_test_utilities import PrintHostLogContents
from chromoting_test_utilities import PROD_DIR_ID
from chromoting_test_utilities import RunCommandInSubProcess
from chromoting_test_utilities import TestCaseSetup
from chromoting_test_utilities import TestMachineCleanup

SUCCESS_INDICATOR = 'SUCCESS: all tests passed.'
TEST_FAILURE = False
FAILING_TESTS = ''
BROWSER_NOT_STARTED_ERROR = (
    'Still waiting for the following processes to finish')
TIME_OUT_INDICATOR = '(TIMED OUT)'
MAX_RETRIES = 1


def LaunchBTCommand(args, command):
  """Launches the specified browser-test command.

    Retry if the execution failed because a browser-instance was not launched or
    because the JID used did not match the host-JID.
  Args:
    args: Command line args, used for test-case startup tasks.
    command: Browser-test command line.

  Returns:
    host_log_file_names: Array of host logs created for this command, including
         retries.
  """
  global TEST_FAILURE, FAILING_TESTS
  host_log_file_names = []

  retries = 0
  host_jid_mismatch = False
  host_jid = None
  while retries <= MAX_RETRIES:
    # TestCaseSetup restarts the me2me host, and sets up user-profile dir.
    # It returns the file-name of the me2me host log.
    # If we are attempting to run this test because of a JID-mismatch, don't
    # restart host.
    if host_jid_mismatch:
      # Cleanup user-profile directory, but don't restart host.
      CleanupUserProfileDir(args)
    else:
      host_log_file_names.append(TestCaseSetup(args))
      # Parse the me2me host log to obtain the JID that the host registered.
      host_jid = None
      with open(host_log_file_names[retries], 'r') as host_log_file:
        for line in host_log_file:
          # The host JID will be recorded in a line saying 'Signaling
          # connected'.
          if 'Signaling connected. ' in line:
            components = line.split('/')
            host_jid = components[-1]
            break

    results = RunCommandInSubProcess(command)

    # Get the JID used by this test to connect a remote-host, if any.
    jids_used = GetJidListFromTestResults(results)

    # Check for JID mismatch before checking for test success, so that we may
    # record instances where a test passed despite a JID mismatch.
    if jids_used and host_jid.rstrip() not in jids_used:
      host_jid_mismatch = True
      print 'Host JID mismatch. JID in host log = %s.' % host_jid.rstrip()
      print 'Host JIDs used by test:'
      for jid in jids_used:
        print jid

    if host_jid_mismatch:
      # The JID for the remote-host did not match the JID that was used for this
      # execution of the test. This happens because of a replication delay in
      # updating all instances of the Chromoting Directory Server. To
      # work-around this, sleep for 30s, which, based off a recent (08/2015)
      # query for average replication delay for Chromoting, should be sufficient
      # for the current JID value to have fully propagated.
      retries += 1
      time.sleep(30)
      continue
    elif jids_used:
      print 'JID used by test matched me2me host JID: %s' % host_jid
    else:
      # There wasn't a mismatch and no JIDs were returned. If no JIDs were
      # returned, that means the test didn't use any JIDs, so there is nothing
      # further for us to do.
      pass

    if SUCCESS_INDICATOR in results:
      break

    # Sometimes, during execution of browser-tests, a browser instance is
    # not started and the test times out. See http://crbug/480025.
    # To work around it, check if this execution failed owing to that
    # problem and retry.
    # There are 2 things to look for in the results:
    # A line saying "Still waiting for the following processes to finish",
    # and, because sometimes that line gets logged even if the test
    # eventually passes, we'll also look for "(TIMED OUT)", before retrying.
    if not (
        BROWSER_NOT_STARTED_ERROR in results and TIME_OUT_INDICATOR in results):
      # Test failed for some other reason. Let's not retry.
      break
    retries += 1

  # Check that the test passed.
  if SUCCESS_INDICATOR not in results:
    TEST_FAILURE = True
    # Add this command-line to list of tests that failed.
    FAILING_TESTS += command

  return host_log_file_names


def main(args):

  InitialiseTestMachineForLinux(args.cfg_file)

  host_log_files = []
  with open(args.commands_file) as f:
    for line in f:
      # Replace the PROD_DIR value in the command-line with
      # the passed in value.
      line = line.replace(PROD_DIR_ID, args.prod_dir)
      # Launch specified command line for test.
      host_log_files.extend(LaunchBTCommand(args, line))

  # All tests completed. Include host-logs in the test results.
  PrintHostLogContents(host_log_files)

  return host_log_files

if __name__ == '__main__':

  parser = argparse.ArgumentParser()
  parser.add_argument('-f', '--commands_file',
                      help='path to file listing commands to be launched.')
  parser.add_argument('-p', '--prod_dir',
                      help='path to folder having product and test binaries.')
  parser.add_argument('-c', '--cfg_file',
                      help='path to test host config file.')
  parser.add_argument('--me2me_manifest_file',
                      help='path to me2me host manifest file.')
  parser.add_argument('--it2me_manifest_file',
                      help='path to it2me host manifest file.')
  parser.add_argument(
      '-u', '--user_profile_dir',
      help='path to user-profile-dir, used by connect-to-host tests.')
  command_line_args = parser.parse_args()
  host_logs = ''
  try:
    host_logs = main(command_line_args)
    if TEST_FAILURE:
      print '++++++++++AT LEAST 1 TEST FAILED++++++++++'
      print FAILING_TESTS.rstrip('\n')
      print '++++++++++++++++++++++++++++++++++++++++++'
      raise Exception('At least one test failed.')
  finally:
    # Stop host and cleanup user-profile-dir.
    TestMachineCleanup(command_line_args.user_profile_dir, host_logs)