FileFilter.java revision 5f21f5a4a9f240e1c35ab86b2f3a332f0d541cf0
1/*
2 * Copyright (C) 2010 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
17package com.android.dumprendertree2;
18
19import android.util.Log;
20
21import com.android.dumprendertree2.forwarder.ForwarderManager;
22
23import java.io.BufferedReader;
24import java.io.File;
25import java.io.FileNotFoundException;
26import java.io.IOException;
27import java.io.InputStream;
28import java.io.InputStreamReader;
29import java.io.StringReader;
30import java.net.MalformedURLException;
31import java.net.URL;
32import java.net.URLConnection;
33import java.util.ArrayList;
34import java.util.Arrays;
35import java.util.HashSet;
36import java.util.List;
37import java.util.Set;
38
39/**
40 * A utility to filter out some files/directories from the views and tests that run.
41 */
42public class FileFilter {
43    private static final String LOG_TAG = "FileFilter";
44
45    private static final String TEST_EXPECTATIONS_TXT_PATH =
46            "platform/android/test_expectations.txt";
47
48    private static final String HTTP_TESTS_PATH = "http/tests/";
49    private static final String SSL_PATH = "ssl/";
50
51    private static final String TOKEN_CRASH = "CRASH";
52    private static final String TOKEN_FAIL = "FAIL";
53    private static final String TOKEN_SLOW = "SLOW";
54
55    private final Set<String> mCrashList = new HashSet<String>();
56    private final Set<String> mFailList = new HashSet<String>();
57    private final Set<String> mSlowList = new HashSet<String>();
58
59    private final String mRootDirPath;
60
61    public FileFilter(String rootDirPath) {
62        /** It may or may not contain a trailing slash */
63        this.mRootDirPath = rootDirPath;
64
65        loadTestExpectations();
66    }
67
68    private static final String trimTrailingSlashIfPresent(String path) {
69        File file = new File(path);
70        return file.getPath();
71    }
72
73    public void loadTestExpectations() {
74        URL url = null;
75        try {
76            url = new URL(ForwarderManager.getHostSchemePort(false) + "LayoutTests/" +
77                    TEST_EXPECTATIONS_TXT_PATH);
78        } catch (MalformedURLException e) {
79            assert false;
80        }
81
82        try {
83            InputStream inputStream = null;
84            BufferedReader bufferedReader = null;
85            try {
86                bufferedReader = new BufferedReader(new StringReader(new String(
87                        FsUtils.readDataFromUrl(url))));
88
89                String line;
90                String entry;
91                String[] parts;
92                String path;
93                Set<String> tokens;
94                while (true) {
95                    line = bufferedReader.readLine();
96                    if (line == null) {
97                        break;
98                    }
99
100                    /** Remove the comment and trim */
101                    entry = line.split("//", 2)[0].trim();
102
103                    /** Omit empty lines, advance to next line */
104                    if (entry.isEmpty()) {
105                        continue;
106                    }
107
108                    /** Split on whitespace into path part and the rest */
109                    parts = entry.split("\\s", 2);
110
111                    /** At this point parts.length >= 1 */
112                    if (parts.length == 1) {
113                        Log.w(LOG_TAG + "::reloadConfiguration",
114                                "There are no options specified for the test!");
115                        continue;
116                    }
117
118                    path = trimTrailingSlashIfPresent(parts[0]);
119
120                    /** Split on whitespace */
121                    tokens = new HashSet<String>(Arrays.asList(parts[1].split("\\s", 0)));
122
123                    /** Chose the right collections to add to */
124                    if (tokens.contains(TOKEN_CRASH)) {
125                        mCrashList.add(path);
126
127                        /** If test is on skip list we ignore any further options */
128                        continue;
129                    }
130
131                    if (tokens.contains(TOKEN_FAIL)) {
132                        mFailList.add(path);
133                    }
134                    if (tokens.contains(TOKEN_SLOW)) {
135                        mSlowList.add(path);
136                    }
137                }
138            } finally {
139                if (inputStream != null) {
140                    inputStream.close();
141                }
142                if (bufferedReader != null) {
143                    bufferedReader.close();
144                }
145            }
146        } catch (FileNotFoundException e) {
147            Log.w(LOG_TAG, "reloadConfiguration(): File not found: " + e.getMessage());
148        } catch (IOException e) {
149            Log.e(LOG_TAG, "url=" + url, e);
150        }
151    }
152
153    /**
154     * Checks if test is expected to crash.
155     *
156     * <p>
157     * Path given should relative within LayoutTests folder, e.g. fast/dom/foo.html
158     *
159     * @param testPath
160     *            - a relative path within LayoutTests folder
161     * @return if the test is supposed to be skipped
162     */
163    public boolean isCrash(String testPath) {
164        for (String prefix : getPrefixes(testPath)) {
165            if (mCrashList.contains(prefix)) {
166                return true;
167            }
168        }
169
170        return false;
171    }
172
173    /**
174     * Checks if test result is supposed to be "failed".
175     *
176     * <p>
177     * Path given should relative within LayoutTests folder, e.g. fast/dom/foo.html
178     *
179     * @param testPath
180     *            - a relative path within LayoutTests folder
181     * @return if the test result is supposed to be "failed"
182     */
183    public boolean isFail(String testPath) {
184        for (String prefix : getPrefixes(testPath)) {
185            if (mFailList.contains(prefix)) {
186                return true;
187            }
188        }
189
190        return false;
191    }
192
193    /**
194     * Checks if test is slow and should have timeout increased.
195     *
196     * <p>
197     * Path given should relative within LayoutTests folder, e.g. fast/dom/foo.html
198     *
199     * @param testPath
200     *            - a relative path within LayoutTests folder
201     * @return if the test is slow and should have timeout increased.
202     */
203    public boolean isSlow(String testPath) {
204        for (String prefix : getPrefixes(testPath)) {
205            if (mSlowList.contains(prefix)) {
206                return true;
207            }
208        }
209
210        return false;
211    }
212
213    /**
214     * Returns the list of all path prefixes of the given path.
215     *
216     * <p>
217     * e.g. this/is/a/path returns the list: this this/is this/is/a this/is/a/path
218     *
219     * @param path
220     * @return the list of all path prefixes of the given path.
221     */
222    private static List<String> getPrefixes(String path) {
223        File file = new File(path);
224        List<String> prefixes = new ArrayList<String>(8);
225
226        do {
227            prefixes.add(file.getPath());
228            file = file.getParentFile();
229        } while (file != null);
230
231        return prefixes;
232    }
233
234    /**
235     * Checks if the directory may contain tests or contains just helper files.
236     *
237     * @param dirName
238     * @return
239     *      if the directory may contain tests
240     */
241    public static boolean isTestDir(String dirName) {
242        return (!dirName.equals("script-tests")
243                && !dirName.equals("resources") && !dirName.startsWith("."));
244    }
245
246    /**
247     * Checks if the file is a test.
248     * Currently we run .html and .xhtml tests.
249     *
250     * @param testName
251     * @return
252     *      if the file is a test
253     */
254    public static boolean isTestFile(String testName) {
255        return testName.endsWith(".html") || testName.endsWith(".xhtml");
256    }
257
258    /**
259     * Return a URL of the test on the server.
260     *
261     * @param relativePath
262     * @return a URL of the test on the server
263     */
264    public static URL getUrl(String relativePath) {
265        String urlBase = ForwarderManager.getHostSchemePort(false);
266
267        /**
268         * URL is formed differently for HTTP vs non-HTTP tests, because HTTP tests
269         * expect different document root. See run_apache2.py and .conf file for details
270         */
271        if (relativePath.startsWith(HTTP_TESTS_PATH)) {
272            relativePath = relativePath.substring(HTTP_TESTS_PATH.length());
273            if (relativePath.startsWith(SSL_PATH)) {
274                urlBase = ForwarderManager.getHostSchemePort(true);
275            }
276        } else {
277            relativePath = "LayoutTests/" + relativePath;
278        }
279
280        try {
281            return new URL(urlBase + relativePath);
282        } catch (MalformedURLException e) {
283            Log.e(LOG_TAG, "Malformed URL!", e);
284        }
285
286        return null;
287    }
288
289    /**
290     * Return the path to the file relative to the tests root dir
291     *
292     * @param filePath
293     * @return
294     *      the path relative to the tests root dir
295     */
296    public String getRelativePath(String filePath) {
297        File rootDir = new File(mRootDirPath);
298        return filePath.replaceFirst(rootDir.getPath() + File.separator, "");
299    }
300
301    /**
302     * Return the path to the file relative to the tests root dir
303     *
304     * @param filePath
305     * @return
306     *      the path relative to the tests root dir
307     */
308    public String getRelativePath(File file) {
309        return getRelativePath(file.getAbsolutePath());
310    }
311
312    public File getAbsoluteFile(String relativePath) {
313        return new File(mRootDirPath, relativePath);
314    }
315
316    public String getAboslutePath(String relativePath) {
317        return getAbsoluteFile(relativePath).getAbsolutePath();
318    }
319
320    /**
321     * If the path contains extension (e.g .foo at the end of the file) then it changes
322     * this (.foo) into newEnding (so it has to contain the dot if we want to preserve it).
323     *
324     * <p>If the path doesn't contain an extension, it adds the ending to the path.
325     *
326     * @param relativePath
327     * @param newEnding
328     * @return
329     *      a new path, containing the newExtension
330     */
331    public static String setPathEnding(String relativePath, String newEnding) {
332        int dotPos = relativePath.lastIndexOf('.');
333        if (dotPos == -1) {
334            return relativePath + newEnding;
335        }
336
337        return relativePath.substring(0, dotPos) + newEnding;
338    }
339}