# Copyright 2020 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.

from contextlib import contextmanager
from recipe_engine import recipe_api

BUCKET_NAME = 'flutter_infra'
FUCHSIA_BUCKET_NAME = 'fuchsia'
FUCHSIA_SDK_CIPD = 'fuchsia/sdk/core/linux-amd64'
FUCHSIA_IMAGE_NAME = 'generic-x64.tgz'
FUCHSIA_PACKAGES_ARCHIVE_NAME = 'generic-x64.tar.gz'
FUCHSIA_TEST_SCRIPT_NAME = 'run_fuchsia_tests.sh'

SSH_CONFIG = """
Host *
  CheckHostIP no
  StrictHostKeyChecking no
  ForwardAgent no
  ForwardX11 no
  GSSAPIDelegateCredentials no
  UserKnownHostsFile /dev/null
  User fuchsia
  IdentitiesOnly yes
  IdentityFile $FUCHSIA_PRIVATE_KEY
  ControlPersist yes
  ControlMaster auto
  ControlPath /tmp/fuchsia--%r@%h:%p
  ConnectTimeout 10
  ServerAliveInterval 1
  ServerAliveCountMax 10
  LogLevel ERROR
"""


class FuchsiaUtilsApi(recipe_api.RecipeApi):
  """Provides utilities to execute fuchsia tests."""

  @contextmanager
  def make_temp_dir(self, label):
    temp_dir = self.m.path.mkdtemp('tmp')
    try:
      yield temp_dir
    finally:
      self.m.file.rmtree('temp dir for %s' % label, temp_dir)

  def get_fuchsia_version(self, flutter_bin):
    """Get the Fuchsia SDK version from the given Flutter SDK.

    Args:
      flutter_bin: Path to Flutter bin with internal/fuchsia-linux.version.

    Returns:
      String of the Fuchsia SDK version to pull artifacts from GCP.
    """
    # Flutter SDK only stores the CIPD version, so CIPD must be queried to
    # find the SDK version tag for this ref.
    version_path = flutter_bin.join('internal', 'fuchsia-linux.version')
    version = self.m.file.read_text('Read fuchsia cipd version', version_path)
    fuchsia_cipd = self.m.cipd.describe(FUCHSIA_SDK_CIPD, version=version)
    # There are multiple tags in a Fuchsia SDK CIPD description requiring
    # a search through the tags tuple for the version tag.
    for tag in fuchsia_cipd.tags:
      if 'version:' in tag.tag:
        return tag.tag.replace('version:', '')
    raise recipe_api.InfraFailure('No version tag on Fuchsia SDK CIPD ref')

  def download_fuchsia_deps(self, flutter_bin, destination_path):
    """Download dependencies to initialize Fuchsia bot.

    Args:
      flutter_bin: Path to Flutter bin with internal/fuchsia-linux.version.
      destination_path: Path to store the downloaded Fuchsia dependencies.
    """
    with self.m.step.nest('Download Fuchsia Dependencies'):
      fuchsia_version = self.get_fuchsia_version(flutter_bin)
      self.m.gsutil.download(
          FUCHSIA_BUCKET_NAME,
          'development/%s/images/%s' % (fuchsia_version, FUCHSIA_IMAGE_NAME),
          destination_path,
          name="download fuchsia system image")
      self.m.gsutil.download(
          FUCHSIA_BUCKET_NAME,
          'development/%s/packages/%s' %
          (fuchsia_version, FUCHSIA_PACKAGES_ARCHIVE_NAME),
          destination_path,
          name="download fuchsia companion packages")

  def copy_tool_deps(self, checkout_path, destination_path):
    """Copy necessary tools from Flutter SDK to initialize Fuchsia bot.

    Args:
      flutter_bin: Path to Flutter bin with internal/fuchsia-linux.version.
      destination_path: Path to store the downloaded Fuchsia dependencies.
    """
    flutter_bin = checkout_path.join('bin')
    fuchsia_tools = flutter_bin.join('cache', 'artifacts', 'fuchsia', 'tools', 'x64')
    self.download_fuchsia_deps(flutter_bin, destination_path)
    with self.m.step.nest('Collect tool deps'):
      self.m.file.copy(
          'Copy test script',
          checkout_path.join('dev', 'bots', FUCHSIA_TEST_SCRIPT_NAME),
          destination_path)
      self.m.file.copy('Copy device-finder',
                       fuchsia_tools.join('device-finder'), destination_path)
      self.m.file.copy('Copy pm', fuchsia_tools.join('pm'), destination_path)

  def collect_results(self, fuchsia_swarming_metadata, timeout='30m'):
    # Collect the result of the task by metadata.
    fuchsia_output = self.m.path['cleanup'].join('fuchsia_test_output')
    self.m.file.ensure_directory('swarming output', fuchsia_output)
    results = self.m.swarming.collect(
        'collect',
        fuchsia_swarming_metadata,
        output_dir=fuchsia_output,
        timeout=timeout)
    self.m.display_util.display_tasks(
        'Display builds',
        results=results,
        metadata=fuchsia_swarming_metadata,
        raise_on_failure=True)

  def upload_deps(self, checkout_path):
    with self.m.step.nest('Create CAS Archive'):
      with self.make_temp_dir('cas_dir') as cas_dir:
        self.copy_tool_deps(checkout_path, cas_dir)
        cas_flutter = cas_dir.join('flutter')
        self.m.file.copytree('Copy flutter framework', checkout_path,
                             cas_flutter)
        return self.m.cas_util.upload(cas_dir, step_name='Archive Fuchsia Test CAS')

  def trigger_swarming_task(self, checkout_path):
    cas_hash = self.upload_deps(checkout_path)
    fuchsia_ctl_package = self.m.cipd.EnsureFile()
    fuchsia_ctl_package.add_package(
        'flutter/fuchsia_ctl/${platform}',
        self.m.properties.get('fuchsia_ctl_version'))
    request = (
        self.m.swarming.task_request().with_name(
            'flutter_fuchsia_driver_tests').with_priority(100))
    request = (
        request.with_slice(
            0,
            request[0].with_cipd_ensure_file(fuchsia_ctl_package).with_command([
                './%s' % FUCHSIA_TEST_SCRIPT_NAME, FUCHSIA_IMAGE_NAME
            ]).with_dimensions(pool='luci.flutter.tests').with_cas_input_root(
                cas_hash).with_expiration_secs(3600).with_io_timeout_secs(
                    3600).with_execution_timeout_secs(3600).with_idempotent(
                        True).with_containment_type('AUTO')))

    return self.m.swarming.trigger(
        'Trigger Fuchsia Driver Tests', requests=[request])

  def run_test(self, checkout_path):
    """Create a swarming task to run tests against Fuchsia device.

    Args:
      checkout_path: Location of Flutter SDK
    """
    with self.m.step.nest('Fuchsia Tests'):
      self.m.step(
          'Flutter Config Enable Fuchsia',
          ['flutter', 'config', '--enable-fuchsia'])
      self.m.step(
          'Precache Flutter Artifacts',
          ['flutter', 'precache', '--fuchsia', '--no-android', '--no-ios', '--force'])
      self.m.step('Precache Flutter Runners', [
          'flutter', 'precache', '--flutter_runner', '--no-android', '--no-ios'
      ])
      return self.trigger_swarming_task(checkout_path)

  def device_name(self):
    """Extracts the device name from the bot name.

    This function expects a bot name [host]--[device_name] where host
    is the hostname the bot is running on and [device_name] is the
    fuchsia device name, e.g. fuchsia-tests-lab01-0001--ocean-bats-wick-snub.
    """
    return self.m.swarming.bot_id.split('--')[1]

  def fuchsia_environment(self, checkout_path):
    env, env_paths = self.m.repo_util.flutter_environment(checkout_path)
    private_key_path = '/etc/botanist/keys/id_rsa_infra'
    config_path = self.m.path['cleanup'].join('fuchsia_ssh__config')
    public_key_path = self.m.path['cleanup'].join('fuchsia_key.pub')
    with self.m.step.nest('Prepare Environment'):
      self.m.step(
          'Create public key', ['ssh-keygen', '-y', '-f', private_key_path],
          stdout=self.m.raw_io.output_text(leak_to=public_key_path))
      self.m.file.write_raw('Create ssh_config', config_path, SSH_CONFIG)
    env['FUCHSIA_SSH_CONFIG'] = config_path
    env['FUCHSIA_PRIVATE_KEY'] = private_key_path
    env['FUCHSIA_PUBLIC_KEY'] = public_key_path
    return env, env_paths
