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"));
++  }
++
++}

Reply via email to