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 28 @OptionClass(alias = "aaos-moped-test") 29 public class MopedRunner implements IRemoteTest { 30 @Option(name = "test-artifact", description = "test artifact") 31 private File test_artifact = null; 32 33 @Option(name = "artifact", description = "test artifact") 34 private String artifact_str = null; 35 36 @Option(name = "unzip-build-timeout-min", description = "unzip build timeout in minutes") 37 private int unzip_build_timeout_min = 10; 38 39 @Option(name = "test-timeout-min", description = "test timeout in minutes") 40 private int test_timeout_min = 60; 41 42 @Option(name = "testcase", description = "which moped test binary to run") 43 private String test_case = null; 44 45 private File mLocalDestFile; 46 private File mLocalSrcFile; 47 private String mArtifactLocation; 48 unTarTestArtifact(TestInformation testInfo)49 private void unTarTestArtifact(TestInformation testInfo) throws TargetSetupError, TimeoutException, URISyntaxException { 50 if (test_artifact != null && artifact_str == null) { 51 artifact_str = test_artifact.toPath().toString(); 52 } 53 String jarPath = getClass() 54 .getProtectionDomain() 55 .getCodeSource() 56 .getLocation() 57 .toURI() 58 .getPath(); 59 File jarFile = new File(jarPath); 60 mLocalSrcFile = new File(jarFile.getParent() + "/../testcases/" + artifact_str); 61 mLocalDestFile = new File(testInfo.dependenciesFolder().toString()); 62 mArtifactLocation = 63 mLocalDestFile.getPath() 64 + "/" 65 + mLocalSrcFile.getName().replaceAll(".tar.*gz", "/"); 66 Path localArtifactPath = Paths.get(mArtifactLocation); 67 if (!Files.exists(localArtifactPath)) { 68 // untar file 69 executeHostCommand( 70 new String[] { 71 "bash", 72 "-c", 73 "tar xf " + mLocalSrcFile.getPath() + " -C " + mLocalDestFile.getPath() 74 }, 75 unzip_build_timeout_min); 76 } 77 } 78 getDevicesString(TestInformation testInfo)79 private String getDevicesString(TestInformation testInfo) throws DeviceNotAvailableException { 80 StringBuilder deviceString = new StringBuilder(); 81 int deviceNum = 0; 82 for(ITestDevice device : testInfo.getDevices()) { 83 if (deviceNum==0) { // by default the first device is head unit. 84 deviceString.append(String.format(" --hu %s", device.getSerialNumber())); 85 } else { 86 deviceString.append(String.format(" --phone%s %s", String.valueOf(deviceNum), device.getSerialNumber())); 87 } 88 deviceNum++; 89 } 90 deviceString.append(String.format(" --devicenum %s", String.valueOf(deviceNum))); 91 return deviceString.toString(); 92 } 93 94 @Override run(TestInformation testInfo, ITestInvocationListener listener)95 public void run(TestInformation testInfo, ITestInvocationListener listener) 96 throws DeviceNotAvailableException { 97 // Download Moped binanry / config and run test 98 try { 99 unTarTestArtifact(testInfo); 100 executeHostCommand( 101 new String[] {"bash", "-c", "bash " + 102 String.format("%s/run.sh %s --testcase %s", mArtifactLocation, 103 getDevicesString(testInfo), 104 test_case)}, 105 test_timeout_min); 106 } catch (TargetSetupError e) { 107 CLog.logAndDisplay(LogLevel.VERBOSE, "There are problems running tests! %s", e); 108 } catch (TimeoutException e) { 109 CLog.logAndDisplay(LogLevel.VERBOSE, "Test execution timeout! %s", e); 110 } catch (URISyntaxException e) { 111 CLog.logAndDisplay(LogLevel.VERBOSE, "Test artifact not found! %s", e); 112 } 113 } 114 executeHostCommand(String[] command, int timeout)115 private ArrayList<String> executeHostCommand(String[] command, int timeout) 116 throws TargetSetupError, TimeoutException { 117 ArrayList<String> ret = new ArrayList<String>(); 118 try { 119 CLog.logAndDisplay( 120 LogLevel.VERBOSE, "Output of running %s is:", Arrays.toString(command)); 121 Process p = Runtime.getRuntime().exec(command); 122 if (!p.waitFor(timeout, TimeUnit.MINUTES)) { 123 p.destroy(); 124 throw new TimeoutException(); 125 } 126 InputStream is = p.getInputStream(); 127 InputStreamReader isr = new InputStreamReader(is); 128 BufferedReader br = new BufferedReader(isr); 129 String line; 130 while ((line = br.readLine()) != null) { 131 CLog.logAndDisplay(LogLevel.VERBOSE, line); 132 ret.add(line); 133 } 134 int exitCode = p.waitFor(); 135 if (exitCode != 0) { 136 throw new TargetSetupError( 137 "Execution of command " + Arrays.toString(command) + " failed!"); 138 } 139 } catch (IOException e) { 140 CLog.logAndDisplay(LogLevel.VERBOSE, "There are problems with IO! %s", e); 141 } catch (InterruptedException e) { 142 CLog.logAndDisplay(LogLevel.VERBOSE, "User interruption!"); 143 } 144 return ret; 145 } 146 } 147 148