Merge branch '1.6' Conflicts: core/src/test/java/org/apache/accumulo/core/util/shell/command/FormatterCommandTest.java core/src/test/java/org/apache/accumulo/core/util/shell/command/HistoryCommandTest.java core/src/test/java/org/apache/accumulo/core/util/shell/commands/FormatterCommandTest.java core/src/test/java/org/apache/accumulo/core/util/shell/commands/HistoryCommandTest.java shell/src/main/java/org/apache/accumulo/shell/commands/DeleteTableCommand.java shell/src/test/java/org/apache/accumulo/shell/command/FormatterCommandTest.java shell/src/test/java/org/apache/accumulo/shell/command/HistoryCommandTest.java
Project: http://git-wip-us.apache.org/repos/asf/accumulo/repo Commit: http://git-wip-us.apache.org/repos/asf/accumulo/commit/e7d0397c Tree: http://git-wip-us.apache.org/repos/asf/accumulo/tree/e7d0397c Diff: http://git-wip-us.apache.org/repos/asf/accumulo/diff/e7d0397c Branch: refs/heads/master Commit: e7d0397cf4ac97a67b111d2cbe3bc195c60a8791 Parents: c51d424 7f8ef55 Author: Josh Elser <els...@apache.org> Authored: Thu Nov 20 11:51:16 2014 -0500 Committer: Josh Elser <els...@apache.org> Committed: Thu Nov 20 11:51:16 2014 -0500 ---------------------------------------------------------------------- .../shell/commands/DeleteTableCommand.java | 23 +++ .../accumulo/shell/commands/TableOperation.java | 16 +- .../shell/command/DropUserCommandTest.java | 83 --------- .../shell/command/FormatterCommandTest.java | 184 ------------------- .../shell/command/HistoryCommandTest.java | 90 --------- .../shell/commands/DeleteTableCommandTest.java | 42 +++++ .../shell/commands/DropUserCommandTest.java | 83 +++++++++ .../shell/commands/FormatterCommandTest.java | 184 +++++++++++++++++++ .../shell/commands/HistoryCommandTest.java | 90 +++++++++ 9 files changed, 437 insertions(+), 358 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/accumulo/blob/e7d0397c/shell/src/main/java/org/apache/accumulo/shell/commands/DeleteTableCommand.java ---------------------------------------------------------------------- diff --cc shell/src/main/java/org/apache/accumulo/shell/commands/DeleteTableCommand.java index 827a8ec,0000000..55a457c mode 100644,000000..100644 --- a/shell/src/main/java/org/apache/accumulo/shell/commands/DeleteTableCommand.java +++ b/shell/src/main/java/org/apache/accumulo/shell/commands/DeleteTableCommand.java @@@ -1,60 -1,0 +1,83 @@@ +/* + * 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.shell.commands; + ++import java.util.Iterator; ++import java.util.Set; ++ ++import org.apache.accumulo.core.client.impl.Namespaces; ++import org.apache.accumulo.core.client.impl.Tables; ++import org.apache.accumulo.core.util.Pair; +import org.apache.accumulo.shell.Shell; +import org.apache.commons.cli.CommandLine; +import org.apache.commons.cli.Option; +import org.apache.commons.cli.Options; ++import org.slf4j.Logger; ++import org.slf4j.LoggerFactory; + +public class DeleteTableCommand extends TableOperation { ++ private static final Logger log = LoggerFactory.getLogger(DeleteTableCommand.class); ++ + private Option forceOpt; + + @Override + public int execute(final String fullCommand, final CommandLine cl, final Shell shellState) throws Exception { + if (cl.hasOption(forceOpt.getOpt())) { + super.force(); + } else { + super.noForce(); + } + return super.execute(fullCommand, cl, shellState); + } + + @Override + public String description() { + return "deletes a table"; + } + + @Override + protected void doTableOp(final Shell shellState, final String tableName) throws Exception { + shellState.getConnector().tableOperations().delete(tableName); + shellState.getReader().println("Table: [" + tableName + "] has been deleted."); + + if (shellState.getTableName().equals(tableName)) { + shellState.setTableName(""); + } + } + + @Override + public Options getOptions() { + forceOpt = new Option("f", "force", false, "force deletion without prompting"); + final Options opts = super.getOptions(); + + opts.addOption(forceOpt); + return opts; + } ++ ++ @Override ++ protected void pruneTables(String pattern, Set<String> tables) { ++ Iterator<String> tableNames = tables.iterator(); ++ while (tableNames.hasNext()) { ++ String table = tableNames.next(); ++ Pair<String,String> qualifiedName = Tables.qualify(table); ++ if (Namespaces.ACCUMULO_NAMESPACE.equals(qualifiedName.getFirst())) { ++ log.trace("Removing table from deletion set: {}", table); ++ tableNames.remove(); ++ } ++ } ++ } +} http://git-wip-us.apache.org/repos/asf/accumulo/blob/e7d0397c/shell/src/main/java/org/apache/accumulo/shell/commands/TableOperation.java ---------------------------------------------------------------------- diff --cc shell/src/main/java/org/apache/accumulo/shell/commands/TableOperation.java index 1f77940,0000000..565a5e4 mode 100644,000000..100644 --- a/shell/src/main/java/org/apache/accumulo/shell/commands/TableOperation.java +++ b/shell/src/main/java/org/apache/accumulo/shell/commands/TableOperation.java @@@ -1,154 -1,0 +1,168 @@@ +/* + * 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.shell.commands; + +import java.util.Map; +import java.util.Set; +import java.util.SortedSet; +import java.util.TreeSet; + +import org.apache.accumulo.core.client.Instance; +import org.apache.accumulo.core.client.TableNotFoundException; +import org.apache.accumulo.core.client.impl.Namespaces; +import org.apache.accumulo.core.client.impl.Tables; +import org.apache.accumulo.shell.Shell; +import org.apache.accumulo.shell.ShellOptions; +import org.apache.accumulo.shell.Token; +import org.apache.accumulo.shell.Shell.Command; +import org.apache.commons.cli.CommandLine; +import org.apache.commons.cli.Option; +import org.apache.commons.cli.OptionGroup; +import org.apache.commons.cli.Options; + +public abstract class TableOperation extends Command { + + protected Option optTablePattern, optTableName, optNamespace; + private boolean force = true; + private boolean useCommandLine = true; + + @Override + public int execute(final String fullCommand, final CommandLine cl, final Shell shellState) throws Exception { + // populate the tableSet set with the tables you want to operate on + final SortedSet<String> tableSet = new TreeSet<String>(); + if (cl.hasOption(optTablePattern.getOpt())) { ++ String tablePattern = cl.getOptionValue(optTablePattern.getOpt()); + for (String table : shellState.getConnector().tableOperations().list()) - if (table.matches(cl.getOptionValue(optTablePattern.getOpt()))) { ++ if (table.matches(tablePattern)) { + tableSet.add(table); + } ++ pruneTables(tablePattern, tableSet); + } else if (cl.hasOption(optTableName.getOpt())) { + tableSet.add(cl.getOptionValue(optTableName.getOpt())); + } else if (cl.hasOption(optNamespace.getOpt())) { + Instance instance = shellState.getInstance(); + String namespaceId = Namespaces.getNamespaceId(instance, cl.getOptionValue(optNamespace.getOpt())); + for (String tableId : Namespaces.getTableIds(instance, namespaceId)) { + tableSet.add(Tables.getTableName(instance, tableId)); + } + } else if (useCommandLine && cl.getArgs().length > 0) { + for (String tableName : cl.getArgs()) { + tableSet.add(tableName); + } + } else { + shellState.checkTableState(); + tableSet.add(shellState.getTableName()); + } + + if (tableSet.isEmpty()) + Shell.log.warn("No tables found that match your criteria"); + + boolean more = true; + // flush the tables + for (String tableName : tableSet) { + if (!more) { + break; + } + if (!shellState.getConnector().tableOperations().exists(tableName)) { + throw new TableNotFoundException(null, tableName, null); + } + boolean operate = true; + if (!force) { + shellState.getReader().flush(); + String line = shellState.getReader().readLine(getName() + " { " + tableName + " } (yes|no)? "); + more = line != null; + operate = line != null && (line.equalsIgnoreCase("y") || line.equalsIgnoreCase("yes")); + } + if (operate) { + doTableOp(shellState, tableName); + } + } + + return 0; + } + ++ /** ++ * Allows implementation to remove certain tables from the set of tables to be operated on. ++ * ++ * @param pattern ++ * The pattern which tables were selected using ++ * @param tables ++ * A reference to the Set of tables to be operated on ++ */ ++ protected void pruneTables(String pattern, Set<String> tables) { ++ // Default no pruning ++ } ++ + protected abstract void doTableOp(Shell shellState, String tableName) throws Exception; + + @Override + public String description() { + return "makes a best effort to flush tables from memory to disk"; + } + + @Override + public Options getOptions() { + final Options o = new Options(); + + optTablePattern = new Option("p", "pattern", true, "regex pattern of table names to operate on"); + optTablePattern.setArgName("pattern"); + + optTableName = new Option(ShellOptions.tableOption, "table", true, "name of a table to operate on"); + optTableName.setArgName("tableName"); + + optNamespace = new Option(ShellOptions.namespaceOption, "namespace", true, "name of a namespace to operate on"); + optNamespace.setArgName("namespace"); + + final OptionGroup opg = new OptionGroup(); + + opg.addOption(optTablePattern); + opg.addOption(optTableName); + opg.addOption(optNamespace); + + o.addOptionGroup(opg); + + return o; + } + + @Override + public int numArgs() { + return useCommandLine ? Shell.NO_FIXED_ARG_LENGTH_CHECK : 0; + } + + protected void force() { + force = true; + } + + protected void noForce() { + force = false; + } + + protected void disableUnflaggedTableOptions() { + useCommandLine = false; + } + + @Override + public String usage() { + return getName() + " [<table>{ <table>}]"; + } + + @Override + public void registerCompletion(final Token root, final Map<Command.CompletionSet,Set<String>> special) { + if (useCommandLine) + registerCompletionForTables(root, special); + } +} http://git-wip-us.apache.org/repos/asf/accumulo/blob/e7d0397c/shell/src/test/java/org/apache/accumulo/shell/commands/DeleteTableCommandTest.java ---------------------------------------------------------------------- diff --cc shell/src/test/java/org/apache/accumulo/shell/commands/DeleteTableCommandTest.java index 0000000,0000000..3cbb227 new file mode 100644 --- /dev/null +++ b/shell/src/test/java/org/apache/accumulo/shell/commands/DeleteTableCommandTest.java @@@ -1,0 -1,0 +1,42 @@@ ++/* ++ * 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.shell.commands; ++ ++import java.util.Arrays; ++import java.util.HashSet; ++import java.util.Set; ++ ++import org.apache.accumulo.core.metadata.MetadataTable; ++import org.apache.accumulo.core.metadata.RootTable; ++import org.junit.Assert; ++import org.junit.Test; ++ ++/** ++ * ++ */ ++public class DeleteTableCommandTest { ++ ++ @Test ++ public void removeAccumuloNamespaceTables() { ++ Set<String> tables = new HashSet<String>(Arrays.asList(MetadataTable.NAME, RootTable.NAME, "a1", "a2")); ++ DeleteTableCommand cmd = new DeleteTableCommand(); ++ cmd.pruneTables("a.*", tables); ++ ++ Assert.assertEquals(new HashSet<String>(Arrays.asList("a1", "a2")), tables); ++ } ++ ++} http://git-wip-us.apache.org/repos/asf/accumulo/blob/e7d0397c/shell/src/test/java/org/apache/accumulo/shell/commands/DropUserCommandTest.java ---------------------------------------------------------------------- diff --cc shell/src/test/java/org/apache/accumulo/shell/commands/DropUserCommandTest.java index 0000000,0000000..2c82bf1 new file mode 100644 --- /dev/null +++ b/shell/src/test/java/org/apache/accumulo/shell/commands/DropUserCommandTest.java @@@ -1,0 -1,0 +1,83 @@@ ++/* ++ * 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.shell.commands; ++ ++import jline.console.ConsoleReader; ++ ++import org.apache.accumulo.core.client.Connector; ++import org.apache.accumulo.core.client.admin.SecurityOperations; ++import org.apache.accumulo.shell.Shell; ++import org.apache.accumulo.shell.commands.DropUserCommand; ++import org.apache.commons.cli.CommandLine; ++import org.easymock.EasyMock; ++import org.junit.Before; ++import org.junit.Test; ++ ++/** ++ * ++ */ ++public class DropUserCommandTest { ++ ++ private DropUserCommand cmd; ++ ++ @Before ++ public void setup() { ++ cmd = new DropUserCommand(); ++ ++ // Initialize that internal state ++ cmd.getOptions(); ++ } ++ ++ @Test ++ public void dropUserWithoutForcePrompts() throws Exception { ++ Connector conn = EasyMock.createMock(Connector.class); ++ CommandLine cli = EasyMock.createMock(CommandLine.class); ++ Shell shellState = EasyMock.createMock(Shell.class); ++ ConsoleReader reader = EasyMock.createMock(ConsoleReader.class); ++ SecurityOperations secOps = EasyMock.createMock(SecurityOperations.class); ++ ++ EasyMock.expect(shellState.getConnector()).andReturn(conn); ++ ++ // The user we want to remove ++ EasyMock.expect(cli.getArgs()).andReturn(new String[] {"user"}); ++ ++ // We're the root user ++ EasyMock.expect(conn.whoami()).andReturn("root"); ++ ++ // Force option was not provided ++ EasyMock.expect(cli.hasOption("f")).andReturn(false); ++ EasyMock.expect(shellState.getReader()).andReturn(reader); ++ reader.flush(); ++ EasyMock.expectLastCall().once(); ++ ++ // Fake a "yes" response ++ EasyMock.expect(shellState.getReader()).andReturn(reader); ++ EasyMock.expect(reader.readLine(EasyMock.anyObject(String.class))).andReturn("yes"); ++ EasyMock.expect(shellState.getConnector()).andReturn(conn); ++ ++ EasyMock.expect(conn.securityOperations()).andReturn(secOps); ++ secOps.dropLocalUser("user"); ++ EasyMock.expectLastCall(); ++ ++ EasyMock.replay(conn, cli, shellState, reader, secOps); ++ ++ cmd.execute("dropuser foo -f", cli, shellState); ++ ++ EasyMock.verify(conn, cli, shellState, reader, secOps); ++ } ++ ++} http://git-wip-us.apache.org/repos/asf/accumulo/blob/e7d0397c/shell/src/test/java/org/apache/accumulo/shell/commands/FormatterCommandTest.java ---------------------------------------------------------------------- diff --cc shell/src/test/java/org/apache/accumulo/shell/commands/FormatterCommandTest.java index 0000000,0000000..ddcd243 new file mode 100644 --- /dev/null +++ b/shell/src/test/java/org/apache/accumulo/shell/commands/FormatterCommandTest.java @@@ -1,0 -1,0 +1,184 @@@ ++/* ++ * 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.shell.commands; ++ ++import java.io.ByteArrayOutputStream; ++import java.io.IOException; ++import java.io.InputStream; ++import java.util.Iterator; ++import java.util.Map.Entry; ++ ++import org.apache.accumulo.core.client.AccumuloException; ++import org.apache.accumulo.core.client.AccumuloSecurityException; ++import org.apache.accumulo.core.client.TableExistsException; ++import org.apache.accumulo.core.data.Key; ++import org.apache.accumulo.core.data.Value; ++import org.apache.accumulo.core.util.format.Formatter; ++import org.apache.accumulo.shell.Shell; ++import org.apache.accumulo.shell.mock.MockShell; ++import org.apache.log4j.Level; ++import org.apache.log4j.Logger; ++import org.junit.Assert; ++import org.junit.Test; ++ ++/** ++ * Uses the MockShell to test the shell output with Formatters ++ */ ++public class FormatterCommandTest { ++ ByteArrayOutputStream out = null; ++ InputStream in = null; ++ ++ @Test ++ public void test() throws IOException, AccumuloException, AccumuloSecurityException, TableExistsException, ClassNotFoundException { ++ // Keep the Shell AUDIT log off the test output ++ Logger.getLogger(Shell.class).setLevel(Level.WARN); ++ ++ final String[] args = new String[] {"--fake", "-u", "root", "-p", ""}; ++ ++ final String[] commands = createCommands(); ++ ++ in = MockShell.makeCommands(commands); ++ out = new ByteArrayOutputStream(); ++ ++ final MockShell shell = new MockShell(in, out); ++ shell.config(args); ++ ++ // Can't call createtable in the shell with MockAccumulo ++ shell.getConnector().tableOperations().create("test"); ++ ++ try { ++ shell.start(); ++ } catch (Exception e) { ++ Assert.fail("Exception while running commands: " + e.getMessage()); ++ } ++ ++ shell.getReader().flush(); ++ ++ final String[] output = new String(out.toByteArray()).split("\n\r"); ++ ++ boolean formatterOn = false; ++ ++ final String[] expectedDefault = new String[] {"row cf:cq [] 1234abcd", "row cf1:cq1 [] 9876fedc", "row2 cf:cq [] 13579bdf", ++ "row2 cf1:cq [] 2468ace"}; ++ ++ final String[] expectedFormatted = new String[] {"row cf:cq [] 0x31 0x32 0x33 0x34 0x61 0x62 0x63 0x64", ++ "row cf1:cq1 [] 0x39 0x38 0x37 0x36 0x66 0x65 0x64 0x63", "row2 cf:cq [] 0x31 0x33 0x35 0x37 0x39 0x62 0x64 0x66", ++ "row2 cf1:cq [] 0x32 0x34 0x36 0x38 0x61 0x63 0x65"}; ++ ++ int outputIndex = 0; ++ while (outputIndex < output.length) { ++ final String line = output[outputIndex]; ++ ++ if (line.startsWith("root@mock-instance")) { ++ if (line.contains("formatter")) { ++ formatterOn = true; ++ } ++ ++ outputIndex++; ++ } else if (line.startsWith("row")) { ++ int expectedIndex = 0; ++ String[] comparisonData; ++ ++ // Pick the type of data we expect (formatted or default) ++ if (formatterOn) { ++ comparisonData = expectedFormatted; ++ } else { ++ comparisonData = expectedDefault; ++ } ++ ++ // Ensure each output is what we expected ++ while (expectedIndex + outputIndex < output.length && expectedIndex < expectedFormatted.length) { ++ Assert.assertEquals(comparisonData[expectedIndex].trim(), output[expectedIndex + outputIndex].trim()); ++ expectedIndex++; ++ } ++ ++ outputIndex += expectedIndex; ++ } ++ } ++ } ++ ++ private String[] createCommands() { ++ return new String[] {"table test", "insert row cf cq 1234abcd", "insert row cf1 cq1 9876fedc", "insert row2 cf cq 13579bdf", "insert row2 cf1 cq 2468ace", ++ "scan", "formatter -t test -f org.apache.accumulo.core.util.shell.command.FormatterCommandTest$HexFormatter", "scan"}; ++ } ++ ++ /** ++ * <p> ++ * Simple <code>Formatter</code> that will convert each character in the Value from decimal to hexadecimal. Will automatically skip over characters in the ++ * value which do not fall within the [0-9,a-f] range. ++ * </p> ++ * ++ * <p> ++ * Example: <code>'0'</code> will be displayed as <code>'0x30'</code> ++ * </p> ++ */ ++ public static class HexFormatter implements Formatter { ++ private Iterator<Entry<Key,Value>> iter = null; ++ private boolean printTs = false; ++ ++ private final static String tab = "\t"; ++ private final static String newline = "\n"; ++ ++ public HexFormatter() {} ++ ++ @Override ++ public boolean hasNext() { ++ return this.iter.hasNext(); ++ } ++ ++ @Override ++ public String next() { ++ final Entry<Key,Value> entry = iter.next(); ++ ++ String key; ++ ++ // Observe the timestamps ++ if (printTs) { ++ key = entry.getKey().toString(); ++ } else { ++ key = entry.getKey().toStringNoTime(); ++ } ++ ++ final Value v = entry.getValue(); ++ ++ // Approximate how much space we'll need ++ final StringBuilder sb = new StringBuilder(key.length() + v.getSize() * 5); ++ ++ sb.append(key).append(tab); ++ ++ for (byte b : v.get()) { ++ if ((b >= 48 && b <= 57) || (b >= 97 || b <= 102)) { ++ sb.append(String.format("0x%x ", Integer.valueOf(b))); ++ } ++ } ++ ++ sb.append(newline); ++ ++ return sb.toString(); ++ } ++ ++ @Override ++ public void remove() {} ++ ++ @Override ++ public void initialize(final Iterable<Entry<Key,Value>> scanner, final boolean printTimestamps) { ++ this.iter = scanner.iterator(); ++ this.printTs = printTimestamps; ++ } ++ } ++ ++} http://git-wip-us.apache.org/repos/asf/accumulo/blob/e7d0397c/shell/src/test/java/org/apache/accumulo/shell/commands/HistoryCommandTest.java ---------------------------------------------------------------------- diff --cc shell/src/test/java/org/apache/accumulo/shell/commands/HistoryCommandTest.java index 0000000,0000000..8a5b598 new file mode 100644 --- /dev/null +++ b/shell/src/test/java/org/apache/accumulo/shell/commands/HistoryCommandTest.java @@@ -1,0 -1,0 +1,90 @@@ ++/* ++ * 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.shell.commands; ++ ++import static org.easymock.EasyMock.createMock; ++import static org.easymock.EasyMock.expect; ++import static org.easymock.EasyMock.replay; ++import static org.junit.Assert.assertTrue; ++ ++import java.io.ByteArrayInputStream; ++import java.io.ByteArrayOutputStream; ++import java.io.IOException; ++ ++import jline.console.ConsoleReader; ++import jline.console.history.History; ++import jline.console.history.MemoryHistory; ++ ++import org.apache.accumulo.shell.Shell; ++import org.apache.accumulo.shell.commands.HistoryCommand; ++import org.apache.commons.cli.CommandLine; ++import org.junit.Assume; ++import org.junit.Before; ++import org.junit.Test; ++ ++public class HistoryCommandTest { ++ ++ HistoryCommand command; ++ CommandLine cl; ++ ++ ByteArrayOutputStream baos; ++ ConsoleReader reader; ++ Shell shell; ++ ++ @Before ++ public void setUp() throws Exception { ++ command = new HistoryCommand(); ++ command.getOptions(); // Make sure everything is initialized ++ ++ cl = createMock(CommandLine.class); ++ expect(cl.hasOption("c")).andReturn(false); ++ expect(cl.hasOption("np")).andReturn(true); ++ replay(cl); ++ ++ History history = new MemoryHistory(); ++ history.add("foo"); ++ history.add("bar"); ++ ++ baos = new ByteArrayOutputStream(); ++ ++ String input = String.format("!1%n"); // Construct a platform dependent new-line ++ reader = new ConsoleReader(new ByteArrayInputStream(input.getBytes()), baos); ++ reader.setHistory(history); ++ ++ shell = new Shell(reader, null); ++ } ++ ++ @Test ++ public void testCorrectNumbering() throws IOException { ++ command.execute("", cl, shell); ++ reader.flush(); ++ ++ assertTrue(baos.toString().contains("2: bar")); ++ } ++ ++ @Test ++ public void testEventExpansion() throws IOException { ++ // If we use an unsupported terminal, then history expansion doesn't work because JLine can't do magic buffer manipulations. ++ // This has been observed to be the case on certain versions of Eclipse. However, mvn is usually fine. ++ Assume.assumeTrue(reader.getTerminal().isSupported()); ++ ++ reader.readLine(); ++ ++ assertTrue(baos.toString().trim().endsWith("foo")); ++ } ++ ++}