From 82334427e40a834295e0f43298909959f78b73ec Mon Sep 17 00:00:00 2001 From: Liam Clark Date: Tue, 27 Dec 2016 18:14:14 +0100 Subject: [PATCH] On handing an assignment automatically fill in the build penaltiy rubric --- .../ConsecutiveBuildFailureBackend.java | 118 ++++++++++++ .../server/database/controllers/Commits.java | 7 + .../database/controllers/Deliveries.java | 11 ++ .../server/database/entities/Assignment.java | 6 +- .../server/database/entities/Delivery.java | 29 ++- .../server/web/resources/HooksResource.java | 42 +++-- .../resources/ProjectAssignmentsResource.java | 16 +- .../ConsecutiveBuildFailureBackendTest.java | 172 ++++++++++++++++++ .../ProjectAssignmentsResourceTest.java | 2 +- 9 files changed, 377 insertions(+), 26 deletions(-) create mode 100644 src/main/java/nl/tudelft/ewi/devhub/server/backend/ConsecutiveBuildFailureBackend.java create mode 100644 src/test/java/nl/tudelft/ewi/devhub/server/backend/ConsecutiveBuildFailureBackendTest.java diff --git a/src/main/java/nl/tudelft/ewi/devhub/server/backend/ConsecutiveBuildFailureBackend.java b/src/main/java/nl/tudelft/ewi/devhub/server/backend/ConsecutiveBuildFailureBackend.java new file mode 100644 index 00000000..35a50868 --- /dev/null +++ b/src/main/java/nl/tudelft/ewi/devhub/server/backend/ConsecutiveBuildFailureBackend.java @@ -0,0 +1,118 @@ +package nl.tudelft.ewi.devhub.server.backend; + +import com.google.common.collect.Lists; +import com.google.inject.Inject; +import nl.tudelft.ewi.devhub.server.database.controllers.Commits; +import nl.tudelft.ewi.devhub.server.database.controllers.Deliveries; +import nl.tudelft.ewi.devhub.server.database.entities.Assignment; +import nl.tudelft.ewi.devhub.server.database.entities.Commit; +import nl.tudelft.ewi.devhub.server.database.entities.Delivery; +import nl.tudelft.ewi.devhub.server.database.entities.Group; + +import java.util.ArrayList; +import java.util.List; +import java.util.Optional; + +import static java.util.stream.Collectors.toList; + +/** + * Checks whether between the previous assignments delivery and the current deliver, or the start of time if it's the first assignment + * any commits through any branches that are reachable from the commit that has been handed in contained 4 or more consecutive build failures. + */ +public class ConsecutiveBuildFailureBackend { + public static final int MAX_CONSECUTIVE_BUILD_FAILURES = 4; + private Commits commits; + private Deliveries deliveries; + + @Inject + public ConsecutiveBuildFailureBackend(Commits commits, Deliveries deliveries) { + this.commits = commits; + this.deliveries = deliveries; + } + + public boolean hasConsecutiveBuildFailures(Group group, Delivery delivery) { + final List> commitsToCheck = commitsToCheckForBuildFailures(group, delivery); + return consecutiveBuildFailures(commitsToCheck); + } + + protected static boolean consecutiveBuildFailures(List> commitsToCheck) { + return commitsToCheck.stream().anyMatch(ConsecutiveBuildFailureBackend::hasFourFailingCommits); + } + + + protected static boolean hasFourFailingCommits(List commits) { + int consecutive = 0; + + for (Commit commit : commits) { + if (commit.getBuildResult().hasFailed()) { + consecutive++; + if (consecutive == MAX_CONSECUTIVE_BUILD_FAILURES) { + return true; + } + } else { + consecutive = 0; + } + } + + return false; + } + + protected Optional findRootCommit(Group group, Delivery delivery) { + final List assignments = group.getCourseEdition().getAssignments().stream() + .sorted(Assignment::compareTo) + .collect(toList()); + + final int index = assignments.indexOf(delivery.getAssignment()); + final boolean firstAssignment = index < 1; + + if (firstAssignment) { + return commits.firstCommitInRepo(group.getRepository()); + } else { + final Assignment previousAssignment = assignments.get(index - 1); + return deliveries.getLastDelivery(previousAssignment, group).map(Delivery::getCommit); + } + } + + protected List> commitsToCheckForBuildFailures(Group group, Delivery delivery) { + final Commit deliveryCommit = delivery.getCommit(); + Optional>> commits = findRootCommit(group, delivery).map(prevCommit -> commitsTillRoot(deliveryCommit, prevCommit)); + + return commits.orElse(Lists.newArrayList()); + } + + protected static List> commitsTillRoot(Commit commit, Commit root) { + List> commits = Lists.newArrayList(); + commitsBetween(commit, root, commits, new ArrayList<>()); + + return commits; + } + + private static void commitsBetween(Commit current, Commit root, List> allCommitPaths, List currentCommits) { + currentCommits.add(current); + + if (isPastEnd(current, root)) { + allCommitPaths.add(currentCommits); + } else { + List parents = current.getParents(); + if (parents.size() == 1) { + commitsBetween(parents.get(0), root, allCommitPaths, currentCommits); + } else { + for (Commit commit : parents) { + List currentCopy = Lists.newArrayList(currentCommits); + commitsBetween(commit, root, allCommitPaths, currentCopy); + } + } + } + } + + /** + * We are at the end of commits to consider for consecutive build failures if we either rejoined the last commit or are past it in time. + * + * @param end the commit of the last delivery for the previous assignment. + * @param commit the commit we are considering right now. + * @return true if the current commit shouldn't be considered anymore. + */ + private static boolean isPastEnd(Commit end, Commit commit) { + return commit.getCommitTime().before(end.getCommitTime()) || commit.equals(end); + } +} diff --git a/src/main/java/nl/tudelft/ewi/devhub/server/database/controllers/Commits.java b/src/main/java/nl/tudelft/ewi/devhub/server/database/controllers/Commits.java index 0f7590a8..29233a76 100644 --- a/src/main/java/nl/tudelft/ewi/devhub/server/database/controllers/Commits.java +++ b/src/main/java/nl/tudelft/ewi/devhub/server/database/controllers/Commits.java @@ -36,6 +36,13 @@ public Optional retrieve(RepositoryEntity repository, String commitId) { return Optional.ofNullable(entityManager.find(Commit.class, key)); } + public Optional firstCommitInRepo(RepositoryEntity repositoryEntity) { + return Optional.ofNullable(query().from(commit) + .where(commit.repository.eq(repositoryEntity)) + .orderBy(commit.commitTime.asc()) + .singleResult(commit)); + } + /** * Ensure that a commit exists in the database. Recursively check if the parents exists as well. * diff --git a/src/main/java/nl/tudelft/ewi/devhub/server/database/controllers/Deliveries.java b/src/main/java/nl/tudelft/ewi/devhub/server/database/controllers/Deliveries.java index f2b156fe..adaca6d3 100644 --- a/src/main/java/nl/tudelft/ewi/devhub/server/database/controllers/Deliveries.java +++ b/src/main/java/nl/tudelft/ewi/devhub/server/database/controllers/Deliveries.java @@ -1,11 +1,13 @@ package nl.tudelft.ewi.devhub.server.database.controllers; import nl.tudelft.ewi.devhub.server.database.entities.Assignment; +import nl.tudelft.ewi.devhub.server.database.entities.Commit; import nl.tudelft.ewi.devhub.server.database.entities.Delivery; import nl.tudelft.ewi.devhub.server.database.entities.Group; import com.google.inject.Inject; import com.google.inject.persist.Transactional; +import nl.tudelft.ewi.devhub.server.database.entities.rubrics.Mastery; import javax.persistence.EntityManager; import java.util.Comparator; @@ -111,6 +113,15 @@ public Delivery find(Group group, long deliveryId) { "No delivery found for id " + deliveryId); } + + public Optional deliveryForCommit(Commit commit) { + return Optional.ofNullable( + query().from(delivery) + .where(delivery.commit.eq(commit)) + .singleResult(delivery) + ); + } + /** * Return the most recent deliveries. * @param groups Groups to search deliveries for. diff --git a/src/main/java/nl/tudelft/ewi/devhub/server/database/entities/Assignment.java b/src/main/java/nl/tudelft/ewi/devhub/server/database/entities/Assignment.java index 7aaa9ade..6613f7b1 100644 --- a/src/main/java/nl/tudelft/ewi/devhub/server/database/entities/Assignment.java +++ b/src/main/java/nl/tudelft/ewi/devhub/server/database/entities/Assignment.java @@ -8,9 +8,7 @@ import lombok.ToString; import nl.tudelft.ewi.devhub.server.database.Base; import nl.tudelft.ewi.devhub.server.database.entities.identity.FKSegmentedIdentifierGenerator; -import nl.tudelft.ewi.devhub.server.database.entities.rubrics.DutchGradingStrategy; -import nl.tudelft.ewi.devhub.server.database.entities.rubrics.GradingStrategy; -import nl.tudelft.ewi.devhub.server.database.entities.rubrics.Task; +import nl.tudelft.ewi.devhub.server.database.entities.rubrics.*; import com.fasterxml.jackson.annotation.JsonBackReference; import com.fasterxml.jackson.annotation.JsonIgnoreProperties; @@ -43,6 +41,7 @@ import java.net.URI; import java.util.Date; import java.util.List; +import java.util.Optional; /** * Created by jgmeligmeyling on 04/03/15. @@ -124,6 +123,7 @@ public double getNumberOfAchievablePoints() { .sum(); } + @JsonIgnore public GradingStrategy getGradingStrategy() { return new DutchGradingStrategy(); diff --git a/src/main/java/nl/tudelft/ewi/devhub/server/database/entities/Delivery.java b/src/main/java/nl/tudelft/ewi/devhub/server/database/entities/Delivery.java index 15027b34..b5cf5246 100644 --- a/src/main/java/nl/tudelft/ewi/devhub/server/database/entities/Delivery.java +++ b/src/main/java/nl/tudelft/ewi/devhub/server/database/entities/Delivery.java @@ -9,7 +9,6 @@ import nl.tudelft.ewi.devhub.server.database.entities.rubrics.Mastery; import com.fasterxml.jackson.annotation.JsonBackReference; -import com.fasterxml.jackson.annotation.JsonIdentityInfo; import com.fasterxml.jackson.annotation.JsonIgnore; import com.fasterxml.jackson.annotation.JsonManagedReference; @@ -43,11 +42,7 @@ import javax.persistence.TemporalType; import javax.validation.constraints.NotNull; import java.net.URI; -import java.util.Collection; -import java.util.Comparator; -import java.util.Date; -import java.util.List; -import java.util.Map; +import java.util.*; /** * Delivery for an assignment @@ -239,6 +234,28 @@ public boolean isLate() { return dueDate != null && getTimestamp().after(dueDate); } + @JsonIgnore + public void setBuildFailed() { + Optional buildFailureMastery = findMasteryByDescription("Build for submitted commit fails"); + buildFailureMastery.ifPresent(mastery -> this.getRubrics().put(mastery.getCharacteristic(), mastery)); + } + + @JsonIgnore + public void setConsecutiveBuildFailures() { + Optional buildFailureMastery = findMasteryByDescription("Four subsequent failing"); + buildFailureMastery.ifPresent(mastery -> this.getRubrics().put(mastery.getCharacteristic(), mastery)); + } + + @JsonIgnore + private Optional findMasteryByDescription(String description) { + return this.getAssignment().getTasks().stream() + .flatMap(tasks -> tasks.getCharacteristics().stream()) + .filter(mastery -> mastery.getDescription().equals("Build failure penalty")) + .findAny().flatMap(characteristic -> characteristic.getLevels().stream() + .filter(mastery -> mastery.getDescription().contains(description)) + .findAny()); + } + @Override public URI getURI() { return getGroup().getURI() diff --git a/src/main/java/nl/tudelft/ewi/devhub/server/web/resources/HooksResource.java b/src/main/java/nl/tudelft/ewi/devhub/server/web/resources/HooksResource.java index 3db9da71..3ce89e78 100644 --- a/src/main/java/nl/tudelft/ewi/devhub/server/web/resources/HooksResource.java +++ b/src/main/java/nl/tudelft/ewi/devhub/server/web/resources/HooksResource.java @@ -17,14 +17,13 @@ import nl.tudelft.ewi.devhub.server.backend.warnings.PMDWarningGenerator; import nl.tudelft.ewi.devhub.server.backend.warnings.PMDWarningGenerator.PMDReport; import nl.tudelft.ewi.devhub.server.backend.warnings.SuccessiveBuildFailureGenerator; -import nl.tudelft.ewi.devhub.server.database.controllers.BuildResults; -import nl.tudelft.ewi.devhub.server.database.controllers.Commits; -import nl.tudelft.ewi.devhub.server.database.controllers.PullRequests; -import nl.tudelft.ewi.devhub.server.database.controllers.RepositoriesController; -import nl.tudelft.ewi.devhub.server.database.controllers.Warnings; +import nl.tudelft.ewi.devhub.server.database.controllers.*; import nl.tudelft.ewi.devhub.server.database.entities.BuildResult; import nl.tudelft.ewi.devhub.server.database.entities.Commit; +import nl.tudelft.ewi.devhub.server.database.entities.Delivery; import nl.tudelft.ewi.devhub.server.database.entities.RepositoryEntity; +import nl.tudelft.ewi.devhub.server.database.entities.rubrics.Characteristic; +import nl.tudelft.ewi.devhub.server.database.entities.rubrics.Mastery; import nl.tudelft.ewi.devhub.server.database.entities.warnings.CheckstyleWarning; import nl.tudelft.ewi.devhub.server.database.entities.warnings.CommitWarning; import nl.tudelft.ewi.devhub.server.database.entities.warnings.FindbugsWarning; @@ -57,8 +56,11 @@ import javax.ws.rs.core.MediaType; import java.io.UnsupportedEncodingException; import java.util.Locale; +import java.util.Map; +import java.util.Optional; import java.util.Set; import java.util.concurrent.ExecutorService; +import java.util.function.BiFunction; import java.util.stream.Collectors; import java.util.stream.Stream; @@ -83,19 +85,20 @@ public class HooksResource extends Resource { private final FindBugsWarningGenerator findBugsWarningGenerator; private final SuccessiveBuildFailureGenerator successiveBuildFailureGenerator; private final ExecutorService executor; + private final Deliveries deliveries; @Inject public HooksResource(BuildResults buildResults, - Commits commits, - Warnings warnings, - BuildResultMailer mailer, - ExecutorService executor, - PMDWarningGenerator pmdWarningGenerator, - GitPushHandlerWorkerFactory gitPushHandlerWorkerFactory, - RepositoriesController repositoriesController, - FindBugsWarningGenerator findBugsWarningGenerator, - CheckstyleWarningGenerator checkstyleWarningGenerator, - SuccessiveBuildFailureGenerator successiveBuildFailureGenerator) { + Commits commits, + Warnings warnings, + BuildResultMailer mailer, + ExecutorService executor, + PMDWarningGenerator pmdWarningGenerator, + GitPushHandlerWorkerFactory gitPushHandlerWorkerFactory, + RepositoriesController repositoriesController, + FindBugsWarningGenerator findBugsWarningGenerator, + CheckstyleWarningGenerator checkstyleWarningGenerator, + SuccessiveBuildFailureGenerator successiveBuildFailureGenerator, Deliveries deliveries) { this.mailer = mailer; this.commits = commits; this.warnings = warnings; @@ -107,6 +110,7 @@ public HooksResource(BuildResults buildResults, this.findBugsWarningGenerator = findBugsWarningGenerator; this.checkstyleWarningGenerator = checkstyleWarningGenerator; this.successiveBuildFailureGenerator = successiveBuildFailureGenerator; + this.deliveries = deliveries; } /** @@ -265,6 +269,7 @@ public void onBuildResult(@QueryParam("repository") @NotEmpty String repository, RepositoryEntity repositoryEntity = repositoriesController.find(repoName); Commit commit = commits.ensureExists(repositoryEntity, commitId); + BuildResult result; try { result = buildResults.find(repositoryEntity, commitId); @@ -285,6 +290,7 @@ public void onBuildResult(@QueryParam("repository") @NotEmpty String repository, if (!result.getSuccess()) { mailer.sendFailedBuildResult(Lists.newArrayList(Locale.ENGLISH), result); + fillInBuildFailureRubric(commit); } try { @@ -294,9 +300,15 @@ public void onBuildResult(@QueryParam("repository") @NotEmpty String repository, catch (Exception e) { log.warn("Failed to persist sucessive build failure for {}", e, result); } + } + @Transactional + public void fillInBuildFailureRubric(Commit commit) { + deliveries.deliveryForCommit(commit) + .ifPresent(Delivery::setBuildFailed); } + @POST @Path("pmd-result") @RequireAuthenticatedBuildServer diff --git a/src/main/java/nl/tudelft/ewi/devhub/server/web/resources/ProjectAssignmentsResource.java b/src/main/java/nl/tudelft/ewi/devhub/server/web/resources/ProjectAssignmentsResource.java index 3dc044f1..e62ba2ff 100644 --- a/src/main/java/nl/tudelft/ewi/devhub/server/web/resources/ProjectAssignmentsResource.java +++ b/src/main/java/nl/tudelft/ewi/devhub/server/web/resources/ProjectAssignmentsResource.java @@ -10,6 +10,7 @@ import com.google.inject.servlet.RequestScoped; import lombok.Data; import lombok.extern.slf4j.Slf4j; +import nl.tudelft.ewi.devhub.server.backend.ConsecutiveBuildFailureBackend; import nl.tudelft.ewi.devhub.server.backend.DeliveriesBackend; import nl.tudelft.ewi.devhub.server.database.controllers.Assignments; import nl.tudelft.ewi.devhub.server.database.controllers.BuildResults; @@ -69,6 +70,7 @@ public class ProjectAssignmentsResource extends Resource { private final Deliveries deliveries; private final DeliveriesBackend deliveriesBackend; private final Assignments assignments; + private final ConsecutiveBuildFailureBackend consecutiveBuildFailureBackend; @Inject public ProjectAssignmentsResource(final TemplateEngine templateEngine, @@ -79,7 +81,8 @@ public ProjectAssignmentsResource(final TemplateEngine templateEngine, final RepositoriesApi repositoriesApi, final DeliveriesBackend deliveriesBackend, final Assignments assignments, - final Commits commits) { + final Commits commits, + ConsecutiveBuildFailureBackend consecutiveBuildFailureBackend) { this.templateEngine = templateEngine; this.group = group; @@ -91,6 +94,7 @@ public ProjectAssignmentsResource(final TemplateEngine templateEngine, this.deliveriesBackend = deliveriesBackend; this.assignments = assignments; this.commits = commits; + this.consecutiveBuildFailureBackend = consecutiveBuildFailureBackend; } protected Map getBaseParameters() { @@ -188,6 +192,7 @@ protected boolean canSeeGrade(Assignment assignment) { @POST @Path("{assignmentId : \\d+}") @Consumes(MediaType.MULTIPART_FORM_DATA) + @Transactional public Response postAssignment(@Context HttpServletRequest request, @PathParam("assignmentId") long assignmentId, MultipartFormDataInput formData) throws IOException, ApiError { @@ -198,12 +203,20 @@ public Response postAssignment(@Context HttpServletRequest request, Assignment assignment = assignments.find(group.getCourse(), assignmentId); + Delivery delivery = new Delivery(); delivery.setAssignment(assignment); delivery.setCommit(commits.ensureExists(repositoryEntity, commitId)); delivery.setNotes(notes); delivery.setGroup(group); + + Optional.of(delivery).filter(d -> d.getCommit().getBuildResult().hasFailed()).ifPresent(Delivery::setBuildFailed); + if (consecutiveBuildFailureBackend.hasConsecutiveBuildFailures(group, delivery)) { + delivery.setConsecutiveBuildFailures(); + } + + deliveriesBackend.deliver(delivery); addAttachments(formDataMap, delivery); @@ -215,6 +228,7 @@ public Response postAssignment(@Context HttpServletRequest request, return redirect(request.getRequestURI()); } + private void addAttachments(Map> formDataMap, Delivery delivery) throws IOException, ApiError { List attachments = formDataMap.get("file-attachment"); for(InputPart attachment : attachments) { diff --git a/src/test/java/nl/tudelft/ewi/devhub/server/backend/ConsecutiveBuildFailureBackendTest.java b/src/test/java/nl/tudelft/ewi/devhub/server/backend/ConsecutiveBuildFailureBackendTest.java new file mode 100644 index 00000000..f8a48792 --- /dev/null +++ b/src/test/java/nl/tudelft/ewi/devhub/server/backend/ConsecutiveBuildFailureBackendTest.java @@ -0,0 +1,172 @@ +package nl.tudelft.ewi.devhub.server.backend; + +import com.google.common.collect.Lists; +import lombok.AllArgsConstructor; +import nl.tudelft.ewi.devhub.server.database.controllers.Commits; +import nl.tudelft.ewi.devhub.server.database.controllers.Deliveries; +import nl.tudelft.ewi.devhub.server.database.entities.*; +import org.junit.Before; +import org.junit.Test; +import org.junit.experimental.runners.Enclosed; +import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.mockito.runners.MockitoJUnitRunner; + +import java.util.Date; +import java.util.List; +import java.util.Optional; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; +import static org.mockito.Matchers.any; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +@RunWith(Enclosed.class) +public class ConsecutiveBuildFailureBackendTest { + + @RunWith(MockitoJUnitRunner.class) + public static class RootCommitTests { + private ConsecutiveBuildFailureBackend commitChecking; + private Date now = new Date(); + + @Mock + private Deliveries deliveries; + @Mock + private Commits commits; + @Mock + private Group group; + @Mock + private CourseEdition courseEdition; + @Mock + private Commit firstCommit; + @Mock + private Delivery delivery; + + + @Before + public void setUp() { + commitChecking = new ConsecutiveBuildFailureBackend(commits, deliveries); + when(group.getCourseEdition()).thenReturn(courseEdition); + when(commits.firstCommitInRepo(any())).thenReturn(Optional.of(firstCommit)); + } + + @Test + public void testFindRootCommitNoPreviousDelivery() { + Optional rootCommit = commitChecking.findRootCommit(group, delivery); + assertEquals(firstCommit, rootCommit.get()); + } + + @Test + public void testFindRootCommit() { + Assignment handedIn = mock(Assignment.class); + Assignment previous = mock(Assignment.class); + + //assignments need to be in this order since sorting on mocks is a bit weird. + when(courseEdition.getAssignments()).thenReturn(Lists.newArrayList(previous, handedIn)); + when(deliveries.getLastDelivery(previous, group)).thenReturn(Optional.of(delivery)); + when(delivery.getCommit()).thenReturn(firstCommit); + when(delivery.getAssignment()).thenReturn(handedIn); + + Optional rootCommit = commitChecking.findRootCommit(group, delivery); + assertEquals(firstCommit, rootCommit.get()); + } + } + + public static class CommitGraphTest { + private Date now = new Date(); + + @Test + public void testCommitTraversalHasRightDimensions() { + CommitGraph graph = graphWithConsecutiveFailures(); + List> commitsTillRoot = ConsecutiveBuildFailureBackend.commitsTillRoot(graph.end, graph.root); + + //we have two branches. + assertEquals(2, commitsTillRoot.size()); + // the first branch has 7 commits in it. + assertEquals(7, commitsTillRoot.get(0).size()); + } + + @Test + public void testConsecutiveBuildFailures() { + CommitGraph graph = graphWithConsecutiveFailures(); + List> commitsTillRoot = ConsecutiveBuildFailureBackend.commitsTillRoot(graph.end, graph.root); + assertTrue(ConsecutiveBuildFailureBackend.consecutiveBuildFailures(commitsTillRoot)); + } + + @Test + public void testNoConsecutiveBuildFailures() { + CommitGraph graph = graphWithNoConsecutiveFailures(); + List> commitsTillRoot = ConsecutiveBuildFailureBackend.commitsTillRoot(graph.end, graph.root); + assertFalse(ConsecutiveBuildFailureBackend.consecutiveBuildFailures(commitsTillRoot)); + } + + /** + * represent the following commit graphWithConsecutiveFailures + * B - D - E - F - G + * / \ + * AD - C - HD + *

+ * where D E F G had failures + * and a postfix d is a failure. + */ + private CommitGraph graphWithConsecutiveFailures() { + Commit a = commitWithBuildResult(success(), "a"); + + Commit b = withBuildResultAndParent(a, success(), "b"); + Commit c = withBuildResultAndParent(a, success(), "c"); + + Commit d = withBuildResultAndParent(b, failure(), "d"); + Commit e = withBuildResultAndParent(d, failure(), "e"); + Commit f = withBuildResultAndParent(e, failure(), "f"); + Commit g = withBuildResultAndParent(f, failure(), "g"); + + Commit h = commitWithBuildResult(success(), "h"); + h.setParents(Lists.newArrayList(g, c)); + + return new CommitGraph(a, h); + } + + private CommitGraph graphWithNoConsecutiveFailures() { + Commit a = commitWithBuildResult(success(), "a"); + Commit b = withBuildResultAndParent(a, success(), "b"); + + return new CommitGraph(a,b); + } + + private Commit commitWithBuildResult(BuildResult result, String id) { + Commit commit = new Commit(); + commit.setBuildResult(result); + result.setCommit(commit); + commit.setCommitTime(now); + commit.setCommitId(id); + + return commit; + } + + private Commit withBuildResultAndParent(Commit parent, BuildResult result, String id) { + Commit commit = commitWithBuildResult(result, id); + commit.setParents(Lists.newArrayList(parent)); + return commit; + } + + @AllArgsConstructor + public static class CommitGraph { + final Commit root; + final Commit end; + } + + public static BuildResult failure() { + BuildResult buildResult = new BuildResult(); + buildResult.setSuccess(false); + return buildResult; + } + + public static BuildResult success() { + BuildResult buildResult = new BuildResult(); + buildResult.setSuccess(true); + return buildResult; + } + } +} \ No newline at end of file diff --git a/src/test/java/nl/tudelft/ewi/devhub/server/web/resources/ProjectAssignmentsResourceTest.java b/src/test/java/nl/tudelft/ewi/devhub/server/web/resources/ProjectAssignmentsResourceTest.java index 34df82a4..d70b9ffb 100644 --- a/src/test/java/nl/tudelft/ewi/devhub/server/web/resources/ProjectAssignmentsResourceTest.java +++ b/src/test/java/nl/tudelft/ewi/devhub/server/web/resources/ProjectAssignmentsResourceTest.java @@ -33,7 +33,7 @@ public class ProjectAssignmentsResourceTest { @Before public void setUp() { - resource = new ProjectAssignmentsResource(null, user, group, null, null, null, null, null, null); + resource = new ProjectAssignmentsResource(null, user, group, null, null, null, null, null, null, null); Mockito.when(group.getCourseEdition()).thenReturn(edition); }