Skip to content

Commit

Permalink
Merge pull request #20 from hotungkhanh/kan-62/backend-tests
Browse files Browse the repository at this point in the history
unit tests for backend
  • Loading branch information
hotungkhanh authored Sep 24, 2024
2 parents 8e7b351 + 7288250 commit 83fba30
Show file tree
Hide file tree
Showing 7 changed files with 139 additions and 34 deletions.
22 changes: 22 additions & 0 deletions backend/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -57,11 +57,33 @@
<artifactId>quarkus-junit5</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-junit5-internal</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>io.rest-assured</groupId>
<artifactId>rest-assured</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>ai.timefold.solver</groupId>
<artifactId>timefold-solver-test</artifactId>
<version>1.13.0</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.awaitility</groupId>
<artifactId>awaitility</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.assertj</groupId>
<artifactId>assertj-core</artifactId>
<version>3.26.3</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-jdbc-postgresql</artifactId>
Expand Down
8 changes: 6 additions & 2 deletions backend/src/main/java/org/acme/TimetableResource.java
Original file line number Diff line number Diff line change
Expand Up @@ -31,16 +31,20 @@ public class TimetableResource {
@Inject
SolverManager<Timetable, String> solverManager;

private int jobId = 0;

@POST
public Timetable handleRequest(Timetable problem) throws ExecutionException, InterruptedException {
jobId += 1;
String name = "Job" + Integer.toString(jobId);

Timetable solution = solverManager.solve("job 1", problem).getFinalBestSolution();
Timetable solution = solverManager.solve(name, problem).getFinalBestSolution();
return solution;
}

@GET
@Produces(MediaType.APPLICATION_JSON)
public Timetable hello() throws ExecutionException, InterruptedException {
public Timetable solveExample() throws ExecutionException, InterruptedException {

Student a = new Student("a");
Student b = new Student("b");
Expand Down
21 changes: 21 additions & 0 deletions backend/src/main/java/org/acme/domain/Unit.java
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,27 @@ public Unit(int unitID, String name, Duration duration, List<Student> students,
this.wantsLab = wantsLab;
}

/**
* Creates a unit.
*
* @param unitID The unit’s ID.
* @param name The unit’s ID.
* @param duration The unit’s duration.
* @param students The list of students enrolled in the unit.
* @param wantsLab Whether the unit wants a laboratory room.
* @param room The unit's room.
*/
public Unit(int unitID, String name, DayOfWeek dayOfWeek, LocalTime startTime, Duration duration, List<Student> students, boolean wantsLab, Room room) {
this.unitID = unitID;
this.name = name;
this.dayOfWeek = dayOfWeek;
this.startTime = startTime;
this.duration = duration;
this.students = students;
this.wantsLab = wantsLab;
this.room = room;
}

public int getUnitID() {
return unitID;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ public Constraint[] defineConstraints(ConstraintFactory constraintFactory) {
/**
* Penalize 1 hard score for each student with overlapping units.
*/
private Constraint studentConflict(ConstraintFactory constraintFactory) {
public Constraint studentConflict(ConstraintFactory constraintFactory) {
// A student can be in at most one unit at the same time.
return constraintFactory
// Select each pair of conflicting units.
Expand All @@ -62,7 +62,7 @@ private Constraint studentConflict(ConstraintFactory constraintFactory) {
/**
* Penalize 1 hard score for each room with overlapping units.
*/
Constraint roomConflict(ConstraintFactory constraintFactory) {
public Constraint roomConflict(ConstraintFactory constraintFactory) {
// A room can accommodate at most one unit at the same time.
return constraintFactory
// Select each pair of 2 different units ...
Expand All @@ -81,7 +81,7 @@ Constraint roomConflict(ConstraintFactory constraintFactory) {
/**
* Penalize 1 soft score for each student overflowing the capacity of the room.
*/
Constraint roomCapacity(ConstraintFactory constraintFactory) {
public Constraint roomCapacity(ConstraintFactory constraintFactory) {
// A room cannot accommodate more students than its capacity.
return constraintFactory
.forEach(Unit.class)
Expand All @@ -94,7 +94,7 @@ Constraint roomCapacity(ConstraintFactory constraintFactory) {
/**
* Penalize 1 soft score for each laboratory unit not assigned to a laboratory.
*/
Constraint labPreference(ConstraintFactory constraintFactory) {
public Constraint labPreference(ConstraintFactory constraintFactory) {
// Some units prefer to have a laboratory room.
return constraintFactory
.forEach(Unit.class)
Expand Down
8 changes: 0 additions & 8 deletions backend/src/test/java/org/acme/TimetableResourceIT.java

This file was deleted.

20 changes: 0 additions & 20 deletions backend/src/test/java/org/acme/TimetableResourceTest.java

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
package org.acme.solver;

import java.time.DayOfWeek;
import java.time.Duration;
import java.time.LocalTime;
import java.util.List;

import org.acme.domain.*;

import jakarta.inject.Inject;
import ai.timefold.solver.test.api.score.stream.ConstraintVerifier;
import org.junit.jupiter.api.Test;

import io.quarkus.test.junit.QuarkusTest;

@QuarkusTest
public class TimetableConstraintProviderTest {
private static final Room ROOM1 = new Room("1", 2, true);
private static final Room ROOM2 = new Room("2", 2, false);
private static final Room ROOM3 = new Room("3", 2, true);
private static final Student STUDENT1 = new Student("student1");
private static final Student STUDENT2 = new Student("student2");
private static final Student STUDENT3 = new Student("student3");
private static final Student STUDENT4 = new Student("student4");
private static final Student STUDENT5 = new Student("student5");
private static final DayOfWeek DAY_OF_WEEK = DayOfWeek.MONDAY;
private static final LocalTime START_TIME = LocalTime.of(8, 0);
private static final Duration DURATION = Duration.ofMinutes(120);

@Inject
ConstraintVerifier<TimetableConstraintProvider, Timetable> constraintVerifier;

/**
* Student Constraint: Penalize 1 if a student is attending two units at the same time.
*/
@Test
void studentConflict() {
Unit firstUnit = new Unit(1, "unit1", DAY_OF_WEEK, START_TIME, DURATION, List.of(STUDENT1), true, ROOM1);
Unit conflictingUnit = new Unit(2, "unit2", DAY_OF_WEEK, START_TIME, DURATION, List.of(STUDENT1), false, ROOM2);
Unit nonConflictingUnit = new Unit(3, "unit3", DAY_OF_WEEK, START_TIME, DURATION, List.of(STUDENT2), true, ROOM3);
ConflictingUnit conflictingUnitPair = new ConflictingUnit(firstUnit, conflictingUnit, 1);

constraintVerifier.verifyThat(TimetableConstraintProvider::studentConflict)
.given(firstUnit, conflictingUnit, nonConflictingUnit, conflictingUnitPair)
.penalizesBy(1);
}

/**
* Room Constraint: Penalize 1 if a room is occupied by two units at the same time.
*/
@Test
void roomConflict() {
Unit firstUnit = new Unit(1, "unit1", DAY_OF_WEEK, START_TIME, DURATION, List.of(STUDENT1), true, ROOM1);
Unit conflictingUnit = new Unit(2, "unit2", DAY_OF_WEEK, START_TIME, DURATION, List.of(STUDENT2), true, ROOM1);
Unit nonConflictingUnit = new Unit(3, "unit3", DAY_OF_WEEK, START_TIME, DURATION, List.of(STUDENT3), false, ROOM2);
constraintVerifier.verifyThat(TimetableConstraintProvider::roomConflict)
.given(firstUnit, conflictingUnit, nonConflictingUnit)
.penalizesBy(1);
}

/**
* Room Capacity Constraint: Penalize 1 if a room is occupied by more students than its capacity.
*/
@Test
void roomCapacityConflict() {
Unit firstUnit = new Unit(1, "unit1", DAY_OF_WEEK, START_TIME, DURATION, List.of(STUDENT1), true, ROOM1);
Unit conflictingUnit = new Unit(2, "unit2", DAY_OF_WEEK, START_TIME, DURATION, List.of(STUDENT2, STUDENT3, STUDENT4), false, ROOM2);
Unit nonConflictingUnit = new Unit(3, "unit3", DAY_OF_WEEK, START_TIME, DURATION, List.of(STUDENT5), true, ROOM3);
constraintVerifier.verifyThat(TimetableConstraintProvider::roomCapacity)
.given(firstUnit, conflictingUnit, nonConflictingUnit)
.penalizesBy(1);
}

/**
* Lab Constraint: Penalize 1 if a non-lab room is occupied by a lab unit.
*/
@Test
void labConflict() {
Unit firstUnit = new Unit(1, "unit1", DAY_OF_WEEK, START_TIME, DURATION, List.of(STUDENT1), true, ROOM1);
Unit conflictingUnit = new Unit(2, "unit2", DAY_OF_WEEK, START_TIME, DURATION, List.of(STUDENT2), true, ROOM2);
Unit nonConflictingUnit = new Unit(3, "unit3", DAY_OF_WEEK, START_TIME, DURATION, List.of(STUDENT5), true, ROOM3);
constraintVerifier.verifyThat(TimetableConstraintProvider::labPreference)
.given(firstUnit, conflictingUnit, nonConflictingUnit)
.penalizesBy(1);
}
}

0 comments on commit 83fba30

Please sign in to comment.