/*
* 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.Date;
import java.util.HashMap;
import com.thoughtworks.go.config.CaseInsensitiveString;
import com.thoughtworks.go.config.JobConfig;
import com.thoughtworks.go.config.JobConfigs;
import com.thoughtworks.go.config.PipelineConfig;
import com.thoughtworks.go.config.materials.dependency.DependencyMaterialConfig;
import com.thoughtworks.go.config.materials.mercurial.HgMaterial;
import com.thoughtworks.go.config.materials.mercurial.HgMaterialConfig;
import com.thoughtworks.go.domain.JobInstance;
import com.thoughtworks.go.domain.MaterialRevision;
import com.thoughtworks.go.domain.MaterialRevisions;
import com.thoughtworks.go.domain.Pipeline;
import com.thoughtworks.go.domain.Stage;
import com.thoughtworks.go.domain.activity.JobStatusCache;
import com.thoughtworks.go.domain.activity.StageStatusCache;
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.helper.*;
import com.thoughtworks.go.server.cache.GoCache;
import com.thoughtworks.go.server.dao.JobInstanceDao;
import com.thoughtworks.go.server.dao.PipelineDao;
import com.thoughtworks.go.server.dao.PipelineSqlMapDao;
import com.thoughtworks.go.server.dao.StageDao;
import com.thoughtworks.go.server.domain.JobStatusListener;
import com.thoughtworks.go.server.domain.PipelineConfigDependencyGraph;
import com.thoughtworks.go.server.domain.PipelineTimeline;
import com.thoughtworks.go.server.domain.StageStatusListener;
import com.thoughtworks.go.server.domain.Username;
import com.thoughtworks.go.server.functional.helpers.MaterialRevisionBuilder;
import com.thoughtworks.go.server.materials.DependencyMaterialUpdateNotifier;
import com.thoughtworks.go.server.messaging.JobResultTopic;
import com.thoughtworks.go.server.messaging.StageStatusTopic;
import com.thoughtworks.go.server.persistence.MaterialRepository;
import com.thoughtworks.go.server.transaction.TestTransactionSynchronizationManager;
import com.thoughtworks.go.server.transaction.TestTransactionTemplate;
import com.thoughtworks.go.server.transaction.TransactionSynchronizationManager;
import com.thoughtworks.go.server.transaction.TransactionTemplate;
import com.thoughtworks.go.serverhealth.ServerHealthService;
import com.thoughtworks.go.serverhealth.ServerHealthStates;
import com.thoughtworks.go.util.SystemEnvironment;
import com.thoughtworks.go.plugin.infra.PluginManager;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mockito;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import static com.thoughtworks.go.helper.GoConfigMother.createPipelineConfigWithMaterialConfig;
import static com.thoughtworks.go.helper.ModificationsMother.changedDependencyMaterialRevision;
import static com.thoughtworks.go.helper.ModificationsMother.createHgMaterialWithMultipleRevisions;
import static com.thoughtworks.go.helper.ModificationsMother.createSvnMaterialWithMultipleRevisions;
import static com.thoughtworks.go.helper.ModificationsMother.dependencyMaterialRevision;
import static com.thoughtworks.go.helper.ModificationsMother.oneModifiedFile;
import static com.thoughtworks.go.domain.config.CaseInsensitiveStringMother.str;
import static org.hamcrest.core.Is.is;
import static org.junit.Assert.assertThat;
import static org.junit.Assert.assertTrue;
import static org.mockito.Matchers.any;
import static org.mockito.Matchers.anyLong;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
@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 PipelineServiceTriangleDependencyTest {
private PipelineTimeline pipelineTimeline;
private PipelineService service;
private PipelineSqlMapDao pipelineDao;
private MaterialRepository materialRepository;
private Modification first;
private Modification third;
private Modification second;
@Autowired private TransactionTemplate actualTransactionTemplate;
@Autowired private TransactionSynchronizationManager transactionSynchronizationManager;
@Autowired private GoConfigService goConfigService;
@Autowired private GoCache goCache;
@Autowired private SystemEnvironment systemEnvironment;
@Autowired private PluginManager pluginManager;
@Autowired private MaterialConfigConverter materialConfigConverter;
@Autowired private DependencyMaterialUpdateNotifier notifier;
@Before public void setUp() throws Exception {
pipelineTimeline = mock(PipelineTimeline.class);
pipelineDao = mock(PipelineSqlMapDao.class);
materialRepository = mock(MaterialRepository.class);
TestTransactionSynchronizationManager mockTransactionSynchronizationManager = new TestTransactionSynchronizationManager();
TransactionTemplate mockTransactionTemplate = new TestTransactionTemplate(mockTransactionSynchronizationManager);
service = new PipelineService(pipelineDao, mock(StageService.class), mock(PipelineLockService.class), pipelineTimeline, materialRepository, mockTransactionTemplate, systemEnvironment, null,
materialConfigConverter);
first = oneModifiedFile("1");
third = oneModifiedFile("3");
second = oneModifiedFile("2");
first.setId(1);
third.setId(3);
second.setId(2);
notifier.disableUpdates();
}
public void teardown() {
notifier.enableUpdates();
}
@Test
public void shouldCopyMissingRevisionsForSameMaterialThatsUsedMoreThanOnce() throws Exception {
PipelineConfig pipelineConfig = PipelineConfigMother.pipelineConfig("last");
pipelineConfig.materialConfigs().clear();
HgMaterialConfig onDirOne = MaterialConfigsMother.hgMaterialConfig("google.com", "dirOne");
HgMaterialConfig onDirTwo = MaterialConfigsMother.hgMaterialConfig("google.com", "dirTwo");
pipelineConfig.addMaterialConfig(onDirOne);
pipelineConfig.addMaterialConfig(onDirTwo);
HashMap<Material, String> materialToCommit = new HashMap<>();
materialToCommit.put(new MaterialConfigConverter().toMaterial(onDirOne), "abc");
materialToCommit.put(new MaterialConfigConverter().toMaterial(onDirTwo), "abc");
MaterialRevisions revs = ModificationsMother.getMaterialRevisions(materialToCommit);
MaterialRevisions finalRevisions = service.getRevisionsBasedOnDependencies(new PipelineConfigDependencyGraph(pipelineConfig), revs);
assertThat(finalRevisions.getRevisions(), is(revs.getRevisions()));
}
@Test
public void shouldTellPipelineMaterialModificationsToUpdateItselfOnSave() throws Exception {
Pipeline pipeline = PipelineMother.pipeline("cruise");
when(pipelineDao.save(pipeline)).thenReturn(pipeline);
when(pipelineTimeline.pipelineBefore(anyLong())).thenReturn(9L);
when(pipelineTimeline.pipelineAfter(pipeline.getId())).thenReturn(-1L);
when(materialRepository.findMaterialRevisionsForPipeline(9L)).thenReturn(MaterialRevisions.EMPTY);
service.save(pipeline);
Mockito.verify(pipelineTimeline).update();
}
@Test
public void shouldNotNotifyStatusListenersWhenTransactionRollsback() throws Exception {
StageStatusListener stageStatusListener = mock(StageStatusListener.class);
JobStatusListener jobStatusListener = mock(JobStatusListener.class);
Pipeline pipeline = stubPipelineSaveForStatusListener(stageStatusListener, jobStatusListener);
Mockito.doThrow(new RuntimeException()).when(pipelineTimeline).update();
try {
service.save(pipeline);
} catch (RuntimeException e) {
//ignore
}
verify(stageStatusListener, never()).stageStatusChanged(any(Stage.class));
verify(jobStatusListener, never()).jobStatusChanged(any(JobInstance.class));
}
@Test
public void shouldNotifyStageStatusListenersOnlyWhenTransactionCommits() throws Exception {
StageStatusListener stageStatusListener = mock(StageStatusListener.class);
JobStatusListener jobStatusListener = mock(JobStatusListener.class);
Pipeline pipeline = stubPipelineSaveForStatusListener(stageStatusListener, jobStatusListener);
service.save(pipeline);
verify(stageStatusListener).stageStatusChanged(any(Stage.class));
verify(jobStatusListener).jobStatusChanged(any(JobInstance.class));
}
private Pipeline stubPipelineSaveForStatusListener(StageStatusListener stageStatusListener, JobStatusListener jobStatusListener) {
StageDao stageDao = mock(StageDao.class);
ServerHealthService serverHealthService = mock(ServerHealthService.class);
when(serverHealthService.getAllLogs()).thenReturn(new ServerHealthStates());
JobInstanceService jobInstanceService = new JobInstanceService(mock(JobInstanceDao.class), mock(PropertiesService.class), mock(JobResultTopic.class), mock(JobStatusCache.class),
actualTransactionTemplate, transactionSynchronizationManager, null, null, goConfigService, null, pluginManager, serverHealthService, jobStatusListener);
StageService stageService = new StageService(stageDao, jobInstanceService, mock(StageStatusTopic.class), mock(StageStatusCache.class), mock(SecurityService.class), mock(PipelineDao.class),
mock(ChangesetService.class), mock(GoConfigService.class), actualTransactionTemplate, transactionSynchronizationManager,
goCache);
Stage savedStage = StageMother.passedStageInstance("stage", "job", "pipeline-name");
when(stageDao.save(any(Pipeline.class), any(Stage.class))).thenReturn(savedStage);
stageService.addStageStatusListener(stageStatusListener);
service = new PipelineService(pipelineDao, stageService, mock(PipelineLockService.class), pipelineTimeline, materialRepository, actualTransactionTemplate,systemEnvironment, null, materialConfigConverter);
Pipeline pipeline = PipelineMother.pipeline("cruise", savedStage);
when(pipelineDao.save(pipeline)).thenReturn(pipeline);
when(pipelineTimeline.pipelineBefore(anyLong())).thenReturn(9L);
when(pipelineTimeline.pipelineAfter(pipeline.getId())).thenReturn(-1L);
when(materialRepository.findMaterialRevisionsForPipeline(9L)).thenReturn(MaterialRevisions.EMPTY);
return pipeline;
}
@Test
public void shouldUpdateTheToAndFromRevisionOfThePipelineAfterThePipelineBeingSaved() throws Exception {
MaterialRevisions scheduleTime = createHgMaterialWithMultipleRevisions(1L, first);
scheduleTime.addAll(createSvnMaterialWithMultipleRevisions(2, first));
MaterialRevisions next = createHgMaterialWithMultipleRevisions(1L, third, second, first);
next.addAll(createSvnMaterialWithMultipleRevisions(2, third, second, first));
MaterialRevisions expected = createHgMaterialWithMultipleRevisions(1L, third, second);
expected.addAll(createSvnMaterialWithMultipleRevisions(2L, third, second));
Pipeline pipeline = pipeline(scheduleTime, jobs());
Pipeline savedPipeline = pipeline(scheduleTime, jobs());
when(pipelineTimeline.pipelineAfter(pipeline.getId())).thenReturn(11L);
when(pipelineTimeline.pipelineBefore(pipeline.getId())).thenReturn(-1L);
when(materialRepository.findMaterialRevisionsForPipeline(11L)).thenReturn(next);
when(pipelineDao.save(pipeline)).thenReturn(savedPipeline);
service.save(pipeline);
}
@Test
public void shouldGetTheRevisionsFromTheUpStreamPipelineThatUsesTheSameMaterial() throws Exception {
MaterialRevisions expected = new MaterialRevisions();
MaterialRevision up1Revision = dependencyMaterialRevision("up1", 1, "label", "stage", 1, new Date());
up1Revision.markAsChanged();
expected.addRevision(up1Revision);
expected.addAll(createHgMaterialWithMultipleRevisions(1L, first));
expected.addAll(createSvnMaterialWithMultipleRevisions(2L, third));
MaterialRevisions actual = new MaterialRevisions();
actual.addRevision(up1Revision);
actual.addAll(createHgMaterialWithMultipleRevisions(1L, third));
actual.addAll(createSvnMaterialWithMultipleRevisions(2L, third));
PipelineConfig current = createPipelineConfigWithMaterialConfig("current", new DependencyMaterialConfig(new CaseInsensitiveString("up1"), new CaseInsensitiveString("first")),
actual.getMaterials().get(0).config());
PipelineConfig up1 = createPipelineConfigWithMaterialConfig("up1", expected.getMaterials().get(1).config(), expected.getMaterials().get(2).config());
Pipeline pipeline = PipelineMother.passedPipelineInstance("up1", "stage", "job");
pipeline.setId(10);
when(pipelineDao.findPipelineByNameAndCounter("up1", 1)).thenReturn(pipeline);
when(materialRepository.findMaterialRevisionsForPipeline(10)).thenReturn(expected);
PipelineConfigDependencyGraph dependencyGraph = new PipelineConfigDependencyGraph(current, new PipelineConfigDependencyGraph(up1));
assertThat(service.getRevisionsBasedOnDependencies(dependencyGraph, actual), is(expected));
}
@Test
public void shouldGetTheRevisionsFromTheUpStreamPipelineFor2SameMaterial() throws Exception {
MaterialRevision up1Revision = dependencyMaterialRevision("up1", 1, "label", "stage", 1, new Date());
up1Revision.markAsChanged();
MaterialRevisions expected = new MaterialRevisions();
expected.addRevision(up1Revision);
expected.addAll(createHgMaterialWithMultipleRevisions(1L, first));
expected.addAll(createSvnMaterialWithMultipleRevisions(2L, first));
MaterialRevisions actual = new MaterialRevisions();
actual.addRevision(up1Revision);
actual.addAll(createHgMaterialWithMultipleRevisions(1L, third));
actual.addAll(createSvnMaterialWithMultipleRevisions(2L, third));
PipelineConfig current = createPipelineConfigWithMaterialConfig("current", new DependencyMaterialConfig(new CaseInsensitiveString("up1"), new CaseInsensitiveString("first")),
MaterialConfigsMother.hgMaterialConfig(), MaterialConfigsMother.svnMaterialConfig());
PipelineConfig up1 = createPipelineConfigWithMaterialConfig("up1", MaterialConfigsMother.hgMaterialConfig(), MaterialConfigsMother.svnMaterialConfig());
Pipeline pipeline = PipelineMother.passedPipelineInstance("up1", "stage", "job");
pipeline.setId(10);
when(pipelineDao.findPipelineByNameAndCounter("up1", 1)).thenReturn(pipeline);
when(materialRepository.findMaterialRevisionsForPipeline(10)).thenReturn(expected);
PipelineConfigDependencyGraph dependencyGraph = new PipelineConfigDependencyGraph(current, new PipelineConfigDependencyGraph(up1));
assertThat(service.getRevisionsBasedOnDependencies(dependencyGraph, actual), is(expected));
}
@Test
public void shouldChooseTheRevisionFromThirdWhenSecondIsNotModified() throws Exception {
// Third* <- Second
// | /
// | /
// Last
//
// * indicates changed
Date date = new Date();
MaterialRevisionBuilder builder = new MaterialRevisionBuilder(pipelineDao, materialRepository);
PipelineConfigDependencyGraph graph = builder.depInstance("last", 1, date, builder.depInstance("third", 3, date, builder.depInstance("second", 2, date, builder.svnInstance("1", date))),
builder.depInstance("second", 4, date, builder.svnInstance("2", date))).getGraph();
MaterialRevisions actual = new MaterialRevisions();
actual.addRevision(builder.lookingAtDep("third", 3, date).markAsChanged().revision());
actual.addRevision(builder.lookingAtDep("second", 4, date).revision());
MaterialRevisions expected = new MaterialRevisions();
expected.addRevision(builder.depInstance("third", 3, date).getRevision());
expected.addRevision(builder.depInstance("second", 2, date).getRevision());
MaterialRevisions finalRevisions = service.getRevisionsBasedOnDependencies(graph, actual);
assertThat(finalRevisions, is(expected));
for (int i = 0; i < expected.numberOfRevisions(); i++) {
assertTrue(finalRevisions.getMaterialRevision(i) == actual.getMaterialRevision(i));
}
}
@Test
public void shouldChooseTheRevisionFromSecondWhenThirdIsNotModified() throws Exception {
// Third <- Second*
// | /
// | /
// Last
//
// * indicates changed
Date date = new Date();
MaterialRevisionBuilder builder = new MaterialRevisionBuilder(pipelineDao, materialRepository);
PipelineConfigDependencyGraph graph = builder.depInstance("last", 1, date, builder.depInstance("third", 3, date,
builder.depInstance("second", 2, date, builder.svnInstance("1", date))),
builder.depInstance("second", 4, date, builder.svnInstance("2", date))).getGraph();
MaterialRevisions actual = new MaterialRevisions();
actual.addRevision(builder.lookingAtDep("third", 3, date).revision());
actual.addRevision(builder.lookingAtDep("second", 4, date).markAsChanged().revision());
MaterialRevisions expected = new MaterialRevisions();
expected.addRevision(builder.depInstance("third", 3, date).getRevision());
expected.addRevision(builder.depInstance("second", 4, date).getRevision());
MaterialRevisions finalRevisions = service.getRevisionsBasedOnDependencies(graph, actual);
assertThat(finalRevisions, is(expected));
for (int i = 0; i < expected.numberOfRevisions(); i++) {
assertTrue(finalRevisions.getMaterialRevision(i) == actual.getMaterialRevision(i));
}
}
@Test
public void shouldChooseTheRevisionFromSecondWhenThirdIsNotModifiedInspiteOfSecondBeingFirstMaterialInConfig() throws Exception {
// Third <- Second*
// | /
// | /
// Last
//
// * indicates changed
Date date = new Date();
MaterialRevisionBuilder builder = new MaterialRevisionBuilder(pipelineDao, materialRepository);
PipelineConfigDependencyGraph graph = builder.depInstance("last", 1, date, builder.depInstance("second", 4, date,
builder.svnInstance("2", date)), builder.depInstance("third", 3, date,
builder.depInstance("second", 2, date, builder.svnInstance("1", date)))).getGraph();
MaterialRevisions actual = new MaterialRevisions();
actual.addRevision(builder.lookingAtDep("second", 4, date).markAsChanged().revision());
actual.addRevision(builder.lookingAtDep("third", 3, date).revision());
MaterialRevisions expected = new MaterialRevisions();
expected.addRevision(builder.depInstance("second", 4, date).getRevision());
expected.addRevision(builder.depInstance("third", 3, date).getRevision());
MaterialRevisions finalRevisions = service.getRevisionsBasedOnDependencies(graph, actual);
assertThat(finalRevisions, is(expected));
for (int i = 0; i < expected.numberOfRevisions(); i++) {
assertTrue(finalRevisions.getMaterialRevision(i) == actual.getMaterialRevision(i));
}
}
@Test
public void shouldChooseTheRevisionFromThirdWhenBothThirdAndSecondAreModified() throws Exception {
// Third* <- Second*
// | /
// | /
// Last
//
// * indicates changed
Date date = new Date();
MaterialRevisionBuilder builder = new MaterialRevisionBuilder(pipelineDao, materialRepository);
PipelineConfigDependencyGraph graph = builder.depInstance("last", 1, date, builder.depInstance("third", 3, date, builder.depInstance("second", 2, date, builder.svnInstance("1", date))),
builder.depInstance("second", 4, date, builder.svnInstance("2", date))).getGraph();
MaterialRevisions actual = new MaterialRevisions();
actual.addRevision(builder.lookingAtDep("third", 3, date).markAsChanged().revision());
actual.addRevision(builder.lookingAtDep("second", 4, date).markAsChanged().revision());
MaterialRevisions expected = new MaterialRevisions();
expected.addRevision(builder.depInstance("third", 3, date).getRevision());
expected.addRevision(builder.depInstance("second", 2, date).getRevision());
MaterialRevisions finalRevisions = service.getRevisionsBasedOnDependencies(graph, actual);
assertThat(finalRevisions, is(expected));
for (int i = 0; i < expected.numberOfRevisions(); i++) {
assertTrue(finalRevisions.getMaterialRevision(i) == actual.getMaterialRevision(i));
}
}
@Test
public void shouldChooseTheRevisionFromThirdWhenSecondComesBeforeThirdInConfiguration() throws Exception {
// Third* <- Second*
// | /
// | /
// Last
//
// * indicates changed
Date date = new Date();
MaterialRevisionBuilder builder = new MaterialRevisionBuilder(pipelineDao, materialRepository);
PipelineConfigDependencyGraph graph = builder.depInstance("last", 1, date, builder.depInstance("second", 4, date,
builder.svnInstance("2", date)), builder.depInstance("third", 3, date,
builder.depInstance("second", 2, date, builder.svnInstance("1", date)))).getGraph();
MaterialRevisions actual = new MaterialRevisions();
actual.addRevision(builder.lookingAtDep("second", 4, date).markAsChanged().revision());
actual.addRevision(builder.lookingAtDep("third", 3, date).markAsChanged().revision());
MaterialRevisions expected = new MaterialRevisions();
expected.addRevision(builder.depInstance("second", 2, date).getRevision());
expected.addRevision(builder.depInstance("third", 3, date).getRevision());
MaterialRevisions finalRevisions = service.getRevisionsBasedOnDependencies(graph, actual);
assertThat(finalRevisions, is(expected));
for (int i = 0; i < expected.numberOfRevisions(); i++) {
assertTrue(finalRevisions.getMaterialRevision(i) == actual.getMaterialRevision(i));
}
}
@Test
public void shouldChooseTheRevisionFromSecondInAComplexSituation() throws Exception {
// hg -> First git
// | \ |
// | Third <- Second*
// | | /
// | | /
// +------> Last
//
// * indicates changed
Date date = new Date();
MaterialRevisionBuilder builder = new MaterialRevisionBuilder(pipelineDao, materialRepository);
PipelineConfigDependencyGraph graph = builder.depInstance("last", 1, date, builder.hgInstance("rev2", date),
builder.depInstance("second", 4, date, builder.svnInstance("2", date)),
builder.depInstance("third", 3, date, builder.depInstance("first", 1, date, builder.hgInstance("rev1", date)),
builder.depInstance("second", 2, date, builder.svnInstance("1", date)))).getGraph();
MaterialRevisions actual = new MaterialRevisions();
actual.addRevision(builder.lookingAtHg("rev2", date).markAsChanged().revision());
actual.addRevision(builder.lookingAtDep("second", 4, date).markAsChanged().revision());
actual.addRevision(builder.lookingAtDep("third", 3, date).markAsChanged().revision());
MaterialRevisions expected = new MaterialRevisions();
expected.addRevision(builder.hgInstance("rev1", date).getRevision());
expected.addRevision(builder.depInstance("second", 2, date).getRevision());
expected.addRevision(builder.depInstance("third", 3, date).getRevision());
MaterialRevisions finalRevisions = service.getRevisionsBasedOnDependencies(graph, actual);
assertThat(finalRevisions, is(expected));
for (int i = 0; i < expected.numberOfRevisions(); i++) {
assertTrue(finalRevisions.getMaterialRevision(i) == actual.getMaterialRevision(i));
}
}
@Test
public void shouldIgnoreUpstreamPipelineWhenThereIsNothingInCommon() throws Exception {
MaterialRevision up1Revision = dependencyMaterialRevision("up1", 1, "label", "stage", 1, new Date());
up1Revision.markAsChanged();
MaterialRevision earlierUp0Revision = dependencyMaterialRevision("up0", 1, "label", "stage", 1, new Date());
MaterialRevision laterUp0Revision = dependencyMaterialRevision("up0", 2, "label", "stage", 1, new Date());
laterUp0Revision.markAsChanged();
MaterialRevisions expected = new MaterialRevisions();
expected.addRevision(earlierUp0Revision);
expected.addRevision(up1Revision);
expected.addAll(createSvnMaterialWithMultipleRevisions(2L, third));
MaterialRevisions allUp1Revisions = new MaterialRevisions();
allUp1Revisions.addRevision(earlierUp0Revision);
MaterialRevisions allUp0Revisions = new MaterialRevisions();
allUp0Revisions.addAll(createHgMaterialWithMultipleRevisions(3L, first));
MaterialRevisions actual = new MaterialRevisions();
actual.addRevision(laterUp0Revision);
actual.addRevision(up1Revision);
actual.addAll(createSvnMaterialWithMultipleRevisions(2L, third));
DependencyMaterialConfig sameUpstream = new DependencyMaterialConfig(new CaseInsensitiveString("up0"), new CaseInsensitiveString("stage"));
PipelineConfig current = createPipelineConfigWithMaterialConfig("current", sameUpstream,
new DependencyMaterialConfig(new CaseInsensitiveString("up1"), new CaseInsensitiveString("stage")),
MaterialConfigsMother.svnMaterialConfig());
PipelineConfig up1 = createPipelineConfigWithMaterialConfig("up1", sameUpstream);
PipelineConfig up0 = createPipelineConfigWithMaterialConfig("up0", MaterialConfigsMother.hgMaterialConfig());
Pipeline up1Pipeline = PipelineMother.passedPipelineInstance("up1", "stage", "job");
up1Pipeline.setId(10);
Pipeline up0Pipeline = PipelineMother.passedPipelineInstance("up0", "stage", "job");
up0Pipeline.setId(5);
when(pipelineDao.findPipelineByNameAndCounter("up1", 1)).thenReturn(up1Pipeline);
when(materialRepository.findMaterialRevisionsForPipeline(10)).thenReturn(allUp1Revisions);
when(pipelineDao.findPipelineByNameAndCounter("up0", 1)).thenReturn(up0Pipeline);
when(materialRepository.findMaterialRevisionsForPipeline(5)).thenReturn(allUp0Revisions);
when(pipelineDao.findPipelineByNameAndCounter("up0", 2)).thenReturn(up0Pipeline);
when(materialRepository.findMaterialRevisionsForPipeline(5)).thenReturn(allUp0Revisions);
PipelineConfigDependencyGraph dependencyGraph = new PipelineConfigDependencyGraph(current, new PipelineConfigDependencyGraph(up1, new PipelineConfigDependencyGraph(up0)),
new PipelineConfigDependencyGraph(up0));
assertThat(service.getRevisionsBasedOnDependencies(dependencyGraph, actual), is(expected));
}
@Test
public void shouldGetTheRevisionsForDependencyMaterialFromUpStreamPipeline() throws Exception {
Date modifiedTime = new Date();
MaterialRevisions expected = new MaterialRevisions();
expected.addRevision(dependencyMaterialRevision("up1", 1, "label", "stage", 1, modifiedTime));
expected.addRevision(dependencyMaterialRevision("common", 3, "label", "first", 1, modifiedTime));
MaterialRevisions actual = new MaterialRevisions();
actual.addRevision(changedDependencyMaterialRevision("up1", 1, "label", "stage", 1, modifiedTime));
actual.addRevision(dependencyMaterialRevision("common", 4, "label", "first", 1, modifiedTime));
PipelineConfig current = createPipelineConfigWithMaterialConfig("current", new DependencyMaterialConfig(new CaseInsensitiveString("common"), new CaseInsensitiveString("first")),
new DependencyMaterialConfig(new CaseInsensitiveString("up1"), new CaseInsensitiveString("first")));
PipelineConfig up1 = createPipelineConfigWithMaterialConfig("up1", new DependencyMaterialConfig(new CaseInsensitiveString("common"), new CaseInsensitiveString("first")));
PipelineConfig common = createPipelineConfigWithMaterialConfig("common", MaterialConfigsMother.hgMaterialConfig());
Pipeline pipeline = PipelineMother.passedPipelineInstance("up1", "stage", "job");
pipeline.setId(10);
when(pipelineDao.findPipelineByNameAndCounter("up1", 1)).thenReturn(pipeline);
MaterialRevisions upStreamPipelinesRevisions = new MaterialRevisions();
upStreamPipelinesRevisions.addRevision(dependencyMaterialRevision("common", 3, "label", "first", 1, modifiedTime));
when(materialRepository.findMaterialRevisionsForPipeline(10)).thenReturn(upStreamPipelinesRevisions);
PipelineConfigDependencyGraph dependencyGraph = new PipelineConfigDependencyGraph(current, new PipelineConfigDependencyGraph(up1, new PipelineConfigDependencyGraph(common)));
MaterialRevisions finalRevisions = service.getRevisionsBasedOnDependencies(dependencyGraph, actual);
assertThat(finalRevisions, is(expected));
for (int i = 0; i < expected.numberOfRevisions(); i++) {
assertTrue(finalRevisions.getMaterialRevision(i) == actual.getMaterialRevision(i));
}
}
@Test
public void shouldGetTheRevisionsForDependencyMaterial_WithSharedParentInMiddleOfTheTree() throws Exception {
Date modifiedTime = new Date();
MaterialRevisions expected = new MaterialRevisions();
expected.addRevision(dependencyMaterialRevision("up1", 1, "label", "stage", 1, modifiedTime));
expected.addRevision(dependencyMaterialRevision("common", 3, "label", "first", 1, modifiedTime));
MaterialRevisions actual = new MaterialRevisions();
actual.addRevision(changedDependencyMaterialRevision("up1", 1, "label", "stage", 1, modifiedTime));
actual.addRevision(changedDependencyMaterialRevision("common", 4, "label", "first", 1, modifiedTime));
PipelineConfig current = createPipelineConfigWithMaterialConfig("current", new DependencyMaterialConfig(new CaseInsensitiveString("common"), new CaseInsensitiveString("first")),
new DependencyMaterialConfig(new CaseInsensitiveString("up1"), new CaseInsensitiveString("first")));
PipelineConfig up1 = createPipelineConfigWithMaterialConfig("up1", new DependencyMaterialConfig(new CaseInsensitiveString("common"), new CaseInsensitiveString("first")));
PipelineConfig common = createPipelineConfigWithMaterialConfig("common", new DependencyMaterialConfig(new CaseInsensitiveString("commonsParent"), new CaseInsensitiveString("first")));
PipelineConfig commonsParent = createPipelineConfigWithMaterialConfig("commonsParent", MaterialConfigsMother.hgMaterialConfig());
Pipeline pipeline = PipelineMother.passedPipelineInstance("up1", "stage", "job");
pipeline.setId(10);
when(pipelineDao.findPipelineByNameAndCounter("up1", 1)).thenReturn(pipeline);
MaterialRevisions upStreamPipelinesRevisions = new MaterialRevisions();
upStreamPipelinesRevisions.addRevision(dependencyMaterialRevision("common", 3, "label", "first", 1, modifiedTime));
when(materialRepository.findMaterialRevisionsForPipeline(10)).thenReturn(upStreamPipelinesRevisions);
Pipeline commonPipeline = PipelineMother.passedPipelineInstance("common", "first", "job");
commonPipeline.setId(5);
when(pipelineDao.findPipelineByNameAndCounter("common", 3)).thenReturn(commonPipeline);
MaterialRevisions commonPipelinesRevisions = new MaterialRevisions();
upStreamPipelinesRevisions.addRevision(dependencyMaterialRevision("commonsParent", 2, "label-2", "first", 1, modifiedTime));
when(materialRepository.findMaterialRevisionsForPipeline(5)).thenReturn(commonPipelinesRevisions);
PipelineConfigDependencyGraph dependencyGraph = new PipelineConfigDependencyGraph(current,
new PipelineConfigDependencyGraph(up1, new PipelineConfigDependencyGraph(common, new PipelineConfigDependencyGraph(commonsParent))),
new PipelineConfigDependencyGraph(common, new PipelineConfigDependencyGraph(commonsParent)));
MaterialRevisions finalRevisions = service.getRevisionsBasedOnDependencies(dependencyGraph, actual);
assertThat(finalRevisions, is(expected));
for (int i = 0; i < expected.numberOfRevisions(); i++) {
assertTrue(finalRevisions.getMaterialRevision(i) == actual.getMaterialRevision(i));
}
}
@Test
public void shouldGetTheRevisionsFromTheUpStreamPipelineBasedOnCurrentConfiguration() throws Exception {
MaterialRevisions expectedIfPegged = createHgMaterialWithMultipleRevisions(1L, first);
MaterialRevision up1Revision = dependencyMaterialRevision("up1", 1, "label", "stage", 1, new Date());
up1Revision.markAsChanged();
expectedIfPegged.addRevision(up1Revision);
MaterialRevisions actual = createHgMaterialWithMultipleRevisions(1L, third);
actual.addRevision(up1Revision);
PipelineConfig current = createPipelineConfigWithMaterialConfig("current", actual.getMaterials().get(0).config(),
new DependencyMaterialConfig(new CaseInsensitiveString("up1"), new CaseInsensitiveString("first")));
PipelineConfig up1 = createPipelineConfigWithMaterialConfig("up1");//The pipeline does not have the material anymore
when(pipelineDao.findBuildCauseOfPipelineByNameAndCounter("up1", 1)).thenReturn(BuildCause.createManualForced(expectedIfPegged, new Username(str("loser"))));
PipelineConfigDependencyGraph dependencyGraph = new PipelineConfigDependencyGraph(current, new PipelineConfigDependencyGraph(up1));
assertThat(service.getRevisionsBasedOnDependencies(dependencyGraph, actual), is(actual));
}
@Test
public void shouldGetTheRevisionsFromTheNearestUpStreamPipeline() throws Exception {
MaterialRevisions uppestRevision = createHgMaterialWithMultipleRevisions(1L, first);
MaterialRevisions secondHgRevision = createHgMaterialWithMultipleRevisions(1L, second);
((HgMaterial) secondHgRevision.getMaterialRevision(0).getMaterial()).setFolder("mother");
MaterialRevisions upRevision = new MaterialRevisions(secondHgRevision.getMaterialRevision(0), dependencyMaterialRevision("up0", 2, "label", "stage", 1, new Date()));
MaterialRevisions actual = createHgMaterialWithMultipleRevisions(1L, third);
((HgMaterial) actual.getMaterials().get(0)).setFolder("mother");
MaterialRevision up1Modification = dependencyMaterialRevision("up1", 1, "label", "stage", 1, new Date());
up1Modification.markAsChanged();
actual.addRevision(up1Modification);
PipelineConfig current = createPipelineConfigWithMaterialConfig("current", actual.getMaterials().get(0).config(),
new DependencyMaterialConfig(new CaseInsensitiveString("up1"), new CaseInsensitiveString("stage")));
PipelineConfig up1 = createPipelineConfigWithMaterialConfig("up1", upRevision.getMaterials().get(0).config(), upRevision.getMaterials().get(1).config());
PipelineConfig up0 = createPipelineConfigWithMaterialConfig("up0", MaterialConfigsMother.hgMaterialConfig());
Pipeline pipeline = PipelineMother.passedPipelineInstance("up1", "stage", "job");
pipeline.setId(10);
Pipeline uppestPipeline = PipelineMother.passedPipelineInstance("up0", "stage", "job");
uppestPipeline.setId(5);
when(pipelineDao.findPipelineByNameAndCounter("up1", 1)).thenReturn(pipeline);
when(materialRepository.findMaterialRevisionsForPipeline(10)).thenReturn(upRevision);
when(pipelineDao.findPipelineByNameAndCounter("up0", 2)).thenReturn(uppestPipeline);
when(materialRepository.findMaterialRevisionsForPipeline(5)).thenReturn(uppestRevision);
PipelineConfigDependencyGraph dependencyGraph = new PipelineConfigDependencyGraph(current, new PipelineConfigDependencyGraph(up1, new PipelineConfigDependencyGraph(up0)));
secondHgRevision.addRevision(up1Modification);
assertThat(service.getRevisionsBasedOnDependencies(dependencyGraph, actual), is(secondHgRevision));
}
@Test
public void shouldNotGetTheRevisionsFromUpStreamPipelineIfTheDependencyMaterialHasNotChanged() throws Exception {
MaterialRevisions expected = createHgMaterialWithMultipleRevisions(1L, first);
MaterialRevision up1Revision = dependencyMaterialRevision("up1", 1, "label", "stage", 1, new Date());
expected.addRevision(up1Revision);
MaterialRevisions actual = createHgMaterialWithMultipleRevisions(1L, third);
actual.addRevision(up1Revision);
up1Revision.markAsNotChanged();
PipelineConfig current = createPipelineConfigWithMaterialConfig("current", actual.getMaterials().get(0).config(),
new DependencyMaterialConfig(new CaseInsensitiveString("up1"), new CaseInsensitiveString("first")));
PipelineConfig up1 = createPipelineConfigWithMaterialConfig("up1", expected.getMaterials().get(0).config());
when(pipelineDao.findBuildCauseOfPipelineByNameAndCounter("up1", 1)).thenReturn(BuildCause.createManualForced(expected, new Username(str("loser"))));
PipelineConfigDependencyGraph dependencyGraph = new PipelineConfigDependencyGraph(current, new PipelineConfigDependencyGraph(up1));
assertThat(service.getRevisionsBasedOnDependencies(dependencyGraph, actual), is(actual));
}
@Test
public void shouldGetTheRevisionsFromTheUpStreamPipelineThatUsesTheSameMaterialEvenIfItIsNotADirectMaterial() throws Exception {
MaterialRevisions uppestRevision = createHgMaterialWithMultipleRevisions(1L, first);
MaterialRevisions upRevision = new MaterialRevisions(dependencyMaterialRevision("up0", 2, "label", "stage", 1, new Date()));
MaterialRevisions expected = new MaterialRevisions(uppestRevision.getMaterialRevision(0));
MaterialRevision up1Revision = dependencyMaterialRevision("up1", 1, "label", "stage", 1, new Date());
up1Revision.markAsChanged();
expected.addRevision(up1Revision);
MaterialRevisions actual = createHgMaterialWithMultipleRevisions(1L, third);
actual.addRevision(up1Revision);
PipelineConfig current = createPipelineConfigWithMaterialConfig("current", actual.getMaterials().get(0).config(),
new DependencyMaterialConfig(new CaseInsensitiveString("up1"), new CaseInsensitiveString("stage")));
PipelineConfig up1 = createPipelineConfigWithMaterialConfig("up1", upRevision.getMaterials().get(0).config());
PipelineConfig up0 = createPipelineConfigWithMaterialConfig("up0", uppestRevision.getMaterials().get(0).config());
Pipeline pipeline = PipelineMother.passedPipelineInstance("up1", "stage", "job");
pipeline.setId(10);
Pipeline uppestPipeline = PipelineMother.passedPipelineInstance("up0", "stage", "job");
uppestPipeline.setId(5);
when(pipelineDao.findPipelineByNameAndCounter("up1", 1)).thenReturn(pipeline);
when(materialRepository.findMaterialRevisionsForPipeline(10)).thenReturn(upRevision);
when(pipelineDao.findPipelineByNameAndCounter("up0", 2)).thenReturn(uppestPipeline);
when(materialRepository.findMaterialRevisionsForPipeline(5)).thenReturn(uppestRevision);
PipelineConfigDependencyGraph dependencyGraph = new PipelineConfigDependencyGraph(current, new PipelineConfigDependencyGraph(up1, new PipelineConfigDependencyGraph(up0)));
assertThat(service.getRevisionsBasedOnDependencies(dependencyGraph, actual), is(expected));
}
@Test
public void shouldReturnTheOrderedListOfStageIdentifiers() throws Exception {
//TODO: does it? while we trust it, may be its a good idea to validate --shilpa & jj
}
private JobConfigs jobs() {
JobConfigs configs = new JobConfigs();
configs.add(new JobConfig("job"));
return configs;
}
private Pipeline pipeline(MaterialRevisions scheduleTime, JobConfigs configs) {
Pipeline pipeline = PipelineMother.schedule(PipelineConfigMother.pipelineConfig("mummy", scheduleTime.getMaterialRevision(0).getMaterial().config(), configs),
BuildCause.createWithModifications(scheduleTime, "me"));
pipeline.setId(10);
return pipeline;
}
}