| /* |
| * Copyright (C) 2008 The Android Open Source Project |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| |
| package com.android.cts; |
| |
| import com.android.ddmlib.AdbCommandRejectedException; |
| import com.android.ddmlib.MultiLineReceiver; |
| import com.android.ddmlib.RawImage; |
| import com.android.ddmlib.TimeoutException; |
| import com.android.ddmlib.log.LogReceiver.ILogListener; |
| import com.android.ddmlib.log.LogReceiver.LogEntry; |
| |
| import java.awt.image.BufferedImage; |
| import java.io.File; |
| import java.io.IOException; |
| import java.security.NoSuchAlgorithmException; |
| import java.util.ArrayList; |
| |
| import javax.imageio.ImageIO; |
| |
| /** |
| * TestPackage for Reference Application Testing. |
| */ |
| public class ReferenceAppTestPackage extends TestPackage { |
| |
| private static final String ACTION_REFERENCE_APP_TEST = "ReferenceAppTest"; |
| private final String apkToTestName; |
| private final String packageUnderTest; |
| private ArrayList<String> testOutputLines = new ArrayList<String>(); |
| |
| /** |
| * Construct a ReferenceAppTest package with given necessary information. |
| * |
| * @param instrumentationRunner The instrumentation runner. |
| * @param testPkgBinaryName The binary name of the TestPackage. |
| * @param targetNameSpace The package name space of the dependent package, if available. |
| * @param targetBinaryName The binary name of the dependent package, if available. |
| * @param version The version of the CTS Host allowed. |
| * @param androidVersion The version of the Android platform allowed. |
| * @param jarPath The host controller's jar path and file. |
| * @param appNameSpace The package name space used to uninstall the TestPackage. |
| * @param appPackageName The Java package name of the test package. |
| * @param apkToTestName the apk package that contains the ReferenceApp to be tested. |
| * @param packageUnderTest the Java package name of the ReferenceApp to be tested. |
| * @throws NoSuchAlgorithmException |
| */ |
| public ReferenceAppTestPackage(String instrumentationRunner, |
| String testPkgBinaryName, String targetNameSpace, |
| String targetBinaryName, String version, |
| String androidVersion, String jarPath, |
| String appNameSpace, String appPackageName, |
| String apkToTestName, String packageUnderTest) throws NoSuchAlgorithmException { |
| super(instrumentationRunner, testPkgBinaryName, targetNameSpace, targetBinaryName, version, |
| androidVersion, jarPath, appNameSpace, appPackageName); |
| this.apkToTestName = apkToTestName; |
| this.packageUnderTest = packageUnderTest; |
| } |
| |
| /** |
| * Run the package over the device. |
| * |
| * @param device The device to run the package. |
| * @param javaPkgName The java package name. |
| * @param testSessionLog The TestSessionLog for this TestSession. |
| * @throws DeviceDisconnectedException if the device disconnects during the test |
| */ |
| @Override |
| public void run(final TestDevice device, final String javaPkgName, |
| TestSessionLog testSessionLog) throws DeviceDisconnectedException, |
| InvalidApkPathException, InvalidNameSpaceException { |
| Test test = getTests().iterator().next(); |
| if ((test != null) && (test.getResult().isNotExecuted())) { |
| String appToTestApkPath = |
| HostConfig.getInstance().getCaseRepository().getApkPath(apkToTestName); |
| |
| // TODO: This is non-obvious and should be cleaned up |
| device.setRuntimeListener(device); |
| |
| // Install the Reference App |
| device.installAPK(appToTestApkPath); |
| device.waitForCommandFinish(); |
| |
| // Install the Reference App Tests |
| String testApkPath = HostConfig.getInstance().getCaseRepository() |
| .getApkPath(getAppBinaryName()); |
| device.installAPK(testApkPath); |
| device.waitForCommandFinish(); |
| |
| runTests(device, testSessionLog); |
| |
| // Uninstall the Reference App Tests |
| device.uninstallAPK(getAppPackageName()); |
| device.waitForCommandFinish(); |
| |
| // Uninstall the Reference App |
| device.uninstallAPK(packageUnderTest); |
| device.waitForCommandFinish(); |
| |
| verifyTestResults(test); |
| } |
| } |
| |
| private void verifyTestResults(Test test) { |
| // Now go through the results of the test and see if it ran OK |
| boolean testRanOk = false; |
| String numberOfTestsRan = "unknown"; |
| for (String line : testOutputLines) { |
| if (line.startsWith("OK")) { |
| testRanOk = true; |
| int startIndex = 4; // OK (5 tests) |
| int endIndex = line.indexOf(' ', 4); |
| numberOfTestsRan = line.substring(4, endIndex); |
| break; |
| } |
| } |
| if (!testRanOk) { |
| test.setResult(new CtsTestResult(CtsTestResult.CODE_FAIL, null, null)); |
| } else { |
| test.setResult(new CtsTestResult(CtsTestResult.CODE_PASS, |
| numberOfTestsRan + " tests passed", null)); |
| } |
| } |
| |
| private static final String REF_APP_COMMAND_COMPONENT = "ReferenceAppTestCase"; |
| private static final String TAKE_SNAPSHOT_CMD = "takeSnapshot"; |
| |
| /** |
| * Run the tests for this test package. |
| * |
| * @param device the device under test. |
| * @param testSessionLog the TestSessionLog for this test |
| * @throws DeviceDisconnectedException if the device disconnects. |
| */ |
| private void runTests(final TestDevice device, |
| final TestSessionLog testSessionLog) throws DeviceDisconnectedException { |
| Log.i("Running reference tests for " + apkToTestName); |
| |
| device.addMainLogListener(new ILogListener() { |
| public void newData(byte[] data, int offset, int length) { |
| // use newEntry instead |
| } |
| |
| public void newEntry(LogEntry entry) { |
| // skip first bytes, its the log level |
| String component = ""; |
| String msg = ""; |
| for (int i = 1; i < entry.len; i++) { |
| if (entry.data[i] == 0) { |
| component = new String(entry.data, 1, i - 1); |
| msg = new String(entry.data, i + 1, entry.len - i - 2); |
| // clean up any trailing newlines |
| if (msg.endsWith("\n")) { |
| msg = msg.substring(0, msg.length() - 1); |
| } |
| break; |
| } |
| } |
| if (REF_APP_COMMAND_COMPONENT.equals(component)) { |
| String[] parts = msg.split(":", 2); |
| if (parts == null || |
| parts.length != 2) { |
| Log.e("Got reference app command component with invalid cmd: " + msg, |
| null); |
| return; |
| } |
| |
| String cmd = parts[0]; |
| String cmdArgs = parts[1]; |
| if (TAKE_SNAPSHOT_CMD.equals(cmd)) { |
| takeSnapshot(device, testSessionLog, cmdArgs); |
| } |
| } |
| } |
| |
| private void takeSnapshot(TestDevice device, |
| TestSessionLog testSessionLog, |
| String cmdArgs) { |
| try { |
| RawImage rawImage = device.getScreenshot(); |
| if (rawImage != null) { |
| String outputFilename = testSessionLog.getResultDir() + |
| File.separator + cmdArgs + ".png"; |
| File output = new File(outputFilename); |
| BufferedImage im = HostUtils.convertRawImageToBufferedImage(rawImage); |
| ImageIO.write(im, "png", output); |
| } else { |
| Log.e("getScreenshot returned a null image", null); |
| } |
| } catch (IOException e) { |
| Log.e("Error taking snapshot! " + cmdArgs, e); |
| } catch (TimeoutException e) { |
| Log.e("Error taking snapshot! " + cmdArgs, e); |
| } catch (AdbCommandRejectedException e) { |
| Log.e("Error taking snapshot! " + cmdArgs, e); |
| } |
| } |
| }); |
| |
| final String commandStr = "am instrument -w -e package "+ getAppPackageName() + " " |
| + getAppPackageName() + "/" + getInstrumentationRunner(); |
| Log.d(commandStr); |
| |
| device.startActionTimer(ACTION_REFERENCE_APP_TEST); |
| device.executeShellCommand(commandStr, new ReferenceAppResultsObserver(device)); |
| device.waitForCommandFinish(); |
| } |
| |
| /** |
| * Reference app result observer. |
| */ |
| class ReferenceAppResultsObserver extends MultiLineReceiver { |
| |
| private final TestDevice device; |
| |
| public ReferenceAppResultsObserver(TestDevice td) { |
| this.device = td; |
| } |
| |
| /** {@inheritDoc} */ |
| @Override |
| public void processNewLines(String[] lines) { |
| for (String line : lines) { |
| testOutputLines.add(line); |
| } |
| } |
| |
| /** {@inheritDoc} */ |
| public boolean isCancelled() { |
| return false; |
| } |
| |
| /** {@inheritDoc} */ |
| @Override |
| public void done() { |
| device.stopActionTimer(); |
| device.notifyExternalTestComplete(); |
| } |
| } |
| } |