This is an automated email from the ASF dual-hosted git repository. mmiller pushed a commit to branch main in repository https://gitbox.apache.org/repos/asf/accumulo.git
The following commit(s) were added to refs/heads/main by this push: new 8b8a6f7 Refactor Shell ITs (#2503) 8b8a6f7 is described below commit 8b8a6f7339fdcfbf4118c6164eb47035d857f0d9 Author: Mike Miller <mmil...@apache.org> AuthorDate: Fri Feb 18 04:49:10 2022 -0500 Refactor Shell ITs (#2503) * Create ShellCreateTableIT from tests moved from ShellServerIT to help with debugging * Create MockShell class * Modify ShellServerIT to not delete tables after ever test * Move ShellConfigIT into shell package * Move ShellIT into shell package --- .../org/apache/accumulo/test/VolumeChooserIT.java | 2 +- .../accumulo/test/shell/ErrorMessageCallback.java | 48 ++ .../org/apache/accumulo/test/shell/MockShell.java | 185 +++++ .../accumulo/test/{ => shell}/ShellConfigIT.java | 10 +- .../accumulo/test/shell/ShellCreateTableIT.java | 713 ++++++++++++++++++ .../apache/accumulo/test/{ => shell}/ShellIT.java | 2 +- .../accumulo/test/{ => shell}/ShellServerIT.java | 827 +-------------------- 7 files changed, 957 insertions(+), 830 deletions(-) diff --git a/test/src/main/java/org/apache/accumulo/test/VolumeChooserIT.java b/test/src/main/java/org/apache/accumulo/test/VolumeChooserIT.java index bb474ea..6419c6c 100644 --- a/test/src/main/java/org/apache/accumulo/test/VolumeChooserIT.java +++ b/test/src/main/java/org/apache/accumulo/test/VolumeChooserIT.java @@ -65,7 +65,7 @@ public class VolumeChooserIT extends ConfigurableMacBase { private static final String TP = Property.TABLE_ARBITRARY_PROP_PREFIX.getKey(); static final String PREFERRED_CHOOSER_PROP = TP + "volume.preferred"; - static final String PERTABLE_CHOOSER_PROP = TP + "volume.chooser"; + public static final String PERTABLE_CHOOSER_PROP = TP + "volume.chooser"; private static final String GP = Property.GENERAL_ARBITRARY_PROP_PREFIX.getKey(); diff --git a/test/src/main/java/org/apache/accumulo/test/shell/ErrorMessageCallback.java b/test/src/main/java/org/apache/accumulo/test/shell/ErrorMessageCallback.java new file mode 100644 index 0000000..98ac0a1 --- /dev/null +++ b/test/src/main/java/org/apache/accumulo/test/shell/ErrorMessageCallback.java @@ -0,0 +1,48 @@ +/* + * 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.accumulo.test.shell; + +import java.util.Properties; + +import org.apache.accumulo.core.client.Accumulo; +import org.apache.accumulo.core.client.AccumuloClient; + +public class ErrorMessageCallback { + private final String errorMessage; + + public ErrorMessageCallback(Properties properties) { + errorMessage = checkAuths(properties); + } + + public ErrorMessageCallback() { + errorMessage = ""; + } + + private String checkAuths(Properties properties) { + try (AccumuloClient c = Accumulo.newClient().from(properties).build()) { + return "Current auths for root are: " + c.securityOperations().getUserAuthorizations("root"); + } catch (Exception e) { + return "Could not check authorizations"; + } + } + + public String getErrorMessage() { + return errorMessage; + } +} diff --git a/test/src/main/java/org/apache/accumulo/test/shell/MockShell.java b/test/src/main/java/org/apache/accumulo/test/shell/MockShell.java new file mode 100644 index 0000000..b7ae57e --- /dev/null +++ b/test/src/main/java/org/apache/accumulo/test/shell/MockShell.java @@ -0,0 +1,185 @@ +/* + * 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.accumulo.test.shell; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; + +import java.io.File; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; + +import org.apache.accumulo.core.clientImpl.ClientInfo; +import org.apache.accumulo.shell.Shell; +import org.jline.reader.LineReader; +import org.jline.reader.LineReaderBuilder; +import org.jline.terminal.Size; +import org.jline.terminal.Terminal; +import org.jline.terminal.impl.DumbTerminal; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class MockShell { + private static final Logger shellLog = LoggerFactory.getLogger(MockShell.class); + private static final ErrorMessageCallback noop = new ErrorMessageCallback(); + + public TestOutputStream output; + public StringInputStream input; + public Shell shell; + public LineReader reader; + public Terminal terminal; + + MockShell(String user, String rootPass, String instanceName, String zookeepers, File configFile) + throws IOException { + ClientInfo info = ClientInfo.from(configFile.toPath()); + // start the shell + output = new TestOutputStream(); + input = new StringInputStream(); + terminal = new DumbTerminal(input, output); + terminal.setSize(new Size(80, 24)); + reader = LineReaderBuilder.builder().terminal(terminal).build(); + shell = new Shell(reader); + shell.setLogErrorsToConsole(); + if (info.saslEnabled()) { + // Pull the kerberos principal out when we're using SASL + shell.config("-u", user, "-z", instanceName, zookeepers, "--config-file", + configFile.getAbsolutePath()); + } else { + shell.config("-u", user, "-p", rootPass, "-z", instanceName, zookeepers, "--config-file", + configFile.getAbsolutePath()); + } + exec("quit", true); + shell.start(); + shell.setExit(false); + } + + String exec(String cmd) throws IOException { + output.clear(); + shell.execCommand(cmd, true, true); + return output.get(); + } + + String exec(String cmd, boolean expectGoodExit) throws IOException { + return exec(cmd, expectGoodExit, noop); + } + + String exec(String cmd, boolean expectGoodExit, ErrorMessageCallback callback) + throws IOException { + String result = exec(cmd); + if (expectGoodExit) + assertGoodExit("", true, callback); + else + assertBadExit("", true, callback); + return result; + } + + String exec(String cmd, boolean expectGoodExit, String expectString) throws IOException { + return exec(cmd, expectGoodExit, expectString, noop); + } + + String exec(String cmd, boolean expectGoodExit, String expectString, + ErrorMessageCallback callback) throws IOException { + return exec(cmd, expectGoodExit, expectString, true, callback); + } + + String exec(String cmd, boolean expectGoodExit, String expectString, boolean stringPresent) + throws IOException { + return exec(cmd, expectGoodExit, expectString, stringPresent, noop); + } + + String exec(String cmd, boolean expectGoodExit, String expectString, boolean stringPresent, + ErrorMessageCallback callback) throws IOException { + String result = exec(cmd); + if (expectGoodExit) + assertGoodExit(expectString, stringPresent, callback); + else + assertBadExit(expectString, stringPresent, callback); + return result; + } + + void assertGoodExit(String s, boolean stringPresent) { + assertGoodExit(s, stringPresent, noop); + } + + void assertGoodExit(String s, boolean stringPresent, ErrorMessageCallback callback) { + shellLog.debug("Shell Output: '{}'", output.get()); + if (shell.getExitCode() != 0) { + String errorMsg = callback.getErrorMessage(); + assertEquals(errorMsg, 0, shell.getExitCode()); + } + + if (!s.isEmpty()) + assertEquals(s + " present in " + output.get() + " was not " + stringPresent, stringPresent, + output.get().contains(s)); + } + + void assertBadExit(String s, boolean stringPresent, ErrorMessageCallback callback) { + shellLog.debug(output.get()); + if (shell.getExitCode() == 0) { + String errorMsg = callback.getErrorMessage(); + assertTrue(errorMsg, shell.getExitCode() > 0); + } + + if (!s.isEmpty()) + assertEquals(s + " present in " + output.get() + " was not " + stringPresent, stringPresent, + output.get().contains(s)); + shell.resetExitCode(); + } + + void writeToHistory(String cmd) { + input.set(cmd); + reader.readLine(); + } + + static class TestOutputStream extends OutputStream { + StringBuilder sb = new StringBuilder(); + + @Override + public void write(int b) { + sb.append((char) (0xff & b)); + } + + public String get() { + return sb.toString(); + } + + public void clear() { + sb.setLength(0); + } + } + + static class StringInputStream extends InputStream { + private String source = ""; + private int offset = 0; + + @Override + public int read() { + if (offset == source.length()) + return '\n'; + else + return source.charAt(offset++); + } + + public void set(String other) { + source = other; + offset = 0; + } + } +} diff --git a/test/src/main/java/org/apache/accumulo/test/ShellConfigIT.java b/test/src/main/java/org/apache/accumulo/test/shell/ShellConfigIT.java similarity index 94% rename from test/src/main/java/org/apache/accumulo/test/ShellConfigIT.java rename to test/src/main/java/org/apache/accumulo/test/shell/ShellConfigIT.java index 308bbbd..f7b1667 100644 --- a/test/src/main/java/org/apache/accumulo/test/ShellConfigIT.java +++ b/test/src/main/java/org/apache/accumulo/test/shell/ShellConfigIT.java @@ -16,7 +16,7 @@ * specific language governing permissions and limitations * under the License. */ -package org.apache.accumulo.test; +package org.apache.accumulo.test.shell; import static java.nio.charset.StandardCharsets.UTF_8; import static org.apache.accumulo.test.VolumeChooserIT.PERTABLE_CHOOSER_PROP; @@ -36,7 +36,7 @@ import org.apache.accumulo.core.conf.Property; import org.apache.accumulo.harness.AccumuloClusterHarness; import org.apache.accumulo.harness.conf.StandaloneAccumuloClusterConfiguration; import org.apache.accumulo.miniclusterImpl.MiniAccumuloClusterImpl; -import org.apache.accumulo.test.ShellServerIT.TestShell; +import org.apache.accumulo.test.FairVolumeChooser; import org.junit.After; import org.junit.Before; import org.junit.Test; @@ -95,13 +95,13 @@ public class ShellConfigIT extends AccumuloClusterHarness { assertNotNull(clientPropsFile); - TestShell ts = null; + MockShell ts = null; if (token instanceof PasswordToken) { String passwd = new String(((PasswordToken) token).getPassword(), UTF_8); - ts = new TestShell(getAdminPrincipal(), passwd, getCluster().getInstanceName(), + ts = new MockShell(getAdminPrincipal(), passwd, getCluster().getInstanceName(), getCluster().getZooKeepers(), clientPropsFile); } else if (token instanceof KerberosToken) { - ts = new TestShell(getAdminPrincipal(), null, getCluster().getInstanceName(), + ts = new MockShell(getAdminPrincipal(), null, getCluster().getInstanceName(), getCluster().getZooKeepers(), clientPropsFile); } else { fail("Unknown token type"); diff --git a/test/src/main/java/org/apache/accumulo/test/shell/ShellCreateTableIT.java b/test/src/main/java/org/apache/accumulo/test/shell/ShellCreateTableIT.java new file mode 100644 index 0000000..2499b16 --- /dev/null +++ b/test/src/main/java/org/apache/accumulo/test/shell/ShellCreateTableIT.java @@ -0,0 +1,713 @@ +/* + * 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.accumulo.test.shell; + +import static java.nio.charset.StandardCharsets.UTF_8; +import static java.nio.file.Files.newBufferedReader; +import static java.util.Objects.requireNonNull; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertThrows; +import static org.junit.Assert.assertTrue; + +import java.io.BufferedReader; +import java.io.BufferedWriter; +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Paths; +import java.util.ArrayList; +import java.util.Base64; +import java.util.Collection; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.SortedSet; +import java.util.TreeSet; +import java.util.UUID; + +import org.apache.accumulo.core.client.Accumulo; +import org.apache.accumulo.core.client.AccumuloClient; +import org.apache.accumulo.core.client.AccumuloException; +import org.apache.accumulo.core.client.AccumuloSecurityException; +import org.apache.accumulo.core.client.TableNotFoundException; +import org.apache.accumulo.core.util.TextUtil; +import org.apache.accumulo.harness.MiniClusterConfigurationCallback; +import org.apache.accumulo.harness.SharedMiniClusterBase; +import org.apache.accumulo.miniclusterImpl.MiniAccumuloConfigImpl; +import org.apache.accumulo.test.categories.MiniClusterOnlyTests; +import org.apache.accumulo.test.categories.SunnyDayTests; +import org.apache.hadoop.conf.Configuration; +import org.apache.hadoop.io.Text; +import org.junit.After; +import org.junit.AfterClass; +import org.junit.Before; +import org.junit.BeforeClass; +import org.junit.Test; +import org.junit.experimental.categories.Category; + +@Category({MiniClusterOnlyTests.class, SunnyDayTests.class}) +public class ShellCreateTableIT extends SharedMiniClusterBase { + + private MockShell ts; + + private static class SSCTITCallback implements MiniClusterConfigurationCallback { + @Override + public void configureMiniCluster(MiniAccumuloConfigImpl cfg, Configuration coreSite) { + // Only one tserver to avoid race conditions on ZK propagation (auths and configuration) + cfg.setNumTservers(1); + // Set the min span to 0 so we will definitely get all the traces back. See ACCUMULO-4365 + Map<String,String> siteConf = cfg.getSiteConfig(); + cfg.setSiteConfig(siteConf); + } + } + + @BeforeClass + public static void setupMiniCluster() throws Exception { + SharedMiniClusterBase.startMiniClusterWithConfig(new SSCTITCallback()); + } + + @Before + public void setupShell() throws Exception { + ts = new MockShell(getPrincipal(), getRootPassword(), + getCluster().getConfig().getInstanceName(), getCluster().getConfig().getZooKeepers(), + getCluster().getConfig().getClientPropsFile()); + } + + @AfterClass + public static void tearDownAfterClass() { + SharedMiniClusterBase.stopMiniCluster(); + } + + @After + public void tearDownShell() { + ts.shell.shutdown(); + } + + @Test + public void testCreateTableWithLocalityGroups() throws Exception { + final String table = getUniqueNames(1)[0]; + ts.exec("createtable " + table + " -l locg1=fam1,fam2", true); + try (AccumuloClient accumuloClient = Accumulo.newClient().from(getClientProps()).build()) { + Map<String,Set<Text>> lMap = accumuloClient.tableOperations().getLocalityGroups(table); + Set<Text> expectedColFams = Set.of(new Text("fam1"), new Text("fam2")); + for (Map.Entry<String,Set<Text>> entry : lMap.entrySet()) { + assertEquals("locg1", entry.getKey()); + assertTrue(entry.getValue().containsAll(expectedColFams)); + } + ts.exec("deletetable -f " + table); + } + } + + /** + * Due to the existing complexity of the createtable command, the createtable help only displays + * an example of setting one locality group. It is possible to set multiple groups if needed. This + * test verifies that capability. + */ + @Test + public void testCreateTableWithMultipleLocalityGroups() throws Exception { + final String table = getUniqueNames(1)[0]; + ts.exec("createtable " + table + " -l locg1=fam1,fam2 locg2=colfam1", true); + try (AccumuloClient accumuloClient = Accumulo.newClient().from(getClientProps()).build()) { + Map<String,Set<Text>> lMap = accumuloClient.tableOperations().getLocalityGroups(table); + assertTrue(lMap.containsKey("locg1")); + assertTrue(lMap.containsKey("locg2")); + Set<Text> expectedColFams1 = Set.of(new Text("fam1"), new Text("fam2")); + Set<Text> expectedColFams2 = Set.of(new Text("colfam1")); + assertTrue(lMap.get("locg1").containsAll(expectedColFams1)); + assertTrue(lMap.get("locg2").containsAll(expectedColFams2)); + ts.exec("deletetable -f " + table); + } + } + + @Test + public void testCreateTableWithLocalityGroupsBadArguments() throws IOException { + final String table = getUniqueNames(1)[0]; + ts.exec("createtable " + table + " -l locg1 fam1,fam2", false); + ts.exec("createtable " + table + "-l", false); + ts.exec("createtable " + table + " -l locg1 = fam1,fam2", false); + ts.exec("createtable " + table + " -l locg1=fam1 ,fam2", false); + ts.exec("createtable " + table + " -l locg1=fam1,fam2 locg1=fam3,fam4", false); + ts.exec("createtable " + table + " -l locg1=fam1,fam2 locg2=fam1", false); + ts.exec("createtable " + table + " -l locg1", false); + ts.exec("createtable " + table + " group=fam1", false); + ts.exec("createtable " + table + "-l fam1,fam2", false); + } + + @Test + public void testCreateTableWithIterators() throws Exception { + final String tmpTable = "tmpTable"; + final String table = getUniqueNames(1)[0]; + + // create iterator profile + // Will use tmpTable for creating profile since setshelliter is requiring a table + // even though its command line help indicates that it is optional. Likely due to + // the fact that setshelliter extends setiter, which does require a table argument. + ts.exec("createtable " + tmpTable, true); + String output = ts.exec("tables"); + assertTrue(output.contains(tmpTable)); + + ts.input.set("\n5000\n\n"); + ts.exec("setshelliter -n itname -p 10 -pn profile1 -ageoff", true); + output = ts.exec("listshelliter"); + assertTrue(output.contains("Profile : profile1")); + + // create table making use of the iterator profile + ts.exec("createtable " + table + " -i profile1:scan,minc", true); + ts.exec("insert foo a b c", true); + ts.exec("scan", true, "foo a:b []\tc"); + ts.exec("sleep 6", true); + ts.exec("scan", true, "", true); + ts.exec("deletetable -f " + table); + ts.exec("deletetable -f " + tmpTable); + } + + /** + * Due to the existing complexity of the createtable command, the createtable help only displays + * an example of setting one iterator upon table creation. It is possible to set multiple if + * needed. This test verifies that capability. + */ + @Test + public void testCreateTableWithMultipleIterators() throws Exception { + final String tmpTable = "tmpTable"; + final String table = getUniqueNames(1)[0]; + + // create iterator profile + // Will use tmpTable for creating profile since setshelliter is requiring a table + // even though its command line help indicates that it is optional. Likely due to + // the fact that setshelliter extends setiter, which does require a table argument. + ts.exec("createtable " + tmpTable, true); + String output = ts.exec("tables"); + assertTrue(output.contains(tmpTable)); + + ts.input.set("\n5000\n\n"); + ts.exec("setshelliter -n itname -p 10 -pn profile1 -ageoff", true); + output = ts.exec("listshelliter"); + assertTrue(output.contains("Profile : profile1")); + + ts.input.set("2\n"); + ts.exec("setshelliter -n iter2 -p 11 -pn profile2 -vers", true); + output = ts.exec("listshelliter"); + assertTrue(output.contains("Profile : profile2")); + + // create table making use of the iterator profiles + ts.exec("createtable " + table + " -i profile1:scan,minc profile2:all ", true); + ts.exec("insert foo a b c", true); + ts.exec("scan", true, "foo a:b []\tc"); + ts.exec("sleep 6", true); + ts.exec("scan", true, "", true); + output = ts.exec("listiter -t " + table + " -all"); + assertTrue(output.contains("Iterator itname, scan scope options")); + assertTrue(output.contains("Iterator itname, minc scope options")); + assertFalse(output.contains("Iterator itname, majc scope options")); + assertTrue(output.contains("Iterator iter2, scan scope options")); + assertTrue(output.contains("Iterator iter2, minc scope options")); + assertTrue(output.contains("Iterator iter2, majc scope options")); + ts.exec("deletetable -f " + table); + ts.exec("deletetable -f " + tmpTable); + } + + @Test + public void testCreateTableWithIteratorsBadArguments() throws IOException { + final String tmpTable = "tmpTable"; + final String table = getUniqueNames(1)[0]; + ts.exec("createtable " + tmpTable, true); + String output = ts.exec("tables"); + assertTrue(output.contains(tmpTable)); + ts.input.set("\n5000\n\n"); + ts.exec("setshelliter -n itname -p 10 -pn profile1 -ageoff", true); + output = ts.exec("listshelliter"); + assertTrue(output.contains("Profile : profile1")); + // test various bad argument calls + ts.exec("createtable " + table + " -i noprofile:scan,minc", false); + ts.exec("createtable " + table + " -i profile1:scan,minc,all,majc", false); + ts.exec("createtable " + table + " -i profile1:scan,all,majc", false); + ts.exec("createtable " + table + " -i profile1:scan,min,majc", false); + ts.exec("createtable " + table + " -i profile1:scan,max,all", false); + ts.exec("createtable " + table + " -i profile1:", false); + ts.exec("createtable " + table + " -i profile1: ", false); + ts.exec("createtable " + table + " -i profile1:-scan", false); + ts.exec("createtable " + table + " profile1:majc", false); + ts.exec("createtable " + table + " -i profile1: all", false); + ts.exec("createtable " + table + " -i profile1: All", false); + ts.exec("createtable " + table + " -i profile1: scan", false); + ts.exec("createtable " + table + " -i profile1:minc scan", false); + ts.exec("createtable " + table + " -i profile1:minc,Scan", false); + ts.exec("createtable " + table + " -i profile1:minc, scan", false); + ts.exec("createtable " + table + " -i profile1:minc,,scan", false); + ts.exec("createtable " + table + " -i profile1:minc,minc", false); + ts.exec("createtable " + table + " -i profile1:minc,Minc", false); + ts.exec("createtable " + table + " -i profile1:minc, ,scan", false); + ts.exec("createtable " + table + "-i", false); + ts.exec("createtable " + table + "-i ", false); + ts.exec("deletetable -f " + tmpTable); + } + + /** + * Verify that table can be created in offline status and then be brought online. + */ + @Test + public void testCreateTableOffline() throws IOException { + final String tableName = getUniqueNames(1)[0]; + ts.exec("createtable " + tableName + " -o", true); + String output = ts.exec("tables"); + assertTrue(output.contains(tableName)); + output = ts.exec("scan -t " + tableName, false, "is offline", true); + assertTrue(output.contains("TableOfflineException")); + ts.exec("table " + tableName, true); + ts.exec("online", true); + ts.exec("scan", true); + ts.exec("deletetable -f " + tableName, true); + } + + /** + * Use shell to create a table with a supplied file containing splits. + * + * The splits will be contained in a file, sorted and un-encoded with no repeats or blank lines. + */ + @Test + public void testCreateTableWithSplitsFile1() + throws IOException, AccumuloSecurityException, TableNotFoundException, AccumuloException { + String splitsFile = System.getProperty("user.dir") + "/target/splitFile"; + try (AccumuloClient client = Accumulo.newClient().from(getClientProps()).build()) { + generateSplitsFile(splitsFile, 1000, 12, false, false, true, false, false); + SortedSet<Text> expectedSplits = readSplitsFromFile(splitsFile); + final String tableName = getUniqueNames(1)[0]; + ts.exec("createtable " + tableName + " -sf " + splitsFile, true); + Collection<Text> createdSplits = client.tableOperations().listSplits(tableName); + assertEquals(expectedSplits, new TreeSet<>(createdSplits)); + } finally { + Files.delete(Paths.get(splitsFile)); + } + } + + /** + * Use shell to create a table with a supplied file containing splits. + * + * The splits will be contained in a file, unsorted and un-encoded with no repeats or blank lines. + */ + @Test + public void testCreateTableWithSplitsFile2() + throws IOException, AccumuloSecurityException, TableNotFoundException, AccumuloException { + String splitsFile = System.getProperty("user.dir") + "/target/splitFile"; + try (AccumuloClient client = Accumulo.newClient().from(getClientProps()).build()) { + generateSplitsFile(splitsFile, 300, 12, false, false, false, false, false); + SortedSet<Text> expectedSplits = readSplitsFromFile(splitsFile); + final String tableName = getUniqueNames(1)[0]; + ts.exec("createtable " + tableName + " -sf " + splitsFile, true); + Collection<Text> createdSplits = client.tableOperations().listSplits(tableName); + assertEquals(expectedSplits, new TreeSet<>(createdSplits)); + } finally { + Files.delete(Paths.get(splitsFile)); + } + } + + /** + * Use shell to create a table with a supplied file containing splits. + * + * The splits will be contained in a file, sorted and encoded with no repeats or blank lines. + */ + @Test + public void testCreateTableWithSplitsFile3() + throws IOException, AccumuloSecurityException, TableNotFoundException, AccumuloException { + String splitsFile = System.getProperty("user.dir") + "/target/splitFile"; + try (AccumuloClient client = Accumulo.newClient().from(getClientProps()).build()) { + generateSplitsFile(splitsFile, 100, 23, false, true, true, false, false); + SortedSet<Text> expectedSplits = readSplitsFromFile(splitsFile); + final String tableName = getUniqueNames(1)[0]; + ts.exec("createtable " + tableName + " -sf " + splitsFile, true); + Collection<Text> createdSplits = client.tableOperations().listSplits(tableName); + assertEquals(expectedSplits, new TreeSet<>(createdSplits)); + } finally { + Files.delete(Paths.get(splitsFile)); + } + } + + /** + * Use shell to create a table with a supplied file containing splits. + * + * The splits will be contained in a file, sorted and un-encoded with a blank line and no repeats. + */ + @Test + public void testCreateTableWithSplitsFile4() + throws IOException, AccumuloSecurityException, TableNotFoundException, AccumuloException { + String splitsFile = System.getProperty("user.dir") + "/target/splitFile"; + try (AccumuloClient client = Accumulo.newClient().from(getClientProps()).build()) { + generateSplitsFile(splitsFile, 100, 31, false, false, true, true, false); + SortedSet<Text> expectedSplits = readSplitsFromFile(splitsFile); + final String tableName = getUniqueNames(1)[0]; + ts.exec("createtable " + tableName + " -sf " + splitsFile, true); + Collection<Text> createdSplits = client.tableOperations().listSplits(tableName); + assertEquals(expectedSplits, new TreeSet<>(createdSplits)); + } finally { + Files.delete(Paths.get(splitsFile)); + } + } + + /** + * Use shell to create a table with a supplied file containing splits. + * + * The splits will be contained in a file, sorted and un-encoded with a blank line and no repeats. + */ + @Test + public void testCreateTableWithSplitsFile5() + throws IOException, AccumuloSecurityException, TableNotFoundException, AccumuloException { + String splitsFile = System.getProperty("user.dir") + "/target/splitFile"; + try (AccumuloClient client = Accumulo.newClient().from(getClientProps()).build()) { + generateSplitsFile(splitsFile, 100, 32, false, false, true, false, true); + SortedSet<Text> expectedSplits = readSplitsFromFile(splitsFile); + final String tableName = getUniqueNames(1)[0]; + ts.exec("createtable " + tableName + " -sf " + splitsFile, true); + Collection<Text> createdSplits = client.tableOperations().listSplits(tableName); + assertEquals(expectedSplits, new TreeSet<>(createdSplits)); + } finally { + Files.delete(Paths.get(splitsFile)); + } + } + + /** + * Use shell to create a table with a supplied file containing splits. + * + * The splits will be contained in a file, unsorted and un-encoded with a blank line and repeats. + */ + @Test + public void testCreateTableWithSplitsFile6() + throws IOException, AccumuloSecurityException, TableNotFoundException, AccumuloException { + String splitsFile = System.getProperty("user.dir") + "/target/splitFile"; + try (AccumuloClient client = Accumulo.newClient().from(getClientProps()).build()) { + generateSplitsFile(splitsFile, 100, 12, false, false, false, true, true); + SortedSet<Text> expectedSplits = readSplitsFromFile(splitsFile); + final String tableName = getUniqueNames(1)[0]; + ts.exec("createtable " + tableName + " -sf " + splitsFile, true); + Collection<Text> createdSplits = client.tableOperations().listSplits(tableName); + assertEquals(expectedSplits, new TreeSet<>(createdSplits)); + } finally { + Files.delete(Paths.get(splitsFile)); + } + } + + /** + * Use shell to create a table with a supplied file containing splits. + * + * The splits will be contained in a file, sorted and encoded with a blank line and repeats. + */ + @Test + public void testCreateTableWithSplitsFile7() + throws IOException, AccumuloSecurityException, TableNotFoundException, AccumuloException { + String splitsFile = System.getProperty("user.dir") + "/target/splitFile"; + try (AccumuloClient client = Accumulo.newClient().from(getClientProps()).build()) { + generateSplitsFile(splitsFile, 100, 12, false, false, true, true, true); + SortedSet<Text> expectedSplits = readSplitsFromFile(splitsFile); + final String tableName = getUniqueNames(1)[0]; + ts.exec("createtable " + tableName + " -sf " + splitsFile, true); + Collection<Text> createdSplits = client.tableOperations().listSplits(tableName); + assertEquals(expectedSplits, new TreeSet<>(createdSplits)); + } finally { + Files.delete(Paths.get(splitsFile)); + } + } + + /** + * Use shell to create a table with a supplied file containing splits. + * + * The splits file will be empty. + */ + @Test + public void testCreateTableWithEmptySplitFile() + throws IOException, AccumuloSecurityException, TableNotFoundException, AccumuloException { + String splitsFile = System.getProperty("user.dir") + "/target/splitFile"; + try (AccumuloClient client = Accumulo.newClient().from(getClientProps()).build()) { + generateSplitsFile(splitsFile, 0, 0, false, false, false, false, false); + final String tableName = getUniqueNames(1)[0]; + ts.exec("createtable " + tableName + " -sf " + splitsFile, false); + assertThrows(TableNotFoundException.class, + () -> client.tableOperations().listSplits(tableName)); + } finally { + Files.delete(Paths.get(splitsFile)); + } + } + + /** + * Use shell to create a table that used splits from another table. + */ + @Test + public void testCreateTableWithCopySplitsFromOtherTable() + throws IOException, AccumuloSecurityException, TableNotFoundException, AccumuloException { + // create a table and add some splits + try (AccumuloClient client = Accumulo.newClient().from(getClientProps()).build()) { + final String[] tableNames = getUniqueNames(2); + final String tableName0 = tableNames[0]; + final String tableName2 = tableNames[1]; + + ts.exec("createtable " + tableName0, true); + String output = ts.exec("tables", true); + assertTrue(output.contains(tableName0)); + ts.exec("table " + tableName0, true); + // add splits to this table using the addsplits command. + List<Text> splits = new ArrayList<>(); + splits.add(new Text("ccccc")); + splits.add(new Text("fffff")); + splits.add(new Text("mmmmm")); + splits.add(new Text("sssss")); + ts.exec("addsplits " + splits.get(0) + " " + splits.get(1) + " " + splits.get(2) + " " + + splits.get(3), true); + // Now create a table that will used the previous tables splits and create them at table + // creation + ts.exec("createtable " + tableName2 + " --copy-splits " + tableName0, true); + ts.exec("table " + tableName0, true); + String tablesOutput = ts.exec("tables", true); + assertTrue(tablesOutput.contains(tableName2)); + Collection<Text> createdSplits = client.tableOperations().listSplits(tableName2); + assertEquals(new TreeSet<>(splits), new TreeSet<>(createdSplits)); + ts.exec("deletetable -f " + tableName0, true); + ts.exec("deletetable -f " + tableName2, true); + } + } + + /** + * Use shell to create a table with a supplied file containing splits. + * + * The splits will be contained in a file, sorted and encoded with no repeats or blank lines. + */ + @Test + public void testCreateTableWithBinarySplitsFile1() + throws IOException, AccumuloSecurityException, TableNotFoundException, AccumuloException { + String splitsFile = System.getProperty("user.dir") + "/target/splitFile"; + try (AccumuloClient client = Accumulo.newClient().from(getClientProps()).build()) { + generateSplitsFile(splitsFile, 200, 12, true, true, true, false, false); + SortedSet<Text> expectedSplits = readSplitsFromFile(splitsFile); + final String tableName = getUniqueNames(1)[0]; + ts.exec("createtable " + tableName + " -sf " + splitsFile, true); + Collection<Text> createdSplits = client.tableOperations().listSplits(tableName); + assertEquals(expectedSplits, new TreeSet<>(createdSplits)); + } finally { + Files.delete(Paths.get(splitsFile)); + } + } + + /** + * Use shell to create a table with a supplied file containing splits. + * + * The splits will be contained in a file, unsorted and encoded with no repeats or blank lines. + */ + @Test + public void testCreateTableWithBinarySplitsFile2() + throws IOException, AccumuloSecurityException, TableNotFoundException, AccumuloException { + String splitsFile = System.getProperty("user.dir") + "/target/splitFile"; + try (AccumuloClient client = Accumulo.newClient().from(getClientProps()).build()) { + generateSplitsFile(splitsFile, 300, 12, true, true, false, false, false); + SortedSet<Text> expectedSplits = readSplitsFromFile(splitsFile); + final String tableName = getUniqueNames(1)[0]; + ts.exec("createtable " + tableName + " -sf " + splitsFile, true); + Collection<Text> createdSplits = client.tableOperations().listSplits(tableName); + assertEquals(expectedSplits, new TreeSet<>(createdSplits)); + } finally { + Files.delete(Paths.get(splitsFile)); + } + } + + /** + * Use shell to create a table with a supplied file containing splits. + * + * The splits will be contained in a file, sorted and encoded with no repeats or blank lines. + */ + @Test + public void testCreateTableWithBinarySplitsFile3() + throws IOException, AccumuloSecurityException, TableNotFoundException, AccumuloException { + String splitsFile = System.getProperty("user.dir") + "/target/splitFile"; + try (AccumuloClient client = Accumulo.newClient().from(getClientProps()).build()) { + generateSplitsFile(splitsFile, 100, 23, true, true, true, false, false); + SortedSet<Text> expectedSplits = readSplitsFromFile(splitsFile); + final String tableName = getUniqueNames(1)[0]; + ts.exec("createtable " + tableName + " -sf " + splitsFile, true); + Collection<Text> createdSplits = client.tableOperations().listSplits(tableName); + assertEquals(expectedSplits, new TreeSet<>(createdSplits)); + } finally { + Files.delete(Paths.get(splitsFile)); + } + } + + /** + * Use shell to create a table with a supplied file containing splits. + * + * The splits will be contained in a file, sorted and encoded with a blank line and no repeats. + */ + @Test + public void testCreateTableWithBinarySplitsFile4() + throws IOException, AccumuloSecurityException, TableNotFoundException, AccumuloException { + String splitsFile = System.getProperty("user.dir") + "/target/splitFile"; + try (AccumuloClient client = Accumulo.newClient().from(getClientProps()).build()) { + generateSplitsFile(splitsFile, 100, 31, true, true, true, true, false); + SortedSet<Text> expectedSplits = readSplitsFromFile(splitsFile); + final String tableName = getUniqueNames(1)[0]; + ts.exec("createtable " + tableName + " -sf " + splitsFile, true); + Collection<Text> createdSplits = client.tableOperations().listSplits(tableName); + assertEquals(expectedSplits, new TreeSet<>(createdSplits)); + } finally { + Files.delete(Paths.get(splitsFile)); + } + } + + /** + * Use shell to create a table with a supplied file containing splits. + * + * The splits will be contained in a file, sorted and encoded with a blank line and no repeats. + */ + @Test + public void testCreateTableWithBinarySplitsFile5() + throws IOException, AccumuloSecurityException, TableNotFoundException, AccumuloException { + String splitsFile = System.getProperty("user.dir") + "/target/splitFile"; + try (AccumuloClient client = Accumulo.newClient().from(getClientProps()).build()) { + generateSplitsFile(splitsFile, 100, 32, true, true, true, false, true); + SortedSet<Text> expectedSplits = readSplitsFromFile(splitsFile); + final String tableName = getUniqueNames(1)[0]; + ts.exec("createtable " + tableName + " -sf " + splitsFile, true); + Collection<Text> createdSplits = client.tableOperations().listSplits(tableName); + assertEquals(expectedSplits, new TreeSet<>(createdSplits)); + } finally { + Files.delete(Paths.get(splitsFile)); + } + } + + /** + * Use shell to create a table with a supplied file containing splits. + * + * The splits will be contained in a file, unsorted and encoded with a blank line and repeats. + */ + @Test + public void testCreateTableWithBinarySplitsFile6() + throws IOException, AccumuloSecurityException, TableNotFoundException, AccumuloException { + String splitsFile = System.getProperty("user.dir") + "/target/splitFile"; + try (AccumuloClient client = Accumulo.newClient().from(getClientProps()).build()) { + generateSplitsFile(splitsFile, 100, 12, true, true, false, true, true); + SortedSet<Text> expectedSplits = readSplitsFromFile(splitsFile); + final String tableName = getUniqueNames(1)[0]; + ts.exec("createtable " + tableName + " -sf " + splitsFile, true); + Collection<Text> createdSplits = client.tableOperations().listSplits(tableName); + assertEquals(expectedSplits, new TreeSet<>(createdSplits)); + } finally { + Files.delete(Paths.get(splitsFile)); + } + } + + /** + * Use shell to create a table with a supplied file containing splits. + * + * The splits will be contained in a file, sorted and encoded with a blank line and repeats. + */ + @Test + public void testCreateTableWithBinarySplitsFile7() + throws IOException, AccumuloSecurityException, TableNotFoundException, AccumuloException { + String splitsFile = System.getProperty("user.dir") + "/target/splitFile"; + try (AccumuloClient client = Accumulo.newClient().from(getClientProps()).build()) { + generateSplitsFile(splitsFile, 100, 12, true, true, true, true, true); + SortedSet<Text> expectedSplits = readSplitsFromFile(splitsFile); + final String tableName = getUniqueNames(1)[0]; + ts.exec("createtable " + tableName + " -sf " + splitsFile, true); + Collection<Text> createdSplits = client.tableOperations().listSplits(tableName); + assertEquals(expectedSplits, new TreeSet<>(createdSplits)); + } finally { + Files.delete(Paths.get(splitsFile)); + } + } + + private SortedSet<Text> readSplitsFromFile(final String splitsFile) throws IOException { + SortedSet<Text> splits = new TreeSet<>(); + try (BufferedReader reader = newBufferedReader(Paths.get(splitsFile))) { + String split; + while ((split = reader.readLine()) != null) { + Text unencodedString = decode(split); + if (unencodedString != null) + splits.add(unencodedString); + } + } + return splits; + } + + private void generateSplitsFile(final String splitsFile, final int numItems, final int len, + final boolean binarySplits, final boolean encoded, final boolean sort, + final boolean addBlankLine, final boolean repeat) throws IOException { + + java.nio.file.Path splitsPath = java.nio.file.Paths.get(splitsFile); + int insertAt = (len % 2 == 0) ? len / 2 : (len + 1) / 2; + Collection<Text> sortedSplits = null; + Collection<Text> randomSplits; + + if (binarySplits) + randomSplits = generateBinarySplits(numItems, len); + else + randomSplits = generateNonBinarySplits(numItems, len); + + if (sort) + sortedSplits = new TreeSet<>(randomSplits); + + try (BufferedWriter writer = Files.newBufferedWriter(splitsPath, UTF_8)) { + int cnt = 0; + Collection<Text> splits; + if (sort) + splits = sortedSplits; + else + splits = randomSplits; + + for (Text text : splits) { + if (addBlankLine && cnt++ == insertAt) + writer.write('\n'); + writer.write(encode(text, encoded) + '\n'); + if (repeat) + writer.write(encode(text, encoded) + '\n'); + } + } + } + + private Collection<Text> generateNonBinarySplits(final int numItems, final int len) { + Set<Text> splits = new HashSet<>(); + for (int i = 0; i < numItems; i++) { + splits.add(getRandomText(len)); + } + return splits; + } + + private Collection<Text> generateBinarySplits(final int numItems, final int len) { + Set<Text> splits = new HashSet<>(); + for (int i = 0; i < numItems; i++) { + byte[] split = new byte[len]; + random.nextBytes(split); + splits.add(new Text(split)); + } + return splits; + } + + private Text getRandomText(final int len) { + int desiredLen = Math.min(len, 32); + return new Text( + String.valueOf(UUID.randomUUID()).replaceAll("-", "").substring(0, desiredLen - 1)); + } + + private static String encode(final Text text, final boolean encode) { + if (text.toString().isBlank()) + return null; + return encode ? Base64.getEncoder().encodeToString(TextUtil.getBytes(text)) : text.toString(); + } + + private Text decode(final String text) { + if (requireNonNull(text).isBlank()) + return null; + return new Text(text); + } +} diff --git a/test/src/main/java/org/apache/accumulo/test/ShellIT.java b/test/src/main/java/org/apache/accumulo/test/shell/ShellIT.java similarity index 99% rename from test/src/main/java/org/apache/accumulo/test/ShellIT.java rename to test/src/main/java/org/apache/accumulo/test/shell/ShellIT.java index 5a8b7a7..cdfa98f 100644 --- a/test/src/main/java/org/apache/accumulo/test/ShellIT.java +++ b/test/src/main/java/org/apache/accumulo/test/shell/ShellIT.java @@ -16,7 +16,7 @@ * specific language governing permissions and limitations * under the License. */ -package org.apache.accumulo.test; +package org.apache.accumulo.test.shell; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertTrue; diff --git a/test/src/main/java/org/apache/accumulo/test/ShellServerIT.java b/test/src/main/java/org/apache/accumulo/test/shell/ShellServerIT.java similarity index 70% rename from test/src/main/java/org/apache/accumulo/test/ShellServerIT.java rename to test/src/main/java/org/apache/accumulo/test/shell/ShellServerIT.java index 26da4af..65412dc 100644 --- a/test/src/main/java/org/apache/accumulo/test/ShellServerIT.java +++ b/test/src/main/java/org/apache/accumulo/test/shell/ShellServerIT.java @@ -16,11 +16,9 @@ * specific language governing permissions and limitations * under the License. */ -package org.apache.accumulo.test; +package org.apache.accumulo.test.shell; import static java.nio.charset.StandardCharsets.UTF_8; -import static java.nio.file.Files.newBufferedReader; -import static java.util.Objects.requireNonNull; import static org.apache.accumulo.fate.util.UtilWaitThread.sleepUninterruptibly; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; @@ -30,41 +28,26 @@ import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; import java.io.BufferedReader; -import java.io.BufferedWriter; import java.io.File; import java.io.FileReader; import java.io.IOException; -import java.io.InputStream; -import java.io.OutputStream; import java.io.PrintWriter; import java.lang.reflect.Constructor; -import java.nio.file.Files; -import java.nio.file.Paths; import java.util.ArrayList; import java.util.Arrays; -import java.util.Base64; -import java.util.Collection; import java.util.Collections; -import java.util.HashSet; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Map.Entry; -import java.util.Set; -import java.util.SortedSet; -import java.util.TreeSet; -import java.util.UUID; import java.util.concurrent.TimeUnit; import java.util.regex.Pattern; import org.apache.accumulo.core.Constants; import org.apache.accumulo.core.client.Accumulo; import org.apache.accumulo.core.client.AccumuloClient; -import org.apache.accumulo.core.client.AccumuloException; -import org.apache.accumulo.core.client.AccumuloSecurityException; import org.apache.accumulo.core.client.IteratorSetting; import org.apache.accumulo.core.client.Scanner; -import org.apache.accumulo.core.client.TableNotFoundException; import org.apache.accumulo.core.client.admin.TableOperations; import org.apache.accumulo.core.client.sample.RowSampler; import org.apache.accumulo.core.client.security.tokens.AuthenticationToken; @@ -84,13 +67,11 @@ import org.apache.accumulo.core.file.FileOperations; import org.apache.accumulo.core.file.FileSKVWriter; import org.apache.accumulo.core.metadata.MetadataTable; import org.apache.accumulo.core.security.Authorizations; -import org.apache.accumulo.core.util.TextUtil; import org.apache.accumulo.core.util.format.Formatter; import org.apache.accumulo.core.util.format.FormatterConfig; import org.apache.accumulo.harness.MiniClusterConfigurationCallback; import org.apache.accumulo.harness.SharedMiniClusterBase; import org.apache.accumulo.miniclusterImpl.MiniAccumuloConfigImpl; -import org.apache.accumulo.shell.Shell; import org.apache.accumulo.test.categories.MiniClusterOnlyTests; import org.apache.accumulo.test.categories.SunnyDayTests; import org.apache.accumulo.test.compaction.TestCompactionStrategy; @@ -100,11 +81,7 @@ import org.apache.hadoop.fs.FileSystem; import org.apache.hadoop.fs.Path; import org.apache.hadoop.io.Text; import org.apache.hadoop.tools.DistCp; -import org.jline.reader.LineReader; -import org.jline.reader.LineReaderBuilder; -import org.jline.terminal.Size; import org.jline.terminal.Terminal; -import org.jline.terminal.impl.DumbTerminal; import org.junit.After; import org.junit.AfterClass; import org.junit.Assume; @@ -129,170 +106,9 @@ public class ShellServerIT extends SharedMiniClusterBase { private static final Property VFS_CONTEXT_CLASSPATH_PROPERTY = Property.VFS_CONTEXT_CLASSPATH_PROPERTY; - public static class TestOutputStream extends OutputStream { - StringBuilder sb = new StringBuilder(); - - @Override - public void write(int b) { - sb.append((char) (0xff & b)); - } - - public String get() { - return sb.toString(); - } - - public void clear() { - sb.setLength(0); - } - } - private static final Logger log = LoggerFactory.getLogger(ShellServerIT.class); - public static class StringInputStream extends InputStream { - private String source = ""; - private int offset = 0; - - @Override - public int read() { - if (offset == source.length()) - return '\n'; - else - return source.charAt(offset++); - } - - public void set(String other) { - source = other; - offset = 0; - } - } - - private abstract static class ErrorMessageCallback { - public abstract String getErrorMessage(); - } - - private static class NoOpErrorMessageCallback extends ErrorMessageCallback { - private static final String empty = ""; - - @Override - public String getErrorMessage() { - return empty; - } - } - - public static class TestShell { - private static final Logger shellLog = LoggerFactory.getLogger(TestShell.class); - public TestOutputStream output; - public StringInputStream input; - public Shell shell; - public LineReader reader; - public Terminal terminal; - - TestShell(String user, String rootPass, String instanceName, String zookeepers, File configFile) - throws IOException { - ClientInfo info = ClientInfo.from(configFile.toPath()); - // start the shell - output = new TestOutputStream(); - input = new StringInputStream(); - terminal = new DumbTerminal(input, output); - terminal.setSize(new Size(80, 24)); - reader = LineReaderBuilder.builder().terminal(terminal).build(); - shell = new Shell(reader); - shell.setLogErrorsToConsole(); - if (info.saslEnabled()) { - // Pull the kerberos principal out when we're using SASL - shell.config("-u", user, "-z", instanceName, zookeepers, "--config-file", - configFile.getAbsolutePath()); - } else { - shell.config("-u", user, "-p", rootPass, "-z", instanceName, zookeepers, "--config-file", - configFile.getAbsolutePath()); - } - exec("quit", true); - shell.start(); - shell.setExit(false); - } - - String exec(String cmd) throws IOException { - output.clear(); - shell.execCommand(cmd, true, true); - return output.get(); - } - - String exec(String cmd, boolean expectGoodExit) throws IOException { - return exec(cmd, expectGoodExit, noop); - } - - String exec(String cmd, boolean expectGoodExit, ErrorMessageCallback callback) - throws IOException { - String result = exec(cmd); - if (expectGoodExit) - assertGoodExit("", true, callback); - else - assertBadExit("", true, callback); - return result; - } - - String exec(String cmd, boolean expectGoodExit, String expectString) throws IOException { - return exec(cmd, expectGoodExit, expectString, noop); - } - - String exec(String cmd, boolean expectGoodExit, String expectString, - ErrorMessageCallback callback) throws IOException { - return exec(cmd, expectGoodExit, expectString, true, callback); - } - - String exec(String cmd, boolean expectGoodExit, String expectString, boolean stringPresent) - throws IOException { - return exec(cmd, expectGoodExit, expectString, stringPresent, noop); - } - - String exec(String cmd, boolean expectGoodExit, String expectString, boolean stringPresent, - ErrorMessageCallback callback) throws IOException { - String result = exec(cmd); - if (expectGoodExit) - assertGoodExit(expectString, stringPresent, callback); - else - assertBadExit(expectString, stringPresent, callback); - return result; - } - - void assertGoodExit(String s, boolean stringPresent) { - assertGoodExit(s, stringPresent, noop); - } - - void assertGoodExit(String s, boolean stringPresent, ErrorMessageCallback callback) { - shellLog.debug("Shell Output: '{}'", output.get()); - if (shell.getExitCode() != 0) { - String errorMsg = callback.getErrorMessage(); - assertEquals(errorMsg, 0, shell.getExitCode()); - } - - if (!s.isEmpty()) - assertEquals(s + " present in " + output.get() + " was not " + stringPresent, stringPresent, - output.get().contains(s)); - } - - void assertBadExit(String s, boolean stringPresent, ErrorMessageCallback callback) { - shellLog.debug(output.get()); - if (shell.getExitCode() == 0) { - String errorMsg = callback.getErrorMessage(); - assertTrue(errorMsg, shell.getExitCode() > 0); - } - - if (!s.isEmpty()) - assertEquals(s + " present in " + output.get() + " was not " + stringPresent, stringPresent, - output.get().contains(s)); - shell.resetExitCode(); - } - - void writeToHistory(String cmd) { - input.set(cmd); - reader.readLine(); - } - } - - private static final NoOpErrorMessageCallback noop = new NoOpErrorMessageCallback(); - - private TestShell ts; + private MockShell ts; private static String rootPath; @@ -325,7 +141,7 @@ public class ShellServerIT extends SharedMiniClusterBase { @Before public void setupShell() throws Exception { - ts = new TestShell(getPrincipal(), getRootPassword(), + ts = new MockShell(getPrincipal(), getRootPassword(), getCluster().getConfig().getInstanceName(), getCluster().getConfig().getZooKeepers(), getCluster().getConfig().getClientPropsFile()); } @@ -336,20 +152,6 @@ public class ShellServerIT extends SharedMiniClusterBase { } @After - public void deleteTables() throws Exception { - try (AccumuloClient c = Accumulo.newClient().from(getClientProps()).build()) { - for (String table : c.tableOperations().list()) { - if (!table.startsWith(Namespace.ACCUMULO.name() + ".") && !table.equals("trace")) - try { - c.tableOperations().delete(table); - } catch (TableNotFoundException e) { - // don't care - } - } - } - } - - @After public void tearDownShell() { ts.shell.shutdown(); } @@ -751,17 +553,7 @@ public class ShellServerIT extends SharedMiniClusterBase { while (!success) { try { ts.exec("insert a b c d -l foo", false, "does not have authorization", true, - new ErrorMessageCallback() { - @Override - public String getErrorMessage() { - try (AccumuloClient c = Accumulo.newClient().from(getClientProps()).build()) { - return "Current auths for root are: " - + c.securityOperations().getUserAuthorizations("root"); - } catch (Exception e) { - return "Could not check authorizations"; - } - } - }); + new ErrorMessageCallback(getClientProps())); success = true; } catch (AssertionError e) { Thread.sleep(500); @@ -2306,615 +2098,4 @@ public class ShellServerIT extends SharedMiniClusterBase { // check that there are two files, with none having extra summary info assertMatches(output, "(?sm).*^.*total[:]2[,]\\s+missing[:]0[,]\\s+extra[:]0.*$.*"); } - - @Test - public void testCreateTableWithLocalityGroups() throws Exception { - final String table = getUniqueNames(1)[0]; - ts.exec("createtable " + table + " -l locg1=fam1,fam2", true); - try (AccumuloClient accumuloClient = Accumulo.newClient().from(getClientProps()).build()) { - Map<String,Set<Text>> lMap = accumuloClient.tableOperations().getLocalityGroups(table); - Set<Text> expectedColFams = Set.of(new Text("fam1"), new Text("fam2")); - for (Entry<String,Set<Text>> entry : lMap.entrySet()) { - assertEquals("locg1", entry.getKey()); - assertTrue(entry.getValue().containsAll(expectedColFams)); - } - ts.exec("deletetable -f " + table); - } - } - - /** - * Due to the existing complexity of the createtable command, the createtable help only displays - * an example of setting one locality group. It is possible to set multiple groups if needed. This - * test verifies that capability. - */ - @Test - public void testCreateTableWithMultipleLocalityGroups() throws Exception { - final String table = getUniqueNames(1)[0]; - ts.exec("createtable " + table + " -l locg1=fam1,fam2 locg2=colfam1", true); - try (AccumuloClient accumuloClient = Accumulo.newClient().from(getClientProps()).build()) { - Map<String,Set<Text>> lMap = accumuloClient.tableOperations().getLocalityGroups(table); - assertTrue(lMap.containsKey("locg1")); - assertTrue(lMap.containsKey("locg2")); - Set<Text> expectedColFams1 = Set.of(new Text("fam1"), new Text("fam2")); - Set<Text> expectedColFams2 = Set.of(new Text("colfam1")); - assertTrue(lMap.get("locg1").containsAll(expectedColFams1)); - assertTrue(lMap.get("locg2").containsAll(expectedColFams2)); - ts.exec("deletetable -f " + table); - } - } - - @Test - public void testCreateTableWithLocalityGroupsBadArguments() throws IOException { - final String table = getUniqueNames(1)[0]; - ts.exec("createtable " + table + " -l locg1 fam1,fam2", false); - ts.exec("createtable " + table + "-l", false); - ts.exec("createtable " + table + " -l locg1 = fam1,fam2", false); - ts.exec("createtable " + table + " -l locg1=fam1 ,fam2", false); - ts.exec("createtable " + table + " -l locg1=fam1,fam2 locg1=fam3,fam4", false); - ts.exec("createtable " + table + " -l locg1=fam1,fam2 locg2=fam1", false); - ts.exec("createtable " + table + " -l locg1", false); - ts.exec("createtable " + table + " group=fam1", false); - ts.exec("createtable " + table + "-l fam1,fam2", false); - } - - @Test - public void testCreateTableWithIterators() throws Exception { - final String tmpTable = "tmpTable"; - final String table = getUniqueNames(1)[0]; - - // create iterator profile - // Will use tmpTable for creating profile since setshelliter is requiring a table - // even though its command line help indicates that it is optional. Likely due to - // the fact that setshelliter extends setiter, which does require a table argument. - ts.exec("createtable " + tmpTable, true); - String output = ts.exec("tables"); - assertTrue(output.contains(tmpTable)); - - ts.input.set("\n5000\n\n"); - ts.exec("setshelliter -n itname -p 10 -pn profile1 -ageoff", true); - output = ts.exec("listshelliter"); - assertTrue(output.contains("Profile : profile1")); - - // create table making use of the iterator profile - ts.exec("createtable " + table + " -i profile1:scan,minc", true); - ts.exec("insert foo a b c", true); - ts.exec("scan", true, "foo a:b []\tc"); - ts.exec("sleep 6", true); - ts.exec("scan", true, "", true); - ts.exec("deletetable -f " + table); - ts.exec("deletetable -f " + tmpTable); - } - - /** - * Due to the existing complexity of the createtable command, the createtable help only displays - * an example of setting one iterator upon table creation. It is possible to set multiple if - * needed. This test verifies that capability. - */ - @Test - public void testCreateTableWithMultipleIterators() throws Exception { - final String tmpTable = "tmpTable"; - final String table = getUniqueNames(1)[0]; - - // create iterator profile - // Will use tmpTable for creating profile since setshelliter is requiring a table - // even though its command line help indicates that it is optional. Likely due to - // the fact that setshelliter extends setiter, which does require a table argument. - ts.exec("createtable " + tmpTable, true); - String output = ts.exec("tables"); - assertTrue(output.contains(tmpTable)); - - ts.input.set("\n5000\n\n"); - ts.exec("setshelliter -n itname -p 10 -pn profile1 -ageoff", true); - output = ts.exec("listshelliter"); - assertTrue(output.contains("Profile : profile1")); - - ts.input.set("2\n"); - ts.exec("setshelliter -n iter2 -p 11 -pn profile2 -vers", true); - output = ts.exec("listshelliter"); - assertTrue(output.contains("Profile : profile2")); - - // create table making use of the iterator profiles - ts.exec("createtable " + table + " -i profile1:scan,minc profile2:all ", true); - ts.exec("insert foo a b c", true); - ts.exec("scan", true, "foo a:b []\tc"); - ts.exec("sleep 6", true); - ts.exec("scan", true, "", true); - output = ts.exec("listiter -t " + table + " -all"); - assertTrue(output.contains("Iterator itname, scan scope options")); - assertTrue(output.contains("Iterator itname, minc scope options")); - assertFalse(output.contains("Iterator itname, majc scope options")); - assertTrue(output.contains("Iterator iter2, scan scope options")); - assertTrue(output.contains("Iterator iter2, minc scope options")); - assertTrue(output.contains("Iterator iter2, majc scope options")); - ts.exec("deletetable -f " + table); - ts.exec("deletetable -f " + tmpTable); - } - - @Test - public void testCreateTableWithIteratorsBadArguments() throws IOException { - final String tmpTable = "tmpTable"; - final String table = getUniqueNames(1)[0]; - ts.exec("createtable " + tmpTable, true); - String output = ts.exec("tables"); - assertTrue(output.contains(tmpTable)); - ts.input.set("\n5000\n\n"); - ts.exec("setshelliter -n itname -p 10 -pn profile1 -ageoff", true); - output = ts.exec("listshelliter"); - assertTrue(output.contains("Profile : profile1")); - // test various bad argument calls - ts.exec("createtable " + table + " -i noprofile:scan,minc", false); - ts.exec("createtable " + table + " -i profile1:scan,minc,all,majc", false); - ts.exec("createtable " + table + " -i profile1:scan,all,majc", false); - ts.exec("createtable " + table + " -i profile1:scan,min,majc", false); - ts.exec("createtable " + table + " -i profile1:scan,max,all", false); - ts.exec("createtable " + table + " -i profile1:", false); - ts.exec("createtable " + table + " -i profile1: ", false); - ts.exec("createtable " + table + " -i profile1:-scan", false); - ts.exec("createtable " + table + " profile1:majc", false); - ts.exec("createtable " + table + " -i profile1: all", false); - ts.exec("createtable " + table + " -i profile1: All", false); - ts.exec("createtable " + table + " -i profile1: scan", false); - ts.exec("createtable " + table + " -i profile1:minc scan", false); - ts.exec("createtable " + table + " -i profile1:minc,Scan", false); - ts.exec("createtable " + table + " -i profile1:minc, scan", false); - ts.exec("createtable " + table + " -i profile1:minc,,scan", false); - ts.exec("createtable " + table + " -i profile1:minc,minc", false); - ts.exec("createtable " + table + " -i profile1:minc,Minc", false); - ts.exec("createtable " + table + " -i profile1:minc, ,scan", false); - ts.exec("createtable " + table + "-i", false); - ts.exec("createtable " + table + "-i ", false); - ts.exec("deletetable -f " + tmpTable); - } - - /** - * Verify that table can be created in offline status and then be brought online. - */ - @Test - public void testCreateTableOffline() throws IOException { - final String tableName = getUniqueNames(1)[0]; - ts.exec("createtable " + tableName + " -o", true); - String output = ts.exec("tables"); - assertTrue(output.contains(tableName)); - output = ts.exec("scan -t " + tableName, false, "is offline", true); - assertTrue(output.contains("TableOfflineException")); - ts.exec("table " + tableName, true); - ts.exec("online", true); - ts.exec("scan", true); - ts.exec("deletetable -f " + tableName, true); - } - - /** - * Use shell to create a table with a supplied file containing splits. - * - * The splits will be contained in a file, sorted and un-encoded with no repeats or blank lines. - */ - @Test - public void testCreateTableWithSplitsFile1() - throws IOException, AccumuloSecurityException, TableNotFoundException, AccumuloException { - String splitsFile = System.getProperty("user.dir") + "/target/splitFile"; - try (AccumuloClient client = Accumulo.newClient().from(getClientProps()).build()) { - generateSplitsFile(splitsFile, 1000, 12, false, false, true, false, false); - SortedSet<Text> expectedSplits = readSplitsFromFile(splitsFile); - final String tableName = getUniqueNames(1)[0]; - ts.exec("createtable " + tableName + " -sf " + splitsFile, true); - Collection<Text> createdSplits = client.tableOperations().listSplits(tableName); - assertEquals(expectedSplits, new TreeSet<>(createdSplits)); - } finally { - Files.delete(Paths.get(splitsFile)); - } - } - - /** - * Use shell to create a table with a supplied file containing splits. - * - * The splits will be contained in a file, unsorted and un-encoded with no repeats or blank lines. - */ - @Test - public void testCreateTableWithSplitsFile2() - throws IOException, AccumuloSecurityException, TableNotFoundException, AccumuloException { - String splitsFile = System.getProperty("user.dir") + "/target/splitFile"; - try (AccumuloClient client = Accumulo.newClient().from(getClientProps()).build()) { - generateSplitsFile(splitsFile, 300, 12, false, false, false, false, false); - SortedSet<Text> expectedSplits = readSplitsFromFile(splitsFile); - final String tableName = getUniqueNames(1)[0]; - ts.exec("createtable " + tableName + " -sf " + splitsFile, true); - Collection<Text> createdSplits = client.tableOperations().listSplits(tableName); - assertEquals(expectedSplits, new TreeSet<>(createdSplits)); - } finally { - Files.delete(Paths.get(splitsFile)); - } - } - - /** - * Use shell to create a table with a supplied file containing splits. - * - * The splits will be contained in a file, sorted and encoded with no repeats or blank lines. - */ - @Test - public void testCreateTableWithSplitsFile3() - throws IOException, AccumuloSecurityException, TableNotFoundException, AccumuloException { - String splitsFile = System.getProperty("user.dir") + "/target/splitFile"; - try (AccumuloClient client = Accumulo.newClient().from(getClientProps()).build()) { - generateSplitsFile(splitsFile, 100, 23, false, true, true, false, false); - SortedSet<Text> expectedSplits = readSplitsFromFile(splitsFile); - final String tableName = getUniqueNames(1)[0]; - ts.exec("createtable " + tableName + " -sf " + splitsFile, true); - Collection<Text> createdSplits = client.tableOperations().listSplits(tableName); - assertEquals(expectedSplits, new TreeSet<>(createdSplits)); - } finally { - Files.delete(Paths.get(splitsFile)); - } - } - - /** - * Use shell to create a table with a supplied file containing splits. - * - * The splits will be contained in a file, sorted and un-encoded with a blank line and no repeats. - */ - @Test - public void testCreateTableWithSplitsFile4() - throws IOException, AccumuloSecurityException, TableNotFoundException, AccumuloException { - String splitsFile = System.getProperty("user.dir") + "/target/splitFile"; - try (AccumuloClient client = Accumulo.newClient().from(getClientProps()).build()) { - generateSplitsFile(splitsFile, 100, 31, false, false, true, true, false); - SortedSet<Text> expectedSplits = readSplitsFromFile(splitsFile); - final String tableName = getUniqueNames(1)[0]; - ts.exec("createtable " + tableName + " -sf " + splitsFile, true); - Collection<Text> createdSplits = client.tableOperations().listSplits(tableName); - assertEquals(expectedSplits, new TreeSet<>(createdSplits)); - } finally { - Files.delete(Paths.get(splitsFile)); - } - } - - /** - * Use shell to create a table with a supplied file containing splits. - * - * The splits will be contained in a file, sorted and un-encoded with a blank line and no repeats. - */ - @Test - public void testCreateTableWithSplitsFile5() - throws IOException, AccumuloSecurityException, TableNotFoundException, AccumuloException { - String splitsFile = System.getProperty("user.dir") + "/target/splitFile"; - try (AccumuloClient client = Accumulo.newClient().from(getClientProps()).build()) { - generateSplitsFile(splitsFile, 100, 32, false, false, true, false, true); - SortedSet<Text> expectedSplits = readSplitsFromFile(splitsFile); - final String tableName = getUniqueNames(1)[0]; - ts.exec("createtable " + tableName + " -sf " + splitsFile, true); - Collection<Text> createdSplits = client.tableOperations().listSplits(tableName); - assertEquals(expectedSplits, new TreeSet<>(createdSplits)); - } finally { - Files.delete(Paths.get(splitsFile)); - } - } - - /** - * Use shell to create a table with a supplied file containing splits. - * - * The splits will be contained in a file, unsorted and un-encoded with a blank line and repeats. - */ - @Test - public void testCreateTableWithSplitsFile6() - throws IOException, AccumuloSecurityException, TableNotFoundException, AccumuloException { - String splitsFile = System.getProperty("user.dir") + "/target/splitFile"; - try (AccumuloClient client = Accumulo.newClient().from(getClientProps()).build()) { - generateSplitsFile(splitsFile, 100, 12, false, false, false, true, true); - SortedSet<Text> expectedSplits = readSplitsFromFile(splitsFile); - final String tableName = getUniqueNames(1)[0]; - ts.exec("createtable " + tableName + " -sf " + splitsFile, true); - Collection<Text> createdSplits = client.tableOperations().listSplits(tableName); - assertEquals(expectedSplits, new TreeSet<>(createdSplits)); - } finally { - Files.delete(Paths.get(splitsFile)); - } - } - - /** - * Use shell to create a table with a supplied file containing splits. - * - * The splits will be contained in a file, sorted and encoded with a blank line and repeats. - */ - @Test - public void testCreateTableWithSplitsFile7() - throws IOException, AccumuloSecurityException, TableNotFoundException, AccumuloException { - String splitsFile = System.getProperty("user.dir") + "/target/splitFile"; - try (AccumuloClient client = Accumulo.newClient().from(getClientProps()).build()) { - generateSplitsFile(splitsFile, 100, 12, false, false, true, true, true); - SortedSet<Text> expectedSplits = readSplitsFromFile(splitsFile); - final String tableName = getUniqueNames(1)[0]; - ts.exec("createtable " + tableName + " -sf " + splitsFile, true); - Collection<Text> createdSplits = client.tableOperations().listSplits(tableName); - assertEquals(expectedSplits, new TreeSet<>(createdSplits)); - } finally { - Files.delete(Paths.get(splitsFile)); - } - } - - /** - * Use shell to create a table with a supplied file containing splits. - * - * The splits file will be empty. - */ - @Test - public void testCreateTableWithEmptySplitFile() - throws IOException, AccumuloSecurityException, TableNotFoundException, AccumuloException { - String splitsFile = System.getProperty("user.dir") + "/target/splitFile"; - try (AccumuloClient client = Accumulo.newClient().from(getClientProps()).build()) { - generateSplitsFile(splitsFile, 0, 0, false, false, false, false, false); - final String tableName = getUniqueNames(1)[0]; - ts.exec("createtable " + tableName + " -sf " + splitsFile, false); - assertThrows(TableNotFoundException.class, - () -> client.tableOperations().listSplits(tableName)); - } finally { - Files.delete(Paths.get(splitsFile)); - } - } - - /** - * Use shell to create a table that used splits from another table. - */ - @Test - public void testCreateTableWithCopySplitsFromOtherTable() - throws IOException, AccumuloSecurityException, TableNotFoundException, AccumuloException { - // create a table and add some splits - try (AccumuloClient client = Accumulo.newClient().from(getClientProps()).build()) { - final String[] tableNames = getUniqueNames(2); - final String tableName0 = tableNames[0]; - final String tableName2 = tableNames[1]; - - ts.exec("createtable " + tableName0, true); - String output = ts.exec("tables", true); - assertTrue(output.contains(tableName0)); - ts.exec("table " + tableName0, true); - // add splits to this table using the addsplits command. - List<Text> splits = new ArrayList<>(); - splits.add(new Text("ccccc")); - splits.add(new Text("fffff")); - splits.add(new Text("mmmmm")); - splits.add(new Text("sssss")); - ts.exec("addsplits " + splits.get(0) + " " + splits.get(1) + " " + splits.get(2) + " " - + splits.get(3), true); - // Now create a table that will used the previous tables splits and create them at table - // creation - ts.exec("createtable " + tableName2 + " --copy-splits " + tableName0, true); - ts.exec("table " + tableName0, true); - String tablesOutput = ts.exec("tables", true); - assertTrue(tablesOutput.contains(tableName2)); - Collection<Text> createdSplits = client.tableOperations().listSplits(tableName2); - assertEquals(new TreeSet<>(splits), new TreeSet<>(createdSplits)); - ts.exec("deletetable -f " + tableName0, true); - ts.exec("deletetable -f " + tableName2, true); - } - } - - /** - * Use shell to create a table with a supplied file containing splits. - * - * The splits will be contained in a file, sorted and encoded with no repeats or blank lines. - */ - @Test - public void testCreateTableWithBinarySplitsFile1() - throws IOException, AccumuloSecurityException, TableNotFoundException, AccumuloException { - String splitsFile = System.getProperty("user.dir") + "/target/splitFile"; - try (AccumuloClient client = Accumulo.newClient().from(getClientProps()).build()) { - generateSplitsFile(splitsFile, 200, 12, true, true, true, false, false); - SortedSet<Text> expectedSplits = readSplitsFromFile(splitsFile); - final String tableName = getUniqueNames(1)[0]; - ts.exec("createtable " + tableName + " -sf " + splitsFile, true); - Collection<Text> createdSplits = client.tableOperations().listSplits(tableName); - assertEquals(expectedSplits, new TreeSet<>(createdSplits)); - } finally { - Files.delete(Paths.get(splitsFile)); - } - } - - /** - * Use shell to create a table with a supplied file containing splits. - * - * The splits will be contained in a file, unsorted and encoded with no repeats or blank lines. - */ - @Test - public void testCreateTableWithBinarySplitsFile2() - throws IOException, AccumuloSecurityException, TableNotFoundException, AccumuloException { - String splitsFile = System.getProperty("user.dir") + "/target/splitFile"; - try (AccumuloClient client = Accumulo.newClient().from(getClientProps()).build()) { - generateSplitsFile(splitsFile, 300, 12, true, true, false, false, false); - SortedSet<Text> expectedSplits = readSplitsFromFile(splitsFile); - final String tableName = getUniqueNames(1)[0]; - ts.exec("createtable " + tableName + " -sf " + splitsFile, true); - Collection<Text> createdSplits = client.tableOperations().listSplits(tableName); - assertEquals(expectedSplits, new TreeSet<>(createdSplits)); - } finally { - Files.delete(Paths.get(splitsFile)); - } - } - - /** - * Use shell to create a table with a supplied file containing splits. - * - * The splits will be contained in a file, sorted and encoded with no repeats or blank lines. - */ - @Test - public void testCreateTableWithBinarySplitsFile3() - throws IOException, AccumuloSecurityException, TableNotFoundException, AccumuloException { - String splitsFile = System.getProperty("user.dir") + "/target/splitFile"; - try (AccumuloClient client = Accumulo.newClient().from(getClientProps()).build()) { - generateSplitsFile(splitsFile, 100, 23, true, true, true, false, false); - SortedSet<Text> expectedSplits = readSplitsFromFile(splitsFile); - final String tableName = getUniqueNames(1)[0]; - ts.exec("createtable " + tableName + " -sf " + splitsFile, true); - Collection<Text> createdSplits = client.tableOperations().listSplits(tableName); - assertEquals(expectedSplits, new TreeSet<>(createdSplits)); - } finally { - Files.delete(Paths.get(splitsFile)); - } - } - - /** - * Use shell to create a table with a supplied file containing splits. - * - * The splits will be contained in a file, sorted and encoded with a blank line and no repeats. - */ - @Test - public void testCreateTableWithBinarySplitsFile4() - throws IOException, AccumuloSecurityException, TableNotFoundException, AccumuloException { - String splitsFile = System.getProperty("user.dir") + "/target/splitFile"; - try (AccumuloClient client = Accumulo.newClient().from(getClientProps()).build()) { - generateSplitsFile(splitsFile, 100, 31, true, true, true, true, false); - SortedSet<Text> expectedSplits = readSplitsFromFile(splitsFile); - final String tableName = getUniqueNames(1)[0]; - ts.exec("createtable " + tableName + " -sf " + splitsFile, true); - Collection<Text> createdSplits = client.tableOperations().listSplits(tableName); - assertEquals(expectedSplits, new TreeSet<>(createdSplits)); - } finally { - Files.delete(Paths.get(splitsFile)); - } - } - - /** - * Use shell to create a table with a supplied file containing splits. - * - * The splits will be contained in a file, sorted and encoded with a blank line and no repeats. - */ - @Test - public void testCreateTableWithBinarySplitsFile5() - throws IOException, AccumuloSecurityException, TableNotFoundException, AccumuloException { - String splitsFile = System.getProperty("user.dir") + "/target/splitFile"; - try (AccumuloClient client = Accumulo.newClient().from(getClientProps()).build()) { - generateSplitsFile(splitsFile, 100, 32, true, true, true, false, true); - SortedSet<Text> expectedSplits = readSplitsFromFile(splitsFile); - final String tableName = getUniqueNames(1)[0]; - ts.exec("createtable " + tableName + " -sf " + splitsFile, true); - Collection<Text> createdSplits = client.tableOperations().listSplits(tableName); - assertEquals(expectedSplits, new TreeSet<>(createdSplits)); - } finally { - Files.delete(Paths.get(splitsFile)); - } - } - - /** - * Use shell to create a table with a supplied file containing splits. - * - * The splits will be contained in a file, unsorted and encoded with a blank line and repeats. - */ - @Test - public void testCreateTableWithBinarySplitsFile6() - throws IOException, AccumuloSecurityException, TableNotFoundException, AccumuloException { - String splitsFile = System.getProperty("user.dir") + "/target/splitFile"; - try (AccumuloClient client = Accumulo.newClient().from(getClientProps()).build()) { - generateSplitsFile(splitsFile, 100, 12, true, true, false, true, true); - SortedSet<Text> expectedSplits = readSplitsFromFile(splitsFile); - final String tableName = getUniqueNames(1)[0]; - ts.exec("createtable " + tableName + " -sf " + splitsFile, true); - Collection<Text> createdSplits = client.tableOperations().listSplits(tableName); - assertEquals(expectedSplits, new TreeSet<>(createdSplits)); - } finally { - Files.delete(Paths.get(splitsFile)); - } - } - - /** - * Use shell to create a table with a supplied file containing splits. - * - * The splits will be contained in a file, sorted and encoded with a blank line and repeats. - */ - @Test - public void testCreateTableWithBinarySplitsFile7() - throws IOException, AccumuloSecurityException, TableNotFoundException, AccumuloException { - String splitsFile = System.getProperty("user.dir") + "/target/splitFile"; - try (AccumuloClient client = Accumulo.newClient().from(getClientProps()).build()) { - generateSplitsFile(splitsFile, 100, 12, true, true, true, true, true); - SortedSet<Text> expectedSplits = readSplitsFromFile(splitsFile); - final String tableName = getUniqueNames(1)[0]; - ts.exec("createtable " + tableName + " -sf " + splitsFile, true); - Collection<Text> createdSplits = client.tableOperations().listSplits(tableName); - assertEquals(expectedSplits, new TreeSet<>(createdSplits)); - } finally { - Files.delete(Paths.get(splitsFile)); - } - } - - private SortedSet<Text> readSplitsFromFile(final String splitsFile) throws IOException { - SortedSet<Text> splits = new TreeSet<>(); - try (BufferedReader reader = newBufferedReader(Paths.get(splitsFile))) { - String split; - while ((split = reader.readLine()) != null) { - Text unencodedString = decode(split); - if (unencodedString != null) - splits.add(unencodedString); - } - } - return splits; - } - - private void generateSplitsFile(final String splitsFile, final int numItems, final int len, - final boolean binarySplits, final boolean encoded, final boolean sort, - final boolean addBlankLine, final boolean repeat) throws IOException { - - java.nio.file.Path splitsPath = java.nio.file.Paths.get(splitsFile); - int insertAt = (len % 2 == 0) ? len / 2 : (len + 1) / 2; - Collection<Text> sortedSplits = null; - Collection<Text> randomSplits; - - if (binarySplits) - randomSplits = generateBinarySplits(numItems, len); - else - randomSplits = generateNonBinarySplits(numItems, len); - - if (sort) - sortedSplits = new TreeSet<>(randomSplits); - - try (BufferedWriter writer = Files.newBufferedWriter(splitsPath, UTF_8)) { - int cnt = 0; - Collection<Text> splits; - if (sort) - splits = sortedSplits; - else - splits = randomSplits; - - for (Text text : splits) { - if (addBlankLine && cnt++ == insertAt) - writer.write('\n'); - writer.write(encode(text, encoded) + '\n'); - if (repeat) - writer.write(encode(text, encoded) + '\n'); - } - } - } - - private Collection<Text> generateNonBinarySplits(final int numItems, final int len) { - Set<Text> splits = new HashSet<>(); - for (int i = 0; i < numItems; i++) { - splits.add(getRandomText(len)); - } - return splits; - } - - private Collection<Text> generateBinarySplits(final int numItems, final int len) { - Set<Text> splits = new HashSet<>(); - for (int i = 0; i < numItems; i++) { - byte[] split = new byte[len]; - random.nextBytes(split); - splits.add(new Text(split)); - } - return splits; - } - - private Text getRandomText(final int len) { - int desiredLen = Math.min(len, 32); - return new Text( - String.valueOf(UUID.randomUUID()).replaceAll("-", "").substring(0, desiredLen - 1)); - } - - private static String encode(final Text text, final boolean encode) { - if (text.toString().isBlank()) - return null; - return encode ? Base64.getEncoder().encodeToString(TextUtil.getBytes(text)) : text.toString(); - } - - private Text decode(final String text) { - if (requireNonNull(text).isBlank()) - return null; - return new Text(text); - } }