133259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck# Copyright 2013 The Chromium Authors. All rights reserved.
233259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck# Use of this source code is governed by a BSD-style license that can be
333259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck# found in the LICENSE file.
433259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck
533259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reckimport os
633259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reckimport unittest
733259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck
833259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reckimport mock
933259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reckfrom pyfakefs import fake_filesystem_unittest
1033259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck
1133259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reckfrom telemetry.core import android_platform
1233259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reckfrom telemetry.internal.backends.chrome import android_browser_finder
1333259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reckfrom telemetry.internal.platform import android_platform_backend
1433259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reckfrom telemetry.internal.util import binary_manager
1533259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reckfrom telemetry.testing import options_for_unittests
1633259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck
1733259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck
1833259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reckdef FakeFetchPath(dependency, arch, os_name, os_version=None):
1933259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck  return os.path.join(
2033259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck      'dependency_dir', dependency, '%s_%s_%s.apk' % (
2133259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck        os_name, os_version, arch))
2233259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck
2333259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck
2433259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reckclass AndroidBrowserFinderTest(fake_filesystem_unittest.TestCase):
2533259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck  def setUp(self):
2633259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck    self.finder_options = options_for_unittests.GetCopy()
2733259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck    # Mock out what's needed for testing with exact APKs
2833259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck    self.setUpPyfakefs()
2933259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck    self._fetch_path_patcher = mock.patch(
3033259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck        'telemetry.internal.backends.chrome.android_browser_finder.binary_manager.FetchPath',  # pylint: disable=line-too-long
3133259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck        FakeFetchPath)
3233259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck    self._fetch_path_mock = self._fetch_path_patcher.start()
3333259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck    self._get_package_name_patcher = mock.patch(
3433259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck        'devil.android.apk_helper.GetPackageName')
3533259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck    self._get_package_name_mock = self._get_package_name_patcher.start()
3633259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck    self.fake_platform = mock.Mock(spec=android_platform.AndroidPlatform)
3733259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck    self.fake_platform.CanLaunchApplication.return_value = True
3833259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck    self.fake_platform._platform_backend = mock.create_autospec(
3933259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck        android_platform_backend, spec_set=True)
4033259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck    self.fake_platform.GetOSVersionName.return_value = 'L23ds5'
4133259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck    self.fake_platform.GetArchName.return_value = 'armeabi-v7a'
4233259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck    # The android_browser_finder converts the os version name to 'k' or 'l'
4333259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck    self.expected_reference_build = FakeFetchPath(
4433259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck        'chrome_stable', 'armeabi-v7a', 'android', 'l')
4533259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck
4633259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck  def tearDown(self):
4733259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck    self.tearDownPyfakefs()
4833259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck    self._get_package_name_patcher.stop()
4933259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck    self._fetch_path_patcher.stop()
5033259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck
5133259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck  def testNoPlatformReturnsEmptyList(self):
5233259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck    fake_platform = None
5333259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck    possible_browsers = android_browser_finder._FindAllPossibleBrowsers(
5433259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck        self.finder_options, fake_platform)
5533259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck    self.assertEqual([], possible_browsers)
5633259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck
5733259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck  def testCanLaunchAlwaysTrueReturnsAllExceptExactAndReference(self):
5833259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck    if not self.finder_options.chrome_root:
5933259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck      self.skipTest('--chrome-root is not specified, skip the test')
6033259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck    all_types = set(
6133259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck        android_browser_finder.FindAllBrowserTypes(self.finder_options))
6233259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck    expected_types = all_types - set(('exact', 'reference'))
6333259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck    possible_browsers = android_browser_finder._FindAllPossibleBrowsers(
6433259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck        self.finder_options, self.fake_platform)
6533259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck    self.assertEqual(
6633259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck        expected_types,
6733259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck        set([b.browser_type for b in possible_browsers]))
6833259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck
6933259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck  def testCanLaunchAlwaysTrueReturnsAllExceptExact(self):
7033259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck    if not self.finder_options.chrome_root:
7133259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck      self.skipTest('--chrome-root is not specified, skip the test')
7233259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck    self.fs.CreateFile(self.expected_reference_build)
7333259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck    all_types = set(
7433259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck        android_browser_finder.FindAllBrowserTypes(self.finder_options))
7533259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck    expected_types = all_types - set(('exact',))
7633259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck    possible_browsers = android_browser_finder._FindAllPossibleBrowsers(
7733259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck        self.finder_options, self.fake_platform)
7833259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck    self.assertEqual(
7933259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck        expected_types,
8033259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck        set([b.browser_type for b in possible_browsers]))
8133259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck
8233259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck  def testCanLaunchAlwaysTrueWithExactApkReturnsAll(self):
8333259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck    if not self.finder_options.chrome_root:
8433259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck      self.skipTest('--chrome-root is not specified, skip the test')
8533259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck    self.fs.CreateFile(
8633259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck        '/foo/ContentShell.apk')
8733259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck    self.fs.CreateFile(self.expected_reference_build)
8833259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck    self.finder_options.browser_executable = '/foo/ContentShell.apk'
8933259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck    self._get_package_name_mock.return_value = 'org.chromium.content_shell_apk'
9033259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck
9133259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck    expected_types = set(
9233259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck        android_browser_finder.FindAllBrowserTypes(self.finder_options))
9333259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck    possible_browsers = android_browser_finder._FindAllPossibleBrowsers(
9433259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck        self.finder_options, self.fake_platform)
9533259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck    self.assertEqual(
9633259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck        expected_types,
9733259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck        set([b.browser_type for b in possible_browsers]))
9833259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck
9933259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck  def testErrorWithUnknownExactApk(self):
10033259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck    self.fs.CreateFile(
10133259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck        '/foo/ContentShell.apk')
10233259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck    self.finder_options.browser_executable = '/foo/ContentShell.apk'
10333259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck    self._get_package_name_mock.return_value = 'org.unknown.app'
10433259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck
10533259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck    self.assertRaises(Exception,
10633259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck        android_browser_finder._FindAllPossibleBrowsers,
10733259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck        self.finder_options, self.fake_platform)
10833259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck
10933259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck  def testErrorWithNonExistantExactApk(self):
11033259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck    self.finder_options.browser_executable = '/foo/ContentShell.apk'
11133259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck    self._get_package_name_mock.return_value = 'org.chromium.content_shell_apk'
11233259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck
11333259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck    self.assertRaises(Exception,
11433259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck        android_browser_finder._FindAllPossibleBrowsers,
11533259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck        self.finder_options, self.fake_platform)
11633259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck
11733259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck  def testNoErrorWithUnrecognizedApkName(self):
11833259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck    if not self.finder_options.chrome_root:
11933259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck      self.skipTest('--chrome-root is not specified, skip the test')
12033259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck    self.fs.CreateFile(
12133259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck        '/foo/unknown.apk')
12233259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck    self.finder_options.browser_executable = '/foo/unknown.apk'
12333259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck
12433259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck    possible_browsers = android_browser_finder._FindAllPossibleBrowsers(
12533259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck        self.finder_options, self.fake_platform)
12633259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck    self.assertNotIn('exact', [b.browser_type for b in possible_browsers])
12733259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck
12833259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck  def testCanLaunchExactWithUnrecognizedApkNameButKnownPackageName(self):
12933259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck    if not self.finder_options.chrome_root:
13033259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck      self.skipTest('--chrome-root is not specified, skip the test')
13133259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck    self.fs.CreateFile(
13233259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck        '/foo/MyFooBrowser.apk')
13333259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck    self._get_package_name_mock.return_value = 'org.chromium.chrome'
13433259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck    self.finder_options.browser_executable = '/foo/MyFooBrowser.apk'
13533259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck
13633259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck    possible_browsers = android_browser_finder._FindAllPossibleBrowsers(
13733259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck        self.finder_options, self.fake_platform)
13833259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck    self.assertIn('exact', [b.browser_type for b in possible_browsers])
13933259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck
14033259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck  def testNoErrorWithMissingReferenceBuild(self):
14133259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck    if not self.finder_options.chrome_root:
14233259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck      self.skipTest('--chrome-root is not specified, skip the test')
14333259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck    possible_browsers = android_browser_finder._FindAllPossibleBrowsers(
14433259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck      self.finder_options, self.fake_platform)
14533259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck    self.assertNotIn('reference', [b.browser_type for b in possible_browsers])
14633259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck
14733259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck  def testNoErrorWithReferenceBuildCloudStorageError(self):
14833259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck    if not self.finder_options.chrome_root:
14933259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck      self.skipTest('--chrome-root is not specified, skip the test')
15033259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck    with mock.patch(
15133259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck        'telemetry.internal.backends.chrome.android_browser_finder.binary_manager.FetchPath',  # pylint: disable=line-too-long
15233259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck        side_effect=binary_manager.CloudStorageError):
15333259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck      possible_browsers = android_browser_finder._FindAllPossibleBrowsers(
15433259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck        self.finder_options, self.fake_platform)
15533259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck    self.assertNotIn('reference', [b.browser_type for b in possible_browsers])
15633259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck
15733259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck  def testNoErrorWithReferenceBuildNoPathFoundError(self):
15833259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck    if not self.finder_options.chrome_root:
15933259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck      self.skipTest('--chrome-root is not specified, skip the test')
16033259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck    self._fetch_path_mock.side_effect = binary_manager.NoPathFoundError
16133259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck    possible_browsers = android_browser_finder._FindAllPossibleBrowsers(
16233259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck      self.finder_options, self.fake_platform)
16333259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck    self.assertNotIn('reference', [b.browser_type for b in possible_browsers])
16433259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck
16533259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck
16633259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reckclass FakePossibleBrowser(object):
16733259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck  def __init__(self, last_modification_time):
16833259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck    self._last_modification_time = last_modification_time
16933259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck
17033259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck  def last_modification_time(self):
17133259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck    return self._last_modification_time
17233259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck
17333259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck
17433259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reckclass SelectDefaultBrowserTest(unittest.TestCase):
17533259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck  def testEmptyListGivesNone(self):
17633259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck    self.assertIsNone(android_browser_finder.SelectDefaultBrowser([]))
17733259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck
17833259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck  def testSinglePossibleReturnsSame(self):
17933259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck    possible_browsers = [FakePossibleBrowser(last_modification_time=1)]
18033259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck    self.assertIs(
18133259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck      possible_browsers[0],
18233259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck      android_browser_finder.SelectDefaultBrowser(possible_browsers))
18333259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck
18433259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck  def testListGivesNewest(self):
18533259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck    possible_browsers = [
18633259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck        FakePossibleBrowser(last_modification_time=2),
18733259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck        FakePossibleBrowser(last_modification_time=3),  # newest
18833259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck        FakePossibleBrowser(last_modification_time=1),
18933259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck        ]
19033259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck    self.assertIs(
19133259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck      possible_browsers[1],
19233259e44c8229f70ffe0cf3bb5ca9375c4feb2f9John Reck      android_browser_finder.SelectDefaultBrowser(possible_browsers))
193