/*
* Licensed to CRATE Technology GmbH ("Crate") under one or more contributor
* license agreements. See the NOTICE file distributed with this work for
* additional information regarding copyright ownership. Crate 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.
*
* However, if you have executed another commercial license agreement
* with Crate these terms will supersede the license and you may use the
* software solely pursuant to the terms of the relevant commercial agreement.
*/
package io.crate.analyze;
import com.google.common.collect.ImmutableList;
import io.crate.exceptions.*;
import io.crate.metadata.PartitionName;
import io.crate.metadata.TableIdent;
import io.crate.test.integration.CrateDummyClusterServiceUnitTest;
import io.crate.testing.SQLExecutor;
import org.apache.lucene.util.BytesRef;
import org.elasticsearch.cluster.ClusterName;
import org.elasticsearch.cluster.ClusterState;
import org.elasticsearch.cluster.metadata.MetaData;
import org.elasticsearch.cluster.metadata.RepositoriesMetaData;
import org.elasticsearch.cluster.metadata.RepositoryMetaData;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.test.ClusterServiceUtils;
import org.junit.Before;
import org.junit.Test;
import static io.crate.analyze.TableDefinitions.*;
import static org.hamcrest.Matchers.*;
public class SnapshotRestoreAnalyzerTest extends CrateDummyClusterServiceUnitTest {
private SQLExecutor executor;
@Before
public void prepare() {
RepositoriesMetaData repositoriesMetaData = new RepositoriesMetaData(
new RepositoryMetaData(
"my_repo",
"fs",
Settings.builder().put("location", "/tmp/my_repo").build()
));
ClusterState clusterState = ClusterState.builder(new ClusterName("testing"))
.metaData(MetaData.builder()
.putCustom(RepositoriesMetaData.TYPE, repositoriesMetaData))
.build();
ClusterServiceUtils.setState(clusterService, clusterState);
executor = SQLExecutor.builder(clusterService)
.addDocTable(USER_TABLE_INFO)
.addDocTable(TEST_DOC_LOCATIONS_TABLE_INFO)
.addDocTable(TEST_PARTITIONED_TABLE_INFO)
.build();
}
private <T> T analyze(String statement) {
return executor.analyze(statement);
}
@Test
public void testCreateSnapshotAll() throws Exception {
CreateSnapshotAnalyzedStatement statement = analyze("CREATE SNAPSHOT my_repo.my_snapshot ALL WITH (wait_for_completion=true)");
assertThat(statement.indices(), is(CreateSnapshotAnalyzedStatement.ALL_INDICES));
assertThat(statement.snapshot().getRepository(), is("my_repo"));
assertThat(statement.snapshot().getSnapshotId().getName(), is("my_snapshot"));
assertThat(statement.snapshotSettings().getAsMap(),
allOf(
hasEntry("wait_for_completion", "true"),
hasEntry("ignore_unavailable", "false")
));
}
@Test
public void testCreateSnapshotUnknownRepo() throws Exception {
expectedException.expect(RepositoryUnknownException.class);
expectedException.expectMessage("Repository 'unknown_repo' unknown");
analyze("CREATE SNAPSHOT unknown_repo.my_snapshot ALL");
}
@Test
public void testCreateSnapshotUnsupportedParameter() throws Exception {
expectedException.expect(IllegalArgumentException.class);
expectedException.expectMessage("setting 'foo' not supported");
analyze("CREATE SNAPSHOT my_repo.my_snapshot ALL with (foo=true)");
}
@Test
public void testCreateSnapshotUnknownTables() throws Exception {
expectedException.expect(TableUnknownException.class);
expectedException.expectMessage("Table 'doc.t2' unknown");
analyze("CREATE SNAPSHOT my_repo.my_snapshot TABLE users, t2, custom.users");
}
@Test
public void testCreateSnapshotUnknownSchema() throws Exception {
expectedException.expect(SchemaUnknownException.class);
expectedException.expectMessage("Schema 'myschema' unknown");
analyze("CREATE SNAPSHOT my_repo.my_snapshot TABLE users, myschema.users");
}
@Test
public void testCreateSnapshotUnknownPartition() throws Exception {
expectedException.expect(PartitionUnknownException.class);
expectedException.expectMessage("No partition for table 'doc.parted' with ident '04130' exists");
analyze("CREATE SNAPSHOT my_repo.my_snapshot TABLE parted PARTITION (date='1970-01-01')");
}
@Test
public void testCreateSnapshotUnknownTableIgnore() throws Exception {
CreateSnapshotAnalyzedStatement statement = analyze("CREATE SNAPSHOT my_repo.my_snapshot TABLE users, t2 WITH (ignore_unavailable=true)");
assertThat(statement.indices(), contains("users"));
assertThat(statement.snapshotSettings().getAsBoolean(SnapshotSettings.IGNORE_UNAVAILABLE.name(), false), is(true));
}
@Test
public void testCreateSnapshotUnknownSchemaIgnore() throws Exception {
CreateSnapshotAnalyzedStatement statement = analyze("CREATE SNAPSHOT my_repo.my_snapshot TABLE users, my_schema.t2 WITH (ignore_unavailable=true)");
assertThat(statement.indices(), contains("users"));
assertThat(statement.snapshotSettings().getAsBoolean(SnapshotSettings.IGNORE_UNAVAILABLE.name(), false), is(true));
}
@Test
public void testCreateSnapshotCreateSnapshotTables() throws Exception {
CreateSnapshotAnalyzedStatement statement = analyze("CREATE SNAPSHOT my_repo.my_snapshot TABLE users, locations WITH (wait_for_completion=true)");
assertThat(statement.indices(), containsInAnyOrder("users", "locations"));
assertThat(statement.snapshot().getRepository(), is("my_repo"));
assertThat(statement.snapshot().getSnapshotId().getName(), is("my_snapshot"));
assertThat(statement.snapshotSettings().getAsMap().size(), is(2));
assertThat(statement.snapshotSettings().getAsMap(),
allOf(
hasEntry("wait_for_completion", "true"),
hasEntry("ignore_unavailable", "false")
));
}
@Test
public void testCreateSnapshotNoRepoName() throws Exception {
expectedException.expect(IllegalArgumentException.class);
expectedException.expectMessage("Snapshot must be specified by \"<repository_name>\".\"<snapshot_name>\"");
analyze("CREATE SNAPSHOT my_snapshot TABLE users ");
}
@Test
public void testCreateSnapshotInvalidRepoName() throws Exception {
expectedException.expect(IllegalArgumentException.class);
expectedException.expectMessage("Invalid repository name 'my.repo'");
analyze("CREATE SNAPSHOT my.repo.my_snapshot ALL");
}
@Test
public void testCreateSnapshotSnapshotSysTable() throws Exception {
expectedException.expect(UnsupportedOperationException.class);
expectedException.expectMessage("The relation \"sys.shards\" doesn't support or allow " +
"CREATE SNAPSHOT operations, as it is read-only.");
analyze("CREATE SNAPSHOT my_repo.my_snapshot TABLE sys.shards");
}
@Test
public void testCreateSnapshotNoWildcards() throws Exception {
expectedException.expect(TableUnknownException.class);
expectedException.expectMessage("Table 'doc.user*' unknown");
analyze("CREATE SNAPSHOT my_repo.my_snapshot TABLE \"user*\"");
}
@Test
public void testCreateSnapshotListTablesTwice() throws Exception {
CreateSnapshotAnalyzedStatement statement = analyze("CREATE SNAPSHOT my_repo.my_snapshot TABLE users, locations, users");
assertThat(statement.indices(), hasSize(2));
assertThat(statement.indices(), containsInAnyOrder("users", "locations"));
}
@Test
public void testCreateSnapshotListPartitionsAndPartitionedTable() throws Exception {
CreateSnapshotAnalyzedStatement statement = analyze("CREATE SNAPSHOT my_repo.my_snapshot TABLE parted, parted PARTITION (date=1395961200000)");
assertThat(statement.indices(), hasSize(3));
assertThat(statement.indices(), containsInAnyOrder(".partitioned.parted.04732cpp6ks3ed1o60o30c1g", ".partitioned.parted.0400", ".partitioned.parted.04732cpp6ksjcc9i60o30c1g"));
}
@Test
public void testDropSnapshot() throws Exception {
DropSnapshotAnalyzedStatement statement = analyze("drop snapshot my_repo.my_snap_1");
assertThat(statement.repository(), is("my_repo"));
assertThat(statement.snapshot(), is("my_snap_1"));
}
@Test
public void testDropSnapshotUnknownRepo() throws Exception {
expectedException.expect(RepositoryUnknownException.class);
expectedException.expectMessage("Repository 'unknown_repo' unknown");
analyze("drop snapshot unknown_repo.my_snap_1");
}
@Test
public void testRestoreSnapshotAll() throws Exception {
RestoreSnapshotAnalyzedStatement statement = analyze("RESTORE SNAPSHOT my_repo.my_snapshot ALL");
assertThat(statement.snapshotName(), is("my_snapshot"));
assertThat(statement.repositoryName(), is("my_repo"));
assertThat(statement.restoreAll(), is(true));
assertThat(statement.restoreAll(), is(true));
assertThat(statement.settings().getAsMap(), // default settings
allOf(
hasEntry("wait_for_completion", "false"),
hasEntry("ignore_unavailable", "false")
));
}
@Test
public void testRestoreSnapshotSingleTable() throws Exception {
RestoreSnapshotAnalyzedStatement statement = analyze(
"RESTORE SNAPSHOT my_repo.my_snapshot TABLE custom.restoreme");
assertThat(statement.restoreTables().get(0).tableIdent(), is(new TableIdent("custom", "restoreme")));
assertThat(statement.restoreTables().get(0).partitionName(), is(nullValue()));
assertThat(statement.settings().getAsMap(),
allOf(
hasEntry("wait_for_completion", "false"),
hasEntry("ignore_unavailable", "false")
));
}
@Test
public void testRestoreExistingTable() throws Exception {
expectedException.expect(TableAlreadyExistsException.class);
expectedException.expectMessage("The table 'doc.users' already exists.");
analyze("RESTORE SNAPSHOT my_repo.my_snapshot TABLE users");
}
@Test
public void testRestoreUnsupportedParameter() throws Exception {
expectedException.expect(IllegalArgumentException.class);
expectedException.expectMessage("setting 'foo' not supported");
analyze("RESTORE SNAPSHOT my_repo.my_snapshot TABLE users WITH (foo=true)");
}
@Test
public void testRestoreSinglePartition() throws Exception {
RestoreSnapshotAnalyzedStatement statement = analyze(
"RESTORE SNAPSHOT my_repo.my_snapshot TABLE parted PARTITION (date=123)");
PartitionName partition = new PartitionName("parted", ImmutableList.of(new BytesRef("123")));
assertThat(statement.restoreTables().size(), is(1));
assertThat(statement.restoreTables().get(0).partitionName(), is(partition));
assertThat(statement.restoreTables().get(0).tableIdent(), is(new TableIdent(null, "parted")));
}
@Test
public void testRestoreSinglePartitionToUnknownTable() throws Exception {
RestoreSnapshotAnalyzedStatement statement = analyze(
"RESTORE SNAPSHOT my_repo.my_snapshot TABLE unknown_parted PARTITION (date=123)");
PartitionName partitionName = new PartitionName("unknown_parted", ImmutableList.of(new BytesRef("123")));
assertThat(statement.restoreTables().size(), is(1));
assertThat(statement.restoreTables().get(0).partitionName(), is(partitionName));
assertThat(statement.restoreTables().get(0).tableIdent(), is(new TableIdent(null, "unknown_parted")));
}
@Test
public void testRestoreSingleExistingPartition() throws Exception {
expectedException.expect(PartitionAlreadyExistsException.class);
expectedException.expectMessage("Partition '.partitioned.parted.04732cpp6ksjcc9i60o30c1g' already exists");
analyze("RESTORE SNAPSHOT my_repo.my_snapshot TABLE parted PARTITION (date=1395961200000)");
}
@Test
public void testRestoreUnknownRepo() throws Exception {
expectedException.expect(RepositoryUnknownException.class);
expectedException.expectMessage("Repository 'unknown_repo' unknown");
analyze("RESTORE SNAPSHOT unknown_repo.my_snapshot ALL");
}
}