Commit 73c10129 authored by mamunozgil's avatar mamunozgil
Browse files

Revert "Refactor for backtracking manifesto"

This reverts commit 375b37bf.
parent c1884045
This commit is part of merge request !1. Comments created here will be created in the context of that merge request.
Showing with 308 additions and 321 deletions
+308 -321
...@@ -3,188 +3,134 @@ package de.hftstuttgart.dtabackend.utils; ...@@ -3,188 +3,134 @@ package de.hftstuttgart.dtabackend.utils;
import java.io.BufferedReader; import java.io.BufferedReader;
import java.io.FileReader; import java.io.FileReader;
import java.io.IOException; import java.io.IOException;
import java.nio.file.Files; import java.net.MalformedURLException;
import java.nio.file.Path; import java.nio.file.Path;
import java.io.File;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.stream.Collectors; import java.util.stream.Collectors;
import java.util.stream.IntStream; import java.util.stream.IntStream;
import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger; import org.apache.logging.log4j.Logger;
import com.fasterxml.jackson.core.exc.StreamReadException;
import com.fasterxml.jackson.databind.DatabindException;
import de.hftstuttgart.dtabackend.models.ExerciseCompetencyProfile; import de.hftstuttgart.dtabackend.models.ExerciseCompetencyProfile;
import de.hftstuttgart.dtabackend.models.ICompetencyProfile; import de.hftstuttgart.dtabackend.models.ICompetencyProfile;
import de.hftstuttgart.dtabackend.models.Result; import de.hftstuttgart.dtabackend.models.Result;
import de.hftstuttgart.dtabackend.models.ResultSummary; import de.hftstuttgart.dtabackend.models.ResultSummary;
import de.hftstuttgart.dtabackend.models.TestCompetencyProfile; import de.hftstuttgart.dtabackend.models.TestCompetencyProfile;
public class CompetencyAssessmentUtil { import java.io.FileNotFoundException;
private static final Logger LOG = LogManager.getLogger(CompetencyAssessmentUtil.class);
public static final String TEST_COMPETENCY_MANIFEST_FILE_NAME = "competency-tests.mft";
public static final String EXERCISE_COMPETENCY_MANIFEST_FILE_NAME = "exercise-tests.mft";
/**
* Retrieves the base directory where the test competency manifest is located
* by traversing upwards until it finds the file "exercise-tests.mft".
*
* @param startDir Starting directory path to begin the search
* @return Path of the base directory if found; otherwise, null
*/
public static Path getBaseDirectory(Path startDir) {
Path currentDir = startDir;
while (currentDir != null) {
Path manifestPath = currentDir.resolve(EXERCISE_COMPETENCY_MANIFEST_FILE_NAME);
if (Files.exists(manifestPath)) {
return currentDir;
}
currentDir = currentDir.getParent();
}
LOG.warn("Base directory with " + EXERCISE_COMPETENCY_MANIFEST_FILE_NAME + " not found starting from " + startDir);
return null;
}
/**
* Reads and loads test competency profiles from the base directory.
*
* @param exercisePath Path to the starting exercise directory
* @return List of TestCompetencyProfile instances loaded from the manifest
*/
public static List<TestCompetencyProfile> readTestCompetencyProfiles(Path exercisePath) {
Path baseDir = getBaseDirectory(exercisePath);
if (baseDir == null) {
LOG.error("Unable to locate the base directory for reading test competency profiles.");
return null;
}
return readTestCompetencyProfiles(baseDir, TEST_COMPETENCY_MANIFEST_FILE_NAME);
}
/**
* Reads and loads exercise competency profiles from the specified exercise directory.
*
* @param exercisePath Path to the exercise directory
* @return List of ExerciseCompetencyProfile instances loaded from the manifest
*/
public static List<ExerciseCompetencyProfile> readExerciseCompetencyProfiles(Path exercisePath) {
return readExerciseCompetencyProfiles(exercisePath, EXERCISE_COMPETENCY_MANIFEST_FILE_NAME);
}
private static List<TestCompetencyProfile> readTestCompetencyProfiles(Path baseDir, String fileName) {
List<TestCompetencyProfile> testCompetencyProfiles = new ArrayList<>();
Path manifestPath = baseDir.resolve(fileName);
try (BufferedReader testCompetencyManifest = new BufferedReader(new FileReader(manifestPath.toFile()))) { public class CompetencyAssessmentUtil {
String testEntry = testCompetencyManifest.readLine(); private static final Logger LOG = LogManager.getLogger(CompetencyAssessmentUtil.class);
while (testEntry != null) {
String[] testEntryComponents = testEntry.split(ICompetencyProfile.COMPETENCY_SEPARATOR); public static String TEST_COMPETENCY_MANIFEST_FILE_NAME="competency-tests.mft";
TestCompetencyProfile currentProfile = new TestCompetencyProfile(); public static String EXERCISE_COMPETENCY_MANIFEST_FILE_NAME="exercise-tests.mft";
currentProfile.testPackageName = testEntryComponents[0];
currentProfile.testClassName = testEntryComponents[1]; /*public static void main(String[] args) throws StreamReadException, DatabindException, MalformedURLException, IOException {
currentProfile.testName = testEntryComponents[2]; ResultSummary summary=ExecuteTestUtil.generateResult("1", Path.of(args[0]), Path.of(args[1]));
for (int competencyIndex = 0; competencyIndex < ICompetencyProfile.MAX_COMPETENCY_DIMENSIONS; competencyIndex++) { System.out.println(summary.successfulTestCompetencyProfile);
currentProfile.competencyAssessments[competencyIndex] = Float.valueOf(testEntryComponents[competencyIndex + 3]); }
} */
testCompetencyProfiles.add(currentProfile); public static float[] sumTestCompetencyProfiles(List<TestCompetencyProfile> testCompetencyProfiles) {
testEntry = testCompetencyManifest.readLine(); float[] tcpTotalProfile=new float[ICompetencyProfile.MAX_COMPETENCY_DIMENSIONS];
} for(TestCompetencyProfile currentProfile: testCompetencyProfiles) {
LOG.info("Loaded " + testCompetencyProfiles.size() + " test competency profiles from " + manifestPath); tcpTotalProfile=ICompetencyProfile.competencySum(tcpTotalProfile, currentProfile.competencyAssessments);
} catch (IOException e) { }
LOG.error("Error reading test competency manifest file at " + manifestPath, e); return tcpTotalProfile;
} }
return testCompetencyProfiles; public static float[] sumSuccessfulCompetencyProfiles(List<TestCompetencyProfile> testCompetencyProfiles, ResultSummary resultSummary, boolean success) {
} float[] sumSuccessful=new float[ICompetencyProfile.MAX_COMPETENCY_DIMENSIONS];
for(Result currentResult: resultSummary.results) {
private static List<ExerciseCompetencyProfile> readExerciseCompetencyProfiles(Path exercisePath, String fileName) { boolean isSuccess = Integer.valueOf(currentResult.state).equals(Result.State.SUCCESS.ordinal());
List<ExerciseCompetencyProfile> exerciseCompetencyProfiles = new ArrayList<>(); if (isSuccess == success) {
Path manifestPath = exercisePath.resolve(fileName); TestCompetencyProfile currentProfile=new TestCompetencyProfile();
currentProfile.testPackageName=(currentResult.packageName!=null)?currentResult.packageName:"";
try (BufferedReader exerciseCompetencyManifest = new BufferedReader(new FileReader(manifestPath.toFile()))) { currentProfile.testClassName=(currentResult.className!=null)?currentResult.className:"";
String exerciseEntry = exerciseCompetencyManifest.readLine(); currentProfile.testName=(currentResult.name!=null)?currentResult.name:"";
while (exerciseEntry != null) { int testIndex=testCompetencyProfiles.indexOf(currentProfile);
String[] exerciseEntryComponents = exerciseEntry.split(ExerciseCompetencyProfile.COMPETENCY_SEPARATOR); if(testIndex!=-1) {
ExerciseCompetencyProfile currentProfile = new ExerciseCompetencyProfile(); sumSuccessful=ICompetencyProfile.competencySum(sumSuccessful, testCompetencyProfiles.get(testIndex).competencyAssessments);
currentProfile.exerciseTopicName = exerciseEntryComponents[0]; }
currentProfile.exerciseName = exerciseEntryComponents[1]; }
currentProfile.exerciseURL = exerciseEntryComponents[2]; }
for (int competencyIndex = 0; competencyIndex < ExerciseCompetencyProfile.MAX_COMPETENCY_DIMENSIONS; competencyIndex++) { return sumSuccessful;
currentProfile.competencyAssessments[competencyIndex] = Float.valueOf(exerciseEntryComponents[competencyIndex + 3]); }
}
currentProfile.difficulty = Float.parseFloat(exerciseEntryComponents[19]); public static List<TestCompetencyProfile> readTestCompetencyProfiles(Path testPath, String fileName) {
exerciseCompetencyProfiles.add(currentProfile); List<TestCompetencyProfile> testCompetencyProfiles=new ArrayList<TestCompetencyProfile>();
exerciseEntry = exerciseCompetencyManifest.readLine(); try {
} BufferedReader testCompetencyManifest=new BufferedReader(new FileReader(new File(testPath.toFile(), fileName)));
LOG.info("Loaded " + exerciseCompetencyProfiles.size() + " exercise competency profiles from " + manifestPath); String testEntry=testCompetencyManifest.readLine();
} catch (IOException e) { while(testEntry!=null)
LOG.error("Error reading exercise competency manifest file at " + manifestPath, e); {
} String[] testEntyComponents=testEntry.split(ICompetencyProfile.COMPETENCY_SEPARATOR);
TestCompetencyProfile currentProfile=new TestCompetencyProfile();
return exerciseCompetencyProfiles; currentProfile.testPackageName=testEntyComponents[0];
} currentProfile.testClassName=testEntyComponents[1];
currentProfile.testName=testEntyComponents[2];
/** for(int competencyIndex=0; competencyIndex<ICompetencyProfile.MAX_COMPETENCY_DIMENSIONS; competencyIndex++) {
* Converts an array of floats into a semicolon-separated string. currentProfile.competencyAssessments[competencyIndex]=Float.valueOf(testEntyComponents[competencyIndex+3]);
* }
* @param array Array of float values to pack testCompetencyProfiles.add(currentProfile);
* @return Semicolon-separated string of float values testEntry=testCompetencyManifest.readLine();
*/ }
public static String packFloats(float[] array) { testCompetencyManifest.close();
return IntStream.range(0, array.length) LOG.info("Added "+testCompetencyProfiles.size()+" test competency profiles from test competency manifest. Optional agent functionality enabled.");
.mapToObj(i -> String.valueOf(array[i])) } catch (FileNotFoundException e) {
.collect(Collectors.joining(";")); LOG.info("Test competency manifest file for agent feedback not found. Skipping optional functionality.");
} testCompetencyProfiles=null;
} catch (IOException e) {
/** LOG.info("Test competency manifest file for agent feedback unreadable. Skipping optional functionality.");
* Sums the competency profiles across all test competency profiles. testCompetencyProfiles=null;
* }
* @param testCompetencyProfiles List of test competency profiles return testCompetencyProfiles;
* @return An array representing the sum of competencies }
*/
public static float[] sumTestCompetencyProfiles(List<TestCompetencyProfile> testCompetencyProfiles) { public static List<ExerciseCompetencyProfile> readExerciseCompetencyProfiles(Path exercisePath, String fileName) {
float[] tcpTotalProfile = new float[ICompetencyProfile.MAX_COMPETENCY_DIMENSIONS]; List<ExerciseCompetencyProfile> exerciseCompetencyProfiles = new ArrayList<>();
for (TestCompetencyProfile currentProfile : testCompetencyProfiles) {
tcpTotalProfile = ICompetencyProfile.competencySum(tcpTotalProfile, currentProfile.competencyAssessments); try (BufferedReader exerciseCompetencyManifest = new BufferedReader(new FileReader(new File(exercisePath.toFile(), fileName)))) {
} String exerciseEntry = exerciseCompetencyManifest.readLine();
return tcpTotalProfile;
} while (exerciseEntry != null) {
String[] exerciseEntyComponents = exerciseEntry.split(ExerciseCompetencyProfile.COMPETENCY_SEPARATOR);
/** ExerciseCompetencyProfile currentProfile = new ExerciseCompetencyProfile();
* Sums only the successful test competency profiles, based on the results summary.
* currentProfile.exerciseTopicName = exerciseEntyComponents[0];
* @param testCompetencyProfiles List of test competency profiles currentProfile.exerciseName = exerciseEntyComponents[1];
* @param resultSummary The result summary containing test results currentProfile.exerciseURL = exerciseEntyComponents[2];
* @param success Indicates whether to sum successful (true) or unsuccessful (false) profiles
* @return An array representing the sum of competencies for successful or unsuccessful profiles for (int competencyIndex = 0; competencyIndex < ExerciseCompetencyProfile.MAX_COMPETENCY_DIMENSIONS; competencyIndex++) {
*/ currentProfile.competencyAssessments[competencyIndex] = Float.valueOf(exerciseEntyComponents[competencyIndex+3]);
public static float[] sumSuccessfulCompetencyProfiles(List<TestCompetencyProfile> testCompetencyProfiles, ResultSummary resultSummary, boolean success) { }
float[] sumSuccessful = new float[ICompetencyProfile.MAX_COMPETENCY_DIMENSIONS];
for (Result currentResult : resultSummary.results) { currentProfile.difficulty = Float.parseFloat(exerciseEntyComponents[19]);
boolean isSuccess = Integer.valueOf(currentResult.state).equals(Result.State.SUCCESS.ordinal());
if (isSuccess == success) { exerciseCompetencyProfiles.add(currentProfile);
TestCompetencyProfile currentProfile = new TestCompetencyProfile();
currentProfile.testPackageName = (currentResult.packageName != null) ? currentResult.packageName : ""; exerciseEntry = exerciseCompetencyManifest.readLine();
currentProfile.testClassName = (currentResult.className != null) ? currentResult.className : ""; }
currentProfile.testName = (currentResult.name != null) ? currentResult.name : ""; exerciseCompetencyManifest.close();
int testIndex = testCompetencyProfiles.indexOf(currentProfile); LOG.info("Added " + exerciseCompetencyProfiles.size() + " test competency profiles from exercise competency manifest.");
if (testIndex != -1) { } catch (FileNotFoundException e) {
sumSuccessful = ICompetencyProfile.competencySum(sumSuccessful, testCompetencyProfiles.get(testIndex).competencyAssessments); LOG.info("Exercise competency manifest file not found.");
} } catch (IOException e) {
} LOG.info("Exercise competency manifest file unreadable.");
} }
return sumSuccessful;
} return exerciseCompetencyProfiles;
}
public static String packFloats(float[] array) {
return IntStream.range(0, array.length)
.mapToObj(i -> String.valueOf(array[i]))
.collect(Collectors.joining(";"));
}
/**
* Checks if all elements in the competency profile array are zero (indicating full success).
*
* @param competencyProfile Array of competency values
* @return True if all values are zero; false otherwise
*/
public static boolean isFullSuccess(float[] competencyProfile) {
for (float value : competencyProfile) {
if (value != 0.0f) {
return false;
}
}
return true;
}
} }
...@@ -7,6 +7,7 @@ import com.github.dockerjava.api.model.Bind; ...@@ -7,6 +7,7 @@ import com.github.dockerjava.api.model.Bind;
import com.github.dockerjava.api.model.Volume; import com.github.dockerjava.api.model.Volume;
import de.hftstuttgart.dtabackend.models.ExerciseCompetencyProfile; import de.hftstuttgart.dtabackend.models.ExerciseCompetencyProfile;
import de.hftstuttgart.dtabackend.models.ICompetencyProfile;
import de.hftstuttgart.dtabackend.models.Recommendation; import de.hftstuttgart.dtabackend.models.Recommendation;
import de.hftstuttgart.dtabackend.models.ResultSummary; import de.hftstuttgart.dtabackend.models.ResultSummary;
import de.hftstuttgart.dtabackend.models.TestCompetencyProfile; import de.hftstuttgart.dtabackend.models.TestCompetencyProfile;
...@@ -21,7 +22,10 @@ import java.net.MalformedURLException; ...@@ -21,7 +22,10 @@ import java.net.MalformedURLException;
import java.nio.file.Files; import java.nio.file.Files;
import java.nio.file.Path; import java.nio.file.Path;
import java.nio.file.Paths; import java.nio.file.Paths;
import java.util.*; import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.regex.Matcher; import java.util.regex.Matcher;
import java.util.regex.Pattern; import java.util.regex.Pattern;
import java.util.stream.Collectors; import java.util.stream.Collectors;
...@@ -34,180 +38,217 @@ public class ExecuteTestUtil { ...@@ -34,180 +38,217 @@ public class ExecuteTestUtil {
private final String assignmentBasePath; private final String assignmentBasePath;
private final Path testTmpPathHost; private final Path testTmpPathHost;
public ExecuteTestUtil(Environment env, DockerUtil dockerUtil) { public ExecuteTestUtil(
Environment env,
DockerUtil dockerUtil
) {
this.dockerUtil = dockerUtil; this.dockerUtil = dockerUtil;
this.assignmentBasePath = Paths.get(
// set base path for assignments to be stored
Path p = Paths.get(
env.getProperty("data.dir"), env.getProperty("data.dir"),
env.getProperty("data.dir.test.folder.name")) env.getProperty("data.dir.test.folder.name"));
.toAbsolutePath().toString(); this.assignmentBasePath = p.toAbsolutePath().toString();
// set path of temporary directory on host _and_ inside our container, _must_ be identical
this.testTmpPathHost = Paths.get(env.getProperty("host.tests.tmp.dir")); this.testTmpPathHost = Paths.get(env.getProperty("host.tests.tmp.dir"));
} }
public ResultSummary runTests(String assignmentId, Path workDirectory) throws IOException, InterruptedException { 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 // define paths for the test, the submission and where the result is to be expected afterwards
LOG.info("Reading test config"); Path testPath = Paths.get(workDirectory.toAbsolutePath().toString(), "/test");
String image = loadImageConfig(workDirectory); Path srcPath = Paths.get(workDirectory.toAbsolutePath().toString(), "/src");
Path resultPath = Paths.get(workDirectory.toAbsolutePath().toString(), "/result");
// Define paths to mount in the container // clone stored test to tmpdir
Path testPathHost = testTmpPathHost.resolve(workDirectory.getFileName()).resolve(testPath.getFileName()); LOG.debug("copying pre-downloaded unitttest repo");
Path srcPathHost = testTmpPathHost.resolve(workDirectory.getFileName()).resolve(srcPath.getFileName()); FileUtil.copyFolder(
Path resultPathHost = testTmpPathHost.resolve(workDirectory.getFileName()).resolve(resultPath.getFileName()); Paths.get(assignmentBasePath, assignmentId),
testPath);
// Start container with mounts LOG.debug("copy test config");
dockerUtil.runContainer( Files.copy(
image, Paths.get(assignmentBasePath, assignmentId + ".txt"),
new Bind(testPathHost.toString(), new Volume("/data/test")), Paths.get(workDirectory.toAbsolutePath().toString(), "config.txt"));
new Bind(srcPathHost.toString(), new Volume("/data/src")),
new Bind(resultPathHost.toString(), new Volume("/data/result"))
);
return generateResult(assignmentId, resultPath, testPathHost); Files.createDirectory(resultPath);
}
private String loadImageConfig(Path workDirectory) throws FileNotFoundException { LOG.info("reading test config");
Matcher config = RegexUtil.extractConfig( Matcher config = RegexUtil.extractConfig(
new FileInputStream(workDirectory.resolve("config.txt").toFile()), new FileInputStream(Paths.get(workDirectory.toAbsolutePath().toString(), "config.txt").toFile()), Pattern.compile(RegexUtil.DTA_TESTCONFIGREGEX));
Pattern.compile(RegexUtil.DTA_TESTCONFIGREGEX)); String image="";
if(config==null)
if (config == null) { {
config = RegexUtil.extractConfig( config = RegexUtil.extractConfig(
new FileInputStream(workDirectory.resolve("config.txt").toFile()), new FileInputStream(Paths.get(workDirectory.toAbsolutePath().toString(), "config.txt").toFile()), Pattern.compile(RegexUtil.TESTCONFIGREGEX));
Pattern.compile(RegexUtil.TESTCONFIGREGEX)); if(config==null)
{
if (config == null) { throw new RuntimeException("couldn't find repo config for unittest image extraction");
throw new RuntimeException("Couldn't find repo config for unittest image extraction"); }
} image=config.group(4);
return config.group(4); }
else
{
image=config.group(5);
} }
return config.group(5); // define the paths to mount as Binds from Host to the test-container
Path testPathHost = Paths.get(
testTmpPathHost.toAbsolutePath().toString(),
workDirectory.getName(workDirectory.getNameCount()-1).toString(),
testPath.getName(testPath.getNameCount()-1).toString()
);
Path srcPathHost = Paths.get(
testTmpPathHost.toAbsolutePath().toString(),
workDirectory.getName(workDirectory.getNameCount()-1).toString(),
srcPath.getName(srcPath.getNameCount()-1).toString()
);
Path resultPathHost = Paths.get(
testTmpPathHost.toAbsolutePath().toString(),
workDirectory.getName(workDirectory.getNameCount()-1).toString(),
resultPath.getName(resultPath.getNameCount()-1).toString()
);
// start test-container with professor given image and bind mounts for test, submission and result
dockerUtil.runContainer(
image,
new Bind(testPathHost.toAbsolutePath().toString(), new Volume("/data/test")),
new Bind(srcPathHost.toAbsolutePath().toString(), new Volume("/data/src")),
new Bind(resultPathHost.toAbsolutePath().toString(), new Volume("/data/result"))
);
ResultSummary resultSummary = generateResult(assignmentId, resultPath, testPathHost);
return resultSummary;
} }
private ResultSummary generateResult(String assignmentId, Path resultPath, Path testPathHost) private ResultSummary generateResult(String assignmentId, Path resultPath, Path testPathHost)
throws IOException, StreamReadException, DatabindException, MalformedURLException { throws IOException, StreamReadException, DatabindException, MalformedURLException {
File resultFile = resultPath.resolve("result.json").toFile(); // define expected result file
File resultFile = Paths.get(resultPath.toAbsolutePath().toString(), "result.json").toFile();
// check if result file is there
if (!resultFile.exists() || !resultFile.isFile()) { if (!resultFile.exists() || !resultFile.isFile()) {
LOG.error(String.format("Could not find result file in %s", resultFile.getAbsolutePath())); LOG.error(String.format("Could not find result file in %s", resultFile.getAbsolutePath()));
throw new RuntimeException("No result file found"); throw new RuntimeException("no resultfile found");
} }
LOG.debug("Parse results JSON"); LOG.debug("parse results json");
ObjectMapper objectMapper = new ObjectMapper(); ObjectMapper objectMapper = new ObjectMapper();
ResultSummary resultSummary = objectMapper.readValue(resultFile.toURI().toURL(), ResultSummary.class); ResultSummary resultSummary = objectMapper.readValue(resultFile.toURI().toURL(), ResultSummary.class);
LOG.debug("Result JSON returned at " + resultSummary.timestamp + " with " + resultSummary.results.size() + " test results."); LOG.debug("result json returned time "+ 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() LOG.info("Checking for optional test competency profile information for paedagogical agent functionality...");
.filter(profile -> topicOrder.get(profile.exerciseTopicName) <= currentTopicIndex) List<TestCompetencyProfile> testCompetencyProfiles=CompetencyAssessmentUtil.readTestCompetencyProfiles(testPathHost, CompetencyAssessmentUtil.TEST_COMPETENCY_MANIFEST_FILE_NAME);
.collect(Collectors.toList()); if(testCompetencyProfiles!=null) {
LOG.info("Found optional test competency profiles, generating agent profile data...");
if (CompetencyAssessmentUtil.isFullSuccess(unsuccessful)) { resultSummary.overallTestCompetencyProfile=CompetencyAssessmentUtil.packFloats(CompetencyAssessmentUtil.sumTestCompetencyProfiles(testCompetencyProfiles));
filteredExercises = filteredExercises.stream() resultSummary.successfulTestCompetencyProfile=CompetencyAssessmentUtil.packFloats(CompetencyAssessmentUtil.sumSuccessfulCompetencyProfiles(testCompetencyProfiles, resultSummary, true));
.filter(profile -> profile.difficulty >= currentDifficulty && !testRepoURL.equals(profile.exerciseURL))
.collect(Collectors.toList()); LOG.info("Checking for optional exercise competency profile information for paedagogical agent exercise recommendation functionality...");
} else { //testPathHost or assignmentBasePath
filteredExercises = filteredExercises.stream() Path exerciseManifestFile = Paths.get(testPathHost.toAbsolutePath().toString(), CompetencyAssessmentUtil.EXERCISE_COMPETENCY_MANIFEST_FILE_NAME);
.filter(profile -> profile.difficulty <= currentDifficulty) if (Files.exists(exerciseManifestFile)) {
.collect(Collectors.toList()); LOG.info("Found optional exercise competency profiles, generating recommendations...");
resultSummary.recommendations = recommendNextExercises(assignmentId, testPathHost, testCompetencyProfiles, resultSummary);
}
} }
return resultSummary;
return filteredExercises; }
}
/*
public static float calculateScore(ExerciseCompetencyProfile profile, float[] unsuccessful, Map<String, Integer> topicOrder, float currentDifficulty) { * exercise recommendation part
float score = 1.0f; */
for (int i = 0; i < profile.competencyAssessments.length - 1; i++) { public List<Recommendation> recommendNextExercises(String assignmentId, Path testPathHost, List<TestCompetencyProfile> testCompetencyProfiles, ResultSummary resultSummary)
score += profile.competencyAssessments[i] * unsuccessful[i]; throws FileNotFoundException {
} // fetch repo url from original test upload
Pattern pattern = Pattern.compile(RegexUtil.DTA_TESTCONFIGREGEX);
score *= profile.difficulty * (0.5f + Math.abs(currentDifficulty - profile.difficulty)); File file = Paths.get(assignmentBasePath, assignmentId + ".txt").toFile();
score *= topicOrder.getOrDefault(profile.exerciseTopicName, 1); FileInputStream configFileStream = new FileInputStream(file);
Matcher config = RegexUtil.extractConfig(configFileStream, pattern);
return Math.round(score * 10.0f) / 10.0f; String testRepoURL = config.group(1);
}
List<ExerciseCompetencyProfile> exerciseCompetencyProfiles = CompetencyAssessmentUtil.readExerciseCompetencyProfiles(testPathHost, CompetencyAssessmentUtil.EXERCISE_COMPETENCY_MANIFEST_FILE_NAME);
int currentTopicIndex=0;
float currentDifficulty=0.0f;
//build course topic order
Map<String, Integer> topicOrder = new HashMap<>();
int order = 1;
for (ExerciseCompetencyProfile e : exerciseCompetencyProfiles) {
if (!topicOrder.containsKey(e.exerciseTopicName)) {
topicOrder.put(e.exerciseTopicName, order++);
}
if (e.exerciseURL.equals(testRepoURL)) {
currentTopicIndex = order;
currentDifficulty = e.difficulty;
}
}
//filter exercises according to success
float[] unsuccessful = CompetencyAssessmentUtil.sumSuccessfulCompetencyProfiles(testCompetencyProfiles, resultSummary, false);
List<ExerciseCompetencyProfile> filteredExercises = filterExercisesByTopicsAndDifficulty(
exerciseCompetencyProfiles, topicOrder, currentTopicIndex, testRepoURL,
currentDifficulty, unsuccessful, resultSummary);
//compute recommendations
List<Recommendation> recommendedExercises = new ArrayList<>();
for (ExerciseCompetencyProfile exerciseProfile : filteredExercises) {
Recommendation recommendation = new Recommendation(exerciseProfile.exerciseTopicName, exerciseProfile.exerciseURL, exerciseProfile.exerciseName,
exerciseProfile.difficulty, calculateScore(exerciseProfile, unsuccessful, topicOrder, currentDifficulty));
recommendedExercises.add(recommendation);
LOG.info("Recommending exercise "+recommendation.topic+"/"+recommendation.exerciseName+" with score "+recommendation.score);
}
//sort the recommendations for successful or resilient learners, otherwise reverse in display
recommendedExercises.stream().sorted(Recommendation.COMPARE_BY_SCORE).collect(Collectors.toList());
return recommendedExercises;
}
public static List<ExerciseCompetencyProfile> filterExercisesByTopicsAndDifficulty(List<ExerciseCompetencyProfile> exerciseCompetencyProfiles,
Map<String, Integer> topicOrder, int currentTopicIndex, String testRepoURL, float currentDifficulty, float[] unsuccessful,
ResultSummary resultSummary) {
//filter out all advanced topics in any case
//option for later: include next topic if fullsuccess and current difficulty == max difficulty
List<ExerciseCompetencyProfile> filteredExercises = exerciseCompetencyProfiles.stream()
.filter(testProfile -> topicOrder.get(testProfile.exerciseTopicName) <= currentTopicIndex)
.collect(Collectors.toList());
//filter by difficulty according to success
if (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 boolean isFullSuccess(float[] unsuccessful) {
for (float value : unsuccessful) {
if (value != 0.0f) {
return false;
}
}
return true;
}
public static float calculateScore(ExerciseCompetencyProfile exerciseProfile, float[] unsuccessful, Map<String, Integer> topicOrder, float currentDifficulty) {
//ensure factor 1 for full success not to blank out score, thus offset the base
float score = 1.0f;
//competency profile difference to not fully achieved competencies component
for (int i = 0; i < exerciseProfile.competencyAssessments.length-1; i++) {
score += exerciseProfile.competencyAssessments[i] * unsuccessful[i];
}
//difficulty component
score = score * (exerciseProfile.difficulty*(0.5f+Math.abs(currentDifficulty-exerciseProfile.difficulty)));
//topic component
score *= topicOrder.get(exerciseProfile.exerciseTopicName);
score = Math.round(score * 10.0f) / 10.0f;
return score;
}
} }
\ No newline at end of file
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