/*
* Copyright 2012-2017 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.data.solr.core;
import static org.mockito.Mockito.*;
import java.io.IOException;
import java.util.Arrays;
import java.util.Collections;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import org.apache.http.ParseException;
import org.apache.solr.client.solrj.SolrClient;
import org.apache.solr.client.solrj.SolrQuery;
import org.apache.solr.client.solrj.SolrRequest;
import org.apache.solr.client.solrj.SolrServerException;
import org.apache.solr.client.solrj.request.schema.SchemaRequest;
import org.apache.solr.client.solrj.request.schema.SchemaRequest.SchemaVersion;
import org.apache.solr.client.solrj.response.QueryResponse;
import org.apache.solr.client.solrj.response.SolrPingResponse;
import org.apache.solr.client.solrj.response.UpdateResponse;
import org.apache.solr.common.SolrDocumentList;
import org.apache.solr.common.SolrException;
import org.apache.solr.common.SolrException.ErrorCode;
import org.apache.solr.common.SolrInputDocument;
import org.apache.solr.common.params.CommonParams;
import org.apache.solr.common.params.SolrParams;
import org.apache.solr.common.util.NamedList;
import org.hamcrest.core.Is;
import org.hamcrest.core.IsEqual;
import org.hamcrest.core.IsNull;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.ArgumentCaptor;
import org.mockito.Mock;
import org.mockito.Mockito;
import org.mockito.junit.MockitoJUnitRunner;
import org.springframework.core.annotation.AnnotationUtils;
import org.springframework.core.convert.converter.Converter;
import org.springframework.dao.DataAccessException;
import org.springframework.dao.InvalidDataAccessApiUsageException;
import org.springframework.data.annotation.Id;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.solr.UncategorizedSolrException;
import org.springframework.data.solr.core.mapping.Indexed;
import org.springframework.data.solr.core.mapping.SolrDocument;
import org.springframework.data.solr.core.query.Criteria;
import org.springframework.data.solr.core.query.PartialUpdate;
import org.springframework.data.solr.core.query.Query;
import org.springframework.data.solr.core.query.SimpleQuery;
import org.springframework.data.solr.core.query.SimpleStringCriteria;
import org.springframework.data.solr.core.query.SolrDataQuery;
import org.springframework.data.solr.core.schema.SolrPersistentEntitySchemaCreator.Feature;
import org.springframework.data.solr.repository.Score;
import org.springframework.data.solr.server.SolrClientFactory;
/**
* @author Christoph Strobl
* @author Joachim Uhrlass
* @author Francisco Spaeth
*/
@RunWith(MockitoJUnitRunner.Silent.class)
public class SolrTemplateTests {
private SolrTemplate solrTemplate;
private static final SimpleJavaObject SIMPLE_OBJECT = new SimpleJavaObject("simple-string-id", 123l);
private static final SimpleBoostedJavaObject SIMPLE_BOOSTED_OBJECT = new SimpleBoostedJavaObject("simple-string-id",
123l, "simple-string-boost");
private static final SolrInputDocument SIMPLE_DOCUMENT = new SolrInputDocument();
private @Mock SolrClient solrClientMock;
@Before
public void setUp() {
solrTemplate = new SolrTemplate(solrClientMock);
solrTemplate.afterPropertiesSet();
}
@Test(expected = IllegalArgumentException.class)
public void testNullServerFactory() {
new SolrTemplate((SolrClientFactory) null);
}
@Test
public void testPing() throws SolrServerException, IOException {
Mockito.when(solrClientMock.ping()).thenReturn(new SolrPingResponse());
SolrPingResponse pingResult = solrTemplate.ping();
Assert.assertNotNull(pingResult);
Mockito.verify(solrClientMock, Mockito.times(1)).ping();
}
@Test(expected = DataAccessException.class)
public void testPingThrowsException() throws SolrServerException, IOException {
Mockito.when(solrClientMock.ping())
.thenThrow(new SolrServerException("error", new SolrException(ErrorCode.NOT_FOUND, "not found")));
solrTemplate.ping();
}
@Test(expected = InvalidDataAccessApiUsageException.class)
public void testQueryThrowsParseException() throws SolrServerException, IOException {
Mockito.when(solrClientMock.query(any(), Mockito.any(SolrParams.class), Mockito.eq(SolrRequest.METHOD.GET)))
.thenThrow(new SolrServerException("error",
new SolrException(ErrorCode.BAD_REQUEST, new ParseException("parse error"))));
solrTemplate.executeSolrQuery(new SolrQuery(), SolrRequest.METHOD.GET);
}
@Test(expected = UncategorizedSolrException.class)
public void testQueryThrowsUntranslateableException() throws SolrServerException, IOException {
Mockito.when(solrClientMock.query(any(), Mockito.any(SolrParams.class), Mockito.eq(SolrRequest.METHOD.GET)))
.thenThrow(new SecurityException());
solrTemplate.executeSolrQuery(new SolrQuery(), SolrRequest.METHOD.GET);
}
@Test
public void testSaveBean() throws IOException, SolrServerException {
Mockito.when(solrClientMock.add(Mockito.any(SolrInputDocument.class), Mockito.eq(-1)))
.thenReturn(new UpdateResponse());
UpdateResponse updateResponse = solrTemplate.saveBean(SIMPLE_OBJECT);
Assert.assertNotNull(updateResponse);
ArgumentCaptor<SolrInputDocument> captor = ArgumentCaptor.forClass(SolrInputDocument.class);
Mockito.verify(solrClientMock, Mockito.times(1)).add(captor.capture(), Mockito.eq(-1));
Assert.assertEquals(SIMPLE_OBJECT.getId(), captor.getValue().getFieldValue("id"));
Assert.assertEquals(SIMPLE_OBJECT.getValue(), captor.getValue().getFieldValue("value"));
}
@Test
public void testSaveBeanCommitWithin() throws IOException, SolrServerException {
Mockito.when(solrClientMock.add(Mockito.any(SolrInputDocument.class), Mockito.eq(10000)))
.thenReturn(new UpdateResponse());
UpdateResponse updateResponse = solrTemplate.saveBean(SIMPLE_OBJECT, 10000);
Assert.assertNotNull(updateResponse);
ArgumentCaptor<SolrInputDocument> captor = ArgumentCaptor.forClass(SolrInputDocument.class);
Mockito.verify(solrClientMock, Mockito.times(1)).add(captor.capture(), Mockito.eq(10000));
Assert.assertEquals(SIMPLE_OBJECT.getId(), captor.getValue().getFieldValue("id"));
Assert.assertEquals(SIMPLE_OBJECT.getValue(), captor.getValue().getFieldValue("value"));
}
@SuppressWarnings("unchecked")
@Test
public void testPartialUpdate() throws SolrServerException, IOException {
Mockito.when(solrClientMock.add(Mockito.any(SolrInputDocument.class), Mockito.eq(-1)))
.thenReturn(new UpdateResponse());
PartialUpdate update = new PartialUpdate("id", "update-id");
update.add("field_1", "update");
solrTemplate.saveBean(update);
ArgumentCaptor<SolrInputDocument> captor = ArgumentCaptor.forClass(SolrInputDocument.class);
Mockito.verify(solrClientMock, Mockito.times(1)).add(captor.capture(), Mockito.eq(-1));
Assert.assertTrue(captor.getValue().getFieldValue("field_1") instanceof Map);
Assert.assertEquals("update", ((Map<String, Object>) captor.getValue().getFieldValue("field_1")).get("set"));
}
@SuppressWarnings("unchecked")
@Test
public void testSaveBeans() throws IOException, SolrServerException {
Mockito.when(solrClientMock.add(Mockito.anyCollectionOf(SolrInputDocument.class), Mockito.eq(-1)))
.thenReturn(new UpdateResponse());
List<SimpleJavaObject> collection = Arrays.asList(new SimpleJavaObject("1", 1l), new SimpleJavaObject("2", 2l),
new SimpleJavaObject("3", 3l));
UpdateResponse updateResponse = solrTemplate.saveBeans(collection);
Assert.assertNotNull(updateResponse);
@SuppressWarnings("rawtypes")
ArgumentCaptor<List> captor = ArgumentCaptor.forClass(List.class);
Mockito.verify(solrClientMock, Mockito.times(1)).add(captor.capture(), Mockito.eq(-1));
Assert.assertEquals(3, captor.getValue().size());
}
@SuppressWarnings("unchecked")
@Test
public void testSaveBeansCommitWithin() throws IOException, SolrServerException {
Mockito.when(solrClientMock.add(Mockito.anyCollectionOf(SolrInputDocument.class), Mockito.eq(10000)))
.thenReturn(new UpdateResponse());
List<SimpleJavaObject> collection = Arrays.asList(new SimpleJavaObject("1", 1l), new SimpleJavaObject("2", 2l),
new SimpleJavaObject("3", 3l));
UpdateResponse updateResponse = solrTemplate.saveBeans(collection, 10000);
Assert.assertNotNull(updateResponse);
@SuppressWarnings("rawtypes")
ArgumentCaptor<List> captor = ArgumentCaptor.forClass(List.class);
Mockito.verify(solrClientMock, Mockito.times(1)).add(captor.capture(), Mockito.eq(10000));
Assert.assertEquals(3, captor.getValue().size());
}
@Test
public void testSaveDocument() throws IOException, SolrServerException {
Mockito.when(solrClientMock.add(Mockito.any(SolrInputDocument.class), Mockito.eq(-1)))
.thenReturn(new UpdateResponse());
UpdateResponse updateResponse = solrTemplate.saveDocument(SIMPLE_DOCUMENT);
Assert.assertNotNull(updateResponse);
Mockito.verify(solrClientMock, Mockito.times(1)).add(Mockito.eq(SIMPLE_DOCUMENT), Mockito.eq(-1));
}
@Test
public void testSaveDocumentCommitWithin() throws IOException, SolrServerException {
Mockito.when(solrClientMock.add(Mockito.any(SolrInputDocument.class), Mockito.eq(10000)))
.thenReturn(new UpdateResponse());
UpdateResponse updateResponse = solrTemplate.saveDocument(SIMPLE_DOCUMENT, 10000);
Assert.assertNotNull(updateResponse);
Mockito.verify(solrClientMock, Mockito.times(1)).add(Mockito.eq(SIMPLE_DOCUMENT), Mockito.eq(10000));
}
@Test
public void testSaveDocuments() throws IOException, SolrServerException {
Mockito.when(solrClientMock.add(Mockito.anyCollectionOf(SolrInputDocument.class), Mockito.eq(-1)))
.thenReturn(new UpdateResponse());
List<SolrInputDocument> collection = Collections.singletonList(SIMPLE_DOCUMENT);
UpdateResponse updateResponse = solrTemplate.saveDocuments(collection);
Assert.assertNotNull(updateResponse);
Mockito.verify(solrClientMock, Mockito.times(1)).add(Mockito.eq(collection), Mockito.eq(-1));
}
@Test
public void testSaveDocumentsCommitWithin() throws IOException, SolrServerException {
Mockito.when(solrClientMock.add(Mockito.anyCollectionOf(SolrInputDocument.class), Mockito.eq(10000)))
.thenReturn(new UpdateResponse());
List<SolrInputDocument> collection = Collections.singletonList(SIMPLE_DOCUMENT);
UpdateResponse updateResponse = solrTemplate.saveDocuments(collection, 10000);
Assert.assertNotNull(updateResponse);
Mockito.verify(solrClientMock, Mockito.times(1)).add(Mockito.eq(collection), Mockito.eq(10000));
}
@Test
public void testDeleteById() throws IOException, SolrServerException {
Mockito.when(solrClientMock.deleteById(Mockito.anyString())).thenReturn(new UpdateResponse());
UpdateResponse updateResponse = solrTemplate.deleteById("1");
Assert.assertNotNull(updateResponse);
Mockito.verify(solrClientMock, Mockito.times(1)).deleteById(Mockito.eq("1"));
}
@Test
public void testDeleteByIdWithCollection() throws IOException, SolrServerException {
Mockito.when(solrClientMock.deleteById(Mockito.anyListOf(String.class))).thenReturn(new UpdateResponse());
List<String> idsToDelete = Arrays.asList("1", "2");
UpdateResponse updateResponse = solrTemplate.deleteById(idsToDelete);
Assert.assertNotNull(updateResponse);
@SuppressWarnings("unchecked")
ArgumentCaptor<List<String>> captor = (ArgumentCaptor<List<String>>) (Object) ArgumentCaptor.forClass(List.class);
Mockito.verify(solrClientMock, Mockito.times(1)).deleteById(captor.capture());
Assert.assertEquals(idsToDelete.size(), captor.getValue().size());
for (String s : idsToDelete) {
Assert.assertTrue(captor.getValue().contains(s));
}
}
@Test
public void testCount() throws SolrServerException, IOException {
ArgumentCaptor<SolrQuery> captor = ArgumentCaptor.forClass(SolrQuery.class);
QueryResponse responseMock = Mockito.mock(QueryResponse.class);
SolrDocumentList resultList = new SolrDocumentList();
resultList.setNumFound(10);
Mockito.when(responseMock.getResults()).thenReturn(resultList);
Mockito.when(solrClientMock.query(Mockito.any(SolrQuery.class), Mockito.eq(SolrRequest.METHOD.GET)))
.thenReturn(responseMock);
long result = solrTemplate.count(new SimpleQuery(new Criteria("field_1").is("value1")));
Assert.assertEquals(resultList.getNumFound(), result);
Mockito.verify(solrClientMock, Mockito.times(1)).query(captor.capture(), Mockito.eq(SolrRequest.METHOD.GET));
Assert.assertEquals(Integer.valueOf(0), captor.getValue().getStart());
Assert.assertEquals(Integer.valueOf(0), captor.getValue().getRows());
}
@Test
public void testCountWhenPagingSet() throws SolrServerException, IOException {
ArgumentCaptor<SolrQuery> captor = ArgumentCaptor.forClass(SolrQuery.class);
QueryResponse responseMock = Mockito.mock(QueryResponse.class);
SolrDocumentList resultList = new SolrDocumentList();
resultList.setNumFound(10);
Mockito.when(responseMock.getResults()).thenReturn(resultList);
Mockito.when(solrClientMock.query(Mockito.any(SolrQuery.class), Mockito.eq(SolrRequest.METHOD.GET)))
.thenReturn(responseMock);
Query query = new SimpleQuery(new Criteria("field_1").is("value1"));
query.setPageRequest(new PageRequest(0, 5));
long result = solrTemplate.count(query);
Assert.assertEquals(resultList.getNumFound(), result);
Mockito.verify(solrClientMock, Mockito.times(1)).query(captor.capture(), Mockito.eq(SolrRequest.METHOD.GET));
Assert.assertEquals(Integer.valueOf(0), captor.getValue().getStart());
Assert.assertEquals(Integer.valueOf(0), captor.getValue().getRows());
}
@Test(expected = IllegalArgumentException.class)
public void testCountNullQuery() {
solrTemplate.count(null);
}
@Test
public void testCommit() throws SolrServerException, IOException {
solrTemplate.commit();
Mockito.verify(solrClientMock, Mockito.times(1)).commit();
}
@Test
public void testSoftCommit() throws SolrServerException, IOException {
solrTemplate.softCommit();
Mockito.verify(solrClientMock, Mockito.times(1)).commit(Mockito.eq(true), Mockito.eq(true), Mockito.eq(true));
}
@Test
public void testRollback() throws SolrServerException, IOException {
solrTemplate.rollback();
Mockito.verify(solrClientMock, Mockito.times(1)).rollback();
}
@Test
public void testDifferentQueryParser() throws SolrServerException, IOException {
QueryParser parser = new QueryParser() {
@Override
public void registerConverter(Converter<?, ?> converter) {}
@Override
public String getQueryString(SolrDataQuery query) {
return "*:*";
}
@Override
public SolrQuery constructSolrQuery(SolrDataQuery query) {
return new SolrQuery(getQueryString(query));
}
};
solrTemplate.registerQueryParser(SimpleQuery.class, parser);
solrTemplate.querySolr(new SimpleQuery(new SimpleStringCriteria("my:criteria")), null);
ArgumentCaptor<SolrParams> captor = ArgumentCaptor.forClass(SolrParams.class);
Mockito.verify(solrClientMock, Mockito.times(1)).query(nullable(String.class), captor.capture(),
Mockito.eq(SolrRequest.METHOD.GET));
Assert.assertEquals("*:*", captor.getValue().getParams(CommonParams.Q)[0]);
}
@Test // DATASOLR-88
public void testSaveBoostedShouldUseDocumentBoost()
throws IOException, SolrServerException, SecurityException, NoSuchFieldException {
solrTemplate.saveBean(SIMPLE_BOOSTED_OBJECT);
ArgumentCaptor<SolrInputDocument> captor = ArgumentCaptor.forClass(SolrInputDocument.class);
Mockito.verify(solrClientMock, Mockito.times(1)).add(captor.capture(), Mockito.eq(-1));
Assert.assertEquals(SIMPLE_BOOSTED_OBJECT.getId(), captor.getValue().getFieldValue("id"));
Assert.assertEquals(SIMPLE_BOOSTED_OBJECT.getValue(), captor.getValue().getFieldValue("value"));
float entityBoost = AnnotationUtils.getAnnotation(SIMPLE_BOOSTED_OBJECT.getClass(), SolrDocument.class).boost();
Assert.assertThat(captor.getValue().getDocumentBoost(), Is.is(entityBoost));
}
@Test // DATASOLR-88
public void testSaveBoostedShouldUseFieldBoostViaIndexedAnnotation()
throws IOException, SolrServerException, SecurityException, NoSuchFieldException {
solrTemplate.saveBean(SIMPLE_BOOSTED_OBJECT);
ArgumentCaptor<SolrInputDocument> captor = ArgumentCaptor.forClass(SolrInputDocument.class);
Mockito.verify(solrClientMock, Mockito.times(1)).add(captor.capture(), Mockito.eq(-1));
Assert.assertEquals(SIMPLE_BOOSTED_OBJECT.getId(), captor.getValue().getFieldValue("id"));
Assert.assertEquals(SIMPLE_BOOSTED_OBJECT.getValue(), captor.getValue().getFieldValue("value"));
float fieldBoost = AnnotationUtils
.getAnnotation(SIMPLE_BOOSTED_OBJECT.getClass().getDeclaredField("boostedField"), Indexed.class).boost();
Assert.assertThat(captor.getValue().getField("boostedField").getBoost(), Is.is(fieldBoost));
}
@Test // DATASOLR-72, DATASOLR-313, DATASOLR-309
public void schemaShouldBeUpdatedPriorToSavingEntity() throws SolrServerException, IOException {
NamedList<Object> nl = new NamedList<>();
Map<String, Object> schema = new LinkedHashMap<>();
nl.add("version", 1.5F);
nl.add("schema", schema);
schema.put("version", 1.5F);
schema.put("name", "mock");
schema.put("fields", Collections.<NamedList<Object>> emptyList());
schema.put("dynamicFields", Collections.<NamedList<Object>> emptyList());
schema.put("fieldTypes", Collections.<NamedList<Object>> emptyList());
schema.put("copyFields", Collections.<NamedList<Object>> emptyList());
// schema.add(name, val);
when(solrClientMock.request((SchemaVersion) any(), anyString())).thenReturn(nl);
when(solrClientMock.request((SchemaRequest) any(), anyString())).thenReturn(nl);
solrTemplate = new SolrTemplate(solrClientMock);
solrTemplate.setSchemaCreationFeatures(Collections.singletonList(Feature.CREATE_MISSING_FIELDS));
solrTemplate.afterPropertiesSet();
solrTemplate.saveBean(new DocumentWithIndexAnnotations());
ArgumentCaptor<SolrRequest> requestCaptor = ArgumentCaptor.forClass(SolrRequest.class);
Mockito.verify(solrClientMock, Mockito.times(4)).request(requestCaptor.capture(), Mockito.anyString());
SolrRequest capturedRequest = requestCaptor.getValue();
Assert.assertThat(capturedRequest.getMethod(), IsEqual.equalTo(SolrRequest.METHOD.POST));
Assert.assertThat(capturedRequest.getPath(), IsEqual.equalTo("/schema"));
Assert.assertThat(capturedRequest.getContentStreams(), IsNull.notNullValue());
}
@Test // DATASOLR-83
public void testGetById() throws SolrServerException, IOException {
Mockito.when(solrClientMock.getById(anyCollection())).thenReturn(new SolrDocumentList());
solrTemplate.getById("myId", DocumentWithIndexAnnotations.class);
Mockito.verify(solrClientMock, Mockito.times(1)).getById(eq(Collections.singletonList("myId")));
}
@Test // DATASOLR-83
public void testGetByIds() throws SolrServerException, IOException {
Mockito.when(solrClientMock.getById(anyCollection())).thenReturn(new SolrDocumentList());
List<String> ids = Arrays.asList("myId1", "myId2");
solrTemplate.getById(ids, DocumentWithIndexAnnotations.class);
Mockito.verify(solrClientMock, Mockito.times(1)).getById(eq(ids));
}
@Test // DATASOLR-160
public void testSaveShouldNotSaveScoreField()
throws IOException, SolrServerException, SecurityException, NoSuchFieldException {
solrTemplate.saveBean(new DocumentWithScoreAnnotation());
ArgumentCaptor<SolrInputDocument> captor = ArgumentCaptor.forClass(SolrInputDocument.class);
Mockito.verify(solrClientMock, Mockito.times(1)).add(captor.capture(), Mockito.eq(-1));
Assert.assertNull(captor.getValue().getFieldValue("score"));
}
@Test // DATASOLR-215
public void usesTemplateDefaultRequestMethodForQuery() throws SolrServerException, IOException {
solrTemplate = new SolrTemplate(solrClientMock, RequestMethod.POST);
solrTemplate.afterPropertiesSet();
Mockito.when(solrClientMock.query(any(), Mockito.any(SolrParams.class), Mockito.eq(SolrRequest.METHOD.POST)))
.thenReturn(new QueryResponse());
solrTemplate.querySolr(new SimpleQuery("*:*"), DocumentWithIndexAnnotations.class);
Mockito.verify(solrClientMock, Mockito.times(1)).query(any(), Mockito.any(SolrParams.class),
Mockito.eq(SolrRequest.METHOD.POST));
}
@Test // DATASOLR-215
public void usesTemplateMethodRequetsParameterForQuery() throws SolrServerException, IOException {
solrTemplate = new SolrTemplate(solrClientMock, RequestMethod.POST);
solrTemplate.afterPropertiesSet();
Mockito.when(solrClientMock.query(any(), Mockito.any(SolrParams.class), Mockito.eq(SolrRequest.METHOD.PUT)))
.thenReturn(new QueryResponse());
solrTemplate.querySolr(new SimpleQuery("*:*"), DocumentWithIndexAnnotations.class, RequestMethod.PUT);
Mockito.verify(solrClientMock, Mockito.times(1)).query(any(), Mockito.any(SolrParams.class),
Mockito.eq(SolrRequest.METHOD.PUT));
}
static class DocumentWithIndexAnnotations {
@Id String id;
@Indexed(name = "namedProperty") String renamedProperty;
}
static class DocumentWithScoreAnnotation {
@Id String id;
@Score Float scoreProperty;
}
}