accumulo-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From ctubb...@apache.org
Subject [1/5] accumulo git commit: ACCUMULO-3804 Always seal jars
Date Tue, 12 May 2015 22:42:57 GMT
Repository: accumulo
Updated Branches:
  refs/heads/master d353b6168 -> 9cf9aaaca


http://git-wip-us.apache.org/repos/asf/accumulo/blob/9cf9aaac/test/src/test/java/org/apache/accumulo/test/proxy/TestProxyReadWrite.java
----------------------------------------------------------------------
diff --git a/test/src/test/java/org/apache/accumulo/test/proxy/TestProxyReadWrite.java b/test/src/test/java/org/apache/accumulo/test/proxy/TestProxyReadWrite.java
new file mode 100644
index 0000000..1a75fea
--- /dev/null
+++ b/test/src/test/java/org/apache/accumulo/test/proxy/TestProxyReadWrite.java
@@ -0,0 +1,468 @@
+/*
+ * 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.proxy;
+
+import static org.junit.Assert.assertEquals;
+
+import java.nio.ByteBuffer;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Properties;
+import java.util.Set;
+
+import org.apache.accumulo.core.client.security.tokens.PasswordToken;
+import org.apache.accumulo.core.iterators.user.RegExFilter;
+import org.apache.accumulo.proxy.Proxy;
+import org.apache.accumulo.proxy.Util;
+import org.apache.accumulo.proxy.thrift.BatchScanOptions;
+import org.apache.accumulo.proxy.thrift.ColumnUpdate;
+import org.apache.accumulo.proxy.thrift.IteratorSetting;
+import org.apache.accumulo.proxy.thrift.Key;
+import org.apache.accumulo.proxy.thrift.KeyValue;
+import org.apache.accumulo.proxy.thrift.Range;
+import org.apache.accumulo.proxy.thrift.ScanColumn;
+import org.apache.accumulo.proxy.thrift.ScanOptions;
+import org.apache.accumulo.proxy.thrift.ScanResult;
+import org.apache.accumulo.proxy.thrift.TimeType;
+import org.apache.thrift.protocol.TCompactProtocol;
+import org.apache.thrift.server.TServer;
+import org.junit.After;
+import org.junit.AfterClass;
+import org.junit.Before;
+import org.junit.BeforeClass;
+import org.junit.Test;
+
+import com.google.common.net.HostAndPort;
+
+public class TestProxyReadWrite {
+  protected static TServer proxy;
+  protected static TestProxyClient tpc;
+  protected static ByteBuffer userpass;
+  protected static final int port = 10194;
+  protected static final String testtable = "testtable";
+
+  @BeforeClass
+  public static void setup() throws Exception {
+    Properties prop = new Properties();
+    prop.setProperty("useMockInstance", "true");
+    prop.put("tokenClass", PasswordToken.class.getName());
+
+    proxy = Proxy.createProxyServer(HostAndPort.fromParts("localhost", port), new TCompactProtocol.Factory(), prop).server;
+    tpc = new TestProxyClient("localhost", port);
+    userpass = tpc.proxy().login("root", Collections.singletonMap("password", ""));
+  }
+
+  @AfterClass
+  public static void tearDown() throws InterruptedException {
+    proxy.stop();
+  }
+
+  @Before
+  public void makeTestTable() throws Exception {
+    tpc.proxy().createTable(userpass, testtable, true, TimeType.MILLIS);
+  }
+
+  @After
+  public void deleteTestTable() throws Exception {
+    tpc.proxy().deleteTable(userpass, testtable);
+  }
+
+  private static void addMutation(Map<ByteBuffer,List<ColumnUpdate>> mutations, String row, String cf, String cq, String value) {
+    ColumnUpdate update = new ColumnUpdate(ByteBuffer.wrap(cf.getBytes()), ByteBuffer.wrap(cq.getBytes()));
+    update.setValue(value.getBytes());
+    mutations.put(ByteBuffer.wrap(row.getBytes()), Collections.singletonList(update));
+  }
+
+  private static void addMutation(Map<ByteBuffer,List<ColumnUpdate>> mutations, String row, String cf, String cq, String vis, String value) {
+    ColumnUpdate update = new ColumnUpdate(ByteBuffer.wrap(cf.getBytes()), ByteBuffer.wrap(cq.getBytes()));
+    update.setValue(value.getBytes());
+    update.setColVisibility(vis.getBytes());
+    mutations.put(ByteBuffer.wrap(row.getBytes()), Collections.singletonList(update));
+  }
+
+  /**
+   * Insert 100000 cells which have as the row [0..99999] (padded with zeros). Set a range so only the entries between -Inf...5 come back (there should be
+   * 50,000)
+   */
+  @Test
+  public void readWriteBatchOneShotWithRange() throws Exception {
+    int maxInserts = 100000;
+    Map<ByteBuffer,List<ColumnUpdate>> mutations = new HashMap<ByteBuffer,List<ColumnUpdate>>();
+    String format = "%1$05d";
+    for (int i = 0; i < maxInserts; i++) {
+      addMutation(mutations, String.format(format, i), "cf" + i, "cq" + i, Util.randString(10));
+
+      if (i % 1000 == 0 || i == maxInserts - 1) {
+        tpc.proxy().updateAndFlush(userpass, testtable, mutations);
+        mutations.clear();
+      }
+    }
+
+    Key stop = new Key();
+    stop.setRow("5".getBytes());
+    BatchScanOptions options = new BatchScanOptions();
+    options.ranges = Collections.singletonList(new Range(null, false, stop, false));
+    String cookie = tpc.proxy().createBatchScanner(userpass, testtable, options);
+
+    int i = 0;
+    boolean hasNext = true;
+
+    int k = 1000;
+    while (hasNext) {
+      ScanResult kvList = tpc.proxy().nextK(cookie, k);
+      i += kvList.getResultsSize();
+      hasNext = kvList.isMore();
+    }
+    assertEquals(i, 50000);
+  }
+
+  /**
+   * Insert 100000 cells which have as the row [0..99999] (padded with zeros). Set a columnFamily so only the entries with specified column family come back
+   * (there should be 50,000)
+   */
+  @Test
+  public void readWriteBatchOneShotWithColumnFamilyOnly() throws Exception {
+    int maxInserts = 100000;
+    Map<ByteBuffer,List<ColumnUpdate>> mutations = new HashMap<ByteBuffer,List<ColumnUpdate>>();
+    String format = "%1$05d";
+    for (int i = 0; i < maxInserts; i++) {
+
+      addMutation(mutations, String.format(format, i), "cf" + (i % 2), "cq" + (i % 2), Util.randString(10));
+
+      if (i % 1000 == 0 || i == maxInserts - 1) {
+        tpc.proxy().updateAndFlush(userpass, testtable, mutations);
+        mutations.clear();
+      }
+    }
+
+    BatchScanOptions options = new BatchScanOptions();
+
+    ScanColumn sc = new ScanColumn();
+    sc.colFamily = ByteBuffer.wrap("cf0".getBytes());
+
+    options.columns = Collections.singletonList(sc);
+    String cookie = tpc.proxy().createBatchScanner(userpass, testtable, options);
+
+    int i = 0;
+    boolean hasNext = true;
+
+    int k = 1000;
+    while (hasNext) {
+      ScanResult kvList = tpc.proxy().nextK(cookie, k);
+      i += kvList.getResultsSize();
+      hasNext = kvList.isMore();
+    }
+    assertEquals(i, 50000);
+  }
+
+  /**
+   * Insert 100000 cells which have as the row [0..99999] (padded with zeros). Set a columnFamily + columnQualififer so only the entries with specified column
+   * come back (there should be 50,000)
+   */
+  @Test
+  public void readWriteBatchOneShotWithFullColumn() throws Exception {
+    int maxInserts = 100000;
+    Map<ByteBuffer,List<ColumnUpdate>> mutations = new HashMap<ByteBuffer,List<ColumnUpdate>>();
+    String format = "%1$05d";
+    for (int i = 0; i < maxInserts; i++) {
+
+      addMutation(mutations, String.format(format, i), "cf" + (i % 2), "cq" + (i % 2), Util.randString(10));
+
+      if (i % 1000 == 0 || i == maxInserts - 1) {
+        tpc.proxy().updateAndFlush(userpass, testtable, mutations);
+        mutations.clear();
+      }
+    }
+
+    BatchScanOptions options = new BatchScanOptions();
+
+    ScanColumn sc = new ScanColumn();
+    sc.colFamily = ByteBuffer.wrap("cf0".getBytes());
+    sc.colQualifier = ByteBuffer.wrap("cq0".getBytes());
+
+    options.columns = Collections.singletonList(sc);
+    String cookie = tpc.proxy().createBatchScanner(userpass, testtable, options);
+
+    int i = 0;
+    boolean hasNext = true;
+
+    int k = 1000;
+    while (hasNext) {
+      ScanResult kvList = tpc.proxy().nextK(cookie, k);
+      i += kvList.getResultsSize();
+      hasNext = kvList.isMore();
+    }
+    assertEquals(i, 50000);
+  }
+
+  /**
+   * Insert 100000 cells which have as the row [0..99999] (padded with zeros). Filter the results so only the even numbers come back.
+   */
+  @Test
+  public void readWriteBatchOneShotWithFilterIterator() throws Exception {
+    int maxInserts = 10000;
+    Map<ByteBuffer,List<ColumnUpdate>> mutations = new HashMap<ByteBuffer,List<ColumnUpdate>>();
+    String format = "%1$05d";
+    for (int i = 0; i < maxInserts; i++) {
+      addMutation(mutations, String.format(format, i), "cf" + i, "cq" + i, Util.randString(10));
+
+      if (i % 1000 == 0 || i == maxInserts - 1) {
+        tpc.proxy().updateAndFlush(userpass, testtable, mutations);
+        mutations.clear();
+      }
+
+    }
+
+    String regex = ".*[02468]";
+
+    org.apache.accumulo.core.client.IteratorSetting is = new org.apache.accumulo.core.client.IteratorSetting(50, regex, RegExFilter.class);
+    RegExFilter.setRegexs(is, regex, null, null, null, false);
+
+    IteratorSetting pis = Util.iteratorSetting2ProxyIteratorSetting(is);
+    ScanOptions opts = new ScanOptions();
+    opts.iterators = Collections.singletonList(pis);
+    String cookie = tpc.proxy().createScanner(userpass, testtable, opts);
+
+    int i = 0;
+    boolean hasNext = true;
+
+    int k = 1000;
+    while (hasNext) {
+      ScanResult kvList = tpc.proxy().nextK(cookie, k);
+      for (KeyValue kv : kvList.getResults()) {
+        assertEquals(Integer.parseInt(new String(kv.getKey().getRow())), i);
+
+        i += 2;
+      }
+      hasNext = kvList.isMore();
+    }
+  }
+
+  @Test
+  public void readWriteOneShotWithRange() throws Exception {
+    int maxInserts = 100000;
+    Map<ByteBuffer,List<ColumnUpdate>> mutations = new HashMap<ByteBuffer,List<ColumnUpdate>>();
+    String format = "%1$05d";
+    for (int i = 0; i < maxInserts; i++) {
+      addMutation(mutations, String.format(format, i), "cf" + i, "cq" + i, Util.randString(10));
+
+      if (i % 1000 == 0 || i == maxInserts - 1) {
+        tpc.proxy().updateAndFlush(userpass, testtable, mutations);
+        mutations.clear();
+      }
+    }
+
+    Key stop = new Key();
+    stop.setRow("5".getBytes());
+    ScanOptions opts = new ScanOptions();
+    opts.range = new Range(null, false, stop, false);
+    String cookie = tpc.proxy().createScanner(userpass, testtable, opts);
+
+    int i = 0;
+    boolean hasNext = true;
+
+    int k = 1000;
+    while (hasNext) {
+      ScanResult kvList = tpc.proxy().nextK(cookie, k);
+      i += kvList.getResultsSize();
+      hasNext = kvList.isMore();
+    }
+    assertEquals(i, 50000);
+  }
+
+  /**
+   * Insert 100000 cells which have as the row [0..99999] (padded with zeros). Filter the results so only the even numbers come back.
+   */
+  @Test
+  public void readWriteOneShotWithFilterIterator() throws Exception {
+    int maxInserts = 10000;
+    Map<ByteBuffer,List<ColumnUpdate>> mutations = new HashMap<ByteBuffer,List<ColumnUpdate>>();
+    String format = "%1$05d";
+    for (int i = 0; i < maxInserts; i++) {
+      addMutation(mutations, String.format(format, i), "cf" + i, "cq" + i, Util.randString(10));
+
+      if (i % 1000 == 0 || i == maxInserts - 1) {
+
+        tpc.proxy().updateAndFlush(userpass, testtable, mutations);
+        mutations.clear();
+
+      }
+
+    }
+
+    String regex = ".*[02468]";
+
+    org.apache.accumulo.core.client.IteratorSetting is = new org.apache.accumulo.core.client.IteratorSetting(50, regex, RegExFilter.class);
+    RegExFilter.setRegexs(is, regex, null, null, null, false);
+
+    IteratorSetting pis = Util.iteratorSetting2ProxyIteratorSetting(is);
+    ScanOptions opts = new ScanOptions();
+    opts.iterators = Collections.singletonList(pis);
+    String cookie = tpc.proxy().createScanner(userpass, testtable, opts);
+
+    int i = 0;
+    boolean hasNext = true;
+
+    int k = 1000;
+    while (hasNext) {
+      ScanResult kvList = tpc.proxy().nextK(cookie, k);
+      for (KeyValue kv : kvList.getResults()) {
+        assertEquals(Integer.parseInt(new String(kv.getKey().getRow())), i);
+
+        i += 2;
+      }
+      hasNext = kvList.isMore();
+    }
+  }
+
+  // @Test
+  // This test takes kind of a long time. Enable it if you think you may have memory issues.
+  public void manyWritesAndReads() throws Exception {
+    int maxInserts = 1000000;
+    Map<ByteBuffer,List<ColumnUpdate>> mutations = new HashMap<ByteBuffer,List<ColumnUpdate>>();
+    String format = "%1$06d";
+    String writer = tpc.proxy().createWriter(userpass, testtable, null);
+    for (int i = 0; i < maxInserts; i++) {
+      addMutation(mutations, String.format(format, i), "cf" + i, "cq" + i, Util.randString(10));
+
+      if (i % 1000 == 0 || i == maxInserts - 1) {
+
+        tpc.proxy().update(writer, mutations);
+        mutations.clear();
+
+      }
+
+    }
+
+    tpc.proxy().flush(writer);
+    tpc.proxy().closeWriter(writer);
+
+    String cookie = tpc.proxy().createScanner(userpass, testtable, null);
+
+    int i = 0;
+    boolean hasNext = true;
+
+    int k = 1000;
+    while (hasNext) {
+      ScanResult kvList = tpc.proxy().nextK(cookie, k);
+      for (KeyValue kv : kvList.getResults()) {
+        assertEquals(Integer.parseInt(new String(kv.getKey().getRow())), i);
+        i++;
+      }
+      hasNext = kvList.isMore();
+      if (hasNext)
+        assertEquals(k, kvList.getResults().size());
+    }
+    assertEquals(maxInserts, i);
+  }
+
+  @Test
+  public void asynchReadWrite() throws Exception {
+    int maxInserts = 10000;
+    Map<ByteBuffer,List<ColumnUpdate>> mutations = new HashMap<ByteBuffer,List<ColumnUpdate>>();
+    String format = "%1$05d";
+    String writer = tpc.proxy().createWriter(userpass, testtable, null);
+    for (int i = 0; i < maxInserts; i++) {
+      addMutation(mutations, String.format(format, i), "cf" + i, "cq" + i, Util.randString(10));
+
+      if (i % 1000 == 0 || i == maxInserts - 1) {
+        tpc.proxy().update(writer, mutations);
+        mutations.clear();
+      }
+    }
+
+    tpc.proxy().flush(writer);
+    tpc.proxy().closeWriter(writer);
+
+    String regex = ".*[02468]";
+
+    org.apache.accumulo.core.client.IteratorSetting is = new org.apache.accumulo.core.client.IteratorSetting(50, regex, RegExFilter.class);
+    RegExFilter.setRegexs(is, regex, null, null, null, false);
+
+    IteratorSetting pis = Util.iteratorSetting2ProxyIteratorSetting(is);
+    ScanOptions opts = new ScanOptions();
+    opts.iterators = Collections.singletonList(pis);
+    String cookie = tpc.proxy().createScanner(userpass, testtable, opts);
+
+    int i = 0;
+    boolean hasNext = true;
+
+    int k = 1000;
+    int numRead = 0;
+    while (hasNext) {
+      ScanResult kvList = tpc.proxy().nextK(cookie, k);
+      for (KeyValue kv : kvList.getResults()) {
+        assertEquals(i, Integer.parseInt(new String(kv.getKey().getRow())));
+        numRead++;
+        i += 2;
+      }
+      hasNext = kvList.isMore();
+    }
+    assertEquals(maxInserts / 2, numRead);
+  }
+
+  @Test
+  public void testVisibility() throws Exception {
+
+    Set<ByteBuffer> auths = new HashSet<ByteBuffer>();
+    auths.add(ByteBuffer.wrap("even".getBytes()));
+    tpc.proxy().changeUserAuthorizations(userpass, "root", auths);
+
+    int maxInserts = 10000;
+    Map<ByteBuffer,List<ColumnUpdate>> mutations = new HashMap<ByteBuffer,List<ColumnUpdate>>();
+    String format = "%1$05d";
+    String writer = tpc.proxy().createWriter(userpass, testtable, null);
+    for (int i = 0; i < maxInserts; i++) {
+      if (i % 2 == 0)
+        addMutation(mutations, String.format(format, i), "cf" + i, "cq" + i, "even", Util.randString(10));
+      else
+        addMutation(mutations, String.format(format, i), "cf" + i, "cq" + i, "odd", Util.randString(10));
+
+      if (i % 1000 == 0 || i == maxInserts - 1) {
+        tpc.proxy().update(writer, mutations);
+        mutations.clear();
+      }
+    }
+
+    tpc.proxy().flush(writer);
+    tpc.proxy().closeWriter(writer);
+    ScanOptions opts = new ScanOptions();
+    opts.authorizations = auths;
+    String cookie = tpc.proxy().createScanner(userpass, testtable, opts);
+
+    int i = 0;
+    boolean hasNext = true;
+
+    int k = 1000;
+    int numRead = 0;
+    while (hasNext) {
+      ScanResult kvList = tpc.proxy().nextK(cookie, k);
+      for (KeyValue kv : kvList.getResults()) {
+        assertEquals(Integer.parseInt(new String(kv.getKey().getRow())), i);
+        i += 2;
+        numRead++;
+      }
+      hasNext = kvList.isMore();
+
+    }
+    assertEquals(maxInserts / 2, numRead);
+  }
+
+}

