adb: Fix PTY logic for non-interactive shells.
Change `adb shell` so that interactive sessions use a PTY but
non-interactive do not. This matches `ssh` functionality better
and also enables future work to split stdout/stderr for
non-interactive sessions.
A test to verify this behavior is added to test_device.py with
supporting modifications in device.py.
Bug: http://b/21215503
Change-Id: Ib4ba40df85f82ddef4e0dd557952271c859d1c7b
diff --git a/test_device.py b/test_device.py
index 48a3f6c..c893ad4 100644
--- a/test_device.py
+++ b/test_device.py
@@ -155,6 +155,31 @@
output = self.device.shell(['uname'])
self.assertEqual(output, 'Linux' + self.device.linesep)
+ def test_pty_logic(self):
+ """Verify PTY logic for shells.
+
+ Interactive shells should use a PTY, non-interactive should not.
+
+ 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
+ # gives an exit code of 0 iff stdin is connected to a terminal.
+ #
+ # 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 \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]
+ self.assertEqual(exit_code, 1)
+
class ArgumentEscapingTest(DeviceTest):
def test_shell_escaping(self):