• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1#!/usr/bin/env python3
2
3from itertools import product
4import pipes
5import re
6import subprocess
7import sys
8import unittest
9
10BITNESS_32 = ("", "32")
11BITNESS_64 = ("64", "64")
12
13APP_PROCESS_FOR_PRETTY_BITNESS = 'app_process%s'
14NATIVE_TEST_SERVICE_FOR_BITNESS = ' /data/nativetest%s/aidl_test_service/aidl_test_service%s'
15CPP_TEST_CLIENT_FOR_BITNESS = ' /data/nativetest%s/aidl_test_client/aidl_test_client%s'
16NDK_TEST_CLIENT_FOR_BITNESS = ' /data/nativetest%s/aidl_test_client_ndk/aidl_test_client_ndk%s'
17RUST_TEST_CLIENT_FOR_BITNESS = ' /data/nativetest%s/aidl_test_rust_client/aidl_test_rust_client%s'
18RUST_TEST_SERVICE_FOR_BITNESS = ' /data/nativetest%s/aidl_test_rust_service/aidl_test_rust_service%s'
19
20# From AidlTestsJava.java
21INSTRUMENTATION_SUCCESS_PATTERN = r'TEST SUCCESS\n$'
22
23class TestFail(Exception):
24    """Raised on test failures."""
25    pass
26
27def pretty_bitness(bitness):
28    """Returns a human readable version of bitness, corresponding to BITNESS_* variable"""
29    return bitness[-1]
30
31class ShellResult(object):
32    """Represents the result of running a shell command."""
33
34    def __init__(self, exit_status, stdout, stderr):
35        """Construct an instance.
36
37        Args:
38            exit_status: integer exit code of shell command
39            stdout: string stdout of shell command
40            stderr: string stderr of shell command
41        """
42        self.stdout = stdout
43        self.stderr = stderr
44        self.exit_status = exit_status
45
46    def printable_string(self):
47        """Get a string we could print to the logs and understand."""
48        output = []
49        output.append('stdout:')
50        for line in self.stdout.splitlines():
51            output.append('  > %s' % line)
52        output.append('stderr:')
53        for line in self.stderr.splitlines():
54            output.append('  > %s' % line)
55        return '\n'.join(output)
56
57
58class AdbHost(object):
59    """Represents a device connected via ADB."""
60
61    def run(self, command, background=False, ignore_status=False):
62        """Run a command on the device via adb shell.
63
64        Args:
65            command: string containing a shell command to run.
66            background: True iff we should run this command in the background.
67            ignore_status: True iff we should ignore the command's exit code.
68
69        Returns:
70            instance of ShellResult.
71
72        Raises:
73            subprocess.CalledProcessError on command exit != 0.
74        """
75        if background:
76            command = '( %s ) </dev/null >/dev/null 2>&1 &' % command
77        return self.adb('shell %s' % pipes.quote(command),
78                        ignore_status=ignore_status)
79
80    def adb(self, command, ignore_status=False):
81        """Run an ADB command (e.g. `adb sync`).
82
83        Args:
84            command: string containing command to run
85            ignore_status: True iff we should ignore the command's exit code.
86
87        Returns:
88            instance of ShellResult.
89
90        Raises:
91            subprocess.CalledProcessError on command exit != 0.
92        """
93        command = 'adb %s' % command
94        p = subprocess.Popen(command, shell=True, close_fds=True,
95                             stdout=subprocess.PIPE, stderr=subprocess.PIPE,
96                             universal_newlines=True)
97        stdout, stderr = p.communicate()
98        if not ignore_status and p.returncode:
99            raise subprocess.CalledProcessError(p.returncode, command)
100        return ShellResult(p.returncode, stdout, stderr)
101
102class NativeServer:
103    def __init__(self, host, bitness):
104        self.name = "%s_bit_native_server" % pretty_bitness(bitness)
105        self.host = host
106        self.binary = NATIVE_TEST_SERVICE_FOR_BITNESS % bitness
107    def cleanup(self):
108        self.host.run('killall %s' % self.binary, ignore_status=True)
109    def run(self):
110        return self.host.run(self.binary, background=True)
111
112class NativeClient:
113    def cleanup(self):
114        self.host.run('killall %s' % self.binary, ignore_status=True)
115    def run(self):
116        result = self.host.run(self.binary + ' --gtest_color=yes', ignore_status=True)
117        print(result.printable_string())
118        if result.exit_status:
119            raise TestFail(result.stdout)
120
121class CppClient(NativeClient):
122    def __init__(self, host, bitness):
123        self.name = "%s_bit_cpp_client" % pretty_bitness(bitness)
124        self.host = host
125        self.binary = CPP_TEST_CLIENT_FOR_BITNESS % bitness
126
127class NdkClient(NativeClient):
128    def __init__(self, host, bitness):
129        self.name = "%s_bit_ndk_client" % pretty_bitness(bitness)
130        self.host = host
131        self.binary = NDK_TEST_CLIENT_FOR_BITNESS % bitness
132
133class JavaServer:
134    def __init__(self, host, bitness):
135        self.name = "java_server_%s" % pretty_bitness(bitness)
136        self.host = host
137        self.bitness = bitness
138    def cleanup(self):
139        self.host.run('killall ' + APP_PROCESS_FOR_PRETTY_BITNESS % pretty_bitness(self.bitness),
140                      ignore_status=True)
141    def run(self):
142        return self.host.run('CLASSPATH=/data/framework/aidl_test_java_service.jar '
143                             + APP_PROCESS_FOR_PRETTY_BITNESS % pretty_bitness(self.bitness) +
144                             ' /data/framework android.aidl.service.TestServiceServer',
145                             background=True)
146
147class JavaClient:
148    def __init__(self, host, bitness):
149        self.name = "java_client_%s" % pretty_bitness(bitness)
150        self.host = host
151        self.bitness = bitness
152    def cleanup(self):
153        self.host.run('killall ' + APP_PROCESS_FOR_PRETTY_BITNESS % pretty_bitness(self.bitness),
154                      ignore_status=True)
155    def run(self):
156        result = self.host.run('CLASSPATH=/data/framework/aidl_test_java_client.jar '
157                               + APP_PROCESS_FOR_PRETTY_BITNESS % pretty_bitness(self.bitness) +
158                               ' /data/framework android.aidl.tests.AidlJavaTests')
159        print(result.printable_string())
160        if re.search(INSTRUMENTATION_SUCCESS_PATTERN, result.stdout) is None:
161            raise TestFail(result.stdout)
162
163class JavaVersionTestClient:
164    def __init__(self, host, bitness, ver):
165        self.name = "java_client_sdk%d_%s" % (ver, pretty_bitness(bitness))
166        self.host = host
167        self.bitness = bitness
168        self.ver = ver
169    def cleanup(self):
170        self.host.run('killall ' + APP_PROCESS_FOR_PRETTY_BITNESS % pretty_bitness(self.bitness),
171                      ignore_status=True)
172    def run(self):
173        result = self.host.run('CLASSPATH=/data/framework/aidl_test_java_client_sdk%d.jar ' % self.ver
174                               + APP_PROCESS_FOR_PRETTY_BITNESS % pretty_bitness(self.bitness) +
175                               ' /data/framework android.aidl.sdkversion.tests.AidlJavaVersionTests')
176        print(result.printable_string())
177        if re.search(INSTRUMENTATION_SUCCESS_PATTERN, result.stdout) is None:
178            raise TestFail(result.stdout)
179
180class JavaVersionTestServer:
181    def __init__(self, host, bitness, ver):
182        self.name = "java_server_sdk%s_%s" % (ver, pretty_bitness(bitness))
183        self.host = host
184        self.bitness = bitness
185        self.ver = ver
186    def cleanup(self):
187        self.host.run('killall ' + APP_PROCESS_FOR_PRETTY_BITNESS % pretty_bitness(self.bitness),
188                      ignore_status=True)
189    def run(self):
190        return self.host.run('CLASSPATH=/data/framework/aidl_test_java_service_sdk%d.jar ' % self.ver
191                             + APP_PROCESS_FOR_PRETTY_BITNESS % pretty_bitness(self.bitness) +
192                             ' /data/framework android.aidl.sdkversion.service.AidlJavaVersionTestService',
193                             background=True)
194
195def getprop(host, prop):
196    return host.run('getprop "%s"' % prop).stdout.strip()
197
198class RustClient:
199    def __init__(self, host, bitness):
200        self.name = "%s_bit_rust_client" % pretty_bitness(bitness)
201        self.host = host
202        self.binary = RUST_TEST_CLIENT_FOR_BITNESS % bitness
203    def cleanup(self):
204        self.host.run('killall %s' % self.binary, ignore_status=True)
205    def run(self):
206        result = self.host.run(self.binary, ignore_status=True)
207        print(result.printable_string())
208        if result.exit_status:
209            raise TestFail(result.stdout)
210
211class RustServer:
212    def __init__(self, host, bitness):
213        self.name = "%s_bit_rust_server" % pretty_bitness(bitness)
214        self.host = host
215        self.binary = RUST_TEST_SERVICE_FOR_BITNESS % bitness
216    def cleanup(self):
217        self.host.run('killall %s' % self.binary, ignore_status=True)
218    def run(self):
219        return self.host.run(self.binary, background=True)
220
221class RustAsyncServer:
222    def __init__(self, host, bitness):
223        self.name = "%s_bit_rust_server_async" % pretty_bitness(bitness)
224        self.host = host
225        self.binary = RUST_TEST_SERVICE_FOR_BITNESS % bitness
226    def cleanup(self):
227        self.host.run('killall %s' % self.binary, ignore_status=True)
228    def run(self):
229        return self.host.run(self.binary, background=True)
230
231def supported_bitnesses(host):
232    bitnesses = []
233    if getprop(host, "ro.product.cpu.abilist32") != "":
234        bitnesses += [BITNESS_32]
235    if getprop(host, "ro.product.cpu.abilist64") != "":
236        bitnesses += [BITNESS_64]
237    return bitnesses
238
239# tests added dynamically below
240class TestAidl(unittest.TestCase):
241    pass
242
243def make_test(client, server):
244    def test(self):
245        try:
246            client.cleanup()
247            server.cleanup()
248            server.run()
249            client.run()
250        finally:
251            client.cleanup()
252            server.cleanup()
253    return test
254
255def add_test(client, server):
256    test_name = 'test_%s_to_%s' % (client.name, server.name)
257    test = make_test(client, server)
258    setattr(TestAidl, test_name, test)
259
260if __name__ == '__main__':
261    host = AdbHost()
262    bitnesses = supported_bitnesses(host)
263    if len(bitnesses) == 0:
264        print("No clients installed")
265        exit(1)
266
267    clients = []
268    servers = []
269
270    for bitness in bitnesses:
271        clients += [NdkClient(host, bitness)]
272
273        clients += [CppClient(host, bitness)]
274        servers += [NativeServer(host, bitness)]
275
276        clients += [JavaClient(host, bitness)]
277        servers += [JavaServer(host, bitness)]
278
279        clients += [RustClient(host, bitness)]
280        servers += [RustServer(host, bitness)]
281        servers += [RustAsyncServer(host, bitness)]
282
283    for client in clients:
284        for server in servers:
285            add_test(client, server)
286
287    # boolean: >= 29
288    # typed:   >= 23
289    versions = [1, 29]
290    for c_version, c_bitness, s_version, s_bitness in product(versions, bitnesses, repeat=2):
291        client = JavaVersionTestClient(host, c_bitness, c_version)
292        server = JavaVersionTestServer(host, s_bitness, s_version)
293        add_test(client, server)
294
295    suite = unittest.TestLoader().loadTestsFromTestCase(TestAidl)
296    sys.exit(not unittest.TextTestRunner(verbosity=2).run(suite).wasSuccessful())
297