/******************************************************************************* * Copyright (c) 2000, 2017 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 Corporation - initial API and implementation * James Blackburn (Broadcom Corp.) - ongoing development *******************************************************************************/ package org.eclipse.core.tests.internal.builders; import java.util.*; import junit.framework.Test; import junit.framework.TestSuite; import org.eclipse.core.resources.*; import org.eclipse.core.runtime.CoreException; import org.eclipse.core.tests.resources.TestPerformer; /** * This class tests builds that span multiple projects. Project builders * can specify what other projects they are interested in receiving deltas for, * and they should only be receiving deltas for exactly those projects. */ public class MultiProjectBuildTest extends AbstractBuilderTest { //various resource handles private IProject project1; private IProject project2; private IProject project3; private IProject project4; private IFile file1; private IFile file2; private IFile file3; private IFile file4; public MultiProjectBuildTest() { super(null); } /** * Public constructor required for test harness. */ public MultiProjectBuildTest(String name) { super(name); } /** * Returns an array of interesting project combinations. */ protected Object[] interestingProjects() { //mix things up, because requests from one run affect results in the next. return new Object[] {new IProject[] {}, new IProject[] {project3}, new IProject[] {project1}, new IProject[] {project1, project2, project3}, new IProject[] {project2}, new IProject[] {project3}, new IProject[] {project4}, new IProject[] {project1, project2}, new IProject[] {project1, project3}, new IProject[] {project3}, new IProject[] {project2, project3}, new IProject[] {project1, project2, project3}, new IProject[] {project1, project2, project4}, new IProject[] {project1}, new IProject[] {project1, project3, project4}, new IProject[] {project1, project2}, new IProject[] {project2, project3, project4}, new IProject[] {project3, project4}, new IProject[] {project1, project2, project3, project4},}; } public static Test suite() { return new TestSuite(MultiProjectBuildTest.class); } /** * Modifies any files in the given projects, all in a single operation */ protected void dirty(final IProject[] projects) throws CoreException { getWorkspace().run((IWorkspaceRunnable) monitor -> { for (IProject project : projects) { IResource[] members = project.members(); for (int j = 0; j < members.length; j++) { if (members[j].getType() == IResource.FILE && !members[j].getName().equals(IProjectDescription.DESCRIPTION_FILE_NAME)) { ((IFile) members[j]).setContents(getRandomContents(), true, true, null); } } } getWorkspace().build(IncrementalProjectBuilder.INCREMENTAL_BUILD, null); }, getMonitor()); } /** * Returns an array reversed. */ Object[] reverse(Object[] input) { if (input == null) { return null; } int len = input.length; Object[] output = new Object[len]; for (int i = 0; i < len; i++) { output[len - i - 1] = input[i]; } return output; } /* * @see TestCase#setUp() */ @Override protected void setUp() throws Exception { super.setUp(); setAutoBuilding(true); IWorkspaceRoot root = getWorkspace().getRoot(); project1 = root.getProject("Project1"); project2 = root.getProject("Project2"); project3 = root.getProject("Project3"); project4 = root.getProject("Project4"); file1 = project1.getFile("File1"); file2 = project2.getFile("File2"); file3 = project3.getFile("File3"); file4 = project4.getFile("File4"); IResource[] resources = {project1, project2, project3, project4, file1, file2, file3, file4}; ensureExistsInWorkspace(resources, true); } /* * @see TestCase#tearDown() */ @Override protected void tearDown() throws Exception { super.tearDown(); getWorkspace().getRoot().delete(true, getMonitor()); } /** * In this test, only project1 has a builder, but it is interested in deltas from the other projects. * We vary the set of projects that are changed, and the set of projects we request deltas for. */ public void testDeltas() { //add builder and do an initial build to get the instance try { setAutoBuilding(false); addBuilder(project1, DeltaVerifierBuilder.BUILDER_NAME); project1.build(IncrementalProjectBuilder.FULL_BUILD, getMonitor()); } catch (CoreException e) { fail("1.0", e); } final DeltaVerifierBuilder builder = DeltaVerifierBuilder.getInstance(); assertTrue("1.1", builder != null); //always check deltas for all projects final IProject[] allProjects = new IProject[] {project1, project2, project3, project4}; builder.checkDeltas(allProjects); //hold onto the set of requested projects here final IProject[][] previousRequest = new IProject[][] {new IProject[] {project1}}; //hold onto projects that have been modified since the last time the builder was run. final HashSet<IProject> previouslyModified = new HashSet<>(); new TestPerformer("testDeltas") { @Override public Object[] interestingOldState(Object[] args) throws Exception { return null; } @Override public Object invokeMethod(Object[] args, int count) throws Exception { //set requests for next build IProject[] requested = (IProject[]) args[0]; IProject[] toModify = (IProject[]) args[1]; builder.reset(); builder.requestDeltas(requested); //do the build dirty(toModify); Object result = previousRequest[0]; if (builder.wasBuilt()) { //if the builder ran, update previous request previousRequest[0] = requested; previouslyModified.clear(); } else { previouslyModified.addAll(Arrays.asList(toModify)); } return result; } @Override public boolean shouldFail(Object[] args, int count) { return false; } @Override public boolean wasSuccess(Object[] args, Object result, Object[] oldState) throws Exception { HashSet<IProject> requested = new HashSet<>(Arrays.asList((IProject[]) result)); HashSet<IProject> modified = new HashSet<>(Arrays.asList((IProject[]) args[1])); modified.addAll(previouslyModified); HashSet<IProject> obtained = new HashSet<>(); if (!builder.getReceivedDeltas().isEmpty()) { obtained.addAll(builder.getReceivedDeltas()); } ArrayList<IProject> emptyDeltas = builder.getEmptyDeltas(); //the builder's project is implicitly requested requested.add(builder.getProject()); for (IProject project : allProjects) { boolean wasObtained = obtained.contains(project); boolean wasRequested = requested.contains(project); boolean wasModified = modified.contains(project); boolean wasEmpty = emptyDeltas.contains(project); if (wasObtained) { //every delta we obtained should have been requested and (modified or empty) if (!wasRequested || !(wasModified || wasEmpty)) { return false; } } else { //if delta was not obtained, then must be unchanged or not requested if (wasRequested && wasModified) { return false; } } } return true; } }.performTest(new Object[][] {interestingProjects(), reverse(interestingProjects())}); } /** * Tests a builder that requests deltas for closed and missing projects. */ public void testRequestMissingProject() { //add builder and do an initial build to get the instance try { addBuilder(project1, DeltaVerifierBuilder.BUILDER_NAME); project1.build(IncrementalProjectBuilder.FULL_BUILD, getMonitor()); } catch (CoreException e) { fail("1.0", e); } final DeltaVerifierBuilder builder = DeltaVerifierBuilder.getInstance(); assertTrue("1.1", builder != null); //always check deltas for all projects final IProject[] allProjects = new IProject[] {project1, project2, project3, project4}; try { project2.close(getMonitor()); project3.delete(IResource.ALWAYS_DELETE_PROJECT_CONTENT, getMonitor()); } catch (CoreException e1) { fail("1.99", e1); } builder.checkDeltas(allProjects); //modify a file in project1 to force an autobuild try { file1.setContents(getRandomContents(), IResource.NONE, getMonitor()); } catch (CoreException e2) { fail("2.99", e2); } } /** * Test for Bug #5102. Never reproduced but interesting little test, worth keeping around */ public void testPR() throws Exception { //create a project with a RefreshLocalJavaFileBuilder and a SortBuilder on the classpath IProject project = getWorkspace().getRoot().getProject("P1"); project.create(null); project.open(null); IProjectDescription desc = project.getDescription(); ICommand one = desc.newCommand(); one.setBuilderName(RefreshLocalJavaFileBuilder.BUILDER_NAME); ICommand two = desc.newCommand(); two.setBuilderName(SortBuilder.BUILDER_NAME); desc.setBuildSpec(new ICommand[] {one, two}); project.setDescription(desc, null); //do a full build project.build(IncrementalProjectBuilder.FULL_BUILD, null); //do an incremental build by creating a file IFile file = project.getFile("Foo"); file.create(getRandomContents(), true, getMonitor()); } }