1 /* 2 * Copyright (C) 2008 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.android.cts; 18 19 import com.android.ddmlib.AdbCommandRejectedException; 20 import com.android.ddmlib.MultiLineReceiver; 21 import com.android.ddmlib.RawImage; 22 import com.android.ddmlib.TimeoutException; 23 import com.android.ddmlib.log.LogReceiver.ILogListener; 24 import com.android.ddmlib.log.LogReceiver.LogEntry; 25 26 import java.awt.image.BufferedImage; 27 import java.io.File; 28 import java.io.IOException; 29 import java.security.NoSuchAlgorithmException; 30 import java.util.ArrayList; 31 32 import javax.imageio.ImageIO; 33 34 /** 35 * TestPackage for Reference Application Testing. 36 */ 37 public class ReferenceAppTestPackage extends TestPackage { 38 39 private static final String ACTION_REFERENCE_APP_TEST = "ReferenceAppTest"; 40 private final String apkToTestName; 41 private final String packageUnderTest; 42 private ArrayList<String> testOutputLines = new ArrayList<String>(); 43 44 /** 45 * Construct a ReferenceAppTest package with given necessary information. 46 * 47 * @param instrumentationRunner The instrumentation runner. 48 * @param testPkgBinaryName The binary name of the TestPackage. 49 * @param targetNameSpace The package name space of the dependent package, if available. 50 * @param targetBinaryName The binary name of the dependent package, if available. 51 * @param version The version of the CTS Host allowed. 52 * @param androidVersion The version of the Android platform allowed. 53 * @param jarPath The host controller's jar path and file. 54 * @param appNameSpace The package name space used to uninstall the TestPackage. 55 * @param appPackageName The Java package name of the test package. 56 * @param apkToTestName the apk package that contains the ReferenceApp to be tested. 57 * @param packageUnderTest the Java package name of the ReferenceApp to be tested. 58 * @throws NoSuchAlgorithmException 59 */ 60 public ReferenceAppTestPackage(String instrumentationRunner, 61 String testPkgBinaryName, String targetNameSpace, 62 String targetBinaryName, String version, 63 String androidVersion, String jarPath, 64 String appNameSpace, String appPackageName, 65 String apkToTestName, String packageUnderTest) throws NoSuchAlgorithmException { 66 super(instrumentationRunner, testPkgBinaryName, targetNameSpace, targetBinaryName, version, 67 androidVersion, jarPath, appNameSpace, appPackageName, null); 68 this.apkToTestName = apkToTestName; 69 this.packageUnderTest = packageUnderTest; 70 } 71 72 /** 73 * Run the package over the device. 74 * 75 * @param device The device to run the package. 76 * @param javaPkgName The java package name. 77 * @param testSessionLog The TestSessionLog for this TestSession. 78 * @throws DeviceDisconnectedException if the device disconnects during the test 79 */ 80 @Override 81 public void run(final TestDevice device, final String javaPkgName, 82 TestSessionLog testSessionLog) throws DeviceDisconnectedException, 83 InvalidApkPathException, InvalidNameSpaceException { 84 Test test = getTests().iterator().next(); 85 if ((test != null) && (test.getResult().isNotExecuted())) { 86 String appToTestApkPath = 87 HostConfig.getInstance().getCaseRepository().getApkPath(apkToTestName); 88 89 // TODO: This is non-obvious and should be cleaned up 90 device.setRuntimeListener(device); 91 92 // Install the Reference App 93 device.installAPK(appToTestApkPath); 94 device.waitForCommandFinish(); 95 96 // Install the Reference App Tests 97 String testApkPath = HostConfig.getInstance().getCaseRepository() 98 .getApkPath(getAppBinaryName()); 99 device.installAPK(testApkPath); 100 device.waitForCommandFinish(); 101 102 runTests(device, testSessionLog); 103 104 // Uninstall the Reference App Tests 105 device.uninstallAPK(getAppPackageName()); 106 device.waitForCommandFinish(); 107 108 // Uninstall the Reference App 109 device.uninstallAPK(packageUnderTest); 110 device.waitForCommandFinish(); 111 112 verifyTestResults(test); 113 } 114 } 115 116 private void verifyTestResults(Test test) { 117 // Now go through the results of the test and see if it ran OK 118 boolean testRanOk = false; 119 String numberOfTestsRan = "unknown"; 120 for (String line : testOutputLines) { 121 if (line.startsWith("OK")) { 122 testRanOk = true; 123 int startIndex = 4; // OK (5 tests) 124 int endIndex = line.indexOf(' ', 4); 125 numberOfTestsRan = line.substring(4, endIndex); 126 break; 127 } 128 } 129 if (!testRanOk) { 130 test.setResult(new CtsTestResult(CtsTestResult.CODE_FAIL, null, null)); 131 } else { 132 test.setResult(new CtsTestResult(CtsTestResult.CODE_PASS, 133 numberOfTestsRan + " tests passed", null)); 134 } 135 } 136 137 private static final String REF_APP_COMMAND_COMPONENT = "ReferenceAppTestCase"; 138 private static final String TAKE_SNAPSHOT_CMD = "takeSnapshot"; 139 140 /** 141 * Run the tests for this test package. 142 * 143 * @param device the device under test. 144 * @param testSessionLog the TestSessionLog for this test 145 * @throws DeviceDisconnectedException if the device disconnects. 146 */ 147 private void runTests(final TestDevice device, 148 final TestSessionLog testSessionLog) throws DeviceDisconnectedException { 149 Log.i("Running reference tests for " + apkToTestName); 150 151 device.addMainLogListener(new ILogListener() { 152 public void newData(byte[] data, int offset, int length) { 153 // use newEntry instead 154 } 155 156 public void newEntry(LogEntry entry) { 157 // skip first bytes, its the log level 158 String component = ""; 159 String msg = ""; 160 for (int i = 1; i < entry.len; i++) { 161 if (entry.data[i] == 0) { 162 component = new String(entry.data, 1, i - 1); 163 msg = new String(entry.data, i + 1, entry.len - i - 2); 164 // clean up any trailing newlines 165 if (msg.endsWith("\n")) { 166 msg = msg.substring(0, msg.length() - 1); 167 } 168 break; 169 } 170 } 171 if (REF_APP_COMMAND_COMPONENT.equals(component)) { 172 String[] parts = msg.split(":", 2); 173 if (parts == null || 174 parts.length != 2) { 175 Log.e("Got reference app command component with invalid cmd: " + msg, 176 null); 177 return; 178 } 179 180 String cmd = parts[0]; 181 String cmdArgs = parts[1]; 182 if (TAKE_SNAPSHOT_CMD.equals(cmd)) { 183 takeSnapshot(device, testSessionLog, cmdArgs); 184 } 185 } 186 } 187 188 private void takeSnapshot(TestDevice device, 189 TestSessionLog testSessionLog, 190 String cmdArgs) { 191 try { 192 RawImage rawImage = device.getScreenshot(); 193 if (rawImage != null) { 194 String outputFilename = testSessionLog.getResultDir() + 195 File.separator + cmdArgs + ".png"; 196 File output = new File(outputFilename); 197 BufferedImage im = HostUtils.convertRawImageToBufferedImage(rawImage); 198 ImageIO.write(im, "png", output); 199 } else { 200 Log.e("getScreenshot returned a null image", null); 201 } 202 } catch (IOException e) { 203 Log.e("Error taking snapshot! " + cmdArgs, e); 204 } catch (TimeoutException e) { 205 Log.e("Error taking snapshot! " + cmdArgs, e); 206 } catch (AdbCommandRejectedException e) { 207 Log.e("Error taking snapshot! " + cmdArgs, e); 208 } 209 } 210 }); 211 212 final String commandStr = "am instrument -w -e package "+ getAppPackageName() + " " 213 + getAppPackageName() + "/" + getInstrumentationRunner(); 214 Log.d(commandStr); 215 216 device.startActionTimer(ACTION_REFERENCE_APP_TEST); 217 device.executeShellCommand(commandStr, new ReferenceAppResultsObserver(device)); 218 device.waitForCommandFinish(); 219 } 220 221 /** 222 * Reference app result observer. 223 */ 224 class ReferenceAppResultsObserver extends MultiLineReceiver { 225 226 private final TestDevice device; 227 228 public ReferenceAppResultsObserver(TestDevice td) { 229 this.device = td; 230 } 231 232 /** {@inheritDoc} */ 233 @Override 234 public void processNewLines(String[] lines) { 235 for (String line : lines) { 236 testOutputLines.add(line); 237 } 238 } 239 240 /** {@inheritDoc} */ 241 public boolean isCancelled() { 242 return false; 243 } 244 245 /** {@inheritDoc} */ 246 @Override 247 public void done() { 248 device.stopActionTimer(); 249 device.notifyExternalTestComplete(); 250 } 251 } 252 } 253