package com.smartcodeltd.jenkinsci.plugins.buildmonitor.viewmodel.syntacticsugar;
import com.google.common.base.Supplier;
import com.google.common.collect.Lists;
import com.sonyericsson.jenkins.plugins.bfa.model.FailureCauseBuildAction;
import com.sonyericsson.jenkins.plugins.bfa.model.FoundFailureCause;
import hudson.model.AbstractBuild;
import hudson.model.AbstractProject;
import hudson.model.Result;
import hudson.model.User;
import hudson.plugins.claim.ClaimBuildAction;
import hudson.scm.ChangeLogSet;
import jenkins.model.CauseOfInterruption;
import jenkins.model.InterruptedBuildAction;
import org.jvnet.hudson.plugins.groovypostbuild.GroovyPostbuildAction;
import org.powermock.api.mockito.PowerMockito;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Iterator;
import java.util.List;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
import static org.powermock.api.mockito.PowerMockito.mockStatic;
/**
* @author Jan Molak
*/
public class BuildStateRecipe implements Supplier<AbstractBuild<?, ?>> {
private AbstractBuild<?, ?> build;
public BuildStateRecipe() {
build = mock(AbstractBuild.class);
AbstractProject parent = mock(AbstractProject.class);
doReturn(parent).when(build).getParent();
}
public BuildStateRecipe hasNumber(int number) {
when(build.getNumber()).thenReturn(number);
// see hudson.model.Run::getDisplayName
return hasName("#" + number);
}
public BuildStateRecipe hasName(String name) {
when(build.getDisplayName()).thenReturn(name);
return this;
}
public BuildStateRecipe whichNumberIs(int number) {
return hasNumber(number);
}
public BuildStateRecipe finishedWith(Result result) {
when(build.getResult()).thenReturn(result);
return this;
}
public BuildStateRecipe withChangesFrom(String... authors) {
ChangeLogSet changeSet = changeSetBasedOn(entriesBy(authors));
when(build.getChangeSet()).thenReturn(changeSet);
// any methods that use getChangeSet as their source of data should be called normally
// (build is a partial mock in this case)
when(build.getCulprits()).thenCallRealMethod();
return this;
}
public BuildStateRecipe succeededThanksTo(String... authors) {
finishedWith(Result.SUCCESS);
withChangesFrom(authors);
return this;
}
public BuildStateRecipe wasBrokenBy(String... culprits) {
finishedWith(Result.FAILURE);
withChangesFrom(culprits);
return this;
}
public BuildStateRecipe hasntStartedYet() {
when(build.hasntStartedYet()).thenReturn(true);
return this;
}
public BuildStateRecipe isStillBuilding() {
when(build.isBuilding()).thenReturn(true);
return this;
}
public BuildStateRecipe isStillUpdatingTheLog() {
when(build.isLogUpdated()).thenReturn(true);
return this;
}
public BuildStateRecipe startedAt(String time) throws Exception {
long startedAt = new SimpleDateFormat("H:m:s").parse(time).getTime();
Calendar timestamp = mock(Calendar.class);
when(build.getTimestamp()).thenReturn(timestamp);
when(timestamp.getTimeInMillis()).thenReturn(startedAt);
return this;
}
public BuildStateRecipe took(int minutes) throws Exception{
long duration = (long) minutes * 60 * 1000;
when(build.getDuration()).thenReturn(duration);
return this;
}
public BuildStateRecipe usuallyTakes(int minutes) throws Exception{
long duration = (long) minutes * 60 * 1000;
when(build.getEstimatedDuration()).thenReturn(duration);
return this;
}
public BuildStateRecipe wasClaimedBy(String aPotentialHero, String reason) {
final ClaimBuildAction action = claimBuildAction(aPotentialHero, reason);
when(build.getAction(ClaimBuildAction.class)).thenReturn(action);
return this;
}
private ClaimBuildAction claimBuildAction(String author, String reason) {
ClaimBuildAction action = mock(ClaimBuildAction.class);
when(action.isClaimed()).thenReturn(true);
when(action.getClaimedByName()).thenReturn(author);
when(action.getReason()).thenReturn(reason);
return action;
}
public BuildStateRecipe wasAbortedBy(String username) {
User user = userCalled(username);
mockStatic(User.class);
PowerMockito.when(User.get(user.getId())).thenReturn(user);
final InterruptedBuildAction action = interruptedBuildAction(user);
when(build.getAction(InterruptedBuildAction.class)).thenReturn(action);
finishedWith(Result.ABORTED);
return this;
}
private InterruptedBuildAction interruptedBuildAction(User user) {
List<CauseOfInterruption> causes = Lists.<CauseOfInterruption>newArrayList(
new CauseOfInterruption.UserInterruption(user)
);
InterruptedBuildAction action = mock(InterruptedBuildAction.class);
when(action.getCauses()).thenReturn(causes);
return action;
}
public BuildStateRecipe knownProblems(String... failures) {
final FailureCauseBuildAction action = failureCauseBuildAction(failures);
when(build.getAction(FailureCauseBuildAction.class)).thenReturn(action);
return this;
}
private FailureCauseBuildAction failureCauseBuildAction(String... FailureNames) {
FailureCauseBuildAction action = mock(FailureCauseBuildAction.class);
List<FoundFailureCause> items = new ArrayList<FoundFailureCause>();
for( String name : FailureNames ) {
items.add(failure(name));
}
when(action.getFoundFailureCauses()).thenReturn(items);
return action;
}
private FoundFailureCause failure(String name) {
FoundFailureCause failure = mock(FoundFailureCause.class);
when(failure.getName()).thenReturn(name);
return failure;
}
public BuildStateRecipe hasBadges(BadgeRecipe... badges) {
List<GroovyPostbuildAction> actions = new ArrayList<GroovyPostbuildAction>();
for (int i = 0; i < badges.length; i++) {
actions.add(badges[i].get());
}
when(build.getActions(GroovyPostbuildAction.class)).thenReturn(actions);
return this;
}
public BuildStateRecipe and() {
return this;
}
@Override
public AbstractBuild get() {
return build;
}
// todo: replace mock user with userCalled
private List<ChangeLogSet.Entry> entriesBy(String... authors) {
List<ChangeLogSet.Entry> entries = new ArrayList<ChangeLogSet.Entry>();
for (String name : authors) {
User author = mock(User.class);
ChangeLogSet.Entry entry = mock(ChangeLogSet.Entry.class);
when(author.getFullName()).thenReturn(name);
when(entry.getAuthor()).thenReturn(author);
entries.add(entry);
}
return entries;
}
private User userCalled(String name) {
User user = mock(User.class);
when(user.getId()).thenReturn(name.toLowerCase());
when(user.getFullName()).thenReturn(name);
return user;
}
private ChangeLogSet changeSetBasedOn(final List<ChangeLogSet.Entry> entries) {
return new ChangeLogSet<ChangeLogSet.Entry>(null) {
@Override
public boolean isEmptySet() {
return false;
}
public Iterator<Entry> iterator() {
return entries.iterator();
}
};
}
}