From 52f07c51d736ff66552b54fb2ccb6e809cc6fa48 Mon Sep 17 00:00:00 2001 From: Ole Vester Date: Thu, 4 Jul 2024 18:11:38 +0200 Subject: [PATCH 01/15] Update endpoint calls and extend simulation to online IDE --- README.md | 3 + .../ase/domain/OnlineIdeFileSubmission.java | 27 +++ .../de/tum/cit/ase/domain/Simulation.java | 24 +++ .../interaction/SimulatedArtemisStudent.java | 188 ++++++++++++++---- .../simulation/SimulationDataService.java | 3 + .../SimulationExecutionService.java | 24 ++- .../changelog/00000000000018_add_ide_type.xml | 16 ++ .../resources/config/liquibase/master.xml | 1 + .../app/entities/simulation/simulation.ts | 15 ++ .../create-simulation-box.component.html | 8 + .../create-simulation-box.component.ts | 6 +- .../simulation-card.component.html | 1 + .../simulation-card.component.ts | 10 +- .../service/SimulationExecutionServiceIT.java | 90 ++++----- 14 files changed, 314 insertions(+), 102 deletions(-) create mode 100644 src/main/java/de/tum/cit/ase/domain/OnlineIdeFileSubmission.java create mode 100644 src/main/resources/config/liquibase/changelog/00000000000018_add_ide_type.xml diff --git a/README.md b/README.md index 7fb1848f..0df804af 100644 --- a/README.md +++ b/README.md @@ -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`. diff --git a/src/main/java/de/tum/cit/ase/domain/OnlineIdeFileSubmission.java b/src/main/java/de/tum/cit/ase/domain/OnlineIdeFileSubmission.java new file mode 100644 index 00000000..84a6bfe4 --- /dev/null +++ b/src/main/java/de/tum/cit/ase/domain/OnlineIdeFileSubmission.java @@ -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; + } +} diff --git a/src/main/java/de/tum/cit/ase/domain/Simulation.java b/src/main/java/de/tum/cit/ase/domain/Simulation.java index 0be5ec8e..f52eeb33 100644 --- a/src/main/java/de/tum/cit/ase/domain/Simulation.java +++ b/src/main/java/de/tum/cit/ase/domain/Simulation.java @@ -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; @@ -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; } @@ -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, + } } diff --git a/src/main/java/de/tum/cit/ase/service/artemis/interaction/SimulatedArtemisStudent.java b/src/main/java/de/tum/cit/ase/service/artemis/interaction/SimulatedArtemisStudent.java index 2b83d9a4..9bf5637a 100644 --- a/src/main/java/de/tum/cit/ase/service/artemis/interaction/SimulatedArtemisStudent.java +++ b/src/main/java/de/tum/cit/ase/service/artemis/interaction/SimulatedArtemisStudent.java @@ -8,6 +8,7 @@ import com.thedeanda.lorem.LoremIpsum; import de.tum.cit.ase.artemisModel.*; import de.tum.cit.ase.domain.ArtemisUser; +import de.tum.cit.ase.domain.OnlineIdeFileSubmission; import de.tum.cit.ase.domain.RequestStat; import de.tum.cit.ase.service.artemis.ArtemisUserService; import de.tum.cit.ase.util.UMLClassDiagrams; @@ -16,6 +17,7 @@ import java.nio.charset.Charset; import java.nio.file.Path; import java.util.ArrayList; +import java.util.Arrays; import java.util.List; import java.util.Random; import org.apache.commons.io.FileUtils; @@ -23,6 +25,7 @@ import org.eclipse.jgit.api.errors.GitAPIException; import org.eclipse.jgit.transport.UsernamePasswordCredentialsProvider; import org.slf4j.LoggerFactory; +import org.springframework.http.MediaType; /** * A simulated Artemis student that can be used to interact with the Artemis server. @@ -76,7 +79,7 @@ public List performInitialCalls() { * @param examId the ID of the exam * @return the list of request stats */ - public List participateInExam(long courseId, long examId) { + public List participateInExam(long courseId, long examId, boolean onlineIde) { if (!authenticated) { throw new IllegalStateException("User " + username + " is not logged in or not a student."); } @@ -86,7 +89,7 @@ public List participateInExam(long courseId, long examId) { List requestStats = new ArrayList<>(); requestStats.add(fetchLiveEvents()); - requestStats.addAll(handleExercises()); + requestStats.addAll(handleExercises(onlineIde)); return requestStats; } @@ -181,10 +184,10 @@ private RequestStat navigateIntoExam() { private RequestStat startExam() { long start = System.nanoTime(); - studentExam = - webClient - .get() - .uri(uriBuilder -> + studentExam = webClient + .get() + .uri( + uriBuilder -> uriBuilder .pathSegment( "api", @@ -197,10 +200,10 @@ private RequestStat startExam() { "conduction" ) .build() - ) - .retrieve() - .bodyToMono(StudentExam.class) - .block(); + ) + .retrieve() + .bodyToMono(StudentExam.class) + .block(); return new RequestStat(now(), System.nanoTime() - start, START_STUDENT_EXAM); } @@ -208,8 +211,9 @@ private RequestStat fetchLiveEvents() { long start = System.nanoTime(); webClient .get() - .uri(uriBuilder -> - uriBuilder.pathSegment("api", "courses", courseIdString, "exams", examIdString, "student-exams", "live-events").build() + .uri( + uriBuilder -> + uriBuilder.pathSegment("api", "courses", courseIdString, "exams", examIdString, "student-exams", "live-events").build() ) .retrieve() .toBodilessEntity() @@ -217,7 +221,7 @@ private RequestStat fetchLiveEvents() { return new RequestStat(now(), System.nanoTime() - start, MISC); } - private List handleExercises() { + private List handleExercises(boolean onlineIde) { List requestStats = new ArrayList<>(); for (var exercise : studentExam.getExercises()) { if (exercise instanceof ModelingExercise) { @@ -227,7 +231,7 @@ private List handleExercises() { } else if (exercise instanceof QuizExercise) { requestStats.add(solveAndSubmitQuizExercise((QuizExercise) exercise)); } else if (exercise instanceof ProgrammingExercise) { - requestStats.addAll(solveAndSubmitProgrammingExercise((ProgrammingExercise) exercise)); + requestStats.addAll(solveAndSubmitProgrammingExercise((ProgrammingExercise) exercise, onlineIde)); } } return requestStats; @@ -247,8 +251,9 @@ private RequestStat solveAndSubmitModelingExercise(ModelingExercise modelingExer long start = System.nanoTime(); webClient .put() - .uri(uriBuilder -> - uriBuilder.pathSegment("api", "exercises", modelingExercise.getId().toString(), "modeling-submissions").build() + .uri( + uriBuilder -> + uriBuilder.pathSegment("api", "exercises", modelingExercise.getId().toString(), "modeling-submissions").build() ) .bodyValue(modelingSubmission) .retrieve() @@ -285,8 +290,8 @@ private RequestStat solveAndSubmitQuizExercise(QuizExercise quizExercise) { long start = System.nanoTime(); webClient .put() - .uri(uriBuilder -> - uriBuilder.pathSegment("api", "exercises", quizExercise.getId().toString(), "submissions", "exam").build() + .uri( + uriBuilder -> uriBuilder.pathSegment("api", "exercises", quizExercise.getId().toString(), "submissions", "exam").build() ) .bodyValue(quizSubmission) .retrieve() @@ -297,28 +302,46 @@ private RequestStat solveAndSubmitQuizExercise(QuizExercise quizExercise) { return null; } - private List solveAndSubmitProgrammingExercise(ProgrammingExercise programmingExercise) { + private void commitAndPush(List requestStats, boolean onlineIde, Long participationId, String changedFileContent) + throws IOException, GitAPIException { + if (onlineIde) { + makeOnlineIDECommitAndPush(requestStats, participationId, changedFileContent); + } else { + makeOfflineIDECommitAndPush(requestStats); + } + } + + private List solveAndSubmitProgrammingExercise(ProgrammingExercise programmingExercise, boolean onlineIDE) { var programmingParticipation = (ProgrammingExerciseStudentParticipation) programmingExercise .getStudentParticipations() .iterator() .next(); - var repositoryCloneUrl = programmingParticipation.getRepositoryUri(); List requestStats = new ArrayList<>(); + var repositoryCloneUrl = programmingParticipation.getRepositoryUri(); + var participationId = programmingParticipation.getId(); try { long start = System.nanoTime(); - requestStats.add(cloneRepo(repositoryCloneUrl)); + + if (onlineIDE) { + makeInitialProgrammingExerciseOnlineIDECalls(requestStats, participationId); + } else { + requestStats.add(cloneRepo(repositoryCloneUrl)); + } int n = new Random().nextInt(numberOfCommitsAndPushesFrom, numberOfCommitsAndPushesTo); // we do a random number of commits and pushes to make some noise log.info("Commit and push {}x for {}", n, username); for (int j = 0; j < n; j++) { sleep(100); - changeFiles(); - requestStats.add(commitAndPushRepo()); + var makeInvalidChange = new Random().nextBoolean(); + var changedFileContent = changeFiles(makeInvalidChange, false); + + commitAndPush(requestStats, onlineIDE, participationId, changedFileContent); } log.debug(" Clone and commit+push done in " + formatDurationFrom(start)); } catch (Exception e) { log.error("Error while handling programming exercise for {{}}: {{}}", username, e.getMessage()); + log.error(Arrays.toString(e.getStackTrace())); } return requestStats; } @@ -327,8 +350,9 @@ private RequestStat submitStudentExam() { long start = System.nanoTime(); webClient .post() - .uri(uriBuilder -> - uriBuilder.pathSegment("api", "courses", courseIdString, "exams", examIdString, "student-exams", "submit").build() + .uri( + uriBuilder -> + uriBuilder.pathSegment("api", "courses", courseIdString, "exams", examIdString, "student-exams", "submit").build() ) .bodyValue(studentExam) .retrieve() @@ -341,19 +365,20 @@ private RequestStat loadExamSummary() { long start = System.nanoTime(); webClient .get() - .uri(uriBuilder -> - uriBuilder - .pathSegment( - "api", - "courses", - courseIdString, - "exams", - examIdString, - "student-exams", - studentExamId.toString(), - "summary" - ) - .build() + .uri( + uriBuilder -> + uriBuilder + .pathSegment( + "api", + "courses", + courseIdString, + "exams", + examIdString, + "student-exams", + studentExamId.toString(), + "summary" + ) + .build() ) .retrieve() .toBodilessEntity() @@ -406,7 +431,7 @@ private RequestStat commitAndPushRepo() throws IOException, GitAPIException { return new RequestStat(now(), duration, PUSH); } - private void changeFiles() throws IOException { + private String changeFiles(boolean invalidChange, boolean writeToFile) throws IOException { // TODO: produce larger and more realistic commits var bubbleSort = Path.of("repos", username, "src", "de", "tum", "in", "ase", "BubbleSort.java"); log.debug("Change file " + bubbleSort); @@ -434,8 +459,88 @@ public void performSort(final List input) { } } """; + if (invalidChange) { + newContent += "}"; + } + newContent = newContent.replace("$$1", String.valueOf(new Random().nextInt(100))); - FileUtils.writeStringToFile(bubbleSort.toFile(), newContent, Charset.defaultCharset()); + if (writeToFile) { + FileUtils.writeStringToFile(bubbleSort.toFile(), newContent, Charset.defaultCharset()); + } + return newContent; + } + + private void makeInitialProgrammingExerciseOnlineIDECalls(List requestStats, Long participationId) { + requestStats.add(getLatestResultWithFeedback(participationId)); + requestStats.add(fetchRepository(participationId)); + requestStats.add(fetchPlantUml()); + requestStats.add(fetchFiles(participationId)); + } + + private void makeOfflineIDECommitAndPush(List requestStats) throws IOException, GitAPIException { + requestStats.add(commitAndPushRepo()); + } + + private void makeOnlineIDECommitAndPush(List requestStats, Long participationId, String changedFileContent) { + requestStats.add(fetchRepository(participationId)); + + var fileName = String.join("/", "src", "progforbenchtemp", "BubbleSort.java"); + requestStats.add(fetchFile(participationId, fileName)); + + log.debug("Commit and push to " + fileName); + long start = System.nanoTime(); + webClient + .put() + .uri("api/repository/" + participationId + "/files?commit=yes") + .bodyValue(List.of(new OnlineIdeFileSubmission(fileName, changedFileContent))) + .retrieve() + .toBodilessEntity() + .block(); + long duration = System.nanoTime() - start; + requestStats.add(new RequestStat(now(), duration, PUSH)); + } + + private RequestStat getLatestResultWithFeedback(Long participationId) { + long start = System.nanoTime(); + webClient + .get() + .uri("api/programming-exercise-participations/" + participationId + "/latest-result-with-feedbacks?withSubmission=true") + .retrieve() + .toBodilessEntity() + .block(); + return new RequestStat(now(), System.nanoTime() - start, MISC); + } + + private RequestStat fetchRepository(Long participationId) { + long start = System.nanoTime(); + webClient.get().uri("api/repository/" + participationId).retrieve().toBodilessEntity().block(); + return new RequestStat(now(), System.nanoTime() - start, MISC); + } + + private RequestStat fetchFile(Long participationId, String fileName) { + long start = System.nanoTime(); + webClient + .get() + .uri("api/repository/" + participationId + "/file?file=" + fileName) + .accept(MediaType.APPLICATION_OCTET_STREAM) + .retrieve() + .toBodilessEntity() + .block(); + return new RequestStat(now(), System.nanoTime() - start, MISC); + } + + private RequestStat fetchFiles(Long participationId) { + long start = System.nanoTime(); + webClient.get().uri("api/repository/" + participationId + "/files").retrieve().toBodilessEntity().block(); + return new RequestStat(now(), System.nanoTime() - start, MISC); + } + + private RequestStat fetchPlantUml() { + long start = System.nanoTime(); + String plantUmlString = + "%40startuml%0A%0Aclass%20Client%20%7B%0A%7D%0A%0Aclass%20Policy%20%7B%0A%20%20%3Ccolor%3Agrey%3E%2Bconfigure()%3C%2Fcolor%3E%0A%7D%0A%0Aclass%20Context%20%7B%0A%20%20%3Ccolor%3Agrey%3E-dates%3A%20List%3CDate%3E%3C%2Fcolor%3E%0A%20%20%3Ccolor%3Agrey%3E%2Bsort()%3C%2Fcolor%3E%0A%7D%0A%0Ainterface%20SortStrategy%20%7B%0A%20%20%3Ccolor%3Agrey%3E%2BperformSort(List%3CDate%3E)%3C%2Fcolor%3E%0A%7D%0A%0Aclass%20BubbleSort%20%7B%0A%20%20%3Ccolor%3Agrey%3E%2BperformSort(List%3CDate%3E)%3C%2Fcolor%3E%0A%7D%0A%0Aclass%20MergeSort%20%7B%0A%20%20%3Ccolor%3Agrey%3E%2BperformSort(List%3CDate%3E)%3C%2Fcolor%3E%0A%7D%0A%0AMergeSort%20-up-%7C%3E%20SortStrategy%20%23grey%0ABubbleSort%20-up-%7C%3E%20SortStrategy%20%23grey%0APolicy%20-right-%3E%20Context%20%23grey%3A%20context%0AContext%20-right-%3E%20SortStrategy%20%23grey%3A%20sortAlgorithm%0AClient%20.down.%3E%20Policy%0AClient%20.down.%3E%20Context%0A%0Ahide%20empty%20fields%0Ahide%20empty%20methods%0A%0A%40enduml&useDarkTheme=true"; + webClient.get().uri("api/plantuml/svg?plantuml=" + plantUmlString).retrieve().toBodilessEntity().block(); + return new RequestStat(now(), System.nanoTime() - start, MISC); } private RequestStat cloneRepo(String repositoryUrl) throws IOException { @@ -449,8 +554,7 @@ private RequestStat cloneRepo(String repositoryUrl) throws IOException { while (attempt < MAX_RETRIES) { try { long start = System.nanoTime(); - var git = Git - .cloneRepository() + var git = Git.cloneRepository() .setURI(repositoryUrl) .setDirectory(localPath.toFile()) .setCredentialsProvider(getCredentialsProvider()) diff --git a/src/main/java/de/tum/cit/ase/service/simulation/SimulationDataService.java b/src/main/java/de/tum/cit/ase/service/simulation/SimulationDataService.java index 8410bb95..e5495ab2 100644 --- a/src/main/java/de/tum/cit/ase/service/simulation/SimulationDataService.java +++ b/src/main/java/de/tum/cit/ase/service/simulation/SimulationDataService.java @@ -70,6 +70,9 @@ public Simulation createSimulation(Simulation simulation) { if (!validateSimulation(simulation)) { throw new IllegalArgumentException("Invalid simulation"); } + if (simulation.getIdeType() == null) { + throw new IllegalArgumentException("IDE type must not be null"); + } // If only one of the instructor credentials is set, remove both if ((simulation.getInstructorUsername() != null) ^ (simulation.getInstructorPassword() != null)) { simulation.setInstructorUsername(null); diff --git a/src/main/java/de/tum/cit/ase/service/simulation/SimulationExecutionService.java b/src/main/java/de/tum/cit/ase/service/simulation/SimulationExecutionService.java index c0b99d71..ddc94071 100644 --- a/src/main/java/de/tum/cit/ase/service/simulation/SimulationExecutionService.java +++ b/src/main/java/de/tum/cit/ase/service/simulation/SimulationExecutionService.java @@ -238,7 +238,11 @@ private List simulateExamParticipations( performActionWithAll(threadCount, simulation.getNumberOfUsers(), i -> students[i].startExamParticipation(courseId, examId)) ); requestStats.addAll( - performActionWithAll(threadCount, simulation.getNumberOfUsers(), i -> students[i].participateInExam(courseId, examId)) + performActionWithAll( + threadCount, + simulation.getNumberOfUsers(), + i -> students[i].participateInExam(courseId, examId, simulation.getIdeType() == Simulation.IDEType.ONLINE) + ) ); requestStats.addAll( performActionWithAll(threadCount, simulation.getNumberOfUsers(), i -> students[i].submitAndEndExam(courseId, examId)) @@ -491,14 +495,13 @@ private SimulatedArtemisStudent[] initializeStudents(SimulationRun simulationRun SimulatedArtemisStudent[] users = new SimulatedArtemisStudent[artemisUsers.size()]; for (int i = 0; i < artemisUsers.size(); i++) { - users[i] = - SimulatedArtemisUser.createArtemisStudent( - artemisConfiguration.getUrl(simulation.getServer()), - artemisUsers.get(i), - artemisUserService, - simulation.getNumberOfCommitsAndPushesFrom(), - simulation.getNumberOfCommitsAndPushesTo() - ); + users[i] = SimulatedArtemisUser.createArtemisStudent( + artemisConfiguration.getUrl(simulation.getServer()), + artemisUsers.get(i), + artemisUserService, + simulation.getNumberOfCommitsAndPushesFrom(), + simulation.getNumberOfCommitsAndPushesTo() + ); } return users; } catch (Exception e) { @@ -526,8 +529,7 @@ private List performActionWithAll(int threadCount, int numberOfUser List requestStats = Collections.synchronizedList(new ArrayList<>()); try { - Flowable - .range(0, numberOfUsers) + Flowable.range(0, numberOfUsers) .parallel(threadCount) .runOn(scheduler) .doOnNext(i -> { diff --git a/src/main/resources/config/liquibase/changelog/00000000000018_add_ide_type.xml b/src/main/resources/config/liquibase/changelog/00000000000018_add_ide_type.xml new file mode 100644 index 00000000..5bdbbd3d --- /dev/null +++ b/src/main/resources/config/liquibase/changelog/00000000000018_add_ide_type.xml @@ -0,0 +1,16 @@ + + + + + + + + + + + diff --git a/src/main/resources/config/liquibase/master.xml b/src/main/resources/config/liquibase/master.xml index cfdc4dfb..5fe3cd22 100644 --- a/src/main/resources/config/liquibase/master.xml +++ b/src/main/resources/config/liquibase/master.xml @@ -26,6 +26,7 @@ + diff --git a/src/main/webapp/app/entities/simulation/simulation.ts b/src/main/webapp/app/entities/simulation/simulation.ts index ee5f39cc..115b2627 100644 --- a/src/main/webapp/app/entities/simulation/simulation.ts +++ b/src/main/webapp/app/entities/simulation/simulation.ts @@ -13,6 +13,7 @@ export class Simulation { public runs: SimulationRun[], public creationDate: Date, public customizeUserRange: boolean, + public ideType: IdeType, public numberOfCommitsAndPushesFrom: number, public numberOfCommitsAndPushesTo: number, public userRange?: string, @@ -48,3 +49,17 @@ export function getTextRepresentation(mode: Mode): string { return 'Existing course, create exam'; } } + +export enum IdeType { + ONLINE = 'ONLINE', + OFFLINE = 'OFFLINE', +} + +export function getTextRepresentationIdeType(ideType: IdeType): string { + switch (ideType) { + case IdeType.OFFLINE: + return 'Offline'; + case IdeType.ONLINE: + return 'Online'; + } +} diff --git a/src/main/webapp/app/layouts/create-simulation-box/create-simulation-box.component.html b/src/main/webapp/app/layouts/create-simulation-box/create-simulation-box.component.html index 710af724..ad093783 100644 --- a/src/main/webapp/app/layouts/create-simulation-box/create-simulation-box.component.html +++ b/src/main/webapp/app/layouts/create-simulation-box/create-simulation-box.component.html @@ -33,6 +33,14 @@ } +
+ + +
diff --git a/src/main/webapp/app/layouts/create-simulation-box/create-simulation-box.component.ts b/src/main/webapp/app/layouts/create-simulation-box/create-simulation-box.component.ts index 2ff23888..e754e7da 100644 --- a/src/main/webapp/app/layouts/create-simulation-box/create-simulation-box.component.ts +++ b/src/main/webapp/app/layouts/create-simulation-box/create-simulation-box.component.ts @@ -1,5 +1,5 @@ import { Component, EventEmitter, OnInit, Output } from '@angular/core'; -import { getTextRepresentation, Mode, Simulation } from '../../entities/simulation/simulation'; +import { getTextRepresentation, getTextRepresentationIdeType, IdeType, Mode, Simulation } from '../../entities/simulation/simulation'; import { ArtemisServer } from '../../core/util/artemisServer'; import { ProfileService } from '../profiles/profile.service'; import { SimulationsService } from '../../simulations/simulations.service'; @@ -24,6 +24,7 @@ export class CreateSimulationBoxComponent implements OnInit { mode: Mode = Mode.CREATE_COURSE_AND_EXAM; customizeUserRange: boolean = false; userRange: string = ''; + ideType: IdeType = IdeType.OFFLINE; numberOfCommitsAndPushesFrom: number = 8; numberOfCommitsAndPushesTo: number = 15; instructorUsername: string = ''; @@ -36,12 +37,14 @@ export class CreateSimulationBoxComponent implements OnInit { Mode.EXISTING_COURSE_PREPARED_EXAM, Mode.EXISTING_COURSE_UNPREPARED_EXAM, ]; + availableIdeTypes = [IdeType.OFFLINE, IdeType.ONLINE]; serversWithCleanupEnabled: ArtemisServer[] = []; showPassword: boolean = false; protected readonly Mode = Mode; protected readonly ArtemisServer = ArtemisServer; protected readonly getTextRepresentation = getTextRepresentation; + protected readonly getTextRepresentationIdeType = getTextRepresentationIdeType; constructor( private profileService: ProfileService, @@ -75,6 +78,7 @@ export class CreateSimulationBoxComponent implements OnInit { [], new Date(), this.customizeUserRange, + this.ideType, this.numberOfCommitsAndPushesFrom, this.numberOfCommitsAndPushesTo, this.userRange, diff --git a/src/main/webapp/app/layouts/simulation-card/simulation-card.component.html b/src/main/webapp/app/layouts/simulation-card/simulation-card.component.html index bc741efc..80d04129 100644 --- a/src/main/webapp/app/layouts/simulation-card/simulation-card.component.html +++ b/src/main/webapp/app/layouts/simulation-card/simulation-card.component.html @@ -41,6 +41,7 @@ Users: {{ simulation.numberOfUsers }} }

+

IDE Type: {{ getTextRepresentationIdeType(simulation.ideType) }}

Commits: {{ simulation.numberOfCommitsAndPushesFrom }} - {{ simulation.numberOfCommitsAndPushesTo }}

@if (simulation.mode != Mode.CREATE_COURSE_AND_EXAM) {
diff --git a/src/main/webapp/app/layouts/simulation-card/simulation-card.component.ts b/src/main/webapp/app/layouts/simulation-card/simulation-card.component.ts index 4459bce6..6cdb22b0 100644 --- a/src/main/webapp/app/layouts/simulation-card/simulation-card.component.ts +++ b/src/main/webapp/app/layouts/simulation-card/simulation-card.component.ts @@ -1,5 +1,11 @@ import { Component, EventEmitter, Input, OnInit, Output } from '@angular/core'; -import { getTextRepresentation, instructorCredentialsProvided, Mode, Simulation } from '../../entities/simulation/simulation'; +import { + getTextRepresentation, + getTextRepresentationIdeType, + instructorCredentialsProvided, + Mode, + Simulation, +} from '../../entities/simulation/simulation'; import { SimulationRun, Status } from '../../entities/simulation/simulationRun'; import { SimulationsService } from '../../simulations/simulations.service'; import { NgbModal } from '@ng-bootstrap/ng-bootstrap'; @@ -203,4 +209,6 @@ export class SimulationCardComponent implements OnInit { this.simulation.mode !== Mode.EXISTING_COURSE_PREPARED_EXAM && !instructorCredentialsProvided(this.simulation); } + + protected readonly getTextRepresentationIdeType = getTextRepresentationIdeType; } diff --git a/src/test/java/de/tum/cit/ase/service/SimulationExecutionServiceIT.java b/src/test/java/de/tum/cit/ase/service/SimulationExecutionServiceIT.java index 9f33a3dd..803e74b9 100644 --- a/src/test/java/de/tum/cit/ase/service/SimulationExecutionServiceIT.java +++ b/src/test/java/de/tum/cit/ase/service/SimulationExecutionServiceIT.java @@ -144,9 +144,9 @@ public void init() { when(simulatedArtemisStudent2.startExamParticipation(1, 1)).thenReturn(List.of()); when(simulatedArtemisStudent3.startExamParticipation(1, 1)).thenReturn(List.of()); - when((simulatedArtemisStudent1.participateInExam(1, 1))).thenReturn(List.of()); - when((simulatedArtemisStudent2.participateInExam(1, 1))).thenReturn(List.of()); - when((simulatedArtemisStudent3.participateInExam(1, 1))).thenReturn(List.of()); + when((simulatedArtemisStudent1.participateInExam(1, 1, false))).thenReturn(List.of()); + when((simulatedArtemisStudent2.participateInExam(1, 1, false))).thenReturn(List.of()); + when((simulatedArtemisStudent3.participateInExam(1, 1, false))).thenReturn(List.of()); when(simulatedArtemisStudent1.startExamParticipation(1, 1)).thenReturn(List.of()); when(simulatedArtemisStudent2.startExamParticipation(1, 1)).thenReturn(List.of()); @@ -168,9 +168,9 @@ public void init() { statusesOnWebsocketUpdate = new LinkedList<>(); doAnswer(invocation -> { - statusesOnWebsocketUpdate.add(invocation.getArgument(0, SimulationRun.class).getStatus()); - return null; - }) + statusesOnWebsocketUpdate.add(invocation.getArgument(0, SimulationRun.class).getStatus()); + return null; + }) .when(simulationWebsocketService) .sendRunStatusUpdate(any()); } @@ -202,11 +202,10 @@ public void testCreateCourseAndExam_cleanupEnabled_success() { verify(simulatedArtemisAdmin, times(0)).getCourse(anyLong()); verify(simulatedArtemisAdmin, times(1)).createExam(course); verify(simulatedArtemisAdmin, times(1)).createExamExercises(1, exam); - verify(simulatedArtemisAdmin, times(1)) - .registerStudentsForCourse( - 1, - new SimulatedArtemisStudent[] { simulatedArtemisStudent1, simulatedArtemisStudent2, simulatedArtemisStudent3 } - ); + verify(simulatedArtemisAdmin, times(1)).registerStudentsForCourse( + 1, + new SimulatedArtemisStudent[] { simulatedArtemisStudent1, simulatedArtemisStudent2, simulatedArtemisStudent3 } + ); verify(simulatedArtemisAdmin, times(1)).registerStudentsForExam(1, 1); verify(simulatedArtemisAdmin, times(1)).prepareExam(1, 1); verify(simulatedArtemisAdmin, timeout(1000).times(1)).deleteCourse(1); @@ -220,7 +219,7 @@ public void testCreateCourseAndExam_cleanupEnabled_success() { verify(simulatedStudent, times(1)).login(); verify(simulatedStudent, times(1)).performInitialCalls(); verify(simulatedStudent, times(1)).startExamParticipation(1, 1); - verify(simulatedStudent, times(1)).participateInExam(1, 1); + verify(simulatedStudent, times(1)).participateInExam(1, 1, false); verify(simulatedStudent, times(1)).submitAndEndExam(1, 1); } @@ -263,11 +262,10 @@ public void testCreateCourseAndExam_cleanupDisabled_success() { verify(simulatedArtemisAdmin, times(0)).getCourse(anyLong()); verify(simulatedArtemisAdmin, times(1)).createExam(course); verify(simulatedArtemisAdmin, times(1)).createExamExercises(1, exam); - verify(simulatedArtemisAdmin, times(1)) - .registerStudentsForCourse( - 1, - new SimulatedArtemisStudent[] { simulatedArtemisStudent1, simulatedArtemisStudent2, simulatedArtemisStudent3 } - ); + verify(simulatedArtemisAdmin, times(1)).registerStudentsForCourse( + 1, + new SimulatedArtemisStudent[] { simulatedArtemisStudent1, simulatedArtemisStudent2, simulatedArtemisStudent3 } + ); verify(simulatedArtemisAdmin, times(1)).registerStudentsForExam(1, 1); verify(simulatedArtemisAdmin, times(1)).prepareExam(1, 1); verify(simulatedArtemisAdmin, timeout(1000).times(0)).deleteCourse(anyLong()); @@ -281,7 +279,7 @@ public void testCreateCourseAndExam_cleanupDisabled_success() { verify(simulatedStudent, times(1)).login(); verify(simulatedStudent, times(1)).performInitialCalls(); verify(simulatedStudent, times(1)).startExamParticipation(1, 1); - verify(simulatedStudent, times(1)).participateInExam(1, 1); + verify(simulatedStudent, times(1)).participateInExam(1, 1, false); verify(simulatedStudent, times(1)).submitAndEndExam(1, 1); } @@ -338,7 +336,7 @@ public void testExistingCourseCreateExam_cleanupEnabled_success() { verify(simulatedStudent, times(1)).login(); verify(simulatedStudent, times(1)).performInitialCalls(); verify(simulatedStudent, times(1)).startExamParticipation(1, 1); - verify(simulatedStudent, times(1)).participateInExam(1, 1); + verify(simulatedStudent, times(1)).participateInExam(1, 1, false); verify(simulatedStudent, times(1)).submitAndEndExam(1, 1); } @@ -395,7 +393,7 @@ public void testExistingCourseCreateExam_cleanupDisabled_success() { verify(simulatedStudent, times(1)).login(); verify(simulatedStudent, times(1)).performInitialCalls(); verify(simulatedStudent, times(1)).startExamParticipation(1, 1); - verify(simulatedStudent, times(1)).participateInExam(1, 1); + verify(simulatedStudent, times(1)).participateInExam(1, 1, false); verify(simulatedStudent, times(1)).submitAndEndExam(1, 1); } @@ -453,7 +451,7 @@ public void testExistingCourseUnpreparedExam_success() { verify(simulatedStudent, times(1)).login(); verify(simulatedStudent, times(1)).performInitialCalls(); verify(simulatedStudent, times(1)).startExamParticipation(1, 1); - verify(simulatedStudent, times(1)).participateInExam(1, 1); + verify(simulatedStudent, times(1)).participateInExam(1, 1, false); verify(simulatedStudent, times(1)).submitAndEndExam(1, 1); } @@ -513,7 +511,7 @@ public void testExistingCoursePreparedExam_success() { verify(simulatedStudent, times(1)).login(); verify(simulatedStudent, times(1)).performInitialCalls(); verify(simulatedStudent, times(1)).startExamParticipation(1, 1); - verify(simulatedStudent, times(1)).participateInExam(1, 1); + verify(simulatedStudent, times(1)).participateInExam(1, 1, false); verify(simulatedStudent, times(1)).submitAndEndExam(1, 1); } @@ -560,11 +558,10 @@ public void testCreateCourseAndExam_cleanupEnabled_production_success() { verify(simulatedArtemisAdmin, times(0)).getCourse(anyLong()); verify(simulatedArtemisAdmin, times(1)).createExam(course); verify(simulatedArtemisAdmin, times(1)).createExamExercises(1, exam); - verify(simulatedArtemisAdmin, times(1)) - .registerStudentsForCourse( - 1, - new SimulatedArtemisStudent[] { simulatedArtemisStudent1, simulatedArtemisStudent2, simulatedArtemisStudent3 } - ); + verify(simulatedArtemisAdmin, times(1)).registerStudentsForCourse( + 1, + new SimulatedArtemisStudent[] { simulatedArtemisStudent1, simulatedArtemisStudent2, simulatedArtemisStudent3 } + ); verify(simulatedArtemisAdmin, times(1)).registerStudentsForExam(1, 1); verify(simulatedArtemisAdmin, times(1)).prepareExam(1, 1); verify(simulatedArtemisAdmin, timeout(1000).times(1)).deleteCourse(1); @@ -578,7 +575,7 @@ public void testCreateCourseAndExam_cleanupEnabled_production_success() { verify(simulatedStudent, times(1)).login(); verify(simulatedStudent, times(1)).performInitialCalls(); verify(simulatedStudent, times(1)).startExamParticipation(1, 1); - verify(simulatedStudent, times(1)).participateInExam(1, 1); + verify(simulatedStudent, times(1)).participateInExam(1, 1, false); verify(simulatedStudent, times(1)).submitAndEndExam(1, 1); } @@ -636,7 +633,7 @@ public void testCreateCourseAndExam_fail_onInitializeStudents() { verify(simulatedStudent, times(0)).login(); verify(simulatedStudent, times(0)).performInitialCalls(); verify(simulatedStudent, times(0)).startExamParticipation(anyLong(), anyLong()); - verify(simulatedStudent, times(0)).participateInExam(anyLong(), anyLong()); + verify(simulatedStudent, times(0)).participateInExam(anyLong(), anyLong(), false); verify(simulatedStudent, times(0)).submitAndEndExam(anyLong(), anyLong()); } @@ -691,7 +688,7 @@ public void testCreateCourseAndExam_fail_onInitializeAdmin() { verify(simulatedStudent, times(0)).login(); verify(simulatedStudent, times(0)).performInitialCalls(); verify(simulatedStudent, times(0)).startExamParticipation(anyLong(), anyLong()); - verify(simulatedStudent, times(0)).participateInExam(anyLong(), anyLong()); + verify(simulatedStudent, times(0)).participateInExam(anyLong(), anyLong(), false); verify(simulatedStudent, times(0)).submitAndEndExam(anyLong(), anyLong()); } @@ -748,7 +745,7 @@ public void testCreateCourseAndExam_fail_onCreateCourse() { verify(simulatedStudent, times(0)).login(); verify(simulatedStudent, times(0)).performInitialCalls(); verify(simulatedStudent, times(0)).startExamParticipation(anyLong(), anyLong()); - verify(simulatedStudent, times(0)).participateInExam(anyLong(), anyLong()); + verify(simulatedStudent, times(0)).participateInExam(anyLong(), anyLong(), false); verify(simulatedStudent, times(0)).submitAndEndExam(anyLong(), anyLong()); } @@ -791,11 +788,10 @@ public void testCreateCourseAndExam_fail_onRegisterStudentsForCourse() { verify(simulatedArtemisAdmin, times(0)).getCourse(anyLong()); verify(simulatedArtemisAdmin, times(0)).createExam(any()); verify(simulatedArtemisAdmin, times(0)).createExamExercises(anyLong(), any()); - verify(simulatedArtemisAdmin, times(1)) - .registerStudentsForCourse( - 1, - new SimulatedArtemisStudent[] { simulatedArtemisStudent1, simulatedArtemisStudent2, simulatedArtemisStudent3 } - ); + verify(simulatedArtemisAdmin, times(1)).registerStudentsForCourse( + 1, + new SimulatedArtemisStudent[] { simulatedArtemisStudent1, simulatedArtemisStudent2, simulatedArtemisStudent3 } + ); verify(simulatedArtemisAdmin, times(0)).registerStudentsForExam(anyLong(), anyLong()); verify(simulatedArtemisAdmin, times(0)).prepareExam(anyLong(), anyLong()); verify(simulatedArtemisAdmin, timeout(1000).times(1)).deleteCourse(1); @@ -809,7 +805,7 @@ public void testCreateCourseAndExam_fail_onRegisterStudentsForCourse() { verify(simulatedStudent, times(0)).login(); verify(simulatedStudent, times(0)).performInitialCalls(); verify(simulatedStudent, times(0)).startExamParticipation(anyLong(), anyLong()); - verify(simulatedStudent, times(0)).participateInExam(anyLong(), anyLong()); + verify(simulatedStudent, times(0)).participateInExam(anyLong(), anyLong(), false); verify(simulatedStudent, times(0)).submitAndEndExam(anyLong(), anyLong()); } @@ -867,7 +863,7 @@ public void testExistingCourseCreateExam_fail_onGetCourse() { verify(simulatedStudent, times(0)).login(); verify(simulatedStudent, times(0)).performInitialCalls(); verify(simulatedStudent, times(0)).startExamParticipation(anyLong(), anyLong()); - verify(simulatedStudent, times(0)).participateInExam(anyLong(), anyLong()); + verify(simulatedStudent, times(0)).participateInExam(anyLong(), anyLong(), false); verify(simulatedStudent, times(0)).submitAndEndExam(anyLong(), anyLong()); } @@ -925,7 +921,7 @@ public void testExistingCourseCreateExam_fail_onCreateExam() { verify(simulatedStudent, times(0)).login(); verify(simulatedStudent, times(0)).performInitialCalls(); verify(simulatedStudent, times(0)).startExamParticipation(anyLong(), anyLong()); - verify(simulatedStudent, times(0)).participateInExam(anyLong(), anyLong()); + verify(simulatedStudent, times(0)).participateInExam(anyLong(), anyLong(), false); verify(simulatedStudent, times(0)).submitAndEndExam(anyLong(), anyLong()); } @@ -983,7 +979,7 @@ public void testExistingCourseCreateExam_fail_onCreateExamExercises() { verify(simulatedStudent, times(0)).login(); verify(simulatedStudent, times(0)).performInitialCalls(); verify(simulatedStudent, times(0)).startExamParticipation(anyLong(), anyLong()); - verify(simulatedStudent, times(0)).participateInExam(anyLong(), anyLong()); + verify(simulatedStudent, times(0)).participateInExam(anyLong(), anyLong(), false); verify(simulatedStudent, times(0)).submitAndEndExam(anyLong(), anyLong()); } @@ -1041,7 +1037,7 @@ public void testExistingCourseCreateExam_fail_onRegisterStudentsForExam() { verify(simulatedStudent, times(0)).login(); verify(simulatedStudent, times(0)).performInitialCalls(); verify(simulatedStudent, times(0)).startExamParticipation(anyLong(), anyLong()); - verify(simulatedStudent, times(0)).participateInExam(anyLong(), anyLong()); + verify(simulatedStudent, times(0)).participateInExam(anyLong(), anyLong(), false); verify(simulatedStudent, times(0)).submitAndEndExam(anyLong(), anyLong()); } @@ -1099,7 +1095,7 @@ public void testExistingCourseCreateExam_fail_onPrepareExam() { verify(simulatedStudent, times(0)).login(); verify(simulatedStudent, times(0)).performInitialCalls(); verify(simulatedStudent, times(0)).startExamParticipation(anyLong(), anyLong()); - verify(simulatedStudent, times(0)).participateInExam(anyLong(), anyLong()); + verify(simulatedStudent, times(0)).participateInExam(anyLong(), anyLong(), false); verify(simulatedStudent, times(0)).submitAndEndExam(anyLong(), anyLong()); } @@ -1144,9 +1140,9 @@ public void testExistingCourseCreateExam_success_studentsCannotConnect() { when(simulatedArtemisStudent1.startExamParticipation(anyLong(), anyLong())).thenThrow(new RuntimeException("Test exception")); when(simulatedArtemisStudent2.startExamParticipation(anyLong(), anyLong())).thenThrow(new RuntimeException("Test exception")); when(simulatedArtemisStudent3.startExamParticipation(anyLong(), anyLong())).thenThrow(new RuntimeException("Test exception")); - when(simulatedArtemisStudent1.participateInExam(anyLong(), anyLong())).thenThrow(new RuntimeException("Test exception")); - when(simulatedArtemisStudent2.participateInExam(anyLong(), anyLong())).thenThrow(new RuntimeException("Test exception")); - when(simulatedArtemisStudent3.participateInExam(anyLong(), anyLong())).thenThrow(new RuntimeException("Test exception")); + when(simulatedArtemisStudent1.participateInExam(anyLong(), anyLong(), false)).thenThrow(new RuntimeException("Test exception")); + when(simulatedArtemisStudent2.participateInExam(anyLong(), anyLong(), false)).thenThrow(new RuntimeException("Test exception")); + when(simulatedArtemisStudent3.participateInExam(anyLong(), anyLong(), false)).thenThrow(new RuntimeException("Test exception")); when(simulatedArtemisStudent1.submitAndEndExam(anyLong(), anyLong())).thenThrow(new RuntimeException("Test exception")); when(simulatedArtemisStudent2.submitAndEndExam(anyLong(), anyLong())).thenThrow(new RuntimeException("Test exception")); when(simulatedArtemisStudent3.submitAndEndExam(anyLong(), anyLong())).thenThrow(new RuntimeException("Test exception")); @@ -1172,7 +1168,7 @@ public void testExistingCourseCreateExam_success_studentsCannotConnect() { verify(simulatedStudent, times(1)).login(); verify(simulatedStudent, times(1)).performInitialCalls(); verify(simulatedStudent, times(1)).startExamParticipation(1, 1); - verify(simulatedStudent, times(1)).participateInExam(1, 1); + verify(simulatedStudent, times(1)).participateInExam(1, 1, false); verify(simulatedStudent, times(1)).submitAndEndExam(1, 1); } @@ -1230,7 +1226,7 @@ public void testExistingCourseCreateExam_success_failOnCleanup() { verify(simulatedStudent, times(1)).login(); verify(simulatedStudent, times(1)).performInitialCalls(); verify(simulatedStudent, times(1)).startExamParticipation(1, 1); - verify(simulatedStudent, times(1)).participateInExam(1, 1); + verify(simulatedStudent, times(1)).participateInExam(1, 1, false); verify(simulatedStudent, times(1)).submitAndEndExam(1, 1); } From d6a06583fa6b72b43616d3b4242fc06aa8b4541f Mon Sep 17 00:00:00 2001 From: Ole Vester Date: Thu, 4 Jul 2024 18:14:11 +0200 Subject: [PATCH 02/15] Specify request types --- src/main/java/de/tum/cit/ase/domain/RequestType.java | 5 +++++ .../artemis/interaction/SimulatedArtemisStudent.java | 10 +++++----- 2 files changed, 10 insertions(+), 5 deletions(-) diff --git a/src/main/java/de/tum/cit/ase/domain/RequestType.java b/src/main/java/de/tum/cit/ase/domain/RequestType.java index ab64c827..56f3cd42 100644 --- a/src/main/java/de/tum/cit/ase/domain/RequestType.java +++ b/src/main/java/de/tum/cit/ase/domain/RequestType.java @@ -9,5 +9,10 @@ public enum RequestType { SUBMIT_STUDENT_EXAM, CLONE, PUSH, + PROGRAMMING_EXERCISE_RESULT, + REPOSITORY_INFO, + REPOSITORY_FILE, + REPOSITORY_FILES, + PLANT_UML, MISC, } diff --git a/src/main/java/de/tum/cit/ase/service/artemis/interaction/SimulatedArtemisStudent.java b/src/main/java/de/tum/cit/ase/service/artemis/interaction/SimulatedArtemisStudent.java index 9bf5637a..abb9fccc 100644 --- a/src/main/java/de/tum/cit/ase/service/artemis/interaction/SimulatedArtemisStudent.java +++ b/src/main/java/de/tum/cit/ase/service/artemis/interaction/SimulatedArtemisStudent.java @@ -508,13 +508,13 @@ private RequestStat getLatestResultWithFeedback(Long participationId) { .retrieve() .toBodilessEntity() .block(); - return new RequestStat(now(), System.nanoTime() - start, MISC); + return new RequestStat(now(), System.nanoTime() - start, PROGRAMMING_EXERCISE_RESULT); } private RequestStat fetchRepository(Long participationId) { long start = System.nanoTime(); webClient.get().uri("api/repository/" + participationId).retrieve().toBodilessEntity().block(); - return new RequestStat(now(), System.nanoTime() - start, MISC); + return new RequestStat(now(), System.nanoTime() - start, REPOSITORY_INFO); } private RequestStat fetchFile(Long participationId, String fileName) { @@ -526,13 +526,13 @@ private RequestStat fetchFile(Long participationId, String fileName) { .retrieve() .toBodilessEntity() .block(); - return new RequestStat(now(), System.nanoTime() - start, MISC); + return new RequestStat(now(), System.nanoTime() - start, REPOSITORY_FILE); } private RequestStat fetchFiles(Long participationId) { long start = System.nanoTime(); webClient.get().uri("api/repository/" + participationId + "/files").retrieve().toBodilessEntity().block(); - return new RequestStat(now(), System.nanoTime() - start, MISC); + return new RequestStat(now(), System.nanoTime() - start, REPOSITORY_FILES); } private RequestStat fetchPlantUml() { @@ -540,7 +540,7 @@ private RequestStat fetchPlantUml() { String plantUmlString = "%40startuml%0A%0Aclass%20Client%20%7B%0A%7D%0A%0Aclass%20Policy%20%7B%0A%20%20%3Ccolor%3Agrey%3E%2Bconfigure()%3C%2Fcolor%3E%0A%7D%0A%0Aclass%20Context%20%7B%0A%20%20%3Ccolor%3Agrey%3E-dates%3A%20List%3CDate%3E%3C%2Fcolor%3E%0A%20%20%3Ccolor%3Agrey%3E%2Bsort()%3C%2Fcolor%3E%0A%7D%0A%0Ainterface%20SortStrategy%20%7B%0A%20%20%3Ccolor%3Agrey%3E%2BperformSort(List%3CDate%3E)%3C%2Fcolor%3E%0A%7D%0A%0Aclass%20BubbleSort%20%7B%0A%20%20%3Ccolor%3Agrey%3E%2BperformSort(List%3CDate%3E)%3C%2Fcolor%3E%0A%7D%0A%0Aclass%20MergeSort%20%7B%0A%20%20%3Ccolor%3Agrey%3E%2BperformSort(List%3CDate%3E)%3C%2Fcolor%3E%0A%7D%0A%0AMergeSort%20-up-%7C%3E%20SortStrategy%20%23grey%0ABubbleSort%20-up-%7C%3E%20SortStrategy%20%23grey%0APolicy%20-right-%3E%20Context%20%23grey%3A%20context%0AContext%20-right-%3E%20SortStrategy%20%23grey%3A%20sortAlgorithm%0AClient%20.down.%3E%20Policy%0AClient%20.down.%3E%20Context%0A%0Ahide%20empty%20fields%0Ahide%20empty%20methods%0A%0A%40enduml&useDarkTheme=true"; webClient.get().uri("api/plantuml/svg?plantuml=" + plantUmlString).retrieve().toBodilessEntity().block(); - return new RequestStat(now(), System.nanoTime() - start, MISC); + return new RequestStat(now(), System.nanoTime() - start, REPOSITORY_FILES); } private RequestStat cloneRepo(String repositoryUrl) throws IOException { From aec223827dfe0452292d97cf4cf6215e14625c18 Mon Sep 17 00:00:00 2001 From: Ole Vester Date: Thu, 4 Jul 2024 18:32:14 +0200 Subject: [PATCH 03/15] Remove stack trace logging --- .../ase/service/artemis/interaction/SimulatedArtemisStudent.java | 1 - 1 file changed, 1 deletion(-) diff --git a/src/main/java/de/tum/cit/ase/service/artemis/interaction/SimulatedArtemisStudent.java b/src/main/java/de/tum/cit/ase/service/artemis/interaction/SimulatedArtemisStudent.java index abb9fccc..7b3e54b1 100644 --- a/src/main/java/de/tum/cit/ase/service/artemis/interaction/SimulatedArtemisStudent.java +++ b/src/main/java/de/tum/cit/ase/service/artemis/interaction/SimulatedArtemisStudent.java @@ -341,7 +341,6 @@ private List solveAndSubmitProgrammingExercise(ProgrammingExercise log.debug(" Clone and commit+push done in " + formatDurationFrom(start)); } catch (Exception e) { log.error("Error while handling programming exercise for {{}}: {{}}", username, e.getMessage()); - log.error(Arrays.toString(e.getStackTrace())); } return requestStats; } From 9e6779e99f8eec38d26aa742ca90c4de7987677f Mon Sep 17 00:00:00 2001 From: Ole Vester Date: Fri, 5 Jul 2024 11:35:18 +0200 Subject: [PATCH 04/15] Wait for CI jobs to finish before deleting course/exam --- .../tum/cit/ase/service/CiStatusService.java | 87 ++++++++++--------- .../SimulationExecutionService.java | 26 +++--- 2 files changed, 61 insertions(+), 52 deletions(-) diff --git a/src/main/java/de/tum/cit/ase/service/CiStatusService.java b/src/main/java/de/tum/cit/ase/service/CiStatusService.java index 1975c897..ade559d2 100644 --- a/src/main/java/de/tum/cit/ase/service/CiStatusService.java +++ b/src/main/java/de/tum/cit/ase/service/CiStatusService.java @@ -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; @@ -99,56 +100,60 @@ public void subscribeToCiStatusViaBuildQueue(SimulationRun simulationRun, Simula * @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 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 programmingExerciseIds = admin - .getExamWithExercises(examId) - .getExerciseGroups() - .stream() - .flatMap(exerciseGroup -> exerciseGroup.getExercises().stream()) - .filter(exercise -> exercise instanceof ProgrammingExercise) - .map(DomainObject::getId) - .toList(); - - List submissions = new ArrayList<>(); - List 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 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 submissions = new ArrayList<>(); + List 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 submissions) { diff --git a/src/main/java/de/tum/cit/ase/service/simulation/SimulationExecutionService.java b/src/main/java/de/tum/cit/ase/service/simulation/SimulationExecutionService.java index ddc94071..8b434ed9 100644 --- a/src/main/java/de/tum/cit/ase/service/simulation/SimulationExecutionService.java +++ b/src/main/java/de/tum/cit/ase/service/simulation/SimulationExecutionService.java @@ -22,6 +22,7 @@ import io.reactivex.rxjava3.schedulers.Schedulers; import java.time.ZonedDateTime; import java.util.*; +import java.util.concurrent.ExecutionException; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.function.Function; @@ -175,25 +176,28 @@ public synchronized void simulateExam(SimulationRun simulationRun) { List requestStats = simulateExamParticipations(simulationRun, students, admin, courseId, examId); logAndSend(false, simulationRun, "Simulation finished."); - cleanupAsync(admin, simulationRun, courseId, examId); // Calculate, save and send result SimulationRun runWithResult = simulationResultService.calculateAndSaveResult(simulationRun, requestStats); finishSimulationRun(runWithResult); sendRunResult(runWithResult); - // Subscribe to CI status if necessary / possible - if (artemisConfiguration.getIsLocal(simulationRun.getSimulation().getServer())) { - if (admin == null) { - try { - admin = initializeAdminFromUserManagement(simulationRun.getSimulation().getServer()); - } catch (Exception e) { - logAndSend(true, simulationRun, "Cannot get CI status, no admin account available."); - return; - } + if (admin == null) { + try { + admin = initializeAdminFromUserManagement(simulationRun.getSimulation().getServer()); + } catch (Exception e) { + logAndSend(true, simulationRun, "Cannot get CI status, no admin account available."); + return; } - ciStatusService.subscribeToCiStatusViaResults(runWithResult, admin, examId); } + + // Subscribe to CI status, as we can only safely delete the course after all CI jobs have finished + try { + ciStatusService.subscribeToCiStatusViaResults(runWithResult, admin, examId).get(); + } catch (ExecutionException | InterruptedException e) { + logAndSend(true, simulationRun, "Error while subscribing to CI status: %s", e.getMessage()); + } + cleanupAsync(admin, simulationRun, courseId, examId); } /** From a78455639e32ba9c0e3ef85880c38a4974213cd1 Mon Sep 17 00:00:00 2001 From: Mohamed Bilel Besrour Date: Fri, 5 Jul 2024 12:39:40 +0200 Subject: [PATCH 05/15] add testing steps --- .../de/tum/cit/ase/artemisModel/Course.java | 9 + .../ase/artemisModel/ProgrammingExercise.java | 12 +- .../interaction/SimulatedArtemisAdmin.java | 163 ++++++---- .../interaction/SimulatedArtemisStudent.java | 280 +++++++++++++++--- .../artemis/util/ArtemisServerInfo.java | 5 + .../artemis/util/CourseDashboardDTO.java | 8 + .../service/artemis/util/ScienceEventDTO.java | 14 + .../SimulationExecutionService.java | 53 +++- 8 files changed, 434 insertions(+), 110 deletions(-) create mode 100644 src/main/java/de/tum/cit/ase/service/artemis/util/ArtemisServerInfo.java create mode 100644 src/main/java/de/tum/cit/ase/service/artemis/util/CourseDashboardDTO.java create mode 100644 src/main/java/de/tum/cit/ase/service/artemis/util/ScienceEventDTO.java diff --git a/src/main/java/de/tum/cit/ase/artemisModel/Course.java b/src/main/java/de/tum/cit/ase/artemisModel/Course.java index b8a4c030..8f1d985c 100644 --- a/src/main/java/de/tum/cit/ase/artemisModel/Course.java +++ b/src/main/java/de/tum/cit/ase/artemisModel/Course.java @@ -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; @@ -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; + } } diff --git a/src/main/java/de/tum/cit/ase/artemisModel/ProgrammingExercise.java b/src/main/java/de/tum/cit/ase/artemisModel/ProgrammingExercise.java index 867ebe63..09eaab31 100644 --- a/src/main/java/de/tum/cit/ase/artemisModel/ProgrammingExercise.java +++ b/src/main/java/de/tum/cit/ase/artemisModel/ProgrammingExercise.java @@ -9,8 +9,10 @@ public class ProgrammingExercise extends Exercise { private String packageName; private boolean allowOfflineIde = true; private String programmingLanguage = "JAVA"; - private String projectType = "PLAIN_GRADLE"; + private String projectType = "PLAIN_MAVEN"; private boolean staticCodeAnalysisEnabled = false; + // Required for creating course ProgrammingExercise + private Course course; public String getShortName() { return shortName; @@ -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; + } } diff --git a/src/main/java/de/tum/cit/ase/service/artemis/interaction/SimulatedArtemisAdmin.java b/src/main/java/de/tum/cit/ase/service/artemis/interaction/SimulatedArtemisAdmin.java index 0e7b82ae..86066688 100644 --- a/src/main/java/de/tum/cit/ase/service/artemis/interaction/SimulatedArtemisAdmin.java +++ b/src/main/java/de/tum/cit/ase/service/artemis/interaction/SimulatedArtemisAdmin.java @@ -36,8 +36,8 @@ public SimulatedArtemisAdmin(String artemisUrl, String username, String password @Override protected void checkAccess() { var response = webClient.get().uri("api/public/account").retrieve().bodyToMono(User.class).block(); - this.authenticated = - response != null && (response.getAuthorities().contains("ROLE_ADMIN") || response.getAuthorities().contains("ROLE_INSTRUCTOR")); + this.authenticated = response != null && + (response.getAuthorities().contains("ROLE_ADMIN") || response.getAuthorities().contains("ROLE_INSTRUCTOR")); } /** @@ -56,11 +56,12 @@ public void prepareExam(long courseId, long examId) { // Get exam Exam exam = webClient .get() - .uri(uriBuilder -> - uriBuilder - .pathSegment("api", "courses", courseIdString, "exams", examIdString) - .query("withStudents=false&withExerciseGroups=false") - .build() + .uri( + uriBuilder -> + uriBuilder + .pathSegment("api", "courses", courseIdString, "exams", examIdString) + .query("withStudents=false&withExerciseGroups=false") + .build() ) .retrieve() .bodyToMono(Exam.class) @@ -89,8 +90,9 @@ public void prepareExam(long courseId, long examId) { // Generate student exams webClient .post() - .uri(uriBuilder -> - uriBuilder.pathSegment("api", "courses", courseIdString, "exams", examIdString, "generate-student-exams").build() + .uri( + uriBuilder -> + uriBuilder.pathSegment("api", "courses", courseIdString, "exams", examIdString, "generate-student-exams").build() ) .retrieve() .toBodilessEntity() @@ -100,8 +102,11 @@ public void prepareExam(long courseId, long examId) { // Prepare exercise start webClient .post() - .uri(uriBuilder -> - uriBuilder.pathSegment("api", "courses", courseIdString, "exams", examIdString, "student-exams", "start-exercises").build() + .uri( + uriBuilder -> + uriBuilder + .pathSegment("api", "courses", courseIdString, "exams", examIdString, "student-exams", "start-exercises") + .build() ) .retrieve() .toBodilessEntity() @@ -117,10 +122,10 @@ public void prepareExam(long courseId, long examId) { Thread.currentThread().interrupt(); } - status = - webClient - .get() - .uri(uriBuilder -> + status = webClient + .get() + .uri( + uriBuilder -> uriBuilder .pathSegment( "api", @@ -133,10 +138,10 @@ public void prepareExam(long courseId, long examId) { "status" ) .build() - ) - .retrieve() - .bodyToMono(ExamExerciseStartPreparationStatus.class) - .block(); + ) + .retrieve() + .bodyToMono(ExamExerciseStartPreparationStatus.class) + .block(); if (status == null) { log.warn("Preparation status undefined"); } else { @@ -233,18 +238,18 @@ public void createExamExercises(long courseId, Exam exam) { textExerciseGroup.setMandatory(true); textExerciseGroup.setExam(exam); - textExerciseGroup = - webClient - .post() - .uri(uriBuilder -> + textExerciseGroup = webClient + .post() + .uri( + uriBuilder -> uriBuilder .pathSegment("api", "courses", String.valueOf(courseId), "exams", exam.getId().toString(), "exerciseGroups") .build() - ) - .bodyValue(textExerciseGroup) - .retrieve() - .bodyToMono(ExerciseGroup.class) - .block(); + ) + .bodyValue(textExerciseGroup) + .retrieve() + .bodyToMono(ExerciseGroup.class) + .block(); var textExercise = new TextExercise(); textExercise.setExerciseGroup(textExerciseGroup); @@ -264,18 +269,18 @@ public void createExamExercises(long courseId, Exam exam) { modelingExerciseGroup.setMandatory(true); modelingExerciseGroup.setExam(exam); - modelingExerciseGroup = - webClient - .post() - .uri(uriBuilder -> + modelingExerciseGroup = webClient + .post() + .uri( + uriBuilder -> uriBuilder .pathSegment("api", "courses", String.valueOf(courseId), "exams", exam.getId().toString(), "exerciseGroups") .build() - ) - .bodyValue(modelingExerciseGroup) - .retrieve() - .bodyToMono(ExerciseGroup.class) - .block(); + ) + .bodyValue(modelingExerciseGroup) + .retrieve() + .bodyToMono(ExerciseGroup.class) + .block(); var modelingExercise = new ModelingExercise(); modelingExercise.setExerciseGroup(modelingExerciseGroup); @@ -295,18 +300,18 @@ public void createExamExercises(long courseId, Exam exam) { programmingExerciseGroup.setMandatory(true); programmingExerciseGroup.setExam(exam); - programmingExerciseGroup = - webClient - .post() - .uri(uriBuilder -> + programmingExerciseGroup = webClient + .post() + .uri( + uriBuilder -> uriBuilder .pathSegment("api", "courses", String.valueOf(courseId), "exams", exam.getId().toString(), "exerciseGroups") .build() - ) - .bodyValue(programmingExerciseGroup) - .retrieve() - .bodyToMono(ExerciseGroup.class) - .block(); + ) + .bodyValue(programmingExerciseGroup) + .retrieve() + .bodyToMono(ExerciseGroup.class) + .block(); var programmingExercise = new ProgrammingExercise(); programmingExercise.setExerciseGroup(programmingExerciseGroup); @@ -328,18 +333,18 @@ public void createExamExercises(long courseId, Exam exam) { quizExerciseGroup.setMandatory(true); quizExerciseGroup.setExam(exam); - quizExerciseGroup = - webClient - .post() - .uri(uriBuilder -> + quizExerciseGroup = webClient + .post() + .uri( + uriBuilder -> uriBuilder .pathSegment("api", "courses", String.valueOf(courseId), "exams", exam.getId().toString(), "exerciseGroups") .build() - ) - .bodyValue(quizExerciseGroup) - .retrieve() - .bodyToMono(ExerciseGroup.class) - .block(); + ) + .bodyValue(quizExerciseGroup) + .retrieve() + .bodyToMono(ExerciseGroup.class) + .block(); var quizExercise = new QuizExercise(); quizExercise.setExerciseGroup(quizExerciseGroup); @@ -368,6 +373,28 @@ public void createExamExercises(long courseId, Exam exam) { .block(); } + public ProgrammingExercise createCourseProgrammingExercise(Course course) { + if (!authenticated) { + throw new IllegalStateException("User " + username + " is not logged in or does not have the necessary access rights."); + } + + var programmingExercise = new ProgrammingExercise(); + var randomInt = (int) (Math.random() * 1000); + programmingExercise.setTitle("Temporary Benchmarking Programming Exercise " + course.getId() + "-" + randomInt); + programmingExercise.setCourse(course); + programmingExercise.setMaxPoints(5.0); + programmingExercise.setShortName("course" + course.getId() + "prog" + randomInt); + programmingExercise.setPackageName("progForBenchTemp"); + + return webClient + .post() + .uri(uriBuilder -> uriBuilder.pathSegment("api", "programming-exercises", "setup").build()) + .bodyValue(programmingExercise) + .retrieve() + .bodyToMono(ProgrammingExercise.class) + .block(); + } + /** * Register the given students for the course. The registration is parallelized to speed up the process. * @param courseId the ID of the course @@ -383,16 +410,18 @@ public void registerStudentsForCourse(long courseId, SimulatedArtemisStudent[] s Scheduler scheduler = Schedulers.from(threadPoolExecutor); try { - Flowable - .range(0, students.length) + Flowable.range(0, students.length) .parallel(threadCount) .runOn(scheduler) .doOnNext(i -> { try { webClient .post() - .uri(uriBuilder -> - uriBuilder.pathSegment("api", "courses", String.valueOf(courseId), "students", students[i].username).build() + .uri( + uriBuilder -> + uriBuilder + .pathSegment("api", "courses", String.valueOf(courseId), "students", students[i].username) + .build() ) .retrieve() .toBodilessEntity() @@ -421,10 +450,18 @@ public void registerStudentsForExam(long courseId, long examId) { webClient .post() - .uri(uriBuilder -> - uriBuilder - .pathSegment("api", "courses", String.valueOf(courseId), "exams", String.valueOf(examId), "register-course-students") - .build() + .uri( + uriBuilder -> + uriBuilder + .pathSegment( + "api", + "courses", + String.valueOf(courseId), + "exams", + String.valueOf(examId), + "register-course-students" + ) + .build() ) .retrieve() .toBodilessEntity() diff --git a/src/main/java/de/tum/cit/ase/service/artemis/interaction/SimulatedArtemisStudent.java b/src/main/java/de/tum/cit/ase/service/artemis/interaction/SimulatedArtemisStudent.java index 2b83d9a4..278d6fef 100644 --- a/src/main/java/de/tum/cit/ase/service/artemis/interaction/SimulatedArtemisStudent.java +++ b/src/main/java/de/tum/cit/ase/service/artemis/interaction/SimulatedArtemisStudent.java @@ -10,6 +10,9 @@ import de.tum.cit.ase.domain.ArtemisUser; import de.tum.cit.ase.domain.RequestStat; import de.tum.cit.ase.service.artemis.ArtemisUserService; +import de.tum.cit.ase.service.artemis.util.ArtemisServerInfo; +import de.tum.cit.ase.service.artemis.util.CourseDashboardDTO; +import de.tum.cit.ase.service.artemis.util.ScienceEventDTO; import de.tum.cit.ase.util.UMLClassDiagrams; import jakarta.annotation.Nullable; import java.io.IOException; @@ -17,12 +20,14 @@ import java.nio.file.Path; import java.util.ArrayList; import java.util.List; +import java.util.Map; import java.util.Random; import org.apache.commons.io.FileUtils; import org.eclipse.jgit.api.Git; import org.eclipse.jgit.api.errors.GitAPIException; import org.eclipse.jgit.transport.UsernamePasswordCredentialsProvider; import org.slf4j.LoggerFactory; +import org.springframework.core.ParameterizedTypeReference; /** * A simulated Artemis student that can be used to interact with the Artemis server. @@ -39,6 +44,8 @@ public class SimulatedArtemisStudent extends SimulatedArtemisUser { private final int numberOfCommitsAndPushesFrom; private final int numberOfCommitsAndPushesTo; + private boolean isScienceFeatureEnabled = false; + public SimulatedArtemisStudent( String artemisUrl, ArtemisUser artemisUser, @@ -67,7 +74,15 @@ public List performInitialCalls() { throw new IllegalStateException("User " + username + " is not logged in or not a student."); } - return List.of(getInfo(), getSystemNotifications(), getAccount(), getNotificationSettings(), getCourses()); + return List.of( + getInfo(), + getSystemNotifications(), + getAccount(), + getNotificationSettings(), + getCourses(), + getMutedConversations(), + getNotifications() + ); } /** @@ -98,6 +113,16 @@ public List participateInExam(long courseId, long examId) { * @return the list of request stats */ public List startExamParticipation(long courseId, long examId) { + return startExamParticipation(courseId, examId, 0); + } + + /** + * Start participating in an exam, i.e. navigate into the exam and start the exam. + * @param courseId the ID of the course + * @param examId the ID of the exam + * @return the list of request stats + */ + public List startExamParticipation(long courseId, long examId, long courseProgrammingExerciseId) { if (!authenticated) { throw new IllegalStateException("User " + username + " is not logged in or not a student."); } @@ -106,7 +131,17 @@ public List startExamParticipation(long courseId, long examId) { List requestStats = new ArrayList<>(); + requestStats.add(getCourseDashboard(courseProgrammingExerciseId)); + requestStats.add(getCoursesDropdown()); + requestStats.add(getScienceSettings()); + if (courseProgrammingExerciseId > 0) { + if (isScienceFeatureEnabled) { + requestStats.add(putScienceEvent(courseProgrammingExerciseId)); + } + requestStats.add(getExerciseDetails(courseProgrammingExerciseId)); + } requestStats.add(navigateIntoExam()); + requestStats.add(getTestExams()); requestStats.add(startExam()); return requestStats; @@ -135,7 +170,10 @@ public List submitAndEndExam(long courseId, long examId) { private RequestStat getInfo() { long start = System.nanoTime(); - webClient.get().uri("management/info").retrieve().toBodilessEntity().block(); + ArtemisServerInfo response = webClient.get().uri("management/info").retrieve().bodyToMono(ArtemisServerInfo.class).block(); + if (response != null) { + isScienceFeatureEnabled = response.features().contains("science"); + } return new RequestStat(now(), System.nanoTime() - start, MISC); } @@ -157,12 +195,174 @@ private RequestStat getNotificationSettings() { return new RequestStat(now(), System.nanoTime() - start, MISC); } + private RequestStat getNotifications() { + long start = System.nanoTime(); + webClient + .get() + .uri( + uriBuilder -> + uriBuilder + .path("api/notifications") + .queryParam("page", 0) + .queryParam("size", 25) + .queryParam("sort", "notificationDate,desc") + .build() + ) + .retrieve() + .toBodilessEntity() + .block(); + return new RequestStat(now(), System.nanoTime() - start, MISC); + } + private RequestStat getCourses() { long start = System.nanoTime(); webClient.get().uri("api/courses/for-dashboard").retrieve().toBodilessEntity().block(); return new RequestStat(now(), System.nanoTime() - start, MISC); } + private RequestStat getMutedConversations() { + long start = System.nanoTime(); + webClient.get().uri("api/muted-conversations").retrieve().toBodilessEntity().block(); + return new RequestStat(now(), System.nanoTime() - start, MISC); + } + + private RequestStat getCourseDashboard(long exerciseId) { + long start = System.nanoTime(); + CourseDashboardDTO courseDashboard = webClient + .get() + .uri(uriBuilder -> uriBuilder.pathSegment("api", "courses", courseIdString, "for-dashboard").build()) + .retrieve() + .bodyToMono(CourseDashboardDTO.class) + .block(); + + if (courseDashboard == null) { + return new RequestStat(now(), System.nanoTime() - start, MISC); + } + + try { + if (!courseDashboard.course().getCourseInformationSharingConfiguration().equals("DISABLED")) { + getUnreadMessages(); + getExerciseChannelAndMessages(exerciseId); + } + + if (courseDashboard.participationResults() != null) { + for (CourseDashboardDTO.ParticipationResultDTO result : courseDashboard.participationResults()) { + long participationId = result.participationId(); + getLatestResult(participationId); + } + } + } catch (Exception e) { + log.error("Error while getting course dashboard for {{}}: {{}}", username, e.getMessage()); + } + + return new RequestStat(now(), System.nanoTime() - start, MISC); + } + + private void getUnreadMessages() { + webClient + .get() + .uri(uriBuilder -> uriBuilder.pathSegment("api", "courses", courseIdString, "unread-messages").build()) + .retrieve() + .toBodilessEntity() + .block(); + } + + private void getExerciseChannelAndMessages(long exerciseId) { + Map channelResponse = webClient + .get() + .uri( + uriBuilder -> + uriBuilder.pathSegment("api", "courses", courseIdString, "exercises", String.valueOf(exerciseId), "channel").build() + ) + .retrieve() + .bodyToMono(new ParameterizedTypeReference>() {}) + .block(); + final long channelId; + if (channelResponse != null) { + channelId = ((Number) channelResponse.get("id")).longValue(); + if (channelId == 0) { + return; + } + + webClient + .get() + .uri( + uriBuilder -> + uriBuilder + .pathSegment("api", "courses", courseIdString, "messages") + .queryParam("conversationId", channelId) + .queryParam("PostSortCriterion", "CREATION_DATE") + .queryParam("SortingOrder", "DESCENDING") + .queryParam("pagingEnabled", true) + .queryParam("page", 0) + .queryParam("size", 50) + .build() + ) + .retrieve() + .toBodilessEntity() + .block(); + } + } + + private void getLatestResult(long participationId) { + webClient + .get() + .uri( + uriBuilder -> + uriBuilder + .pathSegment( + "api", + "programming-exercise-participations", + String.valueOf(participationId), + "latest-pending-submission" + ) + .build() + ) + .retrieve() + .toBodilessEntity() + .block(); + } + + private RequestStat getCoursesDropdown() { + long start = System.nanoTime(); + webClient.get().uri("api/courses/for-dropdown").retrieve().toBodilessEntity().block(); + return new RequestStat(now(), System.nanoTime() - start, MISC); + } + + private RequestStat getScienceSettings() { + long start = System.nanoTime(); + webClient.get().uri("api/science-settings").retrieve().toBodilessEntity().block(); + return new RequestStat(now(), System.nanoTime() - start, MISC); + } + + private RequestStat putScienceEvent(long exerciseId) { + long start = System.nanoTime(); + try { + webClient + .put() + .uri("api/science") + .bodyValue(new ScienceEventDTO(ScienceEventDTO.ScienceEventType.EXERCISE__OPEN, exerciseId)) + .retrieve() + .toBodilessEntity() + .block(); + } catch (Exception e) { + log.error("Error while putting science event for {{}}: {{}}", username, e.getMessage()); + } + return new RequestStat(now(), System.nanoTime() - start, MISC); + } + + private RequestStat getExerciseDetails(long exerciseId) { + long start = System.nanoTime(); + webClient + .get() + .uri(uriBuilder -> uriBuilder.pathSegment("api", "exercises", String.valueOf(exerciseId), "details").build()) + .retrieve() + .toBodilessEntity() + .block(); + + return new RequestStat(now(), System.nanoTime() - start, MISC); + } + private RequestStat navigateIntoExam() { long start = System.nanoTime(); StudentExam studentExam = webClient @@ -179,12 +379,23 @@ private RequestStat navigateIntoExam() { return new RequestStat(now(), duration, GET_STUDENT_EXAM); } + private RequestStat getTestExams() { + long start = System.nanoTime(); + webClient + .get() + .uri(uriBuilder -> uriBuilder.pathSegment("api", "courses", courseIdString, "test-exams-per-user").build()) + .retrieve() + .toBodilessEntity() + .block(); + return new RequestStat(now(), System.nanoTime() - start, MISC); + } + private RequestStat startExam() { long start = System.nanoTime(); - studentExam = - webClient - .get() - .uri(uriBuilder -> + studentExam = webClient + .get() + .uri( + uriBuilder -> uriBuilder .pathSegment( "api", @@ -197,10 +408,10 @@ private RequestStat startExam() { "conduction" ) .build() - ) - .retrieve() - .bodyToMono(StudentExam.class) - .block(); + ) + .retrieve() + .bodyToMono(StudentExam.class) + .block(); return new RequestStat(now(), System.nanoTime() - start, START_STUDENT_EXAM); } @@ -208,8 +419,9 @@ private RequestStat fetchLiveEvents() { long start = System.nanoTime(); webClient .get() - .uri(uriBuilder -> - uriBuilder.pathSegment("api", "courses", courseIdString, "exams", examIdString, "student-exams", "live-events").build() + .uri( + uriBuilder -> + uriBuilder.pathSegment("api", "courses", courseIdString, "exams", examIdString, "student-exams", "live-events").build() ) .retrieve() .toBodilessEntity() @@ -247,8 +459,9 @@ private RequestStat solveAndSubmitModelingExercise(ModelingExercise modelingExer long start = System.nanoTime(); webClient .put() - .uri(uriBuilder -> - uriBuilder.pathSegment("api", "exercises", modelingExercise.getId().toString(), "modeling-submissions").build() + .uri( + uriBuilder -> + uriBuilder.pathSegment("api", "exercises", modelingExercise.getId().toString(), "modeling-submissions").build() ) .bodyValue(modelingSubmission) .retrieve() @@ -285,8 +498,8 @@ private RequestStat solveAndSubmitQuizExercise(QuizExercise quizExercise) { long start = System.nanoTime(); webClient .put() - .uri(uriBuilder -> - uriBuilder.pathSegment("api", "exercises", quizExercise.getId().toString(), "submissions", "exam").build() + .uri( + uriBuilder -> uriBuilder.pathSegment("api", "exercises", quizExercise.getId().toString(), "submissions", "exam").build() ) .bodyValue(quizSubmission) .retrieve() @@ -327,8 +540,9 @@ private RequestStat submitStudentExam() { long start = System.nanoTime(); webClient .post() - .uri(uriBuilder -> - uriBuilder.pathSegment("api", "courses", courseIdString, "exams", examIdString, "student-exams", "submit").build() + .uri( + uriBuilder -> + uriBuilder.pathSegment("api", "courses", courseIdString, "exams", examIdString, "student-exams", "submit").build() ) .bodyValue(studentExam) .retrieve() @@ -341,19 +555,20 @@ private RequestStat loadExamSummary() { long start = System.nanoTime(); webClient .get() - .uri(uriBuilder -> - uriBuilder - .pathSegment( - "api", - "courses", - courseIdString, - "exams", - examIdString, - "student-exams", - studentExamId.toString(), - "summary" - ) - .build() + .uri( + uriBuilder -> + uriBuilder + .pathSegment( + "api", + "courses", + courseIdString, + "exams", + examIdString, + "student-exams", + studentExamId.toString(), + "summary" + ) + .build() ) .retrieve() .toBodilessEntity() @@ -449,8 +664,7 @@ private RequestStat cloneRepo(String repositoryUrl) throws IOException { while (attempt < MAX_RETRIES) { try { long start = System.nanoTime(); - var git = Git - .cloneRepository() + var git = Git.cloneRepository() .setURI(repositoryUrl) .setDirectory(localPath.toFile()) .setCredentialsProvider(getCredentialsProvider()) diff --git a/src/main/java/de/tum/cit/ase/service/artemis/util/ArtemisServerInfo.java b/src/main/java/de/tum/cit/ase/service/artemis/util/ArtemisServerInfo.java new file mode 100644 index 00000000..3200828b --- /dev/null +++ b/src/main/java/de/tum/cit/ase/service/artemis/util/ArtemisServerInfo.java @@ -0,0 +1,5 @@ +package de.tum.cit.ase.service.artemis.util; + +import java.util.Set; + +public record ArtemisServerInfo(Set features, Set activeProfiles) {} diff --git a/src/main/java/de/tum/cit/ase/service/artemis/util/CourseDashboardDTO.java b/src/main/java/de/tum/cit/ase/service/artemis/util/CourseDashboardDTO.java new file mode 100644 index 00000000..06881d11 --- /dev/null +++ b/src/main/java/de/tum/cit/ase/service/artemis/util/CourseDashboardDTO.java @@ -0,0 +1,8 @@ +package de.tum.cit.ase.service.artemis.util; + +import de.tum.cit.ase.artemisModel.Course; +import java.util.Set; + +public record CourseDashboardDTO(Course course, Set participationResults) { + public record ParticipationResultDTO(Double score, Boolean rated, Long participationId) {} +} diff --git a/src/main/java/de/tum/cit/ase/service/artemis/util/ScienceEventDTO.java b/src/main/java/de/tum/cit/ase/service/artemis/util/ScienceEventDTO.java new file mode 100644 index 00000000..1ddcf166 --- /dev/null +++ b/src/main/java/de/tum/cit/ase/service/artemis/util/ScienceEventDTO.java @@ -0,0 +1,14 @@ +package de.tum.cit.ase.service.artemis.util; + +public record ScienceEventDTO(ScienceEventType type, Long resourceId) { + /** + * Types of events that can be logged for scientific purposes. + *

+ * Important: Please follow the naming convention __ + */ + public enum ScienceEventType { + LECTURE__OPEN, + LECTURE__OPEN_UNIT, + EXERCISE__OPEN, + } +} diff --git a/src/main/java/de/tum/cit/ase/service/simulation/SimulationExecutionService.java b/src/main/java/de/tum/cit/ase/service/simulation/SimulationExecutionService.java index c0b99d71..096169ab 100644 --- a/src/main/java/de/tum/cit/ase/service/simulation/SimulationExecutionService.java +++ b/src/main/java/de/tum/cit/ase/service/simulation/SimulationExecutionService.java @@ -4,6 +4,7 @@ import de.tum.cit.ase.artemisModel.Course; import de.tum.cit.ase.artemisModel.Exam; +import de.tum.cit.ase.artemisModel.ProgrammingExercise; import de.tum.cit.ase.domain.*; import de.tum.cit.ase.repository.LogMessageRepository; import de.tum.cit.ase.repository.SimulationRunRepository; @@ -115,6 +116,8 @@ public synchronized void simulateExam(SimulationRun simulationRun) { students = initializeStudents(simulationRun); + ProgrammingExercise courseProgrammingExercise = null; + // Initialize admin if necessary if (simulation.getMode() != Simulation.Mode.EXISTING_COURSE_PREPARED_EXAM) { admin = initializeAdmin(simulationRun, accountDTO); @@ -143,6 +146,9 @@ public synchronized void simulateExam(SimulationRun simulationRun) { course = getCourse(admin, simulationRun, courseId); } + // Create programming exercise for course, this is needed to simulate some side requests + courseProgrammingExercise = createCourseProgrammingExercise(admin, simulationRun, course); + // Create exam if necessary if (simulation.getMode() != Simulation.Mode.EXISTING_COURSE_UNPREPARED_EXAM) { Exam exam = createExam(admin, simulationRun, course); @@ -172,7 +178,14 @@ public synchronized void simulateExam(SimulationRun simulationRun) { } // Perform simulation of exam participations - List requestStats = simulateExamParticipations(simulationRun, students, admin, courseId, examId); + List requestStats = simulateExamParticipations( + simulationRun, + students, + admin, + courseId, + examId, + courseProgrammingExercise != null ? courseProgrammingExercise.getId() : 0 + ); logAndSend(false, simulationRun, "Simulation finished."); cleanupAsync(admin, simulationRun, courseId, examId); @@ -216,7 +229,8 @@ private List simulateExamParticipations( SimulatedArtemisStudent[] students, SimulatedArtemisAdmin admin, long courseId, - long examId + long examId, + long programmingExerciseId ) { logAndSend(false, simulationRun, "Starting simulation..."); Simulation simulation = simulationRun.getSimulation(); @@ -235,7 +249,11 @@ private List simulateExamParticipations( logAndSend(false, simulationRun, "Participating in exam..."); requestStats.addAll( - performActionWithAll(threadCount, simulation.getNumberOfUsers(), i -> students[i].startExamParticipation(courseId, examId)) + performActionWithAll( + threadCount, + simulation.getNumberOfUsers(), + i -> students[i].startExamParticipation(courseId, examId, programmingExerciseId) + ) ); requestStats.addAll( performActionWithAll(threadCount, simulation.getNumberOfUsers(), i -> students[i].participateInExam(courseId, examId)) @@ -382,6 +400,17 @@ private Course getCourse(SimulatedArtemisAdmin admin, SimulationRun simulationRu } } + private ProgrammingExercise createCourseProgrammingExercise(SimulatedArtemisAdmin admin, SimulationRun simulationRun, Course course) { + logAndSend(false, simulationRun, "Creating course programming exercise..."); + try { + return admin.createCourseProgrammingExercise(course); + } catch (Exception e) { + logAndSend(true, simulationRun, "Error while creating course programming exercise: %s", e.getMessage()); + failSimulationRun(simulationRun); + throw new SimulationFailedException("Error while creating course programming exercise", e); + } + } + /** * Creates an exam for the given simulation run in the given course using the given admin. * Fails the simulation run if an error occurs while creating the exam. @@ -491,14 +520,13 @@ private SimulatedArtemisStudent[] initializeStudents(SimulationRun simulationRun SimulatedArtemisStudent[] users = new SimulatedArtemisStudent[artemisUsers.size()]; for (int i = 0; i < artemisUsers.size(); i++) { - users[i] = - SimulatedArtemisUser.createArtemisStudent( - artemisConfiguration.getUrl(simulation.getServer()), - artemisUsers.get(i), - artemisUserService, - simulation.getNumberOfCommitsAndPushesFrom(), - simulation.getNumberOfCommitsAndPushesTo() - ); + users[i] = SimulatedArtemisUser.createArtemisStudent( + artemisConfiguration.getUrl(simulation.getServer()), + artemisUsers.get(i), + artemisUserService, + simulation.getNumberOfCommitsAndPushesFrom(), + simulation.getNumberOfCommitsAndPushesTo() + ); } return users; } catch (Exception e) { @@ -526,8 +554,7 @@ private List performActionWithAll(int threadCount, int numberOfUser List requestStats = Collections.synchronizedList(new ArrayList<>()); try { - Flowable - .range(0, numberOfUsers) + Flowable.range(0, numberOfUsers) .parallel(threadCount) .runOn(scheduler) .doOnNext(i -> { From e109ccaac57384324e1ccbab626b4fd704664097 Mon Sep 17 00:00:00 2001 From: Ole Vester Date: Fri, 5 Jul 2024 12:56:11 +0200 Subject: [PATCH 06/15] Use CompletableFuture instead of @Async --- src/main/java/de/tum/cit/ase/service/CiStatusService.java | 1 - 1 file changed, 1 deletion(-) diff --git a/src/main/java/de/tum/cit/ase/service/CiStatusService.java b/src/main/java/de/tum/cit/ase/service/CiStatusService.java index ade559d2..35d566e8 100644 --- a/src/main/java/de/tum/cit/ase/service/CiStatusService.java +++ b/src/main/java/de/tum/cit/ase/service/CiStatusService.java @@ -99,7 +99,6 @@ 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 CompletableFuture subscribeToCiStatusViaResults(SimulationRun simulationRun, SimulatedArtemisAdmin admin, long examId) { return CompletableFuture.supplyAsync(() -> { log.info("Subscribing to CI status for simulation run {}", simulationRun.getId()); From 82a933eafd2369947bda67d27aaa126f69e849cf Mon Sep 17 00:00:00 2001 From: Mohamed Bilel Besrour Date: Fri, 5 Jul 2024 13:12:20 +0200 Subject: [PATCH 07/15] add missing import --- .../ase/service/artemis/interaction/SimulatedArtemisStudent.java | 1 + 1 file changed, 1 insertion(+) diff --git a/src/main/java/de/tum/cit/ase/service/artemis/interaction/SimulatedArtemisStudent.java b/src/main/java/de/tum/cit/ase/service/artemis/interaction/SimulatedArtemisStudent.java index 713bbf37..d1f4ac24 100644 --- a/src/main/java/de/tum/cit/ase/service/artemis/interaction/SimulatedArtemisStudent.java +++ b/src/main/java/de/tum/cit/ase/service/artemis/interaction/SimulatedArtemisStudent.java @@ -29,6 +29,7 @@ import org.eclipse.jgit.api.errors.GitAPIException; import org.eclipse.jgit.transport.UsernamePasswordCredentialsProvider; import org.slf4j.LoggerFactory; +import org.springframework.core.ParameterizedTypeReference; import org.springframework.http.MediaType; /** From 6f40a31e3f95d6cf101e7539f0b2809559b00a27 Mon Sep 17 00:00:00 2001 From: Mohamed Bilel Besrour Date: Fri, 5 Jul 2024 13:13:00 +0200 Subject: [PATCH 08/15] remove unused import --- .../ase/service/artemis/interaction/SimulatedArtemisStudent.java | 1 - 1 file changed, 1 deletion(-) diff --git a/src/main/java/de/tum/cit/ase/service/artemis/interaction/SimulatedArtemisStudent.java b/src/main/java/de/tum/cit/ase/service/artemis/interaction/SimulatedArtemisStudent.java index d1f4ac24..2450807d 100644 --- a/src/main/java/de/tum/cit/ase/service/artemis/interaction/SimulatedArtemisStudent.java +++ b/src/main/java/de/tum/cit/ase/service/artemis/interaction/SimulatedArtemisStudent.java @@ -20,7 +20,6 @@ import java.nio.charset.Charset; import java.nio.file.Path; import java.util.ArrayList; -import java.util.Arrays; import java.util.List; import java.util.Map; import java.util.Random; From cc87c161a0f61e929c3471c8e801373493b5f879 Mon Sep 17 00:00:00 2001 From: Mohamed Bilel Besrour <58034472+BBesrour@users.noreply.github.com> Date: Fri, 5 Jul 2024 13:50:46 +0200 Subject: [PATCH 09/15] revert to gradle --- .../java/de/tum/cit/ase/artemisModel/ProgrammingExercise.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/de/tum/cit/ase/artemisModel/ProgrammingExercise.java b/src/main/java/de/tum/cit/ase/artemisModel/ProgrammingExercise.java index 09eaab31..19846d0b 100644 --- a/src/main/java/de/tum/cit/ase/artemisModel/ProgrammingExercise.java +++ b/src/main/java/de/tum/cit/ase/artemisModel/ProgrammingExercise.java @@ -9,7 +9,7 @@ public class ProgrammingExercise extends Exercise { private String packageName; private boolean allowOfflineIde = true; private String programmingLanguage = "JAVA"; - private String projectType = "PLAIN_MAVEN"; + private String projectType = "PLAIN_GRADLE"; private boolean staticCodeAnalysisEnabled = false; // Required for creating course ProgrammingExercise private Course course; From 06bac5e36ca749ddc6a3ebf8bd950177e58ffff2 Mon Sep 17 00:00:00 2001 From: Ole Vester <73833780+ole-ve@users.noreply.github.com> Date: Sun, 7 Jul 2024 14:21:56 +0200 Subject: [PATCH 10/15] Lint --- .../app/layouts/simulation-card/simulation-card.component.ts | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/main/webapp/app/layouts/simulation-card/simulation-card.component.ts b/src/main/webapp/app/layouts/simulation-card/simulation-card.component.ts index 6cdb22b0..a56b76c8 100644 --- a/src/main/webapp/app/layouts/simulation-card/simulation-card.component.ts +++ b/src/main/webapp/app/layouts/simulation-card/simulation-card.component.ts @@ -48,6 +48,7 @@ export class SimulationCardComponent implements OnInit { protected readonly Mode = Mode; protected readonly Status = Status; protected readonly getTextRepresentation = getTextRepresentation; + protected readonly getTextRepresentationIdeType = getTextRepresentationIdeType; protected readonly ArtemisServer = ArtemisServer; protected readonly instructorCredentialsProvided = instructorCredentialsProvided; @@ -209,6 +210,4 @@ export class SimulationCardComponent implements OnInit { this.simulation.mode !== Mode.EXISTING_COURSE_PREPARED_EXAM && !instructorCredentialsProvided(this.simulation); } - - protected readonly getTextRepresentationIdeType = getTextRepresentationIdeType; } From 597a1fcfb7b4bdcc715cf612012b2c3dd7a653e0 Mon Sep 17 00:00:00 2001 From: Mohamed Bilel Besrour Date: Sun, 7 Jul 2024 17:00:48 +0200 Subject: [PATCH 11/15] fix tests --- .../ase/service/SimulationDataServiceIT.java | 45 ++++++++-------- .../service/SimulationExecutionServiceIT.java | 54 +++++++++---------- 2 files changed, 48 insertions(+), 51 deletions(-) diff --git a/src/test/java/de/tum/cit/ase/service/SimulationDataServiceIT.java b/src/test/java/de/tum/cit/ase/service/SimulationDataServiceIT.java index 3a0ad922..ae45b909 100644 --- a/src/test/java/de/tum/cit/ase/service/SimulationDataServiceIT.java +++ b/src/test/java/de/tum/cit/ase/service/SimulationDataServiceIT.java @@ -66,20 +66,19 @@ public void init() { simulation.setName("Test"); simulation.setNumberOfCommitsAndPushesFrom(1); simulation.setNumberOfCommitsAndPushesTo(4); + simulation.setIdeType(Simulation.IDEType.OFFLINE); - when(simulationRepository.save(any(Simulation.class))) - .thenAnswer(invocation -> { - var simulation = invocation.getArgument(0, Simulation.class); - simulation.setId(1L); - return simulation; - }); + when(simulationRepository.save(any(Simulation.class))).thenAnswer(invocation -> { + var simulation = invocation.getArgument(0, Simulation.class); + simulation.setId(1L); + return simulation; + }); - when(simulationRunRepository.save(any(SimulationRun.class))) - .thenAnswer(invocation -> { - var runArg = invocation.getArgument(0, SimulationRun.class); - runArg.setId(1L); - return runArg; - }); + when(simulationRunRepository.save(any(SimulationRun.class))).thenAnswer(invocation -> { + var runArg = invocation.getArgument(0, SimulationRun.class); + runArg.setId(1L); + return runArg; + }); doNothing().when(simulationQueueService).queueSimulationRun(any()); doNothing().when(simulationWebsocketService).sendRunStatusUpdate(any()); @@ -157,12 +156,11 @@ public void createAndQueueSimulationRun_success() { simulation.setId(1L); when(simulationRepository.findById(1L)).thenReturn(java.util.Optional.of(simulation)); - when(simulationRunRepository.save(any(SimulationRun.class))) - .thenAnswer(invocation -> { - var runArg = invocation.getArgument(0, SimulationRun.class); - runArg.setId(1L); - return runArg; - }); + when(simulationRunRepository.save(any(SimulationRun.class))).thenAnswer(invocation -> { + var runArg = invocation.getArgument(0, SimulationRun.class); + runArg.setId(1L); + return runArg; + }); var queuedRun = simulationDataService.createAndQueueSimulationRun(1L, null, null); @@ -178,12 +176,11 @@ public void createAndQueueSimulationRun_fail_prodWithoutAccount() { simulation.setServer(PRODUCTION); when(simulationRepository.findById(1L)).thenReturn(java.util.Optional.of(simulation)); - when(simulationRunRepository.save(any(SimulationRun.class))) - .thenAnswer(invocation -> { - var runArg = invocation.getArgument(0, SimulationRun.class); - runArg.setId(1L); - return runArg; - }); + when(simulationRunRepository.save(any(SimulationRun.class))).thenAnswer(invocation -> { + var runArg = invocation.getArgument(0, SimulationRun.class); + runArg.setId(1L); + return runArg; + }); assertThrows(IllegalArgumentException.class, () -> simulationDataService.createAndQueueSimulationRun(1L, null, null)); verify(simulationRunRepository, times(0)).save(any()); diff --git a/src/test/java/de/tum/cit/ase/service/SimulationExecutionServiceIT.java b/src/test/java/de/tum/cit/ase/service/SimulationExecutionServiceIT.java index 803e74b9..741351b5 100644 --- a/src/test/java/de/tum/cit/ase/service/SimulationExecutionServiceIT.java +++ b/src/test/java/de/tum/cit/ase/service/SimulationExecutionServiceIT.java @@ -140,17 +140,17 @@ public void init() { when(simulatedArtemisStudent2.performInitialCalls()).thenReturn(List.of()); when(simulatedArtemisStudent3.performInitialCalls()).thenReturn(List.of()); - when(simulatedArtemisStudent1.startExamParticipation(1, 1)).thenReturn(List.of()); - when(simulatedArtemisStudent2.startExamParticipation(1, 1)).thenReturn(List.of()); - when(simulatedArtemisStudent3.startExamParticipation(1, 1)).thenReturn(List.of()); + when(simulatedArtemisStudent1.startExamParticipation(1, 1, 0)).thenReturn(List.of()); + when(simulatedArtemisStudent2.startExamParticipation(1, 1, 0)).thenReturn(List.of()); + when(simulatedArtemisStudent3.startExamParticipation(1, 1, 0)).thenReturn(List.of()); when((simulatedArtemisStudent1.participateInExam(1, 1, false))).thenReturn(List.of()); when((simulatedArtemisStudent2.participateInExam(1, 1, false))).thenReturn(List.of()); when((simulatedArtemisStudent3.participateInExam(1, 1, false))).thenReturn(List.of()); - when(simulatedArtemisStudent1.startExamParticipation(1, 1)).thenReturn(List.of()); - when(simulatedArtemisStudent2.startExamParticipation(1, 1)).thenReturn(List.of()); - when(simulatedArtemisStudent3.startExamParticipation(1, 1)).thenReturn(List.of()); + when(simulatedArtemisStudent1.startExamParticipation(1, 1, 0)).thenReturn(List.of()); + when(simulatedArtemisStudent2.startExamParticipation(1, 1, 0)).thenReturn(List.of()); + when(simulatedArtemisStudent3.startExamParticipation(1, 1, 0)).thenReturn(List.of()); course = new Course(); course.setId(1L); @@ -218,7 +218,7 @@ public void testCreateCourseAndExam_cleanupEnabled_success() { )) { verify(simulatedStudent, times(1)).login(); verify(simulatedStudent, times(1)).performInitialCalls(); - verify(simulatedStudent, times(1)).startExamParticipation(1, 1); + verify(simulatedStudent, times(1)).startExamParticipation(1, 1, 0); verify(simulatedStudent, times(1)).participateInExam(1, 1, false); verify(simulatedStudent, times(1)).submitAndEndExam(1, 1); } @@ -278,7 +278,7 @@ public void testCreateCourseAndExam_cleanupDisabled_success() { )) { verify(simulatedStudent, times(1)).login(); verify(simulatedStudent, times(1)).performInitialCalls(); - verify(simulatedStudent, times(1)).startExamParticipation(1, 1); + verify(simulatedStudent, times(1)).startExamParticipation(1, 1, 0); verify(simulatedStudent, times(1)).participateInExam(1, 1, false); verify(simulatedStudent, times(1)).submitAndEndExam(1, 1); } @@ -335,7 +335,7 @@ public void testExistingCourseCreateExam_cleanupEnabled_success() { )) { verify(simulatedStudent, times(1)).login(); verify(simulatedStudent, times(1)).performInitialCalls(); - verify(simulatedStudent, times(1)).startExamParticipation(1, 1); + verify(simulatedStudent, times(1)).startExamParticipation(1, 1, 0); verify(simulatedStudent, times(1)).participateInExam(1, 1, false); verify(simulatedStudent, times(1)).submitAndEndExam(1, 1); } @@ -392,7 +392,7 @@ public void testExistingCourseCreateExam_cleanupDisabled_success() { )) { verify(simulatedStudent, times(1)).login(); verify(simulatedStudent, times(1)).performInitialCalls(); - verify(simulatedStudent, times(1)).startExamParticipation(1, 1); + verify(simulatedStudent, times(1)).startExamParticipation(1, 1, 0); verify(simulatedStudent, times(1)).participateInExam(1, 1, false); verify(simulatedStudent, times(1)).submitAndEndExam(1, 1); } @@ -450,7 +450,7 @@ public void testExistingCourseUnpreparedExam_success() { )) { verify(simulatedStudent, times(1)).login(); verify(simulatedStudent, times(1)).performInitialCalls(); - verify(simulatedStudent, times(1)).startExamParticipation(1, 1); + verify(simulatedStudent, times(1)).startExamParticipation(1, 1, 0); verify(simulatedStudent, times(1)).participateInExam(1, 1, false); verify(simulatedStudent, times(1)).submitAndEndExam(1, 1); } @@ -510,7 +510,7 @@ public void testExistingCoursePreparedExam_success() { )) { verify(simulatedStudent, times(1)).login(); verify(simulatedStudent, times(1)).performInitialCalls(); - verify(simulatedStudent, times(1)).startExamParticipation(1, 1); + verify(simulatedStudent, times(1)).startExamParticipation(1, 1, 0); verify(simulatedStudent, times(1)).participateInExam(1, 1, false); verify(simulatedStudent, times(1)).submitAndEndExam(1, 1); } @@ -574,7 +574,7 @@ public void testCreateCourseAndExam_cleanupEnabled_production_success() { )) { verify(simulatedStudent, times(1)).login(); verify(simulatedStudent, times(1)).performInitialCalls(); - verify(simulatedStudent, times(1)).startExamParticipation(1, 1); + verify(simulatedStudent, times(1)).startExamParticipation(1, 1, 0); verify(simulatedStudent, times(1)).participateInExam(1, 1, false); verify(simulatedStudent, times(1)).submitAndEndExam(1, 1); } @@ -632,7 +632,7 @@ public void testCreateCourseAndExam_fail_onInitializeStudents() { )) { verify(simulatedStudent, times(0)).login(); verify(simulatedStudent, times(0)).performInitialCalls(); - verify(simulatedStudent, times(0)).startExamParticipation(anyLong(), anyLong()); + verify(simulatedStudent, times(0)).startExamParticipation(anyLong(), anyLong(), 0); verify(simulatedStudent, times(0)).participateInExam(anyLong(), anyLong(), false); verify(simulatedStudent, times(0)).submitAndEndExam(anyLong(), anyLong()); } @@ -687,7 +687,7 @@ public void testCreateCourseAndExam_fail_onInitializeAdmin() { )) { verify(simulatedStudent, times(0)).login(); verify(simulatedStudent, times(0)).performInitialCalls(); - verify(simulatedStudent, times(0)).startExamParticipation(anyLong(), anyLong()); + verify(simulatedStudent, times(0)).startExamParticipation(anyLong(), anyLong(), 0); verify(simulatedStudent, times(0)).participateInExam(anyLong(), anyLong(), false); verify(simulatedStudent, times(0)).submitAndEndExam(anyLong(), anyLong()); } @@ -744,7 +744,7 @@ public void testCreateCourseAndExam_fail_onCreateCourse() { )) { verify(simulatedStudent, times(0)).login(); verify(simulatedStudent, times(0)).performInitialCalls(); - verify(simulatedStudent, times(0)).startExamParticipation(anyLong(), anyLong()); + verify(simulatedStudent, times(0)).startExamParticipation(anyLong(), anyLong(), 0); verify(simulatedStudent, times(0)).participateInExam(anyLong(), anyLong(), false); verify(simulatedStudent, times(0)).submitAndEndExam(anyLong(), anyLong()); } @@ -804,7 +804,7 @@ public void testCreateCourseAndExam_fail_onRegisterStudentsForCourse() { )) { verify(simulatedStudent, times(0)).login(); verify(simulatedStudent, times(0)).performInitialCalls(); - verify(simulatedStudent, times(0)).startExamParticipation(anyLong(), anyLong()); + verify(simulatedStudent, times(0)).startExamParticipation(anyLong(), anyLong(), 0); verify(simulatedStudent, times(0)).participateInExam(anyLong(), anyLong(), false); verify(simulatedStudent, times(0)).submitAndEndExam(anyLong(), anyLong()); } @@ -862,7 +862,7 @@ public void testExistingCourseCreateExam_fail_onGetCourse() { )) { verify(simulatedStudent, times(0)).login(); verify(simulatedStudent, times(0)).performInitialCalls(); - verify(simulatedStudent, times(0)).startExamParticipation(anyLong(), anyLong()); + verify(simulatedStudent, times(0)).startExamParticipation(anyLong(), anyLong(), 0); verify(simulatedStudent, times(0)).participateInExam(anyLong(), anyLong(), false); verify(simulatedStudent, times(0)).submitAndEndExam(anyLong(), anyLong()); } @@ -920,7 +920,7 @@ public void testExistingCourseCreateExam_fail_onCreateExam() { )) { verify(simulatedStudent, times(0)).login(); verify(simulatedStudent, times(0)).performInitialCalls(); - verify(simulatedStudent, times(0)).startExamParticipation(anyLong(), anyLong()); + verify(simulatedStudent, times(0)).startExamParticipation(anyLong(), anyLong(), 0); verify(simulatedStudent, times(0)).participateInExam(anyLong(), anyLong(), false); verify(simulatedStudent, times(0)).submitAndEndExam(anyLong(), anyLong()); } @@ -978,7 +978,7 @@ public void testExistingCourseCreateExam_fail_onCreateExamExercises() { )) { verify(simulatedStudent, times(0)).login(); verify(simulatedStudent, times(0)).performInitialCalls(); - verify(simulatedStudent, times(0)).startExamParticipation(anyLong(), anyLong()); + verify(simulatedStudent, times(0)).startExamParticipation(anyLong(), anyLong(), 0); verify(simulatedStudent, times(0)).participateInExam(anyLong(), anyLong(), false); verify(simulatedStudent, times(0)).submitAndEndExam(anyLong(), anyLong()); } @@ -1036,7 +1036,7 @@ public void testExistingCourseCreateExam_fail_onRegisterStudentsForExam() { )) { verify(simulatedStudent, times(0)).login(); verify(simulatedStudent, times(0)).performInitialCalls(); - verify(simulatedStudent, times(0)).startExamParticipation(anyLong(), anyLong()); + verify(simulatedStudent, times(0)).startExamParticipation(anyLong(), anyLong(), 0); verify(simulatedStudent, times(0)).participateInExam(anyLong(), anyLong(), false); verify(simulatedStudent, times(0)).submitAndEndExam(anyLong(), anyLong()); } @@ -1094,7 +1094,7 @@ public void testExistingCourseCreateExam_fail_onPrepareExam() { )) { verify(simulatedStudent, times(0)).login(); verify(simulatedStudent, times(0)).performInitialCalls(); - verify(simulatedStudent, times(0)).startExamParticipation(anyLong(), anyLong()); + verify(simulatedStudent, times(0)).startExamParticipation(anyLong(), anyLong(), 0); verify(simulatedStudent, times(0)).participateInExam(anyLong(), anyLong(), false); verify(simulatedStudent, times(0)).submitAndEndExam(anyLong(), anyLong()); } @@ -1137,9 +1137,9 @@ public void testExistingCourseCreateExam_success_studentsCannotConnect() { when(simulatedArtemisStudent1.performInitialCalls()).thenThrow(new RuntimeException("Test exception")); when(simulatedArtemisStudent2.performInitialCalls()).thenThrow(new RuntimeException("Test exception")); when(simulatedArtemisStudent3.performInitialCalls()).thenThrow(new RuntimeException("Test exception")); - when(simulatedArtemisStudent1.startExamParticipation(anyLong(), anyLong())).thenThrow(new RuntimeException("Test exception")); - when(simulatedArtemisStudent2.startExamParticipation(anyLong(), anyLong())).thenThrow(new RuntimeException("Test exception")); - when(simulatedArtemisStudent3.startExamParticipation(anyLong(), anyLong())).thenThrow(new RuntimeException("Test exception")); + when(simulatedArtemisStudent1.startExamParticipation(anyLong(), anyLong(), 0)).thenThrow(new RuntimeException("Test exception")); + when(simulatedArtemisStudent2.startExamParticipation(anyLong(), anyLong(), 0)).thenThrow(new RuntimeException("Test exception")); + when(simulatedArtemisStudent3.startExamParticipation(anyLong(), anyLong(), 0)).thenThrow(new RuntimeException("Test exception")); when(simulatedArtemisStudent1.participateInExam(anyLong(), anyLong(), false)).thenThrow(new RuntimeException("Test exception")); when(simulatedArtemisStudent2.participateInExam(anyLong(), anyLong(), false)).thenThrow(new RuntimeException("Test exception")); when(simulatedArtemisStudent3.participateInExam(anyLong(), anyLong(), false)).thenThrow(new RuntimeException("Test exception")); @@ -1167,7 +1167,7 @@ public void testExistingCourseCreateExam_success_studentsCannotConnect() { )) { verify(simulatedStudent, times(1)).login(); verify(simulatedStudent, times(1)).performInitialCalls(); - verify(simulatedStudent, times(1)).startExamParticipation(1, 1); + verify(simulatedStudent, times(1)).startExamParticipation(1, 1, 0); verify(simulatedStudent, times(1)).participateInExam(1, 1, false); verify(simulatedStudent, times(1)).submitAndEndExam(1, 1); } @@ -1225,7 +1225,7 @@ public void testExistingCourseCreateExam_success_failOnCleanup() { )) { verify(simulatedStudent, times(1)).login(); verify(simulatedStudent, times(1)).performInitialCalls(); - verify(simulatedStudent, times(1)).startExamParticipation(1, 1); + verify(simulatedStudent, times(1)).startExamParticipation(1, 1, 0); verify(simulatedStudent, times(1)).participateInExam(1, 1, false); verify(simulatedStudent, times(1)).submitAndEndExam(1, 1); } From 281c6e88246a63f23a53f2f7e831fd1bf27c31a4 Mon Sep 17 00:00:00 2001 From: Mohamed Bilel Besrour Date: Sun, 7 Jul 2024 17:13:06 +0200 Subject: [PATCH 12/15] fix tests --- .../interaction/SimulatedArtemisStudent.java | 10 ---- .../service/SimulationExecutionServiceIT.java | 60 +++++++++++-------- 2 files changed, 36 insertions(+), 34 deletions(-) diff --git a/src/main/java/de/tum/cit/ase/service/artemis/interaction/SimulatedArtemisStudent.java b/src/main/java/de/tum/cit/ase/service/artemis/interaction/SimulatedArtemisStudent.java index 2450807d..c267d03f 100644 --- a/src/main/java/de/tum/cit/ase/service/artemis/interaction/SimulatedArtemisStudent.java +++ b/src/main/java/de/tum/cit/ase/service/artemis/interaction/SimulatedArtemisStudent.java @@ -108,16 +108,6 @@ public List participateInExam(long courseId, long examId, boolean o return requestStats; } - /** - * Start participating in an exam, i.e. navigate into the exam and start the exam. - * @param courseId the ID of the course - * @param examId the ID of the exam - * @return the list of request stats - */ - public List startExamParticipation(long courseId, long examId) { - return startExamParticipation(courseId, examId, 0); - } - /** * Start participating in an exam, i.e. navigate into the exam and start the exam. * @param courseId the ID of the course diff --git a/src/test/java/de/tum/cit/ase/service/SimulationExecutionServiceIT.java b/src/test/java/de/tum/cit/ase/service/SimulationExecutionServiceIT.java index 741351b5..ed65bf2a 100644 --- a/src/test/java/de/tum/cit/ase/service/SimulationExecutionServiceIT.java +++ b/src/test/java/de/tum/cit/ase/service/SimulationExecutionServiceIT.java @@ -632,8 +632,8 @@ public void testCreateCourseAndExam_fail_onInitializeStudents() { )) { verify(simulatedStudent, times(0)).login(); verify(simulatedStudent, times(0)).performInitialCalls(); - verify(simulatedStudent, times(0)).startExamParticipation(anyLong(), anyLong(), 0); - verify(simulatedStudent, times(0)).participateInExam(anyLong(), anyLong(), false); + verify(simulatedStudent, times(0)).startExamParticipation(anyLong(), anyLong(), anyLong()); + verify(simulatedStudent, times(0)).participateInExam(anyLong(), anyLong(), anyBoolean()); verify(simulatedStudent, times(0)).submitAndEndExam(anyLong(), anyLong()); } @@ -687,8 +687,8 @@ public void testCreateCourseAndExam_fail_onInitializeAdmin() { )) { verify(simulatedStudent, times(0)).login(); verify(simulatedStudent, times(0)).performInitialCalls(); - verify(simulatedStudent, times(0)).startExamParticipation(anyLong(), anyLong(), 0); - verify(simulatedStudent, times(0)).participateInExam(anyLong(), anyLong(), false); + verify(simulatedStudent, times(0)).startExamParticipation(anyLong(), anyLong(), anyLong()); + verify(simulatedStudent, times(0)).participateInExam(anyLong(), anyLong(), anyBoolean()); verify(simulatedStudent, times(0)).submitAndEndExam(anyLong(), anyLong()); } @@ -744,8 +744,8 @@ public void testCreateCourseAndExam_fail_onCreateCourse() { )) { verify(simulatedStudent, times(0)).login(); verify(simulatedStudent, times(0)).performInitialCalls(); - verify(simulatedStudent, times(0)).startExamParticipation(anyLong(), anyLong(), 0); - verify(simulatedStudent, times(0)).participateInExam(anyLong(), anyLong(), false); + verify(simulatedStudent, times(0)).startExamParticipation(anyLong(), anyLong(), anyLong()); + verify(simulatedStudent, times(0)).participateInExam(anyLong(), anyLong(), anyBoolean()); verify(simulatedStudent, times(0)).submitAndEndExam(anyLong(), anyLong()); } @@ -804,8 +804,8 @@ public void testCreateCourseAndExam_fail_onRegisterStudentsForCourse() { )) { verify(simulatedStudent, times(0)).login(); verify(simulatedStudent, times(0)).performInitialCalls(); - verify(simulatedStudent, times(0)).startExamParticipation(anyLong(), anyLong(), 0); - verify(simulatedStudent, times(0)).participateInExam(anyLong(), anyLong(), false); + verify(simulatedStudent, times(0)).startExamParticipation(anyLong(), anyLong(), anyLong()); + verify(simulatedStudent, times(0)).participateInExam(anyLong(), anyLong(), anyBoolean()); verify(simulatedStudent, times(0)).submitAndEndExam(anyLong(), anyLong()); } @@ -862,8 +862,8 @@ public void testExistingCourseCreateExam_fail_onGetCourse() { )) { verify(simulatedStudent, times(0)).login(); verify(simulatedStudent, times(0)).performInitialCalls(); - verify(simulatedStudent, times(0)).startExamParticipation(anyLong(), anyLong(), 0); - verify(simulatedStudent, times(0)).participateInExam(anyLong(), anyLong(), false); + verify(simulatedStudent, times(0)).startExamParticipation(anyLong(), anyLong(), anyLong()); + verify(simulatedStudent, times(0)).participateInExam(anyLong(), anyLong(), anyBoolean()); verify(simulatedStudent, times(0)).submitAndEndExam(anyLong(), anyLong()); } @@ -920,8 +920,8 @@ public void testExistingCourseCreateExam_fail_onCreateExam() { )) { verify(simulatedStudent, times(0)).login(); verify(simulatedStudent, times(0)).performInitialCalls(); - verify(simulatedStudent, times(0)).startExamParticipation(anyLong(), anyLong(), 0); - verify(simulatedStudent, times(0)).participateInExam(anyLong(), anyLong(), false); + verify(simulatedStudent, times(0)).startExamParticipation(anyLong(), anyLong(), anyLong()); + verify(simulatedStudent, times(0)).participateInExam(anyLong(), anyLong(), anyBoolean()); verify(simulatedStudent, times(0)).submitAndEndExam(anyLong(), anyLong()); } @@ -978,8 +978,8 @@ public void testExistingCourseCreateExam_fail_onCreateExamExercises() { )) { verify(simulatedStudent, times(0)).login(); verify(simulatedStudent, times(0)).performInitialCalls(); - verify(simulatedStudent, times(0)).startExamParticipation(anyLong(), anyLong(), 0); - verify(simulatedStudent, times(0)).participateInExam(anyLong(), anyLong(), false); + verify(simulatedStudent, times(0)).startExamParticipation(anyLong(), anyLong(), anyLong()); + verify(simulatedStudent, times(0)).participateInExam(anyLong(), anyLong(), anyBoolean()); verify(simulatedStudent, times(0)).submitAndEndExam(anyLong(), anyLong()); } @@ -1036,8 +1036,8 @@ public void testExistingCourseCreateExam_fail_onRegisterStudentsForExam() { )) { verify(simulatedStudent, times(0)).login(); verify(simulatedStudent, times(0)).performInitialCalls(); - verify(simulatedStudent, times(0)).startExamParticipation(anyLong(), anyLong(), 0); - verify(simulatedStudent, times(0)).participateInExam(anyLong(), anyLong(), false); + verify(simulatedStudent, times(0)).startExamParticipation(anyLong(), anyLong(), anyLong()); + verify(simulatedStudent, times(0)).participateInExam(anyLong(), anyLong(), anyBoolean()); verify(simulatedStudent, times(0)).submitAndEndExam(anyLong(), anyLong()); } @@ -1094,8 +1094,8 @@ public void testExistingCourseCreateExam_fail_onPrepareExam() { )) { verify(simulatedStudent, times(0)).login(); verify(simulatedStudent, times(0)).performInitialCalls(); - verify(simulatedStudent, times(0)).startExamParticipation(anyLong(), anyLong(), 0); - verify(simulatedStudent, times(0)).participateInExam(anyLong(), anyLong(), false); + verify(simulatedStudent, times(0)).startExamParticipation(anyLong(), anyLong(), anyLong()); + verify(simulatedStudent, times(0)).participateInExam(anyLong(), anyLong(), anyBoolean()); verify(simulatedStudent, times(0)).submitAndEndExam(anyLong(), anyLong()); } @@ -1137,12 +1137,24 @@ public void testExistingCourseCreateExam_success_studentsCannotConnect() { when(simulatedArtemisStudent1.performInitialCalls()).thenThrow(new RuntimeException("Test exception")); when(simulatedArtemisStudent2.performInitialCalls()).thenThrow(new RuntimeException("Test exception")); when(simulatedArtemisStudent3.performInitialCalls()).thenThrow(new RuntimeException("Test exception")); - when(simulatedArtemisStudent1.startExamParticipation(anyLong(), anyLong(), 0)).thenThrow(new RuntimeException("Test exception")); - when(simulatedArtemisStudent2.startExamParticipation(anyLong(), anyLong(), 0)).thenThrow(new RuntimeException("Test exception")); - when(simulatedArtemisStudent3.startExamParticipation(anyLong(), anyLong(), 0)).thenThrow(new RuntimeException("Test exception")); - when(simulatedArtemisStudent1.participateInExam(anyLong(), anyLong(), false)).thenThrow(new RuntimeException("Test exception")); - when(simulatedArtemisStudent2.participateInExam(anyLong(), anyLong(), false)).thenThrow(new RuntimeException("Test exception")); - when(simulatedArtemisStudent3.participateInExam(anyLong(), anyLong(), false)).thenThrow(new RuntimeException("Test exception")); + when(simulatedArtemisStudent1.startExamParticipation(anyLong(), anyLong(), anyLong())).thenThrow( + new RuntimeException("Test exception") + ); + when(simulatedArtemisStudent2.startExamParticipation(anyLong(), anyLong(), anyLong())).thenThrow( + new RuntimeException("Test exception") + ); + when(simulatedArtemisStudent3.startExamParticipation(anyLong(), anyLong(), anyLong())).thenThrow( + new RuntimeException("Test exception") + ); + when(simulatedArtemisStudent1.participateInExam(anyLong(), anyLong(), anyBoolean())).thenThrow( + new RuntimeException("Test exception") + ); + when(simulatedArtemisStudent2.participateInExam(anyLong(), anyLong(), anyBoolean())).thenThrow( + new RuntimeException("Test exception") + ); + when(simulatedArtemisStudent3.participateInExam(anyLong(), anyLong(), anyBoolean())).thenThrow( + new RuntimeException("Test exception") + ); when(simulatedArtemisStudent1.submitAndEndExam(anyLong(), anyLong())).thenThrow(new RuntimeException("Test exception")); when(simulatedArtemisStudent2.submitAndEndExam(anyLong(), anyLong())).thenThrow(new RuntimeException("Test exception")); when(simulatedArtemisStudent3.submitAndEndExam(anyLong(), anyLong())).thenThrow(new RuntimeException("Test exception")); From ddeddb832b3515287ec8565279499ccf0188a449 Mon Sep 17 00:00:00 2001 From: Mohamed Bilel Besrour Date: Sun, 7 Jul 2024 18:03:44 +0200 Subject: [PATCH 13/15] fix tests --- .../SimulationExecutionService.java | 25 ++++++++++--------- 1 file changed, 13 insertions(+), 12 deletions(-) diff --git a/src/main/java/de/tum/cit/ase/service/simulation/SimulationExecutionService.java b/src/main/java/de/tum/cit/ase/service/simulation/SimulationExecutionService.java index 8d9af342..13731538 100644 --- a/src/main/java/de/tum/cit/ase/service/simulation/SimulationExecutionService.java +++ b/src/main/java/de/tum/cit/ase/service/simulation/SimulationExecutionService.java @@ -195,21 +195,22 @@ public synchronized void simulateExam(SimulationRun simulationRun) { finishSimulationRun(runWithResult); sendRunResult(runWithResult); - if (admin == null) { + if (artemisConfiguration.getIsLocal(simulationRun.getSimulation().getServer())) { + if (admin == null) { + try { + admin = initializeAdminFromUserManagement(simulationRun.getSimulation().getServer()); + } catch (Exception e) { + logAndSend(true, simulationRun, "Cannot get CI status, no admin account available."); + return; + } + } + // Subscribe to CI status, as we can only safely delete the course after all CI jobs have finished try { - admin = initializeAdminFromUserManagement(simulationRun.getSimulation().getServer()); - } catch (Exception e) { - logAndSend(true, simulationRun, "Cannot get CI status, no admin account available."); - return; + ciStatusService.subscribeToCiStatusViaResults(runWithResult, admin, examId).get(); + } catch (ExecutionException | InterruptedException e) { + logAndSend(true, simulationRun, "Error while subscribing to CI status: %s", e.getMessage()); } } - - // Subscribe to CI status, as we can only safely delete the course after all CI jobs have finished - try { - ciStatusService.subscribeToCiStatusViaResults(runWithResult, admin, examId).get(); - } catch (ExecutionException | InterruptedException e) { - logAndSend(true, simulationRun, "Error while subscribing to CI status: %s", e.getMessage()); - } cleanupAsync(admin, simulationRun, courseId, examId); } From 9d020846df7dd279ff35a7cff955746454d4c7bc Mon Sep 17 00:00:00 2001 From: Ole Vester Date: Sun, 7 Jul 2024 22:30:36 +0200 Subject: [PATCH 14/15] Store and display new request types --- .../java/de/tum/cit/ase/domain/RequestType.java | 2 -- .../interaction/SimulatedArtemisStudent.java | 4 ++-- .../service/simulation/SimulationResultService.java | 13 +++++++++++++ .../webapp/app/entities/simulation/requestType.ts | 3 +++ .../app/entities/simulation/simulationStats.ts | 8 +++++++- 5 files changed, 25 insertions(+), 5 deletions(-) diff --git a/src/main/java/de/tum/cit/ase/domain/RequestType.java b/src/main/java/de/tum/cit/ase/domain/RequestType.java index 56f3cd42..bb0fd5b9 100644 --- a/src/main/java/de/tum/cit/ase/domain/RequestType.java +++ b/src/main/java/de/tum/cit/ase/domain/RequestType.java @@ -11,8 +11,6 @@ public enum RequestType { PUSH, PROGRAMMING_EXERCISE_RESULT, REPOSITORY_INFO, - REPOSITORY_FILE, REPOSITORY_FILES, - PLANT_UML, MISC, } diff --git a/src/main/java/de/tum/cit/ase/service/artemis/interaction/SimulatedArtemisStudent.java b/src/main/java/de/tum/cit/ase/service/artemis/interaction/SimulatedArtemisStudent.java index c267d03f..e6725648 100644 --- a/src/main/java/de/tum/cit/ase/service/artemis/interaction/SimulatedArtemisStudent.java +++ b/src/main/java/de/tum/cit/ase/service/artemis/interaction/SimulatedArtemisStudent.java @@ -725,7 +725,7 @@ private RequestStat fetchFile(Long participationId, String fileName) { .retrieve() .toBodilessEntity() .block(); - return new RequestStat(now(), System.nanoTime() - start, REPOSITORY_FILE); + return new RequestStat(now(), System.nanoTime() - start, REPOSITORY_FILES); } private RequestStat fetchFiles(Long participationId) { @@ -739,7 +739,7 @@ private RequestStat fetchPlantUml() { String plantUmlString = "%40startuml%0A%0Aclass%20Client%20%7B%0A%7D%0A%0Aclass%20Policy%20%7B%0A%20%20%3Ccolor%3Agrey%3E%2Bconfigure()%3C%2Fcolor%3E%0A%7D%0A%0Aclass%20Context%20%7B%0A%20%20%3Ccolor%3Agrey%3E-dates%3A%20List%3CDate%3E%3C%2Fcolor%3E%0A%20%20%3Ccolor%3Agrey%3E%2Bsort()%3C%2Fcolor%3E%0A%7D%0A%0Ainterface%20SortStrategy%20%7B%0A%20%20%3Ccolor%3Agrey%3E%2BperformSort(List%3CDate%3E)%3C%2Fcolor%3E%0A%7D%0A%0Aclass%20BubbleSort%20%7B%0A%20%20%3Ccolor%3Agrey%3E%2BperformSort(List%3CDate%3E)%3C%2Fcolor%3E%0A%7D%0A%0Aclass%20MergeSort%20%7B%0A%20%20%3Ccolor%3Agrey%3E%2BperformSort(List%3CDate%3E)%3C%2Fcolor%3E%0A%7D%0A%0AMergeSort%20-up-%7C%3E%20SortStrategy%20%23grey%0ABubbleSort%20-up-%7C%3E%20SortStrategy%20%23grey%0APolicy%20-right-%3E%20Context%20%23grey%3A%20context%0AContext%20-right-%3E%20SortStrategy%20%23grey%3A%20sortAlgorithm%0AClient%20.down.%3E%20Policy%0AClient%20.down.%3E%20Context%0A%0Ahide%20empty%20fields%0Ahide%20empty%20methods%0A%0A%40enduml&useDarkTheme=true"; webClient.get().uri("api/plantuml/svg?plantuml=" + plantUmlString).retrieve().toBodilessEntity().block(); - return new RequestStat(now(), System.nanoTime() - start, REPOSITORY_FILES); + return new RequestStat(now(), System.nanoTime() - start, MISC); } private RequestStat cloneRepo(String repositoryUrl) throws IOException { diff --git a/src/main/java/de/tum/cit/ase/service/simulation/SimulationResultService.java b/src/main/java/de/tum/cit/ase/service/simulation/SimulationResultService.java index 11ac8ef1..eb3abb53 100644 --- a/src/main/java/de/tum/cit/ase/service/simulation/SimulationResultService.java +++ b/src/main/java/de/tum/cit/ase/service/simulation/SimulationResultService.java @@ -71,6 +71,16 @@ public SimulationRun calculateAndSaveResult(SimulationRun simulationRun, List Date: Sun, 7 Jul 2024 22:31:25 +0200 Subject: [PATCH 15/15] Fix writeToFile --- .../service/artemis/interaction/SimulatedArtemisStudent.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/main/java/de/tum/cit/ase/service/artemis/interaction/SimulatedArtemisStudent.java b/src/main/java/de/tum/cit/ase/service/artemis/interaction/SimulatedArtemisStudent.java index e6725648..ca236b8c 100644 --- a/src/main/java/de/tum/cit/ase/service/artemis/interaction/SimulatedArtemisStudent.java +++ b/src/main/java/de/tum/cit/ase/service/artemis/interaction/SimulatedArtemisStudent.java @@ -534,7 +534,8 @@ private List solveAndSubmitProgrammingExercise(ProgrammingExercise for (int j = 0; j < n; j++) { sleep(100); var makeInvalidChange = new Random().nextBoolean(); - var changedFileContent = changeFiles(makeInvalidChange, false); + var writeToFile = !onlineIDE; + var changedFileContent = changeFiles(makeInvalidChange, writeToFile); commitAndPush(requestStats, onlineIDE, participationId, changedFileContent); }