1c36fab6a0e8274010c23fcef4576e07b190fd257Jorg Pleumann/*
2c36fab6a0e8274010c23fcef4576e07b190fd257Jorg Pleumann * Copyright (C) 2009 The Android Open Source Project
3c36fab6a0e8274010c23fcef4576e07b190fd257Jorg Pleumann *
4c36fab6a0e8274010c23fcef4576e07b190fd257Jorg Pleumann * Licensed under the Apache License, Version 2.0 (the "License");
5c36fab6a0e8274010c23fcef4576e07b190fd257Jorg Pleumann * you may not use this file except in compliance with the License.
6c36fab6a0e8274010c23fcef4576e07b190fd257Jorg Pleumann * You may obtain a copy of the License at
7c36fab6a0e8274010c23fcef4576e07b190fd257Jorg Pleumann *
8c36fab6a0e8274010c23fcef4576e07b190fd257Jorg Pleumann *      http://www.apache.org/licenses/LICENSE-2.0
9c36fab6a0e8274010c23fcef4576e07b190fd257Jorg Pleumann *
10c36fab6a0e8274010c23fcef4576e07b190fd257Jorg Pleumann * Unless required by applicable law or agreed to in writing, software
11c36fab6a0e8274010c23fcef4576e07b190fd257Jorg Pleumann * distributed under the License is distributed on an "AS IS" BASIS,
12c36fab6a0e8274010c23fcef4576e07b190fd257Jorg Pleumann * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13c36fab6a0e8274010c23fcef4576e07b190fd257Jorg Pleumann * See the License for the specific language governing permissions and
14c36fab6a0e8274010c23fcef4576e07b190fd257Jorg Pleumann * limitations under the License.
15c36fab6a0e8274010c23fcef4576e07b190fd257Jorg Pleumann */
16c36fab6a0e8274010c23fcef4576e07b190fd257Jorg Pleumannpackage com.google.coretests;
17c36fab6a0e8274010c23fcef4576e07b190fd257Jorg Pleumann
18c36fab6a0e8274010c23fcef4576e07b190fd257Jorg Pleumannimport java.io.File;
19c36fab6a0e8274010c23fcef4576e07b190fd257Jorg Pleumannimport java.io.FileInputStream;
20c36fab6a0e8274010c23fcef4576e07b190fd257Jorg Pleumannimport java.io.ObjectInputStream;
21c36fab6a0e8274010c23fcef4576e07b190fd257Jorg Pleumann
22c36fab6a0e8274010c23fcef4576e07b190fd257Jorg Pleumannimport junit.framework.AssertionFailedError;
23c36fab6a0e8274010c23fcef4576e07b190fd257Jorg Pleumannimport junit.framework.Protectable;
24c36fab6a0e8274010c23fcef4576e07b190fd257Jorg Pleumannimport junit.framework.TestCase;
25c36fab6a0e8274010c23fcef4576e07b190fd257Jorg Pleumannimport junit.framework.TestResult;
26c36fab6a0e8274010c23fcef4576e07b190fd257Jorg Pleumannimport junit.textui.TestRunner;
27c36fab6a0e8274010c23fcef4576e07b190fd257Jorg Pleumann
28c36fab6a0e8274010c23fcef4576e07b190fd257Jorg Pleumann/**
29c36fab6a0e8274010c23fcef4576e07b190fd257Jorg Pleumann * A wrapper around a single test that allows to execute the test either in the
30c36fab6a0e8274010c23fcef4576e07b190fd257Jorg Pleumann * same thread, in a separate thread, or even in a different process.
31c36fab6a0e8274010c23fcef4576e07b190fd257Jorg Pleumann */
32c36fab6a0e8274010c23fcef4576e07b190fd257Jorg Pleumannpublic class CoreTestRunnable implements Runnable {
33c36fab6a0e8274010c23fcef4576e07b190fd257Jorg Pleumann
34c36fab6a0e8274010c23fcef4576e07b190fd257Jorg Pleumann    private static boolean IS_DALVIK = "Dalvik".equals(
35c36fab6a0e8274010c23fcef4576e07b190fd257Jorg Pleumann            System.getProperty("java.vm.name"));
36c36fab6a0e8274010c23fcef4576e07b190fd257Jorg Pleumann
37c36fab6a0e8274010c23fcef4576e07b190fd257Jorg Pleumann    /**
38c36fab6a0e8274010c23fcef4576e07b190fd257Jorg Pleumann     * The test case we are supposed to run.
39c36fab6a0e8274010c23fcef4576e07b190fd257Jorg Pleumann     */
40c36fab6a0e8274010c23fcef4576e07b190fd257Jorg Pleumann    private TestCase fTest;
41c36fab6a0e8274010c23fcef4576e07b190fd257Jorg Pleumann
42c36fab6a0e8274010c23fcef4576e07b190fd257Jorg Pleumann    /**
43c36fab6a0e8274010c23fcef4576e07b190fd257Jorg Pleumann     * The TestResult we need to update after the run.
44c36fab6a0e8274010c23fcef4576e07b190fd257Jorg Pleumann     */
45c36fab6a0e8274010c23fcef4576e07b190fd257Jorg Pleumann    private TestResult fResult;
46c36fab6a0e8274010c23fcef4576e07b190fd257Jorg Pleumann
47c36fab6a0e8274010c23fcef4576e07b190fd257Jorg Pleumann    /**
48c36fab6a0e8274010c23fcef4576e07b190fd257Jorg Pleumann     * The Protectable that JUnit has created for us.
49c36fab6a0e8274010c23fcef4576e07b190fd257Jorg Pleumann     */
50c36fab6a0e8274010c23fcef4576e07b190fd257Jorg Pleumann    private Protectable fProtectable;
51c36fab6a0e8274010c23fcef4576e07b190fd257Jorg Pleumann
52c36fab6a0e8274010c23fcef4576e07b190fd257Jorg Pleumann    /**
53c36fab6a0e8274010c23fcef4576e07b190fd257Jorg Pleumann     * Reflects whether we need to invert the test result, which is used for
54c36fab6a0e8274010c23fcef4576e07b190fd257Jorg Pleumann     * treating known failures.
55c36fab6a0e8274010c23fcef4576e07b190fd257Jorg Pleumann     */
56c36fab6a0e8274010c23fcef4576e07b190fd257Jorg Pleumann    private boolean fInvert;
57c36fab6a0e8274010c23fcef4576e07b190fd257Jorg Pleumann
58c36fab6a0e8274010c23fcef4576e07b190fd257Jorg Pleumann    /**
59c36fab6a0e8274010c23fcef4576e07b190fd257Jorg Pleumann     * Reflects whether we need to isolate the test, which means we run it in
60c36fab6a0e8274010c23fcef4576e07b190fd257Jorg Pleumann     * a separate process.
61c36fab6a0e8274010c23fcef4576e07b190fd257Jorg Pleumann     */
62c36fab6a0e8274010c23fcef4576e07b190fd257Jorg Pleumann    private boolean fIsolate;
63c36fab6a0e8274010c23fcef4576e07b190fd257Jorg Pleumann
64c36fab6a0e8274010c23fcef4576e07b190fd257Jorg Pleumann    /**
65c36fab6a0e8274010c23fcef4576e07b190fd257Jorg Pleumann     * If we are isolating the test case, this holds the process that is running
66c36fab6a0e8274010c23fcef4576e07b190fd257Jorg Pleumann     * it.
67c36fab6a0e8274010c23fcef4576e07b190fd257Jorg Pleumann     */
68c36fab6a0e8274010c23fcef4576e07b190fd257Jorg Pleumann    private Process fProcess;
69c36fab6a0e8274010c23fcef4576e07b190fd257Jorg Pleumann
70c36fab6a0e8274010c23fcef4576e07b190fd257Jorg Pleumann    /**
71c36fab6a0e8274010c23fcef4576e07b190fd257Jorg Pleumann     * Creates a new CoreTestRunnable for the given parameters.
72c36fab6a0e8274010c23fcef4576e07b190fd257Jorg Pleumann     */
73c36fab6a0e8274010c23fcef4576e07b190fd257Jorg Pleumann    public CoreTestRunnable(TestCase test, TestResult result,
74c36fab6a0e8274010c23fcef4576e07b190fd257Jorg Pleumann            Protectable protectable, boolean invert, boolean isolate) {
75c36fab6a0e8274010c23fcef4576e07b190fd257Jorg Pleumann
76c36fab6a0e8274010c23fcef4576e07b190fd257Jorg Pleumann        this.fTest = test;
77c36fab6a0e8274010c23fcef4576e07b190fd257Jorg Pleumann        this.fProtectable = protectable;
78c36fab6a0e8274010c23fcef4576e07b190fd257Jorg Pleumann        this.fResult = result;
79c36fab6a0e8274010c23fcef4576e07b190fd257Jorg Pleumann        this.fInvert = invert;
80c36fab6a0e8274010c23fcef4576e07b190fd257Jorg Pleumann        this.fIsolate = isolate;
81c36fab6a0e8274010c23fcef4576e07b190fd257Jorg Pleumann    }
82c36fab6a0e8274010c23fcef4576e07b190fd257Jorg Pleumann
83c36fab6a0e8274010c23fcef4576e07b190fd257Jorg Pleumann    /**
84c36fab6a0e8274010c23fcef4576e07b190fd257Jorg Pleumann     * Executes the test and stores the results. May be run from a secondary
85c36fab6a0e8274010c23fcef4576e07b190fd257Jorg Pleumann     * Thread.
86c36fab6a0e8274010c23fcef4576e07b190fd257Jorg Pleumann     */
87c36fab6a0e8274010c23fcef4576e07b190fd257Jorg Pleumann    public void run() {
88c36fab6a0e8274010c23fcef4576e07b190fd257Jorg Pleumann        try {
89c36fab6a0e8274010c23fcef4576e07b190fd257Jorg Pleumann            if (fIsolate) {
90c36fab6a0e8274010c23fcef4576e07b190fd257Jorg Pleumann                runExternally();
91c36fab6a0e8274010c23fcef4576e07b190fd257Jorg Pleumann            } else {
92c36fab6a0e8274010c23fcef4576e07b190fd257Jorg Pleumann                runInternally();
93c36fab6a0e8274010c23fcef4576e07b190fd257Jorg Pleumann            }
94c36fab6a0e8274010c23fcef4576e07b190fd257Jorg Pleumann
95c36fab6a0e8274010c23fcef4576e07b190fd257Jorg Pleumann            if (fInvert) {
96c36fab6a0e8274010c23fcef4576e07b190fd257Jorg Pleumann                fInvert = false;
97c36fab6a0e8274010c23fcef4576e07b190fd257Jorg Pleumann                throw new AssertionFailedError(
98c36fab6a0e8274010c23fcef4576e07b190fd257Jorg Pleumann                        "@KnownFailure expected to fail, but succeeded");
99c36fab6a0e8274010c23fcef4576e07b190fd257Jorg Pleumann            }
100c36fab6a0e8274010c23fcef4576e07b190fd257Jorg Pleumann        } catch (AssertionFailedError e) {
101c36fab6a0e8274010c23fcef4576e07b190fd257Jorg Pleumann            if (!fInvert) {
102c36fab6a0e8274010c23fcef4576e07b190fd257Jorg Pleumann                fResult.addFailure(fTest, e);
103c36fab6a0e8274010c23fcef4576e07b190fd257Jorg Pleumann            }
104c36fab6a0e8274010c23fcef4576e07b190fd257Jorg Pleumann        } catch (ThreadDeath e) { // don't catch ThreadDeath by accident
105c36fab6a0e8274010c23fcef4576e07b190fd257Jorg Pleumann            throw e;
106c36fab6a0e8274010c23fcef4576e07b190fd257Jorg Pleumann        } catch (Throwable e) {
107c36fab6a0e8274010c23fcef4576e07b190fd257Jorg Pleumann            if (!fInvert) {
108c36fab6a0e8274010c23fcef4576e07b190fd257Jorg Pleumann                fResult.addError(fTest, e);
109c36fab6a0e8274010c23fcef4576e07b190fd257Jorg Pleumann            }
110c36fab6a0e8274010c23fcef4576e07b190fd257Jorg Pleumann        }
111c36fab6a0e8274010c23fcef4576e07b190fd257Jorg Pleumann    }
112c36fab6a0e8274010c23fcef4576e07b190fd257Jorg Pleumann
113c36fab6a0e8274010c23fcef4576e07b190fd257Jorg Pleumann    /**
114c36fab6a0e8274010c23fcef4576e07b190fd257Jorg Pleumann     * Tells the test case to stop. Only used with isolation. We need to kill
115c36fab6a0e8274010c23fcef4576e07b190fd257Jorg Pleumann     * the external process in this case.
116c36fab6a0e8274010c23fcef4576e07b190fd257Jorg Pleumann     */
117c36fab6a0e8274010c23fcef4576e07b190fd257Jorg Pleumann    public void stop() {
118c36fab6a0e8274010c23fcef4576e07b190fd257Jorg Pleumann        if (fProcess != null) {
119c36fab6a0e8274010c23fcef4576e07b190fd257Jorg Pleumann            fProcess.destroy();
120c36fab6a0e8274010c23fcef4576e07b190fd257Jorg Pleumann        }
121c36fab6a0e8274010c23fcef4576e07b190fd257Jorg Pleumann    }
122c36fab6a0e8274010c23fcef4576e07b190fd257Jorg Pleumann
123c36fab6a0e8274010c23fcef4576e07b190fd257Jorg Pleumann    /**
124c36fab6a0e8274010c23fcef4576e07b190fd257Jorg Pleumann     * Runs the test case in the same process. This is basically what a
125c36fab6a0e8274010c23fcef4576e07b190fd257Jorg Pleumann     * run-of-the-mill JUnit does, except we might also do it in a secondary
126c36fab6a0e8274010c23fcef4576e07b190fd257Jorg Pleumann     * thread.
127c36fab6a0e8274010c23fcef4576e07b190fd257Jorg Pleumann     */
128c36fab6a0e8274010c23fcef4576e07b190fd257Jorg Pleumann    private void runInternally() throws Throwable {
129c36fab6a0e8274010c23fcef4576e07b190fd257Jorg Pleumann        fProtectable.protect();
130c36fab6a0e8274010c23fcef4576e07b190fd257Jorg Pleumann    }
131c36fab6a0e8274010c23fcef4576e07b190fd257Jorg Pleumann
132c36fab6a0e8274010c23fcef4576e07b190fd257Jorg Pleumann    /**
133c36fab6a0e8274010c23fcef4576e07b190fd257Jorg Pleumann     * Runs the test case in a different process. This is what we do for
134c36fab6a0e8274010c23fcef4576e07b190fd257Jorg Pleumann     * isolating test cases that have side effects or do suffer from them.
135c36fab6a0e8274010c23fcef4576e07b190fd257Jorg Pleumann     */
136c36fab6a0e8274010c23fcef4576e07b190fd257Jorg Pleumann    private void runExternally() throws Throwable {
137c36fab6a0e8274010c23fcef4576e07b190fd257Jorg Pleumann        Throwable throwable = null;
138c36fab6a0e8274010c23fcef4576e07b190fd257Jorg Pleumann
139c36fab6a0e8274010c23fcef4576e07b190fd257Jorg Pleumann        File file = File.createTempFile("isolation", ".tmp");
140c36fab6a0e8274010c23fcef4576e07b190fd257Jorg Pleumann
141c36fab6a0e8274010c23fcef4576e07b190fd257Jorg Pleumann        fProcess = Runtime.getRuntime().exec(
142c36fab6a0e8274010c23fcef4576e07b190fd257Jorg Pleumann                (IS_DALVIK ? "dalvikvm" : "java") +
143c36fab6a0e8274010c23fcef4576e07b190fd257Jorg Pleumann                " -classpath " + System.getProperty("java.class.path") +
144c36fab6a0e8274010c23fcef4576e07b190fd257Jorg Pleumann                " -Djava.home=" + System.getProperty("java.home") +
145c36fab6a0e8274010c23fcef4576e07b190fd257Jorg Pleumann                " -Duser.home=" + System.getProperty("user.home") +
146c36fab6a0e8274010c23fcef4576e07b190fd257Jorg Pleumann                " -Djava.io.tmpdir=" + System.getProperty("user.home") +
147c36fab6a0e8274010c23fcef4576e07b190fd257Jorg Pleumann                " com.google.coretests.CoreTestIsolator" +
148c36fab6a0e8274010c23fcef4576e07b190fd257Jorg Pleumann                " " + fTest.getClass().getName() +
149c36fab6a0e8274010c23fcef4576e07b190fd257Jorg Pleumann                " " + fTest.getName() +
150c36fab6a0e8274010c23fcef4576e07b190fd257Jorg Pleumann                " " + file.getAbsolutePath());
151c36fab6a0e8274010c23fcef4576e07b190fd257Jorg Pleumann
152c36fab6a0e8274010c23fcef4576e07b190fd257Jorg Pleumann        int result = fProcess.waitFor();
153c36fab6a0e8274010c23fcef4576e07b190fd257Jorg Pleumann
154c36fab6a0e8274010c23fcef4576e07b190fd257Jorg Pleumann        if (result != TestRunner.SUCCESS_EXIT) {
155c36fab6a0e8274010c23fcef4576e07b190fd257Jorg Pleumann            try {
156c36fab6a0e8274010c23fcef4576e07b190fd257Jorg Pleumann                FileInputStream fis = new FileInputStream(file);
157c36fab6a0e8274010c23fcef4576e07b190fd257Jorg Pleumann                ObjectInputStream ois = new ObjectInputStream(fis);
158c36fab6a0e8274010c23fcef4576e07b190fd257Jorg Pleumann                throwable = (Throwable)ois.readObject();
159c36fab6a0e8274010c23fcef4576e07b190fd257Jorg Pleumann                ois.close();
160c36fab6a0e8274010c23fcef4576e07b190fd257Jorg Pleumann            } catch (Exception ex) {
161c36fab6a0e8274010c23fcef4576e07b190fd257Jorg Pleumann                throwable = new RuntimeException("Error isolating test", ex);
162c36fab6a0e8274010c23fcef4576e07b190fd257Jorg Pleumann            }
163c36fab6a0e8274010c23fcef4576e07b190fd257Jorg Pleumann        }
164c36fab6a0e8274010c23fcef4576e07b190fd257Jorg Pleumann
165c36fab6a0e8274010c23fcef4576e07b190fd257Jorg Pleumann        file.delete();
166c36fab6a0e8274010c23fcef4576e07b190fd257Jorg Pleumann
167c36fab6a0e8274010c23fcef4576e07b190fd257Jorg Pleumann        if (throwable != null) {
168c36fab6a0e8274010c23fcef4576e07b190fd257Jorg Pleumann            throw throwable;
169c36fab6a0e8274010c23fcef4576e07b190fd257Jorg Pleumann        }
170c36fab6a0e8274010c23fcef4576e07b190fd257Jorg Pleumann    }
171c36fab6a0e8274010c23fcef4576e07b190fd257Jorg Pleumann
172c36fab6a0e8274010c23fcef4576e07b190fd257Jorg Pleumann}
173