diff --git a/view/src/main/java/se/su/dsv/scipro/crosscutting/ReviewerAssignedDeadline.java b/core/src/main/java/se/su/dsv/scipro/reviewing/ReviewerAssignedDeadline.java similarity index 99% rename from view/src/main/java/se/su/dsv/scipro/crosscutting/ReviewerAssignedDeadline.java rename to core/src/main/java/se/su/dsv/scipro/reviewing/ReviewerAssignedDeadline.java index c7d9d7a1cb..3e1c8bf390 100644 --- a/view/src/main/java/se/su/dsv/scipro/crosscutting/ReviewerAssignedDeadline.java +++ b/core/src/main/java/se/su/dsv/scipro/reviewing/ReviewerAssignedDeadline.java @@ -1,4 +1,4 @@ -package se.su.dsv.scipro.crosscutting; +package se.su.dsv.scipro.reviewing; import com.google.common.eventbus.EventBus; import com.google.common.eventbus.Subscribe; diff --git a/core/src/test/java/se/su/dsv/scipro/reviewing/ReviewerTest.java b/core/src/test/java/se/su/dsv/scipro/reviewing/ReviewerTest.java new file mode 100644 index 0000000000..f3ce8806a1 --- /dev/null +++ b/core/src/test/java/se/su/dsv/scipro/reviewing/ReviewerTest.java @@ -0,0 +1,126 @@ +package se.su.dsv.scipro.reviewing; + +import jakarta.inject.Inject; +import org.junit.jupiter.api.Test; +import se.su.dsv.scipro.file.FileUpload; +import se.su.dsv.scipro.project.Project; +import se.su.dsv.scipro.reviewing.ReviewerAssignmentService.ReviewerAssignment; +import se.su.dsv.scipro.security.auth.roles.Roles; +import se.su.dsv.scipro.system.DegreeType; +import se.su.dsv.scipro.system.ProjectType; +import se.su.dsv.scipro.system.User; +import se.su.dsv.scipro.test.MutableFixedClock; +import se.su.dsv.scipro.util.Either; + +import java.io.InputStream; +import java.time.LocalDate; +import java.time.Month; +import java.time.Year; +import java.util.Optional; +import java.util.Set; +import java.util.function.Function; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertTrue; + +public class ReviewerTest extends ReviewingModuleTest { + + @Inject + MutableFixedClock clock; + @Inject + ReviewerAssignmentService reviewerAssignmentService; + @Inject + ReviewerCapacityService reviewerCapacityService; + @Inject + RoughDraftApprovalService roughDraftApprovalService; + @Inject + ReviewerDecisionService reviewerDecisionService; + + @Test + public void an_assigned_reviewer_should_only_consume_one_target_per_project() { + // Given + clock.setDate(LocalDate.of(2024, Month.MAY, 22)); // some date in spring + + Project project = createProject(); + User reviewer = createUser(); + var target = new ReviewerCapacityService.Target(Year.now(clock), 2, 0, "Can review at any time"); + + // When + reviewerCapacityService.assignTarget(reviewer, target); + Either<AlreadyRequested, RoughDraftApproval> firstReviewRequest = roughDraftApprovalService.requestApproval( + project, + dummyFile(), + "Some comment"); + assertTrue(firstReviewRequest.isRight()); + + ReviewerAssignment assignment = reviewerAssignmentService.assignReviewer(project,reviewer); + assertEquals(ReviewerAssignment.OK, assignment); + + reviewerDecisionService.reject(firstReviewRequest.right(), "Not good enough", Optional.empty()); + + Either<AlreadyRequested, RoughDraftApproval> secondReviewRequest = roughDraftApprovalService.requestApproval( + project, + dummyFile(), + "Some new comment"); + assertTrue(secondReviewRequest.isRight()); + + // Then + ReviewerCapacityService.RemainingTargets remainingTargets = + reviewerCapacityService.getRemainingTargets(reviewer, target.year()); + assertEquals(1, remainingTargets.spring()); + } + + private User createUser() { + User user = User.builder() + .firstName("Edward") + .lastName("Employee") + .emailAddress("stuart@example.com") + .roles(Set.of(Roles.REVIEWER, Roles.SUPERVISOR)) + .build(); + return save(user); + } + + private Project createProject() { + ProjectType bachelor = new ProjectType(DegreeType.BACHELOR, "Bachelor", "Bachelor"); + save(bachelor); + + User supervisor = createUser(); + + Project project = Project.builder() + .title("A project") + .projectType(bachelor) + .startDate(LocalDate.now(clock).minusMonths(1)) + .headSupervisor(supervisor) + .build(); + return save(project); + } + + private FileUpload dummyFile() { + return new FileUpload() { + @Override + public String getFileName() { + return "dummy.tmp"; + } + + @Override + public String getContentType() { + return "text/plain"; + } + + @Override + public User getUploader() { + return null; + } + + @Override + public long getSize() { + return 0; + } + + @Override + public <T> T handleData(Function<InputStream, T> handler) { + return handler.apply(InputStream.nullInputStream()); + } + }; + } +} diff --git a/core/src/test/java/se/su/dsv/scipro/reviewing/ReviewingModuleTest.java b/core/src/test/java/se/su/dsv/scipro/reviewing/ReviewingModuleTest.java index 6033f32e54..8d59c17234 100644 --- a/core/src/test/java/se/su/dsv/scipro/reviewing/ReviewingModuleTest.java +++ b/core/src/test/java/se/su/dsv/scipro/reviewing/ReviewingModuleTest.java @@ -1,7 +1,18 @@ package se.su.dsv.scipro.reviewing; +import com.google.inject.AbstractModule; +import com.google.inject.Module; import se.su.dsv.scipro.test.IntegrationTest; public abstract class ReviewingModuleTest extends IntegrationTest { - + @Override + protected Module moduleUnderTest() { + return new AbstractModule() { + @Override + protected void configure() { + install(ReviewingModuleTest.super.moduleUnderTest()); + bind(ReviewerAssignedDeadline.class).asEagerSingleton(); + } + }; + } } diff --git a/view/src/main/java/se/su/dsv/scipro/crosscutting/CrosscuttingModule.java b/view/src/main/java/se/su/dsv/scipro/crosscutting/CrosscuttingModule.java index 9f583db6d6..fc50e7ff37 100644 --- a/view/src/main/java/se/su/dsv/scipro/crosscutting/CrosscuttingModule.java +++ b/view/src/main/java/se/su/dsv/scipro/crosscutting/CrosscuttingModule.java @@ -2,6 +2,7 @@ package se.su.dsv.scipro.crosscutting; import com.google.common.eventbus.EventBus; import com.google.inject.AbstractModule; +import se.su.dsv.scipro.reviewing.ReviewerAssignedDeadline; public class CrosscuttingModule extends AbstractModule { @Override