Skip to content

Commit

Permalink
PR feedback commit
Browse files Browse the repository at this point in the history
  • Loading branch information
Triver1 committed May 8, 2024
2 parents ad2ee51 + 8f04b8d commit 7a54c9c
Show file tree
Hide file tree
Showing 5 changed files with 134 additions and 113 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,10 @@
import com.ugent.pidgeon.postgre.models.types.UserRole;
import com.ugent.pidgeon.postgre.repository.*;
import com.ugent.pidgeon.util.*;
import java.util.concurrent.CompletableFuture;
import java.util.zip.ZipException;
import java.util.logging.Level;
import java.util.concurrent.CompletableFuture;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.io.Resource;
import org.springframework.http.HttpHeaders;
Expand Down Expand Up @@ -76,40 +79,40 @@ private SubmissionTemplateModel.SubmissionResult runStructureTest(ZipFile file,

private DockerOutput runDockerTest(ZipFile file, TestEntity testEntity, Path outputPath) throws IOException {

// Get the test file from the server
String testScript = testEntity.getDockerTestScript();
String testTemplate = testEntity.getDockerTestTemplate();
String image = testEntity.getDockerImage();
// Get the test file from the server
String testScript = testEntity.getDockerTestScript();
String testTemplate = testEntity.getDockerTestTemplate();
String image = testEntity.getDockerImage();

// The first script must always be null, otherwise there is nothing to run on the container
if(testScript == null){
return null;
}

// Init container and add input files
DockerSubmissionTestModel model = new DockerSubmissionTestModel(image);
model.addZipInputFiles(file);
// The first script must always be null, otherwise there is nothing to run on the container
if (testScript == null) {
return null;
}

// Copy artifacts to the destination
List<File> artifacts = model.getArtifacts();
// Init container and add input files
DockerSubmissionTestModel model = new DockerSubmissionTestModel(image);
model.addZipInputFiles(file);
DockerOutput output;

if (testTemplate == null) {
// This docker test is configured in the simple mode (store test console logs)
output = model.runSubmission(testScript);
} else {
// This docker test is configured in the template mode (store json with feedback)
output = model.runSubmissionWithTemplate(testScript, testTemplate);
}
// Get list of artifact files generated on submission
List<File> artifacts = model.getArtifacts();

// filehandler copy zips
if (!artifacts.isEmpty()) {
Filehandler.copyFilesAsZip(artifacts, outputPath);
}
// Copy all files as zip into the output directory
Filehandler.copyFilesAsZip(artifacts, outputPath);

// Cleanup garbage files and container
model.cleanUp();

// cleanup docker
model.cleanUp();
return output;

if(testTemplate == null){
// This docker test is configured in the simple mode (store test console logs)
return model.runSubmission(testScript);
}else{
// This docker test is configured in the template mode (store json with feedback)
return model.runSubmissionWithTemplate(testScript, testTemplate);
}
}
}

