/* * 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 com.thoughtworks.go.config.*; import com.thoughtworks.go.config.materials.MaterialConfigs; import com.thoughtworks.go.config.materials.svn.SvnMaterialConfig; import com.thoughtworks.go.domain.*; import com.thoughtworks.go.domain.buildcause.BuildCause; import com.thoughtworks.go.domain.materials.MaterialConfig; import com.thoughtworks.go.helper.*; import com.thoughtworks.go.i18n.LocalizedMessage; import com.thoughtworks.go.presentation.PipelineStatusModel; import com.thoughtworks.go.presentation.pipelinehistory.*; import com.thoughtworks.go.server.dao.PipelineDao; import com.thoughtworks.go.server.dao.StageDao; import com.thoughtworks.go.server.domain.JobDurationStrategy; import com.thoughtworks.go.server.domain.PipelineTimeline; import com.thoughtworks.go.server.domain.Username; import com.thoughtworks.go.server.domain.user.PipelineSelections; import com.thoughtworks.go.server.persistence.MaterialRepository; import com.thoughtworks.go.server.scheduling.TriggerMonitor; import com.thoughtworks.go.server.service.result.HttpLocalizedOperationResult; import com.thoughtworks.go.server.service.result.HttpOperationResult; import com.thoughtworks.go.server.service.result.ServerHealthStateOperationResult; import com.thoughtworks.go.server.service.support.toggle.FeatureToggleService; import com.thoughtworks.go.server.service.support.toggle.Toggles; import com.thoughtworks.go.server.util.Pagination; import com.thoughtworks.go.serverhealth.HealthStateScope; import com.thoughtworks.go.serverhealth.HealthStateType; import org.joda.time.DateTime; import org.junit.Before; import org.junit.Test; import org.mockito.Mock; import java.util.*; import static com.thoughtworks.go.presentation.pipelinehistory.PipelineInstanceModels.createPipelineInstanceModels; import static javax.servlet.http.HttpServletResponse.SC_NOT_IMPLEMENTED; import static org.hamcrest.Matchers.hasItem; import static org.hamcrest.Matchers.not; import static org.hamcrest.core.Is.is; import static org.hamcrest.core.IsNull.nullValue; import static org.junit.Assert.assertThat; import static org.mockito.Mockito.*; import static org.mockito.MockitoAnnotations.initMocks; public class PipelineHistoryServiceTest { private static final CruiseConfig CRUISE_CONFIG = ConfigMigrator.loadWithMigration("<cruise xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" " + " xsi:noNamespaceSchemaLocation=\"cruise-config.xsd\" schemaVersion=\"17\" >" + "<server artifactsdir=\"target/testfiles/tmpCCRoot/data/logs\"></server>" + " <pipelines>" + " <pipeline name='pipeline'>" + " <materials>" + " <svn url='ape'/>" + " </materials>" + " <stage name='auto'>" + " <jobs>" + " <job name='unit'/>" + " </jobs>" + " </stage>" + " <stage name='manual'>" + " <jobs>" + " <job name='unit'/>" + " </jobs>" + " </stage>" + " </pipeline>" + " </pipelines>" + "</cruise>").config; @Mock private StageDao stageDao; @Mock private PipelineDao pipelineDao; @Mock private GoConfigService goConfigService; @Mock private SecurityService securityService; @Mock private ScheduleService scheduleService; @Mock private PipelineTimeline pipelineTimeline; @Mock private PipelineUnlockApiService pipelineUnlockService; @Mock private SchedulingCheckerService schedulingCheckerService; @Mock private PipelineLockService pipelineLockService; @Mock public PipelinePauseService pipelinePauseService; @Mock public FeatureToggleService featureToggleService; private PipelineHistoryService pipelineHistoryService; private static final Username USERNAME = new Username(new CaseInsensitiveString("bar")); private PipelineConfig config; @Before public void setUp() { initMocks(this); when(featureToggleService.isToggleOn(Toggles.PIPELINE_COMMENT_FEATURE_TOGGLE_KEY)).thenReturn(true); when(goConfigService.isPipelineEditableViaUI(any(String.class))).thenReturn(true); Toggles.initializeWith(featureToggleService); pipelineHistoryService = new PipelineHistoryService(pipelineDao, stageDao, goConfigService, securityService, scheduleService, mock(MaterialRepository.class), JobDurationStrategy.ALWAYS_ZERO, mock(TriggerMonitor.class), pipelineTimeline, pipelineUnlockService, schedulingCheckerService, pipelineLockService, pipelinePauseService); config = CRUISE_CONFIG.pipelineConfigByName(new CaseInsensitiveString("pipeline")); } @Test public void shouldUnderstandLatestPipelineModel() { Username username = new Username(new CaseInsensitiveString("loser")); String pipelineName = "junk"; String groupName = "some-pipeline-group"; PipelineInstanceModel pipeline = PipelineInstanceModel.createPipeline(pipelineName, -1, "1.0", BuildCause.createManualForced(), new StageInstanceModels()); when(pipelineDao.loadHistory(pipelineName, 1, 0)).thenReturn(createPipelineInstanceModels(pipeline)); when(schedulingCheckerService.canManuallyTrigger(pipelineName, username)).thenReturn(false); when(securityService.hasViewPermissionForPipeline(username, pipelineName)).thenReturn(true); when(securityService.hasOperatePermissionForPipeline(username.getUsername(), pipelineName)).thenReturn(true); when(goConfigService.isLockable(pipelineName)).thenReturn(true); when(goConfigService.findGroupNameByPipeline(new CaseInsensitiveString(pipelineName))).thenReturn(groupName); when(goConfigService.isUserAdminOfGroup(username.getUsername(), groupName)).thenReturn(true); when(pipelineLockService.isLocked(pipelineName)).thenReturn(true); stubConfigServiceToReturnPipeline(pipelineName, PipelineConfigMother.createPipelineConfig(pipelineName, "dev", "foo", "bar")); PipelineModel loadedPipeline = pipelineHistoryService.latestPipelineModel(username, pipelineName); assertThat(loadedPipeline.canForce(), is(false)); assertThat(loadedPipeline.canOperate(), is(true)); assertThat(loadedPipeline.getLatestPipelineInstance().isLockable(), is(true)); assertThat(loadedPipeline.getLatestPipelineInstance().isCurrentlyLocked(), is(true)); assertThat(loadedPipeline.getLatestPipelineInstance(), is(pipeline)); assertThat(loadedPipeline.canAdminister(), is(true)); } @Test public void shouldLoadCanOperateAndLockableFlagForAllPipelines() { Username jez = new Username(new CaseInsensitiveString("jez")); CruiseConfig cruiseConfig = ConfigMigrator.loadWithMigration(ConfigFileFixture.CONFIG).config; PipelineConfig pipelineConfig = cruiseConfig.pipelineConfigByName(new CaseInsensitiveString("pipeline1")); pipelineConfig.setTrackingTool(new TrackingTool("http://link", "#")); pipelineConfig = cruiseConfig.pipelineConfigByName(new CaseInsensitiveString("pipeline2")); pipelineConfig.setMingleConfig(new MingleConfig("baseUrl", "id")); when(goConfigService.currentCruiseConfig()).thenReturn(cruiseConfig); PipelineInstanceModels activePipelineInstances = createPipelineInstanceModels(); StageInstanceModel stage1 = new StageInstanceModel("stage1", "2", JobHistory.withJob("plan1", JobState.Building, JobResult.Unknown, new Date())); activePipelineInstances.add(activePipeline("pipeline1", 10, 1.0, stage1, new NullStageHistoryItem("stage2", true))); activePipelineInstances.add(activePipeline("pipeline2", 5, 2.5, new StageInstanceModel("plan1", "2", JobHistory.withJob("plan1", JobState.Building, JobResult.Unknown, new Date())))); activePipelineInstances.add( activePipeline("non-operatable-pipeline", 5, 2.0, new StageInstanceModel("one", "2", JobHistory.withJob("plan1", JobState.Completed, JobResult.Failed, new Date())))); when(goConfigService.isLockable("pipeline1")).thenReturn(true); when(pipelineDao.loadActivePipelines()).thenReturn(activePipelineInstances); stubPermisssionsForActivePipeline(jez, cruiseConfig, "pipeline1", true, true); stubPermisssionsForActivePipeline(jez, cruiseConfig, "pipeline2", true, false); stubPermisssionsForActivePipeline(jez, cruiseConfig, "non-operatable-pipeline", false, false); when(goConfigService.hasPipelineNamed(new CaseInsensitiveString(any(String.class)))).thenReturn(true); when(securityService.hasOperatePermissionForStage("pipeline1", "stage1", CaseInsensitiveString.str(jez.getUsername()))).thenReturn(true); List<PipelineGroupModel> groups = pipelineHistoryService.allActivePipelineInstances(jez, PipelineSelections.ALL); PipelineModel secondPipelineModel = groups.get(0).getPipelineModels().get(1); assertPipelineIs(secondPipelineModel, "pipeline2", true, false); PipelineInstanceModel secondPim = secondPipelineModel.getLatestPipelineInstance(); assertThat(secondPim.getTrackingTool(), is(nullValue())); assertThat(secondPim.getMingleConfig(), is(new MingleConfig("baseUrl", "id"))); assertThat(secondPim.isLockable(), is(false)); PipelineModel firstPipelineModel = groups.get(0).getPipelineModels().get(0); assertPipelineIs(firstPipelineModel, "pipeline1", true, true); PipelineInstanceModel pim = firstPipelineModel.getLatestPipelineInstance(); assertThat(pim.isLockable(), is(true)); assertThat(pim.getTrackingTool(), is(new TrackingTool("http://link", "#"))); assertThat(pim.getMingleConfig(), is(new MingleConfig())); PipelineModel nonOperatablePipelineModel = groups.get(1).getPipelineModels().get(0); assertPipelineIs(nonOperatablePipelineModel, "non-operatable-pipeline", false, false); } @Test public void shouldLoadCurrentlyLockedStatusFlagForAllPipelines() { Username foo = new Username(new CaseInsensitiveString("foo")); CruiseConfig cruiseConfig = ConfigMigrator.loadWithMigration(ConfigFileFixture.CONFIG).config; when(goConfigService.currentCruiseConfig()).thenReturn(cruiseConfig); PipelineInstanceModels activePipelineInstances = createPipelineInstanceModels(); PipelineInstanceModel pipeline1 = activePipeline("pipeline1", 9, 2.0, new StageInstanceModel("stage1", "3", StageResult.Failed, new StageIdentifier()), new StageInstanceModel("stage2", "4", JobHistory.withJob("plan1", JobState.Building, JobResult.Unknown, new Date()))); PipelineInstanceModel pipeline2 = activePipeline("pipeline2", 5, 2.5, new StageInstanceModel("plan1", "2", JobHistory.withJob("plan1", JobState.Building, JobResult.Unknown, new Date()))); PipelineInstanceModel pipeline3 = activePipeline("pipeline3", 5, 2.5, new StageInstanceModel("plan1", "2", JobHistory.withJob("plan1", JobState.Building, JobResult.Unknown, new Date()))); activePipelineInstances.add(pipeline1); activePipelineInstances.add(pipeline2); activePipelineInstances.add(pipeline3); when(pipelineDao.loadActivePipelines()).thenReturn(activePipelineInstances); stubPermisssionsForActivePipeline(foo, cruiseConfig, "pipeline1", true, true); stubPermisssionsForActivePipeline(foo, cruiseConfig, "pipeline2", true, true); stubPermisssionsForActivePipeline(foo, cruiseConfig, "pipeline3", true, true); when(goConfigService.hasPipelineNamed(new CaseInsensitiveString(any(String.class)))).thenReturn(true); when(goConfigService.isLockable("pipeline1")).thenReturn(true); when(goConfigService.isLockable("pipeline2")).thenReturn(true); when(pipelineLockService.isLocked("pipeline1")).thenReturn(true); List<PipelineGroupModel> groups = pipelineHistoryService.allActivePipelineInstances(foo, PipelineSelections.ALL); PipelineGroupModel group = groups.get(0); PipelineModel pipelineModel1 = group.getPipelineModels().get(0); PipelineInstanceModel firstPipelinePIM = pipelineModel1.getActivePipelineInstances().get(0); assertThat(firstPipelinePIM.isLockable(), is (true)); assertThat(firstPipelinePIM.isCurrentlyLocked(), is(true)); PipelineModel pipelineModel2 = group.getPipelineModels().get(1); PipelineInstanceModel secondPipeline = pipelineModel2.getActivePipelineInstances().get(0); assertThat(secondPipeline.isLockable(), is (true)); assertThat(secondPipeline.isCurrentlyLocked(), is(false)); PipelineModel pipelineModel3 = group.getPipelineModels().get(2); PipelineInstanceModel thirdPipeline = pipelineModel3.getActivePipelineInstances().get(0); assertThat(thirdPipeline.isLockable(), is (false)); assertThat(thirdPipeline.isCurrentlyLocked(), is(false)); } @Test public void shouldLoadCanOperateFlagForAllNonActivePipelines() { Username jez = new Username(new CaseInsensitiveString("jez")); setupExpectationsForAllActivePipelinesWithTwoGroups(jez); List<PipelineGroupModel> groups = pipelineHistoryService.allActivePipelineInstances(jez, PipelineSelections.ALL); PipelineModel secondPipelineModel = groups.get(0).getPipelineModels().get(1); assertPipelineIs(secondPipelineModel, "pipeline2", true, false); PipelineModel firstPipelineModel = groups.get(0).getPipelineModels().get(0); assertPipelineIs(firstPipelineModel, "pipeline1", true, true); PipelineModel nonOperatablePipelineModel = groups.get(1).getPipelineModels().get(0); assertPipelineIs(nonOperatablePipelineModel, "non-operatable-pipeline", false, false); } @Test public void shouldSetAdminPermissionOnEveryGroupModel() throws Exception { Username jez = new Username(new CaseInsensitiveString("jez")); setupExpectationsForAllActivePipelinesWithTwoGroups(jez); when(goConfigService.isUserAdminOfGroup(jez.getUsername(), "defaultGroup")).thenReturn(true); when(goConfigService.isUserAdminOfGroup(jez.getUsername(), "foo")).thenReturn(false); List<PipelineGroupModel> groups = pipelineHistoryService.allActivePipelineInstances(jez, PipelineSelections.ALL); assertThat(groups.get(0).getPipelineModels().get(0).canAdminister(), is(true)); assertThat(groups.get(0).getPipelineModels().get(1).canAdminister(), is(true)); assertThat(groups.get(1).getPipelineModels().get(0).canAdminister(), is(false)); verify(goConfigService, times(1)).isUserAdminOfGroup(jez.getUsername(), "defaultGroup"); verify(goConfigService, times(1)).isUserAdminOfGroup(jez.getUsername(), "foo"); } @Test public void shouldRestrictAdminPermissionOnRemotePipelines() throws Exception { when(goConfigService.isPipelineEditableViaUI(any(String.class))).thenReturn(false); Username jez = new Username(new CaseInsensitiveString("jez")); setupExpectationsForAllActivePipelinesWithTwoGroups(jez); when(goConfigService.isUserAdminOfGroup(jez.getUsername(), "defaultGroup")).thenReturn(true); when(goConfigService.isUserAdminOfGroup(jez.getUsername(), "foo")).thenReturn(false); List<PipelineGroupModel> groups = pipelineHistoryService.allActivePipelineInstances(jez, PipelineSelections.ALL); assertThat(groups.get(0).getPipelineModels().get(0).canAdminister(), is(false)); assertThat(groups.get(0).getPipelineModels().get(1).canAdminister(), is(false)); assertThat(groups.get(1).getPipelineModels().get(0).canAdminister(), is(false)); verify(goConfigService, times(1)).isUserAdminOfGroup(jez.getUsername(), "defaultGroup"); verify(goConfigService, times(1)).isUserAdminOfGroup(jez.getUsername(), "foo"); } private void setupExpectationsForAllActivePipelinesWithTwoGroups(Username jez) { CruiseConfig cruiseConfig = ConfigMigrator.loadWithMigration(ConfigFileFixture.CONFIG).config; when(goConfigService.currentCruiseConfig()).thenReturn(cruiseConfig); PipelineInstanceModels activePipelineInstances = createPipelineInstanceModels(); when(pipelineDao.loadActivePipelines()).thenReturn(activePipelineInstances); stubForNonActivePipeline(jez, cruiseConfig, "pipeline1", true, true, activePipeline("pipeline1", 10, 2.0, new StageInstanceModel("stage1", "10", JobHistory.withJob("plan1", JobState.Completed, JobResult.Failed, new Date())))); stubForNonActivePipeline(jez, cruiseConfig, "pipeline2", true, false, activePipeline("pipeline2", 10, 2.0, new StageInstanceModel("stage1", "8", JobHistory.withJob("plan1", JobState.Completed, JobResult.Passed, new Date())))); stubForNonActivePipeline(jez, cruiseConfig, "non-operatable-pipeline", false, false, activePipeline("non-operatable-pipeline", 10, 2.0, new StageInstanceModel("one", "10", JobHistory.withJob("defaultJob", JobState.Completed, JobResult.Failed, new Date())))); when(goConfigService.hasPipelineNamed(new CaseInsensitiveString(any(String.class)))).thenReturn(true); } private void stubForNonActivePipeline(Username username, CruiseConfig cruiseConfig, String pipelineName, boolean operatePermission, boolean canTrigger, PipelineInstanceModel pipeline) { stubPermisssionsForActivePipeline(username, cruiseConfig, pipelineName, operatePermission, canTrigger); when(pipelineDao.loadHistory(pipelineName, 1, 0)).thenReturn(createPipelineInstanceModels(pipeline)); } private void stubPermisssionsForActivePipeline(Username username, CruiseConfig cruiseConfig, String pipelineName, boolean operatePermission, boolean canTrigger) { when(securityService.hasViewPermissionForPipeline(username, pipelineName)).thenReturn(true); when(securityService.hasOperatePermissionForPipeline(username.getUsername(), pipelineName)).thenReturn(operatePermission); stubConfigServiceToReturnPipeline(pipelineName, cruiseConfig.pipelineConfigByName(new CaseInsensitiveString(pipelineName))); when(schedulingCheckerService.canManuallyTrigger(pipelineName, username)).thenReturn(canTrigger); } private void assertPipelineIs(PipelineModel secondPipelineModel, String pipelineName, boolean canOperate, boolean canForce) { assertThat(secondPipelineModel.canOperate(), is(canOperate)); assertThat(secondPipelineModel.canForce(), is(canForce)); PipelineInstanceModel secondActivePipeline = secondPipelineModel.getActivePipelineInstances().get(0); assertThat(secondActivePipeline.getName(), is(pipelineName)); } private PipelineInstanceModel activePipeline(String pipelineName, int pipelineCounter, double naturalOrder, StageInstanceModel... moreStages) { StageInstanceModels stagesForNonOperatablePipeline = new StageInstanceModels(); stagesForNonOperatablePipeline.addAll(Arrays.asList(moreStages)); PipelineInstanceModel nonOperatablePipeline = PipelineInstanceModel.createPipeline(pipelineName, -1, "1.0", BuildCause.createWithEmptyModifications(), stagesForNonOperatablePipeline); nonOperatablePipeline.setNaturalOrder(naturalOrder); nonOperatablePipeline.setCounter(pipelineCounter); return nonOperatablePipeline; } @Test public void shouldLoadAllActivePipelinesWithPreviousStageState() { Username foo = new Username(new CaseInsensitiveString("foo")); CruiseConfig cruiseConfig = ConfigMigrator.loadWithMigration(ConfigFileFixture.CONFIG).config; when(goConfigService.currentCruiseConfig()).thenReturn(cruiseConfig); PipelineInstanceModels activePipelineInstances = createPipelineInstanceModels(); PipelineInstanceModel earlier = activePipeline("pipeline1", 9, 2.0, new StageInstanceModel("stage1", "3", StageResult.Failed, new StageIdentifier()), new StageInstanceModel("stage2", "4", JobHistory.withJob("plan1", JobState.Building, JobResult.Unknown, new Date()))); earlier.setId(1); PipelineInstanceModel latest = activePipeline("pipeline1", 10, 1.0, new StageInstanceModel("stage1", "4", JobHistory.withJob("plan1", JobState.Building, JobResult.Unknown, new Date())), new NullStageHistoryItem("stage2", true)); latest.setId(2); activePipelineInstances.add(latest); activePipelineInstances.add(earlier); when(pipelineDao.loadActivePipelines()).thenReturn(activePipelineInstances); when(pipelineDao.loadHistory(1)).thenReturn(earlier); when(pipelineDao.loadHistory(2)).thenReturn(latest); when(pipelineDao.loadHistory(3)).thenReturn(activePipeline("pipeline1", 11, 3.0, new StageInstanceModel("stage1", "3", StageResult.Failed, new StageIdentifier()), new StageInstanceModel("stage2", "2", StageResult.Passed, new StageIdentifier()))); when(pipelineTimeline.runBefore(2, new CaseInsensitiveString("pipeline1"))).thenReturn(new PipelineTimelineEntry("pipeline1", 1, 9, new HashMap<>())); when(pipelineTimeline.runBefore(1, new CaseInsensitiveString("pipeline1"))).thenReturn(new PipelineTimelineEntry("pipeline1", 3, 11, new HashMap<>())); stubPermisssionsForActivePipeline(foo, cruiseConfig, "pipeline1", true, true); when(goConfigService.hasPipelineNamed(new CaseInsensitiveString(any(String.class)))).thenReturn(true); List<PipelineGroupModel> groups = pipelineHistoryService.allActivePipelineInstances(foo, PipelineSelections.ALL); PipelineGroupModel group = groups.get(0); PipelineModel pipelineModel = group.getPipelineModels().get(0); PipelineInstanceModels activePipelines = pipelineModel.getActivePipelineInstances(); assertPipelineIs(activePipelines.get(0), "pipeline1", "stage1", StageResult.Failed); assertPipelineIs(activePipelines.get(1), "pipeline1", "stage2", StageResult.Passed); } @Test public void allActivePipelines_shouldOnlyKeepSelectedPipelines() { Username foo = new Username(new CaseInsensitiveString("foo")); CruiseConfig cruiseConfig = ConfigMigrator.loadWithMigration(ConfigFileFixture.CONFIG).config; when(goConfigService.currentCruiseConfig()).thenReturn(cruiseConfig); PipelineInstanceModels activePipelineInstances = createPipelineInstanceModels( activePipeline("pipeline1", 1, 1.0), activePipeline("pipeline2", 1, 1.0), activePipeline("pipeline4", 1, 1.0), activePipeline("non-operatable-pipeline", 1, 1.0) ); for (String pipeline : new String[]{"pipeline1", "pipeline2", "pipeline3", "pipeline4", "non-operatable-pipeline"}) { stubPermisssionsForActivePipeline(foo, cruiseConfig, pipeline, true, true); when(pipelineDao.loadHistory(pipeline,1,0)).thenReturn(createPipelineInstanceModels()); } when(pipelineDao.loadActivePipelines()).thenReturn(activePipelineInstances); when(goConfigService.hasPipelineNamed(new CaseInsensitiveString(any(String.class)))).thenReturn(true); List<PipelineGroupModel> groups = pipelineHistoryService.allActivePipelineInstances(foo, new PipelineSelections(Arrays.asList("pipeline1","pipeline2"))); assertThat(groups.size(),is(2)); assertThat(groups.get(0).getName(),is("defaultGroup")); assertThat(groups.get(0).containsPipeline("pipeline1"),is(false)); assertThat(groups.get(0).containsPipeline("pipeline2"),is(false)); assertThat(groups.get(0).containsPipeline("pipeline3"),is(true)); assertThat(groups.get(0).containsPipeline("pipeline4"),is(true)); assertThat(groups.get(1).getName(),is("foo")); assertThat(groups.get(1).containsPipeline("non-operatable-pipeline"),is(true)); } @Test public void allActivePipelines_shouldRemove_EmptyGroups() { Username bar = new Username(new CaseInsensitiveString("non-existant")); CruiseConfig cruiseConfig = ConfigMigrator.loadWithMigration(ConfigFileFixture.CONFIG).config; when(goConfigService.currentCruiseConfig()).thenReturn(cruiseConfig); when(pipelineDao.loadActivePipelines()).thenReturn(createPipelineInstanceModels()); when(goConfigService.hasPipelineNamed(new CaseInsensitiveString(any(String.class)))).thenReturn(true); List<PipelineGroupModel> groups = pipelineHistoryService.allActivePipelineInstances(bar, new PipelineSelections()); assertThat(groups.isEmpty(),is(true)); } @Test public void shouldGetActivePipeline() { Username foo = new Username(new CaseInsensitiveString("foo")); CruiseConfig cruiseConfig = ConfigMigrator.loadWithMigration(ConfigFileFixture.CONFIG).config; when(goConfigService.currentCruiseConfig()).thenReturn(cruiseConfig); PipelineInstanceModels activePipelineInstances = createPipelineInstanceModels( activePipeline("pipeline1", 1, 1.0), activePipeline("pipeline2", 1, 1.0), activePipeline("pipeline4", 1, 1.0), activePipeline("non-operatable-pipeline", 1, 1.0) ); for (String pipeline : new String[]{"pipeline1", "pipeline2", "pipeline3", "pipeline4", "non-operatable-pipeline"}) { stubPermisssionsForActivePipeline(foo, cruiseConfig, pipeline, true, true); when(pipelineDao.loadHistory(pipeline, 1, 0)).thenReturn(createPipelineInstanceModels()); } when(pipelineDao.loadActivePipelines()).thenReturn(activePipelineInstances); when(goConfigService.hasPipelineNamed(new CaseInsensitiveString(any(String.class)))).thenReturn(true); List<PipelineGroupModel> groups = pipelineHistoryService.getActivePipelineInstance(foo, "pipeline1"); assertThat(groups.size(), is(1)); assertThat(groups.get(0).getName(), is("defaultGroup")); assertThat(groups.get(0).containsPipeline("pipeline1"), is(true)); } @Test public void getActivePipelineInstance_shouldRemoveEmptyGroups() { Username foo = new Username(new CaseInsensitiveString("foo")); CruiseConfig cruiseConfig = ConfigMigrator.loadWithMigration(ConfigFileFixture.CONFIG).config; when(goConfigService.currentCruiseConfig()).thenReturn(cruiseConfig); when(pipelineDao.loadActivePipelines()).thenReturn(createPipelineInstanceModels()); when(goConfigService.hasPipelineNamed(new CaseInsensitiveString(any(String.class)))).thenReturn(true); List<PipelineGroupModel> groups = pipelineHistoryService.getActivePipelineInstance(foo, "pipeline1"); assertThat(groups.isEmpty(),is(true)); } @Test public void allActivePipelines_shouldOnlyKeepSelectedPipelines_andRemove_EmptyGroups() { Username foo = new Username(new CaseInsensitiveString("foo")); CruiseConfig cruiseConfig = ConfigMigrator.loadWithMigration(ConfigFileFixture.CONFIG).config; when(goConfigService.currentCruiseConfig()).thenReturn(cruiseConfig); PipelineInstanceModels activePipelineInstances = createPipelineInstanceModels( activePipeline("pipeline1", 1, 1.0), activePipeline("pipeline2", 1, 1.0), activePipeline("pipeline4", 1, 1.0), activePipeline("non-operatable-pipeline", 1, 1.0) ); for (String pipeline : new String[]{"pipeline1", "pipeline2", "pipeline3", "pipeline4", "non-operatable-pipeline"}) { stubPermisssionsForActivePipeline(foo, cruiseConfig, pipeline, true, true); when(pipelineDao.loadHistory(pipeline,1,0)).thenReturn(createPipelineInstanceModels()); } when(pipelineDao.loadActivePipelines()).thenReturn(activePipelineInstances); when(goConfigService.hasPipelineNamed(new CaseInsensitiveString(any(String.class)))).thenReturn(true); List<PipelineGroupModel> groups = pipelineHistoryService.allActivePipelineInstances(foo, new PipelineSelections(Arrays.asList("non-operatable-pipeline"))); assertThat(groups.size(), is(1)); assertThat(groups.get(0).getName(), is("defaultGroup")); assertThat(groups.get(0).containsPipeline("pipeline1"), is(true)); assertThat(groups.get(0).containsPipeline("pipeline2"),is(true)); assertThat(groups.get(0).containsPipeline("pipeline3"), is(true)); assertThat(groups.get(0).containsPipeline("pipeline4"), is(true)); } @Test public void allActivePipelines_shouldSkipNullPipelinesWhenLoadingPreviousStageStae() { Username foo = new Username(new CaseInsensitiveString("foo")); CruiseConfig cruiseConfig = ConfigMigrator.loadWithMigration(ConfigFileFixture.CONFIG).config; when(goConfigService.currentCruiseConfig()).thenReturn(cruiseConfig); PipelineInstanceModels activePipelineInstances = createPipelineInstanceModels(); PipelineInstanceModel latest = activePipeline("pipeline1", 10, 1.0, new StageInstanceModel("stage1", "4", JobHistory.withJob("plan1", JobState.Building, JobResult.Unknown, new Date())), new NullStageHistoryItem("stage2", true)); latest.setId(2); activePipelineInstances.add(latest); when(pipelineDao.loadActivePipelines()).thenReturn(activePipelineInstances); when(pipelineDao.loadHistory(1)).thenReturn(null); when(pipelineDao.loadHistory(2)).thenReturn(latest); when(pipelineDao.loadHistory(3)).thenReturn(activePipeline("pipeline1", 11, 3.0, new StageInstanceModel("stage1", "3", StageResult.Failed, new StageIdentifier()))); //2>1>3 when(pipelineTimeline.runBefore(2, new CaseInsensitiveString("pipeline1"))).thenReturn(new PipelineTimelineEntry("pipeline1", 1, 9, new HashMap<>())); when(pipelineTimeline.runBefore(1, new CaseInsensitiveString("pipeline1"))).thenReturn(new PipelineTimelineEntry("pipeline1", 3, 11, new HashMap<>())); stubPermisssionsForActivePipeline(foo, cruiseConfig, "pipeline1", true, true); when(goConfigService.hasPipelineNamed(new CaseInsensitiveString(any(String.class)))).thenReturn(true); List<PipelineGroupModel> groups = pipelineHistoryService.allActivePipelineInstances(foo, PipelineSelections.ALL); PipelineGroupModel group = groups.get(0); PipelineModel pipelineModel = group.getPipelineModels().get(0); PipelineInstanceModels activePipelines = pipelineModel.getActivePipelineInstances(); assertPipelineIs(activePipelines.get(0), "pipeline1", "stage1", StageResult.Failed); } private void assertPipelineIs(PipelineInstanceModel pipeline, String pipelineName, String activeStageName, StageResult previousStageResult) { assertThat(pipeline.getName(), is(pipelineName)); StageInstanceModel activeStage = pipeline.activeStage(); assertThat(activeStage.getName(), is(activeStageName)); assertThat(activeStage.getPreviousStage().getResult(), is(previousStageResult)); } @Test public void findPipelineInstanceUsingIdShouldPopulateAppendEmptyStagesFromConfig() throws Exception { ensureConfigHasPipeline("pipeline"); ensureHasPermission(Username.ANONYMOUS, "pipeline"); PipelineInstanceModel instanceModel = PipelineInstanceModel.createEmptyPipelineInstanceModel("pipeline", BuildCause.createNeverRun(), new StageInstanceModels()); when(pipelineDao.loadHistoryByIdWithBuildCause(1L)).thenReturn(instanceModel); stubConfigServiceToReturnPipeline("pipeline", config); PipelineInstanceModel pipelineInstance = pipelineHistoryService.findPipelineInstance("pipeline", 1, 1L, Username.ANONYMOUS, new HttpOperationResult()); StageInstanceModels models = pipelineInstance.getStageHistory(); assertThat(models.size(), is(2)); } @Test public void findPipelineInstanceShouldPopulateAppendEmptyStagesFromConfig() throws Exception { ensureConfigHasPipeline("pipeline"); ensureHasPermission(Username.ANONYMOUS, "pipeline"); PipelineInstanceModel instanceModel = PipelineInstanceModel.createEmptyPipelineInstanceModel("pipeline", BuildCause.createNeverRun(), new StageInstanceModels()); when(pipelineDao.findPipelineHistoryByNameAndCounter("pipeline", 1)).thenReturn(instanceModel); stubConfigServiceToReturnPipeline("pipeline", config); PipelineInstanceModel pipelineInstance = pipelineHistoryService.findPipelineInstance("pipeline", 1, Username.ANONYMOUS, new HttpOperationResult()); StageInstanceModels models = pipelineInstance.getStageHistory(); assertThat(models.size(), is(2)); } @Test public void findPipelineInstanceShouldChangeResultTo404WhenPipelineNotFound() throws Exception { ensureConfigHasPipeline("pipeline"); ensureHasPermission(Username.ANONYMOUS, "pipeline"); when(pipelineDao.findPipelineHistoryByNameAndCounter("pipeline", 1)).thenReturn(null); when(goConfigService.pipelineConfigNamed(new CaseInsensitiveString("pipeline"))).thenReturn(config); HttpOperationResult operationResult = new HttpOperationResult(); PipelineInstanceModel pipelineInstance = pipelineHistoryService.findPipelineInstance("pipeline", 1, Username.ANONYMOUS, operationResult); assertThat(pipelineInstance, is(nullValue())); assertThat(operationResult.httpCode(), is(404)); } @Test public void shouldPopulateIfPipelineCanBeUnlockedAndIsLockable() throws Exception { ensureConfigHasPipeline("pipeline"); stubConfigServiceToReturnPipeline("pipeline", config); when(goConfigService.isLockable("pipeline")).thenReturn(true); ensureHasPermission(Username.ANONYMOUS, "pipeline"); PipelineInstanceModel instanceModel = PipelineInstanceModel.createPipeline("pipeline", -1, "label", BuildCause.createNeverRun(), new StageInstanceModels()); when(pipelineDao.findPipelineHistoryByNameAndCounter("pipeline", 1)).thenReturn(instanceModel); when(pipelineUnlockService.canUnlock(eq("pipeline"), eq(Username.ANONYMOUS), any(HttpOperationResult.class))).thenReturn(true); PipelineInstanceModel pipelineInstance = pipelineHistoryService.findPipelineInstance("pipeline", 1, Username.ANONYMOUS, new HttpOperationResult()); assertThat(pipelineInstance.canUnlock(), is(true)); assertThat(pipelineInstance.isLockable(), is(true)); } @Test public void shouldPopulateWetherStageAndPipelineCanBeRunAccordingToOperatePermissions() throws Exception { ensureConfigHasPipeline("pipeline"); ensureHasPermission(Username.ANONYMOUS, "pipeline"); StageInstanceModels stages = new StageInstanceModels(); stages.add(new StageInstanceModel("dev", "1", new JobHistory())); stages.add(new StageInstanceModel("qa", "1", new JobHistory())); PipelineInstanceModel instanceModel = PipelineInstanceModel.createPipeline("pipeline", -1, "label", BuildCause.createNeverRun(), stages); when(pipelineDao.findPipelineHistoryByNameAndCounter("pipeline", 1)).thenReturn(instanceModel); stubConfigServiceToReturnPipeline("pipeline", config); StageInstanceModel firstStage = instanceModel.getStageHistory().get(0); when(scheduleService.canRun(instanceModel.getPipelineIdentifier(), firstStage.getName(), CaseInsensitiveString.str(Username.ANONYMOUS.getUsername()), instanceModel.hasPreviousStageBeenScheduled(firstStage.getName()))).thenReturn(true); StageInstanceModel secondStage = instanceModel.getStageHistory().get(1); when(scheduleService.canRun(instanceModel.getPipelineIdentifier(), secondStage.getName(), CaseInsensitiveString.str(Username.ANONYMOUS.getUsername()), instanceModel.hasPreviousStageBeenScheduled(secondStage.getName()))).thenReturn(false); when(securityService.hasOperatePermissionForStage("pipeline", "dev", CaseInsensitiveString.str(Username.ANONYMOUS.getUsername()))).thenReturn(true); when(securityService.hasOperatePermissionForStage("pipeline", "qa", CaseInsensitiveString.str(Username.ANONYMOUS.getUsername()))).thenReturn(false); PipelineInstanceModel pipelineInstance = pipelineHistoryService.findPipelineInstance("pipeline", 1, Username.ANONYMOUS, new HttpOperationResult()); StageInstanceModels models = pipelineInstance.getStageHistory(); assertThat(models.get(0).getCanRun(), is(true)); assertThat(models.get(1).getCanRun(), is(false)); assertThat(models.get(0).hasOperatePermission(), is(true)); assertThat(models.get(1).hasOperatePermission(), is(false)); } @Test public void shouldPopulatePipelineInstanceModelWithTheBeforeAndAfterForTheGivenPipeline() throws Exception { DateTime now = new DateTime(); PipelineTimelineEntry first = PipelineMaterialModificationMother.modification(Arrays.asList("first"), 1, "123", now); PipelineTimelineEntry second = PipelineMaterialModificationMother.modification(Arrays.asList("first"), 1, "123", now); when(pipelineTimeline.runBefore(1, new CaseInsensitiveString("pipeline"))).thenReturn(first); when(pipelineTimeline.runAfter(1, new CaseInsensitiveString("pipeline"))).thenReturn(second); PipelineInstanceModel expected = PipelineHistoryMother.pipelineHistoryItemWithOneStage("pipeline", "auto", now.toDate()); expected.setId(1); when(pipelineDao.loadHistory(1)).thenReturn(expected); when(goConfigService.currentCruiseConfig()).thenReturn(CRUISE_CONFIG); when(goConfigService.pipelineConfigNamed(new CaseInsensitiveString("pipeline"))).thenReturn(config); when(securityService.hasOperatePermissionForStage("pipeline", "auto", CaseInsensitiveString.str(Username.ANONYMOUS.getUsername()))).thenReturn(true); ensureHasPermission(Username.ANONYMOUS, "pipeline"); PipelineInstanceModel model = pipelineHistoryService.load(1, Username.ANONYMOUS, new HttpOperationResult()); assertThat(model.getPipelineBefore(), is(first)); assertThat(model.getPipelineAfter(), is(second)); assertThat(model.stage("auto").hasOperatePermission(), is(true)); } @Test public void shouldReturnDependencyGraphOnlyIfUserHasPermissions() throws Exception { PipelineInstanceModel instanceModel = pim("blahPipeline"); instanceModel.setId(12); PipelineDependencyGraphOld expected = new PipelineDependencyGraphOld(instanceModel, createPipelineInstanceModels()); when(pipelineDao.pipelineGraphByNameAndCounter("blahPipeline", 12)).thenReturn(expected); ensureConfigHasPipeline("blahPipeline"); when(goConfigService.downstreamPipelinesOf("blahPipeline")).thenReturn(new ArrayList<>()); stubConfigServiceToReturnPipeline("blahPipeline", PipelineConfigMother.pipelineConfig("blahPipeline")); when(pipelineTimeline.pipelineBefore(12)).thenReturn(1L); when(pipelineDao.loadHistory(1)).thenReturn(new PipelineInstanceModel("blahPipeline", 21, "prev-label", BuildCause.createWithEmptyModifications(), new StageInstanceModels())); Username foo = new Username(new CaseInsensitiveString("foo")); ensureHasPermission(USERNAME, "blahPipeline"); assertThat(pipelineHistoryService.pipelineDependencyGraph("blahPipeline", 12, foo, new HttpOperationResult()), is(nullValue())); assertThat(pipelineHistoryService.pipelineDependencyGraph("blahPipeline", 12, USERNAME, new HttpOperationResult()), is(expected)); } @Test public void shouldReturnGraphWithADiffOfMaterialRevisionsForTheGivenPipeline() throws Exception { PipelineInstanceModel pim = pim("blahPipeline"); MaterialRevisions actualRevs = ModificationsMother.multipleModifications(); pim.setId(23); pim.setMaterialRevisionsOnBuildCause(actualRevs); PipelineDependencyGraphOld expected = new PipelineDependencyGraphOld(pim, createPipelineInstanceModels()); when(pipelineDao.pipelineGraphByNameAndCounter("blahPipeline", 12)).thenReturn(expected); ensureConfigHasPipeline("blahPipeline"); when(goConfigService.downstreamPipelinesOf("blahPipeline")).thenReturn(new ArrayList<>()); stubConfigServiceToReturnPipeline("blahPipeline", PipelineConfigMother.pipelineConfig("blahPipeline")); when(pipelineTimeline.pipelineBefore(23)).thenReturn(1L); when(pipelineDao.loadHistory(1L)).thenReturn(new PipelineInstanceModel("blahPipeline", 21, "prev-label", BuildCause.createWithEmptyModifications(), new StageInstanceModels())); ensureHasPermission(USERNAME, "blahPipeline"); PipelineDependencyGraphOld actual = pipelineHistoryService.pipelineDependencyGraph("blahPipeline", 12, USERNAME, new HttpOperationResult()); assertThat(actual.pipeline().getPreviousLabel(), is("prev-label")); assertThat(actual.pipeline().getPreviousCounter(), is(21)); assertThat(actual.pipeline().getCurrentRevisions(), is(actualRevs)); } @Test public void shouldSetStageRunAndOperatePermissionsInTheDependencyGraph() throws Exception { PipelineInstanceModel pim = pim("blahPipeline"); pim.setId(23); pim.getStageHistory().add(new StageInstanceModel("stage", "1", new JobHistory())); PipelineDependencyGraphOld expected = new PipelineDependencyGraphOld(pim, createPipelineInstanceModels()); when(pipelineDao.pipelineGraphByNameAndCounter("blahPipeline", 12)).thenReturn(expected); ensureConfigHasPipeline("blahPipeline"); when(goConfigService.downstreamPipelinesOf("blahPipeline")).thenReturn(new ArrayList<>()); stubConfigServiceToReturnPipeline("blahPipeline", PipelineConfigMother.pipelineConfig("blahPipeline")); when(scheduleService.canRun(pim.getPipelineIdentifier(), "stage", CaseInsensitiveString.str(USERNAME.getUsername()), true)).thenReturn(true); when(securityService.hasOperatePermissionForStage("blahPipeline", "stage", CaseInsensitiveString.str(USERNAME.getUsername()))).thenReturn(true); when(pipelineTimeline.pipelineBefore(23)).thenReturn(-1L); ensureHasPermission(USERNAME, "blahPipeline"); PipelineDependencyGraphOld actual = pipelineHistoryService.pipelineDependencyGraph("blahPipeline", 12, USERNAME, new HttpOperationResult()); assertThat(actual.pipeline().getStageHistory().size(), is(1)); assertThat(actual.pipeline().getStageHistory().get(0).getCanRun(), is(true)); assertThat(actual.pipeline().getStageHistory().get(0).hasOperatePermission(), is(true)); } @Test public void shouldSetStageRunAndOperatePermissionsInTheDependencyGraphForTheDependentPipelinesOfAPipelineInstance() throws Exception { PipelineInstanceModel down1Pim = pim("down1"); down1Pim.getStageHistory().add(new StageInstanceModel("stage", "1", new JobHistory())); PipelineInstanceModel actualPim = pim("blahPipeline"); actualPim.setId(23); PipelineDependencyGraphOld returned = new PipelineDependencyGraphOld(actualPim, createPipelineInstanceModels(down1Pim)); when(pipelineDao.pipelineGraphByNameAndCounter("blahPipeline", 12)).thenReturn(returned); ensureConfigHasPipeline("blahPipeline"); ensureHasPermission(USERNAME, "blahPipeline"); ensureConfigHasPipeline("down1"); ensureHasPermission(USERNAME, "down1"); when(goConfigService.downstreamPipelinesOf("blahPipeline")).thenReturn(Arrays.asList(PipelineConfigMother.pipelineConfig("down1"))); stubConfigServiceToReturnPipeline("blahPipeline", PipelineConfigMother.pipelineConfig("blahPipeline")); stubConfigServiceToReturnPipeline("down1", PipelineConfigMother.pipelineConfig("down1")); when(scheduleService.canRun(down1Pim.getPipelineIdentifier(), down1Pim.getStageHistory().first().getName(), CaseInsensitiveString.str(USERNAME.getUsername()), true)).thenReturn(true); when(securityService.hasOperatePermissionForStage("down1", "stage", CaseInsensitiveString.str(USERNAME.getUsername()))).thenReturn(true); when(pipelineTimeline.pipelineBefore(23)).thenReturn(-1L); PipelineDependencyGraphOld actual = pipelineHistoryService.pipelineDependencyGraph("blahPipeline", 12, USERNAME, new HttpOperationResult()); StageInstanceModel firstStageOfDown1 = actual.dependencies().get(0).getStageHistory().get(0); assertThat(actual.dependencies().size(), is(1)); assertThat(firstStageOfDown1.hasOperatePermission(), is(true)); assertThat(firstStageOfDown1.getCanRun(), is(true)); } @Test public void shouldReturn404WhenPipelineInstanceIsNotPresent() throws Exception { when(pipelineDao.pipelineGraphByNameAndCounter("blahPipeline", 12)).thenReturn(null); ensureConfigHasPipeline("blahPipeline"); ensureHasPermission(USERNAME, "blahPipeline"); HttpOperationResult result = new HttpOperationResult(); pipelineHistoryService.pipelineDependencyGraph("blahPipeline", 12, USERNAME, result); assertThat(result.canContinue(), is(false)); assertThat(result.httpCode(), is(404)); assertThat(result.message(), is("Pipeline [blahPipeline] with counter [12] is not found")); } @Test public void shouldRemoveDependencyPipelineWhichIsNotPresentInConfig() throws Exception { ensureConfigHasPipeline("blahPipeline"); ensureConfigHasPipeline("down1"); ensureConfigContainsPipelineIs("down2", false); when(goConfigService.downstreamPipelinesOf("blahPipeline")).thenReturn(Arrays.asList(PipelineConfigMother.pipelineConfig("down1"))); stubConfigServiceToReturnPipeline("blahPipeline", PipelineConfigMother.pipelineConfig("blahPipeline")); PipelineConfig downOneConfig = PipelineConfigMother.pipelineConfig("down1"); stubConfigServiceToReturnPipeline("down1", downOneConfig); when(goConfigService.isLockable("blahPipeline")).thenReturn(true); when(pipelineUnlockService.canUnlock("blahPipeline", USERNAME, new HttpOperationResult())).thenReturn(true); when(pipelineTimeline.pipelineBefore(23)).thenReturn(-1L); ensureHasPermission(USERNAME, "blahPipeline"); ensureHasPermission(USERNAME, "down1"); PipelineInstanceModel actualPim = pim("down1"); actualPim.setCanRun(false); actualPim.setStageHistory(PipelineHistoryMother.stagePerJob("stage", PipelineHistoryMother.job(JobResult.Failed))); PipelineInstanceModel returned = pim("blahPipeline"); returned.setId(23); PipelineDependencyGraphOld graph = new PipelineDependencyGraphOld(returned, createPipelineInstanceModels(actualPim, pim("down2"))); when(pipelineDao.pipelineGraphByNameAndCounter("blahPipeline", 12)).thenReturn(graph); when(schedulingCheckerService.canManuallyTrigger(actualPim.getName(), USERNAME)).thenReturn(true); PipelineDependencyGraphOld actual = pipelineHistoryService.pipelineDependencyGraph("blahPipeline", 12, USERNAME, new HttpOperationResult()); assertThat(actual.dependencies().size(), is(1)); assertThat(actual.dependencies().get(0), is(actualPim)); assertThat(actual.dependencies().get(0).getCanRun(), is(true)); } @Test public void shouldAddOtherDependentPipelinePresentInConfig() throws Exception { ensureConfigHasPipeline("blahPipeline"); ensureConfigHasPipeline("down1"); ensureConfigHasPipeline("noPermission"); PipelineConfig other = GoConfigMother.createPipelineConfigWithMaterialConfig("other"); other.add(new StageConfig(new CaseInsensitiveString("badChildhood"), new JobConfigs())); when(pipelineUnlockService.canUnlock(eq("blahPipeline"), eq(USERNAME), any(HttpOperationResult.class))).thenReturn(true); when(goConfigService.isLockable("blahPipeline")).thenReturn(true); when(goConfigService.downstreamPipelinesOf("blahPipeline")).thenReturn(Arrays.asList(other)); stubConfigServiceToReturnPipeline("blahPipeline", PipelineConfigMother.pipelineConfig("blahPipeline", new StageConfig(new CaseInsensitiveString("first"), new JobConfigs()))); ensureHasPermission(USERNAME, "blahPipeline"); SvnMaterialConfig svnMaterialConfig = MaterialConfigsMother.svnMaterialConfig(); svnMaterialConfig.setName(null); stubConfigServiceToReturnMaterialAndPipeline("down1", new MaterialConfigs(svnMaterialConfig), PipelineConfigMother.pipelineConfig("down1", new StageConfig( new CaseInsensitiveString("first"), new JobConfigs() ))); ensureHasPermission(USERNAME, "down1"); stubConfigServiceToReturnMaterialAndPipeline("other", new MaterialConfigs(), other); when(pipelineTimeline.pipelineBefore(23)).thenReturn(-1L); PipelineInstanceModel actualPim = pim("down1"); PipelineInstanceModel noPermission = pim("noPermission"); PipelineInstanceModel returned = pim("blahPipeline"); returned.setId(23); PipelineDependencyGraphOld graph = new PipelineDependencyGraphOld(returned, createPipelineInstanceModels(actualPim, noPermission)); when(pipelineDao.pipelineGraphByNameAndCounter("blahPipeline", 12)).thenReturn(graph); PipelineDependencyGraphOld actual = pipelineHistoryService.pipelineDependencyGraph("blahPipeline", 12, USERNAME, new HttpOperationResult()); assertThat(actual.pipeline().isLockable(), is(true)); assertThat(actual.pipeline().canUnlock(), is(true)); assertThat(actual.dependencies().size(), is(2)); assertThat(actual.dependencies().get(0), is(actualPim)); assertHasMaterial(actualPim, MaterialsMother.svnMaterial().config()); PipelineInstanceModel otherInstance = actual.dependencies().get(1); assertThat(otherInstance.getName(), is("other")); assertThat(otherInstance.getMaterials().size(), is(0)); } @Test public void shouldReturnPageNumberForAPipelineCounter() { when(pipelineDao.getPageNumberForCounter("some-pipeline", 100, 10)).thenReturn(1); assertThat(pipelineHistoryService.getPageNumberForCounter("some-pipeline", 100, 10), is(1)); } @Test public void shouldPopulateDataCorrectly_getPipelineStatus() { CruiseConfig cruiseConfig = mock(BasicCruiseConfig.class); PipelineConfig pipelineConfig = new PipelineConfig(); PipelinePauseInfo pipelinePauseInfo = new PipelinePauseInfo(true,"pausing pipeline for some-reason", "some-one"); when(cruiseConfig.getPipelineConfigByName(new CaseInsensitiveString("pipeline-name"))).thenReturn(pipelineConfig); when(goConfigService.currentCruiseConfig()).thenReturn(cruiseConfig); when(securityService.hasViewPermissionForPipeline(Username.valueOf("user-name"), "pipeline-name")).thenReturn(true); when(pipelinePauseService.pipelinePauseInfo("pipeline-name")).thenReturn(pipelinePauseInfo); when(pipelineLockService.isLocked("pipeline-name")).thenReturn(true); when(schedulingCheckerService.canManuallyTrigger(eq(pipelineConfig), eq("user-name"), any(ServerHealthStateOperationResult.class))).thenReturn(true); PipelineStatusModel pipelineStatus = pipelineHistoryService.getPipelineStatus("pipeline-name", "user-name", new HttpOperationResult()); assertThat(pipelineStatus.isPaused(), is(true)); assertThat(pipelineStatus.pausedCause(), is("pausing pipeline for some-reason")); assertThat(pipelineStatus.pausedBy(), is("some-one")); assertThat(pipelineStatus.isLocked(), is(true)); assertThat(pipelineStatus.isSchedulable(), is(true)); } @Test public void shouldPopulateResultAsNotFound_getPipelineStatus() { CruiseConfig cruiseConfig = mock(BasicCruiseConfig.class); when(cruiseConfig.getPipelineConfigByName(new CaseInsensitiveString("pipeline-name"))).thenReturn(null); when(goConfigService.currentCruiseConfig()).thenReturn(cruiseConfig); HttpOperationResult result = new HttpOperationResult(); PipelineStatusModel pipelineStatus = pipelineHistoryService.getPipelineStatus("pipeline-name", "user-name", result); assertThat(pipelineStatus, is(nullValue())); assertThat(result.httpCode(), is(404)); } @Test public void shouldPopulateResultAsUnauthorized_getPipelineStatus() { CruiseConfig cruiseConfig = mock(BasicCruiseConfig.class); PipelineConfig pipelineConfig = new PipelineConfig(); when(cruiseConfig.getPipelineConfigByName(new CaseInsensitiveString("pipeline-name"))).thenReturn(pipelineConfig); when(goConfigService.currentCruiseConfig()).thenReturn(cruiseConfig); when(securityService.hasViewPermissionForPipeline(Username.valueOf("user-name"), "pipeline-name")).thenReturn(false); HttpOperationResult result = new HttpOperationResult(); PipelineStatusModel pipelineStatus = pipelineHistoryService.getPipelineStatus("pipeline-name", "user-name", result); assertThat(pipelineStatus, is(nullValue())); assertThat(result.httpCode(), is(401)); } @Test public void shouldPopulateResultAsNotFoundWhenPipelineNotFound_loadMinimalData() { String pipelineName = "unknown-pipeline"; CruiseConfig cruiseConfig = mock(BasicCruiseConfig.class); when(cruiseConfig.hasPipelineNamed(new CaseInsensitiveString(pipelineName))).thenReturn(false); when(goConfigService.currentCruiseConfig()).thenReturn(cruiseConfig); HttpOperationResult result = new HttpOperationResult(); PipelineInstanceModels pipelineInstanceModels = pipelineHistoryService.loadMinimalData(pipelineName, Pagination.pageFor(0, 0, 10), new Username(new CaseInsensitiveString("looser")), result); assertThat(pipelineInstanceModels, is(nullValue())); assertThat(result.httpCode(), is(404)); assertThat(result.detailedMessage(), is("Not Found { Pipeline " + pipelineName + " not found }\n")); } @Test public void shouldPopulateResultAsUnauthorizedWhenUserNotAllowedToViewPipeline_loadMinimalData() { Username noAccessUserName = new Username(new CaseInsensitiveString("foo")); Username withAccessUserName = new Username(new CaseInsensitiveString("admin")); String pipelineName = "no-access-pipeline"; CruiseConfig cruiseConfig = mock(BasicCruiseConfig.class); when(cruiseConfig.hasPipelineNamed(new CaseInsensitiveString(pipelineName))).thenReturn(true); when(goConfigService.currentCruiseConfig()).thenReturn(cruiseConfig); when(securityService.hasViewPermissionForPipeline(noAccessUserName, pipelineName)).thenReturn(false); when(securityService.hasViewPermissionForPipeline(withAccessUserName, pipelineName)).thenReturn(true); when(pipelineDao.loadHistory(pipelineName, 10, 0)).thenReturn(PipelineInstanceModels.createPipelineInstanceModels()); HttpOperationResult result = new HttpOperationResult(); PipelineInstanceModels pipelineInstanceModels = pipelineHistoryService.loadMinimalData(pipelineName, Pagination.pageFor(0, 1, 10), noAccessUserName, result); assertThat(pipelineInstanceModels, is(nullValue())); assertThat(result.httpCode(), is(401)); result = new HttpOperationResult(); pipelineInstanceModels = pipelineHistoryService.loadMinimalData(pipelineName, Pagination.pageFor(0, 1, 10), withAccessUserName, result); assertThat(pipelineInstanceModels, is(not(nullValue()))); assertThat(result.canContinue(), is(true)); } @Test public void shouldUpdateCommentUsingPipelineDao() { CaseInsensitiveString authorizedUser = new CaseInsensitiveString("can-access"); HttpLocalizedOperationResult result = new HttpLocalizedOperationResult(); when(securityService.hasOperatePermissionForPipeline(authorizedUser, "pipeline_name")).thenReturn(true); pipelineHistoryService.updateComment("pipeline_name", 1, "test comment", new Username(authorizedUser), result); verify(pipelineDao, times(1)).updateComment("pipeline_name", 1, "test comment"); } @Test public void shouldNotUpdateCommentWhenUserIsUnauthorized() { CaseInsensitiveString unauthorizedUser = new CaseInsensitiveString("cannot-access"); String pipelineName = "pipeline_name"; when(securityService.hasOperatePermissionForPipeline(unauthorizedUser, pipelineName)).thenReturn(false); HttpLocalizedOperationResult result = mock(HttpLocalizedOperationResult.class); pipelineHistoryService.updateComment(pipelineName, 1, "test comment", new Username(unauthorizedUser), result); verify(pipelineDao, never()).updateComment(pipelineName, 1, "test comment"); verify(result, times(1)).unauthorized(LocalizedMessage.cannotOperatePipeline(pipelineName), HealthStateType.general(HealthStateScope.forPipeline(pipelineName))); } @Test public void shouldFailWhenFeatureIsToggledOff_updateComment() { when(featureToggleService.isToggleOn(Toggles.PIPELINE_COMMENT_FEATURE_TOGGLE_KEY)).thenReturn(false); Toggles.initializeWith(featureToggleService); CaseInsensitiveString unauthorizedUser = new CaseInsensitiveString("cannot-access"); String pipelineName = "pipeline_name"; HttpLocalizedOperationResult result = new HttpLocalizedOperationResult(); pipelineHistoryService.updateComment(pipelineName, 1, "test comment", new Username(unauthorizedUser), result); assertThat(result.httpCode(), is(SC_NOT_IMPLEMENTED)); assertThat(result.localizable(), is(LocalizedMessage.string("FEATURE_NOT_AVAILABLE", "Pipeline Comment"))); verify(pipelineDao, never()).updateComment(pipelineName, 1, "test comment"); } private void stubConfigServiceToReturnMaterialAndPipeline(String downPipelineName, MaterialConfigs downPipelineMaterial, PipelineConfig down1Config) { when(goConfigService.materialConfigsFor(new CaseInsensitiveString(downPipelineName))).thenReturn(downPipelineMaterial); stubConfigServiceToReturnPipeline(downPipelineName, down1Config); } private void stubConfigServiceToReturnPipeline(String blahPipelineName, PipelineConfig blahPipelineConfig) { when(goConfigService.pipelineConfigNamed(new CaseInsensitiveString(blahPipelineName))).thenReturn(blahPipelineConfig); when(goConfigService.findFirstStageOfPipeline(new CaseInsensitiveString(blahPipelineName))).thenReturn(blahPipelineConfig.get(0)); } private void assertHasMaterial(PipelineInstanceModel otherInstance, MaterialConfig materialConfig) { assertThat(otherInstance, is(not(nullValue()))); assertThat(otherInstance.getMaterials(), is(not(nullValue()))); assertThat(otherInstance.getMaterials().size(), is(1)); assertThat(otherInstance.getMaterials(), hasItem(materialConfig)); } private PipelineInstanceModel pim(String pipelineName) { return PipelineHistoryMother.singlePipeline(pipelineName, new StageInstanceModels()); } private void ensureConfigHasPipeline(String pipelineName) { ensureConfigContainsPipelineIs(pipelineName, true); } private void ensureHasPermission(Username bar, String pipelineName) { when(securityService.hasViewPermissionForPipeline(bar, pipelineName)).thenReturn(true); } private void ensureConfigContainsPipelineIs(String pipelineName, boolean isPresent) { when(goConfigService.hasPipelineNamed(new CaseInsensitiveString(pipelineName))).thenReturn(isPresent); } }