From 88f44c8998ff2514bc39916afec916bb3a8fccd1 Mon Sep 17 00:00:00 2001 From: Hsin-Yi Chen Date: Tue, 4 Feb 2020 15:29:51 +0800 Subject: Convert vts_vndk_dependency_test to a host test TradeFed does not support running Python file on device. This commit converts vts_vndk_dependency_test to a python_test_host. Bug: 147454897 Test: ANDROID_SERIAL=ABCDEF \ VTS_DATA_FILE_PATH=$ANDROID_HOST_OUT/vts/android-vts/testcases \ LD_LIBRARY_PATH=$ANDROID_HOST_OUT_TESTCASES/../lib64 \ $ANDROID_HOST_OUT_TESTCASES/vts_vndk_dependency_test/x86_64/vts_vndk_dependency_test Change-Id: I9c4a3eb48864fb511bc89e643a0549d98a351bec Merged-In: I9c4a3eb48864fb511bc89e643a0549d98a351bec (cherry picked from commit 5a37f5e07007eee8f7ab3eecb684d66471f4b9b3) --- Android.bp | 4 +-- dependency/vts_vndk_dependency_test.py | 51 ++++++++++++++++++++++++---------- utils.py | 15 ++++++++-- 3 files changed, 51 insertions(+), 19 deletions(-) diff --git a/Android.bp b/Android.bp index 18a2b91..df43d92 100644 --- a/Android.bp +++ b/Android.bp @@ -12,7 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -python_library { +python_library_host { name: "vts_vndk_utils", pkg_path: "vts/testcases/vndk", srcs: [ @@ -50,7 +50,7 @@ python_defaults { } } -python_test { +python_test_host { name: "vts_vndk_dependency_test", defaults: ["vts_vndk_default"], main: "dependency/vts_vndk_dependency_test.py", diff --git a/dependency/vts_vndk_dependency_test.py b/dependency/vts_vndk_dependency_test.py index 6541a80..65d62c8 100644 --- a/dependency/vts_vndk_dependency_test.py +++ b/dependency/vts_vndk_dependency_test.py @@ -20,7 +20,10 @@ import collections import logging import os +import posixpath as target_path_module import re +import shutil +import tempfile import unittest from vts.testcases.vndk import utils @@ -34,6 +37,8 @@ class VtsVndkDependencyTest(unittest.TestCase): Attributes: _dut: The AndroidDevice under test. + _temp_dir: The temporary directory to which the odm and vendor + partitions are copied. _ll_ndk: Set of strings. The names of low-level NDK libraries in /system/lib[64]. _sp_hal: List of patterns. The names of the same-process HAL libraries @@ -44,6 +49,7 @@ class VtsVndkDependencyTest(unittest.TestCase): _VENDOR_LINK_PATHS: Format strings of vendor processes' link paths. """ _TARGET_DIR_SEP = "/" + _TARGET_ROOT_DIR = "/" _TARGET_ODM_DIR = "/odm" _TARGET_VENDOR_DIR = "/vendor" @@ -74,8 +80,8 @@ class VtsVndkDependencyTest(unittest.TestCase): def __init__(self, target_path, bitness, deps, runpaths): self.target_path = target_path - self.name = os.path.basename(target_path) - self.target_dir = os.path.dirname(target_path) + self.name = target_path_module.basename(target_path) + self.target_dir = target_path_module.dirname(target_path) self.bitness = bitness self.deps = deps # Format runpaths @@ -90,9 +96,19 @@ class VtsVndkDependencyTest(unittest.TestCase): def setUp(self): """Initializes device, temporary directory, and VNDK lists.""" - self._dut = utils.AndroidDevice() + serial_number = os.environ.get("ANDROID_SERIAL") + self.assertTrue(serial_number, "$ANDROID_SERIAL is empty.") + self._dut = utils.AndroidDevice(serial_number) self.assertTrue(self._dut.IsRoot(), "This test requires adb root.") + self._temp_dir = tempfile.mkdtemp() + for target_dir in (self._TARGET_ODM_DIR, self._TARGET_VENDOR_DIR): + if self._dut.IsDirectory(target_dir): + logging.info("adb pull %s %s", target_dir, self._temp_dir) + self._dut.AdbPull(target_dir, self._temp_dir) + else: + logging.info("Skip adb pull %s", target_dir) + vndk_lists = vndk_data.LoadVndkLibraryListsFromResources( self._dut.GetVndkVersion(), vndk_data.SP_HAL, @@ -110,6 +126,11 @@ class VtsVndkDependencyTest(unittest.TestCase): logging.debug("VNDK: %s", self._vndk) logging.debug("VNDK_SP: %s", self._vndk_sp) + def tearDown(self): + """Deletes the temporary directory.""" + logging.info("Delete %s", self._temp_dir) + shutil.rmtree(self._temp_dir, ignore_errors=True) + def _IsElfObjectForAp(self, elf, target_path, abi_list): """Checks whether an ELF object is for application processor. @@ -192,23 +213,28 @@ class VtsVndkDependencyTest(unittest.TestCase): for file_name in file_names: yield os.path.join(root_dir, file_name) - def _LoadElfObjects(self, target_dir, abi_list, elf_error_handler): + def _LoadElfObjects(self, host_dir, target_dir, abi_list, + elf_error_handler): """Scans a host directory recursively and loads all ELF files in it. Args: - target_dir: The host directory to scan. + host_dir: The host directory to scan. + target_dir: The path from which host_dir is copied. abi_list: A list of strings, the ABIs of the ELF files to load. elf_error_handler: A function that takes 2 arguments - (path, exception). It is called when + (target_path, exception). It is called when the parser fails to read an ELF file. Returns: List of ElfObject. """ objs = [] - for target_path in self._IterateFiles(target_dir): + for full_path in self._IterateFiles(host_dir): + rel_path = os.path.relpath(full_path, host_dir) + target_path = target_path_module.join( + target_dir, *rel_path.split(os.path.sep)) try: - elf = elf_parser.ElfParser(target_path) + elf = elf_parser.ElfParser(full_path) except elf_parser.ElfError: logging.debug("%s is not an ELF file", target_path) continue @@ -404,12 +430,9 @@ class VtsVndkDependencyTest(unittest.TestCase): """Tests vendor libraries/executables and SP-HAL dependencies.""" read_errors = [] abi_list = self._dut.GetCpuAbiList() - objs = [] - for target_dir in (self._TARGET_ODM_DIR, self._TARGET_VENDOR_DIR): - if self._dut.IsDirectory(target_dir): - objs.extend(self._LoadElfObjects( - target_dir, abi_list, - lambda p, e: read_errors.append((p, str(e))))) + objs = self._LoadElfObjects( + self._temp_dir, self._TARGET_ROOT_DIR, abi_list, + lambda p, e: read_errors.append((p, str(e)))) dep_errors = self._TestElfDependency(32, objs) if self._dut.GetCpuAbiList(64): diff --git a/utils.py b/utils.py index 8e6cc52..45a5951 100644 --- a/utils.py +++ b/utils.py @@ -24,7 +24,15 @@ import subprocess class AndroidDevice(object): """This class controls the device via adb commands.""" - def _ExecuteCommand(self, *cmd): + def __init__(self, serial_number): + self._serial_number = serial_number + + def AdbPull(self, src, dst): + cmd = ["adb", "-s", self._serial_number, "pull", src, dst] + subprocess.check_call(cmd, shell=False, stdin=subprocess.PIPE, + stdout=subprocess.PIPE, stderr=subprocess.PIPE) + + def _ExecuteCommand(self, *args): """Executes a command. Args: @@ -34,6 +42,8 @@ class AndroidDevice(object): Stdout as a string, stderr as a string, and return code as an integer. """ + cmd = ["adb", "-s", self._serial_number, "shell"] + cmd.extend(args) proc = subprocess.Popen(cmd, shell=False, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE) out, err = proc.communicate() @@ -140,8 +150,7 @@ class AndroidDevice(object): def _Test(self, *args): """Tests file types and status.""" - out, err, return_code = self._ExecuteCommand("sh", "-c", - "test " + " ".join(args)) + out, err, return_code = self._ExecuteCommand("test", *args) if out.strip() or err.strip(): raise IOError("`test` args: %s\nstdout: %s\nstderr: %s" % (args, out, err)) -- cgit v1.2.3