summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/main/java/com/stileeducation/markr/service/StudentService.java8
-rw-r--r--src/main/java/com/stileeducation/markr/service/TestResultsService.java43
-rw-r--r--src/main/java/com/stileeducation/markr/service/TestService.java12
-rw-r--r--src/test/java/com/stileeducation/markr/controller/TestResultsControllerTest.java249
-rw-r--r--src/test/java/com/stileeducation/markr/service/TestResultsServiceTest.java12
5 files changed, 267 insertions, 57 deletions
diff --git a/src/main/java/com/stileeducation/markr/service/StudentService.java b/src/main/java/com/stileeducation/markr/service/StudentService.java
index 95ce182..e49f06a 100644
--- a/src/main/java/com/stileeducation/markr/service/StudentService.java
+++ b/src/main/java/com/stileeducation/markr/service/StudentService.java
@@ -2,6 +2,7 @@ package com.stileeducation.markr.service;
import com.stileeducation.markr.entity.Student;
import com.stileeducation.markr.repository.StudentRepository;
+import jakarta.transaction.Transactional;
import org.springframework.stereotype.Service;
import java.util.Optional;
@@ -15,10 +16,15 @@ public class StudentService {
this.studentRepository = studentRepository;
}
+ @Transactional
public Student findOrCreateStudent(String firstName, String lastName, String studentNumber) {
Optional<Student> optionalStudent = studentRepository.findByStudentNumber(studentNumber);
if (optionalStudent.isPresent()) {
- return optionalStudent.get();
+ Student student = optionalStudent.get();
+ // Reset transients
+ student.setCreated(false);
+ student.setUpdated(false);
+ return student;
} else {
Student student = new Student();
student.setFirstName(firstName);
diff --git a/src/main/java/com/stileeducation/markr/service/TestResultsService.java b/src/main/java/com/stileeducation/markr/service/TestResultsService.java
index a06400e..7823feb 100644
--- a/src/main/java/com/stileeducation/markr/service/TestResultsService.java
+++ b/src/main/java/com/stileeducation/markr/service/TestResultsService.java
@@ -8,7 +8,10 @@ import com.stileeducation.markr.entity.Student;
import com.stileeducation.markr.entity.Test;
import com.stileeducation.markr.entity.TestResult;
import com.stileeducation.markr.exception.TestNotFoundException;
+import com.stileeducation.markr.repository.StudentRepository;
+import com.stileeducation.markr.repository.TestRepository;
import com.stileeducation.markr.repository.TestResultRepository;
+import jakarta.transaction.Transactional;
import org.apache.commons.math3.stat.descriptive.moment.StandardDeviation;
import org.apache.commons.math3.stat.descriptive.rank.Percentile;
import org.springframework.stereotype.Service;
@@ -25,19 +28,29 @@ public class TestResultsService {
private final TestResultRepository testResultRepository;
+ private final StudentRepository studentRepository;
+
+ private final TestRepository testRepository;
+
private final StudentService studentService;
private final TestService testService;
- public TestResultsService(TestResultRepository testResultRepository, StudentService studentService, TestService testService) {
+ public TestResultsService(TestResultRepository testResultRepository,
+ StudentRepository studentRepository,
+ TestRepository testRepository,
+ StudentService studentService,
+ TestService testService) {
this.testResultRepository = testResultRepository;
+ this.studentRepository = studentRepository;
+ this.testRepository = testRepository;
this.studentService = studentService;
this.testService = testService;
}
private static double[] calculatePercentages(List<TestResult> results, double totalMarksAvailable) {
return results.stream()
- .mapToDouble(result -> (double) result.getMarksAwarded() / totalMarksAvailable * 100)
+ .mapToDouble(result -> (double) result.getMarksObtained() / totalMarksAvailable * 100)
.toArray();
}
@@ -55,6 +68,7 @@ public class TestResultsService {
return aggregateResponseDTO;
}
+ @Transactional
public ImportResponseDTO processTestResults(MCQTestResultsDTO testResults) {
ImportResponseDTO.ImportData importData = new ImportResponseDTO.ImportData();
boolean isValid = true;
@@ -70,23 +84,29 @@ public class TestResultsService {
return createImportResponse(importData, isValid);
}
- public TestResult findOrCreateTestResult(Student student, Test test, Integer marksAwarded) {
+ @Transactional
+ public TestResult findOrCreateTestResult(Student student, Test test, Integer marksObtained) {
Optional<TestResult> optionalTestResult = testResultRepository.findByStudentAndTest(student, test);
+
if (optionalTestResult.isPresent()) {
TestResult testResult = optionalTestResult.get();
- if (marksAwarded > testResult.getMarksAwarded()) {
- testResult.setMarksAwarded(marksAwarded);
+
+ // Update marks if new marks are higher
+ if (marksObtained > testResult.getMarksObtained()) {
+ testResult.setMarksObtained(marksObtained);
+ testResult.setCreated(false);
testResult.setUpdated(true);
- testResultRepository.save(testResult);
+ return testResultRepository.save(testResult);
} else {
+ testResult.setCreated(false);
testResult.setUpdated(false);
+ return testResult;
}
- return testResult;
} else {
TestResult testResult = new TestResult();
testResult.setStudent(student);
testResult.setTest(test);
- testResult.setMarksAwarded(marksAwarded);
+ testResult.setMarksObtained(marksObtained);
testResult.setCreated(true);
return testResultRepository.save(testResult);
}
@@ -186,7 +206,8 @@ public class TestResultsService {
dto.setCount(results.size());
}
- private void processTestResult(MCQTestResultDTO mcqTestResult, ImportResponseDTO.ImportData importData) {
+ @Transactional
+ protected void processTestResult(MCQTestResultDTO mcqTestResult, ImportResponseDTO.ImportData importData) {
Student student =
studentService
.findOrCreateStudent(
@@ -228,10 +249,10 @@ public class TestResultsService {
if (isValid) {
response.setStatus("success");
- response.setMessage("Import operation completed successfully.");
+ response.setMessage("Import completed successfully");
} else {
response.setStatus("failure");
- response.setMessage("Data was invalid or processing failed.");
+ response.setMessage("Data was invalid or processing failed");
}
return response;
diff --git a/src/main/java/com/stileeducation/markr/service/TestService.java b/src/main/java/com/stileeducation/markr/service/TestService.java
index 0e109ac..f42da1a 100644
--- a/src/main/java/com/stileeducation/markr/service/TestService.java
+++ b/src/main/java/com/stileeducation/markr/service/TestService.java
@@ -2,6 +2,7 @@ package com.stileeducation.markr.service;
import com.stileeducation.markr.entity.Test;
import com.stileeducation.markr.repository.TestRepository;
+import jakarta.transaction.Transactional;
import org.springframework.stereotype.Service;
import java.util.Optional;
@@ -16,22 +17,27 @@ public class TestService {
this.testRepository = testRepository;
}
+ @Transactional
public Optional<Test> findTest(String testId) {
return testRepository.findByTestId(testId);
}
+ @Transactional
public Test findOrCreateTest(String testId, Integer marksAvailable) {
Optional<Test> optionalTest = testRepository.findByTestId(testId);
+
if (optionalTest.isPresent()) {
Test test = optionalTest.get();
- if (test.getMarksAvailable() < marksAvailable) {
+ if (marksAvailable > test.getMarksAvailable()) {
test.setMarksAvailable(marksAvailable);
+ test.setCreated(false);
test.setUpdated(true);
- testRepository.save(test);
+ return testRepository.save(test);
} else {
+ test.setCreated(false);
test.setUpdated(false);
+ return test;
}
- return test;
} else {
Test test = new Test();
test.setTestId(testId);
diff --git a/src/test/java/com/stileeducation/markr/controller/TestResultsControllerTest.java b/src/test/java/com/stileeducation/markr/controller/TestResultsControllerTest.java
index efb20d6..cd1f3cb 100644
--- a/src/test/java/com/stileeducation/markr/controller/TestResultsControllerTest.java
+++ b/src/test/java/com/stileeducation/markr/controller/TestResultsControllerTest.java
@@ -4,6 +4,8 @@ import com.stileeducation.markr.MarkrApplication;
import com.stileeducation.markr.converter.XmlMarkrMessageConverter;
import com.stileeducation.markr.dto.ImportResponseDTO;
import com.stileeducation.markr.dto.MCQTestResultsDTO;
+import com.stileeducation.markr.repository.TestResultRepository;
+import com.stileeducation.markr.service.TestService;
import jakarta.xml.bind.JAXBContext;
import jakarta.xml.bind.JAXBException;
import jakarta.xml.bind.Marshaller;
@@ -33,6 +35,11 @@ public class TestResultsControllerTest {
@Autowired
private TestRestTemplate restTemplate;
+ @Autowired
+ private TestResultRepository testResultRepository;
+ @Autowired
+ private TestService testService;
+
@BeforeAll
static void setup() throws IOException {
validPayload = new String(new ClassPathResource("sample-results.xml").getInputStream().readAllBytes(), UTF_8);
@@ -95,11 +102,11 @@ public class TestResultsControllerTest {
// Given
String invalidPayload = """
<mcq-test-results>
- <mcq-test-result scanned-on="2017-12-04T12:12:10+11:00">
+ <mcq-test-result scanned-on="2024-07-22T12:12:10+11:00">
<first-name></first-name>
- <last-name>Alysander</last-name>
- <student-number>002299</student-number>
- <test-id>9863</test-id>
+ <last-name>Szukalski</last-name>
+ <student-number>001122</student-number>
+ <test-id>2024001</test-id>
<summary-marks available="20" obtained="13"/>
</mcq-test-result>
</mcq-test-results>
@@ -123,11 +130,11 @@ public class TestResultsControllerTest {
// Given
String invalidPayload = """
<mcq-test-results>
- <mcq-test-result scanned-on="2017-12-04T12:12:10+11:00">
- <first-name>KJ</first-name>
+ <mcq-test-result scanned-on="2024-07-22T12:12:10+11:00">
+ <first-name>Szymon</first-name>
<last-name></last-name>
- <student-number>002299</student-number>
- <test-id>9863</test-id>
+ <student-number>001122</student-number>
+ <test-id>2024001</test-id>
<summary-marks available="20" obtained="13"/>
</mcq-test-result>
</mcq-test-results>
@@ -151,11 +158,11 @@ public class TestResultsControllerTest {
// Given
String invalidPayload = """
<mcq-test-results>
- <mcq-test-result scanned-on="2017-12-04T12:12:10+11:00">
- <first-name>KJ</first-name>
- <last-name>Alysander</last-name>
+ <mcq-test-result scanned-on="2024-07-22T12:12:10+11:00">
+ <first-name>Szymon</first-name>
+ <last-name>Szukalski</last-name>
<student-number></student-number>
- <test-id>9863</test-id>
+ <test-id>2024001</test-id>
<summary-marks available="20" obtained="13"/>
</mcq-test-result>
</mcq-test-results>
@@ -179,10 +186,10 @@ public class TestResultsControllerTest {
// Given
String invalidPayload = """
<mcq-test-results>
- <mcq-test-result scanned-on="2017-12-04T12:12:10+11:00">
- <first-name>KJ</first-name>
- <last-name>Alysander</last-name>
- <student-number>002299</student-number>
+ <mcq-test-result scanned-on="2024-07-22T12:12:10+11:00">
+ <first-name>Szymon</first-name>
+ <last-name>Szukalski</last-name>
+ <student-number>2024001</student-number>
<test-id></test-id>
<summary-marks available="20" obtained="13"/>
</mcq-test-result>
@@ -207,11 +214,11 @@ public class TestResultsControllerTest {
// Given
String invalidPayload = """
<mcq-test-results>
- <mcq-test-result scanned-on="2017-12-04T12:12:10+11:00">
- <first-name>KJ</first-name>
- <last-name>Alysander</last-name>
- <student-number>002299</student-number>
- <test-id>9863</test-id>
+ <mcq-test-result scanned-on="2024-07-22T12:12:10+11:00">
+ <first-name>Szymon</first-name>
+ <last-name>Szukalski</last-name>
+ <student-number>001122</student-number>
+ <test-id>2024001</test-id>
</mcq-test-result>
</mcq-test-results>
""";
@@ -234,11 +241,11 @@ public class TestResultsControllerTest {
// Given
String invalidPayload = """
<mcq-test-results>
- <mcq-test-result scanned-on="2017-12-04T12:12:10+11:00">
- <first-name>KJ</first-name>
- <last-name>Alysander</last-name>
- <student-number>002299</student-number>
- <test-id>9863</test-id>
+ <mcq-test-result scanned-on="2024-07-22T12:12:10+11:00">
+ <first-name>Szymon</first-name>
+ <last-name>Szukalski</last-name>
+ <student-number>001122</student-number>
+ <test-id>2024001</test-id>
<summary-marks obtained="13"/>
</mcq-test-result>
</mcq-test-results>
@@ -262,11 +269,11 @@ public class TestResultsControllerTest {
// Given
String invalidPayload = """
<mcq-test-results>
- <mcq-test-result scanned-on="2017-12-04T12:12:10+11:00">
- <first-name>KJ</first-name>
- <last-name>Alysander</last-name>
- <student-number>002299</student-number>
- <test-id>9863</test-id>
+ <mcq-test-result scanned-on="2024-07-22T12:12:10+11:00">
+ <first-name>Szymon</first-name>
+ <last-name>Szukalski</last-name>
+ <student-number>001122</student-number>
+ <test-id>2024001</test-id>
<summary-marks available="20"/>
</mcq-test-result>
</mcq-test-results>
@@ -290,11 +297,11 @@ public class TestResultsControllerTest {
// Given
String invalidPayload = """
<mcq-test-results>
- <mcq-test-result scanned-on="2017-12-04T12:12:10+11:00">
- <first-name>KJ</first-name>
- <last-name>Alysander</last-name>
- <student-number>002299</student-number>
- <test-id>9863</test-id>
+ <mcq-test-result scanned-on="2024-07-22T12:12:10+11:00">
+ <first-name>Szymon</first-name>
+ <last-name>Szukalski</last-name>
+ <student-number>001122</student-number>
+ <test-id>2024001</test-id>
<summary-marks available="20" obtained="1
</mcq-test-result>
</mcq-test-results>
@@ -312,4 +319,174 @@ public class TestResultsControllerTest {
assertThat(response.getBody()).isNotNull();
assertThat(response.getBody().getMessage()).isEqualTo("Invalid XML payload");
}
+
+ @Test
+ void testInitialSubmitReportsCreatedEntities() throws Exception {
+ // Given
+ String validPayload = """
+ <mcq-test-results>
+ <mcq-test-result scanned-on="2024-07-22T12:12:10+11:00">
+ <first-name>John</first-name>
+ <last-name>Doe</last-name>
+ <student-number>002233</student-number>
+ <test-id>202402</test-id>
+ <summary-marks available="20" obtained="13"/>
+ </mcq-test-result>
+ </mcq-test-results>
+ """;
+
+ HttpHeaders headers = new HttpHeaders();
+ headers.setContentType(XmlMarkrMessageConverter.MEDIA_TYPE);
+ HttpEntity<String> entity = new HttpEntity<>(validPayload, headers);
+
+ // When
+ ResponseEntity<ImportResponseDTO> response = restTemplate.postForEntity(IMPORT_ENDPOINT, entity, ImportResponseDTO.class);
+
+ // Then
+ assertThat(response.getStatusCode()).isEqualTo(HttpStatus.OK);
+ assertThat(response.getBody()).isNotNull();
+ assertThat(response.getBody().getStatus()).isEqualTo("success");
+ assertThat(response.getBody().getMessage()).isEqualTo("Import completed successfully");
+ assertThat(response.getBody().getData().getStudentsCreated()).isEqualTo(1);
+ assertThat(response.getBody().getData().getStudentsUpdated()).isEqualTo(0);
+ assertThat(response.getBody().getData().getTestsCreated()).isEqualTo(1);
+ assertThat(response.getBody().getData().getTestsUpdated()).isEqualTo(0);
+ assertThat(response.getBody().getData().getTestResultsCreated()).isEqualTo(1);
+ assertThat(response.getBody().getData().getTestResultsUpdated()).isEqualTo(0);
+ }
+
+
+ @Test
+ void testSubsequentSubmitReportsNoCreatedOrUpdatedEntities() throws Exception {
+ // Given
+ String validPayload = """
+ <mcq-test-results>
+ <mcq-test-result scanned-on="2024-07-22T12:12:10+11:00">
+ <first-name>John</first-name>
+ <last-name>Doe</last-name>
+ <student-number>003344</student-number>
+ <test-id>202403</test-id>
+ <summary-marks available="20" obtained="13"/>
+ </mcq-test-result>
+ <mcq-test-result scanned-on="2024-07-22T12:12:10+11:00">
+ <first-name>John</first-name>
+ <last-name>Doe</last-name>
+ <student-number>003344</student-number>
+ <test-id>202403</test-id>
+ <summary-marks available="20" obtained="13"/>
+ </mcq-test-result>
+ </mcq-test-results>
+ """;
+
+ HttpHeaders headers = new HttpHeaders();
+ headers.setContentType(XmlMarkrMessageConverter.MEDIA_TYPE);
+ HttpEntity<String> entity = new HttpEntity<>(validPayload, headers);
+
+ // Initial Submit
+ restTemplate.postForEntity(IMPORT_ENDPOINT, entity, ImportResponseDTO.class);
+
+ // When
+ ResponseEntity<ImportResponseDTO> response = restTemplate.postForEntity(IMPORT_ENDPOINT, entity, ImportResponseDTO.class);
+
+ // Then
+ assertThat(response.getStatusCode()).isEqualTo(HttpStatus.OK);
+ assertThat(response.getBody()).isNotNull();
+ assertThat(response.getBody().getStatus()).isEqualTo("success");
+ assertThat(response.getBody().getMessage()).isEqualTo("Import completed successfully");
+ assertThat(response.getBody().getData().getStudentsCreated()).isEqualTo(0);
+ assertThat(response.getBody().getData().getStudentsUpdated()).isEqualTo(0);
+ assertThat(response.getBody().getData().getTestsCreated()).isEqualTo(0);
+ assertThat(response.getBody().getData().getTestsUpdated()).isEqualTo(0);
+ assertThat(response.getBody().getData().getTestResultsCreated()).isEqualTo(0);
+ assertThat(response.getBody().getData().getTestResultsUpdated()).isEqualTo(0);
+ }
+
+
+ @Test
+ void testMarksAvailableAndObtainedAreUpdated() throws Exception {
+ // Given
+ String payload = """
+ <mcq-test-results>
+ <mcq-test-result scanned-on="2024-07-22T12:12:10+11:00">
+ <first-name>John</first-name>
+ <last-name>Doe</last-name>
+ <student-number>004455</student-number>
+ <test-id>202404</test-id>
+ <summary-marks available="20" obtained="13"/>
+ </mcq-test-result>
+ <mcq-test-result scanned-on="2024-07-22T12:12:10+11:00">
+ <first-name>John</first-name>
+ <last-name>Doe</last-name>
+ <student-number>004455</student-number>
+ <test-id>202404</test-id>
+ <summary-marks available="24" obtained="15"/>
+ </mcq-test-result>
+ </mcq-test-results>
+ """;
+
+ HttpHeaders headers = new HttpHeaders();
+ headers.setContentType(XmlMarkrMessageConverter.MEDIA_TYPE);
+ HttpEntity<String> entity = new HttpEntity<>(payload, headers);
+
+ // When
+ ResponseEntity<ImportResponseDTO> response = restTemplate.postForEntity(IMPORT_ENDPOINT, entity, ImportResponseDTO.class);
+
+ // Then
+ assertThat(response.getStatusCode()).isEqualTo(HttpStatus.OK);
+ assertThat(response.getBody()).isNotNull();
+ assertThat(response.getBody().getStatus()).isEqualTo("success");
+ assertThat(response.getBody().getMessage()).isEqualTo("Import completed successfully");
+
+ assertThat(response.getBody().getData().getStudentsCreated()).isEqualTo(1);
+ assertThat(response.getBody().getData().getStudentsUpdated()).isEqualTo(0);
+
+ assertThat(response.getBody().getData().getTestsCreated()).isEqualTo(1);
+ assertThat(response.getBody().getData().getTestsUpdated()).isEqualTo(1);
+
+ assertThat(response.getBody().getData().getTestResultsCreated()).isEqualTo(1);
+ assertThat(response.getBody().getData().getTestResultsUpdated()).isEqualTo(1);
+ }
+
+ @Test
+ void testMarksAvailableAndObtainedAreNotUpdatedWhenFirstSubmissionIsHigher() throws Exception {
+ // Given
+ String payload = """
+ <mcq-test-results>
+ <mcq-test-result scanned-on="2024-07-22T12:12:10+11:00">
+ <first-name>John</first-name>
+ <last-name>Doe</last-name>
+ <student-number>005566</student-number>
+ <test-id>202405</test-id>
+ <summary-marks available="24" obtained="15"/>
+ </mcq-test-result>
+ <mcq-test-result scanned-on="2024-07-22T12:12:10+11:00">
+ <first-name>John</first-name>
+ <last-name>Doe</last-name>
+ <student-number>005566</student-number>
+ <test-id>202405</test-id>
+ <summary-marks available="20" obtained="13"/>
+ </mcq-test-result>
+ </mcq-test-results>
+ """;
+
+ HttpHeaders headers = new HttpHeaders();
+ headers.setContentType(XmlMarkrMessageConverter.MEDIA_TYPE);
+ HttpEntity<String> entity = new HttpEntity<>(payload, headers);
+
+ // When
+ ResponseEntity<ImportResponseDTO> response = restTemplate.postForEntity(IMPORT_ENDPOINT, entity, ImportResponseDTO.class);
+
+ // Then
+ assertThat(response.getStatusCode()).isEqualTo(HttpStatus.OK);
+ assertThat(response.getBody()).isNotNull();
+ assertThat(response.getBody().getStatus()).isEqualTo("success");
+ assertThat(response.getBody().getMessage()).isEqualTo("Import completed successfully");
+ assertThat(response.getBody().getData().getStudentsCreated()).isEqualTo(1);
+ assertThat(response.getBody().getData().getStudentsUpdated()).isEqualTo(0);
+ assertThat(response.getBody().getData().getTestsCreated()).isEqualTo(1);
+ assertThat(response.getBody().getData().getTestsUpdated()).isEqualTo(0);
+ assertThat(response.getBody().getData().getTestResultsCreated()).isEqualTo(1);
+ assertThat(response.getBody().getData().getTestResultsUpdated()).isEqualTo(0);
+ }
+
} \ No newline at end of file
diff --git a/src/test/java/com/stileeducation/markr/service/TestResultsServiceTest.java b/src/test/java/com/stileeducation/markr/service/TestResultsServiceTest.java
index ad4e476..f9a8871 100644
--- a/src/test/java/com/stileeducation/markr/service/TestResultsServiceTest.java
+++ b/src/test/java/com/stileeducation/markr/service/TestResultsServiceTest.java
@@ -89,37 +89,37 @@ class TestResultsServiceTest {
testResult1 = new TestResultBuilder()
.withStudent(student1)
.withTest(test1)
- .withMarksAwarded(10)
+ .withMarksObtained(10)
.build();
testResult2 = new TestResultBuilder()
.withStudent(student2)
.withTest(test1)
- .withMarksAwarded(20)
+ .withMarksObtained(20)
.build();
testResult3 = new TestResultBuilder()
.withStudent(student3)
.withTest(test1)
- .withMarksAwarded(40)
+ .withMarksObtained(40)
.build();
testResult4 = new TestResultBuilder()
.withStudent(student4)
.withTest(test1)
- .withMarksAwarded(50)
+ .withMarksObtained(50)
.build();
testResult5 = new TestResultBuilder()
.withStudent(student3)
.withTest(test1)
- .withMarksAwarded(70)
+ .withMarksObtained(70)
.build();
testResult6 = new TestResultBuilder()
.withStudent(student4)
.withTest(test1)
- .withMarksAwarded(80)
+ .withMarksObtained(80)
.build();
test1Results = List.of(testResult1, testResult2, testResult3, testResult4, testResult5, testResult6);