blob: 2391ae8a3140910f8c388ae410e9f4e8327a7c05 [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.handler.dataimport;
import java.io.Reader;
import java.io.StringReader;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import org.junit.AfterClass;
import org.junit.Before;
import org.junit.BeforeClass;
/**
* Tests exception handling during imports in DataImportHandler
*
*
* @since solr 1.4
*/
public class TestErrorHandling extends AbstractDataImportHandlerTestCase {
//TODO: fix this test to not require FSDirectory.
static String savedFactory;
@BeforeClass
public static void beforeClass() throws Exception {
savedFactory = System.getProperty("solr.DirectoryFactory");
System.setProperty("solr.directoryFactory", "solr.MockFSDirectoryFactory");
initCore("dataimport-solrconfig.xml", "dataimport-schema.xml");
ignoreException("Unexpected close tag");
}
@AfterClass
public static void afterClass() {
if (savedFactory == null) {
System.clearProperty("solr.directoryFactory");
} else {
System.setProperty("solr.directoryFactory", savedFactory);
}
}
@Before @Override
public void setUp() throws Exception {
super.setUp();
clearIndex();
assertU(commit());
}
public void testMalformedStreamingXml() throws Exception {
StringDataSource.xml = malformedXml;
runFullImport(dataConfigWithStreaming);
assertQ(req("id:1"), "//*[@numFound='1']");
assertQ(req("id:2"), "//*[@numFound='1']");
}
public void testMalformedNonStreamingXml() throws Exception {
StringDataSource.xml = malformedXml;
runFullImport(dataConfigWithoutStreaming);
assertQ(req("id:1"), "//*[@numFound='1']");
assertQ(req("id:2"), "//*[@numFound='1']");
}
public void testAbortOnError() throws Exception {
StringDataSource.xml = malformedXml;
runFullImport(dataConfigAbortOnError);
assertQ(req("*:*"), "//*[@numFound='0']");
}
@SuppressWarnings({"unchecked"})
public void testTransformerErrorContinue() throws Exception {
StringDataSource.xml = wellformedXml;
List<Map<String, Object>> rows = new ArrayList<>();
rows.add(createMap("id", "3", "desc", "exception-transformer"));
MockDataSource.setIterator("select * from foo", rows.iterator());
runFullImport(dataConfigWithTransformer);
assertQ(req("*:*"), "//*[@numFound='3']");
}
public void testExternalEntity() throws Exception {
StringDataSource.xml = wellformedXml;
// This should not fail as external entities are replaced by an empty string during parsing:
runFullImport(dataConfigWithEntity);
assertQ(req("*:*"), "//*[@numFound='3']");
}
public static class StringDataSource extends DataSource<Reader> {
public static String xml = "";
@Override
public void init(Context context, Properties initProps) {
}
@Override
public Reader getData(String query) {
return new StringReader(xml);
}
@Override
public void close() {
}
}
public static class ExceptionTransformer extends Transformer {
@Override
public Object transformRow(Map<String, Object> row, Context context) {
throw new RuntimeException("Test exception");
}
}
private String dataConfigWithStreaming = "<dataConfig>\n" +
" <dataSource name=\"str\" type=\"TestErrorHandling$StringDataSource\" />" +
" <document>\n" +
" <entity name=\"node\" dataSource=\"str\" processor=\"XPathEntityProcessor\" url=\"test\" stream=\"true\" forEach=\"/root/node\" onError=\"skip\">\n" +
" <field column=\"id\" xpath=\"/root/node/id\" />\n" +
" <field column=\"desc\" xpath=\"/root/node/desc\" />\n" +
" </entity>\n" +
" </document>\n" +
"</dataConfig>";
private String dataConfigWithoutStreaming = "<dataConfig>\n" +
" <dataSource name=\"str\" type=\"TestErrorHandling$StringDataSource\" />" +
" <document>\n" +
" <entity name=\"node\" dataSource=\"str\" processor=\"XPathEntityProcessor\" url=\"test\" forEach=\"/root/node\" onError=\"skip\">\n" +
" <field column=\"id\" xpath=\"/root/node/id\" />\n" +
" <field column=\"desc\" xpath=\"/root/node/desc\" />\n" +
" </entity>\n" +
" </document>\n" +
"</dataConfig>";
private String dataConfigAbortOnError = "<dataConfig>\n" +
" <dataSource name=\"str\" type=\"TestErrorHandling$StringDataSource\" />" +
" <document>\n" +
" <entity name=\"node\" dataSource=\"str\" processor=\"XPathEntityProcessor\" url=\"test\" forEach=\"/root/node\" onError=\"abort\">\n" +
" <field column=\"id\" xpath=\"/root/node/id\" />\n" +
" <field column=\"desc\" xpath=\"/root/node/desc\" />\n" +
" </entity>\n" +
" </document>\n" +
"</dataConfig>";
private String dataConfigWithTransformer = "<dataConfig>\n" +
" <dataSource name=\"str\" type=\"TestErrorHandling$StringDataSource\" />" +
"<dataSource type=\"MockDataSource\"/>" +
" <document>\n" +
" <entity name=\"node\" dataSource=\"str\" processor=\"XPathEntityProcessor\" url=\"test\" forEach=\"/root/node\">\n" +
" <field column=\"id\" xpath=\"/root/node/id\" />\n" +
" <field column=\"desc\" xpath=\"/root/node/desc\" />\n" +
" <entity name=\"child\" query=\"select * from foo\" transformer=\"TestErrorHandling$ExceptionTransformer\" onError=\"continue\">\n" +
" </entity>" +
" </entity>\n" +
" </document>\n" +
"</dataConfig>";
private String dataConfigWithEntity = "<!DOCTYPE dataConfig [\n" +
" <!ENTITY internalTerm \"node\">\n" +
" <!ENTITY externalTerm SYSTEM \"foo://bar.xyz/external\">\n" +
"]><dataConfig>\n" +
" <dataSource name=\"str\" type=\"TestErrorHandling$StringDataSource\" />" +
" <document>\n" +
" <entity name=\"&internalTerm;\" dataSource=\"str\" processor=\"XPathEntityProcessor\" url=\"test\" forEach=\"/root/node\" onError=\"skip\">\n" +
" <field column=\"id\" xpath=\"/root/node/id\">&externalTerm;</field>\n" +
" <field column=\"desc\" xpath=\"/root/node/desc\" />\n" +
" </entity>\n" +
" </document>\n" +
"</dataConfig>";
private String malformedXml = "<root>\n" +
" <node>\n" +
" <id>1</id>\n" +
" <desc>test1</desc>\n" +
" </node>\n" +
" <node>\n" +
" <id>2</id>\n" +
" <desc>test2</desc>\n" +
" </node>\n" +
" <node>\n" +
" <id/>3</id>\n" +
" <desc>test3</desc>\n" +
" </node>\n" +
"</root>";
private String wellformedXml = "<root>\n" +
" <node>\n" +
" <id>1</id>\n" +
" <desc>test1</desc>\n" +
" </node>\n" +
" <node>\n" +
" <id>2</id>\n" +
" <desc>test2</desc>\n" +
" </node>\n" +
" <node>\n" +
" <id>3</id>\n" +
" <desc>test3</desc>\n" +
" </node>\n" +
"</root>";
}