Skip to content

Commit

Permalink
Integration solution evaluation service (#6)
Browse files Browse the repository at this point in the history
* static analysis works somehow (can't belive it)

* .

* can now clone repositories

* now compilation works

* added test execution

* test execution uses tests from the official repo (no cheaters)

* added cleanup

* added tests

* added Dockerfile

* bash scripts wouldn't work in docker, I am very disappointed in what I had to do to make this thing work...

* just moved the scripts folder...

* made the same ugly fix for the scripts in unzipService, now everything is in strings

* fixed small bugs

* added integration test for solution-evaluation-service

* test finally works

* Modified the creation of the battle and added the unique constraint on repository link of the battle

* refactored docker-comopse, added ContainerHandler methods in all integration tests

* Removed the repository link for team

---------

Co-authored-by: tommi <[email protected]>
  • Loading branch information
SigCatta and Felle33 committed Feb 4, 2024
1 parent 995706a commit 96a879d
Show file tree
Hide file tree
Showing 54 changed files with 1,734 additions and 88 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -29,8 +29,8 @@ public ResponseEntity<Object> getStudentMails() {
.toString();

if (mailAddresses.isEmpty()) {
log.error("No students found");
return new ResponseEntity<>("No students found", getHeaders(), HttpStatus.NOT_FOUND);
log.warn("No students found, maybe the database is empty?");
return new ResponseEntity<>("", getHeaders(), HttpStatus.OK);
}

List<String> addresses = Arrays.stream(mailAddresses.split(","))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -59,8 +59,7 @@ public void notFoundRequest() {
ResponseEntity<Object> response = mailStudentsController.getStudentMails();
assertNotNull(response.getBody());

assertTrue(response.getStatusCode().is4xxClientError());
assertTrue(response.getBody().toString().contains("No students found"));
assertTrue(response.getStatusCode().is2xxSuccessful());
}

private List<String> convertBodyToList(ResponseEntity<Object> response) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ public GetTeamController(BattleService battleService) {
* @param request id of the team
* @return a ResponseEntity with the team or a not found status
*/
@GetMapping("/get-team")
@PostMapping("/get-team")
public ResponseEntity<TeamInfoMessage> getTeam(@RequestBody GetTeamStudentRequest request) {
log.info("[API REQUEST] Get team request with id: {}", request.getBattleId());
try {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
package ckb.BattleManager.dto.input;

import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;

@Data
@Builder
@AllArgsConstructor
@NoArgsConstructor
public class JoinRequest {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,13 @@

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

import java.util.List;

@Data
@AllArgsConstructor
@NoArgsConstructor
public class TeamInfoMessage {
List<String> participantsName;
private Long teamId;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ public class Battle {

private Long tournamentId;

@Column(unique = true)
private String repositoryLink;

@OneToMany(mappedBy = "battle", fetch = FetchType.EAGER, cascade = CascadeType.ALL)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,6 @@ public class Team {
@OneToMany(mappedBy = "team", fetch = FetchType.EAGER, cascade = CascadeType.ALL, orphanRemoval = true)
private List<Participation> participation;

private String repositoryLink;

private Integer score;

private Boolean eduEvaluated;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ public void startBattles() {
sendMailsToParticipants.send(
battleService.getBattleParticipants(battle),
"The battle " + battle.getName() + " is started.\nCheck out the code kata following the link: "
+ "https://github.com/" + battle.getRepositoryLink(),
+ battle.getRepositoryLink(),
battle.getName()
);
} catch (Exception e) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -51,24 +51,19 @@ public Battle createBattle(CreateBattleRequest battleRequest) throws Exception {
.hasEnded(false)
.isClosed(false)
.build();
battleRepository.save(battle);
log.info("Battle saved in the database: {}", battle);
log.info("Battle built: {}", battle);

try {
String repoLink = createGHRepositoryBattleController
.createGHRepository(battle, battleRequest.getFiles());
// https://github.com/Code-Kata-Battle/Test-Battle-xvmudweqnxshqtehmcgq
// 19 => because I want to erase the first 19 chars
repoLink = repoLink.substring(19);
battle.setRepositoryLink(repoLink);
battleRepository.save(battle);
log.info("Battle saved in the database: {}", battle);
} catch (Exception e) {
log.error("Error creating repo in GitHub. Error {}", e.getMessage());
battleRepository.delete(battle);
log.error("Error creating repo in GitHub, the battle {} will not saved in the database. Error {}", battle.getName(), e.getMessage());
throw new Exception("Error creating repo in GitHub");
}

log.info("Set the name of the repository of the battle: {}", battle.getRepositoryLink());
return battle;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,29 +4,28 @@
import ckb.BattleManager.model.Participation;
import ckb.BattleManager.model.Team;
import ckb.BattleManager.model.WorkingPair;
import ckb.BattleManager.repository.ParticipationRepository;
import ckb.BattleManager.repository.TeamRepository;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.time.LocalDateTime;
import java.time.temporal.ChronoUnit;
import java.util.Collection;
import java.util.List;

@Service
@Slf4j
public class TeamService {
private final int MAX_TIME_DEDUCTION = 50;
private final TeamRepository teamRepository;
private final ParticipationRepository participationRepository;
private final ParticipationService participationService;

@Autowired
public TeamService(TeamRepository teamRepository, ParticipationRepository participationRepository, ParticipationService participationService) {
public TeamService(TeamRepository teamRepository, ParticipationService participationService) {
this.teamRepository = teamRepository;
this.participationService = participationService;
this.participationRepository = participationRepository;
}

public Team getTeam(Long idTeam) throws Exception {
Expand All @@ -50,7 +49,6 @@ public void createTeam(Long studentId, Battle battle) {
// TODO: how to set the repository link?
Team team = Team.builder()
.battle(battle)
.repositoryLink("")
.eduEvaluated(false)
.score(0)
.canParticipateToBattle(true)
Expand Down Expand Up @@ -122,12 +120,27 @@ public void assignScore(Long idTeam, Integer score) throws Exception {
throw new Exception("Team score cannot be updated because the tournament is closed");
}

int timeDeduction = computeTimeDeduction(battleOfTeam);
log.info("Time deduction for team with id {}: {}", idTeam, timeDeduction);
score = score - timeDeduction;

team.setScore(Math.max(score, team.getScore()));
teamRepository.save(team);

log.info("Team score updated with id {} and score: {}", idTeam, score);
}

private Integer computeTimeDeduction(Battle battleOfTeam) {
LocalDateTime subDeadline = battleOfTeam.getSubDeadline();
LocalDateTime registrationDeadline = battleOfTeam.getRegDeadline();
LocalDateTime now = LocalDateTime.now();

long battleMinutes = ChronoUnit.MINUTES.between(registrationDeadline, subDeadline);
long minutesPassed = ChronoUnit.MINUTES.between(registrationDeadline, now);

return MAX_TIME_DEDUCTION *( (int) (minutesPassed / battleMinutes));
}

public void assignPersonalScore(Long idTeam, Integer score, Long idEducator) throws Exception {
if (score < 0) {
log.info("Score cannot be negative");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,13 +14,34 @@
@Service
@Slf4j
public class UnzipService {
private final String SCRIPTS_PATH = getScriptsPath();

public List<WorkingPair<String, String>> unzip(String zipFileName, String randomName) throws IOException {
Process process;
String script = SCRIPTS_PATH + "unzip.sh";
ProcessBuilder processBuilder = new ProcessBuilder(script, zipFileName, randomName
).redirectErrorStream(true);
String script =
// create a directory with random name where to unzip the files
"cd || exit 1\n" +
"zipFilePath=" + zipFileName + ";\n" +
"mkdir " + randomName + ";\n" +
"mv " + zipFileName + " " + randomName + ";\n" +
"cd " + randomName + " || exit 1;\n" +

// unzip the file and remove the .git folder
"zipFileName=\"${zipFilePath##*/}\";\n" +
"unzip \"$zipFileName\";\n" +
"unzipDir=$(pwd);\n" +
"cd \"$unzipDir\" || exit 1;\n" +
"rm -rf .git/;\n" +
"readarray -t paths < <(find ./ -type f);\n" +

"echo;\n" +
"echo \"Unzip completed\";\n" +

// print the path of each file
"for path in \"${paths[@]}\"; do\n" +
"\techo \"$path\";\n" +
"done\n" +
"cd || exit 1;\n" +
"exit";
ProcessBuilder processBuilder = new ProcessBuilder("/bin/bash", "-c", script).redirectErrorStream(true);
process = processBuilder.start();

List<WorkingPair<String, String>> files = new ArrayList<>();
Expand Down Expand Up @@ -48,18 +69,24 @@ public List<WorkingPair<String, String>> unzip(String zipFileName, String random

private void cleanUp(String randomName) throws IOException, InterruptedException {
Process process;
String script = SCRIPTS_PATH + "destroyer.sh";
ProcessBuilder processBuilder = new ProcessBuilder(script, randomName).redirectErrorStream(true);
String script =
"cd || exit 1;\n" +
"rm -rf " + randomName + ";\n" +
"exit 0";
ProcessBuilder processBuilder = new ProcessBuilder("/bin/bash", "-c", script).redirectErrorStream(true);
process = processBuilder.start();
if (process.waitFor() != 0) throw new RuntimeException("Error while cleaning up");
}

private String readFiledContent(String zipFileName, String path, String randomName) throws IOException {
log.info("Reading file: {} at {} ...", path, zipFileName);
Process process;
String script = SCRIPTS_PATH + "read-file.sh";
ProcessBuilder processBuilder = new ProcessBuilder(script, zipFileName, path, randomName
).redirectErrorStream(true);

String script =
"cd || exit 1;\n" +
"cd " + randomName + " || exit 1;\n" +
"cat " + path;
ProcessBuilder processBuilder = new ProcessBuilder("/bin/bash", "-c", script).redirectErrorStream(true);
process = processBuilder.start();
try (BufferedReader reader = new BufferedReader(new InputStreamReader(process.getInputStream()))) {
String line;
Expand All @@ -74,9 +101,4 @@ private String readFiledContent(String zipFileName, String path, String randomNa
throw new RuntimeException(e.getMessage());
}
}

private static String getScriptsPath() {
String path = UnzipService.class.getProtectionDomain().getCodeSource().getLocation().getPath();
return path.substring(0, path.indexOf("/battle-manager")) + "/battle-manager/src/main/scripts/";
}
}
13 changes: 6 additions & 7 deletions code/battle-manager/src/main/scripts/read-file.sh
Original file line number Diff line number Diff line change
@@ -1,16 +1,15 @@
#!/usr/bin/bash

# $1 -> zip directory name (on home dir)
# $2 -> file path in the zip directory
# $3 -> directory where the zip file was extracted
# $1 -> file path in the zip directory
# $2 -> directory where the zip file was extracted

if [ $# -ne 3 ]; then
echo "[ERROR] Usage: $0 <zip directory name i.e. random string> <path of the file to reade> <directory where the zip file was extracted>"
if [ $# -ne 2 ]; then
echo "[ERROR] Usage: $0 <path of the file to read> <directory where the zip file was extracted>"
exit 1
fi

cd || exit 1

cd "$3" || exit 1
cd "$2" || exit 1

cat "$2"
cat "$1"
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,6 @@ void setUp() {

team = new Team();
team.setBattle(battle);
team.setRepositoryLink("team_link");
team.setScore(0);
team.setEduEvaluated(false);
team.setCanParticipateToBattle(true);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -113,7 +113,6 @@ void startBattlesWithAnIncorrectTeam() throws InterruptedException {
Team team1 = new Team();
team1.setBattle(battleToStart);
team1.setScore(10);
team1.setRepositoryLink("linkTeam");
team1.setCanParticipateToBattle(true);

Participation participation1 = new Participation();
Expand All @@ -132,7 +131,6 @@ void startBattlesWithAnIncorrectTeam() throws InterruptedException {
Team team2 = new Team();
team2.setBattle(battleToStart);
team2.setScore(10);
team2.setRepositoryLink("linkTeam");
team2.setCanParticipateToBattle(false);
teamRepository.save(team2);

Expand Down Expand Up @@ -179,7 +177,6 @@ void startBattlesWithAnIncorrectTeam2() throws InterruptedException {
Team team3 = new Team();
team3.setBattle(battleToStart);
team3.setScore(10);
team3.setRepositoryLink("linkTeam");
team3.setCanParticipateToBattle(true);
teamRepository.save(team3);

Expand Down Expand Up @@ -214,7 +211,6 @@ void closeBattles() throws InterruptedException {
Team team = new Team();
team.setBattle(battleToClose);
team.setScore(10);
team.setRepositoryLink("linkTeam");
team.setCanParticipateToBattle(true);
teamRepository.save(team);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -58,14 +58,12 @@ void setUp() throws JSONException {

team1 = new Team();
team1.setBattle(battle);
team1.setRepositoryLink("team_link");
team1.setScore(0);
team1.setEduEvaluated(false);
team1.setCanParticipateToBattle(true);

team2 = new Team();
team2.setBattle(battle);
team2.setRepositoryLink("team_link2");
team2.setScore(20);
team2.setEduEvaluated(false);
team2.setCanParticipateToBattle(true);
Expand All @@ -92,7 +90,6 @@ void setUp() throws JSONException {

team3 = new Team();
team3.setBattle(battle);
team3.setRepositoryLink("team_link3");
team3.setScore(20);
team3.setEduEvaluated(false);
team3.setCanParticipateToBattle(false);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
import ckb.BattleManager.model.WorkingPair;
import org.junit.jupiter.api.Disabled;
import org.junit.jupiter.api.Test;
import org.mockserver.integration.ClientAndServer;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.http.ResponseEntity;
Expand All @@ -14,12 +15,15 @@
import java.util.Random;

import static org.junit.jupiter.api.Assertions.assertTrue;
import static org.mockserver.model.HttpRequest.request;
import static org.mockserver.model.HttpResponse.response;

@SpringBootTest
public class UnzipServiceTest {
@Autowired
private UnzipService unzipService;
private final WebClient webClient = WebClient.create();
private final ClientAndServer mockServer = new ClientAndServer(8083);
private final int STRING_LENGTH = 20;

@Test
Expand All @@ -28,6 +32,10 @@ public class UnzipServiceTest {
// this method should only be tested manually and locally, otherwise it will fail
// files will be put in the home directory automatically by rest controllers when the application is running
public void unzipTest() throws IOException {

mockServer.when(request().withMethod("POST").withPath("/api/github/create-repo"))
.respond(response().withStatusCode(200));

List<WorkingPair<String, String>> files = unzipService.unzip("repo.zip", getRandomString());

CreateRepositoryRequest repoRequest = CreateRepositoryRequest.builder()
Expand Down
Loading

0 comments on commit 96a879d

Please sign in to comment.