package pl.edu.icm.saos.enrichment.upload;
import static org.hamcrest.Matchers.containsInAnyOrder;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertThat;
import static org.mockito.Mockito.*;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.put;
import static org.springframework.test.web.servlet.result.MockMvcResultHandlers.print;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.header;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
import static org.springframework.test.web.servlet.setup.MockMvcBuilders.webAppContextSetup;
import static pl.edu.icm.saos.common.json.JsonNormalizer.normalizeJson;
import static pl.edu.icm.saos.enrichment.upload.EnrichmentTagUploadResponseMessages.ERROR_AUTHENTICATION_FAILED;
import static pl.edu.icm.saos.enrichment.upload.EnrichmentTagUploadResponseMessages.ERROR_EMPTY_DATA;
import static pl.edu.icm.saos.enrichment.upload.EnrichmentTagUploadResponseMessages.ERROR_INVALID_DATA;
import static pl.edu.icm.saos.enrichment.upload.EnrichmentTagUploadResponseMessages.ERROR_INVALID_JSON_FORMAT;
import static pl.edu.icm.saos.enrichment.upload.EnrichmentTagUploadResponseMessages.ERROR_MAX_UPLOAD_SIZE_EXCEEDED;
import static pl.edu.icm.saos.enrichment.upload.EnrichmentTagUploadResponseMessages.ERROR_SAME_TAG_ALREADY_UPLOADED;
import static pl.edu.icm.saos.enrichment.upload.EnrichmentTagUploadResponseMessages.ERROR_UNSUPPORTED_HTTP_CONTENT_TYPE;
import static pl.edu.icm.saos.enrichment.upload.EnrichmentTagUploadResponseMessages.ERROR_UNSUPPORTED_HTTP_METHOD;
import static pl.edu.icm.saos.enrichment.upload.EnrichmentTagUploadResponseMessages.OK_MESSAGE;
import java.io.IOException;
import java.io.InputStream;
import org.apache.commons.codec.binary.Base64;
import org.hamcrest.Matchers;
import org.junit.Before;
import org.junit.Test;
import org.junit.experimental.categories.Category;
import org.mockito.Mockito;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.security.web.FilterChainProxy;
import org.springframework.test.context.web.WebAppConfiguration;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.ResultActions;
import org.springframework.web.context.WebApplicationContext;
import pl.edu.icm.saos.batch.core.JobForcingExecutor;
import pl.edu.icm.saos.common.batch.JobName;
import pl.edu.icm.saos.common.service.ServiceExecutionStatus;
import pl.edu.icm.saos.common.testcommon.category.SlowTest;
import pl.edu.icm.saos.persistence.common.TestPersistenceObjectFactory;
import pl.edu.icm.saos.persistence.enrichment.EnrichmentTagRepository;
import pl.edu.icm.saos.persistence.enrichment.UploadEnrichmentTagRepository;
import pl.edu.icm.saos.persistence.enrichment.model.EnrichmentTag;
import pl.edu.icm.saos.persistence.model.Judgment;
import pl.edu.icm.saos.webapp.WebappTestSupport;
/**
*
* @author Ćukasz Dumiszewski
*
*/
@Category(SlowTest.class)
@WebAppConfiguration
public class EnrichmentTagUploadControllerTest extends WebappTestSupport {
@Autowired
private WebApplicationContext webApplicationCtx;
@Autowired
private FilterChainProxy springSecurityFilterChain;
@Autowired
private EnrichmentTagRepository enrichmentTagRepository;
@Autowired
private UploadEnrichmentTagRepository uploadEnrichmentTagRepository;
@Autowired
private EnrichmentTagUploadService enrichmentTagUploadService;
@Autowired
private TestPersistenceObjectFactory testPersistenceObjectFactory;
@Autowired
private EnrichmentTagUploadController enrichmentTagUploadController;
@Autowired
private JobForcingExecutor jobForcingExecutor;
@Value("${enrichment.enricher.login}")
private String enricherLogin;
private String enricherPassword = "pass";
private static final String URL = "/api/enrichment/tags";
private MockMvc mvc;
@Before
public void setUp() throws IOException {
mvc = webAppContextSetup(webApplicationCtx).addFilter(springSecurityFilterChain).build();
assertEquals(0, enrichmentTagRepository.count());
assertEquals(0, uploadEnrichmentTagRepository.count());
}
// ------------------------ TESTS --------------------------
@Test
public void uploadEnrichmentTags_Unauthorized_NoAuthHeader() throws Exception {
// execute
ResultActions result = mvc.perform(post(URL));
// assert
assertUnauthorized(result);
}
@Test
public void uploadEnrichmentTags_Unauthorized_InvalidUsername() throws Exception {
// given
String basicAuth = "Basic " + new String(Base64.encodeBase64((enricherLogin + "_badSuffix:pass").getBytes()));
// execute & assert
ResultActions result = mvc.perform(post(URL).header("Authorization", basicAuth));
// assert
assertUnauthorized(result);
}
@Test
public void uploadEnrichmentTags_Unauthorized_InvalidPassword() throws Exception {
// given
String basicAuth = "Basic " + new String(Base64.encodeBase64((enricherLogin + ":invalidPassword").getBytes()));
// execute
ResultActions result = mvc.perform(post(URL).header("Authorization", basicAuth));
// assert
assertUnauthorized(result);
}
@Test
public void uploadEnrichmentTags_MethodNotAllowed() throws Exception {
// given
String basicAuth = "Basic " + new String(Base64.encodeBase64((enricherLogin + ":" + enricherPassword).getBytes()));
// execute
ResultActions result = mvc.perform(post(URL).header("Authorization", basicAuth));
// assert
assertError(result, HttpStatus.METHOD_NOT_ALLOWED, ERROR_UNSUPPORTED_HTTP_METHOD);
}
@Test
public void uploadEnrichmentTags_UnsupportedMediaType() throws Exception {
// given
String basicAuth = "Basic " + new String(Base64.encodeBase64((enricherLogin + ":" + enricherPassword).getBytes()));
// execute
ResultActions result = mvc.perform(put(URL).header("Authorization", basicAuth).contentType(MediaType.TEXT_PLAIN));
// assert
assertError(result, HttpStatus.UNSUPPORTED_MEDIA_TYPE, ERROR_UNSUPPORTED_HTTP_CONTENT_TYPE);
}
@Test
public void uploadEnrichmentTags_EmptyData_NoBody() throws Exception {
// given
String basicAuth = "Basic " + new String(Base64.encodeBase64((enricherLogin + ":" + enricherPassword).getBytes()));
// execute
ResultActions result = mvc.perform(put(URL).header("Authorization", basicAuth).contentType(MediaType.APPLICATION_JSON));
// assert
assertError(result, HttpStatus.BAD_REQUEST, ERROR_EMPTY_DATA);
}
@Test
public void uploadEnrichmentTags_EmptyData_EmptyBody() throws Exception {
// execute
ResultActions result = performPut("");
// assert
assertError(result, HttpStatus.BAD_REQUEST, ERROR_EMPTY_DATA);
}
@Test
public void uploadEnrichmentTags_InvalidJsonFormat_NoArrayTagAtTheBeginning() throws Exception {
// execute
ResultActions result = performPut(normalizeJson("{'xxx':'yyy'}"));
// assert
assertError(result, HttpStatus.BAD_REQUEST, ERROR_INVALID_JSON_FORMAT);
}
@Test
public void uploadEnrichmentTags_InvalidJsonFormat() throws Exception {
// execute
ResultActions result = performPut("[{\"'xxx\"'}]");
// assert
assertError(result, HttpStatus.BAD_REQUEST, ERROR_INVALID_JSON_FORMAT);
}
@Test
public void uploadEnrichmentTags_InvalidData_EmptyTagType() throws Exception {
// execute
ResultActions result = performPut("[" + createJsonTag(12, "", "{'caseNo':'1234'}") + "]");
// assert
assertError(result, HttpStatus.BAD_REQUEST, ERROR_INVALID_DATA);
}
@Test
public void uploadEnrichmentTags_InvalidData_NoJsonValue() throws Exception {
// execute
ResultActions result = performPut("[" + createJsonTag(12, "", "'YYY'") + "]");
// assert
assertError(result, HttpStatus.BAD_REQUEST, ERROR_INVALID_JSON_FORMAT);
}
@Test
public void uploadEnrichmentTags_MaxUploadSizeExceeded() throws Exception {
// given
long maxUploadSize = enrichmentTagUploadService.getEnrichmentTagMaxUploadSize();
enrichmentTagUploadService.setEnrichmentTagMaxUploadSize(10);
// execute
ResultActions result = performPut("[" + createJsonTag(12, "REFERENCED_REGULATIONS", "{'CCC':'YYY'}") + "]");
enrichmentTagUploadService.setEnrichmentTagMaxUploadSize(maxUploadSize);
// assert
assertError(result, HttpStatus.REQUEST_ENTITY_TOO_LARGE, ERROR_MAX_UPLOAD_SIZE_EXCEEDED);
}
@Test
public void uploadEnrichmentTags_SameTagAlreadyUploaded() throws Exception {
// execute
ResultActions result = performPut("[" + createJsonTag(12, "REFERENCED_REGULATIONS", "{'XXX':'YYY'}") + ","
+ createJsonTag(12, "REFERENCED_REGULATIONS", "{'ABC':'YYY'}") + "]");
// assert
assertError(result, HttpStatus.BAD_REQUEST, ERROR_SAME_TAG_ALREADY_UPLOADED);
assertEquals(0, enrichmentTagRepository.count());
assertEquals(0, uploadEnrichmentTagRepository.count());
}
@Test
public void uploadEnrichmentTags_InternalServerError() throws Exception {
// given
EnrichmentTagUploadService mockEnrichmentTagUploadService = mock(EnrichmentTagUploadService.class);
Mockito.doThrow(Exception.class).when(mockEnrichmentTagUploadService).uploadEnrichmentTags(Mockito.any(InputStream.class));
enrichmentTagUploadController.setEnrichmentTagUploadService(mockEnrichmentTagUploadService);
// execute
ResultActions result = performPut("[" + createJsonTag(12, "REFERENCED_REGULATIONS", "{'CCC':'YYY'}") + "]");
enrichmentTagUploadController.setEnrichmentTagUploadService(enrichmentTagUploadService);
// assert
assertError(result, HttpStatus.INTERNAL_SERVER_ERROR, EnrichmentTagUploadResponseMessages.ERROR_INTERVAL_SERVER_ERROR);
}
@Test
public void uploadEnrichmentTags_OK() throws Exception {
// given
Judgment ccJudgment = testPersistenceObjectFactory.createCcJudgment();
Judgment scJudgment = testPersistenceObjectFactory.createScJudgment();
String jsonValue1 = normalizeJson("{'XXX':'YYY'}");
String jsonValue2 = normalizeJson("{'caseNumbers':['YYY','xx-345']}");
String jsonValue3 = normalizeJson("{'caseNumbers':['YYY','xx-345','YYY-2222']}");
long nonExistingJudgmentId = scJudgment.getId() + ccJudgment.getId();
// execute
ResultActions result = performPut("[" + createJsonTag(ccJudgment.getId(), "REFERENCED_REGULATIONS", jsonValue1) + ","
+ createJsonTag(ccJudgment.getId(), "REFERENCED_CASE_NUMBERS", jsonValue2) + ","
+ createJsonTag(nonExistingJudgmentId, "REFERENCED_CASE_NUMBERS", jsonValue2) + "," // non-existing judgment shouldn't ne copied to production tags,
+ createJsonTag(scJudgment.getId(), "REFERENCED_CASE_NUMBERS", jsonValue3) + "]");
// assert
assertOk(result);
assertEquals(4, uploadEnrichmentTagRepository.count());
Thread.sleep(700);
assertEquals(3, enrichmentTagRepository.count());
EnrichmentTag expectedEnrichmentTag1 = createEnrichmentTag(ccJudgment.getId(), "REFERENCED_REGULATIONS", jsonValue1);
EnrichmentTag expectedEnrichmentTag2 = createEnrichmentTag(ccJudgment.getId(), "REFERENCED_CASE_NUMBERS", jsonValue2);
EnrichmentTag expectedEnrichmentTag3 = createEnrichmentTag(scJudgment.getId(), "REFERENCED_CASE_NUMBERS", jsonValue3);
assertThat(enrichmentTagRepository.findAll(), containsInAnyOrder(expectedEnrichmentTag1, expectedEnrichmentTag2, expectedEnrichmentTag3));
verify(jobForcingExecutor).forceStartNewJob(JobName.TAG_POST_UPLOAD_PROCESSING);
}
@Test
public void uploadEnrichmentTags_OK_Twice() throws Exception { // checks if old tags are deleted and no constraint violation ex happens
//---------- FIRST TIME ----------
// given
Judgment ccJudgment = testPersistenceObjectFactory.createCcJudgment();
String jsonValue1 = normalizeJson("{'XXX':'YYY'}");
String jsonValue2 = normalizeJson("{'caseNumbers':['YYY','xx-345']}");
// execute
ResultActions result = performPut("[" + createJsonTag(ccJudgment.getId(), "REFERENCED_REGULATIONS", jsonValue1) + ","
+ createJsonTag(ccJudgment.getId(), "REFERENCED_CASE_NUMBERS", jsonValue2) + "]");
// assert
assertOk(result);
assertEquals(2, uploadEnrichmentTagRepository.count());
Thread.sleep(700);
assertEquals(2, enrichmentTagRepository.count());
EnrichmentTag expectedEnrichmentTag1 = createEnrichmentTag(ccJudgment.getId(), "REFERENCED_REGULATIONS", jsonValue1);
EnrichmentTag expectedEnrichmentTag2 = createEnrichmentTag(ccJudgment.getId(), "REFERENCED_CASE_NUMBERS", jsonValue2);
assertThat(enrichmentTagRepository.findAll(), containsInAnyOrder(expectedEnrichmentTag1, expectedEnrichmentTag2));
verify(jobForcingExecutor, times(1)).forceStartNewJob(JobName.TAG_POST_UPLOAD_PROCESSING);
//---------- SECOND TIME ----------
// given
jsonValue1 = normalizeJson("{'XXX':'YYZ'}");
// execute
result = performPut("[" + createJsonTag(ccJudgment.getId(), "REFERENCED_REGULATIONS", jsonValue1) + "]");
// assert
assertOk(result);
assertEquals(1, uploadEnrichmentTagRepository.count());
Thread.sleep(700);
assertEquals(1, enrichmentTagRepository.count());
expectedEnrichmentTag1 = createEnrichmentTag(ccJudgment.getId(), "REFERENCED_REGULATIONS", jsonValue1);
assertThat(enrichmentTagRepository.findAll(), containsInAnyOrder(expectedEnrichmentTag1));
verify(jobForcingExecutor, times(2)).forceStartNewJob(JobName.TAG_POST_UPLOAD_PROCESSING);
}
// ------------------------ PRIVATE --------------------------
private void assertUnauthorized(ResultActions result) throws Exception {
assertError(result, HttpStatus.UNAUTHORIZED, ERROR_AUTHENTICATION_FAILED);
}
private void assertError(ResultActions result, HttpStatus httpStatus, String enrichmentTagUploadResponseMessage) throws Exception {
result.andExpect(status().is(httpStatus.value()))
.andExpect(header().string("content-type", Matchers.containsString("application/json")))
.andExpect(jsonPath("$.status").value(ServiceExecutionStatus.ERROR.name()))
.andExpect(jsonPath("$.message").value(enrichmentTagUploadResponseMessage)).andDo(print());
}
private void assertOk(ResultActions result) throws Exception {
result.andExpect(status()
.isOk())
.andExpect(header().string("content-type", Matchers.containsString("application/json")))
.andExpect(jsonPath("$.status").value(ServiceExecutionStatus.OK.name()))
.andExpect(jsonPath("$.message").value(OK_MESSAGE))
.andDo(print());
}
private ResultActions performPut(String content) throws Exception {
String basicAuth = "Basic " + new String(Base64.encodeBase64((enricherLogin + ":" + enricherPassword).getBytes()));
return mvc.perform(put(URL).header("Authorization", basicAuth).contentType(MediaType.APPLICATION_JSON).content(content.getBytes()));
}
private String createJsonTag(long judgmentId, String tagType, String jsonValue) {
String jsonTag = "{'judgmentId':'" + judgmentId + "'," + " 'tagType':'" + tagType + "'," + " 'value':" + jsonValue + "}";
return normalizeJson(jsonTag);
}
private EnrichmentTag createEnrichmentTag(long judgmentId, String tagType, String tagValue) {
EnrichmentTag enrichmentTag = new EnrichmentTag();
enrichmentTag.setJudgmentId(judgmentId);
enrichmentTag.setTagType(tagType);
enrichmentTag.setValue(tagValue);
return enrichmentTag;
}
}