/*
* Copyright 2014-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.query.result;
import static org.hamcrest.core.Is.*;
import static org.hamcrest.core.IsEqual.*;
import static org.hamcrest.core.IsNot.*;
import static org.hamcrest.core.IsNull.*;
import static org.junit.Assert.*;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.NoSuchElementException;
import org.apache.solr.client.solrj.SolrQuery;
import org.apache.solr.common.params.CursorMarkParams;
import org.junit.Test;
import org.springframework.dao.InvalidDataAccessApiUsageException;
import org.springframework.data.solr.core.query.result.DelegatingCursor.PartialResult;
import org.springframework.util.CollectionUtils;
/**
* @author Christoph Strobl
*/
public class DelegatingCursorUnitTests {
@Test(expected = InvalidDataAccessApiUsageException.class) // DATASOLR-162
public void shouldThrowExceptionWhenOpeningMultipleTimes() {
new DelegatingCursorFake<>(null).open().open();
}
@Test // DATASOLR-162
public void shouldNotHaveNextWhenNoElementsAvailable() {
assertThat(new DelegatingCursorFake<>(null).open().hasNext(), is(false));
}
@Test(expected = NoSuchElementException.class) // DATASOLR-162
public void nextShouldThrowExceptionWhenNoMoreElementsAvailable() {
new DelegatingCursorFake<>(null).open().next();
}
@Test // DATASOLR-162
public void shouldReturnElementsInValidOrder() {
PartialResult<String> result = new PartialResult<>("*", Arrays.asList("spring", "data", "solr"));
DelegatingCursor<String> cursor = new DelegatingCursorFake<>(Collections.singleton(result)).open();
assertThat(cursor.next(), equalTo("spring"));
assertThat(cursor.next(), equalTo("data"));
assertThat(cursor.next(), equalTo("solr"));
}
@Test // DATASOLR-162
public void shouldStopWhenNoMoreElementsAvailableAndAlreadyFinished() {
PartialResult<String> result = new PartialResult<>("*", Arrays.asList("spring", "data", "solr"));
DelegatingCursor<String> cursor = new DelegatingCursorFake<>(Collections.singleton(result)).open();
cursor.next();
cursor.next();
cursor.next();
assertThat(cursor.hasNext(), is(false));
}
@Test // DATASOLR-162
public void shouldFetchNextSetOfElementsWhenNotFinishedAndCurrentResultsEndReached() {
PartialResult<String> result1 = new PartialResult<>("foo", Arrays.asList("spring", "data"));
PartialResult<String> result2 = new PartialResult<>("foo", Collections.singletonList("solr"));
@SuppressWarnings("unchecked")
DelegatingCursor<String> cursor = new DelegatingCursorFake<>(Arrays.asList(result1, result2)).open();
assertThat(cursor.next(), equalTo("spring"));
assertThat(cursor.next(), equalTo("data"));
assertThat(cursor.next(), equalTo("solr"));
}
@Test // DATASOLR-162
public void shouldDetermineEndOfResultsCorrectly() {
PartialResult<String> result1 = new PartialResult<>("foo", Arrays.asList("spring", "data"));
PartialResult<String> result2 = new PartialResult<>("foo", Collections.singletonList("solr"));
@SuppressWarnings("unchecked")
DelegatingCursor<String> cursor = new DelegatingCursorFake<>(Arrays.asList(result1, result2)).open();
cursor.next();
cursor.next();
cursor.next();
assertThat(cursor.hasNext(), is(false));
}
@Test // DATASOLR-162
public void shouldFinishLoopingWhenCursorMarkEqualsPreviousOne() {
PartialResult<String> result1 = new PartialResult<>("foo", Collections.singletonList("spring"));
PartialResult<String> result2 = new PartialResult<>("bar", Collections.singletonList("data"));
PartialResult<String> result3 = new PartialResult<>("bar", Collections.singletonList("solr"));
@SuppressWarnings("unchecked")
DelegatingCursor<String> cursor = new DelegatingCursorFake<>(Arrays.asList(result1, result2, result3)).open();
assertThat(cursor.hasNext(), is(true));
assertThat(cursor.isFinished(), is(false));
assertThat(cursor.next(), is("spring"));
assertThat(cursor.hasNext(), is(true));
assertThat(cursor.isFinished(), is(false));
assertThat(cursor.next(), is("data"));
assertThat(cursor.hasNext(), is(true));
assertThat(cursor.isFinished(), is(true));
assertThat(cursor.next(), is("solr"));
}
@Test // DATASOLR-162
public void shouldNotModifyInitialQueryWhenRequestingResults() {
SolrQuery initialQuery = new SolrQuery("*:*");
DelegatingCursorFake<String> cursor = new DelegatingCursorFake<>(initialQuery, null);
cursor.open();
SolrQuery executedQuey = cursor.getLastUsedQuery();
assertThat(executedQuey, not(equalTo(initialQuery)));
assertThat(executedQuey.getQuery(), equalTo(initialQuery.getQuery()));
assertThat(executedQuey.get(CursorMarkParams.CURSOR_MARK_PARAM), equalTo(CursorMarkParams.CURSOR_MARK_START));
assertThat(initialQuery.get(CursorMarkParams.CURSOR_MARK_PARAM), nullValue());
}
class DelegatingCursorFake<T> extends DelegatingCursor<T> {
List<PartialResult<T>> values = new ArrayList<>();
private int requestCounter;
private SolrQuery lastUsedQuery;
public DelegatingCursorFake(Collection<PartialResult<T>> results) {
this(new SolrQuery(), results);
}
protected DelegatingCursorFake(SolrQuery query, Collection<PartialResult<T>> results) {
super(query);
if (!CollectionUtils.isEmpty(results)) {
this.values.addAll(results);
}
this.requestCounter = 0;
}
@Override
protected org.springframework.data.solr.core.query.result.DelegatingCursor.PartialResult<T> doLoad(
SolrQuery nativeQuery) {
this.lastUsedQuery = nativeQuery;
return ((!values.isEmpty() && requestCounter <= values.size()) ? values.get(requestCounter++) : null);
}
public SolrQuery getLastUsedQuery() {
return lastUsedQuery;
}
public int getNrRequestsExecuted() {
return this.requestCounter;
}
}
}