package com.hubspot.blazar.data.service; import static org.assertj.core.api.Assertions.assertThat; import java.util.Collections; import java.util.List; import java.util.Set; import org.jukito.JukitoRunner; import org.jukito.UseModules; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import com.google.common.base.Optional; import com.google.inject.Inject; import com.hubspot.blazar.base.BuildOptions; import com.hubspot.blazar.base.BuildOptions.BuildDownstreams; import com.hubspot.blazar.base.BuildTrigger; import com.hubspot.blazar.base.CommitInfo; import com.hubspot.blazar.base.DependencyGraph; import com.hubspot.blazar.base.GitInfo; import com.hubspot.blazar.base.RepositoryBuild; import com.hubspot.blazar.base.RepositoryBuild.State; import com.hubspot.blazar.data.BlazarDataTestModule; import com.hubspot.blazar.data.util.BuildNumbers; import com.hubspot.blazar.github.GitHubProtos.Commit; import com.hubspot.blazar.test.base.service.DatabaseBackedTest; @RunWith(JukitoRunner.class) @UseModules({BlazarDataTestModule.class}) public class RepositoryBuildServiceTest extends DatabaseBackedTest { @Inject private RepositoryBuildService repositoryBuildService; @Inject private BranchService branchService; private GitInfo branchOne; private GitInfo branchTwo; private long buildIdOne; private long buildIdTwo; private BuildTrigger buildTriggerOne; private BuildTrigger buildTriggerTwo; private BuildOptions buildOptionsOne; private BuildOptions buildOptionsTwo; private CommitInfo commitInfoOne; private CommitInfo commitInfoTwo; private DependencyGraph dependencyGraphOne; private DependencyGraph dependencyGraphTwo; @Before public void before() { branchOne = branchService.upsert(GitInfo.fromString("github.com/HubSpot/Test#one")); branchTwo = branchService.upsert(GitInfo.fromString("github.com/HubSpot/Test#two")); Optional<Commit> absentCommit = Optional.absent(); List<Commit> emptyCommits = Collections.emptyList(); Set<Integer> emptyIntegers = Collections.emptySet(); buildTriggerOne = BuildTrigger.forCommit("abc"); buildOptionsOne = new BuildOptions(Collections.singleton(123), BuildDownstreams.NONE, true); buildIdOne = repositoryBuildService.enqueue(branchOne, buildTriggerOne, buildOptionsOne); commitInfoOne = new CommitInfo(Commit.newBuilder().setId("abc").build(), absentCommit, emptyCommits, false); dependencyGraphOne = new DependencyGraph(Collections.singletonMap(123, emptyIntegers), Collections.singletonList(123)); buildTriggerTwo = BuildTrigger.forCommit("def"); buildOptionsTwo = new BuildOptions(Collections.singleton(456), BuildDownstreams.NONE, false); buildIdTwo = repositoryBuildService.enqueue(branchTwo, buildTriggerTwo, buildOptionsTwo); commitInfoTwo = new CommitInfo(Commit.newBuilder().setId("def").build(), absentCommit, emptyCommits, false); dependencyGraphTwo = new DependencyGraph(Collections.singletonMap(456, emptyIntegers), Collections.singletonList(456)); } @Test public void itEnqueuesNewBuildWhenNonePresent() { RepositoryBuild repositoryBuild = repositoryBuildService.get(buildIdOne).get(); validateBuild(RepositoryBuild.queuedBuild(branchOne, buildTriggerOne, 1, buildOptionsOne), repositoryBuild); BuildNumbers buildNumbers = repositoryBuildService.getBuildNumbers(branchOne.getId().get()); assertThat(buildNumbers.getPendingBuildId().get()).isEqualTo(buildIdOne); assertThat(buildNumbers.getPendingBuildNumber().get()).isEqualTo(1); } @Test public void itReturnsPendingBuildForSecondPushEvent() { long newBuildId = repositoryBuildService.enqueue(branchOne, buildTriggerTwo, buildOptionsTwo); assertThat(newBuildId).isEqualTo(buildIdOne); } @Test public void itEnqueuesNewBuildForManualTrigger() { BuildTrigger manualTrigger = BuildTrigger.forUser("test"); long newBuildId = repositoryBuildService.enqueue(branchOne, manualTrigger, buildOptionsOne); assertThat(newBuildId).isNotEqualTo(buildIdOne); RepositoryBuild repositoryBuild = repositoryBuildService.get(newBuildId).get(); validateBuild(RepositoryBuild.queuedBuild(branchOne, manualTrigger, 2, buildOptionsOne), repositoryBuild); BuildNumbers buildNumbers = repositoryBuildService.getBuildNumbers(branchOne.getId().get()); assertThat(buildNumbers.getPendingBuildId().get()).isEqualTo(buildIdOne); assertThat(buildNumbers.getPendingBuildNumber().get()).isEqualTo(1); } @Test public void itEnqueuesNewBuildForDifferentBranch() { assertThat(buildIdTwo).isNotEqualTo(buildIdOne); RepositoryBuild repositoryBuild = repositoryBuildService.get(buildIdTwo).get(); validateBuild(RepositoryBuild.queuedBuild(branchTwo, buildTriggerTwo, 1, buildOptionsTwo), repositoryBuild); BuildNumbers buildNumbers = repositoryBuildService.getBuildNumbers(branchTwo.getId().get()); assertThat(buildNumbers.getPendingBuildId().get()).isEqualTo(buildIdTwo); assertThat(buildNumbers.getPendingBuildNumber().get()).isEqualTo(1); } @Test public void itBeginsPendingBuild() { RepositoryBuild pending = repositoryBuildService.get(buildIdOne).get(); RepositoryBuild launching = pending.toBuilder() .setState(State.LAUNCHING) .setStartTimestamp(Optional.of(123L)) .setCommitInfo(Optional.of(commitInfoOne)) .setSha(Optional.of(commitInfoOne.getCurrent().getId())) .setDependencyGraph(Optional.of(dependencyGraphOne)).build(); repositoryBuildService.begin(launching); RepositoryBuild fetched = repositoryBuildService.get(buildIdOne).get(); validateBuild(launching, fetched); BuildNumbers buildNumbers = repositoryBuildService.getBuildNumbers(branchOne.getId().get()); assertThat(buildNumbers.getPendingBuildId().isPresent()).isFalse(); assertThat(buildNumbers.getPendingBuildNumber().isPresent()).isFalse(); assertThat(buildNumbers.getInProgressBuildId().get()).isEqualTo(buildIdOne); assertThat(buildNumbers.getInProgressBuildNumber().get()).isEqualTo(1); } @Test public void itMovesNextQueuedBuildIntoPendingSlotWhenBuildBegins() { BuildTrigger manualTrigger = BuildTrigger.forUser("test"); long newBuildId = repositoryBuildService.enqueue(branchOne, manualTrigger, buildOptionsOne); assertThat(newBuildId).isNotEqualTo(buildIdOne); RepositoryBuild pending = repositoryBuildService.get(buildIdOne).get(); RepositoryBuild launching = pending.toBuilder() .setState(State.LAUNCHING) .setStartTimestamp(Optional.of(123L)) .setCommitInfo(Optional.of(commitInfoOne)) .setSha(Optional.of(commitInfoOne.getCurrent().getId())) .setDependencyGraph(Optional.of(dependencyGraphOne)).build(); repositoryBuildService.begin(launching); RepositoryBuild fetched = repositoryBuildService.get(buildIdOne).get(); validateBuild(launching, fetched); BuildNumbers buildNumbers = repositoryBuildService.getBuildNumbers(branchOne.getId().get()); assertThat(buildNumbers.getPendingBuildId().get()).isEqualTo(newBuildId); assertThat(buildNumbers.getPendingBuildNumber().get()).isEqualTo(2); assertThat(buildNumbers.getInProgressBuildId().get()).isEqualTo(buildIdOne); assertThat(buildNumbers.getInProgressBuildNumber().get()).isEqualTo(1); } @Test public void itCancelsPendingBuild() { RepositoryBuild repositoryBuild = repositoryBuildService.get(buildIdOne).get(); repositoryBuildService.cancel(repositoryBuild); assertThat(repositoryBuildService.get(buildIdOne).isPresent()).isFalse(); BuildNumbers buildNumbers = repositoryBuildService.getBuildNumbers(branchOne.getId().get()); assertThat(buildNumbers.getPendingBuildId().isPresent()).isFalse(); assertThat(buildNumbers.getPendingBuildNumber().isPresent()).isFalse(); } @Test public void itCancelsExtraQueuedBuildProperly() { BuildTrigger manualTrigger = BuildTrigger.forUser("test"); long newBuildId = repositoryBuildService.enqueue(branchOne, manualTrigger, buildOptionsOne); assertThat(newBuildId).isNotEqualTo(buildIdOne); RepositoryBuild repositoryBuild = repositoryBuildService.get(newBuildId).get(); repositoryBuildService.cancel(repositoryBuild); assertThat(repositoryBuildService.get(newBuildId).isPresent()).isFalse(); BuildNumbers buildNumbers = repositoryBuildService.getBuildNumbers(branchOne.getId().get()); assertThat(buildNumbers.getPendingBuildId().get()).isEqualTo(buildIdOne); assertThat(buildNumbers.getPendingBuildNumber().get()).isEqualTo(1); } @Test public void itMovesNextQueuedBuildIntoPendingSlotProperly() { BuildTrigger manualTrigger = BuildTrigger.forUser("test"); long newBuildId = repositoryBuildService.enqueue(branchOne, manualTrigger, buildOptionsOne); assertThat(newBuildId).isNotEqualTo(buildIdOne); RepositoryBuild repositoryBuild = repositoryBuildService.get(buildIdOne).get(); repositoryBuildService.cancel(repositoryBuild); assertThat(repositoryBuildService.get(buildIdOne).isPresent()).isFalse(); BuildNumbers buildNumbers = repositoryBuildService.getBuildNumbers(branchOne.getId().get()); assertThat(buildNumbers.getPendingBuildId().get()).isEqualTo(newBuildId); assertThat(buildNumbers.getPendingBuildNumber().get()).isEqualTo(2); } private static void validateBuild(RepositoryBuild expected, RepositoryBuild actual) { assertThat(actual.getBranchId()).isEqualTo(expected.getBranchId()); assertThat(actual.getBuildNumber()).isEqualTo(expected.getBuildNumber()); assertThat(actual.getState()).isEqualTo(expected.getState()); assertThat(actual.getBuildTrigger()).isEqualTo(expected.getBuildTrigger()); assertThat(actual.getBuildOptions()).isEqualTo(expected.getBuildOptions()); assertThat(actual.getStartTimestamp()).isEqualTo(expected.getStartTimestamp()); assertThat(actual.getEndTimestamp()).isEqualTo(expected.getEndTimestamp()); assertThat(actual.getSha()).isEqualTo(expected.getSha()); assertThat(actual.getCommitInfo()).isEqualTo(expected.getCommitInfo()); assertThat(actual.getDependencyGraph()).isEqualTo(expected.getDependencyGraph()); } }