/* * 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.presentation.pipelinehistory; import java.util.ArrayList; import java.util.Date; import java.util.HashMap; import com.thoughtworks.go.config.CaseInsensitiveString; import com.thoughtworks.go.config.materials.MaterialConfigs; import com.thoughtworks.go.config.materials.mercurial.HgMaterial; import com.thoughtworks.go.config.materials.mercurial.HgMaterialConfig; import com.thoughtworks.go.config.materials.svn.SvnMaterial; import com.thoughtworks.go.domain.JobResult; import com.thoughtworks.go.domain.JobState; import com.thoughtworks.go.domain.MaterialRevision; import com.thoughtworks.go.domain.MaterialRevisions; import com.thoughtworks.go.domain.StageIdentifier; 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.MaterialConfigsMother; import com.thoughtworks.go.helper.MaterialsMother; import com.thoughtworks.go.helper.ModificationsMother; import com.thoughtworks.go.helper.PipelineHistoryMother; import org.joda.time.DateTime; import org.junit.Test; import static com.thoughtworks.go.domain.buildcause.BuildCause.createWithEmptyModifications; import static com.thoughtworks.go.helper.MaterialsMother.hgMaterial; import static com.thoughtworks.go.helper.MaterialsMother.svnMaterial; import static com.thoughtworks.go.helper.PipelineHistoryMother.job; import static com.thoughtworks.go.helper.PipelineHistoryMother.stagePerJob; import static org.hamcrest.Matchers.is; import static org.hamcrest.core.IsNull.nullValue; import static org.junit.Assert.assertThat; import static org.junit.Assert.fail; public class PipelineInstanceModelTest { private static final Modification HG_MATERIAL_MODIFICATION = new Modification("user", "Comment", "email", new Date(), "a087402bd2a7828a130c1bdf43f2d9ef8f48fd46"); @Test public void shouldUnderstandActiveStage() { StageInstanceModels stages = new StageInstanceModels(); stages.addStage("unit1", JobHistory.withJob("test", JobState.Completed, JobResult.Passed, new Date())); JobHistory history = new JobHistory(); history.add(new JobHistoryItem("test-1", JobState.Completed, JobResult.Failed, new Date())); history.add(new JobHistoryItem("test-2", JobState.Building, JobResult.Unknown, new Date())); StageInstanceModel activeStage = new StageInstanceModel("unit2", "1", history); stages.add(activeStage); stages.addFutureStage("unit3", false); PipelineInstanceModel model = PipelineInstanceModel.createPipeline("pipeline", -1, "label", BuildCause.createManualForced(), stages); assertThat(model.activeStage(), is(activeStage)); } @Test public void shouldReturnNullWhenNoActiveStage() { StageInstanceModels stages = new StageInstanceModels(); stages.addStage("unit1", JobHistory.withJob("test", JobState.Completed, JobResult.Passed, new Date())); JobHistory history = new JobHistory(); history.add(new JobHistoryItem("test-1", JobState.Completed, JobResult.Failed, new Date())); history.add(new JobHistoryItem("test-2", JobState.Completed, JobResult.Passed, new Date())); stages.add(new StageInstanceModel("unit2", "1", history)); stages.addFutureStage("unit3", false); PipelineInstanceModel model = PipelineInstanceModel.createPipeline("pipeline", -1, "label", BuildCause.createManualForced(), stages); assertThat(model.activeStage(), is(nullValue())); } @Test public void shouldUnderstandPipelineStatusMessage() throws Exception { MaterialRevisions revisions = ModificationsMother.modifyOneFile(MaterialsMother.hgMaterials("url"), "revision"); StageInstanceModels stages = new StageInstanceModels(); stages.addStage("unit1", JobHistory.withJob("test", JobState.Completed, JobResult.Passed, new Date())); stages.addFutureStage("unit2", false); PipelineInstanceModel model = PipelineInstanceModel.createPipeline("pipeline", -1, "label", BuildCause.createWithModifications(revisions, ""), stages); assertThat(model.getPipelineStatusMessage(), is("Passed: unit1")); } @Test public void shouldGetCurrentRevisionForMaterial() { MaterialRevisions revisions = new MaterialRevisions(); HgMaterial material = MaterialsMother.hgMaterial(); revisions.addRevision(material, HG_MATERIAL_MODIFICATION); PipelineInstanceModel model = PipelineInstanceModel.createPipeline("pipeline", -1, "label", BuildCause.createWithModifications(revisions, ""), new StageInstanceModels()); assertThat(model.getCurrentRevision(material.config()).getRevision(), is("a087402bd2a7828a130c1bdf43f2d9ef8f48fd46")); } @Test public void shouldGetCurrentMaterialRevisionForMaterial() { MaterialRevisions revisions = new MaterialRevisions(); HgMaterial material = MaterialsMother.hgMaterial(); revisions.addRevision(material, HG_MATERIAL_MODIFICATION); PipelineInstanceModel model = PipelineInstanceModel.createPipeline("pipeline", -1, "label", BuildCause.createWithModifications(revisions, ""), new StageInstanceModels()); assertThat(model.findCurrentMaterialRevisionForUI(material.config()), is(revisions.getMaterialRevision(0))); } @Test public void shouldFallbackToPipelineFingerpringWhenGettingCurrentMaterialRevisionForMaterialIsNull() { MaterialRevisions revisions = new MaterialRevisions(); HgMaterial material = MaterialsMother.hgMaterial(); HgMaterial materialWithDifferentDest = MaterialsMother.hgMaterial(); materialWithDifferentDest.setFolder("otherFolder"); revisions.addRevision(material, HG_MATERIAL_MODIFICATION); PipelineInstanceModel model = PipelineInstanceModel.createPipeline("pipeline", -1, "label", BuildCause.createWithModifications(revisions, ""), new StageInstanceModels()); assertThat(model.findCurrentMaterialRevisionForUI(materialWithDifferentDest.config()), is(revisions.getMaterialRevision(0))); } @Test public void shouldGetCurrentRevisionForMaterialByName() { MaterialRevisions revisions = new MaterialRevisions(); HgMaterial material = MaterialsMother.hgMaterial(); SvnMaterial svnMaterial = MaterialsMother.svnMaterial(); material.setName(new CaseInsensitiveString("hg_material")); revisions.addRevision(svnMaterial, new Modification(new Date(), "1024", "MOCK_LABEL-12", null)); revisions.addRevision(material, HG_MATERIAL_MODIFICATION); BuildCause buildCause = BuildCause.createWithModifications(revisions, ""); PipelineInstanceModel model = PipelineInstanceModel.createPipeline("pipeline", -1, "label", buildCause, new StageInstanceModels()); assertThat(model.getCurrentRevision("hg_material").getRevision(), is("a087402bd2a7828a130c1bdf43f2d9ef8f48fd46")); } @Test public void shouldGetLatestMaterialRevisionForMaterial() { HgMaterial material = MaterialsMother.hgMaterial(); assertThat(setUpModificationForHgMaterial().getLatestMaterialRevision(material.config()), is(new MaterialRevision(material, HG_MATERIAL_MODIFICATION))); } @Test public void shouldGetLatestRevisionForMaterial() { HgMaterialConfig hgMaterialConfig = MaterialConfigsMother.hgMaterialConfig(); assertThat(setUpModificationForHgMaterial().getLatestRevision(hgMaterialConfig).getRevision(), is("a087402bd2a7828a130c1bdf43f2d9ef8f48fd46")); } @Test public void shouldGetLatestRevisionForMaterialWithNoModifications() { assertThat(hgMaterialWithNoModifications().getLatestRevision(MaterialConfigsMother.hgMaterialConfig()).getRevision(), is("No historical data")); } @Test public void shouldGetCurrentRevisionForMaterialName() { HgMaterial material = MaterialsMother.hgMaterial(); material.setName(new CaseInsensitiveString("foo")); assertThat(setUpModificationFor(material).getCurrentRevision(CaseInsensitiveString.str(material.getName())).getRevision(), is("a087402bd2a7828a130c1bdf43f2d9ef8f48fd46")); } @Test public void shouldThrowExceptionWhenCurrentRevisionForUnknownMaterialNameRequested() { HgMaterial material = MaterialsMother.hgMaterial(); material.setName(new CaseInsensitiveString("foo")); try { assertThat(setUpModificationFor(material).getCurrentRevision("blah").getRevision(), is("a087402bd2a7828a130c1bdf43f2d9ef8f48fd46")); fail("should have raised an exeption for unknown material name"); } catch (Exception ignored) { } } private PipelineInstanceModel setUpModificationForHgMaterial() { MaterialRevisions revisions = new MaterialRevisions(); revisions.addRevision(MaterialsMother.hgMaterial(), HG_MATERIAL_MODIFICATION); PipelineInstanceModel model = PipelineInstanceModel.createPipeline("pipeline", -1, "label", null, new StageInstanceModels()); model.setLatestRevisions(revisions); return model; } private PipelineInstanceModel hgMaterialWithNoModifications() { MaterialRevisions revisions = new MaterialRevisions(); revisions.addRevision(MaterialsMother.hgMaterial(), new ArrayList<>()); PipelineInstanceModel model = PipelineInstanceModel.createPipeline("pipeline", -1, "label", null, new StageInstanceModels()); model.setLatestRevisions(revisions); return model; } private PipelineInstanceModel setUpModificationFor(HgMaterial material) { MaterialRevisions revisions = new MaterialRevisions(); revisions.addRevision(material, HG_MATERIAL_MODIFICATION); return PipelineInstanceModel.createPipeline("pipeline", -1, "label", BuildCause.createWithModifications(revisions, ""), new StageInstanceModels()); } @Test public void shouldKnowIfLatestRevisionIsReal() throws Exception { assertThat(setUpModificationForHgMaterial().hasModificationsFor(MaterialConfigsMother.hgMaterialConfig()), is(true)); } @Test public void shouldKnowApproverAsApproverForTheFirstStage() { MaterialRevisions revisions = new MaterialRevisions(); StageInstanceModels models = new StageInstanceModels(); StageInstanceModel firstStage = new StageInstanceModel("dev", "1", new JobHistory()); firstStage.setApprovedBy("some_user"); models.add(firstStage); PipelineInstanceModel model = PipelineInstanceModel.createPipeline("pipeline", -1, "label", BuildCause.createWithModifications(revisions, ""), models); assertThat(model.getApprovedBy(), is("some_user")); assertThat(model.getApprovedByForDisplay(), is("Triggered by some_user")); } @Test public void shouldUnderstandIfReal() { assertThat(PipelineInstanceModel.createEmptyModel().hasHistoricalData(), is(true)); assertThat(PipelineInstanceModel.createEmptyPipelineInstanceModel("pipeline", createWithEmptyModifications(), new StageInstanceModels()).hasHistoricalData(), is(false)); } //Pipeline: Red -> Green -> Has_Not_Run_Yet @Test public void shouldBeSucessfulOnAForceContinuedPass_Red_AND_Green_AND_Has_Not_Run_Yet() { Date occuredFirst = new Date(2008, 12, 13); Date occuredSecond = new Date(2008, 12, 14); StageInstanceModels stageInstanceModels = stagePerJob("stage", job(JobResult.Failed, occuredFirst), job(JobResult.Passed, occuredSecond)); stageInstanceModels.add(new NullStageHistoryItem("stage-3", false)); PipelineInstanceModel instanceModel = PipelineInstanceModel.createPipeline("pipeline", -1, "label", createWithEmptyModifications(), stageInstanceModels); assertThat(instanceModel.isLatestStageUnsuccessful(), is(false)); assertThat(instanceModel.isLatestStageSuccessful(), is(true)); assertThat(instanceModel.isRunning(), is(true)); } //Pipeline: Red(Rerun after second stage passed i.e. latest stage) -> Green -> Has_Not_Run_Yet @Test public void shouldReturnStatusOfAfailedRerunAndIncompleteStage() { Date occuredFirst = new Date(2008, 12, 13); Date occuredSecond = new Date(2008, 12, 14); StageInstanceModels stageInstanceModels = stagePerJob("stage", job(JobResult.Failed, occuredSecond), job(JobResult.Passed, occuredFirst)); stageInstanceModels.add(new NullStageHistoryItem("stage-3", false)); PipelineInstanceModel instanceModel = PipelineInstanceModel.createPipeline("pipeline", -1, "label", createWithEmptyModifications(), stageInstanceModels); assertThat(instanceModel.isLatestStageUnsuccessful(), is(true)); assertThat(instanceModel.isLatestStageSuccessful(), is(false)); assertThat(instanceModel.isRunning(), is(true)); } @Test public void shouldReturnStatusOfAFailedRerun() { Date occuredFirst = new Date(2008, 12, 13); Date occuredSecond = new Date(2008, 12, 14); StageInstanceModels stageInstanceModels = stagePerJob("stage", job(JobResult.Failed, occuredSecond), job(JobResult.Passed, occuredFirst)); PipelineInstanceModel instanceModel = PipelineInstanceModel.createPipeline("pipeline", -1, "label", createWithEmptyModifications(), stageInstanceModels); assertThat(instanceModel.isLatestStageUnsuccessful(), is(true)); assertThat(instanceModel.isLatestStageSuccessful(), is(false)); assertThat(instanceModel.isRunning(), is(false)); } @Test public void shouldReturnStatusOfAPassedForceThrough() { Date occuredFirst = new Date(2008, 12, 13); Date occuredSecond = new Date(2008, 12, 14); StageInstanceModels stageInstanceModels = stagePerJob("stage", job(JobResult.Failed, occuredFirst), job(JobResult.Passed, occuredSecond)); PipelineInstanceModel instanceModel = PipelineInstanceModel.createPipeline("pipeline", -1, "label", createWithEmptyModifications(), stageInstanceModels); assertThat(instanceModel.isLatestStageUnsuccessful(), is(false)); assertThat(instanceModel.isLatestStageSuccessful(), is(true)); assertThat(instanceModel.isRunning(), is(false)); } @Test public void shouldReturnPipelineStatusAsPassedWhenAllTheStagesPass() { Date occuredFirst = new Date(2008, 12, 13); Date occuredSecond = new Date(2008, 12, 14); StageInstanceModels stageInstanceModels = stagePerJob("stage", job(JobResult.Passed, occuredSecond), job(JobResult.Passed, occuredFirst)); PipelineInstanceModel instanceModel = PipelineInstanceModel.createPipeline("pipeline", -1, "label", createWithEmptyModifications(), stageInstanceModels); assertThat(instanceModel.isLatestStageUnsuccessful(), is(false)); assertThat(instanceModel.isLatestStageSuccessful(), is(true)); assertThat(instanceModel.isRunning(), is(false)); } @Test public void shouldReturnTheLatestStageEvenWhenThereIsANullStage() { Date occuredFirst = new DateTime().minusDays(1).toDate(); Date occuredSecond = new DateTime().toDate(); StageInstanceModels stageInstanceModels = stagePerJob("stage", job(JobResult.Passed, occuredSecond), job(JobResult.Passed, occuredFirst)); NullStageHistoryItem stageHistoryItem = new NullStageHistoryItem("not_yet_run", false); stageInstanceModels.add(stageHistoryItem); PipelineInstanceModel instanceModel = PipelineInstanceModel.createPipeline("pipeline", -1, "label", createWithEmptyModifications(), stageInstanceModels); StageInstanceModel value = stageInstanceModels.get(0); assertThat(instanceModel.latestStage(), is(value)); } @Test public void shouldReturnIfAStageIsLatest() { Date occuredFirst = new DateTime().minusDays(1).toDate(); Date occuredSecond = new DateTime().toDate(); StageInstanceModels stageInstanceModels = stagePerJob("stage", job(JobResult.Passed, occuredSecond), job(JobResult.Passed, occuredFirst)); NullStageHistoryItem stageHistoryItem = new NullStageHistoryItem("not_yet_run", false); stageInstanceModels.add(stageHistoryItem); PipelineInstanceModel instanceModel = PipelineInstanceModel.createPipeline("pipeline", -1, "label", createWithEmptyModifications(), stageInstanceModels); assertThat(instanceModel.isLatestStage(stageInstanceModels.get(0)), is(true)); assertThat(instanceModel.isLatestStage(stageInstanceModels.get(1)), is(false)); } @Test public void shouldReturnIfAnyMaterialHasModifications() { final SvnMaterial svnMaterial = svnMaterial("http://svnurl"); final HgMaterial hgMaterial = hgMaterial("http://hgurl", "hgdir"); MaterialRevisions currentRevisions = ModificationsMother.getMaterialRevisions(new HashMap<Material, String>() {{ put(svnMaterial, "1"); put(hgMaterial, "a"); }}); MaterialRevisions latestRevisions = ModificationsMother.getMaterialRevisions(new HashMap<Material, String>() {{ put(svnMaterial, "1"); put(hgMaterial, "b"); }}); MaterialConfigs materialConfigs = new MaterialConfigs(); materialConfigs.add(svnMaterial.config()); materialConfigs.add(hgMaterial.config()); StageInstanceModels stages = new StageInstanceModels(); stages.addStage("unit1", JobHistory.withJob("test", JobState.Completed, JobResult.Passed, new Date())); stages.addFutureStage("unit2", false); PipelineInstanceModel model = PipelineInstanceModel.createPipeline("pipeline", -1, "label", BuildCause.createWithModifications(currentRevisions, ""), stages); model.setLatestRevisions(latestRevisions); model.setMaterialConfigs(materialConfigs); assertThat("svnMaterial hasNewRevisions", model.hasNewRevisions(svnMaterial.config()), is(false)); assertThat("hgMaterial hasNewRevisions", model.hasNewRevisions(hgMaterial.config()), is(true)); assertThat("all materials hasNewRevisions", model.hasNewRevisions(), is(true)); } @Test public void shouldUnderstandIfItHasNeverCheckedForRevisions() { StageInstanceModels stages = new StageInstanceModels(); stages.addStage("unit1", JobHistory.withJob("test", JobState.Completed, JobResult.Passed, new Date())); stages.addFutureStage("unit2", false); PipelineInstanceModel pim = PipelineInstanceModel.createPipeline("pipeline", -1, "label", BuildCause.createNeverRun(), stages); pim.setLatestRevisions(MaterialRevisions.EMPTY); assertThat("pim.hasNeverCheckedForRevisions()", pim.hasNeverCheckedForRevisions(), is(true)); } @Test public void shouldReturnTrueIfThePipelineHasStage() { PipelineInstanceModel pim = PipelineHistoryMother.pipelineHistoryItemWithOneStage("pipeline", "stage", new Date()); assertThat(pim.hasStage(pim.getStageHistory().first().getIdentifier()), is(true)); assertThat(pim.hasStage(new StageIdentifier("pipeline",1,"1", "stagex", "2")), is(false)); } @Test public void shouldSetAndGetComment() { PipelineInstanceModel pim = PipelineInstanceModel.createEmptyModel(); pim.setComment("test comment"); assertThat("PipelineInstanceModel.getComment()", pim.getComment(), is("test comment")); } }