1993ca4ad6ca2b8ad6c3f9c46a06e934c19b95e8eChristopher Wiley#!/usr/bin/env python 2993ca4ad6ca2b8ad6c3f9c46a06e934c19b95e8eChristopher Wiley 3993ca4ad6ca2b8ad6c3f9c46a06e934c19b95e8eChristopher Wiley""" 4993ca4ad6ca2b8ad6c3f9c46a06e934c19b95e8eChristopher WileyTest that aidl generates functional code by running it on an Android device. 5993ca4ad6ca2b8ad6c3f9c46a06e934c19b95e8eChristopher Wiley""" 6993ca4ad6ca2b8ad6c3f9c46a06e934c19b95e8eChristopher Wiley 7993ca4ad6ca2b8ad6c3f9c46a06e934c19b95e8eChristopher Wileyimport argparse 8993ca4ad6ca2b8ad6c3f9c46a06e934c19b95e8eChristopher Wileyimport pipes 9993ca4ad6ca2b8ad6c3f9c46a06e934c19b95e8eChristopher Wileyimport subprocess 10993ca4ad6ca2b8ad6c3f9c46a06e934c19b95e8eChristopher Wileyimport shlex 11993ca4ad6ca2b8ad6c3f9c46a06e934c19b95e8eChristopher Wiley 12993ca4ad6ca2b8ad6c3f9c46a06e934c19b95e8eChristopher WileyJAVA_OUTPUT_READER = 'aidl_test_sentinel_searcher' 13993ca4ad6ca2b8ad6c3f9c46a06e934c19b95e8eChristopher WileyNATIVE_TEST_CLIENT = 'aidl_test_client' 14993ca4ad6ca2b8ad6c3f9c46a06e934c19b95e8eChristopher WileyNATIVE_TEST_SERVICE = 'aidl_test_service' 15993ca4ad6ca2b8ad6c3f9c46a06e934c19b95e8eChristopher Wiley 16993ca4ad6ca2b8ad6c3f9c46a06e934c19b95e8eChristopher WileyTEST_FILTER_ALL = 'all' 17993ca4ad6ca2b8ad6c3f9c46a06e934c19b95e8eChristopher WileyTEST_FILTER_JAVA = 'java' 18993ca4ad6ca2b8ad6c3f9c46a06e934c19b95e8eChristopher WileyTEST_FILTER_NATIVE = 'native' 19993ca4ad6ca2b8ad6c3f9c46a06e934c19b95e8eChristopher Wiley 20993ca4ad6ca2b8ad6c3f9c46a06e934c19b95e8eChristopher WileyJAVA_CLIENT_TIMEOUT_SECONDS = 30 21993ca4ad6ca2b8ad6c3f9c46a06e934c19b95e8eChristopher WileyJAVA_LOG_FILE = '/data/data/android.aidl.tests/files/test-client.log' 22993ca4ad6ca2b8ad6c3f9c46a06e934c19b95e8eChristopher WileyJAVA_SUCCESS_SENTINEL = '>>> Java Client Success <<<' 23993ca4ad6ca2b8ad6c3f9c46a06e934c19b95e8eChristopher WileyJAVA_FAILURE_SENTINEL = '>>> Java Client Failure <<<' 24993ca4ad6ca2b8ad6c3f9c46a06e934c19b95e8eChristopher Wiley 25993ca4ad6ca2b8ad6c3f9c46a06e934c19b95e8eChristopher Wileyclass TestFail(Exception): 26993ca4ad6ca2b8ad6c3f9c46a06e934c19b95e8eChristopher Wiley """Raised on test failures.""" 27993ca4ad6ca2b8ad6c3f9c46a06e934c19b95e8eChristopher Wiley pass 28993ca4ad6ca2b8ad6c3f9c46a06e934c19b95e8eChristopher Wiley 29993ca4ad6ca2b8ad6c3f9c46a06e934c19b95e8eChristopher Wiley 30993ca4ad6ca2b8ad6c3f9c46a06e934c19b95e8eChristopher Wileyclass ShellResult(object): 31993ca4ad6ca2b8ad6c3f9c46a06e934c19b95e8eChristopher Wiley """Represents the result of running a shell command.""" 32993ca4ad6ca2b8ad6c3f9c46a06e934c19b95e8eChristopher Wiley 33993ca4ad6ca2b8ad6c3f9c46a06e934c19b95e8eChristopher Wiley def __init__(self, exit_status, stdout, stderr): 34993ca4ad6ca2b8ad6c3f9c46a06e934c19b95e8eChristopher Wiley """Construct an instance. 35993ca4ad6ca2b8ad6c3f9c46a06e934c19b95e8eChristopher Wiley 36993ca4ad6ca2b8ad6c3f9c46a06e934c19b95e8eChristopher Wiley Args: 37993ca4ad6ca2b8ad6c3f9c46a06e934c19b95e8eChristopher Wiley exit_status: integer exit code of shell command 38993ca4ad6ca2b8ad6c3f9c46a06e934c19b95e8eChristopher Wiley stdout: string stdout of shell command 39993ca4ad6ca2b8ad6c3f9c46a06e934c19b95e8eChristopher Wiley stderr: string stderr of shell command 40993ca4ad6ca2b8ad6c3f9c46a06e934c19b95e8eChristopher Wiley """ 41993ca4ad6ca2b8ad6c3f9c46a06e934c19b95e8eChristopher Wiley self.stdout = stdout 42993ca4ad6ca2b8ad6c3f9c46a06e934c19b95e8eChristopher Wiley self.stderr = stderr 43993ca4ad6ca2b8ad6c3f9c46a06e934c19b95e8eChristopher Wiley self.exit_status = exit_status 44993ca4ad6ca2b8ad6c3f9c46a06e934c19b95e8eChristopher Wiley 45993ca4ad6ca2b8ad6c3f9c46a06e934c19b95e8eChristopher Wiley def printable_string(self): 46993ca4ad6ca2b8ad6c3f9c46a06e934c19b95e8eChristopher Wiley """Get a string we could print to the logs and understand.""" 47993ca4ad6ca2b8ad6c3f9c46a06e934c19b95e8eChristopher Wiley output = [] 48993ca4ad6ca2b8ad6c3f9c46a06e934c19b95e8eChristopher Wiley output.append('stdout:') 49993ca4ad6ca2b8ad6c3f9c46a06e934c19b95e8eChristopher Wiley for line in self.stdout.splitlines(): 50993ca4ad6ca2b8ad6c3f9c46a06e934c19b95e8eChristopher Wiley output.append(' > %s' % line) 51993ca4ad6ca2b8ad6c3f9c46a06e934c19b95e8eChristopher Wiley output.append('stderr:') 52993ca4ad6ca2b8ad6c3f9c46a06e934c19b95e8eChristopher Wiley for line in self.stderr.splitlines(): 53993ca4ad6ca2b8ad6c3f9c46a06e934c19b95e8eChristopher Wiley output.append(' > %s' % line) 54993ca4ad6ca2b8ad6c3f9c46a06e934c19b95e8eChristopher Wiley return '\n'.join(output) 55993ca4ad6ca2b8ad6c3f9c46a06e934c19b95e8eChristopher Wiley 56993ca4ad6ca2b8ad6c3f9c46a06e934c19b95e8eChristopher Wiley 57993ca4ad6ca2b8ad6c3f9c46a06e934c19b95e8eChristopher Wileyclass AdbHost(object): 58993ca4ad6ca2b8ad6c3f9c46a06e934c19b95e8eChristopher Wiley """Represents a device connected via ADB.""" 59993ca4ad6ca2b8ad6c3f9c46a06e934c19b95e8eChristopher Wiley 60993ca4ad6ca2b8ad6c3f9c46a06e934c19b95e8eChristopher Wiley def __init__(self, device_serial=None, verbose=None): 61993ca4ad6ca2b8ad6c3f9c46a06e934c19b95e8eChristopher Wiley """Construct an instance. 62993ca4ad6ca2b8ad6c3f9c46a06e934c19b95e8eChristopher Wiley 63993ca4ad6ca2b8ad6c3f9c46a06e934c19b95e8eChristopher Wiley Args: 64993ca4ad6ca2b8ad6c3f9c46a06e934c19b95e8eChristopher Wiley device_serial: options string serial number of attached device. 65993ca4ad6ca2b8ad6c3f9c46a06e934c19b95e8eChristopher Wiley verbose: True iff we should print out ADB commands we run. 66993ca4ad6ca2b8ad6c3f9c46a06e934c19b95e8eChristopher Wiley """ 67993ca4ad6ca2b8ad6c3f9c46a06e934c19b95e8eChristopher Wiley self._device_serial = device_serial 68993ca4ad6ca2b8ad6c3f9c46a06e934c19b95e8eChristopher Wiley self._verbose = verbose 69993ca4ad6ca2b8ad6c3f9c46a06e934c19b95e8eChristopher Wiley 70993ca4ad6ca2b8ad6c3f9c46a06e934c19b95e8eChristopher Wiley def run(self, command, background=False, ignore_status=False): 71993ca4ad6ca2b8ad6c3f9c46a06e934c19b95e8eChristopher Wiley """Run a command on the device via adb shell. 72993ca4ad6ca2b8ad6c3f9c46a06e934c19b95e8eChristopher Wiley 73993ca4ad6ca2b8ad6c3f9c46a06e934c19b95e8eChristopher Wiley Args: 74993ca4ad6ca2b8ad6c3f9c46a06e934c19b95e8eChristopher Wiley command: string containing a shell command to run. 75993ca4ad6ca2b8ad6c3f9c46a06e934c19b95e8eChristopher Wiley background: True iff we should run this command in the background. 76993ca4ad6ca2b8ad6c3f9c46a06e934c19b95e8eChristopher Wiley ignore_status: True iff we should ignore the command's exit code. 77993ca4ad6ca2b8ad6c3f9c46a06e934c19b95e8eChristopher Wiley 78993ca4ad6ca2b8ad6c3f9c46a06e934c19b95e8eChristopher Wiley Returns: 79993ca4ad6ca2b8ad6c3f9c46a06e934c19b95e8eChristopher Wiley instance of ShellResult. 80993ca4ad6ca2b8ad6c3f9c46a06e934c19b95e8eChristopher Wiley 81993ca4ad6ca2b8ad6c3f9c46a06e934c19b95e8eChristopher Wiley Raises: 82993ca4ad6ca2b8ad6c3f9c46a06e934c19b95e8eChristopher Wiley subprocess.CalledProcessError on command exit != 0. 83993ca4ad6ca2b8ad6c3f9c46a06e934c19b95e8eChristopher Wiley """ 84993ca4ad6ca2b8ad6c3f9c46a06e934c19b95e8eChristopher Wiley if background: 85993ca4ad6ca2b8ad6c3f9c46a06e934c19b95e8eChristopher Wiley command = '( %s ) </dev/null >/dev/null 2>&1 &' % command 86993ca4ad6ca2b8ad6c3f9c46a06e934c19b95e8eChristopher Wiley return self.adb('shell %s' % pipes.quote(command), 87993ca4ad6ca2b8ad6c3f9c46a06e934c19b95e8eChristopher Wiley ignore_status=ignore_status) 88993ca4ad6ca2b8ad6c3f9c46a06e934c19b95e8eChristopher Wiley 89993ca4ad6ca2b8ad6c3f9c46a06e934c19b95e8eChristopher Wiley def mktemp(self): 90993ca4ad6ca2b8ad6c3f9c46a06e934c19b95e8eChristopher Wiley """Make a temp file on the device. 91993ca4ad6ca2b8ad6c3f9c46a06e934c19b95e8eChristopher Wiley 92993ca4ad6ca2b8ad6c3f9c46a06e934c19b95e8eChristopher Wiley Returns: 93993ca4ad6ca2b8ad6c3f9c46a06e934c19b95e8eChristopher Wiley path to created file as a string 94993ca4ad6ca2b8ad6c3f9c46a06e934c19b95e8eChristopher Wiley 95993ca4ad6ca2b8ad6c3f9c46a06e934c19b95e8eChristopher Wiley Raises: 96993ca4ad6ca2b8ad6c3f9c46a06e934c19b95e8eChristopher Wiley subprocess.CalledProcessError on failure. 97993ca4ad6ca2b8ad6c3f9c46a06e934c19b95e8eChristopher Wiley """ 98993ca4ad6ca2b8ad6c3f9c46a06e934c19b95e8eChristopher Wiley # Work around b/19635681 99993ca4ad6ca2b8ad6c3f9c46a06e934c19b95e8eChristopher Wiley result = self.run('source /system/etc/mkshrc && mktemp') 100993ca4ad6ca2b8ad6c3f9c46a06e934c19b95e8eChristopher Wiley return result.stdout.strip() 101993ca4ad6ca2b8ad6c3f9c46a06e934c19b95e8eChristopher Wiley 102993ca4ad6ca2b8ad6c3f9c46a06e934c19b95e8eChristopher Wiley def adb(self, command, ignore_status=False): 103993ca4ad6ca2b8ad6c3f9c46a06e934c19b95e8eChristopher Wiley """Run an ADB command (e.g. `adb sync`). 104993ca4ad6ca2b8ad6c3f9c46a06e934c19b95e8eChristopher Wiley 105993ca4ad6ca2b8ad6c3f9c46a06e934c19b95e8eChristopher Wiley Args: 106993ca4ad6ca2b8ad6c3f9c46a06e934c19b95e8eChristopher Wiley command: string containing command to run 107993ca4ad6ca2b8ad6c3f9c46a06e934c19b95e8eChristopher Wiley ignore_status: True iff we should ignore the command's exit code. 108993ca4ad6ca2b8ad6c3f9c46a06e934c19b95e8eChristopher Wiley 109993ca4ad6ca2b8ad6c3f9c46a06e934c19b95e8eChristopher Wiley Returns: 110993ca4ad6ca2b8ad6c3f9c46a06e934c19b95e8eChristopher Wiley instance of ShellResult. 111993ca4ad6ca2b8ad6c3f9c46a06e934c19b95e8eChristopher Wiley 112993ca4ad6ca2b8ad6c3f9c46a06e934c19b95e8eChristopher Wiley Raises: 113993ca4ad6ca2b8ad6c3f9c46a06e934c19b95e8eChristopher Wiley subprocess.CalledProcessError on command exit != 0. 114993ca4ad6ca2b8ad6c3f9c46a06e934c19b95e8eChristopher Wiley """ 115993ca4ad6ca2b8ad6c3f9c46a06e934c19b95e8eChristopher Wiley command = 'adb %s' % command 116993ca4ad6ca2b8ad6c3f9c46a06e934c19b95e8eChristopher Wiley if self._verbose: 117993ca4ad6ca2b8ad6c3f9c46a06e934c19b95e8eChristopher Wiley print(command) 118993ca4ad6ca2b8ad6c3f9c46a06e934c19b95e8eChristopher Wiley p = subprocess.Popen(command, shell=True, close_fds=True, 119993ca4ad6ca2b8ad6c3f9c46a06e934c19b95e8eChristopher Wiley stdout=subprocess.PIPE, stderr=subprocess.PIPE, 120993ca4ad6ca2b8ad6c3f9c46a06e934c19b95e8eChristopher Wiley universal_newlines=True) 121993ca4ad6ca2b8ad6c3f9c46a06e934c19b95e8eChristopher Wiley stdout, stderr = p.communicate() 122993ca4ad6ca2b8ad6c3f9c46a06e934c19b95e8eChristopher Wiley if not ignore_status and p.returncode: 123993ca4ad6ca2b8ad6c3f9c46a06e934c19b95e8eChristopher Wiley raise subprocess.CalledProcessError(p.returncode, command) 124993ca4ad6ca2b8ad6c3f9c46a06e934c19b95e8eChristopher Wiley return ShellResult(p.returncode, stdout, stderr) 125993ca4ad6ca2b8ad6c3f9c46a06e934c19b95e8eChristopher Wiley 126993ca4ad6ca2b8ad6c3f9c46a06e934c19b95e8eChristopher Wiley 127cce25d35d2ee5a80568eec4d504f65fa790473d4Christopher Wileydef run_test(host, test_native, test_java): 128993ca4ad6ca2b8ad6c3f9c46a06e934c19b95e8eChristopher Wiley """Body of the test. 129993ca4ad6ca2b8ad6c3f9c46a06e934c19b95e8eChristopher Wiley 130993ca4ad6ca2b8ad6c3f9c46a06e934c19b95e8eChristopher Wiley Args: 131cce25d35d2ee5a80568eec4d504f65fa790473d4Christopher Wiley host: AdbHost object to run tests on 132993ca4ad6ca2b8ad6c3f9c46a06e934c19b95e8eChristopher Wiley test_native: True iff we should test native Binder clients. 133993ca4ad6ca2b8ad6c3f9c46a06e934c19b95e8eChristopher Wiley test_java: True iff we shoudl test Java Binder clients. 134993ca4ad6ca2b8ad6c3f9c46a06e934c19b95e8eChristopher Wiley """ 135993ca4ad6ca2b8ad6c3f9c46a06e934c19b95e8eChristopher Wiley 136993ca4ad6ca2b8ad6c3f9c46a06e934c19b95e8eChristopher Wiley print('Starting aidl integration testing...') 137cce25d35d2ee5a80568eec4d504f65fa790473d4Christopher Wiley 138993ca4ad6ca2b8ad6c3f9c46a06e934c19b95e8eChristopher Wiley # Kill any previous test context 139e7c4ea5abb2224ad570de982b93568481af2f538Christopher Wiley host.run('rm -f %s' % JAVA_LOG_FILE, ignore_status=True) 140993ca4ad6ca2b8ad6c3f9c46a06e934c19b95e8eChristopher Wiley host.run('pkill %s' % NATIVE_TEST_SERVICE, ignore_status=True) 141993ca4ad6ca2b8ad6c3f9c46a06e934c19b95e8eChristopher Wiley 142993ca4ad6ca2b8ad6c3f9c46a06e934c19b95e8eChristopher Wiley # Start up a native server 143993ca4ad6ca2b8ad6c3f9c46a06e934c19b95e8eChristopher Wiley host.run(NATIVE_TEST_SERVICE, background=True) 144993ca4ad6ca2b8ad6c3f9c46a06e934c19b95e8eChristopher Wiley 145993ca4ad6ca2b8ad6c3f9c46a06e934c19b95e8eChristopher Wiley # Start up clients 146993ca4ad6ca2b8ad6c3f9c46a06e934c19b95e8eChristopher Wiley if test_native: 147d03d72656dca38e85d8187237f8369177b7b9262Christopher Wiley host.run('pkill %s' % NATIVE_TEST_CLIENT, ignore_status=True) 148993ca4ad6ca2b8ad6c3f9c46a06e934c19b95e8eChristopher Wiley result = host.run(NATIVE_TEST_CLIENT, ignore_status=True) 149993ca4ad6ca2b8ad6c3f9c46a06e934c19b95e8eChristopher Wiley if result.exit_status: 150993ca4ad6ca2b8ad6c3f9c46a06e934c19b95e8eChristopher Wiley print(result.printable_string()) 151993ca4ad6ca2b8ad6c3f9c46a06e934c19b95e8eChristopher Wiley raise TestFail('%s returned status code %d' % 152993ca4ad6ca2b8ad6c3f9c46a06e934c19b95e8eChristopher Wiley (NATIVE_TEST_CLIENT, result.exit_status)) 153993ca4ad6ca2b8ad6c3f9c46a06e934c19b95e8eChristopher Wiley 154993ca4ad6ca2b8ad6c3f9c46a06e934c19b95e8eChristopher Wiley if test_java: 155993ca4ad6ca2b8ad6c3f9c46a06e934c19b95e8eChristopher Wiley host.run('am start -S -a android.intent.action.MAIN ' 156993ca4ad6ca2b8ad6c3f9c46a06e934c19b95e8eChristopher Wiley '-n android.aidl.tests/.TestServiceClient ' 157993ca4ad6ca2b8ad6c3f9c46a06e934c19b95e8eChristopher Wiley '--es sentinel.success "%s" ' 158993ca4ad6ca2b8ad6c3f9c46a06e934c19b95e8eChristopher Wiley '--es sentinel.failure "%s"' % 159993ca4ad6ca2b8ad6c3f9c46a06e934c19b95e8eChristopher Wiley (JAVA_SUCCESS_SENTINEL, JAVA_FAILURE_SENTINEL)) 160993ca4ad6ca2b8ad6c3f9c46a06e934c19b95e8eChristopher Wiley result = host.run('%s %d %s "%s" "%s"' % 161993ca4ad6ca2b8ad6c3f9c46a06e934c19b95e8eChristopher Wiley (JAVA_OUTPUT_READER, JAVA_CLIENT_TIMEOUT_SECONDS, 162993ca4ad6ca2b8ad6c3f9c46a06e934c19b95e8eChristopher Wiley JAVA_LOG_FILE, JAVA_SUCCESS_SENTINEL, 163993ca4ad6ca2b8ad6c3f9c46a06e934c19b95e8eChristopher Wiley JAVA_FAILURE_SENTINEL), 164993ca4ad6ca2b8ad6c3f9c46a06e934c19b95e8eChristopher Wiley ignore_status=True) 165993ca4ad6ca2b8ad6c3f9c46a06e934c19b95e8eChristopher Wiley if result.exit_status: 166993ca4ad6ca2b8ad6c3f9c46a06e934c19b95e8eChristopher Wiley print(result.printable_string()) 167993ca4ad6ca2b8ad6c3f9c46a06e934c19b95e8eChristopher Wiley raise TestFail('Java client did not complete successfully.') 168993ca4ad6ca2b8ad6c3f9c46a06e934c19b95e8eChristopher Wiley 169993ca4ad6ca2b8ad6c3f9c46a06e934c19b95e8eChristopher Wiley print('Success!') 170993ca4ad6ca2b8ad6c3f9c46a06e934c19b95e8eChristopher Wiley 171993ca4ad6ca2b8ad6c3f9c46a06e934c19b95e8eChristopher Wiley 172993ca4ad6ca2b8ad6c3f9c46a06e934c19b95e8eChristopher Wileydef main(): 173993ca4ad6ca2b8ad6c3f9c46a06e934c19b95e8eChristopher Wiley """Main entry point.""" 174993ca4ad6ca2b8ad6c3f9c46a06e934c19b95e8eChristopher Wiley parser = argparse.ArgumentParser(description=__doc__) 175993ca4ad6ca2b8ad6c3f9c46a06e934c19b95e8eChristopher Wiley parser.add_argument( 176993ca4ad6ca2b8ad6c3f9c46a06e934c19b95e8eChristopher Wiley '--test-filter', default=TEST_FILTER_ALL, 177993ca4ad6ca2b8ad6c3f9c46a06e934c19b95e8eChristopher Wiley choices=[TEST_FILTER_ALL, TEST_FILTER_JAVA, TEST_FILTER_NATIVE]) 178993ca4ad6ca2b8ad6c3f9c46a06e934c19b95e8eChristopher Wiley parser.add_argument('--verbose', '-v', action='store_true', default=False) 179993ca4ad6ca2b8ad6c3f9c46a06e934c19b95e8eChristopher Wiley args = parser.parse_args() 180cce25d35d2ee5a80568eec4d504f65fa790473d4Christopher Wiley host = AdbHost(verbose=args.verbose) 181cce25d35d2ee5a80568eec4d504f65fa790473d4Christopher Wiley try: 182cce25d35d2ee5a80568eec4d504f65fa790473d4Christopher Wiley # Tragically, SELinux interferes with our testing 183cce25d35d2ee5a80568eec4d504f65fa790473d4Christopher Wiley host.run('setenforce 0') 184cce25d35d2ee5a80568eec4d504f65fa790473d4Christopher Wiley run_test(host, 185cce25d35d2ee5a80568eec4d504f65fa790473d4Christopher Wiley args.test_filter in (TEST_FILTER_ALL, TEST_FILTER_NATIVE), 186cce25d35d2ee5a80568eec4d504f65fa790473d4Christopher Wiley args.test_filter in (TEST_FILTER_ALL, TEST_FILTER_JAVA)) 187cce25d35d2ee5a80568eec4d504f65fa790473d4Christopher Wiley finally: 188cce25d35d2ee5a80568eec4d504f65fa790473d4Christopher Wiley host.run('setenforce 1') 189993ca4ad6ca2b8ad6c3f9c46a06e934c19b95e8eChristopher Wiley 190993ca4ad6ca2b8ad6c3f9c46a06e934c19b95e8eChristopher Wiley 191993ca4ad6ca2b8ad6c3f9c46a06e934c19b95e8eChristopher Wileyif __name__ == '__main__': 192993ca4ad6ca2b8ad6c3f9c46a06e934c19b95e8eChristopher Wiley main() 193