1 2 // Copyright 2023 Google Inc. All Rights Reserved. 3 package com.google.android.car.aaosbt; 4 import com.android.ddmlib.Log.LogLevel; 5 import com.android.tradefed.config.Option; 6 import com.android.tradefed.config.OptionClass; 7 import com.android.tradefed.device.DeviceNotAvailableException; 8 import com.android.tradefed.invoker.TestInformation; 9 import com.android.tradefed.log.LogUtil.CLog; 10 import com.android.tradefed.targetprep.TargetSetupError; 11 import java.io.File; 12 import java.nio.file.Files; 13 import java.nio.file.Path; 14 import java.nio.file.Paths; 15 import java.io.IOException; 16 import java.io.BufferedReader; 17 import java.io.InputStreamReader; 18 import java.io.InputStream; 19 import java.util.ArrayList; 20 import java.util.Arrays; 21 import java.util.concurrent.TimeoutException; 22 import java.util.concurrent.TimeUnit; 23 import com.android.tradefed.result.ITestInvocationListener; 24 import com.android.tradefed.testtype.IRemoteTest; 25 import java.net.URISyntaxException; 26 import com.android.tradefed.device.ITestDevice; 27 import java.util.Map; 28 import java.util.HashMap; 29 import java.util.Collections; 30 31 @OptionClass(alias = "aaos-moped-test") 32 public class MopedRunner implements IRemoteTest { 33 @Option(name = "test-artifact", description = "test artifact") 34 private File test_artifact = null; 35 36 @Option(name = "artifact", description = "test artifact") 37 private String artifact_str = null; 38 39 @Option(name = "unzip-build-timeout-min", description = "unzip build timeout in minutes") 40 private int unzip_build_timeout_min = 10; 41 42 @Option(name = "test-timeout-min", description = "test timeout in minutes") 43 private int test_timeout_min = 60; 44 45 @Option(name = "testcase", description = "which moped test binary to run") 46 private String test_case = null; 47 48 private File mLocalDestFile; 49 private File mLocalSrcFile; 50 private String mArtifactLocation; 51 52 private static final Map<String, String> autoDic = initDeviceMap(); 53 unTarTestArtifact(TestInformation testInfo)54 private void unTarTestArtifact(TestInformation testInfo) throws TargetSetupError, TimeoutException, URISyntaxException { 55 if (test_artifact != null && artifact_str == null) { 56 artifact_str = test_artifact.toPath().toString(); 57 } 58 String jarPath = getClass() 59 .getProtectionDomain() 60 .getCodeSource() 61 .getLocation() 62 .toURI() 63 .getPath(); 64 File jarFile = new File(jarPath); 65 mLocalSrcFile = new File(jarFile.getParent() + "/../testcases/" + artifact_str); 66 mLocalDestFile = new File(testInfo.dependenciesFolder().toString()); 67 mArtifactLocation = 68 mLocalDestFile.getPath() 69 + "/" 70 + mLocalSrcFile.getName().replaceAll(".tar.*gz", "/"); 71 Path localArtifactPath = Paths.get(mArtifactLocation); 72 if (!Files.exists(localArtifactPath)) { 73 // untar file 74 executeHostCommand( 75 new String[] { 76 "bash", 77 "-c", 78 "tar xf " + mLocalSrcFile.getPath() + " -C " + mLocalDestFile.getPath() 79 }, 80 unzip_build_timeout_min); 81 } 82 } 83 initDeviceMap()84 private static Map<String, String> initDeviceMap() { 85 Map<String, String> map = new HashMap<>(); 86 map.put("seahawk", "AUTO"); 87 map.put("seahawk_hwasan", "AUTO"); 88 map.put("cf_x86_auto", "AUTO"); 89 return Collections.unmodifiableMap(map); 90 } 91 checkDevice(ITestDevice device)92 private String checkDevice(ITestDevice device) throws DeviceNotAvailableException { 93 String buildFlavor = device.getBuildFlavor().split("-")[0]; 94 return autoDic.get(buildFlavor); 95 } 96 getDevicesString(TestInformation testInfo)97 private String getDevicesString(TestInformation testInfo) throws DeviceNotAvailableException { 98 StringBuilder deviceString = new StringBuilder(); 99 int deviceNum = 0; 100 int companionDeviceNum = 0; 101 for(ITestDevice device : testInfo.getDevices()) { 102 String deviceType = checkDevice(device); 103 if (deviceType.equals("AUTO")) { 104 deviceString.append(String.format(" --hu %s", device.getSerialNumber())); 105 } else { 106 companionDeviceNum++; 107 deviceString.append(String.format(" --phone%s %s", String.valueOf(companionDeviceNum), device.getSerialNumber())); 108 } 109 deviceNum++; 110 } 111 deviceString.append(String.format(" --devicenum %s", String.valueOf(deviceNum))); 112 return deviceString.toString(); 113 } 114 115 @Override run(TestInformation testInfo, ITestInvocationListener listener)116 public void run(TestInformation testInfo, ITestInvocationListener listener) 117 throws DeviceNotAvailableException { 118 // Download Moped binanry / config and run test 119 try { 120 unTarTestArtifact(testInfo); 121 executeHostCommand( 122 new String[] {"bash", "-c", "bash " + 123 String.format("%s/run.sh %s --testcase %s", mArtifactLocation, 124 getDevicesString(testInfo), 125 test_case)}, 126 test_timeout_min); 127 } catch (TargetSetupError e) { 128 CLog.logAndDisplay(LogLevel.VERBOSE, "There are problems running tests! %s", e); 129 } catch (TimeoutException e) { 130 CLog.logAndDisplay(LogLevel.VERBOSE, "Test execution timeout! %s", e); 131 } catch (URISyntaxException e) { 132 CLog.logAndDisplay(LogLevel.VERBOSE, "Test artifact not found! %s", e); 133 } 134 } 135 executeHostCommand(String[] command, int timeout)136 private ArrayList<String> executeHostCommand(String[] command, int timeout) 137 throws TargetSetupError, TimeoutException { 138 ArrayList<String> ret = new ArrayList<String>(); 139 try { 140 CLog.logAndDisplay( 141 LogLevel.VERBOSE, "Output of running %s is:", Arrays.toString(command)); 142 Process p = Runtime.getRuntime().exec(command); 143 if (!p.waitFor(timeout, TimeUnit.MINUTES)) { 144 p.destroy(); 145 throw new TimeoutException(); 146 } 147 InputStream is = p.getInputStream(); 148 InputStreamReader isr = new InputStreamReader(is); 149 BufferedReader br = new BufferedReader(isr); 150 String line; 151 while ((line = br.readLine()) != null) { 152 CLog.logAndDisplay(LogLevel.VERBOSE, line); 153 ret.add(line); 154 } 155 int exitCode = p.waitFor(); 156 if (exitCode != 0) { 157 throw new TargetSetupError( 158 "Execution of command " + Arrays.toString(command) + " failed!"); 159 } 160 } catch (IOException e) { 161 CLog.logAndDisplay(LogLevel.VERBOSE, "There are problems with IO! %s", e); 162 } catch (InterruptedException e) { 163 CLog.logAndDisplay(LogLevel.VERBOSE, "User interruption!"); 164 } 165 return ret; 166 } 167 } 168 169