• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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.compatibility.common.tradefed.targetprep;
18 
19 import com.android.compatibility.common.tradefed.build.VtsCompatibilityInvocationHelper;
20 import com.android.ddmlib.Log;
21 import com.android.tradefed.build.IBuildInfo;
22 import com.android.tradefed.config.Option;
23 import com.android.tradefed.config.OptionClass;
24 import com.android.tradefed.device.ITestDevice;
25 import com.android.tradefed.device.DeviceNotAvailableException;
26 import com.android.tradefed.log.LogUtil.CLog;
27 import com.android.tradefed.targetprep.BuildError;
28 import com.android.tradefed.targetprep.PushFilePreparer;
29 import com.android.tradefed.targetprep.TargetSetupError;
30 import com.android.tradefed.testtype.IAbi;
31 import com.android.tradefed.testtype.IAbiReceiver;
32 
33 import java.io.File;
34 import java.util.TreeSet;
35 import java.util.Collection;
36 import java.lang.Class;
37 import java.io.BufferedReader;
38 import java.io.FileReader;
39 import java.io.FileNotFoundException;
40 
41 /**
42  * Pushes specified testing artifacts from Compatibility repository.
43  */
44 @OptionClass(alias = "vts-file-pusher")
45 public class VtsFilePusher extends PushFilePreparer implements IAbiReceiver {
46     @Option(name="push-group", description=
47             "A push group name. Must be a .push file under tools/vts-tradefed/res/push_groups/. "
48                     + "May be under a relative path. May be repeated. Duplication of file specs "
49                     + "is ok. Will throw a TargetSetupError if a file push fails.")
50     private Collection<String> mPushSpecGroups = new TreeSet<>();
51 
52     @Option(name="push-group-cleanup", description = "Whether files in push group "
53             + "should be cleaned up from device after test. Note that preparer does not verify "
54             + "that files/directories have been deleted. Default value: true.")
55     private boolean mPushGroupCleanup = true;
56 
57     @Option(name="push-group-remount-system", description="Whether to remounts system "
58             + "partition to be writable before push or clean up default files. "
59             + "Default value: false")
60     private boolean mPushGroupRemount = false;
61 
62     @Option(name = "append-bitness", description = "Append the ABI's bitness to the filename.")
63     private boolean mAppendBitness = false;
64 
65     private static final String DIR_PUSH_GROUPS = "vts/tools/vts-tradefed/res/push_groups";
66     static final String PUSH_GROUP_FILE_EXTENSION = ".push";
67 
68     private Collection<String> mFilesPushed = new TreeSet<>();
69     private IAbi mAbi;
70     private VtsCompatibilityInvocationHelper mInvocationHelper;
71 
72     /**
73      * Load file push specs from .push files as a collection of Strings
74      * @param buildInfo
75      * @return a collection of push spec strings
76      * @throws TargetSetupError if load fails
77      */
loadFilePushGroups(IBuildInfo buildInfo)78     private Collection<String> loadFilePushGroups(IBuildInfo buildInfo) throws TargetSetupError {
79         Collection<String> result = new TreeSet<>();
80         File testDir;
81         try {
82             testDir = mInvocationHelper.getTestsDir();
83         } catch(FileNotFoundException e) {
84             throw new TargetSetupError(e.getMessage());
85         }
86 
87         for (String group: mPushSpecGroups) {
88             TreeSet<String> stack = new TreeSet<>();
89             result.addAll(loadFilePushGroup(group, testDir.getAbsolutePath(), stack));
90         }
91         return result;
92     }
93 
94     /**
95      * Recursively load file push specs from a push group file into a collection of strings.
96      *
97      * @param specFile, push group file name with .push extension. Can contain relative directory.
98      * @param testsDir, the directory where test data files are stored.
99      */
loadFilePushGroup(String specFileName, String testsDir, Collection<String> stack)100     private Collection<String> loadFilePushGroup(String specFileName, String testsDir,
101             Collection<String> stack) throws TargetSetupError {
102         Collection<String> result = new TreeSet<>();
103 
104         String relativePath = new File(
105                 DIR_PUSH_GROUPS, specFileName).getPath();
106         File specFile = null;
107 
108         try {
109             specFile = new File(testsDir, relativePath);
110         } catch(Exception e) {
111             throw new TargetSetupError(e.getMessage());
112         }
113 
114         try (BufferedReader br = new BufferedReader(new FileReader(specFile))) {
115             String line;
116             while ((line = br.readLine()) != null) {
117                 String spec = line.trim();
118                 if (spec.contains("->")) {
119                     result.add(spec);
120                 } else if (spec.contains(PUSH_GROUP_FILE_EXTENSION)) {
121                     if (!stack.contains(spec)) {
122                         stack.add(spec);
123                         result.addAll(loadFilePushGroup(spec, testsDir, stack));
124                         stack.remove(spec);
125                     }
126                 } else if (spec.length() > 0) {
127                     throw new TargetSetupError("Unknown file push spec: " + spec);
128                 }
129             }
130         } catch(Exception e) {
131             throw new TargetSetupError(e.getMessage());
132         }
133 
134         return result;
135     }
136 
137     /**
138      * Push file groups if configured in .xml file.
139      * @param device
140      * @param buildInfo
141      * @throws TargetSetupError, DeviceNotAvailableException
142      */
pushFileGroups(ITestDevice device, IBuildInfo buildInfo)143     private void pushFileGroups(ITestDevice device, IBuildInfo buildInfo)
144             throws TargetSetupError, DeviceNotAvailableException {
145         if (mPushGroupRemount) {
146             device.remountSystemWritable();
147         }
148 
149         for (String pushspec : loadFilePushGroups(buildInfo)) {
150             String[] pair = pushspec.split("->");
151 
152             if (pair.length != 2) {
153                 throw new TargetSetupError(
154                         String.format("Failed to parse push spec '%s'", pushspec));
155             }
156 
157             File src = new File(pair[0]);
158 
159             if (!src.isAbsolute()) {
160                 src = resolveRelativeFilePath(buildInfo, pair[0]);
161             }
162 
163             Class cls = this.getClass();
164 
165             if (!src.exists()) {
166                 Log.w(cls.getSimpleName(), String.format(
167                         "Skipping push spec in push group whose source does not exist: %s",
168                         pushspec));
169                 continue;
170             }
171 
172             Log.d(cls.getSimpleName(),
173                     String.format("Trying to push file from local to remote: %s", pushspec));
174 
175             if ((src.isDirectory() && !device.pushDir(src, pair[1])) ||
176                     (!device.pushFile(src, pair[1]))) {
177                 mFilesPushed = null;
178                 throw new TargetSetupError(String.format("Failed to push local '%s' to remote '%s'",
179                         pair[0], pair[1]));
180             } else {
181                 mFilesPushed.add(pair[1]);
182             }
183         }
184     }
185 
186     /**
187      * {@inheritDoc}
188      */
189     @Override
setUp(ITestDevice device, IBuildInfo buildInfo)190     public void setUp(ITestDevice device, IBuildInfo buildInfo)
191             throws TargetSetupError, BuildError, DeviceNotAvailableException {
192         device.enableAdbRoot();
193         mInvocationHelper = new VtsCompatibilityInvocationHelper();
194         pushFileGroups(device, buildInfo);
195 
196         super.setUp(device, buildInfo);
197     }
198 
199     /**
200      * {@inheritDoc}
201      */
202     @Override
tearDown(ITestDevice device, IBuildInfo buildInfo, Throwable e)203     public void tearDown(ITestDevice device, IBuildInfo buildInfo, Throwable e)
204             throws DeviceNotAvailableException {
205 
206         if (!(e instanceof DeviceNotAvailableException) && mPushGroupCleanup && mFilesPushed != null) {
207             device.enableAdbRoot();
208             if (mPushGroupRemount) {
209                 device.remountSystemWritable();
210             }
211             for (String devicePath : mFilesPushed) {
212                 device.executeShellCommand("rm -r " + devicePath);
213             }
214         }
215 
216         super.tearDown(device, buildInfo, e);
217     }
218 
219     /**
220      * {@inheritDoc}
221      */
222     @Override
setAbi(IAbi abi)223     public void setAbi(IAbi abi) {
224         mAbi = abi;
225     }
226 
227     /**
228      * {@inheritDoc}
229      */
230     @Override
getAbi()231     public IAbi getAbi() {
232         return mAbi;
233     }
234 
235     /**
236      * {@inheritDoc}
237      */
238     @Override
resolveRelativeFilePath(IBuildInfo buildInfo, String fileName)239     public File resolveRelativeFilePath(IBuildInfo buildInfo, String fileName) {
240         File f = null;
241         try {
242             f = new File(mInvocationHelper.getTestsDir(),
243                     String.format("%s%s", fileName, mAppendBitness ? mAbi.getBitness() : ""));
244             CLog.d("Copying from %s", f.getAbsolutePath());
245             return f;
246         } catch (FileNotFoundException e) {
247             CLog.e(e);
248             CLog.e("File not found: %s", f);
249         }
250         return null;
251     }
252 }
253 
254