/*************************GO-LICENSE-START********************************* * Copyright 2014 ThoughtWorks, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. *************************GO-LICENSE-END***********************************/ package com.thoughtworks.go.config.materials.svn; import java.io.File; import java.io.IOException; import java.util.List; import java.util.UUID; import com.thoughtworks.go.config.materials.Materials; import com.thoughtworks.go.domain.MaterialRevision; import com.thoughtworks.go.domain.MaterialRevisions; import com.thoughtworks.go.domain.materials.*; import com.thoughtworks.go.helper.SvnTestRepo; import com.thoughtworks.go.util.ArtifactLogUtil; import com.thoughtworks.go.util.FileUtil; import com.thoughtworks.go.util.TestFileUtil; import com.thoughtworks.go.util.command.ProcessOutputStreamConsumer; import org.junit.After; import org.junit.Before; import org.junit.Test; import static com.thoughtworks.go.config.MaterialRevisionsMatchers.containsModifiedFile; import static com.thoughtworks.go.util.command.ProcessOutputStreamConsumer.inMemoryConsumer; import static org.hamcrest.core.Is.is; import static org.junit.Assert.assertThat; public class SvnMultipleMaterialsTest { private SvnTestRepo repo; private File pipelineDir; @Before public void createRepo() throws IOException { repo = new SvnTestRepo(); pipelineDir = TestFileUtil.createTempFolder("working-dir-" + UUID.randomUUID()); } @After public void cleanupRepo() { repo.tearDown(); FileUtil.deleteFolder(pipelineDir); } @Test public void shouldNotThrowNPEIfTheWorkingDirectoryIsEmpty() throws Exception { SvnMaterial svnMaterial1 = repo.createMaterial("multiple-materials/trunk/part1", "part1"); SvnMaterial svnMaterial2 = repo.createMaterial("multiple-materials/trunk/part2", "part2"); Materials materials = new Materials(svnMaterial1, svnMaterial2); Revision revision = latestRevision(svnMaterial1, pipelineDir, new TestSubprocessExecutionContext()); updateMaterials(materials, revision); FileUtil.deleteFolder(pipelineDir); updateMaterials(materials, revision); } @Test public void shouldClearOutAllDirectoriesIfMaterialsChange() throws Exception { SvnMaterial part1 = repo.createMaterial("multiple-materials/trunk/part1", "part1"); SvnMaterial part2 = repo.createMaterial("multiple-materials/trunk/part2", "part2"); Materials materials = new Materials(part1, part2); Revision revision = latestRevision(part1, pipelineDir, new TestSubprocessExecutionContext()); updateMaterials(materials, revision); assertThat(new File(pipelineDir, "part1").exists(), is(true)); assertThat(new File(pipelineDir, "part2").exists(), is(true)); SvnMaterial newFolder = repo.createMaterial("multiple-materials/trunk/part2", "newFolder"); Materials changedMaterials = new Materials(part1, newFolder); updateMaterials(changedMaterials, revision); assertThat(new File(pipelineDir, "part1").exists(), is(true)); assertThat(new File(pipelineDir, "newFolder").exists(), is(true)); } @Test public void shouldClearOutAllDirectoriesIfMaterialIsDeleted() throws Exception { SvnMaterial part1 = repo.createMaterial("multiple-materials/trunk/part1", "part1"); SvnMaterial part2 = repo.createMaterial("multiple-materials/trunk/part2", "part2"); Materials materials = new Materials(part1, part2); Revision revision = latestRevision(part1, pipelineDir, new TestSubprocessExecutionContext()); updateMaterials(materials, revision); assertThat(new File(pipelineDir, "part1").exists(), is(true)); assertThat(new File(pipelineDir, "part2").exists(), is(true)); Materials changedMaterials = new Materials(part1); updateMaterials(changedMaterials, revision); assertThat(new File(pipelineDir, "part1").exists(), is(true)); assertThat(new File(pipelineDir, "part2").exists(), is(false)); } @Test public void shouldNotDeleteDirectoriesWhenThereIsACruiseOutputDirectory() throws Exception { SvnMaterial svnMaterial1 = repo.createMaterial("multiple-materials/trunk/part1", "part1"); SvnMaterial svnMaterial2 = repo.createMaterial("multiple-materials/trunk/part2", "part2"); Materials materials = new Materials(svnMaterial1, svnMaterial2); Revision revision = latestRevision(svnMaterial1, pipelineDir, new TestSubprocessExecutionContext()); updateMaterials(materials, revision); assertThat(new File(pipelineDir, "part1").exists(), is(true)); assertThat(new File(pipelineDir, "part2").exists(), is(true)); File testFile = new File(pipelineDir, "part1/test-file"); testFile.createNewFile(); assertThat(testFile.exists(), is(true)); //simulates what a build will do TestFileUtil.createTestFolder(pipelineDir, ArtifactLogUtil.CRUISE_OUTPUT_FOLDER); assertThat(pipelineDir.listFiles().length, is(3)); updateMaterials(materials, revision); assertThat(new File(pipelineDir, "part1").exists(), is(true)); assertThat(new File(pipelineDir, "part2").exists(), is(true)); assertThat("Should not delete the part1 directory", testFile.exists(), is(true)); } @Test public void shouldNotDeleteWorkingDirIfThereAreNoRequiredFolders() throws Exception { SvnMaterial part = repo.createMaterial("multiple-materials/trunk/part1", null); Materials materials = new Materials(part); Revision revision = latestRevision(part, pipelineDir, new TestSubprocessExecutionContext()); updateMaterials(materials, revision); File shouldNotCleanUp = new File(pipelineDir, "shouldNotDelete"); shouldNotCleanUp.createNewFile(); assertThat(shouldNotCleanUp.exists(), is(true)); updateMaterials(materials, revision); assertThat("should not clean up working dir for this pipeline if none of the materials specified a sub folder", shouldNotCleanUp.exists(), is(true)); } //This is bug #2320 - Cruise doing full checkouts most times @Test public void shouldNotDeleteWorkingDirIfMaterialsAreCheckedOutToSubfoldersWithTheSameRootBug2320() throws Exception { SvnMaterial svnMaterial1 = repo.createMaterial("multiple-materials/trunk/part1", "root/part1"); SvnMaterial svnMaterial2 = repo.createMaterial("multiple-materials/trunk/part2", "root/part2"); Materials materials = new Materials(svnMaterial1, svnMaterial2); Revision revision = latestRevision(svnMaterial1, pipelineDir, new TestSubprocessExecutionContext()); updateMaterials(materials, revision); assertThat(new File(pipelineDir, "root/part1").exists(), is(true)); assertThat(new File(pipelineDir, "root/part2").exists(), is(true)); File testFile = new File(pipelineDir, "root/part1/test-file"); testFile.createNewFile(); assertThat(testFile.exists(), is(true)); //simulates what a build will do TestFileUtil.createTestFolder(pipelineDir, ArtifactLogUtil.CRUISE_OUTPUT_FOLDER); assertThat(pipelineDir.listFiles().length, is(2)); updateMaterials(materials, revision); assertThat(new File(pipelineDir, "root/part1").exists(), is(true)); assertThat(new File(pipelineDir, "root/part2").exists(), is(true)); assertThat("Should not delete the part1 directory", testFile.exists(), is(true)); } @Test public void shouldDetectLatestModifications() throws Exception { SvnMaterial svnMaterial1 = repo.createMaterial("multiple-materials/trunk/part1", "part1"); SvnMaterial svnMaterial2 = repo.createMaterial("multiple-materials/trunk/part2", "part2"); Materials materials = new Materials(svnMaterial1, svnMaterial2); MaterialRevisions materialRevisions = materials.latestModification(pipelineDir, new TestSubprocessExecutionContext()); MaterialRevision revision1 = materialRevisions.getMaterialRevision(0); assertThat(revision1.getRevision(), is(latestRevision(svnMaterial1, pipelineDir, new TestSubprocessExecutionContext()))); MaterialRevision revision2 = materialRevisions.getMaterialRevision(1); assertThat(revision2.getRevision(), is(latestRevision(svnMaterial2, pipelineDir, new TestSubprocessExecutionContext()))); } @Test public void shouldUpdateMaterialToItsDestFolder() throws Exception { SvnMaterial material1 = repo.createMaterial("multiple-materials/trunk/part1", "part1"); MaterialRevision materialRevision = new MaterialRevision(material1, material1.latestModification(pipelineDir, new TestSubprocessExecutionContext())); materialRevision.updateTo(pipelineDir, ProcessOutputStreamConsumer.inMemoryConsumer(), new TestSubprocessExecutionContext()); assertThat(new File(pipelineDir, "part1").exists(), is(true)); } @Test public void shouldIgnoreDestinationFolderWhenServerSide() throws Exception { SvnMaterial material1 = repo.createMaterial("multiple-materials/trunk/part1", "part1"); MaterialRevision materialRevision = new MaterialRevision(material1, material1.latestModification(pipelineDir, new TestSubprocessExecutionContext())); materialRevision.updateTo(pipelineDir, ProcessOutputStreamConsumer.inMemoryConsumer(), new TestSubprocessExecutionContext(true)); assertThat(new File(pipelineDir, "part1").exists(), is(false)); } @Test public void shouldFindModificationForEachMaterial() throws Exception { SvnMaterial material1 = repo.createMaterial("multiple-materials/trunk/part1", "part1"); SvnMaterial material2 = repo.createMaterial("multiple-materials/trunk/part2", "part2"); Materials materials = new Materials(material1, material2); repo.checkInOneFile("filename.txt", material1); repo.checkInOneFile("filename2.txt", material2); MaterialRevisions materialRevisions = materials.latestModification(pipelineDir, new TestSubprocessExecutionContext()); assertThat(materialRevisions.getRevisions().size(), is(2)); assertThat(materialRevisions, containsModifiedFile("/trunk/part1/filename.txt")); assertThat(materialRevisions, containsModifiedFile("/trunk/part2/filename2.txt")); } private Revision latestRevision(SvnMaterial material, File workingDir, TestSubprocessExecutionContext execCtx) { List<Modification> modifications = material.latestModification(workingDir, execCtx); return new Modifications(modifications).latestRevision(material); } private void updateMaterials(Materials materials, Revision revision) { ProcessOutputStreamConsumer outputStreamConsumer = inMemoryConsumer(); TestSubprocessExecutionContext execCtx = new TestSubprocessExecutionContext(); materials.cleanUp(pipelineDir, outputStreamConsumer); for (Material material : materials) { material.updateTo(outputStreamConsumer, pipelineDir, new RevisionContext(revision), execCtx); } } }