/* * Copyright 2017 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. */ package com.thoughtworks.go.server.service; import java.util.*; import com.thoughtworks.go.config.*; import com.thoughtworks.go.config.materials.MaterialConfigs; import com.thoughtworks.go.config.materials.ScmMaterial; import com.thoughtworks.go.config.materials.dependency.DependencyMaterial; import com.thoughtworks.go.config.materials.svn.SvnMaterial; import com.thoughtworks.go.domain.MaterialInstance; import com.thoughtworks.go.domain.MaterialRevision; import com.thoughtworks.go.domain.MaterialRevisions; import com.thoughtworks.go.domain.PersistentObject; import com.thoughtworks.go.domain.Pipeline; import com.thoughtworks.go.domain.PipelineMaterialRevision; 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.materials.svn.SvnMaterialInstance; import com.thoughtworks.go.helper.MaterialsMother; import com.thoughtworks.go.helper.PipelineConfigMother; import com.thoughtworks.go.i18n.Localizer; import com.thoughtworks.go.security.GoCipher; import com.thoughtworks.go.server.dao.DatabaseAccessHelper; import com.thoughtworks.go.server.domain.Username; import com.thoughtworks.go.server.materials.DependencyMaterialUpdateNotifier; import com.thoughtworks.go.server.persistence.MaterialRepository; import com.thoughtworks.go.server.service.result.HttpLocalizedOperationResult; import com.thoughtworks.go.server.transaction.TransactionTemplate; import com.thoughtworks.go.server.web.PipelineRevisionRange; import com.thoughtworks.go.util.GoConfigFileHelper; import org.joda.time.DateTime; import org.junit.After; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.test.context.ContextConfiguration; import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; import org.springframework.transaction.TransactionStatus; import org.springframework.transaction.support.TransactionCallbackWithoutResult; import static com.thoughtworks.go.helper.ModificationsMother.checkinWithComment; import static org.hamcrest.core.Is.is; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertThat; @RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration(locations = { "classpath:WEB-INF/applicationContext-global.xml", "classpath:WEB-INF/applicationContext-dataLocalAccess.xml", "classpath:WEB-INF/applicationContext-acegi-security.xml" }) public class ChangesetServiceIntegrationTest { @Autowired MaterialRepository materialRepository; @Autowired PipelineService pipelineService; @Autowired ChangesetService changesetService; @Autowired private GoConfigDao goConfigDao; @Autowired private Localizer localizer; @Autowired private DatabaseAccessHelper dbHelper; @Autowired private TransactionTemplate transactionTemplate; @Autowired private DependencyMaterialUpdateNotifier notifier; private PipelineConfig pipelineConfigWithTwoMaterials; private PipelineConfig pipelineConfig; private PipelineConfig pipelineConfigWithSvn; private ScmMaterial git; private ScmMaterial hg; private ScmMaterial svn; private GoConfigFileHelper configHelper; private static int counter = 0; @Before public void setUp() throws Exception { dbHelper.onSetUp(); configHelper = new GoConfigFileHelper(goConfigDao); configHelper.onSetUp(); git = MaterialsMother.gitMaterial("http://google.com", null, "master"); git.setFolder("git"); hg = MaterialsMother.hgMaterial(); hg.setFolder("hg"); svn = MaterialsMother.svnMaterial("http://google.com/svn"); svn.setFolder("svn"); pipelineConfig = configHelper.addPipeline("foo-bar", "stage", new MaterialConfigs(hg.config()), "build"); pipelineConfigWithTwoMaterials = configHelper.addPipeline("foo", "stage", new MaterialConfigs(git.config(), hg.config()), "build"); pipelineConfigWithSvn = configHelper.addPipeline("bar", "stage", new MaterialConfigs(svn.config()), "build"); notifier.disableUpdates(); } @After public void tearDown() throws Exception { notifier.enableUpdates(); dbHelper.onTearDown(); configHelper.onTearDown(); } @Test public void shouldUnderstandModificationsBetween_MultipleSetsOfInstances_OfDifferentPipelines() { Username loser = new Username(new CaseInsensitiveString("loser")); ManualBuild build = new ManualBuild(loser); Date checkinTime = new Date(); Modification hgCommit1 = checkinWithComment("abcd", "#4518 - foo", checkinTime); Modification gitCommit1 = checkinWithComment("1234", "#3750 - agent index", checkinTime); Pipeline pipelineOne = dbHelper.checkinRevisionsToBuild(build, pipelineConfigWithTwoMaterials, dbHelper.addRevisionsWithModifications(hg, hgCommit1), dbHelper.addRevisionsWithModifications(git, gitCommit1)); Modification hgCommit2 = checkinWithComment("bcde", "#4520 - foo", checkinTime); Modification gitCommit2 = checkinWithComment("2355", "#3750 - agent index", checkinTime); dbHelper.checkinRevisionsToBuild(build, pipelineConfigWithTwoMaterials, dbHelper.addRevisionsWithModifications(hg, hgCommit2), dbHelper.addRevisionsWithModifications(git, gitCommit2)); Modification hgCommit3 = checkinWithComment("cdef", "#4521 - get gadget working", checkinTime); Modification gitCommit3 = checkinWithComment("2345", "#4200 - whatever", checkinTime); Pipeline pipelineThree = dbHelper.checkinRevisionsToBuild(build, pipelineConfigWithTwoMaterials, dbHelper.addRevisionsWithModifications(hg, hgCommit3), dbHelper.addRevisionsWithModifications(git, gitCommit3)); Modification svnCommit1 = checkinWithComment("9876", "svn ci", checkinTime); Pipeline pipelineSvnOne = dbHelper.checkinRevisionsToBuild(build, pipelineConfigWithSvn, dbHelper.addRevisionsWithModifications(svn, svnCommit1)); Modification svnCommit2 = checkinWithComment("5432", "another svn ci", checkinTime); Pipeline pipelineSvnTwo = dbHelper.checkinRevisionsToBuild(build, pipelineConfigWithSvn, dbHelper.addRevisionsWithModifications(svn, svnCommit2)); Modification svnCommit3 = checkinWithComment("666", "svn ci 3", checkinTime); Modification svnCommit4 = checkinWithComment("121212", "svn ci 4", checkinTime); Pipeline pipelineSvnThree = dbHelper.checkinRevisionsToBuild(build, pipelineConfigWithSvn, dbHelper.addRevisionsWithModifications(svn, svnCommit4, svnCommit3)); HttpLocalizedOperationResult result = new HttpLocalizedOperationResult(); List<MaterialRevision> revisions = changesetService.revisionsBetween( Arrays.asList(pipelineRevRange(pipelineOne, pipelineThree), pipelineRevRange(pipelineSvnOne, pipelineSvnThree)), loser, result); List<MaterialRevision> expectedRevisions = Arrays.asList( new MaterialRevision(hg, hgCommit3, hgCommit2), new MaterialRevision(git, gitCommit3, gitCommit2), new MaterialRevision(svn, svnCommit4, svnCommit3, svnCommit2)); assertMaterialRevisions(expectedRevisions, revisions); assertThat(result.isSuccessful(), is(true)); } private PipelineRevisionRange pipelineRevRange(Pipeline from, Pipeline to) { return new PipelineRevisionRange(from.getName(), rev(from), rev(to)); } private String rev(Pipeline pipeline) { return String.format("%s/%s/%s/%s", pipeline.getName(), pipeline.getCounter(), pipeline.getFirstStage().getName(), pipeline.getFirstStage().getCounter()); } @Test public void shouldUnderstandModificationsBetweenTwoPipelineInstances() { Username loser = new Username(new CaseInsensitiveString("loser")); ManualBuild build = new ManualBuild(loser); Date checkinTime = new Date(); Modification hgCommit1 = checkinWithComment("abcd", "#4518 - foo", checkinTime); Modification gitCommit1 = checkinWithComment("1234", "#3750 - agent index", checkinTime); Pipeline pipelineOne = dbHelper.checkinRevisionsToBuild(build, pipelineConfigWithTwoMaterials, dbHelper.addRevisionsWithModifications(hg, hgCommit1), dbHelper.addRevisionsWithModifications(git, gitCommit1)); Modification hgCommit2 = checkinWithComment("bcde", "#4520 - foo", checkinTime); Modification gitCommit2 = checkinWithComment("2355", "#3750 - agent index", checkinTime); dbHelper.checkinRevisionsToBuild(build, pipelineConfigWithTwoMaterials, dbHelper.addRevisionsWithModifications(hg, hgCommit2), dbHelper.addRevisionsWithModifications(git, gitCommit2)); Modification hgCommit3 = checkinWithComment("cdef", "#4521 - get gadget working", checkinTime); Modification gitCommit3 = checkinWithComment("2345", "#4200 - whatever", checkinTime); Pipeline pipelineThree = dbHelper.checkinRevisionsToBuild(build, pipelineConfigWithTwoMaterials, dbHelper.addRevisionsWithModifications(hg, hgCommit3), dbHelper.addRevisionsWithModifications(git, gitCommit3)); List<MaterialRevision> expectedRevisions = Arrays.asList( new MaterialRevision(hg, hgCommit3, hgCommit2), new MaterialRevision(git, gitCommit3, gitCommit2)); HttpLocalizedOperationResult result = new HttpLocalizedOperationResult(); List<MaterialRevision> revisions = changesetService.revisionsBetween("foo", pipelineOne.getCounter(), pipelineThree.getCounter(), loser, result, true, false); assertMaterialRevisions(expectedRevisions, revisions); assertThat(result.isSuccessful(), is(true)); } @Test public void shouldNotDuplicateModificationsWhileComputingRevisionsBetweenTwoPipelineInstances() { Username loser = new Username(new CaseInsensitiveString("loser")); ManualBuild build = new ManualBuild(loser); Date checkinTime = new Date(); Modification hgCommit1 = checkinWithComment("abcd", "#4518 - foo", checkinTime); MaterialRevision materialRevision = dbHelper.addRevisionsWithModifications(hg, hgCommit1); Pipeline pipelineOne = dbHelper.checkinRevisionsToBuild(build, pipelineConfig, materialRevision); dbHelper.checkinRevisionsToBuild(build, pipelineConfig, materialRevision); dbHelper.checkinRevisionsToBuild(build, pipelineConfig, materialRevision); Pipeline pipelineFour = dbHelper.checkinRevisionsToBuild(build, pipelineConfig, materialRevision); List<MaterialRevision> expectedRevisions = Arrays.asList(new MaterialRevision(hg, hgCommit1)); HttpLocalizedOperationResult result = new HttpLocalizedOperationResult(); List<MaterialRevision> revisions = changesetService.revisionsBetween(CaseInsensitiveString.str(pipelineConfig.name()), pipelineOne.getCounter(), pipelineFour.getCounter(), loser, result, true, false); assertMaterialRevisions(expectedRevisions, revisions); assertThat(result.isSuccessful(), is(true)); } @Test public void shouldGetModificationsFrom0To1() { Username loser = new Username(new CaseInsensitiveString("loser")); ManualBuild build = new ManualBuild(loser); Date checkinTime = new Date(); Modification hgCommit1 = checkinWithComment("abcd", "#4518 - foo", checkinTime); Modification gitCommit1 = checkinWithComment("1234", "#3750 - agent index", checkinTime); Pipeline pipelineOne = dbHelper.checkinRevisionsToBuild(build, pipelineConfigWithTwoMaterials, dbHelper.addRevisionsWithModifications(hg, hgCommit1), dbHelper.addRevisionsWithModifications(git, gitCommit1)); List<MaterialRevision> expectedRevisions = Arrays.asList(new MaterialRevision(hg, hgCommit1), new MaterialRevision(git, gitCommit1)); HttpLocalizedOperationResult result = new HttpLocalizedOperationResult(); List<MaterialRevision> revisions = changesetService.revisionsBetween("foo", 0, pipelineOne.getCounter(), loser, result, true, false); assertMaterialRevisions(expectedRevisions, revisions); assertThat(result.isSuccessful(), is(true)); } @Test public void shouldGetModificationsFrom1To1() { Username loser = new Username(new CaseInsensitiveString("loser")); ManualBuild build = new ManualBuild(loser); Date checkinTime = new Date(); Modification hgCommit1 = checkinWithComment("abcd", "#4518 - foo", checkinTime); Modification gitCommit1 = checkinWithComment("1234", "#3750 - agent index", checkinTime); Pipeline pipelineOne = dbHelper.checkinRevisionsToBuild(build, pipelineConfigWithTwoMaterials, dbHelper.addRevisionsWithModifications(hg, hgCommit1), dbHelper.addRevisionsWithModifications(git, gitCommit1)); List<MaterialRevision> expectedRevisions = Arrays.asList(new MaterialRevision(hg, hgCommit1), new MaterialRevision(git, gitCommit1)); HttpLocalizedOperationResult result = new HttpLocalizedOperationResult(); List<MaterialRevision> revisions = changesetService.revisionsBetween("foo", pipelineOne.getCounter(), pipelineOne.getCounter(), loser, result, true, false); assertMaterialRevisions(expectedRevisions, revisions); assertThat(result.isSuccessful(), is(true)); } @Test public void shouldFailWhenUserDoesNotHaveAccess() { SecurityConfig securityConfig = new SecurityConfig(new LdapConfig(new GoCipher()), new PasswordFileConfig("/tmp/foo.passwd"), true); securityConfig.adminsConfig().add(new AdminUser(new CaseInsensitiveString("admin"))); configHelper.addSecurity(securityConfig); CruiseConfig config = this.configHelper.getCachedGoConfig().loadForEditing(); config.pipelines(BasicPipelineConfigs.DEFAULT_GROUP).setAuthorization(new Authorization(new ViewConfig(new AdminUser(new CaseInsensitiveString("admin"))))); configHelper.writeConfigFile(config); HttpLocalizedOperationResult result = new HttpLocalizedOperationResult(); changesetService.revisionsBetween("foo", 1, 3, new Username(new CaseInsensitiveString("some_loser")), result, true, false); assertThat(result.isSuccessful(), is(false)); assertThat(result.message(localizer), is("You do not have view permissions for pipeline 'foo'.")); assertThat(result.httpCode(), is(401)); } @Test public void shouldReturn404WhenPipelineIsNotFound() { HttpLocalizedOperationResult result = new HttpLocalizedOperationResult(); changesetService.revisionsBetween("Pipeline_Not_Found", 1, 3, new Username(new CaseInsensitiveString("some_loser")), result, true, false); assertThat(result.isSuccessful(), is(false)); assertThat(result.message(localizer), is("pipeline 'Pipeline_Not_Found' not found.")); assertThat(result.httpCode(), is(404)); } @Test public void shouldFailUnlessPipelineCountersAreNatural() { validateFailsForNonNaturalCounter(-1, 10); validateFailsForNonNaturalCounter(0, 0); validateFailsForNonNaturalCounter(2, -2); validateFailsForNonNaturalCounter(2, 0); validateFailsForNonNaturalCounter(-12, -10); } @Test public void shouldReturnResults_WhenPipelineCountersIsBisect_ButUserWantsToSeeDiff() { Username loser = new Username(new CaseInsensitiveString("loser")); ManualBuild build = new ManualBuild(loser); DateTime now = new DateTime(); Pipeline firstPipeline = dbHelper.checkinRevisionsToBuild(build, pipelineConfig, dbHelper.addRevisionsWithModifications(hg, checkinWithComment("1", "#3518 - hg - foo", now.toDate()))); Modification bisectModification = checkinWithComment("3", "#4750 - Rev 3", now.plusDays(3).toDate()); dbHelper.checkinRevisionsToBuild(build, pipelineConfig, dbHelper.addRevisionsWithModifications(hg, checkinWithComment("2", "#3750 - Rev 2", now.plusDays(2).toDate()), bisectModification, checkinWithComment("4", "#4750 - Rev 4", now.plus(4).toDate()))); dbHelper.checkinRevisionsToBuild(build, pipelineConfig, dbHelper.addRevisionsWithModifications(hg, checkinWithComment("5", "#5750 - Rev 5", now.plusDays(5).toDate()))); Pipeline bisectPipeline = dbHelper.checkinRevisionsToBuild(build, pipelineConfig, new MaterialRevision(hg, bisectModification)); Pipeline nextPipeline = dbHelper.checkinRevisionsToBuild(build, pipelineConfig, dbHelper.addRevisionsWithModifications(hg, checkinWithComment("6", "#4150 - Rev 6", now.plusDays(7).toDate()))); HttpLocalizedOperationResult result = new HttpLocalizedOperationResult(); //when to counter is a bisect List<MaterialRevision> revisionList = changesetService. revisionsBetween("foo-bar", firstPipeline.getCounter(), bisectPipeline.getCounter(), new Username(new CaseInsensitiveString("loser")), result, true, true); assertThat(stringRevisions(revisionList), is(Arrays.asList("5", "2", "3", "4"))); //When from counter is a bisect revisionList = changesetService.revisionsBetween("foo-bar", bisectPipeline.getCounter(), nextPipeline.getCounter(), new Username(new CaseInsensitiveString("loser")), result, true, true); assertThat(stringRevisions(revisionList), is(Arrays.asList("6", "5", "2"))); } @Test public void shouldReturnAnEmptyListWhenEitherOfThePipelineCounterIsABisect() { Username loser = new Username(new CaseInsensitiveString("loser")); ManualBuild build = new ManualBuild(loser); DateTime now = new DateTime(); Pipeline firstPipeline = dbHelper.checkinRevisionsToBuild(build, pipelineConfig, dbHelper.addRevisionsWithModifications(hg, checkinWithComment("1", "#3518 - hg - foo", now.toDate()))); Modification bisectModification = checkinWithComment("3", "#4750 - Rev 3", now.plusDays(3).toDate()); dbHelper.checkinRevisionsToBuild(build, pipelineConfig, dbHelper.addRevisionsWithModifications(hg, checkinWithComment("2", "#3750 - Rev 2", now.plusDays(2).toDate()), bisectModification, checkinWithComment("4", "#4750 - Rev 4", now.plus(4).toDate()))); dbHelper.checkinRevisionsToBuild(build, pipelineConfig, dbHelper.addRevisionsWithModifications(hg, checkinWithComment("5", "#5750 - Rev 5", now.plusDays(5).toDate()))); Pipeline bisectPipeline = dbHelper.checkinRevisionsToBuild(build, pipelineConfig, new MaterialRevision(hg, bisectModification)); Pipeline nextPipeline = dbHelper.checkinRevisionsToBuild(build, pipelineConfig, dbHelper.addRevisionsWithModifications(hg, checkinWithComment("6", "#4150 - Rev 6", now.plusDays(7).toDate()))); HttpLocalizedOperationResult result = new HttpLocalizedOperationResult(); //when to counter is a bisect List<MaterialRevision> revisionList = changesetService.revisionsBetween("foo-bar", firstPipeline.getCounter(), bisectPipeline.getCounter(), new Username(new CaseInsensitiveString("loser")), result, true, false); assertThat(revisionList.isEmpty(), is(true)); //When from counter is a bisect revisionList = changesetService.revisionsBetween("foo-bar", bisectPipeline.getCounter(), nextPipeline.getCounter(), new Username(new CaseInsensitiveString("loser")), result, true, false); assertThat(revisionList.isEmpty(), is(true)); } @Test public void shouldSkipBisectPipelineCountersWhenThereIsABisectBetweenToAndFromCounters() { Username loser = new Username(new CaseInsensitiveString("loser")); ManualBuild build = new ManualBuild(loser); DateTime now = new DateTime(); Pipeline firstPipeline = dbHelper.checkinRevisionsToBuild(build, pipelineConfig, dbHelper.addRevisionsWithModifications(hg, checkinWithComment("1", "#3518 - hg - foo", now.toDate()))); Modification bisectModification = checkinWithComment("3", "#4750 - Rev 3", now.plusDays(3).toDate()); dbHelper.checkinRevisionsToBuild(build, pipelineConfig, dbHelper.addRevisionsWithModifications(hg, checkinWithComment("2", "#3750 - Rev 2", now.plusDays(2).toDate()), bisectModification, checkinWithComment("4", "#4750 - Rev 4", now.plusDays(4).toDate()))); dbHelper.checkinRevisionsToBuild(build, pipelineConfig, dbHelper.addRevisionsWithModifications(hg, checkinWithComment("5", "#5750 - Rev 5", now.plusDays(5).toDate()))); dbHelper.checkinRevisionsToBuild(build, pipelineConfig, new MaterialRevision(hg, bisectModification)); Pipeline lastPipeline = dbHelper.checkinRevisionsToBuild(build, pipelineConfig, dbHelper.addRevisionsWithModifications(hg, checkinWithComment("6", "#6760 - Rev 6", now.plusDays(6).toDate()))); HttpLocalizedOperationResult result = new HttpLocalizedOperationResult(); List<MaterialRevision> revisionsBetween = changesetService.revisionsBetween("foo-bar", firstPipeline.getCounter(), lastPipeline.getCounter(), new Username(new CaseInsensitiveString("loser")), result, true, false); assertThat(result.isSuccessful(), is(true)); assertThat(revisionsBetween.size(), is(1)); Modifications actualMods = revisionsBetween.get(0).getModifications(); assertThat(actualMods.size(), is(5)); } @Test public void shouldPopulateActualFromRevisionId() { PipelineConfig upstreamPipeline = configHelper.addPipeline("upstream", "stage", git.config(), "job"); DependencyMaterial dependencyMaterial = MaterialsMother.dependencyMaterial("upstream", "stage"); PipelineConfig downstreamConfig = configHelper.addPipeline("downstream", "stage", dependencyMaterial.config(), "build"); Username username = new Username(new CaseInsensitiveString("user1")); //By default the pmr's actualFromRevisionId should be the fromRevisionId List<MaterialRevision> revisionsForUpstream1 = new ArrayList<>(); addRevisionWith2Mods(revisionsForUpstream1, git); Pipeline upstream1 = dbHelper.checkinRevisionsToBuild(new ManualBuild(username), upstreamPipeline, revisionsForUpstream1); assertPipelineMaterialRevisions(upstream1); //First downstream pipeline's actualFromRevisionId should also be it's fromRevisionId List<MaterialRevision> revisionsForDownstream1 = new ArrayList<>(); dbHelper.addDependencyRevisionModification(revisionsForDownstream1, dependencyMaterial, upstream1); Pipeline downstream1 = dbHelper.checkinRevisionsToBuild(new ManualBuild(username), downstreamConfig, revisionsForDownstream1); assertPipelineMaterialRevisions(downstream1); // When downstream is triggered with a range of upstream modifications it's actualFromRevisionId should be 1 more than the last one that was built List<MaterialRevision> revisionsForUpstream2 = new ArrayList<>(); addRevisionWith2Mods(revisionsForUpstream2, git); Pipeline upstream2 = dbHelper.checkinRevisionsToBuild(new ManualBuild(username), upstreamPipeline, revisionsForUpstream2); assertPipelineMaterialRevisions(upstream2); List<MaterialRevision> revisionsForUpstream3 = new ArrayList<>(); addRevisionWith2Mods(revisionsForUpstream3, git); Pipeline upstream3 = dbHelper.checkinRevisionsToBuild(new ManualBuild(username), upstreamPipeline, revisionsForUpstream3); assertPipelineMaterialRevisions(upstream3); List<MaterialRevision> revisionsForUpstream4 = new ArrayList<>(); addRevisionWith2Mods(revisionsForUpstream4, git); Pipeline upstream4 = dbHelper.checkinRevisionsToBuild(new ManualBuild(username), upstreamPipeline, revisionsForUpstream4); assertPipelineMaterialRevisions(upstream4); List<MaterialRevision> depMaterialRevision = new ArrayList<>(); dbHelper.addDependencyRevisionModification(depMaterialRevision, dependencyMaterial, upstream2); Modification expectedMod = depMaterialRevision.get(0).getLatestModification(); MaterialInstance dep = materialRepository.findOrCreateFrom(dependencyMaterial); saveRev(expectedMod, dep); dbHelper.addDependencyRevisionModification(depMaterialRevision, dependencyMaterial, upstream3); saveRev(depMaterialRevision.get(0).getLatestModification(), dep); List<MaterialRevision> revisionsForDownstream2 = new ArrayList<>(); dbHelper.addDependencyRevisionModification(revisionsForDownstream2, dependencyMaterial, upstream4); Pipeline downstream2 = dbHelper.checkinRevisionsToBuild(new ManualBuild(username), downstreamConfig, revisionsForDownstream2); List<PipelineMaterialRevision> pmrs = materialRepository.findPipelineMaterialRevisions(downstream2.getId()); assertThat(pmrs.size(), is(1)); assertThat(pmrs.get(0).getActualFromRevisionId(), is(expectedMod.getId())); } private void saveRev(final Modification expectedMod, final MaterialInstance dep) { transactionTemplate.execute(new TransactionCallbackWithoutResult() { @Override protected void doInTransactionWithoutResult(TransactionStatus status) { materialRepository.saveModification(dep, expectedMod); } }); } private void assertPipelineMaterialRevisions(Pipeline upstreamOne) { List<PipelineMaterialRevision> pmrs = materialRepository.findPipelineMaterialRevisions(upstreamOne.getId()); assertThat(pmrs.size(), is(1)); assertThat(pmrs.get(0).getActualFromRevisionId(), is(pmrs.get(0).getFromModification().getId())); } @Test public void shouldReturnTheHgMaterialForAGivenPipeline() { List<MaterialRevision> revisions = new ArrayList<>(); addRevisionWith2Mods(revisions, hg); Username username = new Username(new CaseInsensitiveString("user1")); Pipeline pipelineOne = dbHelper.checkinRevisionsToBuild(new ManualBuild(username), pipelineConfig, revisions); HttpLocalizedOperationResult result = new HttpLocalizedOperationResult(); List<MaterialRevision> actual = changesetService.revisionsBetween(CaseInsensitiveString.str(pipelineConfig.name()), pipelineOne.getCounter(), pipelineOne.getCounter(), username, result, true, false); assertMaterialRevisions(revisions, actual); assertThat(result.isSuccessful(), is(true)); } @Test public void shouldReturnModsOf2MaterialsForAGivenPipeline() { List<MaterialRevision> revisions = new ArrayList<>(); addRevisionWith2Mods(revisions, hg); addRevisionWith2Mods(revisions, git); Username username = new Username(new CaseInsensitiveString("user1")); Pipeline pipelineOne = dbHelper.checkinRevisionsToBuild(new ManualBuild(username), pipelineConfigWithTwoMaterials, revisions); HttpLocalizedOperationResult result = new HttpLocalizedOperationResult(); List<MaterialRevision> actual = changesetService.revisionsBetween(CaseInsensitiveString.str(pipelineConfigWithTwoMaterials.name()), pipelineOne.getCounter(), pipelineOne.getCounter(), username, result, true, false); assertMaterialRevisions(revisions, actual); assertThat(result.isSuccessful(), is(true)); } @Test public void shouldReturnModsOf2MaterialsBetweenTheGivenPipelineCounters() { List<MaterialRevision> revisionsForPipeline1 = new ArrayList<>(); addRevisionWith2Mods(revisionsForPipeline1, hg); addRevisionWith2Mods(revisionsForPipeline1, git); Username username = new Username(new CaseInsensitiveString("user1")); Pipeline pipelineOne = dbHelper.checkinRevisionsToBuild(new ManualBuild(username), pipelineConfigWithTwoMaterials, revisionsForPipeline1); List<MaterialRevision> revisionsForPipeline2 = new ArrayList<>(); addRevisionWith2Mods(revisionsForPipeline2, hg); addRevisionWith2Mods(revisionsForPipeline2, git); Pipeline pipelineTwo = dbHelper.checkinRevisionsToBuild(new ManualBuild(username), pipelineConfigWithTwoMaterials, revisionsForPipeline2); HttpLocalizedOperationResult result = new HttpLocalizedOperationResult(); List<MaterialRevision> actual = changesetService.revisionsBetween(CaseInsensitiveString.str(pipelineConfigWithTwoMaterials.name()), pipelineOne.getCounter(), pipelineTwo.getCounter(), username, result, true, false); List<MaterialRevision> expectedRevisions = groupByMaterial(revisionsForPipeline2); assertMaterialRevisions(expectedRevisions, actual); assertThat(result.isSuccessful(), is(true)); } @Test public void shouldReturnModsOfItsOwnAndAnUpstreamPipelineForTheGivenPipelineCounters() { PipelineConfig upstreamPipeline = configHelper.addPipeline("upstream", "stage", git.config(), "job"); DependencyMaterial dependencyMaterial = MaterialsMother.dependencyMaterial("upstream", "stage"); pipelineConfigWithTwoMaterials.addMaterialConfig(dependencyMaterial.config()); pipelineConfigWithTwoMaterials.removeMaterialConfig(git.config()); Username username = new Username(new CaseInsensitiveString("user1")); //Schedule upstream List<MaterialRevision> revisionsForUpstream1 = new ArrayList<>(); addRevisionWith2Mods(revisionsForUpstream1, git); Pipeline upstreamOne = dbHelper.checkinRevisionsToBuild(new ManualBuild(username), upstreamPipeline, revisionsForUpstream1); //Schedule downstream List<MaterialRevision> revisionsForPipeline1 = new ArrayList<>(); addRevisionWith2Mods(revisionsForPipeline1, hg); dbHelper.addDependencyRevisionModification(revisionsForPipeline1, dependencyMaterial, upstreamOne); Pipeline pipelineOne = dbHelper.checkinRevisionsToBuild(new ManualBuild(username), pipelineConfigWithTwoMaterials, revisionsForPipeline1); HttpLocalizedOperationResult result = new HttpLocalizedOperationResult(); List<MaterialRevision> actual = changesetService.revisionsBetween(CaseInsensitiveString.str(pipelineConfigWithTwoMaterials.name()), pipelineOne.getCounter(), pipelineOne.getCounter(), username, result, true, false); List<MaterialRevision> expectedRevisions = groupByMaterial(revisionsForUpstream1, revisionsForPipeline1); assertMaterialRevisions(expectedRevisions, actual); assertThat(result.isSuccessful(), is(true)); } @Test public void shouldReturnModsOfItsOwnAndAllUpstreamPipelinesForTheGivenCounter() { SvnMaterial svn = MaterialsMother.svnMaterial("http://svn"); PipelineConfig grandFatherPipeline = configHelper.addPipeline("granpa", "stage", svn.config(), "job"); DependencyMaterial parentDependencyMaterial = MaterialsMother.dependencyMaterial("granpa", "stage"); PipelineConfig upstreamPipeline = configHelper.addPipeline("upstream", "stage", git.config(), "job"); upstreamPipeline.addMaterialConfig(parentDependencyMaterial.config()); DependencyMaterial dependencyMaterial = MaterialsMother.dependencyMaterial("upstream", "stage"); pipelineConfigWithTwoMaterials.addMaterialConfig(dependencyMaterial.config()); pipelineConfigWithTwoMaterials.removeMaterialConfig(git.config()); Username username = new Username(new CaseInsensitiveString("user1")); //Schedule grandfather List<MaterialRevision> revisionsForGrandfather1 = new ArrayList<>(); addRevisionWith2Mods(revisionsForGrandfather1, svn); Pipeline grandFatherOne = dbHelper.checkinRevisionsToBuild(new ManualBuild(username), grandFatherPipeline, revisionsForGrandfather1); //Schedule upstream List<MaterialRevision> revisionsForUpstream1 = new ArrayList<>(); addRevisionWith2Mods(revisionsForUpstream1, git); dbHelper.addDependencyRevisionModification(revisionsForUpstream1, parentDependencyMaterial, grandFatherOne); Pipeline upstreamOne = dbHelper.checkinRevisionsToBuild(new ManualBuild(username), upstreamPipeline, revisionsForUpstream1); //Schedule downstream List<MaterialRevision> revisionsForPipeline1 = new ArrayList<>(); addRevisionWith2Mods(revisionsForPipeline1, hg); dbHelper.addDependencyRevisionModification(revisionsForPipeline1, dependencyMaterial, upstreamOne); Pipeline pipelineOne = dbHelper.checkinRevisionsToBuild(new ManualBuild(username), pipelineConfigWithTwoMaterials, revisionsForPipeline1); HttpLocalizedOperationResult result = new HttpLocalizedOperationResult(); List<MaterialRevision> actual = changesetService.revisionsBetween(CaseInsensitiveString.str(pipelineConfigWithTwoMaterials.name()), pipelineOne.getCounter(), pipelineOne.getCounter(), username, result, true, false); List<MaterialRevision> expectedRevisions = groupByMaterial(revisionsForGrandfather1, revisionsForUpstream1, revisionsForPipeline1); assertMaterialRevisions(expectedRevisions, actual); assertThat(result.isSuccessful(), is(true)); } @Test public void shouldFilterOutMaterialRevisionsThatTheUserIsNotAuthorizedToView() throws Exception { configHelper.turnOnSecurity(); configHelper.addAdmins("Yogi"); Username otherUser = new Username(new CaseInsensitiveString("otherUser")); Username user = new Username(new CaseInsensitiveString("user")); SvnMaterial svn = MaterialsMother.svnMaterial("http://svn"); PipelineConfig grandFatherPipeline = configHelper.addPipelineWithGroup("unauthorizedGroup", "granpa", new MaterialConfigs(svn.config()), "stage", "job"); configHelper.setViewPermissionForGroup("unauthorizedGroup", CaseInsensitiveString.str(otherUser.getUsername())); DependencyMaterial parentDependencyMaterial = MaterialsMother.dependencyMaterial("granpa", "stage"); PipelineConfig upstreamPipeline = configHelper.addPipeline("upstream", "stage", new MaterialConfigs(git.config(), parentDependencyMaterial.config()), "job"); DependencyMaterial dependencyMaterial = MaterialsMother.dependencyMaterial("upstream", "stage"); PipelineConfig downstream = configHelper.addPipeline("downstream", "stage", dependencyMaterial.config(), "job"); //Schedule grandfather List<MaterialRevision> revisionsForGrandfather1 = new ArrayList<>(); addRevisionWith2Mods(revisionsForGrandfather1, svn); Pipeline grandFatherOne = dbHelper.checkinRevisionsToBuild(new ManualBuild(user), grandFatherPipeline, revisionsForGrandfather1); //Schedule upstream List<MaterialRevision> revisionsForUpstream1 = new ArrayList<>(); addRevisionWith2Mods(revisionsForUpstream1, git); dbHelper.addDependencyRevisionModification(revisionsForUpstream1, parentDependencyMaterial, grandFatherOne); Pipeline upstreamOne = dbHelper.checkinRevisionsToBuild(new ManualBuild(user), upstreamPipeline, revisionsForUpstream1); //Schedule downstream List<MaterialRevision> revisionsForDownstream = new ArrayList<>(); dbHelper.addDependencyRevisionModification(revisionsForDownstream, dependencyMaterial, upstreamOne); Pipeline pipelineDownstream = dbHelper.checkinRevisionsToBuild(new ManualBuild(user), downstream, revisionsForDownstream); HttpLocalizedOperationResult result = new HttpLocalizedOperationResult(); List<MaterialRevision> actual = changesetService.revisionsBetween(pipelineDownstream.getName(), pipelineDownstream.getCounter(), pipelineDownstream.getCounter(), user, result, true, false); List<MaterialRevision> expectedRevisions = groupByMaterial(revisionsForUpstream1, revisionsForDownstream); assertMaterialRevisions(expectedRevisions, actual); assertThat(result.isSuccessful(), is(true)); } @Test public void shouldNotFilterOutMaterialRevisionsAtThePointInTheDependencyIfMingleConfigDoesNotMatchWithParent() throws Exception { Username user = new Username(new CaseInsensitiveString("user")); SvnMaterial svn = MaterialsMother.svnMaterial("http://svn"); PipelineConfig grandFatherPipeline = configHelper.addPipelineWithGroup("unauthorizedGroup", "granpa", new MaterialConfigs(svn.config()), new MingleConfig("https://granpa-mingle", "go"), "stage", "job"); configHelper.setViewPermissionForGroup("unauthorizedGroup", CaseInsensitiveString.str(user.getUsername())); DependencyMaterial parentDependencyMaterial = MaterialsMother.dependencyMaterial("granpa", "stage"); PipelineConfig upstreamPipeline = configHelper.addPipeline("upstream", "stage", new MaterialConfigs(git.config(), parentDependencyMaterial.config()), "job"); DependencyMaterial dependencyMaterial = MaterialsMother.dependencyMaterial("upstream", "stage"); PipelineConfig downstream = configHelper.addPipeline("downstream", "stage", dependencyMaterial.config(), new MingleConfig("https://downstream-mingle", "go"), "job"); //Schedule grandfather List<MaterialRevision> revisionsForGrandfather1 = new ArrayList<>(); addRevisionWith2Mods(revisionsForGrandfather1, svn); Pipeline grandFatherOne = dbHelper.checkinRevisionsToBuild(new ManualBuild(user), grandFatherPipeline, revisionsForGrandfather1); //Schedule upstream List<MaterialRevision> revisionsForUpstream1 = new ArrayList<>(); addRevisionWith2Mods(revisionsForUpstream1, git); dbHelper.addDependencyRevisionModification(revisionsForUpstream1, parentDependencyMaterial, grandFatherOne); Pipeline upstreamOne = dbHelper.checkinRevisionsToBuild(new ManualBuild(user), upstreamPipeline, revisionsForUpstream1); //Schedule downstream List<MaterialRevision> revisionsForDownstream = new ArrayList<>(); dbHelper.addDependencyRevisionModification(revisionsForDownstream, dependencyMaterial, upstreamOne); Pipeline pipelineDownstream = dbHelper.checkinRevisionsToBuild(new ManualBuild(user), downstream, revisionsForDownstream); HttpLocalizedOperationResult result = new HttpLocalizedOperationResult(); List<MaterialRevision> actual = changesetService.revisionsBetween(pipelineDownstream.getName(), pipelineDownstream.getCounter(), pipelineDownstream.getCounter(), user, result, true, false); List<MaterialRevision> expectedRevisions = groupByMaterial(revisionsForGrandfather1, revisionsForUpstream1, revisionsForDownstream); assertMaterialRevisions(expectedRevisions, actual); assertThat(result.isSuccessful(), is(true)); } @Test public void shouldFilterOutMaterialRevisionsAtThePointInTheDependencyIfTrackingToolDoesNotMatchWithParent() throws Exception { Username user = new Username(new CaseInsensitiveString("user")); SvnMaterial svn = MaterialsMother.svnMaterial("http://svn"); PipelineConfig grandFatherPipeline = configHelper.addPipelineWithGroup("unauthorizedGroup", "granpa", new MaterialConfigs(svn.config()), new TrackingTool("http://jira/${ID}", "some-regex"), "stage", "job"); configHelper.setViewPermissionForGroup("unauthorizedGroup", CaseInsensitiveString.str(user.getUsername())); DependencyMaterial parentDependencyMaterial = MaterialsMother.dependencyMaterial("granpa", "stage"); PipelineConfig upstreamPipeline = configHelper.addPipeline("upstream", "stage", new MaterialConfigs(git.config(), parentDependencyMaterial.config()), "job"); DependencyMaterial dependencyMaterial = MaterialsMother.dependencyMaterial("upstream", "stage"); PipelineConfig downstream = configHelper.addPipeline("downstream", "stage", dependencyMaterial.config(), new TrackingTool("http://mingle/${ID}", "another-regex"), "job"); //Schedule grandfather List<MaterialRevision> revisionsForGrandfather1 = new ArrayList<>(); addRevisionWith2Mods(revisionsForGrandfather1, svn); Pipeline grandFatherOne = dbHelper.checkinRevisionsToBuild(new ManualBuild(user), grandFatherPipeline, revisionsForGrandfather1); //Schedule upstream List<MaterialRevision> revisionsForUpstream1 = new ArrayList<>(); addRevisionWith2Mods(revisionsForUpstream1, git); dbHelper.addDependencyRevisionModification(revisionsForUpstream1, parentDependencyMaterial, grandFatherOne); Pipeline upstreamOne = dbHelper.checkinRevisionsToBuild(new ManualBuild(user), upstreamPipeline, revisionsForUpstream1); //Schedule downstream List<MaterialRevision> revisionsForDownstream = new ArrayList<>(); dbHelper.addDependencyRevisionModification(revisionsForDownstream, dependencyMaterial, upstreamOne); Pipeline pipelineDownstream = dbHelper.checkinRevisionsToBuild(new ManualBuild(user), downstream, revisionsForDownstream); HttpLocalizedOperationResult result = new HttpLocalizedOperationResult(); List<MaterialRevision> actual = changesetService.revisionsBetween(pipelineDownstream.getName(), pipelineDownstream.getCounter(), pipelineDownstream.getCounter(), user, result, true, false); List<MaterialRevision> expectedRevisions = groupByMaterial(revisionsForUpstream1, revisionsForDownstream); assertMaterialRevisions(expectedRevisions, actual); assertThat(result.isSuccessful(), is(true)); } @Test public void shouldNotConsider2MingleConfigsAsDifferentIfTheMqlCriteriaAreDifferent() { PipelineConfig pipelineConfig = PipelineConfigMother.createPipelineConfig("pipeline", "stage", "job"); pipelineConfig.setMingleConfig(new MingleConfig("https://foo.com", "go", "status > In Dev")); assertThat(changesetService.mingleConfigMatches(pipelineConfig, new MingleConfig("https://foo.com", "go", "status > Something Else")), is(true)); } @Test public void shouldReturn_SCMMods_AcrossParentStageFailures() { PipelineConfig upstreamPipeline = configHelper.addPipeline("upstream", "stage", git.config(), "job"); DependencyMaterial dependencyMaterial = MaterialsMother.dependencyMaterial("upstream", "stage"); pipelineConfigWithTwoMaterials.addMaterialConfig(dependencyMaterial.config()); pipelineConfigWithTwoMaterials.removeMaterialConfig(git.config()); Username username = new Username(new CaseInsensitiveString("user1")); //Schedule first of upstream List<MaterialRevision> revisionsForUpstream1 = new ArrayList<>(); addRevisionWith2Mods(revisionsForUpstream1, git); Pipeline upstreamOne = dbHelper.checkinRevisionsToBuild(new ManualBuild(username), upstreamPipeline, revisionsForUpstream1); //Schedule downstream List<MaterialRevision> revisionsForDownstream1 = new ArrayList<>(); addRevisionWith2Mods(revisionsForDownstream1, hg); dbHelper.addDependencyRevisionModification(revisionsForDownstream1, dependencyMaterial, upstreamOne); Pipeline downstreamOne = dbHelper.checkinRevisionsToBuild(new ManualBuild(username), pipelineConfigWithTwoMaterials, revisionsForDownstream1); //Schedule second upstream List<MaterialRevision> revisionsForUpstream2 = new ArrayList<>(); addRevisionWith2Mods(revisionsForUpstream2, git); Pipeline upstreamTwo = dbHelper.checkinRevisionsToBuild(new ManualBuild(username), upstreamPipeline, revisionsForUpstream2); //Schedule second downstream List<MaterialRevision> revisionsForDownstream2 = new ArrayList<>(); addRevisionWith2Mods(revisionsForDownstream2, hg); dbHelper.addDependencyRevisionModification(revisionsForDownstream2, dependencyMaterial, upstreamTwo); Pipeline downstreamTwo = dbHelper.checkinRevisionsToBuild(new ManualBuild(username), pipelineConfigWithTwoMaterials, revisionsForDownstream2); //Schedule multiple upstream, but no corresponding downstream, because upstream stage failed(may be?) List<MaterialRevision> revisionsForUpstream3 = new ArrayList<>(); addRevisionWith2Mods(revisionsForUpstream3, git); Pipeline upstreamThree = dbHelper.checkinRevisionsToBuild(new ManualBuild(username), upstreamPipeline, revisionsForUpstream3); List<MaterialRevision> revisionsForUpstream4 = new ArrayList<>(); addRevisionWith2Mods(revisionsForUpstream4, git); Pipeline upstreamFour = dbHelper.checkinRevisionsToBuild(new ManualBuild(username), upstreamPipeline, revisionsForUpstream4); //Schedule upstream again(upstream stage starts passing once again) List<MaterialRevision> revisionsForUpstream5 = new ArrayList<>(); addRevisionWith2Mods(revisionsForUpstream5, git); Pipeline upstreamFive = dbHelper.checkinRevisionsToBuild(new ManualBuild(username), upstreamPipeline, revisionsForUpstream5); //Schedule downstream for comparision List<MaterialRevision> revisionsForDownstream3 = new ArrayList<>(); addRevisionWith2Mods(revisionsForDownstream3, hg); dbHelper.addDependencyRevisionModification(revisionsForDownstream3, dependencyMaterial, upstreamFive); Pipeline downstreamThree = dbHelper.checkinRevisionsToBuild(new ManualBuild(username), pipelineConfigWithTwoMaterials, revisionsForDownstream3); HttpLocalizedOperationResult result = new HttpLocalizedOperationResult(); List<MaterialRevision> actual = changesetService.revisionsBetween(CaseInsensitiveString.str(pipelineConfigWithTwoMaterials.name()), downstreamOne.getCounter(), downstreamThree.getCounter(), username, result, true, false); List<MaterialRevision> expectedRevisions = groupByMaterial(revisionsForUpstream2, revisionsForUpstream3, revisionsForUpstream4, revisionsForUpstream5, revisionsForDownstream2, revisionsForDownstream3); assertMaterialRevisions(expectedRevisions, actual); assertThat(result.isSuccessful(), is(true)); } @Test public void shouldNotReturnAMaterialWhenNothingHasChangedInIt() { PipelineConfig upstreamPipeline = configHelper.addPipeline("upstream", "stage", git.config(), "job"); DependencyMaterial dependencyMaterial = MaterialsMother.dependencyMaterial("upstream", "stage"); pipelineConfigWithTwoMaterials.addMaterialConfig(dependencyMaterial.config()); pipelineConfigWithTwoMaterials.removeMaterialConfig(git.config()); Username username = new Username(new CaseInsensitiveString("user1")); //Schedule first of upstream List<MaterialRevision> revisionsForUpstream1 = new ArrayList<>(); addRevisionWith2Mods(revisionsForUpstream1, git); Pipeline upstreamOne = dbHelper.checkinRevisionsToBuild(new ManualBuild(username), upstreamPipeline, revisionsForUpstream1); //Schedule downstream List<MaterialRevision> revisionsForDownstream1 = new ArrayList<>(); addRevisionWith2Mods(revisionsForDownstream1, hg); dbHelper.addDependencyRevisionModification(revisionsForDownstream1, dependencyMaterial, upstreamOne); Pipeline downstreamOne = dbHelper.checkinRevisionsToBuild(new ManualBuild(username), pipelineConfigWithTwoMaterials, revisionsForDownstream1); //Schedule second upstream List<MaterialRevision> revisionsForUpstream2 = new ArrayList<>(); addRevisionWith2Mods(revisionsForUpstream2, git); List<MaterialRevision> expectedGitRevision = revisionsForUpstream2; Pipeline upstreamTwo = dbHelper.checkinRevisionsToBuild(new ManualBuild(username), upstreamPipeline, revisionsForUpstream2); //Schedule second downstream List<MaterialRevision> up2Rev = dbHelper.addDependencyRevisionModification(revisionsForDownstream1, dependencyMaterial, upstreamTwo); Pipeline downstreamTwo = dbHelper.checkinRevisionsToBuild(new ManualBuild(username), pipelineConfigWithTwoMaterials, revisionsForDownstream1);//Using the same hg revision. HttpLocalizedOperationResult result = new HttpLocalizedOperationResult(); List<MaterialRevision> actual = changesetService.revisionsBetween(CaseInsensitiveString.str(pipelineConfigWithTwoMaterials.name()), downstreamOne.getCounter(), downstreamTwo.getCounter(), username, result, true, false); List<MaterialRevision> expectedRevisions = groupByMaterial(revisionsForUpstream2, up2Rev);//Should not contain the hg revision that has not changed assertMaterialRevisions(expectedRevisions, actual); assertThat(result.isSuccessful(), is(true)); } @Test public void shouldReturn_SCMMods_AcrossParentStageFailures_WithFailuresNextToFrom() { PipelineConfig upstreamPipeline = configHelper.addPipeline("upstream", "stage", git.config(), "job"); DependencyMaterial dependencyMaterial = MaterialsMother.dependencyMaterial("upstream", "stage"); pipelineConfigWithTwoMaterials.addMaterialConfig(dependencyMaterial.config()); pipelineConfigWithTwoMaterials.removeMaterialConfig(git.config()); Username username = new Username(new CaseInsensitiveString("user1")); //Schedule first of upstream List<MaterialRevision> revisionsForUpstream1 = new ArrayList<>(); addRevisionWith2Mods(revisionsForUpstream1, git); Pipeline upstreamOne = dbHelper.checkinRevisionsToBuild(new ManualBuild(username), upstreamPipeline, revisionsForUpstream1); //Schedule downstream List<MaterialRevision> revisionsForDownstream1 = new ArrayList<>(); addRevisionWith2Mods(revisionsForDownstream1, hg); dbHelper.addDependencyRevisionModification(revisionsForDownstream1, dependencyMaterial, upstreamOne); Pipeline downstreamOne = dbHelper.checkinRevisionsToBuild(new ManualBuild(username), pipelineConfigWithTwoMaterials, revisionsForDownstream1); //Schedule multiple upstream, but no corresponding downstream, because upstream stage failed(may be?) List<MaterialRevision> revisionsForUpstream2 = new ArrayList<>(); addRevisionWith2Mods(revisionsForUpstream2, git); Pipeline upstreamTwo = dbHelper.checkinRevisionsToBuild(new ManualBuild(username), upstreamPipeline, revisionsForUpstream2); List<MaterialRevision> revisionsForUpstream3 = new ArrayList<>(); addRevisionWith2Mods(revisionsForUpstream3, git); Pipeline upstreamThree = dbHelper.checkinRevisionsToBuild(new ManualBuild(username), upstreamPipeline, revisionsForUpstream3); //Schedule upstream again(upstream stage starts passing once again) List<MaterialRevision> revisionsForUpstream4 = new ArrayList<>(); addRevisionWith2Mods(revisionsForUpstream4, git); Pipeline upstreamFour = dbHelper.checkinRevisionsToBuild(new ManualBuild(username), upstreamPipeline, revisionsForUpstream4); //Schedule downstream for comparision List<MaterialRevision> revisionsForDownstream2 = new ArrayList<>(); addRevisionWith2Mods(revisionsForDownstream2, hg); dbHelper.addDependencyRevisionModification(revisionsForDownstream2, dependencyMaterial, upstreamFour); Pipeline downstreamTwo = dbHelper.checkinRevisionsToBuild(new ManualBuild(username), pipelineConfigWithTwoMaterials, revisionsForDownstream2); HttpLocalizedOperationResult result = new HttpLocalizedOperationResult(); List<MaterialRevision> actual = changesetService.revisionsBetween(CaseInsensitiveString.str(pipelineConfigWithTwoMaterials.name()), downstreamOne.getCounter(), downstreamTwo.getCounter(), username, result, true, false); List<MaterialRevision> expectedRevisions = groupByMaterial(revisionsForUpstream2, revisionsForUpstream3, revisionsForUpstream4, revisionsForDownstream2); assertMaterialRevisions(expectedRevisions, actual); assertThat(result.isSuccessful(), is(true)); actual = changesetService.revisionsBetween(CaseInsensitiveString.str(pipelineConfigWithTwoMaterials.name()), downstreamTwo.getCounter(), downstreamTwo.getCounter(), username, result, true, false);//same to and from assertMaterialRevisions(expectedRevisions, actual); assertThat(result.isSuccessful(), is(true)); } @Test public void shouldReturnModsForRangeOfInstancesOfAnUpstreamPipeline() { PipelineConfig upstreamPipeline = configHelper.addPipeline("upstream", "stage", git.config(), "job"); DependencyMaterial dependencyMaterial = MaterialsMother.dependencyMaterial("upstream", "stage"); pipelineConfigWithTwoMaterials.addMaterialConfig(dependencyMaterial.config()); pipelineConfigWithTwoMaterials.removeMaterialConfig(git.config()); Username username = new Username(new CaseInsensitiveString("user1")); //Schedule first of upstream List<MaterialRevision> revisionsForUpstream1 = new ArrayList<>(); addRevisionWith2Mods(revisionsForUpstream1, git); Pipeline upstreamOne = dbHelper.checkinRevisionsToBuild(new ManualBuild(username), upstreamPipeline, revisionsForUpstream1); //Schedule downstream List<MaterialRevision> revisionsForDownstream1 = new ArrayList<>(); addRevisionWith2Mods(revisionsForDownstream1, hg); dbHelper.addDependencyRevisionModification(revisionsForDownstream1, dependencyMaterial, upstreamOne); Pipeline downstreamOne = dbHelper.checkinRevisionsToBuild(new ManualBuild(username), pipelineConfigWithTwoMaterials, revisionsForDownstream1); //Schedule multiple upstreams List<MaterialRevision> revisionsForUpstream2 = new ArrayList<>(); addRevisionWith2Mods(revisionsForUpstream2, git); Pipeline upstreamTwo = dbHelper.checkinRevisionsToBuild(new ManualBuild(username), upstreamPipeline, revisionsForUpstream2); List<MaterialRevision> revisionsForUpstream3 = new ArrayList<>(); addRevisionWith2Mods(revisionsForUpstream3, git); Pipeline upstreamThree = dbHelper.checkinRevisionsToBuild(new ManualBuild(username), upstreamPipeline, revisionsForUpstream3); List<MaterialRevision> revisionsForUpstream4 = new ArrayList<>(); addRevisionWith2Mods(revisionsForUpstream4, git); Pipeline upstreamFour = dbHelper.checkinRevisionsToBuild(new ManualBuild(username), upstreamPipeline, revisionsForUpstream4); //Schedule downstream List<MaterialRevision> revisionsForDownstream2 = new ArrayList<>(); addRevisionWith2Mods(revisionsForDownstream2, hg); dbHelper.addDependencyRevisionModification(revisionsForDownstream2, dependencyMaterial, upstreamFour, upstreamThree, upstreamTwo); Pipeline downstreamTwo = dbHelper.checkinRevisionsToBuild(new ManualBuild(username), pipelineConfigWithTwoMaterials, revisionsForDownstream2); HttpLocalizedOperationResult result = new HttpLocalizedOperationResult(); List<MaterialRevision> actual = changesetService.revisionsBetween(CaseInsensitiveString.str(pipelineConfigWithTwoMaterials.name()), downstreamTwo.getCounter(), downstreamTwo.getCounter(), username, result, true, false); List<MaterialRevision> expectedRevisions = groupByMaterial(revisionsForUpstream2, revisionsForUpstream3, revisionsForUpstream4, revisionsForDownstream2); assertMaterialRevisions(expectedRevisions, actual); assertThat(result.isSuccessful(), is(true)); } @Test public void testShouldGroupMaterialsBasedOnFingerprint() { SvnMaterial first = new SvnMaterial("url", "user1", "password", false); Modification mod1 = new Modification("user1", "comment", "email", new Date(), "revision"); mod1.setMaterialInstance(new SvnMaterialInstance("url", "user1", "flyweight1", false)); Modification mod2 = new Modification("user1", "comment", "email", new Date(), "revision"); mod2.setMaterialInstance(new SvnMaterialInstance("url", "user1", "flyweight1", false)); Map<Material, Modifications> map = changesetService.groupModsByMaterial(Arrays.asList(mod1, mod2)); assertThat(map.size(), is(1)); assertThat(map.get(first), is(new Modifications(mod1, mod2))); } private void assertMaterialRevisions(List<MaterialRevision> expected, List<MaterialRevision> actual) { assertThat(actual.size(), is(expected.size())); for (MaterialRevision expectedRevision : expected) { MaterialRevision actualRevision = revisionFor(expectedRevision.getMaterial().getFingerprint(), actual); assertEquals(expectedRevision.getMaterial().createMaterialInstance(), actualRevision.getMaterial().createMaterialInstance()); assertEquals(expectedRevision.getModifications(), actualRevision.getModifications()); } } private MaterialRevision revisionFor(String fingerprint, List<MaterialRevision> in) { for(MaterialRevision revision: in) { if(revision.getMaterial().getFingerprint().equals(fingerprint)) { return revision; } } return null; } private List<MaterialRevision> groupByMaterial(List<MaterialRevision>... toBeGrouped) { MaterialRevisions grouped = new MaterialRevisions(); for (List<MaterialRevision> materialRevisions : toBeGrouped) { for (MaterialRevision materialRevision : materialRevisions) { MaterialRevision revision = grouped.findRevisionFor(materialRevision.getMaterial()); if (revision == null) { revision = new MaterialRevision(materialRevision.getMaterial(), new ArrayList<>()); grouped.addRevision(revision); } revision.addModifications(materialRevision.getModifications()); Collections.sort(revision.getModifications(), PersistentObject.ORDER_DESCENDING_ID); } } return grouped.getRevisions(); } private void addRevisionWith2Mods(List<MaterialRevision> revisions, final ScmMaterial material) { String revision1 = nextInt(); String revision2 = nextInt(); revisions.add(dbHelper.addRevisionsWithModifications(material, checkinWithComment(revision2, "comment" + revision2, new Date(), "file" + revision2), checkinWithComment(revision1, "comment" + revision1, new Date(), "file" + revision1))); } private String nextInt() { return String.valueOf(++counter); } private void validateFailsForNonNaturalCounter(int fromCounter, int toCounter) { HttpLocalizedOperationResult result; result = new HttpLocalizedOperationResult(); changesetService.revisionsBetween("foo", fromCounter, toCounter, new Username(new CaseInsensitiveString("loser")), result, true, false); assertThat(result.isSuccessful(), is(false)); assertThat(result.message(localizer), is("Pipeline counters should be positive.")); assertThat(result.httpCode(), is(400)); } private List<String> stringRevisions(List<MaterialRevision> revisionList) { List<String> stringRevisions = new ArrayList<>(); for (MaterialRevision revision : revisionList) { for (Modification mod : revision.getModifications()) { stringRevisions.add(mod.getRevision()); } } return stringRevisions; } }