Repository: accumulo
Updated Branches:
  refs/heads/1.6 7ccae952c -> 7f8ef553d
  refs/heads/master c51d424b9 -> e7d0397cf


ACCUMULO-3341 Make deletetable remove any tables in the accumulo namespace 
before attempting deletion.

Also fixed the test package from 'command' to 'commands'.


Project: http://git-wip-us.apache.org/repos/asf/accumulo/repo
Commit: http://git-wip-us.apache.org/repos/asf/accumulo/commit/7f8ef553
Tree: http://git-wip-us.apache.org/repos/asf/accumulo/tree/7f8ef553
Diff: http://git-wip-us.apache.org/repos/asf/accumulo/diff/7f8ef553

Branch: refs/heads/1.6
Commit: 7f8ef553da765221d714bece239d3294495fb79e
Parents: 7ccae95
Author: Josh Elser <els...@apache.org>
Authored: Thu Nov 20 11:27:25 2014 -0500
Committer: Josh Elser <els...@apache.org>
Committed: Thu Nov 20 11:27:25 2014 -0500

----------------------------------------------------------------------
 .../util/shell/commands/DeleteTableCommand.java |  23 +++
 .../util/shell/commands/TableOperation.java     |  16 +-
 .../shell/command/FormatterCommandTest.java     | 184 -------------------
 .../util/shell/command/HistoryCommandTest.java  |  90 ---------
 .../shell/commands/DeleteTableCommandTest.java  |  42 +++++
 .../shell/commands/FormatterCommandTest.java    | 184 +++++++++++++++++++
 .../util/shell/commands/HistoryCommandTest.java |  90 +++++++++
 7 files changed, 354 insertions(+), 275 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/accumulo/blob/7f8ef553/core/src/main/java/org/apache/accumulo/core/util/shell/commands/DeleteTableCommand.java
----------------------------------------------------------------------
diff --git 
a/core/src/main/java/org/apache/accumulo/core/util/shell/commands/DeleteTableCommand.java
 
b/core/src/main/java/org/apache/accumulo/core/util/shell/commands/DeleteTableCommand.java
index a5aa32a..636a45e 100644
--- 
a/core/src/main/java/org/apache/accumulo/core/util/shell/commands/DeleteTableCommand.java
+++ 
b/core/src/main/java/org/apache/accumulo/core/util/shell/commands/DeleteTableCommand.java
@@ -16,12 +16,22 @@
  */
 package org.apache.accumulo.core.util.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.core.util.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
@@ -57,4 +67,17 @@ public class DeleteTableCommand extends TableOperation {
     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/7f8ef553/core/src/main/java/org/apache/accumulo/core/util/shell/commands/TableOperation.java
----------------------------------------------------------------------
diff --git 
a/core/src/main/java/org/apache/accumulo/core/util/shell/commands/TableOperation.java
 
b/core/src/main/java/org/apache/accumulo/core/util/shell/commands/TableOperation.java
index 27946b8..06539c2 100644
--- 
a/core/src/main/java/org/apache/accumulo/core/util/shell/commands/TableOperation.java
+++ 
b/core/src/main/java/org/apache/accumulo/core/util/shell/commands/TableOperation.java
@@ -44,10 +44,12 @@ public abstract class TableOperation extends Command {
     // 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())) {
@@ -92,6 +94,18 @@ public abstract class TableOperation extends Command {
     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

http://git-wip-us.apache.org/repos/asf/accumulo/blob/7f8ef553/core/src/test/java/org/apache/accumulo/core/util/shell/command/FormatterCommandTest.java
----------------------------------------------------------------------
diff --git 
a/core/src/test/java/org/apache/accumulo/core/util/shell/command/FormatterCommandTest.java
 
b/core/src/test/java/org/apache/accumulo/core/util/shell/command/FormatterCommandTest.java
deleted file mode 100644
index 091ef75..0000000
--- 
a/core/src/test/java/org/apache/accumulo/core/util/shell/command/FormatterCommandTest.java
+++ /dev/null
@@ -1,184 +0,0 @@
-/*
- * 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.core.util.shell.command;
-
-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.client.mock.MockShell;
-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.core.util.shell.Shell;
-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/7f8ef553/core/src/test/java/org/apache/accumulo/core/util/shell/command/HistoryCommandTest.java
----------------------------------------------------------------------
diff --git 
a/core/src/test/java/org/apache/accumulo/core/util/shell/command/HistoryCommandTest.java
 
b/core/src/test/java/org/apache/accumulo/core/util/shell/command/HistoryCommandTest.java
deleted file mode 100644
index 4d379cc..0000000
--- 
a/core/src/test/java/org/apache/accumulo/core/util/shell/command/HistoryCommandTest.java
+++ /dev/null
@@ -1,90 +0,0 @@
-/*
- * 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.core.util.shell.command;
-
-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.core.util.shell.Shell;
-import org.apache.accumulo.core.util.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"));
-  }
-
-}

http://git-wip-us.apache.org/repos/asf/accumulo/blob/7f8ef553/core/src/test/java/org/apache/accumulo/core/util/shell/commands/DeleteTableCommandTest.java
----------------------------------------------------------------------
diff --git 
a/core/src/test/java/org/apache/accumulo/core/util/shell/commands/DeleteTableCommandTest.java
 
b/core/src/test/java/org/apache/accumulo/core/util/shell/commands/DeleteTableCommandTest.java
new file mode 100644
index 0000000..ce75173
--- /dev/null
+++ 
b/core/src/test/java/org/apache/accumulo/core/util/shell/commands/DeleteTableCommandTest.java
@@ -0,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.core.util.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/7f8ef553/core/src/test/java/org/apache/accumulo/core/util/shell/commands/FormatterCommandTest.java
----------------------------------------------------------------------
diff --git 
a/core/src/test/java/org/apache/accumulo/core/util/shell/commands/FormatterCommandTest.java
 
b/core/src/test/java/org/apache/accumulo/core/util/shell/commands/FormatterCommandTest.java
new file mode 100644
index 0000000..5611e56
--- /dev/null
+++ 
b/core/src/test/java/org/apache/accumulo/core/util/shell/commands/FormatterCommandTest.java
@@ -0,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.core.util.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.client.mock.MockShell;
+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.core.util.shell.Shell;
+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/7f8ef553/core/src/test/java/org/apache/accumulo/core/util/shell/commands/HistoryCommandTest.java
----------------------------------------------------------------------
diff --git 
a/core/src/test/java/org/apache/accumulo/core/util/shell/commands/HistoryCommandTest.java
 
b/core/src/test/java/org/apache/accumulo/core/util/shell/commands/HistoryCommandTest.java
new file mode 100644
index 0000000..878e2df
--- /dev/null
+++ 
b/core/src/test/java/org/apache/accumulo/core/util/shell/commands/HistoryCommandTest.java
@@ -0,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.core.util.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.core.util.shell.Shell;
+import org.apache.accumulo.core.util.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"));
+  }
+
+}

Reply via email to