# Copyright (c) 2013 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.
import os

from telemetry import test as test_module
from telemetry.core import util
from telemetry.page import page_set
from telemetry.page import page_test

data_path = os.path.join(
    util.GetChromiumSrcDir(), 'content', 'test', 'data', 'gpu')

wait_timeout = 20  # seconds

harness_script = r"""
  var domAutomationController = {};

  domAutomationController._loaded = false;
  domAutomationController._succeeded = false;
  domAutomationController._finished = false;

  domAutomationController.setAutomationId = function(id) {}

  domAutomationController.send = function(msg) {
    msg = msg.toLowerCase()
    if (msg == "loaded") {
      domAutomationController._loaded = true;
    } else if (msg == "success") {
      domAutomationController._succeeded = true;
      domAutomationController._finished = true;
    } else {
      domAutomationController._succeeded = false;
      domAutomationController._finished = true;
    }
  }

  window.domAutomationController = domAutomationController;
  console.log("Harness injected.");
"""

class _ContextLostValidator(page_test.PageTest):
  def __init__(self):
    # Strictly speaking this test doesn't yet need a browser restart
    # after each run, but if more tests are added which crash the GPU
    # process, then it will.
    super(_ContextLostValidator, self).__init__(
      'ValidatePage', needs_browser_restart_after_each_run=True)

  def CustomizeBrowserOptions(self, options):
    options.AppendExtraBrowserArgs(
        '--disable-domain-blocking-for-3d-apis')
    # Required for about:gpucrash handling from Telemetry.
    options.AppendExtraBrowserArgs('--enable-gpu-benchmarking')

  def ValidatePage(self, page, tab, results):
    if page.kill_gpu_process:
      if not tab.browser.supports_tab_control:
        raise page_test.Failure('Browser must support tab control')
      # Crash the GPU process.
      new_tab = tab.browser.tabs.New()
      # To access these debug URLs from Telemetry, they have to be
      # written using the chrome:// scheme.
      new_tab.Navigate('chrome://gpucrash')
      # Activate the original tab and wait for completion.
      tab.Activate()
      completed = False
      try:
        util.WaitFor(lambda: tab.EvaluateJavaScript(
            'window.domAutomationController._finished'), wait_timeout)
        completed = True
      except util.TimeoutException:
        pass
      new_tab.Close()
      if not completed:
        raise page_test.Failure(
            'Test didn\'t complete (no context lost event?)')
    if not tab.EvaluateJavaScript('window.domAutomationController._succeeded'):
      raise page_test.Failure('Test failed (context not restored properly?)')

class ContextLost(test_module.Test):
  enabled = True
  test = _ContextLostValidator

  def CreatePageSet(self, options):
    page_set_dict = {
      'description': 'Test cases for real and synthetic context lost events',
      'user_agent_type': 'desktop',
      'serving_dirs': [''],
      'pages': [
        {
          'name': 'ContextLost.WebGLContextLostFromGPUProcessExit',
          'url': 'file://webgl.html?query=kill_after_notification',
          'script_to_evaluate_on_commit': harness_script,
          'navigate_steps': [
            { 'action': 'navigate' },
            { 'action': 'wait',
              'javascript': 'window.domAutomationController._loaded' }
          ],
          'kill_gpu_process': True
        },
        {
          'name': 'ContextLost.WebGLContextLostFromLoseContextExtension',
          'url': 'file://webgl.html?query=WEBGL_lose_context',
          'script_to_evaluate_on_commit': harness_script,
          'navigate_steps': [
            { 'action': 'navigate' },
            { 'action': 'wait',
              'javascript': 'window.domAutomationController._finished' }
          ],
          'kill_gpu_process': False
        },
      ]
    }
    return page_set.PageSet.FromDict(page_set_dict, data_path)
