Skip to content

Commit

Permalink
Merge pull request #287 from ls1intum/update-benchmark-testing
Browse files Browse the repository at this point in the history
Update exam endpoint calls, allow online IDE, cleanup after CI-builds
  • Loading branch information
Stephan Krusche authored Jul 7, 2024
2 parents e3cfcc4 + 15f24c1 commit c3102de
Show file tree
Hide file tree
Showing 26 changed files with 834 additions and 268 deletions.
3 changes: 3 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -312,6 +312,9 @@ Explanation of the form fields:
- `EXISTING_COURSE_CREATE_EXAM`: The tool will create an exam in an existing course on Artemis. The exam will contain 4 exercises (1 programming exercise, 1 modeling exercise, 1 quiz exercise, and 1 text exercise). The necessary number of students will be registered for the exam. In this mode, you need to create a course on Artemis manually and register the necessary users for the course. The tool needs Instructor permissions in the course (see [Artemis User Management](#artemis-user-management)).
- `EXISTING_COURSE_UNPREPARED_EXAM`: The tool will not create a course or exam on Artemis. You need to create a course and an exam on Artemis manually and register the necessary users for the course and exam. The tool will perform the preparation of the exam (i.e., generating student exam and preparing the exercises for conduction). The tool needs Instructor permissions in the course (see [Artemis User Management](#artemis-user-management)).
- `EXISTING_COURSE_PREPARED_EXAM`: The tool will not create a course or exam on Artemis. You need to create a course and an exam on Artemis manually and register the necessary users for the course and exam. The tool will not perform any preparation steps on Artemis. Instead, it assumes that the exam is already fully prepared for conduction.
- `IDE Type`: The type of IDE that the students will use for the programming exercises. The type determines how/if students clone the repository, push commits, etc. The types are:
- `OFFLINE`: An offline IDE, i.e. not the Artemis-integrated online IDE. The students will clone the repository, push commits, etc. from their local machine.
- `ONLINE`: The Artemis online IDE. The students will use the online IDE to work on the exercises.
- `Users`: The users that will participate in the simulation.
- If the box `Customize` is not checked, you simply need to specify the number of users that will participate in the simulation. The tool will use the users with IDs 1 to n (see [Artemis User Management](#artemis-user-management)).
- If the box `Customize` is checked, you can specify the exact users that will participate in the simulation. You need to specify the user IDs of the users that will participate in the simulation (see [Artemis User Management](#artemis-user-management)). The user IDs must be specified in the format `1,2,3-7,10,15,20-22`.
Expand Down
9 changes: 9 additions & 0 deletions src/main/java/de/tum/cit/ase/artemisModel/Course.java
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ public class Course extends DomainObject {

private String title;
private String shortName;
private String courseInformationSharingConfiguration;

public Course(String title, String shortName) {
this.title = title;
Expand All @@ -27,4 +28,12 @@ public String getShortName() {
public void setShortName(String shortName) {
this.shortName = shortName;
}

public String getCourseInformationSharingConfiguration() {
return courseInformationSharingConfiguration;
}

public void setCourseInformationSharingConfiguration(String courseInformationSharingConfiguration) {
this.courseInformationSharingConfiguration = courseInformationSharingConfiguration;
}
}
10 changes: 10 additions & 0 deletions src/main/java/de/tum/cit/ase/artemisModel/ProgrammingExercise.java
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@ public class ProgrammingExercise extends Exercise {
private String programmingLanguage = "JAVA";
private String projectType = "PLAIN_GRADLE";
private boolean staticCodeAnalysisEnabled = false;
// Required for creating course ProgrammingExercise
private Course course;

public String getShortName() {
return shortName;
Expand Down Expand Up @@ -59,4 +61,12 @@ public boolean isStaticCodeAnalysisEnabled() {
public void setStaticCodeAnalysisEnabled(boolean staticCodeAnalysisEnabled) {
this.staticCodeAnalysisEnabled = staticCodeAnalysisEnabled;
}

public Course getCourse() {
return course;
}

public void setCourse(Course course) {
this.course = course;
}
}
27 changes: 27 additions & 0 deletions src/main/java/de/tum/cit/ase/domain/OnlineIdeFileSubmission.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
package de.tum.cit.ase.domain;

import java.io.Serial;
import java.io.Serializable;

public class OnlineIdeFileSubmission implements Serializable {

@Serial
private static final long serialVersionUID = 1L;

private String fileName;

private String fileContent;

public String getFileName() {
return fileName;
}

public String getFileContent() {
return fileContent;
}

public OnlineIdeFileSubmission(String fileName, String fileContent) {
this.fileName = fileName;
this.fileContent = fileContent;
}
}
3 changes: 3 additions & 0 deletions src/main/java/de/tum/cit/ase/domain/RequestType.java
Original file line number Diff line number Diff line change
Expand Up @@ -9,5 +9,8 @@ public enum RequestType {
SUBMIT_STUDENT_EXAM,
CLONE,
PUSH,
PROGRAMMING_EXERCISE_RESULT,
REPOSITORY_INFO,
REPOSITORY_FILES,
MISC,
}
24 changes: 24 additions & 0 deletions src/main/java/de/tum/cit/ase/domain/Simulation.java
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,10 @@ public class Simulation {
@Column(name = "user_range")
private String userRange;

@Enumerated(EnumType.STRING)
@Column(name = "ide_type", nullable = false)
private IDEType ideType;

@Column(name = "number_of_commits_and_pushes_from")
private int numberOfCommitsAndPushesFrom;

Expand Down Expand Up @@ -152,6 +156,14 @@ public void setUserRange(String userRange) {
this.userRange = userRange;
}

public IDEType getIdeType() {
return ideType;
}

public void setIdeType(IDEType ideType) {
this.ideType = ideType;
}

public int getNumberOfCommitsAndPushesFrom() {
return numberOfCommitsAndPushesFrom;
}
Expand Down Expand Up @@ -225,4 +237,16 @@ public enum Mode {
*/
EXISTING_COURSE_CREATE_EXAM,
}

public enum IDEType {
/**
* Programming exercises will be solved using the Artemis Online IDE.
*/
ONLINE,

/**
* Programming exercises will be solved using an offline IDE.
*/
OFFLINE,
}
}
88 changes: 46 additions & 42 deletions src/main/java/de/tum/cit/ase/service/CiStatusService.java
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
import de.tum.cit.ase.web.websocket.SimulationWebsocketService;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.CompletableFuture;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.scheduling.annotation.Async;
Expand Down Expand Up @@ -98,57 +99,60 @@ public void subscribeToCiStatusViaBuildQueue(SimulationRun simulationRun, Simula
* @param admin the SimulatedArtemisAdmin to use for querying the CI status
* @param examId the ID of the exam to use for querying the CI status
*/
@Async
public void subscribeToCiStatusViaResults(SimulationRun simulationRun, SimulatedArtemisAdmin admin, long examId) {
log.info("Subscribing to CI status for simulation run {}", simulationRun.getId());
CiStatus status = createCiStatus(simulationRun);
public CompletableFuture<Void> subscribeToCiStatusViaResults(SimulationRun simulationRun, SimulatedArtemisAdmin admin, long examId) {
return CompletableFuture.supplyAsync(() -> {
log.info("Subscribing to CI status for simulation run {}", simulationRun.getId());
CiStatus status = createCiStatus(simulationRun);

List<Long> programmingExerciseIds = admin
.getExamWithExercises(examId)
.getExerciseGroups()
.stream()
.flatMap(exerciseGroup -> exerciseGroup.getExercises().stream())
.filter(exercise -> exercise instanceof ProgrammingExercise)
.map(DomainObject::getId)
.toList();

List<Submission> submissions = new ArrayList<>();
List<Participation> participations = new ArrayList<>();
for (Long programmingExerciseId : programmingExerciseIds) {
participations.addAll(admin.getParticipations(programmingExerciseId));
}
for (var participation : participations) {
submissions.addAll(admin.getSubmissions(participation.getId()));
}

int numberOfQueuedJobs = submissions.size() - getNumberOfResults(submissions);
status.setTotalJobs(numberOfQueuedJobs);
status.setQueuedJobs(numberOfQueuedJobs);
status = ciStatusRepository.save(status);
websocketService.sendRunCiUpdate(simulationRun.getId(), status);
List<Long> programmingExerciseIds = admin
.getExamWithExercises(examId)
.getExerciseGroups()
.stream()
.flatMap(exerciseGroup -> exerciseGroup.getExercises().stream())
.filter(exercise -> exercise instanceof ProgrammingExercise)
.map(DomainObject::getId)
.toList();

do {
try {
Thread.sleep(1000 * 60);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
List<Submission> submissions = new ArrayList<>();
List<Participation> participations = new ArrayList<>();
for (Long programmingExerciseId : programmingExerciseIds) {
participations.addAll(admin.getParticipations(programmingExerciseId));
}
log.debug("Updating CI status for simulation run {}", simulationRun.getId());
submissions = new ArrayList<>();
for (var participation : participations) {
submissions.addAll(admin.getSubmissions(participation.getId()));
}
numberOfQueuedJobs = submissions.size() - getNumberOfResults(submissions);

int numberOfQueuedJobs = submissions.size() - getNumberOfResults(submissions);
status.setTotalJobs(numberOfQueuedJobs);
status.setQueuedJobs(numberOfQueuedJobs);
status.setTimeInMinutes(status.getTimeInMinutes() + 1);
status.setAvgJobsPerMinute((double) (status.getTotalJobs() - status.getQueuedJobs()) / status.getTimeInMinutes());
status = ciStatusRepository.save(status);
websocketService.sendRunCiUpdate(simulationRun.getId(), status);
} while (numberOfQueuedJobs > 0);
status.setFinished(true);
status = ciStatusRepository.save(status);
websocketService.sendRunCiUpdate(simulationRun.getId(), status);
log.info("Finished subscribing to CI status for simulation run {}", simulationRun.getId());

do {
try {
Thread.sleep(1000 * 60);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
log.debug("Updating CI status for simulation run {}", simulationRun.getId());
submissions = new ArrayList<>();
for (var participation : participations) {
submissions.addAll(admin.getSubmissions(participation.getId()));
}
numberOfQueuedJobs = submissions.size() - getNumberOfResults(submissions);
status.setQueuedJobs(numberOfQueuedJobs);
status.setTimeInMinutes(status.getTimeInMinutes() + 1);
status.setAvgJobsPerMinute((double) (status.getTotalJobs() - status.getQueuedJobs()) / status.getTimeInMinutes());
status = ciStatusRepository.save(status);
websocketService.sendRunCiUpdate(simulationRun.getId(), status);
} while (numberOfQueuedJobs > 0);
status.setFinished(true);
status = ciStatusRepository.save(status);
websocketService.sendRunCiUpdate(simulationRun.getId(), status);
log.info("Finished subscribing to CI status for simulation run {}", simulationRun.getId());

return null;
});
}

private int getNumberOfResults(List<Submission> submissions) {
Expand Down
Loading

0 comments on commit c3102de

Please sign in to comment.