Skip to content

Commit

Permalink
review changes and modified testcases
Browse files Browse the repository at this point in the history
Signed-off-by: Mohd Kaif Siddique <[email protected]>
  • Loading branch information
Mohd Kaif Siddique committed Dec 3, 2024
1 parent eb5f1a1 commit b2d02f1
Show file tree
Hide file tree
Showing 8 changed files with 379 additions and 29 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -5,20 +5,28 @@
*/
package io.mosip.esignet.mock.identitysystem.controller;

import javax.validation.ConstraintViolation;
import javax.validation.ConstraintViolationException;
import javax.validation.Valid;

import io.mosip.esignet.mock.identitysystem.dto.*;
import io.mosip.esignet.mock.identitysystem.dto.Error;
import io.mosip.esignet.mock.identitysystem.validator.IdentitySchema;
import io.mosip.kernel.core.exception.ErrorResponse;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;

import io.mosip.esignet.mock.identitysystem.exception.MockIdentityException;
import io.mosip.esignet.mock.identitysystem.service.IdentityService;
import io.mosip.esignet.mock.identitysystem.util.HelperUtil;

import java.util.ArrayList;
import java.util.List;
import java.util.Set;


@RestController
Expand All @@ -32,7 +40,7 @@ public class IdentityController {
@PostMapping(value = "identity", consumes = { MediaType.APPLICATION_JSON_VALUE }, produces = {
MediaType.APPLICATION_JSON_VALUE })
public ResponseWrapper<IdentityStatus> createIdentity
(@Valid @RequestBody @IdentitySchema(isCreate=true) RequestWrapper< IdentityData> requestWrapper) throws MockIdentityException {
(@RequestBody @IdentitySchema(isCreate=true) RequestWrapper< IdentityData> requestWrapper) throws MockIdentityException {

ResponseWrapper response = new ResponseWrapper<IdentityStatus>();
IdentityStatus identityStatus = new IdentityStatus();
Expand All @@ -46,7 +54,7 @@ public class IdentityController {
@PutMapping(value = "identity", consumes = { MediaType.APPLICATION_JSON_VALUE }, produces = {
MediaType.APPLICATION_JSON_VALUE })
public ResponseWrapper<IdentityStatus> updateIdentity
(@Valid @RequestBody @IdentitySchema(isCreate=false) RequestWrapper<IdentityData> requestWrapper) throws MockIdentityException {
(@RequestBody @IdentitySchema(isCreate=false) RequestWrapper<IdentityData> requestWrapper) throws MockIdentityException {

ResponseWrapper response = new ResponseWrapper<IdentityStatus>();
IdentityStatus identityStatus = new IdentityStatus();
Expand Down Expand Up @@ -77,4 +85,25 @@ public ResponseWrapper<VerifiedClaimStatus> createVerifiedClaim(@Valid @RequestB
return response;

}

@ExceptionHandler(ConstraintViolationException.class)
public ResponseEntity handleMethodArgumentNotValidException(ConstraintViolationException ex) {
List<Error> errors = new ArrayList<>();
if(ex != null) {
Set<ConstraintViolation<?>> violations = ((ConstraintViolationException) ex).getConstraintViolations();
for(ConstraintViolation<?> cv : violations) {
errors.add(new Error(cv.getMessage(), cv.getPropertyPath().toString() + ": " + cv.getMessage()));
}
return new ResponseEntity<ResponseWrapper>(getResponseWrapper(errors), HttpStatus.OK);
}
return ResponseEntity.status(HttpStatus.BAD_REQUEST)
.body(errors);
}

private ResponseWrapper getResponseWrapper(List<Error> errors) {
ResponseWrapper responseWrapper = new ResponseWrapper<>();
responseWrapper.setResponseTime(HelperUtil.getCurrentUTCDateTime());
responseWrapper.setErrors(errors);
return responseWrapper;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@
import org.springframework.core.io.Resource;
import org.springframework.core.io.ResourceLoader;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;

import javax.validation.ConstraintValidator;
import javax.validation.ConstraintValidatorContext;
import java.io.IOException;
Expand All @@ -21,68 +23,82 @@
@Slf4j
public class IdentitySchemaValidator implements ConstraintValidator<IdentitySchema, Object> {

@Value("${mosip.mock.ida.identity.create.schema.url}")
private String createSchemaUrl;
@Value("${mosip.mock.ida.identity.schema.url}")
private String identitySchemaUrl;

@Value("#{${mosip.mock.ida.identity.update.exempted.field}}")
private Set<String> exemptedField;
@Value("#{${mosip.mock.ida.update-identity.non-mandatory.fields}}")
private Set<String> nonMandatoryFieldsOnUpdate;
private boolean isCreate;

private volatile JsonSchema cachedSchema;
private volatile JsonSchema schema;

@Autowired
ObjectMapper objectMapper;

@Autowired
ResourceLoader resourceLoader;


@Override
public void initialize(IdentitySchema constraintAnnotation) {
this.isCreate = constraintAnnotation.isCreate();
}

@Override
public boolean isValid(Object object, ConstraintValidatorContext context) {
context.disableDefaultConstraintViolation();
if (!(object instanceof RequestWrapper)) {
context.buildConstraintViolationWithTemplate("Invalid request type")
.addConstraintViolation();
return false;
}
RequestWrapper wrapper= (RequestWrapper) object;
Object requestObject = wrapper.getRequest();
if (!(requestObject instanceof IdentityData)) {
context.disableDefaultConstraintViolation();
context.buildConstraintViolationWithTemplate("Invalid request object type").addConstraintViolation();
return false;
}
IdentityData identityData=(IdentityData) requestObject;
JsonNode identityJsonNode = objectMapper.valueToTree(identityData);
Set<ValidationMessage> errors = getCachedSchema().validate(identityJsonNode);
Set<ValidationMessage> errors = getSchema().validate(identityJsonNode);
boolean isValid=true;
String errorName="";
if(!isCreate){
for(ValidationMessage validationMessage: errors){
String field=validationMessage.
getInstanceLocation().getName(0);
// Ignore validation errors with code 1029 (null value) for exempted fields when validating updateIdentity
if(!validationMessage.getCode().equals("1029") || !exemptedField.contains(field)){
if(!validationMessage.getCode().equals("1029") || !nonMandatoryFieldsOnUpdate.contains(field)){
errorName="invalid_"+field.toLowerCase();
isValid=false;
break;
}
}
}else if(!errors.isEmpty()){
isValid=false;
}
if (!isValid) {
context.disableDefaultConstraintViolation();
if(StringUtils.isEmpty(errorName))
errorName="invalid_"+errors.iterator().next().getInstanceLocation().getName(0).toLowerCase();
context.buildConstraintViolationWithTemplate(errorName)
.addConstraintViolation();
log.error("Validation failed for IdentityData: {}", errors);
return false;
}
return true;
}

private JsonSchema getCachedSchema() {
if(cachedSchema !=null ) return cachedSchema;
private JsonSchema getSchema() {
if(schema !=null ) return schema;
synchronized (this) {
if (cachedSchema == null) {
InputStream schemaResponse = getResource(createSchemaUrl);
if (schema == null) {
InputStream schemaResponse = getResource(identitySchemaUrl);
JsonSchemaFactory jsonSchemaFactory = JsonSchemaFactory.getInstance(SpecVersion.VersionFlag.V202012);
cachedSchema = jsonSchemaFactory.getSchema(schemaResponse);
schema = jsonSchemaFactory.getSchema(schemaResponse);
}
}
return cachedSchema;
return schema;
}

private InputStream getResource(String url) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,8 +27,8 @@

##-----------------------------------------Mock-identity-system properties----------------------------------------------

mosip.mock.ida.identity.create.schema.url=classpath:/mock-identity-schema.json
mosip.mock.ida.identity.update.exempted.field={"fullName","name","givenName","familyName","middleName","nickName","preferredUsername","gender","streetAddress","locality","region","country","pin","preferredLang","dateOfBirth","postalCode","encodedPhoto","email","phone","zoneInfo","locale","password"}
mosip.mock.ida.identity.schema.url=classpath:/mock-identity-schema.json
mosip.mock.ida.update-identity.non-mandatory.fields={"fullName","name","givenName","familyName","middleName","nickName","preferredUsername","gender","streetAddress","locality","region","country","pin","preferredLang","dateOfBirth","postalCode","encodedPhoto","email","phone","zoneInfo","locale","password"}

##----------------------------------------- Database properties --------------------------------------------------------
mosip.mockidentitysystem.database.hostname=${database.host}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
##-----------------------------------------Mock-identity-system properties----------------------------------------------

mosip.mock.ida.identity.create.schema.url=classpath:/mock-identity-schema.json
mosip.mock.ida.identity.update.exempted.field={"fullName","name","givenName","familyName","middleName","nickName","preferredUsername","gender","streetAddress","locality","region","country","pin","preferredLang","dateOfBirth","postalCode","encodedPhoto","email","phone","zoneInfo","locale","password"}
mosip.mock.ida.identity.schema.url=classpath:/mock-identity-schema.json
mosip.mock.ida.update-identity.non-mandatory.fields={"fullName","name","givenName","familyName","middleName","nickName","preferredUsername","gender","streetAddress","locality","region","country","pin","preferredLang","dateOfBirth","postalCode","encodedPhoto","email","phone","zoneInfo","locale","password"}


##----------------------------------------- Database properties --------------------------------------------------------

spring.datasource.url=jdbc:postgresql://localhost:5455/mosip_mockidentitysystem?currentSchema=mockidentitysystem
spring.datasource.url=jdbc:postgresql://localhost:5432/mosip_mockidentitysystem?currentSchema=mockidentitysystem
spring.datasource.username=postgres
spring.datasource.password=postgres
spring.datasource.driver-class-name=org.postgresql.Driver
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,6 @@
import org.springframework.test.context.junit4.SpringRunner;
import org.springframework.test.web.servlet.MockMvc;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;

import io.mosip.esignet.mock.identitysystem.service.IdentityService;
Expand Down Expand Up @@ -113,7 +112,6 @@ public void createIdentity_withValidIdentity_returnSuccessResponse() throws Exce
requestWrapper.setRequest(identityRequest);

Mockito.doNothing().when(identityService).addIdentity(identityRequest);

mockMvc.perform(post("/identity").content(objectMapper.writeValueAsString(requestWrapper))
.contentType(MediaType.APPLICATION_JSON)).andExpect(status().isOk())
.andExpect(jsonPath("$.response.status").value("mock identity data created successfully"));
Expand All @@ -128,18 +126,41 @@ public void createIdentity_withInvalidIdentity_returnErrorResponse() throws Exce
requestWrapper.setRequest(identityRequest);

Mockito.doNothing().when(identityService).addIdentity(identityRequest);

mockMvc.perform(post("/identity").content(objectMapper.writeValueAsString(requestWrapper))
.contentType(MediaType.APPLICATION_JSON)).andExpect(status().isOk())
.andExpect(jsonPath("$.errors").isNotEmpty())
.andExpect(jsonPath("$.errors[0].errorCode").value(ErrorConstants.INVALID_INDIVIDUAL_ID));
.andExpect(jsonPath("$.errors[0].errorCode").value("invalid_individualid"));
}

@Test
public void createIdentity_withInvalidFullName_returnErrorResponse() throws Exception {
RequestWrapper<IdentityData> requestWrapper = new RequestWrapper<IdentityData>();
ZonedDateTime requestTime = ZonedDateTime.now(ZoneOffset.UTC);
requestWrapper.setRequestTime(requestTime.format(DateTimeFormatter.ofPattern(UTC_DATETIME_PATTERN)));

List<LanguageValue> nameList=new ArrayList<>();
LanguageValue engLangValue= new LanguageValue();
engLangValue.setValue("Siddharth K سيدارت");
engLangValue.setLanguage("eng");
LanguageValue arabicLangValue= new LanguageValue();
arabicLangValue.setLanguage("ara");
arabicLangValue.setValue("سيدارت ك منصور");
nameList.add(engLangValue);
nameList.add(arabicLangValue);
identityRequest.setFullName(nameList);
requestWrapper.setRequest(identityRequest);

Mockito.doNothing().when(identityService).addIdentity(identityRequest);
mockMvc.perform(post("/identity").content(objectMapper.writeValueAsString(requestWrapper))
.contentType(MediaType.APPLICATION_JSON)).andExpect(status().isOk())
.andExpect(jsonPath("$.errors").isNotEmpty())
.andExpect(jsonPath("$.errors[0].errorCode").value("invalid_fullname"));
}

@Test
public void getIdentity_withValidId_returnSuccessResponse() throws Exception {
identityRequest.setIndividualId("123456789");
Mockito.when(identityService.getIdentity(Mockito.anyString())).thenReturn(identityRequest);

mockMvc.perform(get("/identity/{individualId}", "123456789")
.contentType(MediaType.APPLICATION_JSON)).andExpect(status().isOk())
.andExpect(jsonPath("$.response.individualId").value("123456789"));
Expand All @@ -163,7 +184,6 @@ public void addVerifiedClaims_withValidDetails_returnSuccessResponse() throws Ex
verifiedClaimRequestDto.setVerificationDetail(verificationDetail);

requestWrapper.setRequest(verifiedClaimRequestDto);

Mockito.doNothing().when(identityService).addVerifiedClaim(verifiedClaimRequestDto);
Mockito.when(identityService.getIdentity(Mockito.anyString())).thenReturn(identityRequest);

Expand All @@ -185,7 +205,6 @@ public void addVerifiedClaim_withInvalidClaim_returnErrorResponse() throws Exce
verifiedClaimRequestDto.setVerificationDetail(verificationDetail);

requestWrapper.setRequest(verifiedClaimRequestDto);

Mockito.doNothing().when(identityService).addVerifiedClaim(verifiedClaimRequestDto);

mockMvc.perform(post("/identity/add-verified-claim").content(objectMapper.writeValueAsString(requestWrapper))
Expand All @@ -202,10 +221,24 @@ public void updateIdentity_withValidIdentity_thenPass() throws Exception {
requestWrapper.setRequest(identityRequest);

Mockito.doNothing().when(identityService).updateIdentity(identityRequest);

mockMvc.perform(put("/identity").content(objectMapper.writeValueAsString(requestWrapper))
.contentType(MediaType.APPLICATION_JSON)).andExpect(status().isOk())
.andExpect(jsonPath("$.response.status").value("mock Identity data updated successfully"));
}

@Test
public void updateIdentity_withInValidIdentity_thenFail() throws Exception {
RequestWrapper<IdentityData> requestWrapper = new RequestWrapper<IdentityData>();
ZonedDateTime requestTime = ZonedDateTime.now(ZoneOffset.UTC);
requestWrapper.setRequestTime(requestTime.format(DateTimeFormatter.ofPattern(UTC_DATETIME_PATTERN)));
identityRequest.setFullName(null);
requestWrapper.setRequest(identityRequest);

Mockito.doNothing().when(identityService).updateIdentity(identityRequest);
mockMvc.perform(put("/identity").content(objectMapper.writeValueAsString(requestWrapper))
.contentType(MediaType.APPLICATION_JSON)).andExpect(status().isOk())
.andExpect(jsonPath("$.errors").isNotEmpty())
.andExpect(jsonPath("$.errors[0].errorCode").value("invalid_fullname"));
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@

mosip.mock.ida.identity.schema.url=classpath:/mock-identity-test-schema.json
mosip.mock.ida.update-identity.non-mandatory.fields={"name","givenName","familyName","middleName","nickName","preferredUsername","gender","streetAddress","locality","region","country","pin","preferredLang","dateOfBirth","postalCode","encodedPhoto","email","phone","zoneInfo","locale","password"}
2 changes: 2 additions & 0 deletions mock-identity-system/src/test/resources/bootstrap.properties
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@

spring.profiles.active=test
Loading

0 comments on commit b2d02f1

Please sign in to comment.