Commit 8f2a3683 authored by mamunozgil's avatar mamunozgil
Browse files

Merge branch 'amg-dev-backtracking-manifest' into 'master'

Solve Issue: Finding exercise-manifest

See merge request !1
1 merge request!1Solve Issue: Finding exercise-manifest
Pipeline #10377 passed with stage
in 15 seconds
Showing with 257 additions and 225 deletions
+257 -225
/target
/local-maven-repo
\ No newline at end of file
package de.hftstuttgart.dtabackend.rest.v1.task;
import de.hftstuttgart.dtabackend.utils.*;
import de.hftstuttgart.dtabackend.models.ResultSummary;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.apache.tika.Tika;
import org.springframework.core.env.Environment;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;
import java.io.*;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import jakarta.servlet.annotation.MultipartConfig;
/**
* Rest controller for everything related to the TASK files
*/
@RestController
@RequestMapping("/v1/task/*")
@MultipartConfig
public class TaskUpload {
private static final Logger LOG = LogManager.getLogger(TaskUpload.class);
private final RepoUtil repoUtil;
private final Path testTmpPath;
private final ExecuteTestUtil executeTestUtil;
public TaskUpload(
Environment env,
RepoUtil repoUtil,
ExecuteTestUtil executeTestUtil
) {
this.repoUtil = repoUtil;
this.executeTestUtil = executeTestUtil;
// set path of temporary directory on host and inside our container
this.testTmpPath = Paths.get(env.getProperty("tests.tmp.dir"));
}
@RequestMapping(method = RequestMethod.POST)
public ResultSummary uploadAndTestFile(@RequestParam("taskFile") MultipartFile taskFileRef,
@RequestParam("assignmentId") String assignmentId
) throws IOException, InterruptedException {
LOG.info("submission for testing received");
LOG.debug("creating new temporary directory");
Path workDirectory = Files.createTempDirectory(testTmpPath, "dta");
LOG.debug(String.format("working dir for test is: %s", workDirectory.toAbsolutePath().toString()));
// define paths for the test, the submission and where the result is to be expected afterwards
Path srcPath = Paths.get(workDirectory.toAbsolutePath().toString(), "src");
String mimeInfo = new Tika().detect(taskFileRef.getInputStream());
switch (mimeInfo) {
case "text/plain":
LOG.debug("textfile uploaded, searching for dta config");
// find URI in config file
String subDir="";
Matcher config = RegexUtil.extractConfig(taskFileRef.getInputStream(), Pattern.compile(RegexUtil.DTA_SUBMISSIONCONFIGREGEX));
if(config==null) {
config = RegexUtil.extractConfig(taskFileRef.getInputStream(), Pattern.compile(RegexUtil.SUBMISSIONCONFIGREGEX));
if(config==null)
{
throw new RuntimeException("couldn't find repo config for student submission clone");
}
}
else {
subDir=config.group(4);
}
LOG.debug("calling repo clone");
repoUtil.cloneRepository(config, srcPath.toAbsolutePath().toString(), subDir);
break;
case "application/zip":
LOG.debug("zip archive uploaded, extracting content as student submission");
ArchiveUtil.extractProjectFromZip(taskFileRef.getInputStream(), srcPath.toAbsolutePath());
break;
default:
String msg = String.format("couldn't process uploaded file with mime type %s", mimeInfo);
LOG.error(msg);
throw new RuntimeException(msg);
}
// run test
LOG.debug("calling test execution");
ResultSummary resultSummary = executeTestUtil.runTests(assignmentId, workDirectory);
if (mimeInfo.equals("text/plain")) {
LOG.info("check for provided Ticketsystem information");
UnifiedTicketingUtil.reportResults(taskFileRef.getInputStream(), resultSummary);
}
taskFileRef.getInputStream().close();
LOG.info("submission tested successfully");
return resultSummary;
}
}
package de.hftstuttgart.dtabackend.rest.v1.task;
import de.hftstuttgart.dtabackend.utils.*;
import de.hftstuttgart.dtabackend.models.ResultSummary;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.apache.tika.Tika;
import org.springframework.core.env.Environment;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;
import java.io.*;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import jakarta.servlet.annotation.MultipartConfig;
/**
* Rest controller for everything related to the TASK files
*/
@RestController
@RequestMapping("/v1/task/*")
@MultipartConfig
public class TaskUpload {
private static final Logger LOG = LogManager.getLogger(TaskUpload.class);
private final RepoUtil repoUtil;
private final Path testTmpPath;
private final ExecuteTestUtil executeTestUtil;
public TaskUpload(
Environment env,
RepoUtil repoUtil,
ExecuteTestUtil executeTestUtil
) {
this.repoUtil = repoUtil;
this.executeTestUtil = executeTestUtil;
// set path of temporary directory on host and inside our container
this.testTmpPath = Paths.get(env.getProperty("tests.tmp.dir"));
}
@RequestMapping(method = RequestMethod.POST)
public ResultSummary uploadAndTestFile(@RequestParam("taskFile") MultipartFile taskFileRef,
@RequestParam("assignmentId") String assignmentId
) throws IOException, InterruptedException {
LOG.info("submission for testing received");
LOG.debug("creating new temporary directory");
Path workDirectory = Files.createTempDirectory(testTmpPath, "dta");
LOG.debug(String.format("working dir for test is: %s", workDirectory.toAbsolutePath().toString()));
// define paths for the test, the submission and where the result is to be expected afterwards
Path srcPath = Paths.get(workDirectory.toAbsolutePath().toString(), "src");
LOG.debug(String.format("Source path defined as: %s", srcPath.toAbsolutePath().toString()));
String mimeInfo = new Tika().detect(taskFileRef.getInputStream());
switch (mimeInfo) {
case "text/plain":
LOG.debug("textfile uploaded, searching for dta config");
// find URI in config file
String subDir="";
Matcher config = RegexUtil.extractConfig(taskFileRef.getInputStream(), Pattern.compile(RegexUtil.DTA_SUBMISSIONCONFIGREGEX));
if(config==null) {
config = RegexUtil.extractConfig(taskFileRef.getInputStream(), Pattern.compile(RegexUtil.SUBMISSIONCONFIGREGEX));
if(config==null)
{
throw new RuntimeException("couldn't find repo config for student submission clone");
}
}
else {
subDir=config.group(4);
}
LOG.debug("calling repo clone");
repoUtil.cloneRepository(config, srcPath.toAbsolutePath().toString(), subDir);
break;
case "application/zip":
LOG.debug("zip archive uploaded, extracting content as student submission");
ArchiveUtil.extractProjectFromZip(taskFileRef.getInputStream(), srcPath.toAbsolutePath());
break;
default:
String msg = String.format("couldn't process uploaded file with mime type %s", mimeInfo);
LOG.error(msg);
throw new RuntimeException(msg);
}
// run test
LOG.debug("calling test execution");
ResultSummary resultSummary = executeTestUtil.runTests(assignmentId, workDirectory);
if (mimeInfo.equals("text/plain")) {
LOG.info("check for provided Ticketsystem information");
UnifiedTicketingUtil.reportResults(taskFileRef.getInputStream(), resultSummary);
}
taskFileRef.getInputStream().close();
LOG.info("submission tested successfully");
return resultSummary;
}
}
package de.hftstuttgart.dtabackend.rest.v1.unittest;
import de.hftstuttgart.dtabackend.utils.RepoUtil;
import de.hftstuttgart.dtabackend.utils.RegexUtil;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.springframework.core.env.Environment;
import org.springframework.util.FileSystemUtils;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;
import jakarta.servlet.annotation.MultipartConfig;
import java.io.*;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/**
* Rest controller for anything related to the TEST files.
*/
@RestController
@RequestMapping("/v1/unittest")
@MultipartConfig
public class UnitTestUpload {
private static final Logger LOG = LogManager.getLogger(UnitTestUpload.class);
private final RepoUtil repoUtil;
private final String assignmentBasePath;
public UnitTestUpload(Environment env, RepoUtil repoUtil) {
this.repoUtil = repoUtil;
Path p = Paths.get(env.getProperty("data.dir"), env.getProperty("data.dir.test.folder.name"));
this.assignmentBasePath = p.toAbsolutePath().toString();
}
/**
* Create a subfolder for the specific assignment.
* This is called when the teacher creates an assignment and uploads the JUnit test files
*
* @param unitTestFileRef The text file which contains the JUnit tests meta data
* @param assignmentId ID of the created assignment. Generated by Moodle
*/
@RequestMapping(method = RequestMethod.POST)
public void uploadUnitTestFile(
@RequestParam("unitTestFile") MultipartFile unitTestFileRef,
@RequestParam("assignmentId") String assignmentId
) throws IOException {
LOG.info("received new assignment");
File file = Paths.get(this.assignmentBasePath, assignmentId + ".txt").toFile();
file.mkdirs();
// save assignment config
unitTestFileRef.transferTo(file);
LOG.debug(String.format("saved config file to: %s", file.getAbsolutePath()));
String subDir="";
Pattern pattern = Pattern.compile(RegexUtil.DTA_TESTCONFIGREGEX);
Matcher config = RegexUtil.extractConfig(new FileInputStream(file), pattern);
if (config == null) {
pattern=Pattern.compile(RegexUtil.TESTCONFIGREGEX);
config = RegexUtil.extractConfig(new FileInputStream(file), pattern);
if(config==null)
{
throw new RuntimeException("couldn't find repo config for unittest clone");
}
}
else {
subDir=config.group(4);
}
LOG.debug("calling test repo clone");
// cloning assignment repo to persistent space
repoUtil.cloneRepository(config, Paths.get(this.assignmentBasePath, assignmentId).toAbsolutePath().toString(), subDir);
LOG.info(String.format("stored new assignment: %s", file.getAbsolutePath()));
}
/**
* Delete the folder for the assignment.
* Called when the teacher deletes the JUnitTest assignment
* <p>
* {{url}}:8080/v1/unittest?assignmentId=111
*
* @param assignmentId ID of the assignment to delete. Generated by Moodle
*/
@RequestMapping(method = RequestMethod.DELETE)
public void deleteUnitTestFiles(@RequestParam("assignmentId") String assignmentId) {
LOG.info(String.format("received deletion order for assignment %s", assignmentId));
// deleting config file
File file = Paths.get(
this.assignmentBasePath,
assignmentId + ".txt")
.toFile();
file.delete();
// deleting local copy of repository
file = Paths.get(
this.assignmentBasePath,
assignmentId).toFile();
FileSystemUtils.deleteRecursively(file);
LOG.info(String.format("assignment %s deletion complete", assignmentId));
}
}
package de.hftstuttgart.dtabackend.rest.v1.unittest;
import de.hftstuttgart.dtabackend.utils.RepoUtil;
import de.hftstuttgart.dtabackend.utils.RegexUtil;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.springframework.core.env.Environment;
import org.springframework.util.FileSystemUtils;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;
import jakarta.servlet.annotation.MultipartConfig;
import java.io.*;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/**
* Rest controller for anything related to the TEST files.
*/
@RestController
@RequestMapping("/v1/unittest")
@MultipartConfig
public class UnitTestUpload {
private static final Logger LOG = LogManager.getLogger(UnitTestUpload.class);
private final RepoUtil repoUtil;
private final String assignmentBasePath;
public UnitTestUpload(Environment env, RepoUtil repoUtil) {
this.repoUtil = repoUtil;
Path p = Paths.get(env.getProperty("data.dir"), env.getProperty("data.dir.test.folder.name"));
this.assignmentBasePath = p.toAbsolutePath().toString();
LOG.debug(String.format("Assignment base path initialized as: %s", this.assignmentBasePath));
}
/**
* Create a subfolder for the specific assignment.
* This is called when the teacher creates an assignment and uploads the JUnit test files
*
* @param unitTestFileRef The text file which contains the JUnit tests meta data
* @param assignmentId ID of the created assignment. Generated by Moodle
*/
@RequestMapping(method = RequestMethod.POST)
public void uploadUnitTestFile(
@RequestParam("unitTestFile") MultipartFile unitTestFileRef,
@RequestParam("assignmentId") String assignmentId
) throws IOException {
LOG.info("received new assignment");
File file = Paths.get(this.assignmentBasePath, assignmentId + ".txt").toFile();
file.mkdirs();
// save assignment config
unitTestFileRef.transferTo(file);
LOG.debug(String.format("saved config file to: %s", file.getAbsolutePath()));
String subDir="";
Pattern pattern = Pattern.compile(RegexUtil.DTA_TESTCONFIGREGEX);
Matcher config = RegexUtil.extractConfig(new FileInputStream(file), pattern);
if (config == null) {
pattern=Pattern.compile(RegexUtil.TESTCONFIGREGEX);
config = RegexUtil.extractConfig(new FileInputStream(file), pattern);
if(config==null)
{
throw new RuntimeException("couldn't find repo config for unittest clone");
}
}
else {
subDir=config.group(4);
}
LOG.debug("calling test repo clone");
// cloning assignment repo to persistent space
repoUtil.cloneRepository(config, Paths.get(this.assignmentBasePath, assignmentId).toAbsolutePath().toString(), subDir);
LOG.info(String.format("stored new assignment: %s", file.getAbsolutePath()));
}
/**
* Delete the folder for the assignment.
* Called when the teacher deletes the JUnitTest assignment
* <p>
* {{url}}:8080/v1/unittest?assignmentId=111
*
* @param assignmentId ID of the assignment to delete. Generated by Moodle
*/
@RequestMapping(method = RequestMethod.DELETE)
public void deleteUnitTestFiles(@RequestParam("assignmentId") String assignmentId) {
LOG.info(String.format("received deletion order for assignment %s", assignmentId));
// deleting config file
File file = Paths.get(
this.assignmentBasePath,
assignmentId + ".txt")
.toFile();
file.delete();
LOG.debug(String.format("Deleted file: %s", file.getAbsolutePath()));
// deleting local copy of repository
file = Paths.get(
this.assignmentBasePath,
assignmentId).toFile();
FileSystemUtils.deleteRecursively(file);
LOG.debug(String.format("Deleted directory: %s", file.getAbsolutePath()));
LOG.info(String.format("assignment %s deletion complete", assignmentId));
}
}
......@@ -19,6 +19,7 @@ public class ArchiveUtil
ZipEntry entry;
while ((entry = stream.getNextEntry()) != null) {
LOG.debug(String.format("Processing zip entry: %s", entry.getName()));
File file = outDir.resolve(entry.getName()).toFile();
LOG.debug(String.format("processing entry %s", file.getAbsolutePath()));
......@@ -28,6 +29,7 @@ public class ArchiveUtil
LOG.debug("creating new file");
file.createNewFile();
LOG.debug(String.format("Created new file: %s", file.getAbsolutePath()));
byte[] buffer = new byte[2048];
try (FileOutputStream fos = new FileOutputStream(file);
......
......@@ -67,6 +67,16 @@ public class ExecuteTestUtil {
Paths.get(assignmentBasePath, assignmentId),
testPath);
LOG.debug("copying exercise manifest from: %s in testPath: %s",
assignmentBasePath + assignmentId + "_checkout",
testPath.toString() );
Files.copy(Paths.get(
assignmentBasePath, assignmentId + "_checkout",
CompetencyAssessmentUtil.EXERCISE_COMPETENCY_MANIFEST_FILE_NAME),
Paths.get(
testPath.toString(),
CompetencyAssessmentUtil.EXERCISE_COMPETENCY_MANIFEST_FILE_NAME));
LOG.debug("copy test config");
Files.copy(
Paths.get(assignmentBasePath, assignmentId + ".txt"),
......@@ -140,14 +150,25 @@ public class ExecuteTestUtil {
LOG.info("Checking for optional test competency profile information for paedagogical agent functionality...");
List<TestCompetencyProfile> testCompetencyProfiles=CompetencyAssessmentUtil.readTestCompetencyProfiles(testPathHost, CompetencyAssessmentUtil.TEST_COMPETENCY_MANIFEST_FILE_NAME);
if(testCompetencyProfiles!=null) {
LOG.debug(String.format(
"Reading Test Competency Profiles: basePath=%s, fileName=%s",
testPathHost,
CompetencyAssessmentUtil.TEST_COMPETENCY_MANIFEST_FILE_NAME
));
if(testCompetencyProfiles!=null) {
LOG.info("Found optional test competency profiles, generating agent profile data...");
resultSummary.overallTestCompetencyProfile=CompetencyAssessmentUtil.packFloats(CompetencyAssessmentUtil.sumTestCompetencyProfiles(testCompetencyProfiles));
resultSummary.successfulTestCompetencyProfile=CompetencyAssessmentUtil.packFloats(CompetencyAssessmentUtil.sumSuccessfulCompetencyProfiles(testCompetencyProfiles, resultSummary, true));
LOG.info("Checking for optional exercise competency profile information for paedagogical agent exercise recommendation functionality...");
//testPathHost or assignmentBasePath
Path exerciseManifestFile = Paths.get(testPathHost.toAbsolutePath().toString(), CompetencyAssessmentUtil.EXERCISE_COMPETENCY_MANIFEST_FILE_NAME);
Path exerciseManifestFile = Paths.get(testPathHost.toString(), CompetencyAssessmentUtil.EXERCISE_COMPETENCY_MANIFEST_FILE_NAME);
LOG.debug(String.format(
"Constructing Path for exercise manifest: testPath=%s, fileName=%s -> Resulting Path=%s",
testPathHost.toString(),
CompetencyAssessmentUtil.EXERCISE_COMPETENCY_MANIFEST_FILE_NAME,
exerciseManifestFile.toString()
));
if (Files.exists(exerciseManifestFile)) {
LOG.info("Found optional exercise competency profiles, generating recommendations...");
resultSummary.recommendations = recommendNextExercises(assignmentId, testPathHost, testCompetencyProfiles, resultSummary);
......
......@@ -24,10 +24,12 @@ public class FileUtil {
deleteFolderRecursively(f);
} else {
f.delete();
System.out.println(String.format("Deleted file: %s", f.getAbsolutePath()));
}
}
}
folder.delete();
System.out.println(String.format("Deleted folder: %s", folder.getAbsolutePath()));
}
public static void copyFolder(Path src, Path dst) throws IOException {
......@@ -35,6 +37,7 @@ public class FileUtil {
.forEach(source -> {
try {
Files.copy(source, dst.resolve(src.relativize(source)));
System.out.println(String.format("Copying file from: %s to %s", source.toString(), dst.resolve(src.relativize(source)).toString()));
} catch (IOException e) {
throw new RuntimeException(e.getMessage(), e);
}
......
......@@ -104,7 +104,7 @@ public class RepoUtil {
//copy appropriate path from checkout directory to target directory
FileSystemUtils.copyRecursively(new File(checkoutDirectory+subDir), new File(targetPath));
}
LOG.debug(String.format("cloned from %s to %s", config.group(1), targetDirectory));
LOG.debug(String.format("cloned from %s via %s to %s", config.group(1), checkoutDirectory+subDir, targetDirectory));
}
catch (IOException e) {
LOG.error(String.format("Error while cloning from %s: could not copy to unit test dir", config.group(1)), e);
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment