Home | History | Annotate | Download | only in testtype
      1 /*
      2  * Copyright (C) 2016 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.tradefed.testtype;
     18 
     19 import com.android.ddmlib.IShellOutputReceiver;
     20 import com.android.ddmlib.Log;
     21 import com.android.ddmlib.testrunner.ITestRunListener;
     22 import com.android.tradefed.config.Option;
     23 import com.android.tradefed.config.OptionClass;
     24 import com.android.tradefed.device.DeviceNotAvailableException;
     25 import com.android.tradefed.device.ITestDevice;
     26 import com.android.tradefed.result.ITestInvocationListener;
     27 
     28 import java.util.concurrent.TimeUnit;
     29 
     30 /**
     31  * A Test that runs a system fuzz test package (part of Vendor Test Suite, VTS) on given device.
     32  */
     33 @OptionClass(alias = "vtsfuzztest")
     34 public class VtsFuzzTest implements IDeviceTest, IRemoteTest {
     35 
     36     private static final String LOG_TAG = "VtsFuzzTest";
     37     static final String DEFAULT_FUZZER_BINARY_PATH = "/system/bin/fuzzer";
     38 
     39     static final float DEFAULT_TARGET_VERSION = -1;
     40     static final int DEFAULT_EPOCH_COUNT = 10;
     41 
     42     // fuzzer flags
     43     private static final String VTS_FUZZ_TEST_FLAG_CLASS = "--class";
     44     private static final String VTS_FUZZ_TEST_FLAG_TYPE = "--type";
     45     private static final String VTS_FUZZ_TEST_FLAG_VERSION = "--version";
     46     private static final String VTS_FUZZ_TEST_FLAG_EPOCH_COUNT = "--epoch_count";
     47 
     48     private ITestDevice mDevice = null;
     49 
     50     @Option(name = "fuzzer-binary-path",
     51             description="The path on the device where fuzzer is located.")
     52     private String mFuzzerBinaryPath = DEFAULT_FUZZER_BINARY_PATH;
     53 
     54     @Option(name = "target-component-path",
     55             description="The path of a target component (e.g., .so file path).")
     56     private String mTargetComponentPath = null;
     57 
     58     @Option(name = "target-class",
     59             description="The target component class.")
     60     private String mTargetClass = null;
     61 
     62     @Option(name = "target-type",
     63             description="The target component type.")
     64     private String mTargetType = null;
     65 
     66     @Option(name = "target-version",
     67             description="The target component version.")
     68     private float mTargetVersion = DEFAULT_TARGET_VERSION;
     69 
     70     @Option(name = "epoch-count",
     71             description="The epoch count.")
     72     private int mEpochCount = DEFAULT_EPOCH_COUNT;
     73 
     74     @Option(name = "test-timeout", description =
     75             "The max time in ms for a VTS test to run. " +
     76             "Test run will be aborted if any test takes longer.")
     77     private int mMaxTestTimeMs = 15 * 60 * 1000;  // 15 minutes
     78 
     79     @Option(name = "runtime-hint",
     80             isTimeVal=true,
     81             description="The hint about the test's runtime.")
     82     private long mRuntimeHint = 5 * 60 * 1000;  // 5 minutes
     83 
     84     /**
     85      * {@inheritDoc}
     86      */
     87     @Override
     88     public void setDevice(ITestDevice device) {
     89         mDevice = device;
     90     }
     91 
     92     /**
     93      * {@inheritDoc}
     94      */
     95     @Override
     96     public ITestDevice getDevice() {
     97         return mDevice;
     98     }
     99 
    100     /**
    101      * Set the target component path variable.
    102      *
    103      * @param path The path to set.
    104      */
    105     public void setTargetComponentPath(String path) {
    106         mTargetComponentPath = path;
    107     }
    108 
    109     /**
    110      * Get the target component path variable.
    111      *
    112      * @return The target component path.
    113      */
    114     public String getTargetComponentPath() {
    115         return mTargetComponentPath;
    116     }
    117 
    118     /**
    119      * Set the target class variable.
    120      *
    121      * @param class_name The class name to set.
    122      */
    123     public void setTargetClass(String class_name) {
    124         mTargetClass = class_name;
    125     }
    126 
    127     /**
    128      * Get the target class name variable.
    129      *
    130      * @return The target class name.
    131      */
    132     public String getTargetClass() {
    133         return mTargetClass;
    134     }
    135 
    136     /**
    137      * Set the target type variable.
    138      *
    139      * @param type_name The type name to set.
    140      */
    141     public void setTargetType(String type_name) {
    142         mTargetType = type_name;
    143     }
    144 
    145     /**
    146      * Get the target type name variable.
    147      *
    148      * @return The target type name.
    149      */
    150     public String getTargetType() {
    151         return mTargetType;
    152     }
    153 
    154     /**
    155      * Set the target version variable.
    156      *
    157      * @param version The version to set.
    158      */
    159     public void setTargetVersion(float version) {
    160         mTargetVersion = version;
    161     }
    162 
    163     /**
    164      * Get the target version variable.
    165      *
    166      * @return The version.
    167      */
    168     public float getTargetVersion() {
    169         return mTargetVersion;
    170     }
    171 
    172     /**
    173      * Set the epoch count variable.
    174      *
    175      * @param count The epoch count to set.
    176      */
    177     public void setEpochCount(int count) {
    178         mEpochCount = count;
    179     }
    180 
    181     /**
    182      * Get the epoch count variable.
    183      *
    184      * @return The epoch count.
    185      */
    186     public float getEpochCount() {
    187         return mEpochCount;
    188     }
    189 
    190     /**
    191      * Helper to get all the VtsFuzzTest flags to pass into the adb shell command.
    192      *
    193      * @return the {@link String} of all the VtsFuzzTest flags that should be passed to the VtsFuzzTest
    194      * @throws IllegalArgumentException
    195      */
    196     private String getAllVtsFuzzTestFlags() {
    197         String flags;
    198 
    199         if (mTargetClass == null) {
    200             throw new IllegalArgumentException(VTS_FUZZ_TEST_FLAG_CLASS + " must be set.");
    201         }
    202         flags = String.format("%s=%s", VTS_FUZZ_TEST_FLAG_CLASS, mTargetClass);
    203 
    204         if (mTargetType == null) {
    205             throw new IllegalArgumentException(VTS_FUZZ_TEST_FLAG_TYPE + " must be set.");
    206         }
    207         flags = String.format("%s %s=%s", flags, VTS_FUZZ_TEST_FLAG_TYPE, mTargetType);
    208 
    209         if (mTargetVersion == DEFAULT_TARGET_VERSION) {
    210             throw new IllegalArgumentException(VTS_FUZZ_TEST_FLAG_VERSION + " must be set.");
    211         }
    212         flags = String.format("%s %s=%s", flags, VTS_FUZZ_TEST_FLAG_VERSION, mTargetVersion);
    213 
    214         flags = String.format("%s %s=%s", flags, VTS_FUZZ_TEST_FLAG_EPOCH_COUNT, mEpochCount);
    215 
    216         flags = String.format("%s %s", flags, mTargetComponentPath);
    217         return flags;
    218     }
    219 
    220     /**
    221      * Run the given fuzzer binary using the given flags
    222      *
    223      * @param testDevice the {@link ITestDevice}
    224      * @param resultParser the test run output parser
    225      * @param fullPath absolute file system path to gtest binary on device
    226      * @param flags fuzzer execution flags
    227      * @throws DeviceNotAvailableException
    228      */
    229     private void runTest(final ITestDevice testDevice, final IShellOutputReceiver resultParser,
    230             final String fullPath, final String flags) throws DeviceNotAvailableException {
    231         // TODO: add individual test timeout support, and rerun support
    232         try {
    233             String cmd = getVtsFuzzTestCmdLine(fullPath, flags);
    234             testDevice.executeShellCommand(cmd, resultParser,
    235                     mMaxTestTimeMs,
    236                     TimeUnit.MILLISECONDS,
    237                     0 /* retryAttempts */);
    238         } catch (DeviceNotAvailableException e) {
    239             // TODO: consider moving the flush of parser data on exceptions to TestDevice or
    240             // AdbHelper
    241             resultParser.flush();
    242             throw e;
    243         } catch (RuntimeException e) {
    244             resultParser.flush();
    245             throw e;
    246         }
    247     }
    248 
    249     /**
    250      * Helper method to build the fuzzer command to run.
    251      *
    252      * @param fullPath absolute file system path to fuzzer binary on device
    253      * @param flags fuzzer execution flags
    254      * @return the shell command line to run for the fuzzer
    255      */
    256     protected String getVtsFuzzTestCmdLine(String fullPath, String flags) {
    257         StringBuilder cmdLine = new StringBuilder();
    258         cmdLine.append(String.format("%s %s", fullPath, flags));
    259         return cmdLine.toString();
    260     }
    261 
    262     /**
    263      * Factory method for creating a {@link IShellOutputReceiver} that parses test output and
    264      * forwards results to the result listener.
    265      * <p/>
    266      * Exposed so unit tests can mock
    267      *
    268      * @param listener
    269      * @param runName
    270      * @return a {@link IShellOutputReceiver}
    271      */
    272     IShellOutputReceiver createResultParser(String runName, ITestRunListener listener) {
    273         VtsFuzzTestResultParser resultParser = new VtsFuzzTestResultParser(runName, listener);
    274         return resultParser;
    275     }
    276 
    277     /**
    278      * {@inheritDoc}
    279      */
    280     @Override
    281     public void run(ITestInvocationListener listener) throws DeviceNotAvailableException {
    282         if (mDevice == null) {
    283             throw new IllegalArgumentException("Device has not been set");
    284         }
    285 
    286         if (!mDevice.doesFileExist(mFuzzerBinaryPath)) {
    287             Log.w(LOG_TAG, String.format("Could not find fuzzer binary file %s in %s!",
    288                     mFuzzerBinaryPath, mDevice.getSerialNumber()));
    289             return;
    290         }
    291 
    292         IShellOutputReceiver resultParser = createResultParser(mTargetComponentPath, listener);
    293         String flags = getAllVtsFuzzTestFlags();
    294         Log.i(LOG_TAG, String.format("Running fuzzer '%s %s' on %s",
    295                 mFuzzerBinaryPath, flags, mDevice.getSerialNumber()));
    296         runTest(mDevice, resultParser, mFuzzerBinaryPath, flags);
    297     }
    298 }
    299