Home | History | Annotate | Download | only in targetprep
      1 /*
      2  * Copyright (C) 2015 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.compatibility.common.tradefed.targetprep;
     17 
     18 import com.android.annotations.VisibleForTesting;
     19 import com.android.compatibility.common.tradefed.build.CompatibilityBuildHelper;
     20 import com.android.compatibility.common.util.DynamicConfig;
     21 import com.android.compatibility.common.util.DynamicConfigHandler;
     22 import com.android.ddmlib.Log;
     23 import com.android.tradefed.build.IBuildInfo;
     24 import com.android.tradefed.config.Option;
     25 import com.android.tradefed.config.OptionClass;
     26 import com.android.tradefed.device.DeviceNotAvailableException;
     27 import com.android.tradefed.device.ITestDevice;
     28 import com.android.tradefed.log.LogUtil;
     29 import com.android.tradefed.targetprep.BaseTargetPreparer;
     30 import com.android.tradefed.targetprep.BuildError;
     31 import com.android.tradefed.targetprep.ITargetCleaner;
     32 import com.android.tradefed.targetprep.TargetSetupError;
     33 import com.android.tradefed.util.FileUtil;
     34 import com.android.tradefed.util.StreamUtil;
     35 
     36 import org.json.JSONException;
     37 import org.xmlpull.v1.XmlPullParserException;
     38 
     39 import java.io.File;
     40 import java.io.FileNotFoundException;
     41 import java.io.IOException;
     42 import java.io.InputStream;
     43 import java.net.URL;
     44 
     45 /**
     46  * Pushes dynamic config files from config repository
     47  */
     48 @OptionClass(alias="dynamic-config-pusher")
     49 public class DynamicConfigPusher extends BaseTargetPreparer implements ITargetCleaner {
     50     public enum TestTarget {
     51         DEVICE,
     52         HOST
     53     }
     54 
     55     private static final String LOG_TAG = DynamicConfigPusher.class.getSimpleName();
     56 
     57     @Option(name = "cleanup", description = "Whether to remove config files from the test " +
     58             "target after test completion.")
     59     private boolean mCleanup = true;
     60 
     61     @Option(name = "config-url", description = "The url path of the dynamic config. If set, " +
     62             "will override the default config location defined in CompatibilityBuildProvider.")
     63     private String mConfigUrl;
     64 
     65     @Option(name="config-filename", description = "The module name for module-level " +
     66             "configurations, or the suite name for suite-level configurations", mandatory = true)
     67     private String mModuleName;
     68 
     69     @Option(name = "target", description = "The test target, \"device\" or \"host\"",
     70             mandatory = true)
     71     private TestTarget mTarget;
     72 
     73     @Option(name = "version", description = "The version of the configuration to retrieve " +
     74             "from the server, e.g. \"1.0\". Defaults to suite version string.")
     75     private String mVersion;
     76 
     77     // Options for getting the dynamic file from resources.
     78     @Option(name = "extract-from-resource",
     79             description = "Whether to look for the local dynamic config inside the jar resources "
     80                 + "or on the local disk.")
     81     private boolean mExtractFromResource = false;
     82 
     83     @Option(name = "dynamic-resource-name",
     84             description = "When using --extract-from-resource, this option allow to specify the "
     85                 + "resource name, instead of the module name for the lookup. File will still be "
     86                 + "logged under the module name.")
     87     private String mResourceFileName = null;
     88 
     89     private String mDeviceFilePushed;
     90 
     91     void setModuleName(String moduleName) {
     92         mModuleName = moduleName;
     93     }
     94 
     95     /**
     96      * {@inheritDoc}
     97      */
     98     @Override
     99     public void setUp(ITestDevice device, IBuildInfo buildInfo) throws TargetSetupError, BuildError,
    100             DeviceNotAvailableException {
    101 
    102         CompatibilityBuildHelper buildHelper = new CompatibilityBuildHelper(buildInfo);
    103 
    104         File localConfigFile = getLocalConfigFile(buildHelper, device);
    105 
    106         if (mVersion == null) {
    107             mVersion = buildHelper.getSuiteVersion();
    108         }
    109 
    110         String apfeConfigInJson = null;
    111         String originUrl = (mConfigUrl != null) ? mConfigUrl : buildHelper.getDynamicConfigUrl();
    112 
    113         if (originUrl != null) {
    114             String requestUrl = originUrl;
    115             try {
    116                 requestUrl = originUrl
    117                         .replace("{module}", mModuleName).replace("{version}", mVersion);
    118                 java.net.URL request = new URL(requestUrl);
    119                 apfeConfigInJson = StreamUtil.getStringFromStream(request.openStream());
    120             } catch (IOException e) {
    121                 LogUtil.printLog(Log.LogLevel.WARN, LOG_TAG,
    122                         "Cannot download and parse json config from URL " + requestUrl);
    123             }
    124         } else {
    125             LogUtil.printLog(Log.LogLevel.INFO, LOG_TAG,
    126                     "Dynamic config override URL is not set, using local configuration values");
    127         }
    128 
    129         // Use DynamicConfigHandler to merge local and service configuration into one file
    130         File hostFile = mergeConfigFiles(localConfigFile, apfeConfigInJson, mModuleName, device);
    131 
    132         if (TestTarget.DEVICE.equals(mTarget)) {
    133             String deviceDest = String.format("%s%s.dynamic",
    134                     DynamicConfig.CONFIG_FOLDER_ON_DEVICE, mModuleName);
    135             if (!device.pushFile(hostFile, deviceDest)) {
    136                 throw new TargetSetupError(String.format(
    137                         "Failed to push local '%s' to remote '%s'", hostFile.getAbsolutePath(),
    138                         deviceDest), device.getDeviceDescriptor());
    139             }
    140             mDeviceFilePushed = deviceDest;
    141         }
    142         // add host file to build
    143         buildHelper.addDynamicConfigFile(mModuleName, hostFile);
    144     }
    145 
    146     /**
    147      * {@inheritDoc}
    148      */
    149     @Override
    150     public void tearDown(ITestDevice device, IBuildInfo buildInfo, Throwable e)
    151             throws DeviceNotAvailableException {
    152         // Remove any file we have pushed to the device, host file will be moved to the result
    153         // directory by ResultReporter upon invocation completion.
    154         if (mDeviceFilePushed != null && !(e instanceof DeviceNotAvailableException) && mCleanup) {
    155             device.executeShellCommand("rm -r " + mDeviceFilePushed);
    156         }
    157     }
    158 
    159     @VisibleForTesting
    160     final File getLocalConfigFile(CompatibilityBuildHelper buildHelper, ITestDevice device)
    161             throws TargetSetupError {
    162         File localConfigFile = null;
    163         if (mExtractFromResource) {
    164             String lookupName = (mResourceFileName != null) ? mResourceFileName : mModuleName;
    165             InputStream dynamicFileRes = getClass().getResourceAsStream(
    166                     String.format("/%s.dynamic", lookupName));
    167             try {
    168                 localConfigFile = FileUtil.createTempFile(lookupName, ".dynamic");
    169                 FileUtil.writeToFile(dynamicFileRes, localConfigFile);
    170             } catch (IOException e) {
    171                 FileUtil.deleteFile(localConfigFile);
    172                 throw new TargetSetupError(
    173                         String.format("Fail to unpack '%s.dynamic' from resources", lookupName),
    174                         e, device.getDeviceDescriptor());
    175             }
    176             return localConfigFile;
    177         }
    178 
    179         // If not from resources look at local path.
    180         try {
    181             localConfigFile = buildHelper.getTestFile(String.format("%s.dynamic", mModuleName));
    182         } catch (FileNotFoundException e) {
    183             throw new TargetSetupError("Cannot get local dynamic config file from test directory",
    184                     e, device.getDeviceDescriptor());
    185         }
    186         return localConfigFile;
    187     }
    188 
    189     @VisibleForTesting
    190     File mergeConfigFiles(File localConfigFile, String apfeConfigInJson, String moduleName,
    191             ITestDevice device) throws TargetSetupError {
    192         File hostFile = null;
    193         try {
    194             hostFile = DynamicConfigHandler.getMergedDynamicConfigFile(
    195                     localConfigFile, apfeConfigInJson, moduleName);
    196             return hostFile;
    197         } catch (IOException | XmlPullParserException | JSONException e) {
    198             throw new TargetSetupError("Cannot get merged dynamic config file", e,
    199                     device.getDeviceDescriptor());
    200         } finally {
    201             if (mExtractFromResource) {
    202                 FileUtil.deleteFile(localConfigFile);
    203             }
    204         }
    205     }
    206 }
    207