Home | History | Annotate | Download | only in cts
      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