/******************************************************************************* | |
* Copyright (c) 2013, 2015 IBM Corporation and others. | |
* | |
* This program and the accompanying materials | |
* are made available under the terms of the Eclipse Public License 2.0 | |
* which accompanies this distribution, and is available at | |
* https://www.eclipse.org/legal/epl-2.0/ | |
* | |
* SPDX-License-Identifier: EPL-2.0 | |
* | |
* Contributors: | |
* IBM Corporation - initial API and implementation | |
*******************************************************************************/ | |
package org.eclipse.core.tests.runtime.jobs; | |
import java.io.*; | |
import junit.framework.*; | |
import org.eclipse.core.runtime.*; | |
import org.eclipse.core.runtime.jobs.Job; | |
import org.eclipse.core.tests.harness.FileSystemHelper; | |
import org.eclipse.core.tests.harness.TestBarrier; | |
import org.eclipse.core.tests.runtime.RuntimeTestsPlugin; | |
import org.eclipse.core.tests.session.SessionTestSuite; | |
/** | |
* Test for bug 412138. | |
*/ | |
public class Bug_412138 extends TestCase { | |
private static final String FILE_NAME = FileSystemHelper.getTempDir().append(Bug_412138.class.getName()).toOSString(); | |
public static Test suite() { | |
SessionTestSuite suite = new SessionTestSuite(RuntimeTestsPlugin.PI_RUNTIME_TESTS, Bug_412138.class.getName()); | |
suite.addCrashTest(new Bug_412138("testRunScenario")); | |
suite.addTest(new Bug_412138("testVerifyResult")); | |
return suite; | |
} | |
public Bug_412138(String name) { | |
super(name); | |
} | |
public void testRunScenario() throws InterruptedException { | |
// delete the file so that we don't report previous results | |
new File(FILE_NAME).delete(); | |
final int[] status = {-1}; | |
final Job fakeBuild = new Job("Fake AutoBuildJob") { | |
@Override | |
protected IStatus run(IProgressMonitor monitor) { | |
try { | |
// synchronize on the job object | |
synchronized (this) { | |
// let the other thread call join on this job now | |
status[0] = TestBarrier.STATUS_RUNNING; | |
// go to sleep to allow the other thread to acquire JobManager.lock inside join | |
Thread.sleep(3000); | |
// call a method that requires JobManager.lock | |
isBlocking(); | |
return Status.OK_STATUS; | |
} | |
} catch (InterruptedException e) { | |
return new Status(IStatus.ERROR, RuntimeTestsPlugin.PI_RUNTIME_TESTS, e.getMessage(), e); | |
} | |
} | |
}; | |
Job job = new Job("Some job") { | |
@Override | |
protected IStatus run(IProgressMonitor monitor) { | |
TestBarrier.waitForStatus(status, TestBarrier.STATUS_RUNNING); | |
try { | |
fakeBuild.join(); | |
status[0] = TestBarrier.STATUS_DONE; | |
return Status.OK_STATUS; | |
} catch (InterruptedException e) { | |
return new Status(IStatus.ERROR, RuntimeTestsPlugin.PI_RUNTIME_TESTS, e.getMessage(), e); | |
} | |
} | |
}; | |
try { | |
job.schedule(); | |
fakeBuild.schedule(); | |
TestBarrier.waitForStatus(status, TestBarrier.STATUS_DONE); | |
job.join(); | |
fakeBuild.join(); | |
assertTrue(job.getResult() != null && job.getResult().isOK()); | |
assertTrue(fakeBuild.getResult() != null && fakeBuild.getResult().isOK()); | |
} catch (AssertionFailedError e) { | |
// the test failed so there is a deadlock, but this deadlock would prevent us | |
// from reporting test results; serialize the error to a helper file and | |
// exit JVM to "resolve" deadlock | |
try { | |
ObjectOutputStream stream = new ObjectOutputStream(new FileOutputStream(FILE_NAME)); | |
stream.writeObject(e); | |
stream.close(); | |
} catch (IOException e1) { | |
// we can't do anything if saving the error failed | |
// print the original error, so that there is at least some trace | |
e.printStackTrace(); | |
} | |
} finally { | |
// make sure the test always crashes to satisfy addCrashTest method contract | |
// test result will be verified by the testVerifyResult method | |
System.exit(1); | |
} | |
} | |
public void testVerifyResult() throws IOException, ClassNotFoundException { | |
File file = new File(FILE_NAME); | |
// if the file does not exist, there was no deadlock so the whole test pass | |
if (file.exists()) { | |
try { | |
ObjectInputStream stream = new ObjectInputStream(new FileInputStream(FILE_NAME)); | |
AssertionFailedError e = (AssertionFailedError) stream.readObject(); | |
stream.close(); | |
throw e; | |
} catch (IOException e) { | |
// re-throw since file existence already says the test failed | |
throw e; | |
} catch (ClassNotFoundException e) { | |
// re-throw since file existence already says the test failed | |
throw e; | |
} finally { | |
// helper file is no longer needed | |
file.delete(); | |
} | |
} | |
} | |
} |