#!/usr/bin/env python
# Copyright 2017 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
import sys
import unittest

if __name__ == '__main__':
  sys.path.append(
      os.path.abspath(os.path.join(
          os.path.dirname(__file__),
          '..',
          '..',
      )))

from devil.android import crash_handler
from devil.android import device_errors
from devil.android import device_utils
from devil.android import device_temp_file
from devil.android import device_test_case
from devil.utils import cmd_helper
from devil.utils import reraiser_thread
from devil.utils import timeout_retry


class DeviceCrashTest(device_test_case.DeviceTestCase):
  def setUp(self):
    super(DeviceCrashTest, self).setUp()
    self.device = device_utils.DeviceUtils(self.serial)

  def testCrashDuringCommand(self):
    self.device.EnableRoot()
    with device_temp_file.DeviceTempFile(self.device.adb) as trigger_file:

      trigger_text = 'hello world'

      def victim():
        trigger_cmd = 'echo -n %s > %s; sleep 20' % (cmd_helper.SingleQuote(
            trigger_text), cmd_helper.SingleQuote(trigger_file.name))
        crash_handler.RetryOnSystemCrash(
            lambda d: d.RunShellCommand(
                trigger_cmd,
                shell=True,
                check_return=True,
                retries=1,
                as_root=True,
                timeout=180),
            device=self.device)
        self.assertEquals(
            trigger_text,
            self.device.ReadFile(trigger_file.name, retries=0).strip())
        return True

      def crasher():
        def ready_to_crash():
          try:
            return trigger_text == self.device.ReadFile(
                trigger_file.name, retries=0).strip()
          except device_errors.CommandFailedError:
            return False

        timeout_retry.WaitFor(ready_to_crash, wait_period=2, max_tries=10)
        if not ready_to_crash():
          return False
        self.device.adb.Shell(
            'echo c > /proc/sysrq-trigger',
            expect_status=None,
            timeout=60,
            retries=0)
        return True

    self.assertEquals([True, True], reraiser_thread.RunAsync([crasher, victim]))


if __name__ == '__main__':
  device_test_case.PrepareDevices()
  unittest.main()
