/*************************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.server.materials; import java.io.File; import java.util.Arrays; import java.util.Date; import com.thoughtworks.go.config.CaseInsensitiveString; import com.thoughtworks.go.config.materials.Materials; import com.thoughtworks.go.config.materials.PackageMaterial; import com.thoughtworks.go.config.materials.ScmMaterial; import com.thoughtworks.go.config.materials.dependency.DependencyMaterial; import com.thoughtworks.go.config.materials.git.GitMaterial; import com.thoughtworks.go.config.materials.svn.SvnMaterial; import com.thoughtworks.go.domain.MaterialRevision; import com.thoughtworks.go.domain.MaterialRevisions; import com.thoughtworks.go.domain.Stage; import com.thoughtworks.go.domain.buildcause.BuildCause; import com.thoughtworks.go.domain.materials.Material; import com.thoughtworks.go.domain.materials.Modification; import com.thoughtworks.go.domain.materials.Modifications; import com.thoughtworks.go.domain.packagerepository.ConfigurationPropertyMother; import com.thoughtworks.go.helper.MaterialsMother; import com.thoughtworks.go.helper.StageMother; import com.thoughtworks.go.server.persistence.MaterialRepository; import com.thoughtworks.go.util.TempFiles; import org.junit.After; import org.junit.Before; import org.junit.Test; import org.mockito.Mockito; import static com.thoughtworks.go.domain.materials.Modification.modifications; import static java.lang.String.format; import static org.hamcrest.core.Is.is; import static org.junit.Assert.assertThat; import static org.junit.Assert.fail; import static org.mockito.Mockito.never; import static org.mockito.Mockito.when; public class MaterialCheckerTest { private MaterialRepository materialRepository; private TempFiles tempFiles; private ScmMaterial mockMaterial; private MaterialChecker materialChecker; private File workingFolder; @Before public void setUp() throws Exception { materialRepository = Mockito.mock(MaterialRepository.class); tempFiles = new TempFiles(); mockMaterial = Mockito.mock(ScmMaterial.class); materialChecker = new MaterialChecker(materialRepository); workingFolder = tempFiles.createUniqueFolder("materialChecker"); } @After public void teardown() throws Exception { tempFiles.cleanUp(); } @Test public void shouldUseFlyweightWorkingFolderForLatestModificationCheck() throws Exception { Modification modification = new Modification(); Mockito.when(materialRepository.findLatestModification(mockMaterial)).thenReturn(revisions(mockMaterial, modification)); materialChecker.findLatestRevisions(new MaterialRevisions(), new Materials(mockMaterial)); Mockito.verify(materialRepository).findLatestModification(mockMaterial); } private MaterialRevisions revisions(Material material, Modification modification) { return new MaterialRevisions(new MaterialRevision(material, modifications(modification))); } @Test public void shouldUseLatestPipelineInstanceForDependentPipelineGivenThePreviousRevision() throws Exception { DependencyMaterial dependencyMaterial = new DependencyMaterial(new CaseInsensitiveString("pipeline-name"), new CaseInsensitiveString("stage-name")); Stage passedStage = StageMother.passedStageInstance("stage-name", "job-name", "pipeline-name"); MaterialRevisions materialRevisions = new MaterialRevisions(); Modification previous = new Modification("Unknown", "Unknown", null, passedStage.completedDate(), "pipeline-name/1/stage-name/0"); MaterialRevision previousRevision = revisions(dependencyMaterial, previous).getMaterialRevision(0); when(materialRepository.findModificationsSince(dependencyMaterial, previousRevision)).thenReturn(Arrays.asList(new Modification(new Date(), "pipeline-name/2/stage-name/0", "MOCK_LABEL-12", null))); MaterialRevisions revisionsSince = materialChecker.findRevisionsSince(materialRevisions, new Materials(dependencyMaterial), new MaterialRevisions(previousRevision), new MaterialRevisions()/*will not be used, as no new material has been introduced*/); assertThat(revisionsSince.getMaterialRevision(0).getRevision().getRevision(), is("pipeline-name/2/stage-name/0")); } @Test public void shouldUseLatestPipelineInstanceForDependentPipeline() throws Exception { DependencyMaterial dependencyMaterial = new DependencyMaterial(new CaseInsensitiveString("pipeline-name"), new CaseInsensitiveString("stage-name")); Stage passedStage = StageMother.passedStageInstance("stage-name", "job-name", "pipeline-name"); Modification modification = new Modification("Unknown", "Unknown", null, passedStage.completedDate(), "pipeline-name/1[LABEL-1]/stage-name/0"); Mockito.when(materialRepository.findLatestModification(dependencyMaterial)).thenReturn(revisions(dependencyMaterial,modification)); materialChecker.findLatestRevisions(new MaterialRevisions(), new Materials(dependencyMaterial)); Mockito.verify(materialRepository).findLatestModification(dependencyMaterial); } @Test public void shouldSkipLatestRevisionsForMaterialsThatWereAlreadyChecked() throws Exception { DependencyMaterial dependencyMaterial = new DependencyMaterial(new CaseInsensitiveString("pipeline-name"), new CaseInsensitiveString("stage-name")); SvnMaterial svnMaterial = new SvnMaterial("svnUrl", null, null, false); Stage passedStage = StageMother.passedStageInstance("stage-name", "job-name", "pipeline-name"); Modification dependencyModification = new Modification("Unknown", "Unknown", null, passedStage.completedDate(), "pipeline-name/1[LABEL-1]/stage-name/0"); Modification svnModification = new Modification("user", "commend", "em@il", new Date(), "1"); Mockito.when(materialRepository.findLatestModification(svnMaterial)).thenReturn(revisions(dependencyMaterial, svnModification)); materialChecker.findLatestRevisions(new MaterialRevisions(new MaterialRevision(dependencyMaterial, dependencyModification)), new Materials(dependencyMaterial, svnMaterial)); Mockito.verify(materialRepository, never()).findLatestModification(dependencyMaterial); Mockito.verify(materialRepository).findLatestModification(svnMaterial); } @Test public void shouldFindSpecificRevisionForDependentPipeline() throws Exception { DependencyMaterial dependencyMaterial = new DependencyMaterial(new CaseInsensitiveString("pipeline-name"), new CaseInsensitiveString("stage-name")); Stage passedStage = StageMother.passedStageInstance("stage-name", "job-name", "pipeline-name"); Modification modification = new Modification("Unknown", "Unknown", null, passedStage.completedDate(), "pipeline-name/1/stage-name/0"); Mockito.when(materialRepository.findModificationWithRevision(dependencyMaterial,"pipeline-name/1/stage-name/0")).thenReturn(modification); MaterialRevision actualRevision = materialChecker.findSpecificRevision(dependencyMaterial, "pipeline-name/1/stage-name/0"); assertThat(actualRevision.getModifications().size(), is(1)); assertThat(actualRevision.getModification(0).getModifiedTime(), is(passedStage.completedDate())); assertThat(actualRevision.getModification(0).getRevision(), is("pipeline-name/1/stage-name/0")); } @Test public void shouldThrowExceptionIfSpecifiedRevisionDoesNotExist() throws Exception { DependencyMaterial dependencyMaterial = new DependencyMaterial(new CaseInsensitiveString("pipeline-name"), new CaseInsensitiveString("stage-name")); Mockito.when(materialRepository.findModificationWithRevision(dependencyMaterial,"pipeline-name/500/stage-name/0")).thenReturn(null); try { materialChecker.findSpecificRevision(dependencyMaterial, "pipeline-name/500/stage-name/0"); fail("Should not be able to find revision"); } catch (Exception expected) { assertThat(expected.getMessage(), is(format("Unable to find revision [pipeline-name/500/stage-name/0] for material [%s]", dependencyMaterial))); } } @Test public void shouldThrowExceptionIfRevisionIsNotSpecified() throws Exception { DependencyMaterial dependencyMaterial = new DependencyMaterial(new CaseInsensitiveString("pipeline-name"), new CaseInsensitiveString("stage-name")); try { materialChecker.findSpecificRevision(dependencyMaterial, ""); fail("Should not be able to empty revision"); } catch (Exception expected) { assertThat(expected.getMessage(), is(format("Revision was not specified for material [%s]", dependencyMaterial))); } } @Test public void shouldSkipFindingRevisionsSinceForMaterialsThatWereAlreadyChecked() throws Exception { DependencyMaterial dependencyMaterial = new DependencyMaterial(new CaseInsensitiveString("pipeline-name"), new CaseInsensitiveString("stage-name")); SvnMaterial svnMaterial = new SvnMaterial("svnUrl", null, null, false); Stage passedStage = StageMother.passedStageInstance("stage-name", "job-name", "pipeline-name"); MaterialRevision previousDependantRevision = new MaterialRevision(dependencyMaterial, new Modification("Unknown", "Unknown", null, passedStage.completedDate(), "pipeline-name/1[LABEL-1]/stage-name/0")); Modification dependencyModification = new Modification("Unknown", "Unknown", null, passedStage.completedDate(), "pipeline-name/2[LABEL-2]/stage-name/0"); MaterialRevision previousSvnRevision = new MaterialRevision(svnMaterial, mod(1L)); Modification svnModification = new Modification("user", "commend", "em@il", new Date(), "2"); Mockito.when(materialRepository.findModificationsSince(svnMaterial, previousSvnRevision)).thenReturn(modifications(svnModification)); MaterialRevisions alreadyFoundRevisions = new MaterialRevisions(new MaterialRevision(dependencyMaterial, dependencyModification)); MaterialRevisions latestRevisions = new MaterialRevisions(); //will not be used, as no new materials have appeared MaterialRevisions revisionsSince = materialChecker.findRevisionsSince(alreadyFoundRevisions, new Materials(dependencyMaterial, svnMaterial), new MaterialRevisions(previousDependantRevision, previousSvnRevision), latestRevisions); assertThat(revisionsSince, is(new MaterialRevisions(new MaterialRevision(dependencyMaterial, dependencyModification), new MaterialRevision(svnMaterial, svnModification)))); Mockito.verify(materialRepository, never()).findLatestModification(dependencyMaterial); Mockito.verify(materialRepository).findModificationsSince(svnMaterial, previousSvnRevision); } @Test public void shouldUseLatestMaterialDuringCreationOfNewRevisionsSince_bug7486() throws Exception { DependencyMaterial dependencyMaterial = new DependencyMaterial(new CaseInsensitiveString("pipeline-name"), new CaseInsensitiveString("stage-name")); PackageMaterial oldPkgMaterial = MaterialsMother.packageMaterial("repo-id", "repo-old-name", "pkg-id", "pkg-old-name", ConfigurationPropertyMother.create("key", false, "value")); Stage passedStage = StageMother.passedStageInstance("stage-name", "job-name", "pipeline-name"); MaterialRevision previousDependantRevision = new MaterialRevision(dependencyMaterial, new Modification("Unknown", "Unknown", null, passedStage.completedDate(), "pipeline-name/1[LABEL-1]/stage-name/0")); Modification dependencyModification = new Modification("Unknown", "Unknown", null, passedStage.completedDate(), "pipeline-name/2[LABEL-2]/stage-name/0"); Modification oldPkgMod = mod(1L); MaterialRevision previousPkgRevision = new MaterialRevision(oldPkgMaterial, oldPkgMod); PackageMaterial newPkgMaterial = MaterialsMother.packageMaterial("repo-id", "repo-new-name", "pkg-id", "pkg-new-name", ConfigurationPropertyMother.create("key", false, "value")); Modification newPkgMod = mod(2L); Mockito.when(materialRepository.findModificationsSince(oldPkgMaterial, previousPkgRevision)).thenReturn(modifications(newPkgMod)); MaterialRevisions alreadyFoundRevisions = new MaterialRevisions(new MaterialRevision(dependencyMaterial, dependencyModification)); MaterialRevisions latestRevisions = new MaterialRevisions(); //will not be used, as no new materials have appeared MaterialRevisions revisionsSince = materialChecker.findRevisionsSince(alreadyFoundRevisions, new Materials(dependencyMaterial, newPkgMaterial), new MaterialRevisions(previousDependantRevision, previousPkgRevision), latestRevisions); assertThat(revisionsSince, is(new MaterialRevisions(new MaterialRevision(dependencyMaterial, dependencyModification), new MaterialRevision(oldPkgMaterial, newPkgMod)))); // since name is not part of equals assertThat(((PackageMaterial)revisionsSince.getMaterialRevision(1).getMaterial()).getPackageDefinition().getName(), is("pkg-new-name")); assertThat(((PackageMaterial)revisionsSince.getMaterialRevision(1).getMaterial()).getPackageDefinition().getRepository().getName(), is("repo-new-name")); Mockito.verify(materialRepository, never()).findLatestModification(dependencyMaterial); Mockito.verify(materialRepository).findModificationsSince(oldPkgMaterial, previousPkgRevision); } @Test public void shouldNOTSkipFindingRevisionsSinceForMaterialsThatAreNewlyAdded() throws Exception { SvnMaterial svnMaterial = new SvnMaterial("svnUrl", null, null, false); SvnMaterial svnExternalMaterial = new SvnMaterial("svnExternalUrl", null, null, false); Modification svnExternalModification = new Modification("user", "external commit", "em@il", new Date(), "3"); MaterialRevision previousSvnRevision = new MaterialRevision(svnMaterial, mod(1L)); Modification svnModification = new Modification("user", "commend", "em@il", new Date(), "2"); MaterialRevisions latestRevisions = new MaterialRevisions(new MaterialRevision(svnMaterial, svnModification), new MaterialRevision(svnExternalMaterial, svnExternalModification)); Mockito.when(materialRepository.findModificationsSince(svnMaterial, previousSvnRevision)).thenReturn(modifications(svnModification)); MaterialRevisions revisionsSince = materialChecker.findRevisionsSince(new MaterialRevisions(), new Materials(svnMaterial, svnExternalMaterial), new MaterialRevisions(previousSvnRevision), latestRevisions); assertThat(revisionsSince, is(new MaterialRevisions(new MaterialRevision(svnMaterial, svnModification), new MaterialRevision(svnExternalMaterial, svnExternalModification)))); Mockito.verify(materialRepository).findModificationsSince(svnMaterial, previousSvnRevision); } @Test public void updateChangedRevisionsShouldFilterRevisionsThatHaveBuiltBefore() { CaseInsensitiveString pipelineName = new CaseInsensitiveString("pipelineName"); GitMaterial gitMaterial = new GitMaterial("git://foo"); BuildCause buildCause = BuildCause.createWithModifications(new MaterialRevisions(new MaterialRevision(gitMaterial, mod(10L), mod(9L), mod(8L))), "user"); when(materialRepository.latestModificationRunByPipeline(pipelineName, gitMaterial)).thenReturn(9L); materialChecker.updateChangedRevisions(pipelineName, buildCause); MaterialRevisions actualRevisions = buildCause.getMaterialRevisions(); assertThat(actualRevisions.getModifications(gitMaterial), is(new Modifications(mod(10L)))); assertThat(actualRevisions.findRevisionFor(gitMaterial).isChanged(), is(true)); } @Test public void updateChangedRevisionsShouldRetainLatestRevisionIfAllHaveBuiltBefore() { CaseInsensitiveString pipelineName = new CaseInsensitiveString("pipelineName"); GitMaterial gitMaterial = new GitMaterial("git://foo"); BuildCause buildCause = BuildCause.createWithModifications(new MaterialRevisions(new MaterialRevision(gitMaterial, mod(10L), mod(9L), mod(8L))), "user"); when(materialRepository.latestModificationRunByPipeline(pipelineName, gitMaterial)).thenReturn(10L); materialChecker.updateChangedRevisions(pipelineName, buildCause); MaterialRevisions actualRevisions = buildCause.getMaterialRevisions(); assertThat(actualRevisions.getModifications(gitMaterial), is(new Modifications(mod(10L), mod(9L), mod(8L)))); assertThat(actualRevisions.findRevisionFor(gitMaterial).isChanged(), is(false)); } private Modification mod(final Long revision) { Modification modification = new Modification("user", "comment", "em@il", new Date(12121), revision.toString()); modification.setId(revision); return modification; } }