SOLR-10134: EmbeddedSolrServer handles SchemaAPI requests

This commit is contained in:
Mikhail Khludnev 2017-02-23 00:40:40 +03:00
parent 8b4502c218
commit 0baf2fa33c
6 changed files with 168 additions and 33 deletions

View File

@ -259,6 +259,7 @@ Other Changes
* SOLR-10214: Remove unused HDFS BlockCache metrics and add storeFails, as well as adding total
counts for lookups, hits, and evictions. (yonik)
* SOLR-10134: EmbeddedSolrServer responds on Schema API requests (Robert Alexandersson via Mikhail Khludnev)
================== 6.4.2 ==================

View File

@ -172,6 +172,7 @@ public class EmbeddedSolrServer extends SolrClient {
req = _parser.buildRequestFrom(core, params, request.getContentStreams());
req.getContext().put(PATH, path);
req.getContext().put("httpMethod", request.getMethod().name());
SolrQueryResponse rsp = new SolrQueryResponse();
SolrRequestInfo.setRequestInfo(new SolrRequestInfo(req, rsp));
@ -199,8 +200,33 @@ public class EmbeddedSolrServer extends SolrClient {
};
ByteArrayOutputStream out = new ByteArrayOutputStream();
new JavaBinCodec(resolver) {
try(ByteArrayOutputStream out = new ByteArrayOutputStream()) {
createJavaBinCodec(callback, resolver).setWritableDocFields(resolver).marshal(rsp.getValues(), out);
try(InputStream in = out.toInputStream()){
return (NamedList<Object>) new JavaBinCodec(resolver).unmarshal(in);
}
}
} catch (Exception ex) {
throw new RuntimeException(ex);
}
}
// Now write it out
NamedList<Object> normalized = BinaryResponseWriter.getParsedResponse(req, rsp);
return normalized;
} catch (IOException | SolrException iox) {
throw iox;
} catch (Exception ex) {
throw new SolrServerException(ex);
} finally {
if (req != null) req.close();
SolrRequestInfo.clearRequestInfo();
}
}
private JavaBinCodec createJavaBinCodec(final StreamingResponseCallback callback, final BinaryResponseWriter.Resolver resolver) {
return new JavaBinCodec(resolver) {
@Override
public void writeSolrDocument(SolrDocument doc) {
@ -221,26 +247,7 @@ public class EmbeddedSolrServer extends SolrClient {
super.writeSolrDocumentList(docs);
}
}.setWritableDocFields(resolver). marshal(rsp.getValues(), out);
InputStream in = out.toInputStream();
return (NamedList<Object>) new JavaBinCodec(resolver).unmarshal(in);
} catch (Exception ex) {
throw new RuntimeException(ex);
}
}
// Now write it out
NamedList<Object> normalized = BinaryResponseWriter.getParsedResponse(req, rsp);
return normalized;
} catch (IOException | SolrException iox) {
throw iox;
} catch (Exception ex) {
throw new SolrServerException(ex);
} finally {
if (req != null) req.close();
SolrRequestInfo.clearRequestInfo();
}
};
}
private static void checkForExceptions(SolrQueryResponse rsp) throws Exception {

View File

@ -31,13 +31,14 @@ import org.apache.solr.common.util.ContentStream;
import org.apache.solr.core.SolrCore;
import java.io.Closeable;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.security.Principal;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.HashMap;
import static java.nio.charset.StandardCharsets.UTF_8;
@ -202,7 +203,7 @@ public abstract class SolrQueryRequestBase implements SolrQueryRequest, Closeabl
Iterable<ContentStream> contentStreams = getContentStreams();
if (contentStreams == null) throw new SolrException(SolrException.ErrorCode.BAD_REQUEST, "No content stream");
for (ContentStream contentStream : contentStreams) {
parsedCommands = ApiBag.getCommandOperations(new InputStreamReader((InputStream) contentStream, UTF_8),
parsedCommands = ApiBag.getCommandOperations(getInputStream(contentStream),
getValidators(), validateInput);
}
@ -211,6 +212,18 @@ public abstract class SolrQueryRequestBase implements SolrQueryRequest, Closeabl
}
private InputStreamReader getInputStream(ContentStream contentStream) {
if(contentStream instanceof InputStream) {
return new InputStreamReader((InputStream)contentStream, UTF_8);
} else {
try {
return new InputStreamReader(contentStream.getStream(), UTF_8);
} catch (IOException e) {
throw new RuntimeException(e);
}
}
}
protected ValidatingJsonMap getSpec() {
return null;
}

View File

@ -16,7 +16,7 @@
*/
package org.apache.solr.servlet;
import javax.servlet.http.HttpServletRequest;
import static org.apache.solr.common.params.CommonParams.PATH;
import java.io.ByteArrayOutputStream;
import java.io.File;
@ -33,13 +33,14 @@ import java.security.Principal;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import javax.servlet.http.HttpServletRequest;
import org.apache.commons.fileupload.FileItem;
import org.apache.commons.fileupload.disk.DiskFileItemFactory;
import org.apache.commons.fileupload.servlet.ServletFileUpload;
@ -64,8 +65,6 @@ import org.apache.solr.util.CommandOperation;
import org.apache.solr.util.RTimerTree;
import org.apache.solr.util.SolrFileCleaningTracker;
import static org.apache.solr.common.params.CommonParams.PATH;
public class SolrRequestParsers
{
@ -239,7 +238,7 @@ public class SolrRequestParsers
if (httpSolrCall != null) {
return httpSolrCall.getCommands(validateInput);
}
return Collections.emptyList();
return super.getCommands(validateInput);
}
@Override
@ -247,7 +246,7 @@ public class SolrRequestParsers
if (httpSolrCall != null && httpSolrCall instanceof V2HttpCall) {
return ((V2HttpCall) httpSolrCall).getUrlParts();
}
return Collections.EMPTY_MAP;
return super.getPathTemplateValues();
}
@Override