/**
* Function to get a submission by its ID
Expand All @@ -132,8 +135,8 @@ public ResponseEntity<?> getSubmission(@PathVariable("submissionid") long submis
SubmissionEntity submission = checkResult.getData();
SubmissionJson submissionJson = entityToJsonConverter.getSubmissionJson(submission);

return ResponseEntity.ok(submissionJson);
}
return ResponseEntity.ok(submissionJson);
}

/**
* Function to get all submissions
Expand Down Expand Up @@ -238,51 +241,68 @@ public ResponseEntity<?> submitFile(@RequestParam("file") MultipartFile file, @P
fileEntity.setPath(pathname);
fileRepository.save(fileEntity);

// Run structure tests
TestEntity testEntity = testRepository.findByProjectId(projectid).orElse(null);
SubmissionTemplateModel.SubmissionResult structureTestResult;
if (testEntity == null) {
Logger.getLogger("SubmissionController").info("no tests");
submission.setStructureFeedback("No specific structure requested for this project.");
submission.setStructureAccepted(true);
} else {

// Check file structure
structureTestResult = runStructureTest(new ZipFile(savedFile), testEntity);
if (structureTestResult == null) {
submission.setStructureFeedback(
"No specific structure requested for this project.");
submission.setStructureAccepted(true);
} else {
submission.setStructureAccepted(structureTestResult.passed);
submission.setStructureFeedback(structureTestResult.feedback);
}
// Define docker test as running (1)
submission.setDockerTestState(2);

// save the first feedback, without docker feedback
submissionRepository.save(submission);

if (testEntity.getDockerTestScript() != null) {
// run docker tests in background
File finalSavedFile = savedFile;
CompletableFuture.runAsync(() -> {
try {
// Check if docker tests succeed
DockerOutput dockerOutput = runDockerTest(new ZipFile(finalSavedFile), testEntity,
Filehandler.getSubmissionPath(projectid, groupId, submission.getId()));
if (dockerOutput == null) {
throw new RuntimeException("Error while running docker tests.");
}
// Representation of dockerOutput, this will be a json(easily displayable in frontend) if it is a template test
// or a string if it is a simple test
submission.setDockerFeedback(dockerOutput.toString());
submission.setDockerAccepted(dockerOutput.isAllowed());

submission.setDockerTestState(0);
submissionRepository.save(submission);
} catch (Exception e) {

submission.setDockerFeedback("");
submission.setDockerAccepted(false);

submission.setDockerTestState(-1);
submissionRepository.save(submission);

// Run structure tests
TestEntity testEntity = testRepository.findByProjectId(projectid).orElse(null);
SubmissionTemplateModel.SubmissionResult structureTestResult;
DockerOutput dockerOutput;
if (testEntity == null) {
Logger.getLogger("SubmissionController").info("no tests");
submission.setStructureFeedback("No specific structure requested for this project.");
submission.setStructureAccepted(true);
} else {

// Check file structure
structureTestResult = runStructureTest(new ZipFile(savedFile), testEntity);
if (structureTestResult == null) {
submission.setStructureFeedback(
"No specific structure requested for this project.");
submission.setStructureAccepted(true);
} else {
submission.setStructureAccepted(structureTestResult.passed);
submission.setStructureFeedback(structureTestResult.feedback);
}
// Check if docker tests succeed
dockerOutput = runDockerTest(new ZipFile(savedFile), testEntity, Filehandler.getSubmissionPath(projectid, groupId, submission.getId()).resolve("artifacts.zip"));
if (dockerOutput == null) {
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR)
.body("Error while running docker tests.");
}
// Representation of dockerOutput, this will be a json(easily displayable in frontend) if it is a template test
// or a string if it is a simple test
submission.setDockerFeedback(dockerOutput.getFeedbackAsString());
submission.setDockerAccepted(dockerOutput.isAllowed());
}
submission.setTestFinished(true);
submissionRepository.save(submissionEntity);
// Update the dataabse
submission = submissionRepository.save(submission);
submissionRepository.save(submission);

return ResponseEntity.ok(entityToJsonConverter.getSubmissionJson(submissionEntity));
} catch (Exception e) {
Logger.getGlobal().log(Level.SEVERE, e.getMessage(), e);
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body("Error while saving file: " + e.getMessage());
});
}
}

return ResponseEntity.ok(entityToJsonConverter.getSubmissionJson(submissionEntity));
} catch (IOException ex) {
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR)
.body("Failed to save submissions on file server.");
}
}

/**
* Function to get a submission file
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@
import com.ugent.pidgeon.postgre.models.types.UserRole;
import com.ugent.pidgeon.postgre.repository.*;
import com.ugent.pidgeon.util.*;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.CompletableFuture;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.io.Resource;
import org.springframework.http.*;
Expand Down Expand Up @@ -136,45 +138,46 @@ private ResponseEntity<?> alterTests(
testEntity = new TestEntity();
}

// delete test entry
if(httpMethod.equals(HttpMethod.DELETE)){
// first check if docker image is not used anywhere else
if(!testRepository.imageIsUsed(dockerImage)){
// image is no longer required for any tests
DockerSubmissionTestModel.removeDockerImage(dockerImage);
}

// delete test
testRepository.deleteById(testEntity.getId());
projectEntity.setTestId(null);
projectRepository.save(projectEntity);
return ResponseEntity.ok().build();
}
// Docker test
if(!(dockerImage == null && dockerScript == null && dockerTemplate == null)) {

//Update fields
if (dockerImage != null || !httpMethod.equals(HttpMethod.PATCH)) {
// update/install image if possible, do so in a seperate thread to reduce wait time.
String finalDockerImage = dockerImage;
CompletableFuture.runAsync(() -> {
if (finalDockerImage != null) {
DockerSubmissionTestModel.installImage(finalDockerImage);
}
});
testEntity.setDockerImage(dockerImage);
if (dockerImage == null && !testRepository.imageIsUsed(dockerImage)) {
DockerSubmissionTestModel.removeDockerImage(dockerImage); //TODO: move this to different thread if takes a while
}
}
if (dockerScript != null || !httpMethod.equals(HttpMethod.PATCH)) {

testEntity.setDockerTestScript(dockerScript);
testEntity.setDockerTestTemplate(
dockerTemplate); // If present, the test is in template mode
//Update fields
if (dockerImage != null || !httpMethod.equals(HttpMethod.PATCH)) {
testEntity.setDockerImage(dockerImage);
if (dockerImage == null && !testRepository.imageIsUsed(dockerImage)) {
DockerSubmissionTestModel.removeDockerImage(
dockerImage); //TODO: move this to different thread if takes a while
}
}
if (dockerScript != null || !httpMethod.equals(HttpMethod.PATCH)) {
testEntity.setDockerTestScript(dockerScript);
}
if (dockerTemplate != null || !httpMethod.equals(HttpMethod.PATCH)) {
testEntity.setDockerTestTemplate(dockerTemplate);
}
if (structureTemplate != null || !httpMethod.equals(HttpMethod.PATCH)) {
testEntity.setStructureTemplate(structureTemplate);
}
}
if (dockerTemplate != null || !httpMethod.equals(HttpMethod.PATCH)) {
testEntity.setDockerTestTemplate(dockerTemplate);
}
if (structureTemplate != null || !httpMethod.equals(HttpMethod.PATCH)) {
testEntity.setStructureTemplate(structureTemplate);
}


// save test entity
testEntity = testRepository.save(testEntity);
projectEntity.setTestId(testEntity.getId());
projectRepository.save(projectEntity); // make sure to update test id in project
// save test entity
testEntity = testRepository.save(testEntity);
projectEntity.setTestId(testEntity.getId());
projectRepository.save(projectEntity); // make sure to update test id in project

return ResponseEntity.ok(entityToJsonConverter.testEntityToTestJson(testEntity, projectId));
return ResponseEntity.ok(entityToJsonConverter.testEntityToTestJson(testEntity, projectId));

}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,8 +36,8 @@ public class SubmissionEntity {
@Column(name="docker_feedback")
private String dockerFeedback;

@Column(name="test_finished")
private Boolean testFinished;
@Column(name="docker_test_state")
private Integer dockerTestState;

public SubmissionEntity() {
}
Expand Down Expand Up @@ -119,13 +119,11 @@ public String getDockerFeedback() {
public void setDockerFeedback(String dockerFeedbackFileId) {
this.dockerFeedback = dockerFeedbackFileId;
}

public Boolean getTestFinished() {
return testFinished;
public Integer getDockerTestState() {
return dockerTestState;
}

public void setTestFinished(Boolean testFinished) {
this.testFinished = testFinished;
public void setDockerTestState(Integer dockerTestState) {
this.dockerTestState = dockerTestState;
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -112,7 +112,7 @@ void templateTest() throws InterruptedException {

DockerSubmissionTestModel.installImage("alpine:latest");
// Load docker container
DockerSubmissionTestModel stm = new DockerSubmissionTestModel("alpine");
DockerSubmissionTestModel stm = new DockerSubmissionTestModel("alpine:latest");
stm.addInputFiles(files);
DockerTemplateTestOutput result = stm.runSubmissionWithTemplate(script, template);

Expand Down
2 changes: 1 addition & 1 deletion backend/database/start_database.sql
Original file line number Diff line number Diff line change
Expand Up @@ -108,7 +108,7 @@ CREATE TABLE submissions (
docker_accepted BOOLEAN NOT NULL,
structure_feedback TEXT,
docker_feedback TEXT,
tests_finished BOOLEAN DEFAULT FALSE,
docker_test_state INT DEFAULT 1,
submission_time TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP
);

Expand Down

0 comments on commit 7a54c9c

Please sign in to comment.