package org.apache.solr.schema;
/*
* 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.
*/
import org.apache.solr.client.solrj.impl.HttpSolrServer;
import org.apache.solr.cloud.AbstractFullDistribZkTestBase;
import org.apache.solr.util.BaseTestHarness;
import org.apache.solr.util.RESTfulServerProvider;
import org.apache.solr.util.RestTestHarness;
import org.eclipse.jetty.servlet.ServletHolder;
import org.restlet.ext.servlet.ServerServlet;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.junit.BeforeClass;
import java.util.ArrayList;
import java.util.List;
import java.util.SortedMap;
import java.util.TreeMap;
public class TestCloudManagedSchemaAddField extends AbstractFullDistribZkTestBase {
private static final Logger log = LoggerFactory.getLogger(TestCloudManagedSchemaAddField.class);
public TestCloudManagedSchemaAddField() {
super();
fixShardCount = true;
sliceCount = 4;
shardCount = 8;
}
@BeforeClass
public static void initSysProperties() {
System.setProperty("managed.schema.mutable", "true");
System.setProperty("enable.update.log", "true");
}
@Override
protected String getCloudSolrConfig() {
return "solrconfig-managed-schema.xml";
}
@Override
public SortedMap<ServletHolder,String> getExtraServlets() {
final SortedMap<ServletHolder,String> extraServlets = new TreeMap<>();
final ServletHolder solrRestApi = new ServletHolder("SolrSchemaRestApi", ServerServlet.class);
solrRestApi.setInitParameter("org.restlet.application", "org.apache.solr.rest.SolrSchemaRestApi");
extraServlets.put(solrRestApi, "/schema/*"); // '/schema/*' matches '/schema', '/schema/', and '/schema/whatever...'
return extraServlets;
}
private List<RestTestHarness> restTestHarnesses = new ArrayList<>();
private void setupHarnesses() {
for (int i = 0 ; i < clients.size() ; ++i) {
final HttpSolrServer client = (HttpSolrServer)clients.get(i);
RestTestHarness harness = new RestTestHarness(new RESTfulServerProvider() {
@Override
public String getBaseURL() {
return client.getBaseURL();
}
});
restTestHarnesses.add(harness);
}
}
@Override
public void doTest() throws Exception {
setupHarnesses();
// First. add a bunch of fields, and verify each is present in all shards' schemas
int numFields = 25;
for (int i = 1 ; i <= numFields ; ++i) {
RestTestHarness publisher = restTestHarnesses.get(r.nextInt(restTestHarnesses.size()));
String newFieldName = "newfield" + i;
final String content = "{\"type\":\"text\",\"stored\":\"false\"}";
String request = "/schema/fields/" + newFieldName + "?wt=xml";
String response = publisher.put(request, content);
final long addFieldTime = System.currentTimeMillis();
String result = publisher.validateXPath
(response, "/response/lst[@name='responseHeader']/int[@name='status'][.='0']");
if (null != result) {
fail("PUT REQUEST FAILED: xpath=" + result + " request=" + request
+ " content=" + content + " response=" + response);
}
int maxAttempts = 40;
long retryPauseMillis = 20;
for (RestTestHarness client : restTestHarnesses) {
boolean stillTrying = true;
for (int attemptNum = 1; stillTrying && attemptNum <= maxAttempts ; ++attemptNum) {
request = "/schema/fields/" + newFieldName + "?wt=xml";
response = client.query(request);
long elapsedTimeMillis = System.currentTimeMillis() - addFieldTime;
result = client.validateXPath(response,
"/response/lst[@name='responseHeader']/int[@name='status'][.='0']",
"/response/lst[@name='field']/str[@name='name'][.='" + newFieldName + "']");
if (null == result) {
stillTrying = false;
if (attemptNum > 1) {
log.info("On attempt #" + attemptNum + ", successful request " + request + " against server "
+ client.getBaseURL() + " after " + elapsedTimeMillis + " ms");
}
} else {
if (attemptNum == maxAttempts || ! response.contains("Field '" + newFieldName + "' not found.")) {
String msg = "QUERY FAILED: xpath=" + result + " request=" + request + " response=" + response;
if (attemptNum == maxAttempts) {
msg = "Max retry count " + maxAttempts + " exceeded after " + elapsedTimeMillis +" ms. " + msg;
}
log.error(msg);
fail(msg);
}
Thread.sleep(retryPauseMillis);
}
}
}
}
// Add a doc with one of the newly created fields
String fieldName = "newfield" + (r.nextInt(numFields) + 1);
int addDocClientNum = r.nextInt(restTestHarnesses.size());
RestTestHarness client = restTestHarnesses.get(addDocClientNum);
String updateResult = client.validateUpdate(adoc(fieldName, "word1 word2", "id", "88"));
assertNull("Error adding a document with field " + fieldName + ": " + updateResult, updateResult);
updateResult = client.validateUpdate(BaseTestHarness.commit());
assertNull("Error committing: " + updateResult, updateResult);
// Query for the newly added doc against a different client
int queryDocClientNum = r.nextInt(restTestHarnesses.size());
while (queryDocClientNum == addDocClientNum) {
queryDocClientNum = r.nextInt(restTestHarnesses.size());
}
client = restTestHarnesses.get(queryDocClientNum);
String response = client.query("/select?q=" + fieldName + ":word2");
String queryResult = client.validateXPath(response,
"/response/result[@name='response'][@numFound='1']",
"count(/response/result[@name='response']/doc/int[@name='id']) = 1",
"/response/result[@name='response']/doc/int[@name='id'] = '88'");
assertNull("Error querying for a document with field " + fieldName + ": " + queryResult
+ " response=" + response, queryResult);
}
}