blob: 617416ae8f250b54599bc5e2d4965dcf30ef1566 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2012, 2015 IBM Corporation and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* IBM - initial API and implementation
*******************************************************************************/
package org.eclipse.core.tests.resources.regression;
import java.util.concurrent.Semaphore;
import junit.framework.Test;
import junit.framework.TestSuite;
import org.eclipse.core.resources.*;
import org.eclipse.core.runtime.*;
import org.eclipse.core.tests.resources.ResourceTest;
import org.eclipse.core.tests.resources.usecase.SignaledBuilder;
/**
* Tests a timing problem where a canceled waiting thread could cause a change
* in another thread to skip building.
*/
public class Bug_378156 extends ResourceTest {
class ModifyFileJob extends WorkspaceJob {
private boolean cancel;
private IFile jobFile;
private Semaphore jobFlag;
/**
* Modifies a file and then waits for a signal before returning.
*/
public ModifyFileJob(IFile file, Semaphore semaphore) {
super("Modifying " + file);
this.jobFlag = semaphore;
jobFile = file;
}
@Override
public IStatus runInWorkspace(IProgressMonitor monitor) throws CoreException {
if (cancel) {
throw new OperationCanceledException();
}
jobFile.setContents(getRandomContents(), IResource.NONE, null);
//wait for signal
try {
jobFlag.acquire();
} catch (InterruptedException e) {
fail("0.99", e);
}
return Status.OK_STATUS;
}
/**
* Tells this job to cancel itself while waiting
*/
public void setCancel() {
this.cancel = true;
}
}
public static Test suite() {
return new TestSuite(Bug_378156.class);
}
public void testBugTwoThreads() throws Exception {
//setup
IWorkspaceRoot root = ResourcesPlugin.getWorkspace().getRoot();
final IProject project1 = root.getProject("Bug_378156");
final IFile file = project1.getFile("content.txt");
ensureExistsInWorkspace(project1, true);
//add a builder that can tell us if it was called
IProjectDescription desc = project1.getDescription();
ICommand command = desc.newCommand();
command.setBuilderName(SignaledBuilder.BUILDER_ID);
desc.setBuildSpec(new ICommand[] {command});
project1.setDescription(desc, getMonitor());
ensureExistsInWorkspace(file, getRandomContents());
//build may not be triggered immediately
Thread.sleep(2000);
waitForBuild();
//initialize the builder
SignaledBuilder builder = SignaledBuilder.getInstance(project1);
builder.reset();
//create a job that will modify the file and then wait for a signal
final Semaphore semaphore = new Semaphore(0);
ModifyFileJob runningJob = new ModifyFileJob(file, semaphore);
runningJob.setRule(file);
runningJob.schedule();
//create another copy of the job and immediately cancel it before it gets the lock
ModifyFileJob waitingJob = new ModifyFileJob(file, semaphore);
waitingJob.setCancel();
waitingJob.schedule();
waitingJob.join();
//now let the first job finish
semaphore.release();
runningJob.join();
waitForBuild();
//the builder should have run if the bug is fixed
assertTrue("1.0", builder.wasExecuted());
}
public void testBugOneThread() throws Exception {
//setup
IWorkspaceRoot root = ResourcesPlugin.getWorkspace().getRoot();
final IProject project1 = root.getProject("Bug_378156");
final IFile file = project1.getFile("content.txt");
ensureExistsInWorkspace(project1, true);
//add a builder that can tell us if it was called
IProjectDescription desc = project1.getDescription();
ICommand command = desc.newCommand();
command.setBuilderName(SignaledBuilder.BUILDER_ID);
desc.setBuildSpec(new ICommand[] {command});
project1.setDescription(desc, getMonitor());
ensureExistsInWorkspace(file, getRandomContents());
waitForBuild();
//initialize the builder
SignaledBuilder builder = SignaledBuilder.getInstance(project1);
builder.reset();
getWorkspace().run(new IWorkspaceRunnable() {
@Override
public void run(IProgressMonitor monitor) throws CoreException {
//modify the file so autobuild is needed
file.setContents(getRandomContents(), IResource.NONE, null);
//create a nested operation that immediately cancels
try {
getWorkspace().run(new IWorkspaceRunnable() {
@Override
public void run(IProgressMonitor monitor) {
throw new OperationCanceledException();
}
}, null);
} catch (OperationCanceledException e) {
//don't let this propagate - we changed our mind about canceling
}
}
}, null);
waitForBuild();
//the builder should have run if the bug is fixed
assertTrue("1.0", builder.wasExecuted());
}
}