-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add further integration testing, minor fixes to api spec
- Loading branch information
1 parent
d75ed36
commit f8a17f8
Showing
41 changed files
with
1,553 additions
and
191 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
1 change: 1 addition & 0 deletions
1
caab-service/src/integrationTest/java/uk/gov/laa/ccms/data/api/AbstractIntegrationTest.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
254 changes: 254 additions & 0 deletions
254
...onTest/java/uk/gov/laa/ccms/data/api/controller/ApplicationControllerIntegrationTest.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,254 @@ | ||
package uk.gov.laa.ccms.data.api.controller; | ||
|
||
import static org.junit.jupiter.api.Assertions.assertEquals; | ||
import static org.junit.jupiter.api.Assertions.assertNotNull; | ||
import static org.springframework.test.context.jdbc.Sql.ExecutionPhase.AFTER_TEST_METHOD; | ||
import static org.springframework.test.context.jdbc.Sql.ExecutionPhase.BEFORE_TEST_METHOD; | ||
import static org.springframework.test.context.jdbc.SqlMergeMode.MergeMode.MERGE; | ||
|
||
import com.fasterxml.jackson.databind.ObjectMapper; | ||
import java.io.IOException; | ||
import java.lang.reflect.Field; | ||
import java.lang.reflect.InvocationTargetException; | ||
import java.lang.reflect.Method; | ||
import java.net.URI; | ||
import java.util.List; | ||
import java.util.Random; | ||
import java.util.stream.Stream; | ||
import org.junit.jupiter.params.ParameterizedTest; | ||
import org.junit.jupiter.params.provider.Arguments; | ||
import org.junit.jupiter.params.provider.MethodSource; | ||
import org.springframework.beans.factory.annotation.Autowired; | ||
import org.springframework.boot.test.context.SpringBootTest; | ||
import org.springframework.core.io.ClassPathResource; | ||
import org.springframework.http.HttpStatus; | ||
import org.springframework.http.ResponseEntity; | ||
import org.springframework.test.context.jdbc.Sql; | ||
import org.springframework.test.context.jdbc.SqlMergeMode; | ||
import uk.gov.laa.ccms.caab.api.CaabApiApplication; | ||
import uk.gov.laa.ccms.caab.api.controller.ApplicationController; | ||
import uk.gov.laa.ccms.caab.api.entity.AuditTrail; | ||
import uk.gov.laa.ccms.caab.api.service.ApplicationService; | ||
import uk.gov.laa.ccms.caab.model.ApplicationDetail; | ||
import uk.gov.laa.ccms.data.api.AbstractIntegrationTest; | ||
|
||
@SpringBootTest(classes = CaabApiApplication.class) | ||
@SqlMergeMode(MERGE) | ||
//@ActiveProfiles("local") | ||
//public class ApplicationControllerIntegrationTest { | ||
@Sql(executionPhase = BEFORE_TEST_METHOD, scripts = "/sql/application_tables_create_schema.sql") | ||
@Sql(executionPhase = AFTER_TEST_METHOD, scripts = "/sql/application_tables_drop_schema.sql") | ||
public class ApplicationControllerIntegrationTest extends AbstractIntegrationTest { | ||
|
||
@Autowired | ||
private ApplicationController applicationController; | ||
|
||
@Autowired | ||
private ApplicationService applicationService; | ||
|
||
/** | ||
* Loads the JSON file from the classpath and parses it into an ApplicationDetail object. | ||
* | ||
* @param jsonFilePath The path to the JSON file to load | ||
*/ | ||
private ApplicationDetail loadApplicationDetailFromJsonFile(String jsonFilePath) throws | ||
IOException { | ||
ObjectMapper objectMapper = new ObjectMapper(); | ||
ClassPathResource resource = new ClassPathResource(jsonFilePath); | ||
return objectMapper.readValue(resource.getInputStream(), ApplicationDetail.class); | ||
} | ||
|
||
/** | ||
* Generates a random 12-digit number string to be used as a case reference number. | ||
*/ | ||
private String generateTestCaseRef(){ | ||
Random random = new Random(); | ||
StringBuilder stringBuilder = new StringBuilder(12); | ||
|
||
for (int i = 0; i < 12; i++) { | ||
int digit = random.nextInt(10); // Generate a random digit (0-9) | ||
stringBuilder.append(digit); | ||
} | ||
|
||
return stringBuilder.toString(); | ||
} | ||
|
||
/** | ||
* Arguments for the testCreateApplication test method. | ||
*/ | ||
private static Stream<Arguments> createApplicationArguments() { | ||
return Stream.of( | ||
Arguments.of("/json/applicationDetail_base.json", | ||
"getAuditTrail", | ||
List.of("auditTrail")), | ||
Arguments.of("/json/applicationDetail_costStructure.json", | ||
"getCosts.getAuditTrail", | ||
List.of("costs.auditTrail", "auditTrail")), | ||
Arguments.of("/json/applicationDetail_costEntries.json", | ||
"getCosts.getCostEntries.getAuditTrail", | ||
List.of("costs.costEntries.auditTrail","costs.auditTrail", "auditTrail")), | ||
Arguments.of("/json/applicationDetail_correspondenceAddress.json", | ||
"getCorrespondenceAddress.getAuditTrail", | ||
List.of("correspondenceAddress.auditTrail", "auditTrail")), | ||
Arguments.of("/json/applicationDetail_proceedings.json", | ||
"getProceedings.getAuditTrail", | ||
List.of("proceedings.auditTrail", "auditTrail")), | ||
Arguments.of("/json/applicationDetail_scopeLimitation.json", | ||
"getProceedings.getScopeLimitations.getAuditTrail", | ||
List.of("proceedings.scopeLimitations.auditTrail","proceedings.auditTrail", "auditTrail")), | ||
Arguments.of("/json/applicationDetail_linkedCase.json", | ||
"getLinkedCases.getAuditTrail", | ||
List.of("linkedCases.auditTrail", "auditTrail")), | ||
Arguments.of("/json/applicationDetail_priorAuthority.json", | ||
"getPriorAuthorities.getAuditTrail", | ||
List.of("priorAuthorities.auditTrail", "auditTrail")), | ||
|
||
//No Audit data for reference data items | ||
Arguments.of("/json/applicationDetail_referenceDataItem.json", | ||
"getPriorAuthorities.getAuditTrail", | ||
List.of("priorAuthorities.auditTrail", "auditTrail")), | ||
Arguments.of("/json/applicationDetail_opponent.json", | ||
"getOpponents.getAuditTrail", | ||
List.of("opponents.auditTrail", "auditTrail")), | ||
Arguments.of("/json/applicationDetail_opponentAddress.json", | ||
"getOpponents.getAddress.getAuditTrail", | ||
List.of("opponents.address.auditTrail","opponents.auditTrail", "auditTrail")) | ||
); | ||
} | ||
|
||
/** | ||
* Parameterized test to create an application and verify that the audit trail and non-transient | ||
* variables are set correctly. | ||
* | ||
* @param fileInput The path to the JSON file to load | ||
* @param auditTrailMethod The method to call to get the audit trail object | ||
* (e.g. "getAuditTrail" or "getCosts.getAuditTrail") | ||
* @param auditTrailsToNull A list of audit trails to set to null | ||
* (e.g. "auditTrail" or "costs.auditTrail") | ||
*/ | ||
@ParameterizedTest | ||
@MethodSource("createApplicationArguments") | ||
public void testCreateApplication(String fileInput, String auditTrailMethod, List<String> auditTrailsToNull) | ||
throws IOException, NoSuchMethodException, InvocationTargetException, IllegalAccessException, | ||
NoSuchFieldException { | ||
// Load and parse the JSON file into yourApplicationDetailObject | ||
ApplicationDetail applicationDetail = loadApplicationDetailFromJsonFile( | ||
fileInput); | ||
|
||
String caseReference = generateTestCaseRef(); | ||
applicationDetail.setCaseReferenceNumber(caseReference); | ||
|
||
String auditUser = "[email protected]"; | ||
// Call the createApplication method directly | ||
ResponseEntity<Void> responseEntity = applicationController.createApplication(auditUser, applicationDetail); | ||
|
||
assertEquals(HttpStatus.CREATED, responseEntity.getStatusCode()); | ||
URI locationUri = responseEntity.getHeaders().getLocation(); | ||
|
||
String path = locationUri.getPath(); | ||
String id = path.substring(path.lastIndexOf('/') + 1); | ||
|
||
ApplicationDetail savedApplicationDetails = applicationService.getApplication(Long.valueOf(id)); | ||
|
||
assertAuditTrail(savedApplicationDetails, auditTrailMethod, auditUser); | ||
setAuditPropertiesToNull(savedApplicationDetails, auditTrailsToNull); | ||
assertEquals(applicationDetail, savedApplicationDetails); | ||
} | ||
|
||
/** | ||
* Assert that the audit trail is set correctly in the object. Uses reflection to navigate the | ||
* auditTrailMethod path and assert that the audit trail is set correctly. | ||
*/ | ||
private void assertAuditTrail(Object object, String auditMethod, String expectedAuditUser) | ||
throws InvocationTargetException, IllegalAccessException, NoSuchMethodException { | ||
String[] methodCalls = auditMethod.split("\\."); | ||
assertAuditTrailRecursive(object, methodCalls, 0, expectedAuditUser); | ||
} | ||
|
||
/** | ||
* Recursively navigate the object using the methodCalls array and assert that the audit trail is | ||
* set correctly. | ||
*/ | ||
private void assertAuditTrailRecursive(Object object, String[] methodCalls, int index, String expectedAuditUser) | ||
throws NoSuchMethodException, InvocationTargetException, IllegalAccessException { | ||
if (index >= methodCalls.length || object == null) { | ||
return; | ||
} | ||
|
||
Method method = object.getClass().getMethod(methodCalls[index]); | ||
object = method.invoke(object); | ||
|
||
if (object instanceof List) { | ||
List<?> list = (List<?>) object; | ||
for (Object item : list) { | ||
assertAuditTrailRecursive(item, methodCalls, index + 1, expectedAuditUser); | ||
} | ||
} else { | ||
if (index == methodCalls.length - 1) { | ||
assertAuditDetailsInObject(object, expectedAuditUser); | ||
} else { | ||
assertAuditTrailRecursive(object, methodCalls, index + 1, expectedAuditUser); | ||
} | ||
} | ||
} | ||
|
||
/** | ||
* Used to assert that the audit trail is set correctly in the object. | ||
* | ||
* @param object The object to check | ||
* @param expectedAuditUser The expected audit user | ||
*/ | ||
private void assertAuditDetailsInObject(Object object, String expectedAuditUser) { | ||
if (object instanceof AuditTrail auditTrail) { | ||
assertNotNull(auditTrail); | ||
assertEquals(expectedAuditUser, auditTrail.getCreatedBy()); | ||
assertEquals(expectedAuditUser, auditTrail.getLastSavedBy()); | ||
assertNotNull(auditTrail.getCreated()); | ||
assertNotNull(auditTrail.getLastSaved()); | ||
} | ||
} | ||
|
||
/** | ||
* Sets the audit trail properties to null in the object. Uses reflection to navigate the | ||
* list of auditTrailsToNull and set the audit trail to null. | ||
*/ | ||
private void setAuditPropertiesToNull(Object object, List<String> auditTrailsToNull) throws NoSuchFieldException, IllegalAccessException { | ||
if (object == null || auditTrailsToNull == null) { | ||
return; | ||
} | ||
for (String trail : auditTrailsToNull) { | ||
String[] fields = trail.split("\\."); | ||
nullifyFieldRecursive(object, fields, 0); | ||
} | ||
} | ||
|
||
/** | ||
* Recursively navigate the object using the fields array and set the field to null. | ||
*/ | ||
private static void nullifyFieldRecursive(Object object, String[] fields, int index) | ||
throws NoSuchFieldException, IllegalAccessException { | ||
if (object == null || index >= fields.length) { | ||
return; | ||
} | ||
|
||
if (object instanceof List) { | ||
// Handle List objects | ||
List<?> list = (List<?>) object; | ||
for (Object item : list) { | ||
nullifyFieldRecursive(item, fields, index); | ||
} | ||
} else { | ||
Field field = object.getClass().getDeclaredField(fields[index]); | ||
field.setAccessible(true); | ||
|
||
if (index == fields.length - 1) { | ||
// Last field in the path, set to null | ||
field.set(object, null); | ||
} else { | ||
// Not the last field, navigate to the next object or list in the path | ||
Object nextObject = field.get(object); | ||
nullifyFieldRecursive(nextObject, fields, index + 1); | ||
} | ||
} | ||
} | ||
} |
Oops, something went wrong.