1# Copyright (C) 2012 Google Inc. All rights reserved.
2#
3# Redistribution and use in source and binary forms, with or without
4# modification, are permitted provided that the following conditions are
5# met:
6#
7#    * Redistributions of source code must retain the above copyright
8# notice, this list of conditions and the following disclaimer.
9#    * Redistributions in binary form must reproduce the above
10# copyright notice, this list of conditions and the following disclaimer
11# in the documentation and/or other materials provided with the
12# distribution.
13#    * Neither the name of Google Inc. nor the names of its
14# contributors may be used to endorse or promote products derived from
15# this software without specific prior written permission.
16#
17# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
18# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
19# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
20# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
21# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
22# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
23# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
27# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28
29import optparse
30import StringIO
31import time
32import webkitpy.thirdparty.unittest2 as unittest
33import sys
34
35from webkitpy.common.system import executive_mock
36from webkitpy.common.system.executive_mock import MockExecutive2
37from webkitpy.common.system.systemhost_mock import MockSystemHost
38
39from webkitpy.layout_tests.port import android
40from webkitpy.layout_tests.port import chromium_port_testcase
41from webkitpy.layout_tests.port import driver
42from webkitpy.layout_tests.port import driver_unittest
43from webkitpy.tool.mocktool import MockOptions
44
45
46# Any "adb" commands will be interpret by this class instead of executing actual
47# commansd on the file system, which we don't want to do.
48class MockAndroidDebugBridge:
49    def __init__(self, device_count):
50        self._device_count = device_count
51        self._last_command = None
52
53    # Local public methods.
54
55    def run_command(self, args):
56        self._last_command = ' '.join(args)
57        if args[0].startswith('path'):
58            if args[0] == 'path1':
59                return ''
60            if args[0] == 'path2':
61                return 'version 1.1'
62
63            return 'version 1.0'
64
65        if args[0] == 'adb':
66            if len(args) > 1 and args[1] == 'version':
67                return 'version 1.0'
68            if len(args) > 1 and args[1] == 'devices':
69                return self._get_device_output()
70            if len(args) > 3 and args[3] == 'command':
71                return 'mockoutput'
72            if len(args) > 5 and args[5] == 'battery':
73                return 'level: 99'
74
75        return ''
76
77    def last_command(self):
78        return self._last_command
79
80    # Local private methods.
81
82    def _get_device_output(self):
83        serials = ['123456789ABCDEF0', '123456789ABCDEF1', '123456789ABCDEF2',
84                   '123456789ABCDEF3', '123456789ABCDEF4', '123456789ABCDEF5']
85        output = 'List of devices attached\n'
86        for serial in serials[:self._device_count]:
87            output += '%s\tdevice\n' % serial
88        return output
89
90
91class AndroidCommandsTest(unittest.TestCase):
92    def setUp(self):
93        android.AndroidCommands._adb_command_path = None
94        android.AndroidCommands._adb_command_path_options = ['adb']
95
96    def make_executive(self, device_count):
97        self._mock_executive = MockAndroidDebugBridge(device_count)
98        return MockExecutive2(run_command_fn=self._mock_executive.run_command)
99
100    def make_android_commands(self, device_count, serial):
101        return android.AndroidCommands(self.make_executive(device_count), serial)
102
103    # The "adb" binary with the latest version should be used.
104    def serial_test_adb_command_path(self):
105        executive = self.make_executive(0)
106
107        android.AndroidCommands.set_adb_command_path_options(['path1', 'path2', 'path3'])
108        self.assertEqual('path2', android.AndroidCommands.adb_command_path(executive))
109
110    # The used adb command should include the device's serial number, and get_serial() should reflect this.
111    def test_adb_command_and_get_serial(self):
112        android_commands = self.make_android_commands(1, '123456789ABCDEF0')
113        self.assertEquals(['adb', '-s', '123456789ABCDEF0'], android_commands.adb_command())
114        self.assertEquals('123456789ABCDEF0', android_commands.get_serial())
115
116    # Running an adb command should return the command's output.
117    def test_run_command(self):
118        android_commands = self.make_android_commands(1, '123456789ABCDEF0')
119
120        output = android_commands.run(['command'])
121        self.assertEquals('adb -s 123456789ABCDEF0 command', self._mock_executive.last_command())
122        self.assertEquals('mockoutput', output)
123
124    # Test that the convenience methods create the expected commands.
125    def test_convenience_methods(self):
126        android_commands = self.make_android_commands(1, '123456789ABCDEF0')
127
128        android_commands.file_exists('/tombstones')
129        self.assertEquals('adb -s 123456789ABCDEF0 shell ls /tombstones', self._mock_executive.last_command())
130
131        android_commands.push('foo', 'bar')
132        self.assertEquals('adb -s 123456789ABCDEF0 push foo bar', self._mock_executive.last_command())
133
134        android_commands.pull('bar', 'foo')
135        self.assertEquals('adb -s 123456789ABCDEF0 pull bar foo', self._mock_executive.last_command())
136
137
138class AndroidPortTest(chromium_port_testcase.ChromiumPortTestCase):
139    port_name = 'android'
140    port_maker = android.AndroidPort
141
142    def make_port(self, **kwargs):
143        port = super(AndroidPortTest, self).make_port(**kwargs)
144        port._mock_adb = MockAndroidDebugBridge(kwargs.get('device_count', 1))
145        port._executive = MockExecutive2(run_command_fn=port._mock_adb.run_command)
146        return port
147
148    def make_wdiff_available(self, port):
149        port._wdiff_available = True
150        port._host_port._wdiff_available = True
151
152    # Test that content_shell currently is the only supported driver.
153    def test_non_content_shell_driver(self):
154        self.assertRaises(self.make_port, options=optparse.Values({'driver_name': 'foobar'}))
155
156    # Test that the number of child processes to create depends on the devices.
157    def test_default_child_processes(self):
158        port_default = self.make_port(device_count=5)
159        port_fixed_device = self.make_port(device_count=5, options=optparse.Values({'adb_device': '123456789ABCDEF9'}))
160
161        self.assertEquals(5, port_default.default_child_processes())
162        self.assertEquals(1, port_fixed_device.default_child_processes())
163
164    # Test that an HTTP server indeed is required by Android (as we serve all tests over them)
165    def test_requires_http_server(self):
166        self.assertTrue(self.make_port(device_count=1).requires_http_server())
167
168    # Tests the default timeouts for Android, which are different than the rest of Chromium.
169    def test_default_timeout_ms(self):
170        self.assertEqual(self.make_port(options=optparse.Values({'configuration': 'Release'})).default_timeout_ms(), 10000)
171        self.assertEqual(self.make_port(options=optparse.Values({'configuration': 'Debug'})).default_timeout_ms(), 10000)
172
173
174class ChromiumAndroidDriverTest(unittest.TestCase):
175    def setUp(self):
176        self._mock_adb = MockAndroidDebugBridge(1)
177        self._mock_executive = MockExecutive2(run_command_fn=self._mock_adb.run_command)
178
179        android_commands = android.AndroidCommands(self._mock_executive, '123456789ABCDEF0')
180        self._port = android.AndroidPort(MockSystemHost(executive=self._mock_executive), 'android')
181        self._driver = android.ChromiumAndroidDriver(self._port, worker_number=0,
182            pixel_tests=True, driver_details=android.ContentShellDriverDetails(), android_devices=self._port._devices)
183
184    # The cmd_line() method in the Android port is used for starting a shell, not the test runner.
185    def test_cmd_line(self):
186        self.assertEquals(['adb', '-s', '123456789ABCDEF0', 'shell'], self._driver.cmd_line(False, []))
187
188    # Test that the Chromium Android port can interpret Android's shell output.
189    def test_read_prompt(self):
190        self._driver._server_process = driver_unittest.MockServerProcess(lines=['root@android:/ # '])
191        self.assertIsNone(self._driver._read_prompt(time.time() + 1))
192        self._driver._server_process = driver_unittest.MockServerProcess(lines=['$ '])
193        self.assertIsNone(self._driver._read_prompt(time.time() + 1))
194
195
196class ChromiumAndroidDriverTwoDriversTest(unittest.TestCase):
197    # Test two drivers getting the right serial numbers, and that we disregard per-test arguments.
198    def test_two_drivers(self):
199        mock_adb = MockAndroidDebugBridge(2)
200        mock_executive = MockExecutive2(run_command_fn=mock_adb.run_command)
201
202        port = android.AndroidPort(MockSystemHost(executive=mock_executive), 'android')
203        driver0 = android.ChromiumAndroidDriver(port, worker_number=0, pixel_tests=True,
204            driver_details=android.ContentShellDriverDetails(), android_devices=port._devices)
205        driver1 = android.ChromiumAndroidDriver(port, worker_number=1, pixel_tests=True,
206            driver_details=android.ContentShellDriverDetails(), android_devices=port._devices)
207
208        self.assertEqual(['adb', '-s', '123456789ABCDEF0', 'shell'], driver0.cmd_line(True, []))
209        self.assertEqual(['adb', '-s', '123456789ABCDEF1', 'shell'], driver1.cmd_line(True, ['anything']))
210
211
212class ChromiumAndroidTwoPortsTest(unittest.TestCase):
213    # Test that the driver's command line indeed goes through to the driver.
214    def test_options_with_two_ports(self):
215        mock_adb = MockAndroidDebugBridge(2)
216        mock_executive = MockExecutive2(run_command_fn=mock_adb.run_command)
217
218        port0 = android.AndroidPort(MockSystemHost(executive=mock_executive),
219            'android', options=MockOptions(additional_drt_flag=['--foo=bar']))
220        port1 = android.AndroidPort(MockSystemHost(executive=mock_executive),
221            'android', options=MockOptions(driver_name='content_shell'))
222
223        self.assertEqual(1, port0.driver_cmd_line().count('--foo=bar'))
224        self.assertEqual(0, port1.driver_cmd_line().count('--create-stdin-fifo'))
225