package com.smartcodeltd.jenkinsci.plugins.buildmonitor.viewmodel;
import com.smartcodeltd.jenkinsci.plugins.buildmonitor.facade.RelativeLocation;
import org.junit.Test;
import java.util.List;
import static com.smartcodeltd.jenkinsci.plugins.buildmonitor.viewmodel.syntacticsugar.Loops.asFollows;
import static com.smartcodeltd.jenkinsci.plugins.buildmonitor.viewmodel.syntacticsugar.Sugar.*;
import static com.smartcodeltd.jenkinsci.plugins.buildmonitor.viewmodel.syntacticsugar.TimeMachine.currentTime;
import static hudson.model.Result.*;
import static org.hamcrest.Matchers.containsString;
import static org.hamcrest.core.Is.is;
import static org.hamcrest.core.IsNot.not;
import static org.junit.Assert.assertThat;
import static org.mockito.Mockito.*;
/**
* @author Jan Molak
*/
public class JobViewTest {
private static final String theName = "some-TLAs-followed-by-a-project-name";
private static final String displayName = "Pretty name that has some actual meaning";
private RelativeLocation relativeLocation = mock(RelativeLocation.class); // TODO recipe builder
private JobView view;
/*
* By the way, if you were not aware of this: the configuration page of each job has an "Advanced Project Options"
* section, where you can set a user-friendly "Display Name"
*/
@Test
public void delegates_the_process_of_determining_the_relative_job_name() {
when(relativeLocation.name()).thenReturn(theName);
view = a(jobView().of(
a(job().withName(theName))
).with(relativeLocation));
assertThat(view.name(), is(theName));
assertThat(view.toString(), is(theName));
verify(relativeLocation, times(2)).name();
}
@Test
public void delegates_the_process_of_determining_the_relative_url() {
String expectedUrl = "job/" + theName;
when(relativeLocation.url()).thenReturn(expectedUrl);
view = a(jobView().of(
a(job().withName(theName).withDisplayName(displayName)))
.with(relativeLocation));
assertThat(view.url(), is(expectedUrl));
verify(relativeLocation, times(1)).url();
}
/*
* Should be able to measure the progress
*/
@Test
public void progress_of_a_not_started_job_should_be_zero() {
view = a(jobView().of(a(job())));
assertThat(view.progress(), is(0));
}
@Test
public void progress_of_a_finished_job_should_be_zero() {
view = a(jobView().of(
a(job().whereTheLast(build().finishedWith(SUCCESS)))));
assertThat(view.progress(), is(0));
}
@Test
public void progress_of_a_nearly_finished_job_should_be_100() throws Exception {
view = a(jobView().of(
a(job().whereTheLast(build().isStillBuilding().startedAt("12:00:00").and().usuallyTakes(0))))
.assuming(currentTime().is("12:00:00")));
assertThat(view.progress(), is(100));
}
@Test
public void progress_of_a_job_thats_taking_longer_than_expected_should_be_100() throws Exception {
view = a(jobView()
.of(a(job().whereTheLast(build().isStillBuilding().startedAt("12:00:00").and().usuallyTakes(5))))
.assuming(currentTime().is("12:20:00")));
assertThat(view.progress(), is(100));
}
@Test
public void should_calculate_the_progress_of_a_running_job() throws Exception {
view = a(jobView().of(
a(job().whereTheLast(build().isStillBuilding().startedAt("13:10:00").and().usuallyTakes(5))))
.assuming(currentTime().is("13:11:00")));
assertThat(view.progress(), is(20));
}
@Test
public void should_know_how_long_the_next_build_is_supposed_to_take() throws Exception {
view = a(jobView().of(
a(job().whereTheLast(build().finishedWith(SUCCESS).and().usuallyTakes(5)))));
assertThat(view.estimatedDuration(), is("5m 0s"));
}
@Test
public void should_not_say_anything_if_it_doesnt_know_how_long_the_next_build_is_supposed_to_take() throws Exception {
view = a(jobView().of(a(job())));
assertThat(view.estimatedDuration(), is(""));
}
/*
* Should produce a meaningful status description that can be used in the CSS
*/
@Test
public void should_describe_the_job_as_successful_if_the_last_build_succeeded() {
view = a(jobView().of(
a(job().whereTheLast(build().finishedWith(SUCCESS)))));
assertThat(view.status(), containsString("successful"));
}
@Test
public void should_describe_the_job_as_failing_if_the_last_build_failed() {
view = a(jobView().of(
a(job().whereTheLast(build().finishedWith(FAILURE)))));
assertThat(view.status(), containsString("failing"));
}
@Test
public void should_describe_the_job_as_aborted_if_the_last_build_was_aborted() {
view = a(jobView().of(
a(job().whereTheLast(build().finishedWith(ABORTED)))));
assertThat(view.status(), containsString("aborted"));
}
@Test
public void should_describe_the_job_as_unstable_if_the_last_build_is_unstable() {
view = a(jobView().of(
a(job().whereTheLast(build().finishedWith(UNSTABLE)))));
assertThat(view.status(), containsString("unstable"));
}
@Test
public void should_describe_the_state_of_the_job_as_unknown_when_it_is_yet_to_be_determined() {
view = a(jobView().of(a(job())));
assertThat(view.status(), containsString("unknown"));
}
@Test
public void should_describe_the_job_as_running_if_it_is_running() {
List<JobView> views = asFollows(
a(jobView().of(a(job().whereTheLast(build().hasntStartedYet())))),
a(jobView().of(a(job().whereTheLast(build().isStillBuilding())))),
a(jobView().of(a(job().whereTheLast(build().isStillUpdatingTheLog())))));
for (JobView jobView : views) {
assertThat(jobView.status(), containsString("running"));
}
}
@Test
public void should_describe_the_job_as_disabled_if_not_buildable() {
view = a(jobView().of(a(job().thatIsNotBuildable())));
assertThat(view.status(), containsString("disabled"));
}
@Test
public void should_describe_the_job_as_enabled_if_external_job() {
view = a(jobView().of(a(job().thatIsAnExternalJob())));
assertThat(view.status(), not(containsString("disabled")));
}
@Test
public void should_describe_the_job_as_disabled_and_failing_if_the_last_build_failed_and_the_job_is_disabled() {
view = a(jobView().of(a(job().thatIsNotBuildable().whereTheLast(build().finishedWith(FAILURE)))));
assertThat(view.status(), containsString("disabled"));
assertThat(view.status(), containsString("failing"));
}
@Test
public void should_describe_the_job_as_running_and_successful_if_it_is_running_and_the_previous_build_succeeded() {
List<JobView> views = asFollows(
a(jobView().of(a(job().whereTheLast(build().hasntStartedYet()).andThePrevious(build().finishedWith(SUCCESS))))),
a(jobView().of(a(job().whereTheLast(build().isStillBuilding()).andThePrevious(build().finishedWith(SUCCESS))))),
a(jobView().of(a(job().whereTheLast(build().isStillUpdatingTheLog()).andThePrevious(build().finishedWith(SUCCESS))))));
// I could do this instead of having two assertions:
// assertThat(view.status(), both(containsString("successful")).and(containsString("running")));
// but then it would require Java 7
for (JobView jobView : views) {
assertThat(jobView.status(), containsString("successful"));
assertThat(jobView.status(), containsString("running"));
}
}
@Test
public void should_describe_the_job_as_running_and_failing_if_it_is_running_and_the_previous_build_failed() {
List<JobView> views = asFollows(
a(jobView().of(a(job().
whereTheLast(build().hasntStartedYet()).
andThePrevious(build().finishedWith(FAILURE))))),
a(jobView().of(a(job().
whereTheLast(build().isStillBuilding()).
andThePrevious(build().finishedWith(FAILURE))))),
a(jobView().of(a(job().
whereTheLast(build().isStillUpdatingTheLog()).
andThePrevious(build().finishedWith(FAILURE)))))
);
for (JobView jobView : views) {
assertThat(jobView.status(), containsString("failing"));
assertThat(jobView.status(), containsString("running"));
}
}
/*
* Parallel build execution handling
*/
@Test
public void should_describe_the_job_as_successful_when_there_are_several_builds_running_in_parallel_and_the_last_completed_was_successful() {
view = a(jobView().of(
a(job().whereTheLast(build().isStillBuilding()).
andThePrevious(build().isStillBuilding()).
andThePrevious(build().finishedWith(SUCCESS)))));
assertThat(view.status(), containsString("successful"));
}
@Test
public void should_describe_the_job_as_failing_when_there_are_several_builds_running_in_parallel_and_the_last_completed_failed() {
view = a(jobView().of(
a(job().whereTheLast(build().isStillBuilding()).
andThePrevious(build().isStillBuilding()).
andThePrevious(build().finishedWith(FAILURE)))));
assertThat(view.status(), containsString("failing"));
}
@Test
public void public_api_should_return_reasonable_defaults_for_jobs_that_never_run() throws Exception {
view = a(jobView().of(
a(job().thatHasNeverRun())));
assertThat(view.estimatedDuration(), is(""));
assertThat(view.progress(), is(0));
assertThat(view.status(), is("unknown"));
}
}