View File

@ -0,0 +1,111 @@
/*
* 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.embedded;
import java.io.IOException;
import java.nio.file.Path;
import java.util.Collections;
import java.util.LinkedHashMap;
import java.util.Map;
import org.apache.solr.SolrTestCaseJ4;
import org.apache.solr.client.solrj.SolrServerException;
import org.apache.solr.client.solrj.request.schema.SchemaRequest;
import org.apache.solr.client.solrj.response.schema.SchemaResponse;
import org.apache.solr.client.solrj.response.schema.SchemaResponse.FieldResponse;
import org.apache.solr.common.SolrException;
import org.junit.AfterClass;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Test;
public class TestEmbeddedSolrServerSchemaAPI extends SolrTestCaseJ4 {
private String fieldName = "VerificationTest";
private static EmbeddedSolrServer server;
private final Map<String, Object> fieldAttributes;
{
Map<String,Object> field = new LinkedHashMap<>();
field.put("name", fieldName);
field.put("type", "string");
field.put("stored", false);
field.put("indexed", true);
field.put("multiValued", true);
fieldAttributes = Collections.unmodifiableMap(field);
}
@BeforeClass
public static void initClass() throws Exception {
assertNull("no system props clash please", System.getProperty("managed.schema.mutable"));
System.setProperty("managed.schema.mutable", ""+//true
random().nextBoolean()
);
Path tmpHome = createTempDir("tmp-home");
Path coreDir = tmpHome.resolve(DEFAULT_TEST_CORENAME);
copyMinConf(coreDir.toFile(), null, "solrconfig-managed-schema.xml");
initCore("solrconfig.xml" /*it's renamed to to*/, "schema.xml", tmpHome.toAbsolutePath().toString());
server = new EmbeddedSolrServer(h.getCoreContainer(), DEFAULT_TEST_CORENAME);
}
@AfterClass
public static void destroyClass() throws IOException {
server.close(); // doubtful
server = null;
System.clearProperty("managed.schema.mutable");
}
@Before
public void thereIsNoFieldYet() throws SolrServerException, IOException{
try{
FieldResponse process = new SchemaRequest.Field(fieldName)
.process(server);
fail(""+process);
}catch(SolrException e){
assertTrue(e.getMessage().contains("No")
&& e.getMessage().contains("VerificationTest"));
}
}
@Test
public void testSchemaAddFieldAndVerifyExistence() throws Exception {
assumeTrue("it needs to ammend schema", Boolean.getBoolean("managed.schema.mutable"));
SchemaResponse.UpdateResponse addFieldResponse = new SchemaRequest.AddField(fieldAttributes).process(server);
assertEquals(addFieldResponse.toString(), 0, addFieldResponse.getStatus());
// This asserts that the field was actually created
// this is due to the fact that the response gave OK but actually never created the field.
Map<String,Object> foundFieldAttributes = new SchemaRequest.Field(fieldName).process(server).getField();
assertEquals(fieldAttributes, foundFieldAttributes);
assertEquals("removing " + fieldName, 0,
new SchemaRequest.DeleteField(fieldName).process(server).getStatus());
}
@Test
public void testSchemaAddFieldAndFailOnImmutable() throws Exception {
assumeFalse("it needs a readonly schema", Boolean.getBoolean("managed.schema.mutable"));
SchemaRequest.AddField addFieldUpdateSchemaRequest = new SchemaRequest.AddField(fieldAttributes);
SchemaResponse.UpdateResponse addFieldResponse = addFieldUpdateSchemaRequest.process(server);
// wt hell???? assertFalse(addFieldResponse.toString(), addFieldResponse.getStatus()==0);
assertTrue((""+addFieldResponse).contains("schema is not editable"));
}
}

View File

@ -2019,6 +2019,10 @@ public abstract class SolrTestCaseJ4 extends LuceneTestCase {
// the string to write to the core.properties file may be null in which case nothing is done with it.
// propertiesContent may be an empty string, which will actually work.
public static void copyMinConf(File dstRoot, String propertiesContent) throws IOException {
copyMinConf(dstRoot, propertiesContent, "solrconfig-minimal.xml");
}
public static void copyMinConf(File dstRoot, String propertiesContent, String solrconfigXmlName) throws IOException {
File subHome = new File(dstRoot, "conf");
if (! dstRoot.exists()) {
@ -2030,7 +2034,7 @@ public abstract class SolrTestCaseJ4 extends LuceneTestCase {
}
String top = SolrTestCaseJ4.TEST_HOME() + "/collection1/conf";
FileUtils.copyFile(new File(top, "schema-tiny.xml"), new File(subHome, "schema.xml"));
FileUtils.copyFile(new File(top, "solrconfig-minimal.xml"), new File(subHome, "solrconfig.xml"));
FileUtils.copyFile(new File(top, solrconfigXmlName), new File(subHome, "solrconfig.xml"));
FileUtils.copyFile(new File(top, "solrconfig.snippet.randomindexconfig.xml"), new File(subHome, "solrconfig.snippet.randomindexconfig.xml"));
}