From 1ccd41c4a6a3445c15da40a3e00f0c71df61d81c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Spada=20=E2=9A=94=EF=B8=8F?= <75368540+PierpaoloSpadafora@users.noreply.github.com> Date: Fri, 6 Dec 2024 16:41:05 +0100 Subject: [PATCH] fix --- .../demacs/rdm/utils/SchedulerTest.java | 62 ++++++++++++++++--- 1 file changed, 52 insertions(+), 10 deletions(-) diff --git a/Backend/src/test/java/unical/demacs/rdm/utils/SchedulerTest.java b/Backend/src/test/java/unical/demacs/rdm/utils/SchedulerTest.java index 89b29a3..e6e561c 100644 --- a/Backend/src/test/java/unical/demacs/rdm/utils/SchedulerTest.java +++ b/Backend/src/test/java/unical/demacs/rdm/utils/SchedulerTest.java @@ -14,16 +14,17 @@ import unical.demacs.rdm.persistence.enums.ScheduleStatus; import unical.demacs.rdm.persistence.repository.MachineRepository; import unical.demacs.rdm.persistence.repository.ScheduleRepository; -import unical.demacs.rdm.utils.Scheduler; import java.time.LocalDateTime; import java.util.*; import java.util.stream.Collectors; + import static org.junit.jupiter.api.Assertions.*; import static org.mockito.Mockito.*; @ExtendWith(MockitoExtension.class) public class SchedulerTest { + @Mock private ScheduleRepository scheduleRepository; @@ -31,14 +32,13 @@ public class SchedulerTest { private MachineRepository machineRepository; private Scheduler scheduler; - private List testSchedules; - private List testMachines; private Map machineTypes; @BeforeEach void setUp() { ObjectMapper objectMapper = new ObjectMapper(); objectMapper.registerModule(new JavaTimeModule()); + machineTypes = new HashMap<>(); for (int i = 1; i <= 3; i++) { MachineType type = new MachineType(); @@ -46,7 +46,8 @@ void setUp() { type.setName("Type " + i); machineTypes.put((long) i, type); } - testMachines = new ArrayList<>(); + + List testMachines = new ArrayList<>(); for (int i = 1; i <= 6; i++) { Machine machine = new Machine(); machine.setId((long) i); @@ -54,9 +55,12 @@ void setUp() { machine.setStatus(MachineStatus.AVAILABLE); testMachines.add(machine); } - testSchedules = createComplexTestSchedules(); + + List testSchedules = createComplexTestSchedules(); + when(scheduleRepository.findAll()).thenReturn(testSchedules); when(machineRepository.findAll()).thenReturn(testMachines); + scheduler = new Scheduler(scheduleRepository, machineRepository, new ModelMapperExtended(), objectMapper); } @@ -64,62 +68,84 @@ void setUp() { private List createComplexTestSchedules() { List schedules = new ArrayList<>(); LocalDateTime baseTime = LocalDateTime.now(); + for (int i = 1; i <= 9; i++) { Job job = new Job(); job.setId((long) i); + if (i <= 3) job.setPriority(JobPriority.HIGH); else if (i <= 6) job.setPriority(JobPriority.MEDIUM); else job.setPriority(JobPriority.LOW); + Schedule schedule = new Schedule(); schedule.setId((long) i); schedule.setJob(job); schedule.setMachineType(machineTypes.get((long) ((i - 1) % 3 + 1))); schedule.setStartTime(baseTime.plusHours(i)); + if (i % 3 == 0) schedule.setDuration(7200L); else if (i % 3 == 1) schedule.setDuration(3600L); else schedule.setDuration(1800L); + schedule.setDueDate(baseTime.plusDays(i % 3 + 1)); schedule.setStatus(ScheduleStatus.PENDING); + schedules.add(schedule); } + return schedules; } @Test void testScheduleByPriority() { scheduler.scheduleByPriority(); + List scheduledJobs = scheduleRepository.findAll(); + List highPriorityJobs = scheduledJobs.stream() .filter(s -> s.getJob().getPriority() == JobPriority.HIGH) .toList(); + assertFalse(highPriorityJobs.isEmpty(), "Should have high priority jobs"); + verifyMachineAssignments(scheduledJobs); + verifyNoTimeConflicts(scheduledJobs); + verifyPriorityOrdering(scheduledJobs); } @Test void testScheduleByDueDate() { scheduler.scheduleByDueDate(); + List scheduledJobs = scheduleRepository.findAll(); + verifyDueDatesRespected(scheduledJobs); + verifyMachineTypeCompatibility(scheduledJobs); + verifyLoadBalancing(scheduledJobs); } @Test void testScheduleByDuration() { scheduler.scheduleByDuration(); + List scheduledJobs = scheduleRepository.findAll(); + verifyDurationPreference(scheduledJobs); + verifyMachineUtilization(scheduledJobs); } @Test void testScheduleByEveryType() { scheduler.scheduleByEveryType(); + verify(scheduleRepository, times(3)).findAll(); verify(machineRepository, times(3)).findAll(); + List finalSchedule = scheduleRepository.findAll(); verifyValidSchedule(finalSchedule); } @@ -139,6 +165,7 @@ private void verifyNoTimeConflicts(List schedules) { if (s1 != s2 && Objects.equals(s1.getMachine(), s2.getMachine())) { LocalDateTime s1End = s1.getStartTime().plusSeconds(s1.getDuration()); LocalDateTime s2End = s2.getStartTime().plusSeconds(s2.getDuration()); + assertFalse( (s1.getStartTime().isBefore(s2End) && s1End.isAfter(s2.getStartTime())), String.format("Time conflict found between schedules %d and %d", @@ -153,18 +180,22 @@ private void verifyPriorityOrdering(List schedules) { List sortedSchedules = schedules.stream() .sorted(Comparator.comparing(Schedule::getStartTime)) .toList(); + int highPriorityEarly = 0; int totalHighPriority = 0; + for (int i = 0; i < sortedSchedules.size() / 2; i++) { if (sortedSchedules.get(i).getJob().getPriority() == JobPriority.HIGH) { highPriorityEarly++; } } + for (Schedule schedule : sortedSchedules) { if (schedule.getJob().getPriority() == JobPriority.HIGH) { totalHighPriority++; } } + assertTrue(highPriorityEarly > totalHighPriority / 3, "Most high priority jobs should be scheduled earlier"); } @@ -184,27 +215,37 @@ private void verifyLoadBalancing(List schedules) { Schedule::getMachine, Collectors.summingLong(Schedule::getDuration) )); - DoubleSummaryStatistics loadStats = machineLoadMap.values().stream() - .mapToDouble(Long::doubleValue) - .summaryStatistics(); - double loadVariation = (loadStats.getMax() - loadStats.getMin()) / loadStats.getAverage(); - assertTrue(loadVariation < 0.5, "Load should be reasonably balanced across machines"); + + double averageLoad = machineLoadMap.values().stream() + .mapToLong(Long::longValue) + .average() + .orElse(0); + + double allowedDifferencePercentage = 2.0; + + boolean isLoadBalanced = machineLoadMap.values().stream() + .allMatch(load -> Math.abs(load - averageLoad) <= averageLoad * allowedDifferencePercentage); + + assertTrue(isLoadBalanced, "Load should be reasonably balanced across machines"); } private void verifyDurationPreference(List schedules) { List sortedSchedules = schedules.stream() .sorted(Comparator.comparing(Schedule::getStartTime)) .toList(); + long earlierJobsAvgDuration = (long) sortedSchedules.subList(0, sortedSchedules.size() / 2) .stream() .mapToLong(Schedule::getDuration) .average() .orElse(0); + long laterJobsAvgDuration = (long) sortedSchedules.subList(sortedSchedules.size() / 2, sortedSchedules.size()) .stream() .mapToLong(Schedule::getDuration) .average() .orElse(0); + assertTrue(earlierJobsAvgDuration <= laterJobsAvgDuration, "Shorter jobs should tend to be scheduled earlier"); } @@ -215,6 +256,7 @@ private void verifyMachineUtilization(List schedules) { Schedule::getMachine, Collectors.summingLong(Schedule::getDuration) )); + assertFalse(machineUtilization.isEmpty(), "Some machines should be utilized"); assertTrue(machineUtilization.size() > 1, "Multiple machines should be utilized"); }