adb: add tests for -Tt shell arguments.

Adds python tests to check that -T (disable PTY) and -t (force PTY)
arguments work as expected for `adb shell`.

Bug: http://b/23825231
Change-Id: I5343fae35b2be8459a9b95125f66def46c26adf4
This commit is contained in:
David Pursell
2015-09-22 11:34:42 -07:00
parent b02c99f086
commit d89fcd4f76
2 changed files with 42 additions and 18 deletions

View File

@@ -156,7 +156,7 @@ class AndroidDevice(object):
# adb on Windows returns \r\n even if adbd returns \n. # adb on Windows returns \r\n even if adbd returns \n.
_RETURN_CODE_SEARCH_LENGTH = len('{0}255\r\n'.format(_RETURN_CODE_DELIMITER)) _RETURN_CODE_SEARCH_LENGTH = len('{0}255\r\n'.format(_RETURN_CODE_DELIMITER))
# Shell protocol feature string. # Feature name strings.
SHELL_PROTOCOL_FEATURE = 'shell_2' SHELL_PROTOCOL_FEATURE = 'shell_2'
def __init__(self, serial, product=None): def __init__(self, serial, product=None):

View File

@@ -112,6 +112,33 @@ class DeviceTest(unittest.TestCase):
class ShellTest(DeviceTest): class ShellTest(DeviceTest):
def _interactive_shell(self, shell_args, input):
"""Runs an interactive adb shell.
Args:
shell_args: List of string arguments to `adb shell`.
input: String input to send to the interactive shell.
Returns:
The remote exit code.
Raises:
unittest.SkipTest: The device doesn't support exit codes.
"""
if self.device.SHELL_PROTOCOL_FEATURE not in self.device.features:
raise unittest.SkipTest('exit codes are unavailable on this device')
proc = subprocess.Popen(
self.device.adb_cmd + ['shell'] + shell_args,
stdin=subprocess.PIPE, stdout=subprocess.PIPE,
stderr=subprocess.PIPE)
# Closing host-side stdin doesn't currently trigger the interactive
# shell to exit so we need to explicitly add an exit command to
# close the session from the device side, and append linesep to complete
# the interactive command.
proc.communicate('{}; exit{}'.format(input, self.device.linesep))
return proc.returncode
def test_cat(self): def test_cat(self):
"""Check that we can at least cat a file.""" """Check that we can at least cat a file."""
out = self.device.shell(['cat', '/proc/uptime'])[0].strip() out = self.device.shell(['cat', '/proc/uptime'])[0].strip()
@@ -155,30 +182,27 @@ class ShellTest(DeviceTest):
output = self.device.shell(['uname'])[0] output = self.device.shell(['uname'])[0]
self.assertEqual(output, 'Linux' + self.device.linesep) self.assertEqual(output, 'Linux' + self.device.linesep)
def test_pty_logic(self): def test_default_pty_logic(self):
"""Verify PTY logic for shells. """Verify default PTY logic for shells.
Interactive shells should use a PTY, non-interactive should not. Interactive shells should use a PTY, non-interactive should not.
Bug: http://b/21215503 Bug: http://b/21215503
""" """
proc = subprocess.Popen(
self.device.adb_cmd + ['shell'], stdin=subprocess.PIPE,
stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
# [ -t 0 ] is used (rather than `tty`) to provide portability. This # [ -t 0 ] is used (rather than `tty`) to provide portability. This
# gives an exit code of 0 iff stdin is connected to a terminal. # gives an exit code of 0 iff stdin is connected to a terminal.
# self.assertEqual(0, self._interactive_shell([], '[ -t 0 ]'))
# Closing host-side stdin doesn't currently trigger the interactive self.assertEqual(1, self.device.shell_nocheck(['[ -t 0 ]'])[0])
# shell to exit so we need to explicitly add an exit command to
# close the session from the device side, and append \n to complete
# the interactive command.
result = proc.communicate('[ -t 0 ]; echo x$?; exit 0\n')[0]
partition = result.rpartition('x')
self.assertEqual(partition[1], 'x')
self.assertEqual(int(partition[2]), 0)
exit_code = self.device.shell_nocheck(['[ -t 0 ]'])[0] def test_pty_arguments(self):
self.assertEqual(exit_code, 1) """Tests the -T and -t arguments to manually control PTY."""
if self.device.SHELL_PROTOCOL_FEATURE not in self.device.features:
raise unittest.SkipTest('PTY arguments unsupported on this device')
self.assertEqual(0, self._interactive_shell(['-t'], '[ -t 0 ]'))
self.assertEqual(1, self._interactive_shell(['-T'], '[ -t 0 ]'))
self.assertEqual(0, self.device.shell_nocheck(['-t', '[ -t 0 ]'])[0])
self.assertEqual(1, self.device.shell_nocheck(['-T', '[ -t 0 ]'])[0])
def test_shell_protocol(self): def test_shell_protocol(self):
"""Tests the shell protocol on the device. """Tests the shell protocol on the device.
@@ -190,9 +214,9 @@ class ShellTest(DeviceTest):
""" """
if self.device.SHELL_PROTOCOL_FEATURE not in self.device.features: if self.device.SHELL_PROTOCOL_FEATURE not in self.device.features:
raise unittest.SkipTest('shell protocol unsupported on this device') raise unittest.SkipTest('shell protocol unsupported on this device')
result = self.device.shell_nocheck( result = self.device.shell_nocheck(
shlex.split('echo foo; echo bar >&2; exit 17')) shlex.split('echo foo; echo bar >&2; exit 17'))
self.assertEqual(17, result[0]) self.assertEqual(17, result[0])
self.assertEqual('foo' + self.device.linesep, result[1]) self.assertEqual('foo' + self.device.linesep, result[1])
self.assertEqual('bar' + self.device.linesep, result[2]) self.assertEqual('bar' + self.device.linesep, result[2])