An error occurred while loading the file. Please try again.
ExecuteTestUtil.java 10.11 KiB
package de.hftstuttgart.dtabackend.utils;
import com.fasterxml.jackson.core.exc.StreamReadException;
import com.fasterxml.jackson.databind.DatabindException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.github.dockerjava.api.model.Bind;
import com.github.dockerjava.api.model.Volume;
import de.hftstuttgart.dtabackend.models.ExerciseCompetencyProfile;
import de.hftstuttgart.dtabackend.models.Recommendation;
import de.hftstuttgart.dtabackend.models.ResultSummary;
import de.hftstuttgart.dtabackend.models.TestCompetencyProfile;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.springframework.core.env.Environment;
import org.springframework.stereotype.Component;
import java.io.*;
import java.net.MalformedURLException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.Collectors;
@Component
public class ExecuteTestUtil  {
    private static final Logger LOG = LogManager.getLogger(ExecuteTestUtil.class);
    private final DockerUtil dockerUtil;
    private final String assignmentBasePath;
    private final Path testTmpPathHost;
    public ExecuteTestUtil(Environment env, DockerUtil dockerUtil) {
        this.dockerUtil = dockerUtil;
        this.assignmentBasePath = Paths.get(
            env.getProperty("data.dir"),
            env.getProperty("data.dir.test.folder.name"))
            .toAbsolutePath().toString();
        this.testTmpPathHost = Paths.get(env.getProperty("host.tests.tmp.dir"));
    public ResultSummary runTests(String assignmentId, Path workDirectory) throws IOException, InterruptedException {
        // Define paths
        Path testPath = workDirectory.resolve("test");
        Path srcPath = workDirectory.resolve("src");
        Path resultPath = workDirectory.resolve("result");
        // Clone test to temporary directory
        LOG.debug("Copying pre-downloaded unittest repo");
        FileUtil.copyFolder(Paths.get(assignmentBasePath, assignmentId), testPath);
        // Copy configuration file
        LOG.debug("Copy test config");
        Files.copy(Paths.get(assignmentBasePath, assignmentId + ".txt"), workDirectory.resolve("config.txt"));
        Files.createDirectory(resultPath);
        // Load container image configuration
        LOG.info("Reading test config");
        String image = loadImageConfig(workDirectory);
        // Define paths to mount in the container
        Path testPathHost = testTmpPathHost.resolve(workDirectory.getFileName()).resolve(testPath.getFileName());
        Path srcPathHost = testTmpPathHost.resolve(workDirectory.getFileName()).resolve(srcPath.getFileName());
        Path resultPathHost = testTmpPathHost.resolve(workDirectory.getFileName()).resolve(resultPath.getFileName());
// Start container with mounts dockerUtil.runContainer( image, new Bind(testPathHost.toString(), new Volume("/data/test")), new Bind(srcPathHost.toString(), new Volume("/data/src")), new Bind(resultPathHost.toString(), new Volume("/data/result")) ); return generateResult(assignmentId, resultPath, testPathHost); } private String loadImageConfig(Path workDirectory) throws FileNotFoundException { Matcher config = RegexUtil.extractConfig( new FileInputStream(workDirectory.resolve("config.txt").toFile()), Pattern.compile(RegexUtil.DTA_TESTCONFIGREGEX)); if (config == null) { config = RegexUtil.extractConfig( new FileInputStream(workDirectory.resolve("config.txt").toFile()), Pattern.compile(RegexUtil.TESTCONFIGREGEX)); if (config == null) { throw new RuntimeException("Couldn't find repo config for unittest image extraction"); } return config.group(4); } return config.group(5); } private ResultSummary generateResult(String assignmentId, Path resultPath, Path testPathHost) throws IOException, StreamReadException, DatabindException, MalformedURLException { File resultFile = resultPath.resolve("result.json").toFile(); if (!resultFile.exists() || !resultFile.isFile()) { LOG.error(String.format("Could not find result file in %s", resultFile.getAbsolutePath())); throw new RuntimeException("No result file found"); } LOG.debug("Parse results JSON"); ObjectMapper objectMapper = new ObjectMapper(); ResultSummary resultSummary = objectMapper.readValue(resultFile.toURI().toURL(), ResultSummary.class); LOG.debug("Result JSON returned at " + resultSummary.timestamp + " with " + resultSummary.results.size() + " test results."); LOG.info("Checking for optional test competency profile information..."); List<TestCompetencyProfile> testCompetencyProfiles = CompetencyAssessmentUtil.readTestCompetencyProfiles(testPathHost); if (testCompetencyProfiles != null) { LOG.info("Found test competency profiles, generating profile data..."); resultSummary.overallTestCompetencyProfile = CompetencyAssessmentUtil.packFloats(CompetencyAssessmentUtil.sumTestCompetencyProfiles(testCompetencyProfiles)); resultSummary.successfulTestCompetencyProfile = CompetencyAssessmentUtil.packFloats(CompetencyAssessmentUtil.sumSuccessfulCompetencyProfiles(testCompetencyProfiles, resultSummary, true)); Path exerciseManifestFile = testPathHost.resolve(CompetencyAssessmentUtil.EXERCISE_COMPETENCY_MANIFEST_FILE_NAME); if (Files.exists(exerciseManifestFile)) { LOG.info("Found exercise competency profiles, generating recommendations..."); resultSummary.recommendations = recommendNextExercises(assignmentId, testPathHost, testCompetencyProfiles, resultSummary); } } return resultSummary; } public List<Recommendation> recommendNextExercises(String assignmentId, Path testPathHost, List<TestCompetencyProfile> testCompetencyProfiles, ResultSummary resultSummary) throws FileNotFoundException { String testRepoURL = RegexUtil.extractConfig( new FileInputStream(Paths.get(assignmentBasePath, assignmentId + ".txt").toFile()), Pattern.compile(RegexUtil.DTA_TESTCONFIGREGEX)).group(1); List<ExerciseCompetencyProfile> exerciseCompetencyProfiles = CompetencyAssessmentUtil.readExerciseCompetencyProfiles(testPathHost); int currentTopicIndex = 0;
float currentDifficulty = 0.0f; Map<String, Integer> topicOrder = new HashMap<>(); int order = 1; // Determine currentTopicIndex and set currentDifficulty based on exercise profiles for (ExerciseCompetencyProfile e : exerciseCompetencyProfiles) { if (!topicOrder.containsKey(e.exerciseTopicName)) { topicOrder.put(e.exerciseTopicName, order++); } if (e.exerciseURL.equals(testRepoURL)) { currentTopicIndex = order; currentDifficulty = e.difficulty; // Directly assign to currentDifficulty } } // Sum competencies for unsuccessful tests float[] unsuccessful = CompetencyAssessmentUtil.sumSuccessfulCompetencyProfiles(testCompetencyProfiles, resultSummary, false); // Filter exercises based on topics and difficulty List<ExerciseCompetencyProfile> filteredExercises = filterExercisesByTopicsAndDifficulty( exerciseCompetencyProfiles, topicOrder, currentTopicIndex, testRepoURL, currentDifficulty, unsuccessful); // Generate recommendations without using lambda expressions List<Recommendation> recommendedExercises = new ArrayList<>(); for (ExerciseCompetencyProfile profile : filteredExercises) { float score = calculateScore(profile, unsuccessful, topicOrder, currentDifficulty); Recommendation recommendation = new Recommendation( profile.exerciseTopicName, profile.exerciseURL, profile.exerciseName, profile.difficulty, score); recommendedExercises.add(recommendation); } // Sort the recommendations using Collections.sort and a comparator Collections.sort(recommendedExercises, Recommendation.COMPARE_BY_SCORE); return recommendedExercises; } public static List<ExerciseCompetencyProfile> filterExercisesByTopicsAndDifficulty(List<ExerciseCompetencyProfile> profiles, Map<String, Integer> topicOrder, int currentTopicIndex, String testRepoURL, float currentDifficulty, float[] unsuccessful) { List<ExerciseCompetencyProfile> filteredExercises = profiles.stream() .filter(profile -> topicOrder.get(profile.exerciseTopicName) <= currentTopicIndex) .collect(Collectors.toList()); if (CompetencyAssessmentUtil.isFullSuccess(unsuccessful)) { filteredExercises = filteredExercises.stream() .filter(profile -> profile.difficulty >= currentDifficulty && !testRepoURL.equals(profile.exerciseURL)) .collect(Collectors.toList()); } else { filteredExercises = filteredExercises.stream() .filter(profile -> profile.difficulty <= currentDifficulty) .collect(Collectors.toList()); } return filteredExercises; } public static float calculateScore(ExerciseCompetencyProfile profile, float[] unsuccessful, Map<String, Integer> topicOrder, float currentDifficulty) { float score = 1.0f; for (int i = 0; i < profile.competencyAssessments.length - 1; i++) { score += profile.competencyAssessments[i] * unsuccessful[i]; } score *= profile.difficulty * (0.5f + Math.abs(currentDifficulty - profile.difficulty)); score *= topicOrder.getOrDefault(profile.exerciseTopicName, 1);
return Math.round(score * 10.0f) / 10.0f; } }