text: #!/usr/bin/env python
  
  # Copyright 2019 The Vitess Authors.
  #
  # Licensed under the Apache License, Version 2.0 (the "License");
  # you may not use this file except in compliance with the License.
  # You may obtain a copy of the License at
  #
  #     http://www.apache.org/licenses/LICENSE-2.0
  #
  # Unless required by applicable law or agreed to in writing, software
  # distributed under the License is distributed on an "AS IS" BASIS,
  # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  # See the License for the specific language governing permissions and
  # limitations under the License.
  
  """Initialize the test environment."""
  
  import logging
  import os
  import subprocess
  import sys
  
  import protocols_flavor
  
  # Import the topo implementations that you want registered as options for the
  # --topo-server-flavor flag.
  # pylint: disable=unused-import
  import topo_flavor.zk2
  import topo_flavor.etcd2
  import topo_flavor.consul
  
  # This imports topo_server into this module, so clients can write
  # environment.topo_server().
  # pylint: disable=unused-import
  from topo_flavor.server import topo_server
  
  # Import the VTGate gateway flavors that you want registered as options for the
  # --gateway_implementation flag.
  # pylint: disable=unused-import
  import vtgate_gateway_flavor.discoverygateway
  
  from selenium import webdriver
  from selenium.common.exceptions import WebDriverException
  from selenium.webdriver.chrome.options import Options
  
  from vttest import mysql_flavor
  
  
  # sanity check the environment
  if os.getuid() == 1:
    sys.stderr.write(
        'ERROR: Vitess and mysqld '
        'should not be run as root.\n')
    sys.exit(1)
  if 'VTTOP' not in os.environ:
    sys.stderr.write(
        'ERROR: Vitess environment not set up. '
        'Please run "source dev.env" first.\n')
    sys.exit(1)
  
  # vttop is the toplevel of the vitess source tree
  vttop = os.environ['VTTOP']
  
  # vtroot is where everything gets installed
  vtroot = os.environ['VTROOT']
  
  # vtdataroot is where to put all the data files
  vtdataroot = os.environ.get('VTDATAROOT', '/vt')
  
  # vt_mysql_root is where MySQL is installed
  vt_mysql_root = os.environ.get(
      'VT_MYSQL_ROOT', os.path.join(vtroot, 'dist', 'mysql'))
  
  # tmproot is the temporary place to put all test files
  tmproot = os.path.join(vtdataroot, 'tmp')
  
  # vtlogroot is where to put all the log files
  vtlogroot = tmproot
  
  # where to start allocating ports from
  vtportstart = int(os.environ.get('VTPORTSTART', '6700'))
  
  # url in which binaries export their status.
  status_url = '/debug/status'
  
  # location of the curl binary, used for some tests.
  curl_bin = '/usr/bin/curl'
  
  # if set, we will not build the binaries
  skip_build = False
  
  # location of the run_local_database.py file
  run_local_database = os.path.join(vtroot, 'py-vtdb', 'vttest',
                                    'run_local_database.py')
  
  # url to hit to force the logs to flush.
  flush_logs_url = '/debug/flushlogs'
  
  # set the maximum size for grpc messages to be 5MB (larger than the default of
  # 4MB).
  grpc_max_message_size = 5 * 1024 * 1024
  
  
  def setup():
    try:
      os.makedirs(tmproot)
    except OSError:
      # directory already exists
      pass
  
  
  # port management: reserve count consecutive ports, returns the first one
  def reserve_ports(count):
    global vtportstart
    result = vtportstart
    vtportstart += count
    return result
  
  
  def run(args, raise_on_error=True, **kargs):
    """simple run command, cannot use utils.run to avoid circular dependencies.
  
    Args:
      args: Variable length argument list.
      raise_on_error: if exception should be raised when seeing error.
      **kargs: Arbitrary keyword arguments.
  
    Returns:
      None
  
    Raises:
      Exception: when it cannot start subprocess.
    """
    try:
      logging.debug(
          'run: %s %s', str(args),
          ', '.join('%s=%s' % x for x in kargs.iteritems()))
      proc = subprocess.Popen(args,
                              stdout=subprocess.PIPE,
                              stderr=subprocess.PIPE,
                              **kargs)
      stdout, stderr = proc.communicate()
    except Exception as e:
      raise Exception('Command failed', e, args)
  
    if proc.returncode:
      if raise_on_error:
        raise Exception('Command failed: ' + ' '.join(args) + ':\n' + stdout +
                        stderr)
      else:
        logging.error('Command failed: %s:\n%s%s', ' '.join(args), stdout, stderr)
    return stdout, stderr
  
  
  # compile command line programs, only once
  compiled_progs = []
  
  
  def prog_compile(name):
    if skip_build or name in compiled_progs:
      return
    compiled_progs.append(name)
    logging.debug('Compiling %s', name)
    run(['go', 'install'], cwd=os.path.join(vttop, 'go', 'cmd', name))
  
  
  # binary management: returns the full path for a binary this should
  # typically not be used outside this file, unless you want to bypass
  # global flag injection (see binary_args)
  def binary_path(name):
    prog_compile(name)
    return os.path.join(vtroot, 'bin', name)
  
  
  # returns flags specific to a given binary
  # use this to globally inject flags any time a given command runs
  # e.g. - if name == 'vtctl': return ['-extra_arg', 'value']
  # pylint: disable=unused-argument
  def binary_flags(name):
    return []
  
  
  # returns binary_path + binary_flags as a list
  # this should be used instead of binary_path whenever possible
  def binary_args(name):
    return [binary_path(name)] + binary_flags(name)
  
  
  # returns binary_path + binary_flags as a string
  # this should be used instead of binary_path whenever possible
  def binary_argstr(name):
    return ' '.join(binary_args(name))
  
  
  # binary management for the MySQL distribution.
  def mysql_binary_path(name):
    return os.path.join(vt_mysql_root, 'bin', name)
  
  
  def lameduck_flag(lameduck_period):
    return ['-lameduck-period', lameduck_period]
  
  
  # pylint: disable=unused-argument
  def add_options(parser):
    """Add environment-specific command-line options."""
    pass
  
  
  def setup_protocol_flavor(flavor):
    """Imports the right protocols flavor implementation.
  
    This is a separate method that does dynamic import of the module so the
    tests only depend and import the code they will use.
    Each protocols flavor implementation will import the modules it needs.
  
    Args:
      flavor: the flavor name to use.
    """
    if flavor == 'grpc':
      import grpc_protocols_flavor  # pylint: disable=g-import-not-at-top
      protocols_flavor.set_protocols_flavor(
          grpc_protocols_flavor.GRpcProtocolsFlavor())
  
    else:
      logging.error('Unknown protocols flavor %s', flavor)
      exit(1)
  
    logging.debug('Using protocols flavor \'%s\'', flavor)
  
  
  def reset_mysql_flavor():
    mysql_flavor.set_mysql_flavor(None)
  
  
  def create_webdriver():
    """Creates a webdriver object (local or remote for Travis)."""
  
    # Set common Options
    chrome_options = Options()
    chrome_options.add_argument("--disable-gpu")
    chrome_options.add_argument("--no-sandbox")  
    chrome_options.headless = True
  
    if os.environ.get('CI') == 'true' and os.environ.get('TRAVIS') == 'true':
      username = os.environ['SAUCE_USERNAME']
      access_key = os.environ['SAUCE_ACCESS_KEY']
      capabilities = {}
      capabilities['tunnel-identifier'] = os.environ['TRAVIS_JOB_NUMBER']
      capabilities['build'] = os.environ['TRAVIS_BUILD_NUMBER']
      capabilities['platform'] = 'Linux'
      capabilities['browserName'] = 'chrome'
      capabilities['chromeOptions'] = chrome_options
      hub_url = '%s:%s@localhost:4445' % (username, access_key)
      driver = webdriver.Remote(
          desired_capabilities=capabilities,
          command_executor='http://%s/wd/hub' % hub_url)
  
    else:
      # Only testing against Chrome for now
      os.environ['webdriver.chrome.driver'] = os.path.join(vtroot, 'dist')
      service_log_path = os.path.join(tmproot, 'chromedriver.log')
      
      try:
        driver = webdriver.Chrome(service_args=['--verbose'],
                                  service_log_path=service_log_path,
                                  chrome_options=chrome_options
        )
      except WebDriverException as e:
        if 'Chrome failed to start' not in str(e):
          # Not a Chrome issue. Just re-raise the exception.
          raise
  
        # Chrome issue: Dump the log file.
        logging.error(
            'webdriver failed to start Chrome.\n'
            '\n'
            'See chromedriver.log below for details.\n'
            '\n'
            'Original exception:\n'
            '\n'
            '%s', str(e))
        # Dump the whole log file. This can go over multiple pages because
        # webdriver is constantly polling (after Chrome crashed) and logging
        # each attempt.
        with open(service_log_path, 'r') as f:
          logging.error('Content of chromedriver.log:\n%s', f.read())
        logging.error('webdriver failed to start Chrome. Scroll up for'
                      ' details.')
        exit(1)
  
      driver.set_window_position(0, 0)
      driver.set_window_size(1280, 1024)
    return driver
  
  
  def set_log_level(verbose):
    level = logging.DEBUG
    if verbose == 0:
      level = logging.WARNING
    elif verbose == 1:
      level = logging.INFO
    logging.getLogger().setLevel(level)
  