You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
242 lines
8.4 KiB
242 lines
8.4 KiB
#!/usr/bin/env python3
|
|
|
|
import pipes
|
|
import re
|
|
import subprocess
|
|
import sys
|
|
import unittest
|
|
|
|
BITNESS_32 = ("", "32")
|
|
BITNESS_64 = ("64", "64")
|
|
|
|
APP_PROCESS_FOR_PRETTY_BITNESS = 'app_process%s'
|
|
NATIVE_TEST_SERVICE_FOR_BITNESS = ' /data/nativetest%s/aidl_test_service/aidl_test_service%s'
|
|
CPP_TEST_CLIENT_FOR_BITNESS = ' /data/nativetest%s/aidl_test_client/aidl_test_client%s'
|
|
NDK_TEST_CLIENT_FOR_BITNESS = ' /data/nativetest%s/aidl_test_client_ndk/aidl_test_client_ndk%s'
|
|
RUST_TEST_CLIENT_FOR_BITNESS = ' /data/nativetest%s/aidl_test_rust_client/aidl_test_rust_client%s'
|
|
RUST_TEST_SERVICE_FOR_BITNESS = ' /data/nativetest%s/aidl_test_rust_service/aidl_test_rust_service%s'
|
|
|
|
# From AidlTestsJava.java
|
|
INSTRUMENTATION_SUCCESS_PATTERN = r'TEST SUCCESS\n$'
|
|
|
|
class TestFail(Exception):
|
|
"""Raised on test failures."""
|
|
pass
|
|
|
|
def pretty_bitness(bitness):
|
|
"""Returns a human readable version of bitness, corresponding to BITNESS_* variable"""
|
|
return bitness[-1]
|
|
|
|
class ShellResult(object):
|
|
"""Represents the result of running a shell command."""
|
|
|
|
def __init__(self, exit_status, stdout, stderr):
|
|
"""Construct an instance.
|
|
|
|
Args:
|
|
exit_status: integer exit code of shell command
|
|
stdout: string stdout of shell command
|
|
stderr: string stderr of shell command
|
|
"""
|
|
self.stdout = stdout
|
|
self.stderr = stderr
|
|
self.exit_status = exit_status
|
|
|
|
def printable_string(self):
|
|
"""Get a string we could print to the logs and understand."""
|
|
output = []
|
|
output.append('stdout:')
|
|
for line in self.stdout.splitlines():
|
|
output.append(' > %s' % line)
|
|
output.append('stderr:')
|
|
for line in self.stderr.splitlines():
|
|
output.append(' > %s' % line)
|
|
return '\n'.join(output)
|
|
|
|
|
|
class AdbHost(object):
|
|
"""Represents a device connected via ADB."""
|
|
|
|
def run(self, command, background=False, ignore_status=False):
|
|
"""Run a command on the device via adb shell.
|
|
|
|
Args:
|
|
command: string containing a shell command to run.
|
|
background: True iff we should run this command in the background.
|
|
ignore_status: True iff we should ignore the command's exit code.
|
|
|
|
Returns:
|
|
instance of ShellResult.
|
|
|
|
Raises:
|
|
subprocess.CalledProcessError on command exit != 0.
|
|
"""
|
|
if background:
|
|
command = '( %s ) </dev/null >/dev/null 2>&1 &' % command
|
|
return self.adb('shell %s' % pipes.quote(command),
|
|
ignore_status=ignore_status)
|
|
|
|
def adb(self, command, ignore_status=False):
|
|
"""Run an ADB command (e.g. `adb sync`).
|
|
|
|
Args:
|
|
command: string containing command to run
|
|
ignore_status: True iff we should ignore the command's exit code.
|
|
|
|
Returns:
|
|
instance of ShellResult.
|
|
|
|
Raises:
|
|
subprocess.CalledProcessError on command exit != 0.
|
|
"""
|
|
command = 'adb %s' % command
|
|
p = subprocess.Popen(command, shell=True, close_fds=True,
|
|
stdout=subprocess.PIPE, stderr=subprocess.PIPE,
|
|
universal_newlines=True)
|
|
stdout, stderr = p.communicate()
|
|
if not ignore_status and p.returncode:
|
|
raise subprocess.CalledProcessError(p.returncode, command)
|
|
return ShellResult(p.returncode, stdout, stderr)
|
|
|
|
class NativeServer:
|
|
def __init__(self, host, bitness):
|
|
self.name = "%s_bit_native_server" % pretty_bitness(bitness)
|
|
self.host = host
|
|
self.binary = NATIVE_TEST_SERVICE_FOR_BITNESS % bitness
|
|
def cleanup(self):
|
|
self.host.run('killall %s' % self.binary, ignore_status=True)
|
|
def run(self):
|
|
return self.host.run(self.binary, background=True)
|
|
|
|
class NativeClient:
|
|
def cleanup(self):
|
|
self.host.run('killall %s' % self.binary, ignore_status=True)
|
|
def run(self):
|
|
result = self.host.run(self.binary + ' --gtest_color=yes', ignore_status=True)
|
|
print(result.printable_string())
|
|
if result.exit_status:
|
|
raise TestFail(result.stdout)
|
|
|
|
class CppClient(NativeClient):
|
|
def __init__(self, host, bitness):
|
|
self.name = "%s_bit_cpp_client" % pretty_bitness(bitness)
|
|
self.host = host
|
|
self.binary = CPP_TEST_CLIENT_FOR_BITNESS % bitness
|
|
|
|
class NdkClient(NativeClient):
|
|
def __init__(self, host, bitness):
|
|
self.name = "%s_bit_ndk_client" % pretty_bitness(bitness)
|
|
self.host = host
|
|
self.binary = NDK_TEST_CLIENT_FOR_BITNESS % bitness
|
|
|
|
class JavaServer:
|
|
def __init__(self, host, bitness):
|
|
self.name = "java_server_%s" % pretty_bitness(bitness)
|
|
self.host = host
|
|
self.bitness = bitness
|
|
def cleanup(self):
|
|
self.host.run('killall ' + APP_PROCESS_FOR_PRETTY_BITNESS % pretty_bitness(self.bitness),
|
|
ignore_status=True)
|
|
def run(self):
|
|
return self.host.run('CLASSPATH=/data/framework/aidl_test_java_service.jar '
|
|
+ APP_PROCESS_FOR_PRETTY_BITNESS % pretty_bitness(self.bitness) +
|
|
' /data/framework android.aidl.service.TestServiceServer',
|
|
background=True)
|
|
|
|
class JavaClient:
|
|
def __init__(self, host, bitness):
|
|
self.name = "java_client_%s" % pretty_bitness(bitness)
|
|
self.host = host
|
|
self.bitness = bitness
|
|
def cleanup(self):
|
|
self.host.run('killall ' + APP_PROCESS_FOR_PRETTY_BITNESS % pretty_bitness(self.bitness),
|
|
ignore_status=True)
|
|
def run(self):
|
|
result = self.host.run('CLASSPATH=/data/framework/aidl_test_java_client.jar '
|
|
+ APP_PROCESS_FOR_PRETTY_BITNESS % pretty_bitness(self.bitness) +
|
|
' /data/framework android.aidl.tests.AidlJavaTests')
|
|
print(result.printable_string())
|
|
if re.search(INSTRUMENTATION_SUCCESS_PATTERN, result.stdout) is None:
|
|
raise TestFail(result.stdout)
|
|
|
|
def getprop(host, prop):
|
|
return host.run('getprop "%s"' % prop).stdout.strip()
|
|
|
|
class RustClient:
|
|
def __init__(self, host, bitness):
|
|
self.name = "%s_bit_rust_client" % pretty_bitness(bitness)
|
|
self.host = host
|
|
self.binary = RUST_TEST_CLIENT_FOR_BITNESS % bitness
|
|
def cleanup(self):
|
|
self.host.run('killall %s' % self.binary, ignore_status=True)
|
|
def run(self):
|
|
result = self.host.run(self.binary, ignore_status=True)
|
|
print(result.printable_string())
|
|
if result.exit_status:
|
|
raise TestFail(result.stdout)
|
|
|
|
class RustServer:
|
|
def __init__(self, host, bitness):
|
|
self.name = "%s_bit_rust_server" % pretty_bitness(bitness)
|
|
self.host = host
|
|
self.binary = RUST_TEST_SERVICE_FOR_BITNESS % bitness
|
|
def cleanup(self):
|
|
self.host.run('killall %s' % self.binary, ignore_status=True)
|
|
def run(self):
|
|
return self.host.run(self.binary, background=True)
|
|
|
|
def supported_bitnesses(host):
|
|
bitnesses = []
|
|
if getprop(host, "ro.product.cpu.abilist32") != "":
|
|
bitnesses += [BITNESS_32]
|
|
if getprop(host, "ro.product.cpu.abilist64") != "":
|
|
bitnesses += [BITNESS_64]
|
|
return bitnesses
|
|
|
|
# tests added dynamically below
|
|
class TestAidl(unittest.TestCase):
|
|
pass
|
|
|
|
def make_test(client, server):
|
|
def test(self):
|
|
try:
|
|
client.cleanup()
|
|
server.cleanup()
|
|
server.run()
|
|
client.run()
|
|
finally:
|
|
client.cleanup()
|
|
server.cleanup()
|
|
return test
|
|
|
|
if __name__ == '__main__':
|
|
host = AdbHost()
|
|
bitnesses = supported_bitnesses(host)
|
|
if len(bitnesses) == 0:
|
|
print("No clients installed")
|
|
exit(1)
|
|
|
|
clients = []
|
|
servers = []
|
|
|
|
for bitness in bitnesses:
|
|
clients += [NdkClient(host, bitness)]
|
|
|
|
clients += [CppClient(host, bitness)]
|
|
servers += [NativeServer(host, bitness)]
|
|
|
|
clients += [JavaClient(host, bitness)]
|
|
servers += [JavaServer(host, bitness)]
|
|
|
|
clients += [RustClient(host, bitness)]
|
|
servers += [RustServer(host, bitness)]
|
|
|
|
for client in clients:
|
|
for server in servers:
|
|
test_name = 'test_%s_to_%s' % (client.name, server.name)
|
|
test = make_test(client, server)
|
|
setattr(TestAidl, test_name, test)
|
|
|
|
suite = unittest.TestLoader().loadTestsFromTestCase(TestAidl)
|
|
sys.exit(not unittest.TextTestRunner(verbosity=2).run(suite).wasSuccessful())
|