http://git-wip-us.apache.org/repos/asf/accumulo/blob/9cf9aaac/test/src/test/java/org/apache/accumulo/test/proxy/TestProxySecurityOperations.java
----------------------------------------------------------------------
diff --git a/test/src/test/java/org/apache/accumulo/test/proxy/TestProxySecurityOperations.java b/test/src/test/java/org/apache/accumulo/test/proxy/TestProxySecurityOperations.java
new file mode 100644
index 0000000..eda38e5
--- /dev/null
+++ b/test/src/test/java/org/apache/accumulo/test/proxy/TestProxySecurityOperations.java
@@ -0,0 +1,147 @@
+/*
+ * 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.proxy;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+import java.nio.ByteBuffer;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Properties;
+import java.util.TreeMap;
+
+import org.apache.accumulo.core.client.security.tokens.PasswordToken;
+import org.apache.accumulo.core.util.ByteBufferUtil;
+import org.apache.accumulo.proxy.Proxy;
+import org.apache.accumulo.proxy.thrift.SystemPermission;
+import org.apache.accumulo.proxy.thrift.TablePermission;
+import org.apache.accumulo.proxy.thrift.TimeType;
+import org.apache.thrift.TException;
+import org.apache.thrift.protocol.TCompactProtocol;
+import org.apache.thrift.server.TServer;
+import org.junit.After;
+import org.junit.AfterClass;
+import org.junit.Before;
+import org.junit.BeforeClass;
+import org.junit.Test;
+
+import com.google.common.net.HostAndPort;
+
+public class TestProxySecurityOperations {
+  protected static TServer proxy;
+  protected static TestProxyClient tpc;
+  protected static ByteBuffer userpass;
+  protected static final int port = 10196;
+  protected static final String testtable = "testtable";
+  protected static final String testuser = "VonJines";
+  protected static final ByteBuffer testpw = ByteBuffer.wrap("fiveones".getBytes());
+
+  @BeforeClass
+  public static void setup() throws Exception {
+    Properties prop = new Properties();
+    prop.setProperty("useMockInstance", "true");
+    prop.put("tokenClass", PasswordToken.class.getName());
+
+    proxy = Proxy.createProxyServer(HostAndPort.fromParts("localhost", port), new TCompactProtocol.Factory(), prop).server;
+    while (!proxy.isServing()) {
+      Thread.sleep(500);
+    }
+    tpc = new TestProxyClient("localhost", port);
+    userpass = tpc.proxy().login("root", Collections.singletonMap("password", ""));
+  }
+
+  @AfterClass
+  public static void tearDown() throws InterruptedException {
+    proxy.stop();
+  }
+
+  @Before
+  public void makeTestTableAndUser() throws Exception {
+    tpc.proxy().createTable(userpass, testtable, true, TimeType.MILLIS);
+    tpc.proxy().createLocalUser(userpass, testuser, testpw);
+  }
+
+  @After
+  public void deleteTestTable() throws Exception {
+    tpc.proxy().deleteTable(userpass, testtable);
+    tpc.proxy().dropLocalUser(userpass, testuser);
+  }
+
+  @Test
+  public void create() throws TException {
+    tpc.proxy().createLocalUser(userpass, testuser + "2", testpw);
+    assertTrue(tpc.proxy().listLocalUsers(userpass).contains(testuser + "2"));
+    tpc.proxy().dropLocalUser(userpass, testuser + "2");
+    assertTrue(!tpc.proxy().listLocalUsers(userpass).contains(testuser + "2"));
+  }
+
+  @Test
+  public void authenticate() throws TException {
+    assertTrue(tpc.proxy().authenticateUser(userpass, testuser, bb2pp(testpw)));
+    assertFalse(tpc.proxy().authenticateUser(userpass, "EvilUser", bb2pp(testpw)));
+
+    tpc.proxy().changeLocalUserPassword(userpass, testuser, ByteBuffer.wrap("newpass".getBytes()));
+    assertFalse(tpc.proxy().authenticateUser(userpass, testuser, bb2pp(testpw)));
+    assertTrue(tpc.proxy().authenticateUser(userpass, testuser, bb2pp(ByteBuffer.wrap("newpass".getBytes()))));
+
+  }
+
+  @Test
+  public void tablePermissions() throws TException {
+    tpc.proxy().grantTablePermission(userpass, testuser, testtable, TablePermission.ALTER_TABLE);
+    assertTrue(tpc.proxy().hasTablePermission(userpass, testuser, testtable, TablePermission.ALTER_TABLE));
+
+    tpc.proxy().revokeTablePermission(userpass, testuser, testtable, TablePermission.ALTER_TABLE);
+    assertFalse(tpc.proxy().hasTablePermission(userpass, testuser, testtable, TablePermission.ALTER_TABLE));
+
+  }
+
+  @Test
+  public void systemPermissions() throws TException {
+    tpc.proxy().grantSystemPermission(userpass, testuser, SystemPermission.ALTER_USER);
+    assertTrue(tpc.proxy().hasSystemPermission(userpass, testuser, SystemPermission.ALTER_USER));
+
+    tpc.proxy().revokeSystemPermission(userpass, testuser, SystemPermission.ALTER_USER);
+    assertFalse(tpc.proxy().hasSystemPermission(userpass, testuser, SystemPermission.ALTER_USER));
+
+  }
+
+  @Test
+  public void auths() throws TException {
+    HashSet<ByteBuffer> newauths = new HashSet<ByteBuffer>();
+    newauths.add(ByteBuffer.wrap("BBR".getBytes()));
+    newauths.add(ByteBuffer.wrap("Barney".getBytes()));
+    tpc.proxy().changeUserAuthorizations(userpass, testuser, newauths);
+    List<ByteBuffer> actualauths = tpc.proxy().getUserAuthorizations(userpass, testuser);
+    assertEquals(actualauths.size(), newauths.size());
+
+    for (ByteBuffer auth : actualauths) {
+      assertTrue(newauths.contains(auth));
+    }
+  }
+
+  private Map<String,String> bb2pp(ByteBuffer cf) {
+    Map<String,String> toRet = new TreeMap<String,String>();
+    toRet.put("password", ByteBufferUtil.toString(cf));
+    return toRet;
+  }
+
+}

http://git-wip-us.apache.org/repos/asf/accumulo/blob/9cf9aaac/test/src/test/java/org/apache/accumulo/test/proxy/TestProxyTableOperations.java
----------------------------------------------------------------------
diff --git a/test/src/test/java/org/apache/accumulo/test/proxy/TestProxyTableOperations.java b/test/src/test/java/org/apache/accumulo/test/proxy/TestProxyTableOperations.java
new file mode 100644
index 0000000..e8d7b1e
--- /dev/null
+++ b/test/src/test/java/org/apache/accumulo/test/proxy/TestProxyTableOperations.java
@@ -0,0 +1,202 @@
+/*
+ * 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.proxy;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+
+import java.nio.ByteBuffer;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Properties;
+import java.util.Set;
+
+import org.apache.accumulo.core.client.security.tokens.PasswordToken;
+import org.apache.accumulo.proxy.Proxy;
+import org.apache.accumulo.proxy.thrift.ColumnUpdate;
+import org.apache.accumulo.proxy.thrift.TimeType;
+import org.apache.thrift.TException;
+import org.apache.thrift.protocol.TCompactProtocol;
+import org.apache.thrift.server.TServer;
+import org.junit.After;
+import org.junit.AfterClass;
+import org.junit.Before;
+import org.junit.BeforeClass;
+import org.junit.Test;
+
+import com.google.common.net.HostAndPort;
+
+public class TestProxyTableOperations {
+
+  protected static TServer proxy;
+  protected static TestProxyClient tpc;
+  protected static ByteBuffer userpass;
+  protected static final int port = 10195;
+  protected static final String testtable = "testtable";
+
+  @BeforeClass
+  public static void setup() throws Exception {
+    Properties prop = new Properties();
+    prop.setProperty("useMockInstance", "true");
+    prop.put("tokenClass", PasswordToken.class.getName());
+
+    proxy = Proxy.createProxyServer(HostAndPort.fromParts("localhost", port), new TCompactProtocol.Factory(), prop).server;
+    while (!proxy.isServing()) {
+      Thread.sleep(500);
+    }
+    tpc = new TestProxyClient("localhost", port);
+    userpass = tpc.proxy().login("root", Collections.singletonMap("password", ""));
+  }
+
+  @AfterClass
+  public static void tearDown() throws InterruptedException {
+    proxy.stop();
+  }
+
+  @Before
+  public void makeTestTable() throws Exception {
+    tpc.proxy().createTable(userpass, testtable, true, TimeType.MILLIS);
+  }
+
+  @After
+  public void deleteTestTable() throws Exception {
+    tpc.proxy().deleteTable(userpass, testtable);
+  }
+
+  @Test
+  public void createExistsDelete() throws TException {
+    assertFalse(tpc.proxy().tableExists(userpass, "testtable2"));
+    tpc.proxy().createTable(userpass, "testtable2", true, TimeType.MILLIS);
+    assertTrue(tpc.proxy().tableExists(userpass, "testtable2"));
+    tpc.proxy().deleteTable(userpass, "testtable2");
+    assertFalse(tpc.proxy().tableExists(userpass, "testtable2"));
+  }
+
+  @Test
+  public void listRename() throws TException {
+    assertFalse(tpc.proxy().tableExists(userpass, "testtable2"));
+    tpc.proxy().renameTable(userpass, testtable, "testtable2");
+    assertTrue(tpc.proxy().tableExists(userpass, "testtable2"));
+    tpc.proxy().renameTable(userpass, "testtable2", testtable);
+    assertTrue(tpc.proxy().listTables(userpass).contains("testtable"));
+
+  }
+
+  // This test does not yet function because the backing Mock instance does not yet support merging
+  @Test
+  public void merge() throws TException {
+    Set<ByteBuffer> splits = new HashSet<ByteBuffer>();
+    splits.add(ByteBuffer.wrap("a".getBytes()));
+    splits.add(ByteBuffer.wrap("c".getBytes()));
+    splits.add(ByteBuffer.wrap("z".getBytes()));
+    tpc.proxy().addSplits(userpass, testtable, splits);
+
+    tpc.proxy().mergeTablets(userpass, testtable, ByteBuffer.wrap("b".getBytes()), ByteBuffer.wrap("d".getBytes()));
+
+    splits.remove(ByteBuffer.wrap("c".getBytes()));
+
+    List<ByteBuffer> tableSplits = tpc.proxy().listSplits(userpass, testtable, 10);
+
+    for (ByteBuffer split : tableSplits)
+      assertTrue(splits.contains(split));
+    assertTrue(tableSplits.size() == splits.size());
+
+  }
+
+  @Test
+  public void splits() throws TException {
+    Set<ByteBuffer> splits = new HashSet<ByteBuffer>();
+    splits.add(ByteBuffer.wrap("a".getBytes()));
+    splits.add(ByteBuffer.wrap("b".getBytes()));
+    splits.add(ByteBuffer.wrap("z".getBytes()));
+    tpc.proxy().addSplits(userpass, testtable, splits);
+
+    List<ByteBuffer> tableSplits = tpc.proxy().listSplits(userpass, testtable, 10);
+
+    for (ByteBuffer split : tableSplits)
+      assertTrue(splits.contains(split));
+    assertTrue(tableSplits.size() == splits.size());
+  }
+
+  @Test
+  public void constraints() throws TException {
+    int cid = tpc.proxy().addConstraint(userpass, testtable, "org.apache.accumulo.TestConstraint");
+    Map<String,Integer> constraints = tpc.proxy().listConstraints(userpass, testtable);
+    assertEquals((int) constraints.get("org.apache.accumulo.TestConstraint"), cid);
+    tpc.proxy().removeConstraint(userpass, testtable, cid);
+    constraints = tpc.proxy().listConstraints(userpass, testtable);
+    assertNull(constraints.get("org.apache.accumulo.TestConstraint"));
+  }
+
+  @Test
+  public void localityGroups() throws TException {
+    Map<String,Set<String>> groups = new HashMap<String,Set<String>>();
+    Set<String> group1 = new HashSet<String>();
+    group1.add("cf1");
+    groups.put("group1", group1);
+    Set<String> group2 = new HashSet<String>();
+    group2.add("cf2");
+    group2.add("cf3");
+    groups.put("group2", group2);
+    tpc.proxy().setLocalityGroups(userpass, testtable, groups);
+
+    Map<String,Set<String>> actualGroups = tpc.proxy().getLocalityGroups(userpass, testtable);
+
+    assertEquals(groups.size(), actualGroups.size());
+    for (String groupName : groups.keySet()) {
+      assertTrue(actualGroups.containsKey(groupName));
+      assertEquals(groups.get(groupName).size(), actualGroups.get(groupName).size());
+      for (String cf : groups.get(groupName)) {
+        assertTrue(actualGroups.get(groupName).contains(cf));
+      }
+    }
+  }
+
+  @Test
+  public void tableProperties() throws TException {
+    tpc.proxy().setTableProperty(userpass, testtable, "test.property1", "wharrrgarbl");
+    assertEquals(tpc.proxy().getTableProperties(userpass, testtable).get("test.property1"), "wharrrgarbl");
+    tpc.proxy().removeTableProperty(userpass, testtable, "test.property1");
+    assertNull(tpc.proxy().getTableProperties(userpass, testtable).get("test.property1"));
+  }
+
+  private static void addMutation(Map<ByteBuffer,List<ColumnUpdate>> mutations, String row, String cf, String cq, String value) {
+    ColumnUpdate update = new ColumnUpdate(ByteBuffer.wrap(cf.getBytes()), ByteBuffer.wrap(cq.getBytes()));
+    update.setValue(value.getBytes());
+    mutations.put(ByteBuffer.wrap(row.getBytes()), Collections.singletonList(update));
+  }
+
+  @Test
+  public void tableOperationsRowMethods() throws TException {
+    Map<ByteBuffer,List<ColumnUpdate>> mutations = new HashMap<ByteBuffer,List<ColumnUpdate>>();
+    for (int i = 0; i < 10; i++) {
+      addMutation(mutations, "" + i, "cf", "cq", "");
+    }
+    tpc.proxy().updateAndFlush(userpass, testtable, mutations);
+
+    assertEquals(tpc.proxy().getMaxRow(userpass, testtable, null, null, true, null, true), ByteBuffer.wrap("9".getBytes()));
+
+    tpc.proxy().deleteRows(userpass, testtable, ByteBuffer.wrap("51".getBytes()), ByteBuffer.wrap("99".getBytes()));
+    assertEquals(tpc.proxy().getMaxRow(userpass, testtable, null, null, true, null, true), ByteBuffer.wrap("5".getBytes()));
+  }
+
+}

http://git-wip-us.apache.org/repos/asf/accumulo/blob/9cf9aaac/test/src/test/java/org/apache/accumulo/test/server/security/SystemCredentialsIT.java
----------------------------------------------------------------------
diff --git a/test/src/test/java/org/apache/accumulo/test/server/security/SystemCredentialsIT.java b/test/src/test/java/org/apache/accumulo/test/server/security/SystemCredentialsIT.java
new file mode 100644
index 0000000..7167f6a
--- /dev/null
+++ b/test/src/test/java/org/apache/accumulo/test/server/security/SystemCredentialsIT.java
@@ -0,0 +1,233 @@
+/*
+ * 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.server.security;
+
+import static org.junit.Assert.assertEquals;
+
+import java.nio.ByteBuffer;
+import java.util.List;
+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.Connector;
+import org.apache.accumulo.core.client.Instance;
+import org.apache.accumulo.core.client.Scanner;
+import org.apache.accumulo.core.client.TableNotFoundException;
+import org.apache.accumulo.core.client.impl.Credentials;
+import org.apache.accumulo.core.client.security.SecurityErrorCode;
+import org.apache.accumulo.core.client.security.tokens.AuthenticationToken;
+import org.apache.accumulo.core.client.security.tokens.PasswordToken;
+import org.apache.accumulo.core.conf.AccumuloConfiguration;
+import org.apache.accumulo.core.data.Key;
+import org.apache.accumulo.core.data.Value;
+import org.apache.accumulo.core.metadata.RootTable;
+import org.apache.accumulo.core.security.Authorizations;
+import org.apache.accumulo.server.client.HdfsZooInstance;
+import org.apache.accumulo.server.security.SystemCredentials;
+import org.apache.accumulo.test.functional.ConfigurableMacIT;
+import org.junit.Test;
+
+public class SystemCredentialsIT extends ConfigurableMacIT {
+
+  private static final int FAIL_CODE = 7, BAD_PASSWD_FAIL_CODE = 8;
+
+  @Override
+  protected int defaultTimeoutSeconds() {
+    return 1 * 60;
+  }
+
+  @Test
+  public void testSystemCredentials() throws Exception {
+    assertEquals(0, exec(SystemCredentialsIT.class, "good", getCluster().getZooKeepers()).waitFor());
+    assertEquals(FAIL_CODE, exec(SystemCredentialsIT.class, "bad", getCluster().getZooKeepers()).waitFor());
+    assertEquals(BAD_PASSWD_FAIL_CODE, exec(SystemCredentialsIT.class, "bad_password", getCluster().getZooKeepers()).waitFor());
+  }
+
+  public static void main(final String[] args) throws AccumuloException, TableNotFoundException, AccumuloSecurityException {
+    Credentials creds = null;
+    if (args.length < 2)
+      throw new RuntimeException("Incorrect usage; expected to be run by test only");
+    if (args[0].equals("bad")) {
+      Instance inst = new Instance() {
+
+        @Deprecated
+        @Override
+        public void setConfiguration(AccumuloConfiguration conf) {
+          throw new UnsupportedOperationException();
+        }
+
+        @Override
+        public int getZooKeepersSessionTimeOut() {
+          throw new UnsupportedOperationException();
+        }
+
+        @Override
+        public String getZooKeepers() {
+          throw new UnsupportedOperationException();
+        }
+
+        @Override
+        public String getRootTabletLocation() {
+          throw new UnsupportedOperationException();
+        }
+
+        @Override
+        public List<String> getMasterLocations() {
+          throw new UnsupportedOperationException();
+        }
+
+        @Override
+        public String getInstanceName() {
+          throw new UnsupportedOperationException();
+        }
+
+        @Override
+        public String getInstanceID() {
+          return SystemCredentials.class.getName();
+        }
+
+        @Override
+        public Connector getConnector(String principal, AuthenticationToken token) throws AccumuloException, AccumuloSecurityException {
+          throw new UnsupportedOperationException();
+        }
+
+        @Deprecated
+        @Override
+        public Connector getConnector(String user, CharSequence pass) throws AccumuloException, AccumuloSecurityException {
+          throw new UnsupportedOperationException();
+        }
+
+        @Deprecated
+        @Override
+        public Connector getConnector(String user, ByteBuffer pass) throws AccumuloException, AccumuloSecurityException {
+          throw new UnsupportedOperationException();
+        }
+
+        @Deprecated
+        @Override
+        public Connector getConnector(String user, byte[] pass) throws AccumuloException, AccumuloSecurityException {
+          throw new UnsupportedOperationException();
+        }
+
+        @Deprecated
+        @Override
+        public AccumuloConfiguration getConfiguration() {
+          throw new UnsupportedOperationException();
+        }
+
+      };
+      creds = SystemCredentials.get(inst);
+    } else if (args[0].equals("good")) {
+      creds = SystemCredentials.get(HdfsZooInstance.getInstance());
+    } else if (args[0].equals("bad_password")) {
+      Instance inst = new Instance() {
+
+        @Override
+        public int getZooKeepersSessionTimeOut() {
+          throw new UnsupportedOperationException();
+        }
+
+        @Override
+        public String getZooKeepers() {
+          throw new UnsupportedOperationException();
+        }
+
+        @Override
+        public String getRootTabletLocation() {
+          throw new UnsupportedOperationException();
+        }
+
+        @Override
+        public List<String> getMasterLocations() {
+          throw new UnsupportedOperationException();
+        }
+
+        @Override
+        public String getInstanceName() {
+          throw new UnsupportedOperationException();
+        }
+
+        @Override
+        public String getInstanceID() {
+          return SystemCredentials.class.getName();
+        }
+
+        @Override
+        public Connector getConnector(String principal, AuthenticationToken token) throws AccumuloException, AccumuloSecurityException {
+          throw new UnsupportedOperationException();
+        }
+
+        @Deprecated
+        @Override
+        public Connector getConnector(String user, CharSequence pass) throws AccumuloException, AccumuloSecurityException {
+          throw new UnsupportedOperationException();
+        }
+
+        @Deprecated
+        @Override
+        public Connector getConnector(String user, ByteBuffer pass) throws AccumuloException, AccumuloSecurityException {
+          throw new UnsupportedOperationException();
+        }
+
+        @Deprecated
+        @Override
+        public Connector getConnector(String user, byte[] pass) throws AccumuloException, AccumuloSecurityException {
+          throw new UnsupportedOperationException();
+        }
+
+        @Deprecated
+        @Override
+        public AccumuloConfiguration getConfiguration() {
+          throw new UnsupportedOperationException();
+        }
+
+        @Deprecated
+        @Override
+        public void setConfiguration(AccumuloConfiguration conf) {
+          throw new UnsupportedOperationException();
+        }
+
+      };
+      creds = new SystemCredentials(inst, "!SYSTEM", new PasswordToken("fake"));
+    } else {
+      throw new RuntimeException("Incorrect usage; expected to be run by test only");
+    }
+    Instance instance = HdfsZooInstance.getInstance();
+    Connector conn;
+    try {
+      conn = instance.getConnector(creds.getPrincipal(), creds.getToken());
+    } catch (AccumuloSecurityException e) {
+      e.printStackTrace(System.err);
+      System.exit(BAD_PASSWD_FAIL_CODE);
+      return;
+    }
+    try {
+      Scanner scan = conn.createScanner(RootTable.NAME, Authorizations.EMPTY);
+      for (Entry<Key,Value> e : scan) {
+        e.hashCode();
+      }
+    } catch (RuntimeException e) {
+      // catch the runtime exception from the scanner iterator
+      if (e.getCause() instanceof AccumuloSecurityException
+          && ((AccumuloSecurityException) e.getCause()).getSecurityErrorCode() == SecurityErrorCode.BAD_CREDENTIALS) {
+        e.printStackTrace(System.err);
+        System.exit(FAIL_CODE);
+      }
+    }
+  }
+}

http://git-wip-us.apache.org/repos/asf/accumulo/blob/9cf9aaac/test/src/test/java/org/apache/accumulo/test/start/KeywordStartIT.java
----------------------------------------------------------------------
diff --git a/test/src/test/java/org/apache/accumulo/test/start/KeywordStartIT.java b/test/src/test/java/org/apache/accumulo/test/start/KeywordStartIT.java
new file mode 100644
index 0000000..f7f250a
--- /dev/null
+++ b/test/src/test/java/org/apache/accumulo/test/start/KeywordStartIT.java
@@ -0,0 +1,197 @@
+/*
+ * 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.start;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+import java.io.IOException;
+import java.lang.reflect.Method;
+import java.lang.reflect.Modifier;
+import java.util.Arrays;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.TreeMap;
+
+import org.apache.accumulo.core.file.rfile.PrintInfo;
+import org.apache.accumulo.core.util.Classpath;
+import org.apache.accumulo.core.util.CreateToken;
+import org.apache.accumulo.core.util.Help;
+import org.apache.accumulo.core.util.Jar;
+import org.apache.accumulo.core.util.Version;
+import org.apache.accumulo.gc.GCExecutable;
+import org.apache.accumulo.gc.SimpleGarbageCollector;
+import org.apache.accumulo.master.Master;
+import org.apache.accumulo.master.MasterExecutable;
+import org.apache.accumulo.minicluster.MiniAccumuloRunner;
+import org.apache.accumulo.minicluster.impl.MiniClusterExecutable;
+import org.apache.accumulo.monitor.Monitor;
+import org.apache.accumulo.monitor.MonitorExecutable;
+import org.apache.accumulo.proxy.Proxy;
+import org.apache.accumulo.server.init.Initialize;
+import org.apache.accumulo.server.util.Admin;
+import org.apache.accumulo.server.util.Info;
+import org.apache.accumulo.server.util.LoginProperties;
+import org.apache.accumulo.server.util.ZooKeeperMain;
+import org.apache.accumulo.shell.Shell;
+import org.apache.accumulo.start.Main;
+import org.apache.accumulo.start.spi.KeywordExecutable;
+import org.apache.accumulo.tracer.TraceServer;
+import org.apache.accumulo.tracer.TracerExecutable;
+import org.apache.accumulo.tserver.TServerExecutable;
+import org.apache.accumulo.tserver.TabletServer;
+import org.junit.Test;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class KeywordStartIT {
+
+  private final Logger log = LoggerFactory.getLogger(getClass());
+
+  @Test
+  public void testKeywordsMatch() throws IOException {
+    for (Entry<String,KeywordExecutable> entry : Main.getExecutables(getClass().getClassLoader()).entrySet()) {
+      assertEquals(entry.getKey(), entry.getValue().keyword());
+    }
+  }
+
+  @Test
+  public void testCheckDuplicates() {
+    NoOp one = new NoOp("one");
+    NoOp anotherOne = new NoOp("another");
+    NoOp two = new NoOp("two");
+    NoOp three = new NoOp("three");
+    List<NoOp> services = Arrays.asList(one, three, two, two, three, three, anotherOne);
+    assertEquals(7, services.size());
+    Map<String,KeywordExecutable> results = Main.checkDuplicates(services);
+    assertTrue(results.containsKey(one.keyword()));
+    assertTrue(results.containsKey(anotherOne.keyword()));
+    assertFalse(results.containsKey(two.keyword()));
+    assertFalse(results.containsKey(three.keyword()));
+    assertEquals(2, results.size());
+  }
+
+  // Note: this test may fail in Eclipse, if the services files haven't been generated by the AutoService annotation processor
+  @Test
+  public void testExpectedClasses() throws IOException {
+    TreeMap<String,Class<? extends KeywordExecutable>> expectSet = new TreeMap<>();
+    expectSet.put("admin", Admin.class);
+    expectSet.put("classpath", Classpath.class);
+    expectSet.put("create-token", CreateToken.class);
+    expectSet.put("gc", GCExecutable.class);
+    expectSet.put("help", Help.class);
+    expectSet.put("info", Info.class);
+    expectSet.put("init", Initialize.class);
+    expectSet.put("jar", Jar.class);
+    expectSet.put("login-info", LoginProperties.class);
+    expectSet.put("master", MasterExecutable.class);
+    expectSet.put("minicluster", MiniClusterExecutable.class);
+    expectSet.put("monitor", MonitorExecutable.class);
+    expectSet.put("proxy", Proxy.class);
+    expectSet.put("rfile-info", PrintInfo.class);
+    expectSet.put("shell", Shell.class);
+    expectSet.put("tracer", TracerExecutable.class);
+    expectSet.put("tserver", TServerExecutable.class);
+    expectSet.put("version", Version.class);
+    expectSet.put("zookeeper", ZooKeeperMain.class);
+
+    Iterator<Entry<String,Class<? extends KeywordExecutable>>> expectIter = expectSet.entrySet().iterator();
+    TreeMap<String,KeywordExecutable> actualSet = new TreeMap<>(Main.getExecutables(getClass().getClassLoader()));
+    Iterator<Entry<String,KeywordExecutable>> actualIter = actualSet.entrySet().iterator();
+    Entry<String,Class<? extends KeywordExecutable>> expected;
+    Entry<String,KeywordExecutable> actual;
+    while (expectIter.hasNext() && actualIter.hasNext()) {
+      expected = expectIter.next();
+      actual = actualIter.next();
+      assertEquals(expected.getKey(), actual.getKey());
+      assertEquals(expected.getValue(), actual.getValue().getClass());
+    }
+    boolean moreExpected = expectIter.hasNext();
+    if (moreExpected) {
+      while (expectIter.hasNext()) {
+        log.warn("Missing class for keyword '" + expectIter.next() + "'");
+      }
+    }
+    assertFalse("Missing expected classes", moreExpected);
+    boolean moreActual = actualIter.hasNext();
+    if (moreActual) {
+      while (actualIter.hasNext()) {
+        log.warn("Extra class found with keyword '" + actualIter.next() + "'");
+      }
+    }
+    assertFalse("Found additional unexpected classes", moreActual);
+  }
+
+  @Test
+  public void checkHasMain() {
+    assertFalse("Sanity check for test failed. Somehow the test class has a main method", hasMain(this.getClass()));
+
+    HashSet<Class<?>> expectSet = new HashSet<>();
+    expectSet.add(Admin.class);
+    expectSet.add(CreateToken.class);
+    expectSet.add(Info.class);
+    expectSet.add(Initialize.class);
+    expectSet.add(LoginProperties.class);
+    expectSet.add(Master.class);
+    expectSet.add(MiniAccumuloRunner.class);
+    expectSet.add(Monitor.class);
+    expectSet.add(PrintInfo.class);
+    expectSet.add(Proxy.class);
+    expectSet.add(Shell.class);
+    expectSet.add(SimpleGarbageCollector.class);
+    expectSet.add(TabletServer.class);
+    expectSet.add(TraceServer.class);
+    expectSet.add(ZooKeeperMain.class);
+
+    for (Class<?> c : expectSet) {
+      assertTrue("Class " + c.getName() + " is missing a main method!", hasMain(c));
+    }
+
+  }
+
+  private static boolean hasMain(Class<?> classToCheck) {
+    Method main;
+    try {
+      main = classToCheck.getMethod("main", new String[0].getClass());
+    } catch (NoSuchMethodException e) {
+      return false;
+    }
+    return main != null && Modifier.isPublic(main.getModifiers()) && Modifier.isStatic(main.getModifiers());
+  }
+
+  private static class NoOp implements KeywordExecutable {
+
+    private final String kw;
+
+    public NoOp(String kw) {
+      this.kw = kw;
+    }
+
+    @Override
+    public String keyword() {
+      return kw;
+    }
+
+    @Override
+    public void execute(String[] args) throws Exception {}
+
+  }
+}


Mime
View raw message