blob: 38a18d78543b202ab0b1124620afb2e93e4eb733 [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.cloud.api.collections;
import java.io.IOException;
import java.io.OutputStream;
import java.net.URI;
import org.apache.lucene.store.Directory;
import org.apache.lucene.store.IOContext;
import org.apache.lucene.store.IndexInput;
import org.apache.lucene.tests.util.LuceneTestCase;
import org.apache.solr.client.solrj.SolrServerException;
import org.apache.solr.client.solrj.impl.CloudSolrClient;
import org.apache.solr.client.solrj.request.CollectionAdminRequest;
import org.apache.solr.cloud.MiniSolrCloudCluster;
import org.apache.solr.cloud.SolrCloudTestCase;
import org.apache.solr.cloud.ZkConfigSetService;
import org.apache.solr.common.SolrException;
import org.apache.solr.common.SolrException.ErrorCode;
import org.apache.solr.core.backup.repository.LocalFileSystemRepository;
import org.junit.BeforeClass;
import org.junit.Test;
/**
* This class implements the tests for local file-system integration for Solr backup/restore
* capability. Note that the Solr backup/restore still requires a "shared" file-system. Its just
* that in this case such file-system would be exposed via local file-system API.
*/
// Backups do checksum validation against a footer value not present in 'SimpleText'
@LuceneTestCase.SuppressCodecs({"SimpleText"})
@SolrCloudTestCase.NoPrs // disabled PRS for a while to enure if that is causing test failures
public class TestLocalFSCloudBackupRestore extends AbstractCloudBackupRestoreTestCase {
private static String backupLocation;
@BeforeClass
public static void setupClass() throws Exception {
String solrXml = MiniSolrCloudCluster.DEFAULT_CLOUD_SOLR_XML;
String poisoned =
" <repository name=\""
+ TestLocalFSCloudBackupRestore.poisoned
+ "\" default=\"true\" "
+ "class=\"org.apache.solr.cloud.api.collections.TestLocalFSCloudBackupRestore$PoisonedRepository\"> \n"
+ " </repository>\n";
String local =
" <repository name=\"local\" "
+ "class=\"org.apache.solr.core.backup.repository.LocalFileSystemRepository\"> \n"
+ " </repository>\n";
solrXml =
solrXml.replace(
"</solr>",
"<backup>"
+ (random().nextBoolean() ? poisoned + local : local + poisoned)
+ "</backup>"
+ "</solr>");
configureCluster(NUM_SHARDS) // nodes
.addConfig(
"conf1", TEST_PATH().resolve("configsets").resolve("cloud-minimal").resolve("conf"))
.addConfig(
"confFaulty",
TEST_PATH().resolve("configsets").resolve("cloud-minimal").resolve("conf"))
.withSolrXml(solrXml)
.configure();
cluster
.getZkClient()
.delete(
ZkConfigSetService.CONFIGS_ZKNODE + "/" + "confFaulty" + "/" + "solrconfig.xml",
-1,
true);
boolean whitespacesInPath = random().nextBoolean();
if (whitespacesInPath) {
backupLocation = createTempDir("my backup").toAbsolutePath().toString();
} else {
backupLocation = createTempDir("mybackup").toAbsolutePath().toString();
}
}
@Override
public String getCollectionNamePrefix() {
return "backuprestore";
}
@Override
public String getBackupRepoName() {
return "local";
}
@Override
public String getBackupLocation() {
return backupLocation;
}
@Override
@Test
public void test() throws Exception {
super.test();
CloudSolrClient solrClient = cluster.getSolrClient();
errorBackup(solrClient);
errorRestore(solrClient);
}
private void errorRestore(CloudSolrClient solrClient) throws SolrServerException, IOException {
String backupName = BACKUPNAME_PREFIX + testSuffix;
CollectionAdminRequest.Restore restore =
CollectionAdminRequest.restoreCollection(getCollectionName() + "boo", backupName)
.setLocation(backupLocation);
if (random().nextBoolean()) {
restore.setRepositoryName(poisoned);
}
try {
restore.process(solrClient);
fail("This request should have failed since omitting repo, picks up default poisoned.");
} catch (SolrException ex) {
assertEquals(ErrorCode.SERVER_ERROR.code, ex.code());
assertTrue(ex.getMessage(), ex.getMessage().contains(poisoned));
}
}
private void errorBackup(CloudSolrClient solrClient) throws SolrServerException, IOException {
CollectionAdminRequest.Backup backup =
CollectionAdminRequest.backupCollection(getCollectionName(), "poisonedbackup")
.setLocation(getBackupLocation());
if (random().nextBoolean()) {
backup.setRepositoryName(poisoned);
} // otherwise, we hit default
try {
backup.process(solrClient);
fail("This request should have failed since omitting repo, picks up default poisoned.");
} catch (SolrException ex) {
assertEquals(ErrorCode.SERVER_ERROR.code, ex.code());
}
}
private static final String poisoned = "poisoned";
// let it go through collection handler, and break only when real thing is doing:
// Restore/BackupCore
public static class PoisonedRepository extends LocalFileSystemRepository {
public PoisonedRepository() {
super();
}
@Override
public void copyFileFrom(Directory sourceDir, String fileName, URI dest) {
throw new UnsupportedOperationException(poisoned);
}
@Override
public void copyFileTo(URI sourceDir, String fileName, Directory dest) {
throw new UnsupportedOperationException(poisoned);
}
@Override
public IndexInput openInput(URI dirPath, String fileName, IOContext ctx) {
throw new UnsupportedOperationException(poisoned);
}
@Override
public OutputStream createOutput(URI path) {
throw new UnsupportedOperationException(poisoned);
}
}
}