FileFilter.java revision 84cc2dbb1d9f935182fcbeb1ef68dc340d2ebade
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    public FileFilter() {
60        loadTestExpectations();
61    }
62
63    private static final String trimTrailingSlashIfPresent(String path) {
64        File file = new File(path);
65        return file.getPath();
66    }
67
68    public void loadTestExpectations() {
69        URL url = null;
70        try {
71            url = new URL(ForwarderManager.getHostSchemePort(false) +
72                    "LayoutTests/" + TEST_EXPECTATIONS_TXT_PATH);
73        } catch (MalformedURLException e) {
74            assert false;
75        }
76
77        try {
78            InputStream inputStream = null;
79            BufferedReader bufferedReader = null;
80            try {
81                byte[] httpAnswer = FsUtils.readDataFromUrl(url);
82                if (httpAnswer == null) {
83                    Log.w(LOG_TAG, "loadTestExpectations(): File not found: " +
84                            TEST_EXPECTATIONS_TXT_PATH);
85                    return;
86                }
87                bufferedReader = new BufferedReader(new StringReader(
88                        new String(httpAnswer)));
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(
122                            parts[1].split("\\s", 0)));
123
124                    /** Chose the right collections to add to */
125                    if (tokens.contains(TOKEN_CRASH)) {
126                        mCrashList.add(path);
127
128                        /** If test is on skip list we ignore any further options */
129                        continue;
130                    }
131
132                    if (tokens.contains(TOKEN_FAIL)) {
133                        mFailList.add(path);
134                    }
135                    if (tokens.contains(TOKEN_SLOW)) {
136                        mSlowList.add(path);
137                    }
138                }
139            } finally {
140                if (inputStream != null) {
141                    inputStream.close();
142                }
143                if (bufferedReader != null) {
144                    bufferedReader.close();
145                }
146            }
147        } catch (IOException e) {
148            Log.e(LOG_TAG, "url=" + url, e);
149        }
150    }
151
152    /**
153     * Checks if test is expected to crash.
154     *
155     * <p>
156     * Path given should relative within LayoutTests folder, e.g. fast/dom/foo.html
157     *
158     * @param testPath
159     *            - a relative path within LayoutTests folder
160     * @return if the test is supposed to be skipped
161     */
162    public boolean isCrash(String testPath) {
163        for (String prefix : getPrefixes(testPath)) {
164            if (mCrashList.contains(prefix)) {
165                return true;
166            }
167        }
168
169        return false;
170    }
171
172    /**
173     * Checks if test result is supposed to be "failed".
174     *
175     * <p>
176     * Path given should relative within LayoutTests folder, e.g. fast/dom/foo.html
177     *
178     * @param testPath
179     *            - a relative path within LayoutTests folder
180     * @return if the test result is supposed to be "failed"
181     */
182    public boolean isFail(String testPath) {
183        for (String prefix : getPrefixes(testPath)) {
184            if (mFailList.contains(prefix)) {
185                return true;
186            }
187        }
188
189        return false;
190    }
191
192    /**
193     * Checks if test is slow and should have timeout increased.
194     *
195     * <p>
196     * Path given should relative within LayoutTests folder, e.g. fast/dom/foo.html
197     *
198     * @param testPath
199     *            - a relative path within LayoutTests folder
200     * @return if the test is slow and should have timeout increased.
201     */
202    public boolean isSlow(String testPath) {
203        for (String prefix : getPrefixes(testPath)) {
204            if (mSlowList.contains(prefix)) {
205                return true;
206            }
207        }
208
209        return false;
210    }
211
212    /**
213     * Returns the list of all path prefixes of the given path.
214     *
215     * <p>
216     * e.g. this/is/a/path returns the list: this this/is this/is/a this/is/a/path
217     *
218     * @param path
219     * @return the list of all path prefixes of the given path.
220     */
221    private static List<String> getPrefixes(String path) {
222        File file = new File(path);
223        List<String> prefixes = new ArrayList<String>(8);
224
225        do {
226            prefixes.add(file.getPath());
227            file = file.getParentFile();
228        } while (file != null);
229
230        return prefixes;
231    }
232
233    /**
234     * Checks if the directory may contain tests or contains just helper files.
235     *
236     * @param dirName
237     * @return
238     *      if the directory may contain tests
239     */
240    public static boolean isTestDir(String dirName) {
241        return (!dirName.equals("script-tests")
242                && !dirName.equals("resources") && !dirName.startsWith("."));
243    }
244
245    /**
246     * Checks if the file is a test.
247     * Currently we run .html, .xhtml and .php tests.
248     *
249     * @warning You MUST also call isTestDir() on the parent directory before
250     * assuming that a file is a test.
251     *
252     * @param testName
253     * @return if the file is a test
254     */
255    public static boolean isTestFile(String testName) {
256        return testName.endsWith(".html")
257            || testName.endsWith(".xhtml")
258            || testName.endsWith(".php");
259    }
260
261    /**
262     * Return a URL of the test on the server.
263     *
264     * @param relativePath
265     * @param allowHttps Whether to allow the use of HTTPS, even if the file is in the SSL
266     *     directory.
267     * @return a URL of the test on the server
268     */
269    public static URL getUrl(String relativePath, boolean allowHttps) {
270        String urlBase = ForwarderManager.getHostSchemePort(false);
271
272        /**
273         * URL is formed differently for HTTP vs non-HTTP tests, because HTTP tests
274         * expect different document root. See run_apache2.py and .conf file for details
275         */
276        if (relativePath.startsWith(HTTP_TESTS_PATH)) {
277            relativePath = relativePath.substring(HTTP_TESTS_PATH.length());
278            if (relativePath.startsWith(SSL_PATH) && allowHttps) {
279                urlBase = ForwarderManager.getHostSchemePort(true);
280            }
281        } else {
282            relativePath = "LayoutTests/" + relativePath;
283        }
284
285        try {
286            return new URL(urlBase + relativePath);
287        } catch (MalformedURLException e) {
288            Log.e(LOG_TAG, "Malformed URL!", e);
289        }
290
291        return null;
292    }
293
294    /**
295     * If the path contains extension (e.g .foo at the end of the file) then it changes
296     * this (.foo) into newEnding (so it has to contain the dot if we want to preserve it).
297     *
298     * <p>If the path doesn't contain an extension, it adds the ending to the path.
299     *
300     * @param relativePath
301     * @param newEnding
302     * @return
303     *      a new path, containing the newExtension
304     */
305    public static String setPathEnding(String relativePath, String newEnding) {
306        int dotPos = relativePath.lastIndexOf('.');
307        if (dotPos == -1) {
308            return relativePath + newEnding;
309        }
310
311        return relativePath.substring(0, dotPos) + newEnding;
312    }
313}
314