blob: 82ceaabfd7d0cae376bdbd2c7bd87e4e4e794e15 [file] [log] [blame]
package org.apache.solr.handler.dataimport;
/*
* 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 java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import org.apache.commons.io.FileUtils;
import org.apache.lucene.util.IOUtils;
import org.apache.solr.client.solrj.SolrServerException;
import org.apache.solr.client.solrj.embedded.JettySolrRunner;
import org.apache.solr.client.solrj.impl.HttpSolrClient;
import org.apache.solr.common.SolrInputDocument;
import org.junit.After;
import org.junit.AfterClass;
import org.junit.Before;
import org.junit.BeforeClass;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* End-to-end test of SolrEntityProcessor. "Real" test using embedded Solr
*/
public class TestSolrEntityProcessorEndToEnd extends AbstractDataImportHandlerTestCase {
private static Logger LOG = LoggerFactory.getLogger(TestSolrEntityProcessorEndToEnd.class);
private static final String SOLR_CONFIG = "dataimport-solrconfig.xml";
private static final String SOLR_SCHEMA = "dataimport-schema.xml";
private static final String SOURCE_CONF_DIR = "dih" + File.separator + "solr" + File.separator + "collection1" + File.separator + "conf" + File.separator;
private static final String ROOT_DIR = "dih" + File.separator + "solr" + File.separator;
private static final String DEAD_SOLR_SERVER = "http://[ff01::114]:33332/solr";
private static final List<Map<String,Object>> DB_DOCS = new ArrayList<>();
private static final List<Map<String,Object>> SOLR_DOCS = new ArrayList<>();
static {
// dynamic fields in the destination schema
Map<String,Object> dbDoc = new HashMap<>();
dbDoc.put("dbid_s", "1");
dbDoc.put("dbdesc_s", "DbDescription");
DB_DOCS.add(dbDoc);
Map<String,Object> solrDoc = new HashMap<>();
solrDoc.put("id", "1");
solrDoc.put("desc", "SolrDescription");
SOLR_DOCS.add(solrDoc);
}
private SolrInstance instance = null;
private JettySolrRunner jetty;
private String getDihConfigTagsInnerEntity() {
return "<dataConfig>\r\n"
+ " <dataSource type='MockDataSource' />\r\n"
+ " <document>\r\n"
+ " <entity name='db' query='select * from x'>\r\n"
+ " <field column='dbid_s' />\r\n"
+ " <field column='dbdesc_s' />\r\n"
+ " <entity name='se' processor='SolrEntityProcessor' query='id:${db.dbid_s}'\n"
+ " url='" + getSourceUrl() + "' fields='id,desc'>\r\n"
+ " <field column='id' />\r\n"
+ " <field column='desc' />\r\n" + " </entity>\r\n"
+ " </entity>\r\n" + " </document>\r\n" + "</dataConfig>\r\n";
}
private String generateDIHConfig(String options, boolean useDeadServer) {
return "<dataConfig>\r\n" + " <document>\r\n"
+ " <entity name='se' processor='SolrEntityProcessor'" + " url='"
+ (useDeadServer ? DEAD_SOLR_SERVER : getSourceUrl()) + "' " + options + " />\r\n" + " </document>\r\n"
+ "</dataConfig>\r\n";
}
private String getSourceUrl() {
return buildUrl(jetty.getLocalPort(), "/solr");
}
//TODO: fix this test to close its directories
static String savedFactory;
@BeforeClass
public static void beforeClass() {
savedFactory = System.getProperty("solr.DirectoryFactory");
System.setProperty("solr.directoryFactory", "solr.StandardDirectoryFactory");
}
@AfterClass
public static void afterClass() {
if (savedFactory == null) {
System.clearProperty("solr.directoryFactory");
} else {
System.setProperty("solr.directoryFactory", savedFactory);
}
}
@Override
@Before
public void setUp() throws Exception {
super.setUp();
// destination solr core
initCore(SOLR_CONFIG, SOLR_SCHEMA);
// data source solr instance
instance = new SolrInstance();
instance.setUp();
jetty = createJetty(instance);
}
@Override
@After
public void tearDown() throws Exception {
try {
deleteCore();
} catch (Exception e) {
LOG.error("Error deleting core", e);
}
jetty.stop();
instance.tearDown();
super.tearDown();
}
public void testFullImport() {
assertQ(req("*:*"), "//result[@numFound='0']");
try {
addDocumentsToSolr(SOLR_DOCS);
runFullImport(generateDIHConfig("query='*:*' rows='2' fl='id,desc' onError='skip'", false));
} catch (Exception e) {
LOG.error(e.getMessage(), e);
fail(e.getMessage());
}
assertQ(req("*:*"), "//result[@numFound='1']");
assertQ(req("id:1"), "//result/doc/str[@name='id'][.='1']",
"//result/doc/arr[@name='desc'][.='SolrDescription']");
}
public void testFullImportFqParam() {
assertQ(req("*:*"), "//result[@numFound='0']");
try {
addDocumentsToSolr(generateSolrDocuments(30));
Map<String,String> map = new HashMap<>();
map.put("rows", "50");
runFullImport(generateDIHConfig("query='*:*' fq='desc:Description1*,desc:Description*2' rows='2'", false), map);
} catch (Exception e) {
LOG.error(e.getMessage(), e);
fail(e.getMessage());
}
assertQ(req("*:*"), "//result[@numFound='1']");
assertQ(req("id:12"), "//result[@numFound='1']", "//result/doc/arr[@name='desc'][.='Description12']");
}
public void testFullImportFieldsParam() {
assertQ(req("*:*"), "//result[@numFound='0']");
try {
addDocumentsToSolr(generateSolrDocuments(7));
runFullImport(generateDIHConfig("query='*:*' fl='id' rows='2'", false));
} catch (Exception e) {
LOG.error(e.getMessage(), e);
fail(e.getMessage());
}
assertQ(req("*:*"), "//result[@numFound='7']");
assertQ(req("id:1"), "//result[@numFound='1']");
try {
assertQ(req("id:1"), "//result/doc/arr[@name='desc']");
fail("The document has a field with name desc");
} catch(Exception e) {
}
}
/**
* Receive a row from SQL (Mock) and fetch a row from Solr
*/
public void testFullImportInnerEntity() {
assertQ(req("*:*"), "//result[@numFound='0']");
try {
List<Map<String,Object>> DOCS = new ArrayList<>(DB_DOCS);
Map<String, Object> doc = new HashMap<>();
doc.put("dbid_s", "2");
doc.put("dbdesc_s", "DbDescription2");
DOCS.add(doc);
MockDataSource.setIterator("select * from x", DOCS.iterator());
DOCS = new ArrayList<>(SOLR_DOCS);
Map<String,Object> solrDoc = new HashMap<>();
solrDoc.put("id", "2");
solrDoc.put("desc", "SolrDescription2");
DOCS.add(solrDoc);
addDocumentsToSolr(DOCS);
runFullImport(getDihConfigTagsInnerEntity());
} catch (Exception e) {
LOG.error(e.getMessage(), e);
fail(e.getMessage());
} finally {
MockDataSource.clearCache();
}
assertQ(req("*:*"), "//result[@numFound='2']");
assertQ(req("id:1"), "//result/doc/str[@name='id'][.='1']",
"//result/doc/str[@name='dbdesc_s'][.='DbDescription']",
"//result/doc/str[@name='dbid_s'][.='1']",
"//result/doc/arr[@name='desc'][.='SolrDescription']");
assertQ(req("id:2"), "//result/doc/str[@name='id'][.='2']",
"//result/doc/str[@name='dbdesc_s'][.='DbDescription2']",
"//result/doc/str[@name='dbid_s'][.='2']",
"//result/doc/arr[@name='desc'][.='SolrDescription2']");
}
public void testFullImportWrongSolrUrl() {
assertQ(req("*:*"), "//result[@numFound='0']");
try {
runFullImport(generateDIHConfig("query='*:*' rows='2' fl='id,desc' onError='skip'", true /* use dead server */));
} catch (Exception e) {
LOG.error(e.getMessage(), e);
fail(e.getMessage());
}
assertQ(req("*:*"), "//result[@numFound='0']");
}
public void testFullImportBadConfig() {
assertQ(req("*:*"), "//result[@numFound='0']");
try {
runFullImport(generateDIHConfig("query='bogus:3' rows='2' fl='id,desc' onError='abort'", false));
} catch (Exception e) {
LOG.error(e.getMessage(), e);
fail(e.getMessage());
}
assertQ(req("*:*"), "//result[@numFound='0']");
}
private static List<Map<String,Object>> generateSolrDocuments(int num) {
List<Map<String,Object>> docList = new ArrayList<>();
for (int i = 1; i <= num; i++) {
Map<String,Object> map = new HashMap<>();
map.put("id", i);
map.put("desc", "Description" + i);
docList.add(map);
}
return docList;
}
private void addDocumentsToSolr(List<Map<String,Object>> docs) throws SolrServerException, IOException {
List<SolrInputDocument> sidl = new ArrayList<>();
for (Map<String,Object> doc : docs) {
SolrInputDocument sd = new SolrInputDocument();
for (Entry<String,Object> entry : doc.entrySet()) {
sd.addField(entry.getKey(), entry.getValue());
}
sidl.add(sd);
}
HttpSolrClient solrServer = new HttpSolrClient(getSourceUrl());
try {
solrServer.setConnectionTimeout(15000);
solrServer.setSoTimeout(30000);
solrServer.add(sidl);
solrServer.commit(true, true);
} finally {
solrServer.shutdown();
}
}
private static class SolrInstance {
File homeDir;
File confDir;
public String getHomeDir() {
return homeDir.toString();
}
public String getSchemaFile() {
return SOURCE_CONF_DIR + "dataimport-schema.xml";
}
public String getDataDir() {
return initCoreDataDir.toString();
}
public String getSolrConfigFile() {
return SOURCE_CONF_DIR + "dataimport-solrconfig.xml";
}
public String getSolrXmlFile() {
return ROOT_DIR + "solr.xml";
}
public void setUp() throws Exception {
homeDir = createTempDir().toFile();
initCoreDataDir = new File(homeDir + "/collection1", "data");
confDir = new File(homeDir + "/collection1", "conf");
homeDir.mkdirs();
initCoreDataDir.mkdirs();
confDir.mkdirs();
FileUtils.copyFile(getFile(getSolrXmlFile()), new File(homeDir, "solr.xml"));
File f = new File(confDir, "solrconfig.xml");
FileUtils.copyFile(getFile(getSolrConfigFile()), f);
f = new File(confDir, "schema.xml");
FileUtils.copyFile(getFile(getSchemaFile()), f);
f = new File(confDir, "data-config.xml");
FileUtils.copyFile(getFile(SOURCE_CONF_DIR + "dataconfig-contentstream.xml"), f);
}
public void tearDown() throws Exception {
IOUtils.rm(homeDir.toPath());
}
}
private JettySolrRunner createJetty(SolrInstance instance) throws Exception {
JettySolrRunner jetty = new JettySolrRunner(instance.getHomeDir(), "/solr", 0, null, null, true, null, sslConfig);
jetty.setDataDir(instance.getDataDir());
jetty.start();
return jetty;
}
}