package ca.intelliware.ihtsdo.mlds.repository;
import static org.hamcrest.Matchers.contains;
import static org.hamcrest.Matchers.containsInAnyOrder;
import static org.hamcrest.Matchers.is;
import static org.junit.Assert.assertThat;
import java.util.List;
import java.util.Random;
import javax.annotation.Resource;
import javax.persistence.EntityManager;
import javax.transaction.Transactional;
import org.hibernate.search.jpa.FullTextEntityManager;
import org.hibernate.search.jpa.Search;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.boot.test.SpringApplicationConfiguration;
import org.springframework.data.domain.PageRequest;
import org.springframework.test.context.ActiveProfiles;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.test.context.web.WebAppConfiguration;
import ca.intelliware.ihtsdo.mlds.Application;
import ca.intelliware.ihtsdo.mlds.domain.Affiliate;
import ca.intelliware.ihtsdo.mlds.domain.AffiliateDetails;
import ca.intelliware.ihtsdo.mlds.domain.Country;
import ca.intelliware.ihtsdo.mlds.domain.MailingAddress;
import ca.intelliware.ihtsdo.mlds.domain.Member;
import ca.intelliware.ihtsdo.mlds.domain.StandingState;
import ca.intelliware.ihtsdo.mlds.search.AngularTranslateServiceSetup;
import com.google.common.collect.Lists;
@RunWith(SpringJUnit4ClassRunner.class)
@SpringApplicationConfiguration(classes = Application.class)
@WebAppConfiguration
@ActiveProfiles("dev")
@Transactional
public class AffiliateFullTextSearchTest {
@Resource EntityManager entityManager;
@Resource AffiliateRepository affiliateRepository;
@Resource AffiliateSearchRepository affiliateSearchRepository;
@Resource MemberRepository memberRepository;
@Resource CountryRepository countryRepository;
Random random = new Random();
List<Affiliate> affiliates = Lists.newArrayList();
Member ihtsdo;
Member sweden;
@Before
public void setUp() {
ihtsdo = memberRepository.findOneByKey(Member.KEY_IHTSDO);
sweden = memberRepository.findOneByKey("SE");
for (int i = 0; i < 10; i++) {
affiliates.add(makeAffiliate());
}
}
@Before
public void setupTranslations() {
new AngularTranslateServiceSetup().setup();
}
@Test
public void findAffiliateByFirstName() throws Exception {
long ourInstance = System.currentTimeMillis();
String targetFirstName = "FirstNameTestValue" + ourInstance;
affiliates.get(3).getAffiliateDetails().setFirstName(targetFirstName);
affiliates.get(5).getAffiliateDetails().setFirstName(targetFirstName);
flush();
List<Affiliate> resultList = search(targetFirstName);
assertThat(resultList.size(), is(2));
assertThat(resultList, containsInAnyOrder(affiliates.get(3), affiliates.get(5)));
}
/**
* Make sure that our "ALL" fields is being populated so we can search across multiple fields.
* @throws Exception
*/
@Test
public void findAffiliateByFirstAndLastNameBestMatchFirst() throws Exception {
long ourInstance = System.currentTimeMillis();
String targetFirstName = "FirstNameTestValue" + ourInstance;
String targetLastName = "LastNameTestValue" + ourInstance;
affiliates.get(3).getAffiliateDetails().setFirstName(targetFirstName);
affiliates.get(3).getAffiliateDetails().setLastName(targetLastName);
affiliates.get(5).getAffiliateDetails().setFirstName(targetFirstName);
flush();
List<Affiliate> resultList = search(targetFirstName + " " + targetLastName);
assertThat(resultList.size(), is(2));
assertThat(resultList, contains(affiliates.get(3),affiliates.get(5)));
}
@Test
public void findAffiliateByPartialName() throws Exception {
long ourInstance = System.currentTimeMillis();
String targetFirstName = "ZZFirstNameTestValue" + ourInstance;
affiliates.get(4).getAffiliateDetails().setFirstName(targetFirstName);
flush();
List<Affiliate> resultList = search("ZZFirst");
assertThat(resultList.size(), is(1));
assertThat(resultList, contains(affiliates.get(4)));
}
@Test
public void findAffiliateByMultiplePartialMatches() throws Exception {
long ourInstance = System.currentTimeMillis();
String targetFirstName = "ZZFirstNameTestValue" + ourInstance;
String targetLastName = "ZZLastNameTestValue" + ourInstance;
affiliates.get(4).getAffiliateDetails().setFirstName(targetFirstName);
affiliates.get(4).getAffiliateDetails().setLastName(targetLastName);
flush();
List<Affiliate> resultList = search("ZZFirst ZZLast");
assertThat(resultList.size(), is(1));
assertThat(resultList, contains(affiliates.get(4)));
}
@Test
public void findAffiliateByCountryCommonName() throws Exception {
Country country = new Country("ZZ","ZZZ","ZZZimba");
countryRepository.save(country);
affiliates.get(4).getAffiliateDetails().getAddress().setCountry(country);
flush();
List<Affiliate> resultList = search("ZZZimba");
assertThat(resultList.size(), is(1));
assertThat(resultList, contains(affiliates.get(4)));
}
@Test
public void findAffiliateByEmailDomain() throws Exception {
affiliates.get(4).getAffiliateDetails().setEmail("fred22@exampleZZZ.com");
flush();
List<Affiliate> resultList = search("exampleZZZ.com");
assertThat(resultList.size(), is(1));
assertThat(resultList, contains(affiliates.get(4)));
}
@Test
public void findAffiliateByEmailAddress() throws Exception {
affiliates.get(4).getAffiliateDetails().setEmail("fred22@exampleZZZ.com");
flush();
List<Affiliate> resultList = search("fred22@exampleZZZ.com");
assertThat(resultList.size(), is(1));
assertThat(resultList, contains(affiliates.get(4)));
}
@Test
public void findByNameWithinMatchingMemberOnlyShowsNameMatches() throws Exception {
affiliates.get(4).getAffiliateDetails().setEmail("fred22@exampleZZZ.com");
flush();
List<Affiliate> resultList = search("fred22@exampleZZZ.com", ihtsdo, null, false);
assertThat(resultList.size(), is(1));
assertThat(resultList, contains(affiliates.get(4)));
}
@Test
public void findAffiliateByStandingState() throws Exception {
affiliates.get(3).setStandingState(StandingState.APPLYING);
affiliates.get(5).setStandingState(StandingState.APPLYING);
flush();
List<Affiliate> resultList = search("firstName", null, StandingState.APPLYING, false);
assertThat(resultList.size(), is(2));
assertThat(resultList, containsInAnyOrder(affiliates.get(3), affiliates.get(5)));
}
@Test
public void findAffiliateByStandingStateNot() throws Exception {
affiliates.get(3).setStandingState(StandingState.APPLYING);
affiliates.get(5).setStandingState(StandingState.APPLYING);
flush();
List<Affiliate> resultList = search("firstName", null, StandingState.IN_GOOD_STANDING, true);
assertThat(resultList.size(), is(2));
assertThat(resultList, containsInAnyOrder(affiliates.get(3), affiliates.get(5)));
}
@Test
public void findAffiliateByHomeMember() throws Exception {
affiliates.get(3).setHomeMember(sweden);
affiliates.get(5).setHomeMember(sweden);
flush();
List<Affiliate> resultList = search("firstName", sweden, null, false);
assertThat(resultList.size(), is(2));
assertThat(resultList, containsInAnyOrder(affiliates.get(3), affiliates.get(5)));
}
/**
* flush to JPA + Lucene. JPA queries trigger a JPA flush, but Hibernate Search
* only flushes on TX commit by default. But are using a TX rollback test strategy, so we
* need to flush Lucene manually.
*/
private void flush() {
entityManager.flush();
FullTextEntityManager fullTextEntityManager = Search.getFullTextEntityManager(entityManager);
fullTextEntityManager.flushToIndexes();
}
private List<Affiliate> search(String query) {
return search(query, null, null, false);
}
private List<Affiliate> search(String query, Member member, StandingState standingState, boolean standingStateNot) {
List<Affiliate> resultList = affiliateSearchRepository.findFullTextAndMember(query.toLowerCase(),member,standingState,standingStateNot,new PageRequest(0, 50)).getContent();
return resultList;
}
Affiliate makeAffiliate() {
Affiliate affiliate = new Affiliate();
affiliate.setAffiliateDetails(new AffiliateDetails());
affiliate.getAffiliateDetails().setFirstName(randomString("firstName"));;
affiliate.getAffiliateDetails().setLastName(randomString("lastName"));;
affiliate.getAffiliateDetails().setAddress(new MailingAddress());
affiliate.setHomeMember(ihtsdo);
affiliate.setStandingState(StandingState.IN_GOOD_STANDING);
entityManager.persist(affiliate.getAffiliateDetails());
affiliateRepository.save(affiliate);
return affiliate;
}
private String randomString(String prefix) {
return prefix + random.nextLong();
}
}