/*
* Copyright 2016 Hewlett-Packard Development Company, L.P.
* Licensed under the MIT License (the "License"); you may not use this file except in compliance with the License.
*/
package com.hp.autonomy.frontend.find.core.savedsearches.query;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.datatype.joda.JodaModule;
import com.hp.autonomy.frontend.find.core.savedsearches.ConceptClusterPhrase;
import com.hp.autonomy.frontend.find.core.savedsearches.EmbeddableIndex;
import com.hp.autonomy.frontend.find.core.savedsearches.UserEntity;
import com.hp.autonomy.frontend.find.core.test.AbstractFindIT;
import com.hp.autonomy.frontend.find.core.test.MvcIntegrationTestUtils;
import org.apache.commons.io.IOUtils;
import org.joda.time.DateTime;
import org.junit.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.core.io.Resource;
import org.springframework.http.MediaType;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.test.jdbc.JdbcTestUtils;
import org.springframework.test.web.servlet.MvcResult;
import org.springframework.test.web.servlet.ResultActions;
import org.springframework.test.web.servlet.request.MockHttpServletRequestBuilder;
import javax.annotation.PostConstruct;
import javax.sql.DataSource;
import java.util.Collections;
import java.util.HashSet;
import java.util.Set;
import static com.hp.autonomy.frontend.find.core.savedsearches.query.SavedQueryController.NEW_RESULTS_PATH;
import static org.hamcrest.CoreMatchers.equalTo;
import static org.hamcrest.CoreMatchers.is;
import static org.hamcrest.CoreMatchers.not;
import static org.hamcrest.CoreMatchers.nullValue;
import static org.hamcrest.Matchers.*;
import static org.hamcrest.collection.IsEmptyCollection.empty;
import static org.hamcrest.core.Is.isA;
import static org.junit.Assert.*;
import static org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestPostProcessors.authentication;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.*;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*;
public abstract class AbstractSavedQueryIT extends AbstractFindIT {
private static final TypeReference<Set<SavedQuery>> LIST_TYPE_REFERENCE = new TypeReference<Set<SavedQuery>>() {};
private static final String TITLE = "Any old saved search";
private static final String PRIMARY_PHRASE = "manhattan";
private static final String OTHER_PHRASE = "mid-town";
private static final Integer MIN_SCORE = 88;
private final ObjectMapper mapper = new ObjectMapper();
@SuppressWarnings("SpringJavaAutowiredMembersInspection")
@Autowired
protected DataSource dataSource;
@SuppressWarnings("SpringJavaAutowiredMembersInspection")
@Autowired
protected MvcIntegrationTestUtils integrationTestUtils;
@Value("classpath:save-query-request.json")
private Resource saveQueryRequestResource;
private JdbcTemplate jdbcTemplate;
protected AbstractSavedQueryIT() {
mapper.registerModule(new JodaModule());
}
@PostConstruct
public void initialise() {
jdbcTemplate = new JdbcTemplate(dataSource);
}
@Test
public void create() throws Exception {
createSavedQuery(getBaseSavedQuery())
.andExpect(status().isOk())
.andExpect(content().contentType(MediaType.APPLICATION_JSON_UTF8))
.andExpect(jsonPath("$.id", not(nullValue())))
.andExpect(jsonPath("$.title", equalTo(TITLE)))
.andExpect(jsonPath("$.minScore", equalTo(MIN_SCORE)))
.andExpect(jsonPath("$.conceptClusterPhrases", hasSize(2)))
.andExpect(jsonPath("$.conceptClusterPhrases[*].phrase", containsInAnyOrder(PRIMARY_PHRASE, OTHER_PHRASE)))
.andExpect(jsonPath("$.conceptClusterPhrases[?(@.phrase=='" + PRIMARY_PHRASE + "')].primary", contains(true)))
.andExpect(jsonPath("$.conceptClusterPhrases[?(@.phrase== '" + PRIMARY_PHRASE + "')].clusterId", contains(0)))
.andExpect(jsonPath("$.conceptClusterPhrases[?(@.phrase== '" + OTHER_PHRASE + "')].primary", contains(false)))
.andExpect(jsonPath("$.conceptClusterPhrases[?(@.phrase=='" + OTHER_PHRASE + "')].clusterId", contains(0)));
}
@Test
public void update() throws Exception {
final SavedQuery createdEntity = createAndParseSavedQuery(getBaseSavedQuery());
final String updatedPhrase = "jersey";
final Set<ConceptClusterPhrase> conceptClusterPhrases = new HashSet<>();
conceptClusterPhrases.add(new ConceptClusterPhrase(updatedPhrase, true, 1));
final Integer updatedMinScore = 99;
final SavedQuery updatedQuery = new SavedQuery.Builder()
.setMinScore(updatedMinScore)
.setConceptClusterPhrases(conceptClusterPhrases)
.build();
final MockHttpServletRequestBuilder requestBuilder = put(SavedQueryController.PATH + '/' + createdEntity.getId())
.with(authentication(biAuth()))
.content(mapper.writeValueAsString(updatedQuery))
.contentType(MediaType.APPLICATION_JSON);
mockMvc.perform(requestBuilder)
.andExpect(status().isOk())
.andExpect(content().contentType(MediaType.APPLICATION_JSON_UTF8))
.andExpect(jsonPath("$.id", is(createdEntity.getId().intValue())))
.andExpect(jsonPath("$.minScore", equalTo(updatedMinScore)))
.andExpect(jsonPath("$.conceptClusterPhrases", hasSize(1)))
.andExpect(jsonPath("$.conceptClusterPhrases[*].phrase", contains(updatedPhrase)))
.andExpect(jsonPath("$.conceptClusterPhrases[?(@.phrase=='" + updatedPhrase + "')].primary", contains(true)))
.andExpect(jsonPath("$.conceptClusterPhrases[?(@.phrase== '" + updatedPhrase + "')].clusterId", contains(1)));
}
@Test
public void createAndFetch() throws Exception {
final byte[] requestBytes = IOUtils.toByteArray(saveQueryRequestResource.getInputStream());
final MockHttpServletRequestBuilder requestBuilder = post(SavedQueryController.PATH + '/')
.content(requestBytes)
.contentType(MediaType.APPLICATION_JSON)
.with(authentication(biAuth()));
final MvcResult createResult = mockMvc.perform(requestBuilder)
.andReturn();
final JsonNode responseTree = mapper.readTree(createResult.getResponse().getContentAsString());
final int id = responseTree.get("id").asInt();
listSavedQueries()
.andExpect(status().isOk())
.andExpect(content().contentType(MediaType.APPLICATION_JSON_UTF8))
.andExpect(jsonPath("$[0].id", is(id)))
.andExpect(jsonPath("$[0].title", is("\u30e2\u30f3\u30ad\u30fc")))
.andExpect(jsonPath("$[0].minDate", is(1400000000)))
.andExpect(jsonPath("$[0].maxDate", is(1500000000)))
.andExpect(jsonPath("$[0].conceptClusterPhrases", hasSize(3)))
.andExpect(jsonPath("$[0].conceptClusterPhrases[*].phrase", containsInAnyOrder("characters", "faces", "animals")))
.andExpect(jsonPath("$[0].conceptClusterPhrases[?(@.phrase=='characters')].primary", contains(true)))
.andExpect(jsonPath("$[0].conceptClusterPhrases[?(@.phrase=='characters')].clusterId", contains(1)))
.andExpect(jsonPath("$[0].conceptClusterPhrases[?(@.phrase=='faces')].primary", contains(false)))
.andExpect(jsonPath("$[0].conceptClusterPhrases[?(@.phrase=='faces')].clusterId", contains(1)))
.andExpect(jsonPath("$[0].conceptClusterPhrases[?(@.phrase=='animals')].primary", contains(true)))
.andExpect(jsonPath("$[0].conceptClusterPhrases[?(@.phrase=='animals')].clusterId", contains(2)))
.andExpect(jsonPath("$[0].parametricValues", hasSize(1)))
.andExpect(jsonPath("$[0].parametricValues[0].field", is("CATEGORY")))
.andExpect(jsonPath("$[0].parametricValues[0].value", is("COMPUTING")))
.andExpect(jsonPath("$[0].parametricRanges", hasSize(1)))
.andExpect(jsonPath("$[0].parametricRanges[0].field", is("SOME_DATE")))
.andExpect(jsonPath("$[0].parametricRanges[0].min", is(123456789d)))
.andExpect(jsonPath("$[0].parametricRanges[0].max", is(123456791d)))
.andExpect(jsonPath("$[0].parametricRanges[0].type", is("Date")))
.andExpect(jsonPath("$[0].indexes", hasSize(2)))
.andExpect(jsonPath("$[0].indexes[*].name", containsInAnyOrder("English Wikipedia", "\u65e5\u672c\u8a9e Wikipedia")))
.andExpect(jsonPath("$[0].indexes[?(@.name=='English Wikipedia')].domain", contains("MY_DOMAIN")))
.andExpect(jsonPath("$[0].indexes[?(@.name=='\u65e5\u672c\u8a9e Wikipedia')].domain", contains("MY_DOMAIN")));
}
@Test
public void deleteById() throws Exception {
final SavedQuery createdEntity = createAndParseSavedQuery(getBaseSavedQuery());
final MockHttpServletRequestBuilder requestBuilder = delete(SavedQueryController.PATH + '/' + createdEntity.getId())
.contentType(MediaType.APPLICATION_JSON)
.with(authentication(biAuth()));
mockMvc.perform(requestBuilder).andExpect(status().isOk());
final Set<SavedQuery> queries = listAndParseSavedQueries();
assertThat(queries, is(empty()));
}
@Test
public void getAllReturnsNothing() throws Exception {
assertThat(listAndParseSavedQueries(), is(empty()));
}
@Test
public void basicUserNotAuthorised() throws Exception {
mockMvc.perform(get(SavedQueryController.PATH).with(authentication(userAuth())))
.andExpect(status().is(403));
}
@Test
public void checkTimeAuditDataInsertedUpdated() throws Exception {
final SavedQuery inputSavedQuery = new SavedQuery.Builder()
.setTitle("title")
.setMinScore(0)
.build();
final SavedQuery savedQuery = createAndParseSavedQuery(inputSavedQuery);
assertNotNull(savedQuery.getId());
assertThat(savedQuery.getDateCreated(), isA(DateTime.class));
assertThat(savedQuery.getDateModified(), isA(DateTime.class));
assertTrue(savedQuery.getDateCreated().isEqual(savedQuery.getDateModified().toInstant()));
// Safe to assume completed in an hour
// TODO: mock out the datetime service used by spring auditing to check this properly
assertTrue(savedQuery.getDateCreated().plusHours(1).isAfterNow());
savedQuery.setConceptClusterPhrases(Collections.singleton(new ConceptClusterPhrase("*", true, -1)));
final SavedQuery savedQueryUpdate = new SavedQuery.Builder()
.setId(savedQuery.getId())
.setTitle("new title")
.setMinScore(0)
.build();
final SavedQuery updatedSavedQuery = updateAndParseSavedQuery(savedQueryUpdate);
assertThat(updatedSavedQuery.getDateCreated(), isA(DateTime.class));
assertThat(updatedSavedQuery.getDateModified(), isA(DateTime.class));
assertTrue(updatedSavedQuery.getDateModified().isAfter(savedQuery.getDateCreated().toInstant()));
}
@Test
public void checkUserNotDuplicated() throws Exception {
final SavedQuery savedQuery1 = new SavedQuery.Builder()
.setTitle("title1")
.setMinScore(0)
.build();
final SavedQuery savedQuery2 = new SavedQuery.Builder()
.setTitle("title2")
.setMinScore(0)
.build();
createSavedQuery(savedQuery1);
createSavedQuery(savedQuery2);
final int userRows = JdbcTestUtils.countRowsInTable(jdbcTemplate, "find." + UserEntity.Table.NAME);
assertThat(userRows, is(1));
}
@Test
public void checkForNewQueryResults() throws Exception {
final Set<EmbeddableIndex> indexes = Collections.singleton(integrationTestUtils.getEmbeddableIndex());
final SavedQuery saveRequest1 = new SavedQuery.Builder()
.setTitle("title1")
.setMinScore(0)
.setIndexes(indexes)
.setConceptClusterPhrases(Collections.singleton(new ConceptClusterPhrase("*", true, -1)))
.build();
final SavedQuery saveRequest2 = new SavedQuery.Builder()
.setDateDocsLastFetched(DateTime.now())
.setTitle("title2")
.setMinScore(0)
.setIndexes(indexes)
.setConceptClusterPhrases(Collections.singleton(new ConceptClusterPhrase("*", true, -1)))
.build();
final SavedQuery savedQuery1 = createAndParseSavedQuery(saveRequest1);
final long id1 = savedQuery1.getId();
final SavedQuery savedQuery2 = createAndParseSavedQuery(saveRequest2);
final long id2 = savedQuery2.getId();
mockMvc.perform(get(SavedQueryController.PATH + NEW_RESULTS_PATH + id1).with(authentication(biAuth())))
.andExpect(status().isOk())
.andExpect(content().contentType(MediaType.APPLICATION_JSON_UTF8))
.andExpect(jsonPath("$", greaterThan(0)));
mockMvc.perform(get(SavedQueryController.PATH + NEW_RESULTS_PATH + id2).with(authentication(biAuth())))
.andExpect(status().isOk())
.andExpect(content().contentType(MediaType.APPLICATION_JSON_UTF8))
.andExpect(jsonPath("$", is(0))); // likely to work though not full-proof
}
private ResultActions createSavedQuery(final SavedQuery savedQuery) throws Exception {
final MockHttpServletRequestBuilder requestBuilder = post(SavedQueryController.PATH + '/')
.content(mapper.writeValueAsString(savedQuery))
.contentType(MediaType.APPLICATION_JSON)
.with(authentication(biAuth()));
return mockMvc.perform(requestBuilder);
}
private SavedQuery createAndParseSavedQuery(final SavedQuery savedQuery) throws Exception {
final MvcResult mvcResult = createSavedQuery(savedQuery).andReturn();
final String response = mvcResult.getResponse().getContentAsString();
return mapper.readValue(response, SavedQuery.class);
}
private SavedQuery updateAndParseSavedQuery(final SavedQuery update) throws Exception {
final MockHttpServletRequestBuilder requestBuilder = put(SavedQueryController.PATH + '/' + update.getId())
.content(mapper.writeValueAsString(update))
.contentType(MediaType.APPLICATION_JSON)
.with(authentication(biAuth()));
final MvcResult mvcResult = mockMvc.perform(requestBuilder).andReturn();
final String response = mvcResult.getResponse().getContentAsString();
return mapper.readValue(response, SavedQuery.class);
}
private ResultActions listSavedQueries() throws Exception {
return mockMvc.perform(get(SavedQueryController.PATH).with(authentication(biAuth())));
}
private Set<SavedQuery> listAndParseSavedQueries() throws Exception {
final MvcResult listResult = listSavedQueries()
.andExpect(status().isOk())
.andReturn();
return mapper.readValue(listResult.getResponse().getContentAsString(), LIST_TYPE_REFERENCE);
}
private Set<ConceptClusterPhrase> getBaseConceptClusterPhrases() {
final Set<ConceptClusterPhrase> conceptClusterPhrases = new HashSet<>();
final ConceptClusterPhrase manhattanClusterPhraseOne = new ConceptClusterPhrase(PRIMARY_PHRASE, true, 0);
final ConceptClusterPhrase manhattanClusterPhraseTwo = new ConceptClusterPhrase(OTHER_PHRASE, false, 0);
conceptClusterPhrases.add(manhattanClusterPhraseOne);
conceptClusterPhrases.add(manhattanClusterPhraseTwo);
return conceptClusterPhrases;
}
private SavedQuery getBaseSavedQuery() {
return new SavedQuery.Builder()
.setTitle(TITLE)
.setMinScore(MIN_SCORE)
.setConceptClusterPhrases(getBaseConceptClusterPhrases())
.build();
}
}