/*
* 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.domain.cctray;
import com.thoughtworks.go.domain.JobInstance;
import com.thoughtworks.go.domain.NullStage;
import com.thoughtworks.go.domain.Stage;
import com.thoughtworks.go.domain.activity.ProjectStatus;
import com.thoughtworks.go.domain.cctray.viewers.AllowedViewers;
import com.thoughtworks.go.domain.cctray.viewers.Viewers;
import com.thoughtworks.go.helper.JobInstanceMother;
import com.thoughtworks.go.helper.StageMother;
import org.junit.Before;
import org.junit.Test;
import org.mockito.ArgumentCaptor;
import org.mockito.Captor;
import org.mockito.Mock;
import java.util.Date;
import java.util.HashSet;
import java.util.List;
import static com.thoughtworks.go.util.DataStructureUtils.s;
import static org.hamcrest.CoreMatchers.is;
import static org.hamcrest.Matchers.not;
import static org.junit.Assert.assertThat;
import static org.mockito.Mockito.*;
import static org.mockito.MockitoAnnotations.initMocks;
public class CcTrayStageStatusChangeHandlerTest {
@Mock
private CcTrayCache cache;
@Mock
private CcTrayBreakersCalculator breakersCalculator;
@Mock
private CcTrayJobStatusChangeHandler jobStatusChangeHandler;
@Captor
ArgumentCaptor<List<ProjectStatus>> statusesCaptor;
private CcTrayStageStatusChangeHandler handler;
@Before
public void setUp() throws Exception {
initMocks(this);
handler = new CcTrayStageStatusChangeHandler(cache, jobStatusChangeHandler, breakersCalculator);
}
@Test
public void shouldGenerateStatusesForStageAndAllJobsWithinIt() throws Exception {
JobInstance firstJob = JobInstanceMother.building("job1");
JobInstance secondJob = JobInstanceMother.completed("job2");
Stage stage = StageMother.custom("stage1", firstJob, secondJob);
when(jobStatusChangeHandler.statusFor(firstJob, new HashSet<>())).thenReturn(new ProjectStatus("job1_name", null, null, null, null, null));
when(jobStatusChangeHandler.statusFor(secondJob, new HashSet<>())).thenReturn(new ProjectStatus("job2_name", null, null, null, null, null));
List<ProjectStatus> statuses = handler.statusesOfStageAndItsJobsFor(stage);
assertThat(statuses.size(), is(3));
assertThat(statuses.get(0).name(), is("pipeline :: stage1"));
assertThat(statuses.get(1).name(), is("job1_name"));
assertThat(statuses.get(2).name(), is("job2_name"));
}
@Test
public void shouldCalculateBreakersForStage() throws Exception {
Stage stage = StageMother.custom("stage1", JobInstanceMother.building("job1"));
when(breakersCalculator.calculateFor(stage)).thenReturn(s("breaker1", "breaker2"));
List<ProjectStatus> statuses = handler.statusesOfStageAndItsJobsFor(stage);
assertThat(statuses.get(0).getBreakers(), is(s("breaker1", "breaker2")));
}
@Test
public void shouldCreateJobStatusesWithBreakers_OnlyIfTheyHaveFailed() throws Exception {
JobInstance job1_building = JobInstanceMother.building("job1");
JobInstance job2_failed = JobInstanceMother.failed("job2");
Stage stage = StageMother.custom("stage1", job1_building, job2_failed);
when(breakersCalculator.calculateFor(stage)).thenReturn(s("breaker1", "breaker2"));
handler.statusesOfStageAndItsJobsFor(stage);
verify(jobStatusChangeHandler).statusFor(job1_building, new HashSet<>());
verify(jobStatusChangeHandler).statusFor(job2_failed, s("breaker1", "breaker2"));
}
@Test
public void shouldCreateStatusesWithStageActivityAndWebUrl() throws Exception {
Stage stage = StageMother.custom("stage1", JobInstanceMother.building("job1"));
List<ProjectStatus> statuses = handler.statusesOfStageAndItsJobsFor(stage);
ProjectStatus statusOfStage = statuses.get(0);
assertThat(activityOf(statusOfStage), is("Building"));
assertThat(webUrlOf(statusOfStage), is(webUrlFor("stage1")));
}
@Test
public void shouldLeaveBuildDetailsOfStageSameAsTheDefault_WhenStageIsNotCompleted_AndThereIsNoExistingStageInCache() throws Exception {
String projectName = "pipeline :: stage1";
ProjectStatus.NullProjectStatus defaultStatus = new ProjectStatus.NullProjectStatus(projectName);
Stage stage = StageMother.custom("stage1", JobInstanceMother.building("job1"));
List<ProjectStatus> statuses = handler.statusesOfStageAndItsJobsFor(stage);
ProjectStatus statusOfStage = statuses.get(0);
assertThat(stage.getState().completed(), is(not(true)));
assertThat(statusOfStage.getLastBuildStatus(), is(defaultStatus.getLastBuildStatus()));
assertThat(statusOfStage.getLastBuildTime(), is(defaultStatus.getLastBuildTime()));
assertThat(statusOfStage.getLastBuildLabel(), is(defaultStatus.getLastBuildLabel()));
}
@Test
public void shouldLeaveBuildDetailsOfStageSameAsTheOneInCache_WhenStageIsNotCompleted_AndThereIsAnExistingStageInCache() throws Exception {
String projectName = "pipeline :: stage1";
ProjectStatus existingStageStatus = new ProjectStatus(projectName, "OldActivity", "OldStatus", "OldLabel", new Date(), webUrlFor("stage1"));
when(cache.get(projectName)).thenReturn(existingStageStatus);
Stage stage = StageMother.custom("stage1", JobInstanceMother.building("job1"));
List<ProjectStatus> statuses = handler.statusesOfStageAndItsJobsFor(stage);
ProjectStatus statusOfStage = statuses.get(0);
assertThat(stage.getState().completed(), is(not(true)));
assertThat(statusOfStage.getLastBuildStatus(), is(existingStageStatus.getLastBuildStatus()));
assertThat(statusOfStage.getLastBuildTime(), is(existingStageStatus.getLastBuildTime()));
assertThat(statusOfStage.getLastBuildLabel(), is(existingStageStatus.getLastBuildLabel()));
}
@Test
public void shouldUpdateBuildDetailsOfStageWhenStageIsCompleted() throws Exception {
Stage completedStage = StageMother.createPassedStage("pipeline", 1, "stage1", 1, "job1", new Date());
completedStage.setCompletedByTransitionId(1L);
List<ProjectStatus> statuses = handler.statusesOfStageAndItsJobsFor(completedStage);
ProjectStatus statusOfStage = statuses.get(0);
assertThat(completedStage.isCompleted(), is(true));
assertThat(statusOfStage.getLastBuildStatus(), is("Success"));
assertThat(statusOfStage.getLastBuildTime(), is(completedStage.completedDate()));
assertThat(statusOfStage.getLastBuildLabel(), is("LABEL-1"));
}
@Test
public void shouldReuseViewersListFromExistingStatusWhenCreatingNewStatus() throws Exception {
Viewers viewers = viewers("viewer1", "viewer2");
String projectName = "pipeline :: stage1";
ProjectStatus existingStageStatus = new ProjectStatus(projectName, "OldActivity", "OldStatus", "OldLabel", new Date(), webUrlFor("stage1"));
existingStageStatus.updateViewers(viewers);
when(cache.get(projectName)).thenReturn(existingStageStatus);
Stage stage = StageMother.custom("stage1", JobInstanceMother.building("job1"));
List<ProjectStatus> statuses = handler.statusesOfStageAndItsJobsFor(stage);
ProjectStatus statusOfStage = statuses.get(0);
assertThat(statusOfStage.viewers(), is(viewers));
}
@Test
public void shouldNotUpdateCacheWhenStageWhichHasChangedIsANullStage() throws Exception {
handler.call(new NullStage("some-name"));
verifyZeroInteractions(cache);
verifyZeroInteractions(breakersCalculator);
verifyZeroInteractions(jobStatusChangeHandler);
}
@Test
public void shouldUpdateCacheWhenStageWhichHasChangedIsNotANullStage() throws Exception {
Stage completedStage = StageMother.createPassedStage("pipeline", 1, "stage1", 1, "job1", new Date());
ProjectStatus jobStatus = new ProjectStatus("job1_name", "activity1", "lastBuildStatus1", "lastBuildLabel1", new Date(), "webUrl1");
when(jobStatusChangeHandler.statusFor(completedStage.getJobInstances().first(), new HashSet<>())).thenReturn(jobStatus);
handler.call(completedStage);
verify(breakersCalculator).calculateFor(completedStage);
verify(cache).putAll(statusesCaptor.capture());
List<ProjectStatus> statusesWhichWereCached = statusesCaptor.getValue();
assertThat(statusesWhichWereCached.size(), is(2));
assertThat(statusesWhichWereCached.get(0).name(), is("pipeline :: stage1"));
assertThat(statusesWhichWereCached.get(0).getLastBuildStatus(), is("Success"));
assertThat(activityOf(statusesWhichWereCached.get(0)), is("Sleeping"));
assertThat(statusesWhichWereCached.get(1), is(jobStatus));
}
private String activityOf(ProjectStatus status) {
return status.ccTrayXmlElement("some-path").getAttribute("activity").getValue();
}
private String webUrlOf(ProjectStatus status) {
return status.ccTrayXmlElement("some-path").getAttribute("webUrl").getValue();
}
private String webUrlFor(final String stageName) {
return "some-path/pipelines/pipeline/1/" + stageName + "/1";
}
private Viewers viewers(String... users) {
return new AllowedViewers(s(users));
}
}