#!/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 logging
import os
import posixpath
import shutil
import sys
import tempfile
import unittest

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

from devil import base_error
from devil import devil_env
from devil.android import device_temp_file
from devil.android import device_test_case
from devil.android import device_utils
from devil.android.tools import system_app

logger = logging.getLogger(__name__)


class SystemAppDeviceTest(device_test_case.DeviceTestCase):

  PACKAGE = 'com.google.android.webview'

  def setUp(self):
    super(SystemAppDeviceTest, self).setUp()
    self._device = device_utils.DeviceUtils(self.serial)
    self._original_paths = self._device.GetApplicationPaths(self.PACKAGE)
    self._apk_cache_dir = tempfile.mkdtemp()
    # Host location -> device location
    self._cached_apks = {}
    for o in self._original_paths:
      h = os.path.join(self._apk_cache_dir, posixpath.basename(o))
      self._device.PullFile(o, h, timeout=60)
      self._cached_apks[h] = o

  def tearDown(self):
    final_paths = self._device.GetApplicationPaths(self.PACKAGE)
    if self._original_paths != final_paths:
      try:
        self._device.Uninstall(self.PACKAGE)
      except Exception:  # pylint: disable=broad-except
        pass

      with system_app.EnableSystemAppModification(self._device):
        for cached_apk, install_path in self._cached_apks.iteritems():
          try:
            with device_temp_file.DeviceTempFile(self._device.adb) as tmp:
              self._device.adb.Push(cached_apk, tmp.name)
              self._device.RunShellCommand(
                  ['mv', tmp.name, install_path],
                  as_root=True, check_return=True)
          except base_error.BaseError:
            logger.warning('Failed to reinstall %s',
                           os.path.basename(cached_apk))

    try:
      shutil.rmtree(self._apk_cache_dir)
    except IOError:
      logger.error('Unable to remove app cache directory.')

    super(SystemAppDeviceTest, self).tearDown()

  def _check_preconditions(self):
    if not self._original_paths:
      self.skipTest('%s is not installed on %s' % (
          self.PACKAGE, str(self._device)))
    if not any(p.startswith('/system/') for p in self._original_paths):
      self.skipTest('%s is not installed in a system location on %s' % (
          self.PACKAGE, str(self._device)))

  def testReplace(self):
    self._check_preconditions()
    replacement = devil_env.config.FetchPath(
        'empty_system_webview', device=self._device)
    with system_app.ReplaceSystemApp(self._device, self.PACKAGE, replacement):
      replaced_paths = self._device.GetApplicationPaths(self.PACKAGE)
      self.assertNotEqual(self._original_paths, replaced_paths)
    restored_paths = self._device.GetApplicationPaths(self.PACKAGE)
    self.assertEqual(self._original_paths, restored_paths)

  def testRemove(self):
    self._check_preconditions()
    system_app.RemoveSystemApps(self._device, [self.PACKAGE])
    removed_paths = self._device.GetApplicationPaths(self.PACKAGE)
    self.assertEqual([], removed_paths)


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