Home | History | Annotate | Download | only in targetprep
      1 /*
      2  * Copyright (C) 2012 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 package com.android.tradefed.targetprep;
     17 
     18 import com.android.ddmlib.FileListingService;
     19 import com.android.tradefed.build.IBuildInfo;
     20 import com.android.tradefed.build.IDeviceBuildInfo;
     21 import com.android.tradefed.config.Option;
     22 import com.android.tradefed.config.Option.Importance;
     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.log.LogUtil.CLog;
     27 import com.android.tradefed.util.ArrayUtil;
     28 import com.android.tradefed.util.FileUtil;
     29 
     30 import java.io.File;
     31 import java.util.ArrayList;
     32 import java.util.Collection;
     33 import java.util.Collections;
     34 import java.util.List;
     35 
     36 /**
     37  * A {@link ITargetPreparer} that pushes one or more files/dirs from a {@link
     38  * IDeviceBuildInfo#getTestsDir()} folder onto device.
     39  *
     40  * <p>This preparer will look in alternate directories if the tests zip does not exist or does not
     41  * contain the required apk. The search will go in order from the last alternative dir specified to
     42  * the first.
     43  */
     44 @OptionClass(alias = "tests-zip-file")
     45 public class TestFilePushSetup extends BaseTargetPreparer {
     46 
     47     @Option(name = "test-file-name", description =
     48             "the relative path of a test zip file/directory to install on device. Can be repeated.",
     49             importance = Importance.IF_UNSET)
     50     private Collection<String> mTestPaths = new ArrayList<String>();
     51 
     52     @Option(name = "throw-if-not-found", description =
     53             "Throw exception if the specified file is not found.")
     54     private boolean mThrowIfNoFile = true;
     55 
     56     @Option(name = "alt-dir",
     57             description = "Alternate directory to look for the apk if the apk is not in the tests "
     58                     + "zip file. For each alternate dir, will look in // and //DATA. Can be "
     59                     + "repeated. Look for apks in last alt-dir first.")
     60     private List<File> mAltDirs = new ArrayList<>();
     61 
     62     @Option(name = "alt-dir-behavior", description = "The order of alternate directory to be used "
     63             + "when searching for files to push")
     64     private AltDirBehavior mAltDirBehavior = AltDirBehavior.FALLBACK;
     65 
     66     /**
     67      * Adds a file to the list of items to push
     68      *
     69      * @param fileName
     70      */
     71     protected void addTestFileName(String fileName) {
     72         mTestPaths.add(fileName);
     73     }
     74 
     75     /**
     76      * Retrieves the list of files to be pushed from test zip onto device
     77      */
     78     protected Collection<String> getTestFileNames() {
     79         return mTestPaths;
     80     }
     81 
     82     protected void clearTestFileName() {
     83         mTestPaths.clear();
     84     }
     85 
     86     /**
     87      * Resolve the host side path based on testing artifact information inside build info.
     88      *
     89      * @param buildInfo build artifact information
     90      * @param fileName filename of artifacts to push
     91      * @return a {@link File} representing the physical file/path on host
     92      */
     93     protected File getLocalPathForFilename(IBuildInfo buildInfo, String fileName,
     94             ITestDevice device) throws TargetSetupError {
     95         List<File> dirs = new ArrayList<>();
     96         for (File dir : mAltDirs) {
     97             dirs.add(dir);
     98             dirs.add(FileUtil.getFileForPath(dir, "DATA"));
     99         }
    100         // reverse the order so ones provided via command line last can be searched first
    101         Collections.reverse(dirs);
    102 
    103         List<File> expandedTestDirs = new ArrayList<>();
    104         if (buildInfo instanceof IDeviceBuildInfo) {
    105             File testsDir = ((IDeviceBuildInfo)buildInfo).getTestsDir();
    106             if (testsDir != null && testsDir.exists()) {
    107                 expandedTestDirs.add(FileUtil.getFileForPath(testsDir, "DATA"));
    108             }
    109         }
    110         if (mAltDirBehavior == AltDirBehavior.FALLBACK) {
    111             // alt dirs are appended after build artifact dirs
    112             expandedTestDirs.addAll(dirs);
    113             dirs = expandedTestDirs;
    114         } else if (mAltDirBehavior == AltDirBehavior.OVERRIDE) {
    115             dirs.addAll(expandedTestDirs);
    116         } else {
    117             throw new TargetSetupError("Missing handler for alt-dir-behavior: " + mAltDirBehavior,
    118                     device.getDeviceDescriptor());
    119         }
    120         if (dirs.isEmpty()) {
    121             throw new TargetSetupError(
    122                     "Provided buildInfo does not contain a valid tests directory and no " +
    123                     "alternative directories were provided", device.getDeviceDescriptor());
    124         }
    125 
    126         for (File dir : dirs) {
    127             File testAppFile = new File(dir, fileName);
    128             if (testAppFile.exists()) {
    129                 return testAppFile;
    130             }
    131         }
    132         return null;
    133     }
    134 
    135     /**
    136      * {@inheritDoc}
    137      */
    138     @Override
    139     public void setUp(ITestDevice device, IBuildInfo buildInfo) throws TargetSetupError,
    140             BuildError, DeviceNotAvailableException {
    141         if (!(buildInfo instanceof IDeviceBuildInfo)) {
    142             throw new IllegalArgumentException(String.format("Provided buildInfo is not a %s",
    143                     IDeviceBuildInfo.class.getCanonicalName()));
    144         }
    145         if (mTestPaths.size() == 0) {
    146             CLog.d("No test files to push, skipping");
    147             return;
    148         }
    149         int filePushed = 0;
    150         for (String fileName : mTestPaths) {
    151             File localFile = getLocalPathForFilename(buildInfo, fileName, device);
    152             if (localFile == null) {
    153                 if (mThrowIfNoFile) {
    154                     throw new TargetSetupError(String.format(
    155                             "Could not find test file %s directory in extracted tests.zip",
    156                             fileName), device.getDeviceDescriptor());
    157                 } else {
    158                     CLog.w(String.format(
    159                             "Could not find test file %s directory in extracted tests.zip, but" +
    160                             "will continue test setup as throw-if-not-found is set to false",
    161                             fileName));
    162                     continue;
    163                 }
    164             }
    165             String remoteFileName = getDevicePathFromUserData(fileName);
    166             CLog.d("Pushing file: %s -> %s", localFile.getAbsoluteFile(), remoteFileName);
    167             if (localFile.isDirectory()) {
    168                 device.pushDir(localFile, remoteFileName);
    169             } else if (localFile.isFile()) {
    170                 device.pushFile(localFile, remoteFileName);
    171             }
    172             // there's no recursive option for 'chown', best we can do here
    173             device.executeShellCommand(String.format("chown system.system %s", remoteFileName));
    174             filePushed++;
    175         }
    176         if (filePushed == 0 && mThrowIfNoFile) {
    177             throw new TargetSetupError("No file is pushed from tests.zip",
    178                     device.getDeviceDescriptor());
    179         }
    180     }
    181 
    182     protected void setThrowIfNoFile(boolean throwIfNoFile) {
    183         mThrowIfNoFile = throwIfNoFile;
    184     }
    185 
    186     /**
    187      * Set an alternate directory. Exposed for testing.
    188      */
    189     protected void setAltDir(File altDir) {
    190         mAltDirs.add(altDir);
    191     }
    192 
    193     /**
    194      * Set the alternative directory search behavior. Exposed for testing.
    195      */
    196     protected void setAltDirBehavior(AltDirBehavior behavior) {
    197         mAltDirBehavior = behavior;
    198     }
    199 
    200     static String getDevicePathFromUserData(String path) {
    201         return ArrayUtil.join(FileListingService.FILE_SEPARATOR,
    202                 "", FileListingService.DIRECTORY_DATA, path);
    203     }
    204 }
    205