blob: a46ae881dbbac5ddef3dd06f2149516665db3b50 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2017 Red Hat Inc. 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:
* Red Hat Inc. - initial API and implementation
*******************************************************************************/
package org.eclipse.core.tests.internal.builders;
import java.util.*;
import junit.framework.TestSuite;
import org.eclipse.core.internal.events.BuildCommand;
import org.eclipse.core.resources.*;
import org.eclipse.core.runtime.*;
import org.eclipse.core.runtime.jobs.Job;
import org.eclipse.core.runtime.jobs.JobGroup;
import org.eclipse.core.tests.internal.builders.TimerBuilder.RuleType;
import org.junit.Assert;
import org.junit.Test;
/**
*
*/
public class ParallelBuildChainTest extends AbstractBuilderTest {
public static junit.framework.Test suite() {
return new TestSuite(ParallelBuildChainTest.class);
}
private static final int LONG_BUILD_DURATION = 1000;
public ParallelBuildChainTest() {
super(null);
}
public ParallelBuildChainTest(String name) {
super(name);
}
@Override
protected void setUp() throws Exception {
super.setUp();
IWorkspaceDescription description = getWorkspace().getDescription();
description.setMaxConcurrentBuilds(3);
getWorkspace().setDescription(description);
setAutoBuilding(false);
TimerBuilder.reset();
IWorkspaceRoot root = getWorkspace().getRoot();
IProject projectInstantaneousBuild1 = root.getProject("projectInstantaneousBuild1");
IProject projectLongBuild1 = root.getProject("projectLongBuild1");
IProject projectInstantaneousBuild2 = root.getProject("projectInstantaneousBuild2");
IProject projectLongBuild2 = root.getProject("projectLongBuild2");
IProject projectInstantaneousBuild3 = root.getProject("projectInstantaneousBuild3");
IProject projectLongBuild3 = root.getProject("projectLongBuild3");
ensureExistsInWorkspace(new IResource[] {projectInstantaneousBuild1, projectInstantaneousBuild2, projectInstantaneousBuild3, projectLongBuild1, projectLongBuild2, projectLongBuild3}, true);
configureTimerBuilder(projectInstantaneousBuild1, 0);
configureTimerBuilder(projectInstantaneousBuild2, 0);
configureTimerBuilder(projectInstantaneousBuild3, 0);
configureTimerBuilder(projectLongBuild1, LONG_BUILD_DURATION);
configureTimerBuilder(projectLongBuild2, LONG_BUILD_DURATION);
configureTimerBuilder(projectLongBuild3, LONG_BUILD_DURATION);
}
private void configureTimerBuilder(IProject project, int duration) throws CoreException {
BuildCommand buildCommand = new BuildCommand();
buildCommand.setBuilderName(TimerBuilder.BUILDER_NAME);
Map<String, String> arguments = new HashMap<>(2, (float) 1.);
arguments.put(TimerBuilder.DURATION_ARG, Integer.toString(duration));
arguments.put(TimerBuilder.RULE_TYPE_ARG, TimerBuilder.RuleType.NO_CONFLICT.toString());
buildCommand.setArguments(arguments);
IProjectDescription projectDescription = project.getDescription();
projectDescription.setBuildSpec(new ICommand[] {buildCommand});
project.setDescription(projectDescription, getMonitor());
}
public IProject[] projectWithLongRunningBuilds() {
return Arrays.stream(getWorkspace().getRoot().getProjects()).filter(project -> {
ICommand[] commands;
try {
commands = project.getDescription().getBuildSpec();
return commands.length > 0 && commands[0].getBuilderName().equals(TimerBuilder.BUILDER_NAME)
&& Integer.parseInt(commands[0].getArguments().get(TimerBuilder.DURATION_ARG)) > 0;
} catch (CoreException e) {
fail(e.getMessage(), e);
return false;
}
}).toArray(IProject[]::new);
}
private void setTimerBuilderSchedulingRuleForAllProjects(TimerBuilder.RuleType type, IProgressMonitor monitor) throws CoreException {
for (IProject project : getWorkspace().getRoot().getProjects()) {
IProjectDescription projectDescription = project.getDescription();
BuildCommand command = (BuildCommand) projectDescription.getBuildSpec()[0];
Map<String, String> args = command.getArguments();
if (args == null) {
args = Collections.singletonMap(TimerBuilder.RULE_TYPE_ARG, type.toString());
} else {
args.put(TimerBuilder.RULE_TYPE_ARG, type.toString());
}
command.setArguments(args);
projectDescription.setBuildSpec(new ICommand[] {command});
project.setDescription(projectDescription, getMonitor());
}
}
@Test
public void testIndividualProjectBuildsInParallelNoConflict() throws CoreException, OperationCanceledException, InterruptedException {
long duration = System.currentTimeMillis();
JobGroup group = new JobGroup("Build Group", 5, getWorkspace().getRoot().getProjects().length);
for (IProject project : getWorkspace().getRoot().getProjects()) {
Job job = new Job("Building " + project) {
@Override
public IStatus run(IProgressMonitor monitor) {
try {
project.build(IncrementalProjectBuilder.FULL_BUILD, monitor);
return Status.OK_STATUS;
} catch (CoreException e) {
return new Status(IStatus.ERROR, "org.eclipse.core.tests.resources", e.getMessage(), e);
}
}
};
job.setJobGroup(group);
job.schedule();
}
Assert.assertTrue("Timeout, most likely a deadlock", group.join(5000, getMonitor()));
duration = System.currentTimeMillis() - duration;
assertEquals(getWorkspace().getRoot().getProjects().length, TimerBuilder.getTotalBuilds());
assertTrue(TimerBuilder.getMaxSimultaneousBuilds() >= 3);
assertTrue(duration < projectWithLongRunningBuilds().length * LONG_BUILD_DURATION);
}
@Test
public void testIndividualProjectBuildsInParallelProjectScheduling() throws CoreException, OperationCanceledException, InterruptedException {
setTimerBuilderSchedulingRuleForAllProjects(RuleType.CURRENT_PROJECT_RELAXED, getMonitor());
long duration = System.currentTimeMillis();
JobGroup group = new JobGroup("Build Group", 5, getWorkspace().getRoot().getProjects().length);
for (IProject project : getWorkspace().getRoot().getProjects()) {
Job job = new Job("Building " + project) {
@Override
public IStatus run(IProgressMonitor monitor) {
try {
project.build(IncrementalProjectBuilder.FULL_BUILD, monitor);
return Status.OK_STATUS;
} catch (CoreException e) {
return new Status(IStatus.ERROR, "org.eclipse.core.tests.resources", e.getMessage(), e);
}
}
};
job.setJobGroup(group);
job.schedule();
}
Assert.assertTrue("Timeout, most likely a deadlock", group.join(5000, getMonitor()));
duration = System.currentTimeMillis() - duration;
assertEquals(getWorkspace().getRoot().getProjects().length, TimerBuilder.getTotalBuilds());
assertTrue(TimerBuilder.getMaxSimultaneousBuilds() >= 3);
assertTrue(duration < projectWithLongRunningBuilds().length * LONG_BUILD_DURATION);
}
@Test
public void testWorkspaceBuildConfigParrallelProjectRule() throws CoreException, OperationCanceledException, InterruptedException {
setTimerBuilderSchedulingRuleForAllProjects(RuleType.CURRENT_PROJECT, getMonitor());
long duration = System.currentTimeMillis();
Job job = new Job("Workspace Build") {
@Override
protected IStatus run(IProgressMonitor monitor) {
try {
getWorkspace().build(
Arrays.stream(getWorkspace().getRoot().getProjects()).map(p -> {
try {
return p.getActiveBuildConfig();
} catch (CoreException e) {
fail(e.getMessage(), e);
return null;
}
}).toArray(IBuildConfiguration[]::new),
IncrementalProjectBuilder.INCREMENTAL_BUILD,
true,
getMonitor());
return Status.OK_STATUS;
} catch (CoreException e) {
return new Status(IStatus.ERROR, "org.eclipse.core.tests.resources", e.getMessage(), e);
}
}
};
job.schedule();
Assert.assertTrue("Timeout, most likely a deadlock", job.join(5000, getMonitor()));
duration = System.currentTimeMillis() - duration;
assertEquals(getWorkspace().getRoot().getProjects().length, TimerBuilder.getTotalBuilds());
assertTrue(TimerBuilder.getMaxSimultaneousBuilds() > 1);
assertTrue(TimerBuilder.getMaxSimultaneousBuilds() <= getWorkspace().getDescription().getMaxConcurrentBuilds());
assertTrue(duration < projectWithLongRunningBuilds().length * LONG_BUILD_DURATION);
}
@Test
public void testWorkspaceParrallelBuildNoConflict() throws CoreException, OperationCanceledException, InterruptedException {
setTimerBuilderSchedulingRuleForAllProjects(RuleType.NO_CONFLICT, getMonitor());
long duration = System.currentTimeMillis();
Job job = new Job("Workspace Build") {
@Override
protected IStatus run(IProgressMonitor monitor) {
try {
getWorkspace().build(IncrementalProjectBuilder.INCREMENTAL_BUILD, getMonitor());
return Status.OK_STATUS;
} catch (CoreException e) {
return new Status(IStatus.ERROR, "org.eclipse.core.tests.resources", e.getMessage(), e);
}
}
};
job.schedule();
Assert.assertTrue("Timeout, most likely a deadlock", job.join(5000, getMonitor()));
duration = System.currentTimeMillis() - duration;
assertEquals(getWorkspace().getRoot().getProjects().length, TimerBuilder.getTotalBuilds());
assertTrue(TimerBuilder.getMaxSimultaneousBuilds() > 1);
assertTrue(TimerBuilder.getMaxSimultaneousBuilds() <= getWorkspace().getDescription().getMaxConcurrentBuilds());
assertTrue(duration < projectWithLongRunningBuilds().length * LONG_BUILD_DURATION);
}
@Test
public void testWorkspaceParrallelBuildConflictingRules() throws CoreException, OperationCanceledException, InterruptedException {
setTimerBuilderSchedulingRuleForAllProjects(RuleType.WORKSPACE_ROOT, getMonitor());
long duration = System.currentTimeMillis();
Job job = new Job("Workspace Build") {
@Override
protected IStatus run(IProgressMonitor monitor) {
try {
getWorkspace().build(IncrementalProjectBuilder.INCREMENTAL_BUILD, getMonitor());
return Status.OK_STATUS;
} catch (CoreException e) {
return new Status(IStatus.ERROR, "org.eclipse.core.tests.resources", e.getMessage(), e);
}
}
};
job.schedule();
Assert.assertTrue("Timeout, most likely a deadlock", job.join(5000, getMonitor()));
duration = System.currentTimeMillis() - duration;
assertEquals(getWorkspace().getRoot().getProjects().length, TimerBuilder.getTotalBuilds());
assertEquals(1, TimerBuilder.getMaxSimultaneousBuilds());
assertTrue(duration > projectWithLongRunningBuilds().length * LONG_BUILD_DURATION);
}
@Test
public void testWorkspaceParrallelBuildCurrentProject() throws CoreException, OperationCanceledException, InterruptedException {
setTimerBuilderSchedulingRuleForAllProjects(RuleType.CURRENT_PROJECT, getMonitor());
long duration = System.currentTimeMillis();
Job job = new Job("Workspace Build") {
@Override
protected IStatus run(IProgressMonitor monitor) {
try {
getWorkspace().build(IncrementalProjectBuilder.INCREMENTAL_BUILD, getMonitor());
return Status.OK_STATUS;
} catch (CoreException e) {
return new Status(IStatus.ERROR, "org.eclipse.core.tests.resources", e.getMessage(), e);
}
}
};
job.schedule();
Assert.assertTrue("Timeout, most likely a deadlock", job.join(5000, getMonitor()));
duration = System.currentTimeMillis() - duration;
assertEquals(getWorkspace().getRoot().getProjects().length, TimerBuilder.getTotalBuilds());
assertTrue(TimerBuilder.getMaxSimultaneousBuilds() > 1);
assertTrue(TimerBuilder.getMaxSimultaneousBuilds() <= getWorkspace().getDescription().getMaxConcurrentBuilds());
assertTrue(duration < projectWithLongRunningBuilds().length * LONG_BUILD_DURATION);
}
public void testDependentProjectsBuildSequentially() throws Exception {
IProject[] allProjects = getWorkspace().getRoot().getProjects();
for (int i = 1; i < allProjects.length; i++) {
IProject project = allProjects[i];
IProjectDescription desc = project.getDescription();
desc.setReferencedProjects(new IProject[] {allProjects[i - 1]});
project.setDescription(desc, getMonitor());
}
setTimerBuilderSchedulingRuleForAllProjects(RuleType.NO_CONFLICT, getMonitor());
long duration = System.currentTimeMillis();
Job job = new Job("Workspace Build") {
@Override
protected IStatus run(IProgressMonitor monitor) {
try {
getWorkspace().build(IncrementalProjectBuilder.INCREMENTAL_BUILD, getMonitor());
return Status.OK_STATUS;
} catch (CoreException e) {
return new Status(IStatus.ERROR, "org.eclipse.core.tests.resources", e.getMessage(), e);
}
}
};
job.schedule();
Assert.assertTrue("Timeout, most likely a deadlock", job.join(5000, getMonitor()));
duration = System.currentTimeMillis() - duration;
assertEquals(allProjects.length, TimerBuilder.getTotalBuilds());
assertEquals(1, TimerBuilder.getMaxSimultaneousBuilds());
assertTrue(duration > projectWithLongRunningBuilds().length * LONG_BUILD_DURATION);
assertEquals(sequentialBuildEvents(allProjects), TimerBuilder.events);
}
private List<Object> sequentialBuildEvents(IProject[] allProjects) {
List<Object> res = new ArrayList<>(allProjects.length * 2);
for (IProject project : allProjects) {
res.add(TimerBuilder.buildStartEvent(project));
res.add(TimerBuilder.buildCompleteEvent(project));
}
return res;
}
public void testDependentBuildConfigBuildSequentially() throws Exception {
IProject[] allProjects = getWorkspace().getRoot().getProjects();
for (int i = 1; i < allProjects.length; i++) {
IProject project = allProjects[i];
IProjectDescription desc = project.getDescription();
desc.setBuildConfigReferences(project.getActiveBuildConfig().getName(), new IBuildConfiguration[] {allProjects[i - 1].getActiveBuildConfig()});
project.setDescription(desc, getMonitor());
}
setTimerBuilderSchedulingRuleForAllProjects(RuleType.NO_CONFLICT, getMonitor());
long duration = System.currentTimeMillis();
Job job = new Job("Workspace Build") {
@Override
protected IStatus run(IProgressMonitor monitor) {
try {
getWorkspace().build(IncrementalProjectBuilder.INCREMENTAL_BUILD, getMonitor());
return Status.OK_STATUS;
} catch (CoreException e) {
return new Status(IStatus.ERROR, "org.eclipse.core.tests.resources", e.getMessage(), e);
}
}
};
job.schedule();
Assert.assertTrue("Timeout, most likely a deadlock", job.join(0, getMonitor()));
duration = System.currentTimeMillis() - duration;
assertEquals(allProjects.length, TimerBuilder.getTotalBuilds());
assertEquals(1, TimerBuilder.getMaxSimultaneousBuilds());
assertTrue(duration > projectWithLongRunningBuilds().length * LONG_BUILD_DURATION);
assertEquals(sequentialBuildEvents(allProjects), TimerBuilder.events);
}
public void testDependentBuildConfigsSubset() throws Exception {
setTimerBuilderSchedulingRuleForAllProjects(RuleType.NO_CONFLICT, getMonitor());
IProject[] allProjects = getWorkspace().getRoot().getProjects();
for (int i = 1; i < allProjects.length; i++) {
IProject project = allProjects[i];
IProjectDescription desc = project.getDescription();
desc.setBuildConfigReferences(project.getActiveBuildConfig().getName(),
new IBuildConfiguration[] { allProjects[i - 1].getActiveBuildConfig() });
project.setDescription(desc, getMonitor());
}
long duration = System.currentTimeMillis();
Job job = new Job("Workspace Build") {
@Override
protected IStatus run(IProgressMonitor monitor) {
try {
getWorkspace().build(new IBuildConfiguration[] {allProjects[0].getActiveBuildConfig(), allProjects[2].getActiveBuildConfig(), allProjects[3].getActiveBuildConfig(), allProjects[5].getActiveBuildConfig(),}, IncrementalProjectBuilder.INCREMENTAL_BUILD, false, getMonitor());
return Status.OK_STATUS;
} catch (CoreException e) {
return new Status(IStatus.ERROR, "org.eclipse.core.tests.resources", e.getMessage(), e);
}
}
};
job.schedule();
Assert.assertTrue("Timeout, most likely a deadlock", job.join(0, getMonitor()));
duration = System.currentTimeMillis() - duration;
assertEquals(allProjects.length - 2, TimerBuilder.getTotalBuilds());
assertEquals(Arrays.asList(TimerBuilder.buildStartEvent(allProjects[0]),
TimerBuilder.buildCompleteEvent(allProjects[0]),
TimerBuilder.buildStartEvent(allProjects[2]),
TimerBuilder.buildCompleteEvent(allProjects[2]),
TimerBuilder.buildStartEvent(allProjects[3]),
TimerBuilder.buildCompleteEvent(allProjects[3]),
TimerBuilder.buildStartEvent(allProjects[5]),
TimerBuilder.buildCompleteEvent(allProjects[5])
), TimerBuilder.events);
}
}