OSDN Git Service

c2d6b14b35e297e07a0b0624953e73351b979252
[android-x86/dalvik.git] / libcore / tools / runner / java / dalvik / runner / Mode.java
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
17 package dalvik.runner;
18
19 import java.io.File;
20 import java.io.FileOutputStream;
21 import java.io.FilenameFilter;
22 import java.io.IOException;
23 import java.util.Arrays;
24 import java.util.Collections;
25 import java.util.HashSet;
26 import java.util.List;
27 import java.util.Properties;
28 import java.util.Set;
29 import java.util.concurrent.TimeoutException;
30 import java.util.logging.Logger;
31 import java.util.regex.Pattern;
32
33 /**
34  * A Mode for running tests. Examples including running in a virtual
35  * machine either on the host or a device or within a specific context
36  * such as within an Activity.
37  */
38 abstract class Mode {
39
40     private static final Pattern JAVA_TEST_PATTERN = Pattern.compile("\\/(\\w)+\\.java$");
41
42     private static final Logger logger = Logger.getLogger(Mode.class.getName());
43
44     protected final Environment environment;
45     protected final long timeoutSeconds;
46     protected final File sdkJar;
47
48     /**
49      * Set of Java files needed to built to tun the currently selected
50      * set of tests. We build a subset rather than all the files all
51      * the time to reduce dex packaging costs in the activity mode
52      * case.
53      */
54     protected final Set<File> testRunnerJava = new HashSet<File>();
55
56     /**
57      * Classpath of testRunner on the host side including any
58      * supporting libraries for testRunnerJava. Useful for compiling
59      * testRunnerJava as well as executing it on the host. Execution
60      * on the device requires further packaging typically done by
61      * postCompileTestRunner.
62      */
63     protected final Classpath testRunnerClasspath = new Classpath();
64
65     // TODO: this should be an immutable collection.
66     protected final Classpath testClasspath = Classpath.of(
67             new File("dalvik/libcore/tools/runner/lib/jsr305.jar"),
68             new File("dalvik/libcore/tools/runner/lib/guava.jar"),
69             new File("dalvik/libcore/tools/runner/lib/caliper.jar"),
70             // TODO: we should be able to work with a shipping SDK, not depend on out/...
71             // dalvik/libcore/**/test/ for junit
72             // TODO: jar up just the junit classes and drop the jar in our lib/ directory.
73             new File("out/target/common/obj/JAVA_LIBRARIES/core-tests_intermediates/classes.jar").getAbsoluteFile());
74
75     Mode(Environment environment, long timeoutSeconds, File sdkJar) {
76         this.environment = environment;
77         this.timeoutSeconds = timeoutSeconds;
78         this.sdkJar = sdkJar;
79     }
80
81     /**
82      * Initializes the temporary directories and test harness necessary to run
83      * tests.
84      */
85     protected void prepare(Set<File> testRunnerJava, Classpath testRunnerClasspath) {
86         this.testRunnerJava.add(new File(DalvikRunner.HOME_JAVA, "dalvik/runner/TestRunner.java"));
87         this.testRunnerJava.addAll(dalvikAnnotationSourceFiles());
88         this.testRunnerJava.addAll(testRunnerJava);
89         this.testRunnerClasspath.addAll(testRunnerClasspath);
90         environment.prepare();
91         compileTestRunner();
92     }
93
94     private List<File> dalvikAnnotationSourceFiles() {
95         // Hopefully one day we'll strip the dalvik annotations out, but until then we need to make
96         // them available to javac(1).
97         File sourceDir = new File("dalvik/libcore/dalvik/src/main/java/dalvik/annotation");
98         File[] javaSourceFiles = sourceDir.listFiles(new FilenameFilter() {
99             public boolean accept(File dir, String filename) {
100                 return filename.endsWith(".java");
101             }
102         });
103         return Arrays.asList(javaSourceFiles);
104     }
105
106     private void compileTestRunner() {
107         logger.fine("build testrunner");
108
109         Classpath classpath = new Classpath();
110         classpath.addAll(testClasspath);
111         classpath.addAll(testRunnerClasspath);
112
113         File base = environment.testRunnerClassesDir();
114         new Mkdir().mkdirs(base);
115         new Javac()
116                 .bootClasspath(sdkJar)
117                 .classpath(classpath)
118                 .sourcepath(DalvikRunner.HOME_JAVA)
119                 .destination(base)
120                 .compile(testRunnerJava);
121         postCompileTestRunner();
122     }
123
124     /**
125      * Hook method called after TestRunner compilation.
126      */
127     abstract protected void postCompileTestRunner();
128
129     /**
130      * Compiles classes for the given test and makes them ready for execution.
131      * If the test could not be compiled successfully, it will be updated with
132      * the appropriate test result.
133      */
134     public void buildAndInstall(TestRun testRun) {
135         logger.fine("build " + testRun.getQualifiedName());
136
137         boolean testCompiled;
138         try {
139             testCompiled = compileTest(testRun);
140             if (!testCompiled) {
141                 testRun.setResult(Result.UNSUPPORTED, Collections.<String>emptyList());
142                 return;
143             }
144         } catch (CommandFailedException e) {
145             testRun.setResult(Result.COMPILE_FAILED, e.getOutputLines());
146             return;
147         } catch (IOException e) {
148             testRun.setResult(Result.ERROR, e);
149             return;
150         }
151         testRun.setTestCompiled(testCompiled);
152         environment.prepareUserDir(testRun);
153     }
154
155     /**
156      * Compiles the classes for the described test.
157      *
158      * @return the path to the compiled classes (directory or jar), or {@code
159      *      null} if the test could not be compiled.
160      * @throws CommandFailedException if javac fails
161      */
162     private boolean compileTest(TestRun testRun) throws IOException {
163         if (!JAVA_TEST_PATTERN.matcher(testRun.getTestJava().toString()).find()) {
164             return false;
165         }
166
167         String qualifiedName = testRun.getQualifiedName();
168         File testClassesDir = environment.testClassesDir(testRun);
169         new Mkdir().mkdirs(testClassesDir);
170         FileOutputStream propertiesOut = new FileOutputStream(
171                 new File(testClassesDir, TestProperties.FILE));
172         Properties properties = new Properties();
173         fillInProperties(properties, testRun);
174         properties.store(propertiesOut, "generated by " + Mode.class.getName());
175         propertiesOut.close();
176
177         Classpath classpath = new Classpath();
178         classpath.addAll(testClasspath);
179         classpath.addAll(testRun.getRunnerClasspath());
180
181         Set<File> sourceFiles = new HashSet<File>();
182         sourceFiles.add(testRun.getTestJava());
183         sourceFiles.addAll(dalvikAnnotationSourceFiles());
184
185         // compile the test case
186         new Javac()
187                 .bootClasspath(sdkJar)
188                 .classpath(classpath)
189                 .sourcepath(testRun.getTestDirectory())
190                 .destination(testClassesDir)
191                 .compile(sourceFiles);
192         postCompileTest(testRun);
193         return true;
194     }
195
196     /**
197      * Hook method called after test compilation.
198      *
199      * @param testRun The test being compiled
200      */
201     abstract protected void postCompileTest(TestRun testRun);
202
203
204     /**
205      * Fill in properties for running in this mode
206      */
207     protected void fillInProperties(Properties properties, TestRun testRun) {
208         properties.setProperty(TestProperties.TEST_CLASS, testRun.getTestClass());
209         properties.setProperty(TestProperties.QUALIFIED_NAME, testRun.getQualifiedName());
210         properties.setProperty(TestProperties.RUNNER_CLASS, testRun.getRunnerClass().getName());
211     }
212
213     /**
214      * Runs the test, and updates its test result.
215      */
216     void runTest(TestRun testRun) {
217         if (!testRun.isRunnable()) {
218             throw new IllegalArgumentException();
219         }
220
221         final List<Command> commands = buildCommands(testRun);
222
223         List<String> output = null;
224         for (final Command command : commands) {
225             try {
226                 output = command.executeWithTimeout(timeoutSeconds);
227             } catch (TimeoutException e) {
228                 testRun.setResult(Result.EXEC_TIMEOUT,
229                         Collections.singletonList("Exceeded timeout! (" + timeoutSeconds + "s)"));
230                 return;
231             } catch (Exception e) {
232                 testRun.setResult(Result.ERROR, e);
233                 return;
234             }
235         }
236         // we only look at the output of the last command
237         if (output.isEmpty()) {
238             testRun.setResult(Result.ERROR,
239                     Collections.singletonList("No output returned!"));
240             return;
241         }
242
243         Result result = TestProperties.RESULT_SUCCESS.equals(output.get(output.size() - 1))
244                 ? Result.SUCCESS
245                 : Result.EXEC_FAILED;
246         testRun.setResult(result, output.subList(0, output.size() - 1));
247     }
248
249     /**
250      * Returns commands for test execution.
251      */
252     protected abstract List<Command> buildCommands(TestRun testRun);
253
254     /**
255      * Deletes files and releases any resources required for the execution of
256      * the given test.
257      */
258     void cleanup(TestRun testRun) {
259         environment.cleanup(testRun);
260     }
261
262     /**
263      * Cleans up after all test runs have completed.
264      */
265     void shutdown() {
266         environment.shutdown();
267     }
268 }