| /******************************************************************************* |
| * 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); |
| } |
| } |