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