blob: 1982cf89e083bf69c6677bd2eb985ea5baf9a12e [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You 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.apache.solr.client.solrj.request.json;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.apache.solr.client.solrj.request.AbstractUpdateRequest;
import org.apache.solr.client.solrj.request.CollectionAdminRequest;
import org.apache.solr.client.solrj.request.ContentStreamUpdateRequest;
import org.apache.solr.client.solrj.response.QueryResponse;
import org.apache.solr.client.solrj.response.UpdateResponse;
import org.apache.solr.cloud.SolrCloudTestCase;
import org.apache.solr.common.MapWriter;
import org.apache.solr.common.SolrDocument;
import org.apache.solr.common.SolrDocumentList;
import org.apache.solr.common.params.ModifiableSolrParams;
import org.apache.solr.util.ExternalPaths;
import org.junit.BeforeClass;
import org.junit.Test;
/**
* Integration tests for {@link JsonQueryRequest}
*/
public class JsonQueryRequestIntegrationTest extends SolrCloudTestCase {
private static final String COLLECTION_NAME = "books";
private static final String CONFIG_NAME = "techproducts_config";
private static final int NUM_BOOKS_TOTAL = 10;
private static final int NUM_SCIFI_BOOKS = 2;
private static final int NUM_IN_STOCK = 8;
private static final int NUM_IN_STOCK_AND_FIRST_IN_SERIES = 5;
@BeforeClass
public static void setupCluster() throws Exception {
configureCluster(1)
.addConfig(CONFIG_NAME, new File(ExternalPaths.TECHPRODUCTS_CONFIGSET).toPath())
.configure();
final List<String> solrUrls = new ArrayList<>();
solrUrls.add(cluster.getJettySolrRunner(0).getBaseUrl().toString());
CollectionAdminRequest.createCollection(COLLECTION_NAME, CONFIG_NAME, 1, 1).process(cluster.getSolrClient());
ContentStreamUpdateRequest up = new ContentStreamUpdateRequest("/update");
up.setParam("collection", COLLECTION_NAME);
up.addFile(getFile("solrj/books.csv"), "application/csv");
up.setAction(AbstractUpdateRequest.ACTION.COMMIT, true, true);
UpdateResponse updateResponse = up.process(cluster.getSolrClient());
assertEquals(0, updateResponse.getStatus());
}
@Test
public void testEmptyJson() throws Exception {
final JsonQueryRequest simpleQuery = new JsonQueryRequest();
QueryResponse queryResponse = simpleQuery.process(cluster.getSolrClient(), COLLECTION_NAME);
// No q.alt in techproducts configset, so request should gracefully find no results
assertEquals(0, queryResponse.getStatus());
assertEquals(0, queryResponse.getResults().getNumFound());
}
@Test
public void testCanRunSimpleQueries() throws Exception {
final JsonQueryRequest simpleQuery = new JsonQueryRequest()
.setQuery("*:*");
QueryResponse queryResponse = simpleQuery.process(cluster.getSolrClient(), COLLECTION_NAME);
assertEquals(0, queryResponse.getStatus());
assertEquals(NUM_BOOKS_TOTAL, queryResponse.getResults().getNumFound());
}
@Test
public void testQueriesCanUseLocalParamsSyntax() throws Exception {
final JsonQueryRequest simpleQuery = new JsonQueryRequest()
.setQuery("{!lucene df=genre_s v='scifi'}");
QueryResponse queryResponse = simpleQuery.process(cluster.getSolrClient(), COLLECTION_NAME);
assertEquals(0, queryResponse.getStatus());
assertEquals(NUM_SCIFI_BOOKS, queryResponse.getResults().getNumFound());
}
@Test
public void testQueriesCanUseExpandedSyntax() throws Exception {
//Construct a tree representing the JSON: {lucene: {df:'genre_s', 'query': 'scifi'}}
final Map<String, Object> queryMap = new HashMap<>();
final Map<String, Object> luceneQueryParamMap = new HashMap<>();
queryMap.put("lucene", luceneQueryParamMap);
luceneQueryParamMap.put("df", "genre_s");
luceneQueryParamMap.put("query", "scifi");
final JsonQueryRequest simpleQuery = new JsonQueryRequest()
.setQuery(queryMap);
QueryResponse queryResponse = simpleQuery.process(cluster.getSolrClient(), COLLECTION_NAME);
assertEquals(0, queryResponse.getStatus());
assertEquals(NUM_SCIFI_BOOKS, queryResponse.getResults().getNumFound());
}
@Test
public void testQueriesCanBeRepresentedUsingMapWriters() throws Exception {
final MapWriter queryWriter = new MapWriter() {
@Override
public void writeMap(EntryWriter ew) throws IOException {
ew.put("lucene", (MapWriter) queryParamWriter -> {
queryParamWriter.put("df", "genre_s");
queryParamWriter.put("query", "scifi");
});
}
};
final JsonQueryRequest simpleQuery = new JsonQueryRequest()
.setQuery(queryWriter);
QueryResponse queryResponse = simpleQuery.process(cluster.getSolrClient(), COLLECTION_NAME);
assertEquals(0, queryResponse.getStatus());
assertEquals(NUM_SCIFI_BOOKS, queryResponse.getResults().getNumFound());
}
@Test
public void testQueriesCanBeNested() throws Exception {
final Map<String, Object> queryJsonMap = new HashMap<>();
final Map<String, Object> clausesJsonMap = new HashMap<>();
queryJsonMap.put("bool", clausesJsonMap);
clausesJsonMap.put("must", "genre_s:scifi");
clausesJsonMap.put("must_not", "series_t:Ender");
final JsonQueryRequest simpleQuery = new JsonQueryRequest()
.setQuery(queryJsonMap);
QueryResponse queryResponse = simpleQuery.process(cluster.getSolrClient(), COLLECTION_NAME);
assertEquals(0, queryResponse.getStatus());
assertEquals(1, queryResponse.getResults().getNumFound()); // 2 scifi books, only 1 is NOT "Ender's Game"
}
@Test
public void testFiltersCanBeAddedToQueries() throws Exception {
final JsonQueryRequest simpleQuery = new JsonQueryRequest()
.setQuery("*:*")
.withFilter("inStock:true");
QueryResponse queryResponse = simpleQuery.process(cluster.getSolrClient(), COLLECTION_NAME);
assertEquals(0, queryResponse.getStatus());
assertEquals(NUM_IN_STOCK, queryResponse.getResults().getNumFound());
}
@Test
public void testFiltersCanUseLocalParamsSyntax() throws Exception {
final JsonQueryRequest simpleQuery = new JsonQueryRequest()
.setQuery("*:*")
.withFilter("{!lucene df=inStock v='true'}");
QueryResponse queryResponse = simpleQuery.process(cluster.getSolrClient(), COLLECTION_NAME);
assertEquals(0, queryResponse.getStatus());
assertEquals(NUM_IN_STOCK, queryResponse.getResults().getNumFound());
}
@Test
public void testFiltersCanUseExpandedSyntax() throws Exception {
final Map<String, Object> filterJsonMap = new HashMap<>();
final Map<String, Object> luceneQueryParamsMap = new HashMap<>();
filterJsonMap.put("lucene", luceneQueryParamsMap);
luceneQueryParamsMap.put("df", "genre_s");
luceneQueryParamsMap.put("query", "scifi");
final JsonQueryRequest simpleQuery = new JsonQueryRequest()
.setQuery("*:*")
.withFilter(filterJsonMap);
QueryResponse queryResponse = simpleQuery.process(cluster.getSolrClient(), COLLECTION_NAME);
assertEquals(0, queryResponse.getStatus());
assertEquals(NUM_SCIFI_BOOKS, queryResponse.getResults().getNumFound());
}
@Test
public void testMultipleFiltersCanBeUsed() throws Exception {
final JsonQueryRequest simpleQuery = new JsonQueryRequest()
.setQuery("*:*")
.withFilter("sequence_i:1") // 7 books are the first of a series
.withFilter("inStock:true");// but only 5 are in stock
QueryResponse queryResponse = simpleQuery.process(cluster.getSolrClient(), COLLECTION_NAME);
assertEquals(0, queryResponse.getStatus());
assertEquals(NUM_IN_STOCK_AND_FIRST_IN_SERIES, queryResponse.getResults().getNumFound());
}
@Test
public void canSpecifyFieldsToBeReturned() throws Exception {
final JsonQueryRequest simpleQuery = new JsonQueryRequest()
.setQuery("*:*")
.returnFields("id", "name");
QueryResponse queryResponse = simpleQuery.process(cluster.getSolrClient(), COLLECTION_NAME);
assertEquals(0, queryResponse.getStatus());
final SolrDocumentList docs = queryResponse.getResults();
assertEquals(NUM_BOOKS_TOTAL, docs.getNumFound());
for (SolrDocument returnedDoc : docs) {
final Collection<String> fields = returnedDoc.getFieldNames();
assertEquals(2, fields.size());
assertTrue("Expected field list to contain 'id'", fields.contains("id"));
assertTrue("Expected field list to contain 'name'", fields.contains("name"));
}
}
@Test
public void testObeysResultLimit() throws Exception {
final JsonQueryRequest simpleQuery = new JsonQueryRequest()
.setQuery("*:*")
.setLimit(5);
QueryResponse queryResponse = simpleQuery.process(cluster.getSolrClient(), COLLECTION_NAME);
assertEquals(0, queryResponse.getStatus());
assertEquals(NUM_BOOKS_TOTAL, queryResponse.getResults().getNumFound());
assertEquals(5, queryResponse.getResults().size());
}
@Test
public void testAcceptsTraditionalQueryParamNamesInParamsBlock() throws Exception {
final JsonQueryRequest simpleQuery = new JsonQueryRequest()
.withParam("q", "*:*")
.withParam("rows", 4);
QueryResponse queryResponse = simpleQuery.process(cluster.getSolrClient(), COLLECTION_NAME);
assertEquals(0, queryResponse.getStatus());
assertEquals(NUM_BOOKS_TOTAL, queryResponse.getResults().getNumFound());
assertEquals(4, queryResponse.getResults().size());
}
@Test
public void testReturnsResultsStartingAtOffset() throws Exception {
final JsonQueryRequest originalDocsQuery = new JsonQueryRequest()
.setQuery("*:*");
QueryResponse originalDocsResponse = originalDocsQuery.process(cluster.getSolrClient(), COLLECTION_NAME);
assertEquals(0, originalDocsResponse.getStatus());
assertEquals(NUM_BOOKS_TOTAL, originalDocsResponse.getResults().size());
final SolrDocumentList originalDocs = originalDocsResponse.getResults();
final int offset = 2;
final JsonQueryRequest offsetDocsQuery = new JsonQueryRequest()
.setQuery("*:*")
.setOffset(offset);
QueryResponse offsetDocsResponse = offsetDocsQuery.process(cluster.getSolrClient(), COLLECTION_NAME);
assertEquals(0, offsetDocsResponse.getStatus());
assertEquals(NUM_BOOKS_TOTAL - offset, offsetDocsResponse.getResults().size());
final SolrDocumentList offsetDocs = offsetDocsResponse.getResults();
// Ensure the same docs are returned, shifted by 'offset'
for (int i = 0; i < offsetDocs.size(); i++) {
final String offsetId = (String) offsetDocs.get(i).getFieldValue("id");
final String originalId = (String) originalDocs.get(i + offset).getFieldValue("id");
assertEquals(offsetId, originalId);
}
}
@Test
public void testReturnsReturnsResultsWithSpecifiedSort() throws Exception {
final JsonQueryRequest simpleQuery = new JsonQueryRequest()
.setQuery("*:*")
.setSort("price desc");
QueryResponse queryResponse = simpleQuery.process(cluster.getSolrClient(), COLLECTION_NAME);
assertEquals(0, queryResponse.getStatus());
assertEquals(NUM_BOOKS_TOTAL, queryResponse.getResults().getNumFound());
final SolrDocumentList docs = queryResponse.getResults();
for (int i = 0; i < docs.size() - 1; i++) {
final float pricierDocPrice = (Float) docs.get(i).getFieldValue("price");
final float cheaperDocPrice = (Float) docs.get(i+1).getFieldValue("price");
assertTrue("Expected doc at index " + i + " doc to be more expensive than doc at " + (i+1),
pricierDocPrice >= cheaperDocPrice);
}
}
@Test
public void testCombinesJsonParamsWithUriParams() throws Exception {
final ModifiableSolrParams params = new ModifiableSolrParams();
params.set("fq", "inStock:true");
final JsonQueryRequest simpleQuery = new JsonQueryRequest(params)
.setQuery("*:*");
QueryResponse queryResponse = simpleQuery.process(cluster.getSolrClient(), COLLECTION_NAME);
assertEquals(0, queryResponse.getStatus());
assertEquals(NUM_IN_STOCK, queryResponse.getResults().getNumFound());
}
@Test
public void testExpandsParameterMacros() throws Exception {
final ModifiableSolrParams params = new ModifiableSolrParams();
params.set("FIELD", "inStock");
params.set("VALUE", "true");
final JsonQueryRequest simpleQuery = new JsonQueryRequest(params)
.setQuery("${FIELD}:${VALUE}");
QueryResponse queryResponse = simpleQuery.process(cluster.getSolrClient(), COLLECTION_NAME);
assertEquals(0, queryResponse.getStatus());
assertEquals(NUM_IN_STOCK, queryResponse.getResults().getNumFound());
}
}