# 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 ExitStack

DEPS = [
    'flutter/android_virtual_device',
    'flutter/flutter_deps',
    'flutter/logs_util',
    'flutter/os_utils',
    'flutter/osx_sdk',
    'flutter/repo_util',
    'flutter/yaml',
    'recipe_engine/context',
    'recipe_engine/file',
    'recipe_engine/json',
    'recipe_engine/path',
    'recipe_engine/properties',
    'recipe_engine/step',
    'recipe_engine/runtime',
    'recipe_engine/raw_io',
]


def RunSteps(api):
  """Recipe to run flutter package tests."""
  # Collect memory/cpu/process before task execution.
  api.os_utils.collect_os_info()

  packages_checkout_path = api.path['start_dir'].join('packages')
  flutter_checkout_path = api.path['start_dir'].join('flutter')
  channel = api.properties.get('channel')
  version_file_name = api.properties.get('version_file', '')
  with api.step.nest('checkout source code'):
    api.repo_util.checkout(
        'packages',
        checkout_path=packages_checkout_path,
        url=api.properties.get('git_url'),
        ref=api.properties.get('git_ref')
    )
    # Check out the specified version of Flutter.
    flutter_ref = 'refs/heads/%s' % channel
    # When specified, use a pinned version instead of latest.
    if version_file_name:
      version_file = packages_checkout_path.join('.ci', version_file_name)
      flutter_ref = api.file.read_text(
          'read pinned version', version_file, flutter_ref
      ).strip()
    api.repo_util.checkout(
        'flutter',
        checkout_path=flutter_checkout_path,
        ref=flutter_ref,
        url='https://github.com/flutter/flutter',
    )

  env, env_prefixes = api.repo_util.flutter_environment(flutter_checkout_path)

  env['USE_EMULATOR'] = False
  with api.step.nest('Dependencies'):
    deps = api.properties.get('dependencies', [])
    api.flutter_deps.required_deps(env, env_prefixes, deps)
    dep_list = {d['dependency']: d.get('version') for d in deps}
    # If the emulator dependency is present then we assume it is wanted for testing.
    if 'android_virtual_device' in dep_list.keys():
      env['USE_EMULATOR'] = True
      env['EMULATOR_VERSION'] = dep_list.get('android_virtual_device')

  with api.context(env=env, env_prefixes=env_prefixes,
                   cwd=flutter_checkout_path):
    with api.step.nest('prepare environment'):
      api.step('flutter doctor', ['flutter', 'doctor', '-v'])
      # Fail fast on dependencies problem.
      timeout_secs = 300
      api.step(
          'download dependencies', ['flutter', 'update-packages', '-v'],
          infra_step=True,
          timeout=timeout_secs
      )
  tests_yaml_path = packages_checkout_path.join(
      '.ci', 'targets', api.properties.get('target_file', 'tests.yaml')
  )
  result = api.yaml.read('read yaml', tests_yaml_path, api.json.output())
  with api.context(env=env, env_prefixes=env_prefixes,
                   cwd=packages_checkout_path):
    with api.step.nest('Run package tests'):
      if api.properties.get('$flutter/osx_sdk'):
        with api.osx_sdk('ios'):
          api.flutter_deps.gems(
              env, env_prefixes, flutter_checkout_path.join('dev', 'ci', 'mac')
          )
          with api.context(env=env, env_prefixes=env_prefixes):
            run_test(api, result, packages_checkout_path, env, env_prefixes)
      else:
        with ExitStack() as stack:
          if env['USE_EMULATOR']:
            stack.enter_context(
                  api.android_virtual_device(
                      env=env,
                      env_prefixes=env_prefixes,
                      version=env['EMULATOR_VERSION']
                  )
              )
          run_test(api, result, packages_checkout_path, env, env_prefixes)

  # This is to clean up leaked processes.
  api.os_utils.kill_processes()
  # Collect memory/cpu/process after task execution.
  api.os_utils.collect_os_info()

def run_test(api, result, packages_checkout_path, env, env_prefixes):
  """Run tests sequentially following the script"""
  failed_tasks = []
  for task in result.json.output['tasks']:
    script_path = packages_checkout_path.join(task['script'])
    cmd = ['bash', script_path]
    if 'args' in task:
      args = task['args']
      cmd.extend(args)
    api.logs_util.initialize_logs_collection(env)

    # Flag showing whether the task should always run regardless of previous failures.
    always_run_task = task['always'] if 'always' in task else False
    # Flag showing whether the task should be considered and infra failure or test failure.
    is_infra_step = task['infra_step'] if 'infra_step' in task else False
    with api.context(env=env, env_prefixes=env_prefixes):
      # Runs the task in two scenarios:
      #   1) all earlier tasks pass
      #   2) there are earlier task failures, but the current task is marked as `always: True`.
      #   Note that infra tasks fail and do not run the rest of the tasks including `always`.
      if not failed_tasks or always_run_task:
        step = api.step(task['name'], cmd, raise_on_failure=is_infra_step, infra_step=is_infra_step)
        if step.retcode != 0:
          failed_tasks.append(task['name'])
    api.logs_util.upload_logs(task['name'])
  if failed_tasks:
    raise api.step.StepFailure('Tasks failed: %s' % ','.join(failed_tasks))


def GenTests(api):
  flutter_path = api.path['start_dir'].join('flutter')
  tasks_dict = {
      'tasks': [{'name': 'one', 'script': 'myscript', 'args': ['arg1', 'arg2']}]
  }
  yield api.test(
      'master_channel', api.repo_util.flutter_environment_data(flutter_path),
      api.properties(
          channel='master',
          version_file='flutter_master.version',
      ), api.step_data('read yaml.parse', api.json.output(tasks_dict))
  )
  yield api.test(
      'stable_channel', api.repo_util.flutter_environment_data(flutter_path),
      api.properties(channel='stable',),
      api.step_data('read yaml.parse', api.json.output(tasks_dict))
  )
  yield api.test(
      'mac', api.repo_util.flutter_environment_data(flutter_path),
      api.properties(
          channel='master',
          version_file='flutter_master.version',
          **{'$flutter/osx_sdk': {'sdk_version': 'deadbeef',}},
      ), api.step_data('read yaml.parse', api.json.output(tasks_dict))
  )
  checkout_path = api.path['cleanup'].join('tmp_tmp_1', 'flutter sdk')
  yield api.test(
      "emulator-test", 
      api.repo_util.flutter_environment_data(flutter_path),
      api.properties(
          channel='master',
          version_file='flutter_master.version',
          git_branch='master',
          dependencies=[{
              "dependency": "android_virtual_device", "version": "31"
          }],
      ),
      api.step_data('read yaml.parse', api.json.output(tasks_dict)),
      api.step_data(
          'Run package tests.start avd.Start Android emulator (API level 31)',
          stdout=api.raw_io.output_text(
              'android_31_google_apis_x86|emulator-5554 started (pid: 17687)'
          )
      ), 
      api.runtime(is_experimental=True)
  )
  multiple_tasks_dict = {
      'tasks': [{'name': 'one', 'script': 'myscript', 'args': ['arg1', 'arg2']},
                {
                    'name': 'two', 'script': 'myscript',
                    'args': ['arg1', 'arg2'], 'always': True
                }]
  }
  yield api.test(
      'multiple_tests_with_always',
      api.repo_util.flutter_environment_data(flutter_path),
      api.properties(
          channel='master',
          version_file='flutter_master.version',
      ),
      api.step_data('read yaml.parse', api.json.output(multiple_tasks_dict)),
      api.step_data('Run package tests.one', retcode=1),
      status='FAILURE'
  )
