accumulo-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From e..@apache.org
Subject [39/43] accumulo git commit: ACCUMULO-3871 move ITs into distro jar, stop building test jar
Date Thu, 04 Jun 2015 18:53:20 GMT
http://git-wip-us.apache.org/repos/asf/accumulo/blob/01ae5b85/test/src/main/java/org/apache/accumulo/test/MultiTableBatchWriterIT.java
----------------------------------------------------------------------
diff --git a/test/src/main/java/org/apache/accumulo/test/MultiTableBatchWriterIT.java b/test/src/main/java/org/apache/accumulo/test/MultiTableBatchWriterIT.java
new file mode 100644
index 0000000..2b03780
--- /dev/null
+++ b/test/src/main/java/org/apache/accumulo/test/MultiTableBatchWriterIT.java
@@ -0,0 +1,518 @@
+/*
+ * 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;
+
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.concurrent.TimeUnit;
+
+import org.apache.accumulo.core.client.AccumuloException;
+import org.apache.accumulo.core.client.AccumuloSecurityException;
+import org.apache.accumulo.core.client.BatchWriter;
+import org.apache.accumulo.core.client.BatchWriterConfig;
+import org.apache.accumulo.core.client.Connector;
+import org.apache.accumulo.core.client.MultiTableBatchWriter;
+import org.apache.accumulo.core.client.MutationsRejectedException;
+import org.apache.accumulo.core.client.Scanner;
+import org.apache.accumulo.core.client.TableNotFoundException;
+import org.apache.accumulo.core.client.TableOfflineException;
+import org.apache.accumulo.core.client.admin.TableOperations;
+import org.apache.accumulo.core.client.impl.ClientContext;
+import org.apache.accumulo.core.client.impl.Credentials;
+import org.apache.accumulo.core.client.impl.MultiTableBatchWriterImpl;
+import org.apache.accumulo.core.data.Key;
+import org.apache.accumulo.core.data.Mutation;
+import org.apache.accumulo.core.data.Range;
+import org.apache.accumulo.core.data.Value;
+import org.apache.accumulo.core.security.Authorizations;
+import org.apache.accumulo.harness.AccumuloClusterHarness;
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Test;
+
+import com.google.common.collect.Maps;
+
+public class MultiTableBatchWriterIT extends AccumuloClusterHarness {
+
+  private Connector connector;
+  private MultiTableBatchWriter mtbw;
+
+  @Override
+  public int defaultTimeoutSeconds() {
+    return 5 * 60;
+  }
+
+  @Before
+  public void setUpArgs() throws AccumuloException, AccumuloSecurityException {
+    connector = getConnector();
+    mtbw = getMultiTableBatchWriter(60);
+  }
+
+  public MultiTableBatchWriter getMultiTableBatchWriter(long cacheTimeoutInSeconds) {
+    ClientContext context = new ClientContext(connector.getInstance(), new Credentials(getAdminPrincipal(), getAdminToken()), getCluster().getClientConfig());
+    return new MultiTableBatchWriterImpl(context, new BatchWriterConfig(), cacheTimeoutInSeconds, TimeUnit.SECONDS);
+  }
+
+  @Test
+  public void testTableRenameDataValidation() throws Exception {
+
+    try {
+      final String[] names = getUniqueNames(2);
+      final String table1 = names[0], table2 = names[1];
+
+      TableOperations tops = connector.tableOperations();
+      tops.create(table1);
+
+      BatchWriter bw1 = mtbw.getBatchWriter(table1);
+
+      Mutation m1 = new Mutation("foo");
+      m1.put("col1", "", "val1");
+
+      bw1.addMutation(m1);
+
+      tops.rename(table1, table2);
+      tops.create(table1);
+
+      BatchWriter bw2 = mtbw.getBatchWriter(table1);
+
+      Mutation m2 = new Mutation("bar");
+      m2.put("col1", "", "val1");
+
+      bw1.addMutation(m2);
+      bw2.addMutation(m2);
+
+      mtbw.close();
+
+      Map<Entry<String,String>,String> table1Expectations = new HashMap<Entry<String,String>,String>();
+      table1Expectations.put(Maps.immutableEntry("bar", "col1"), "val1");
+
+      Map<Entry<String,String>,String> table2Expectations = new HashMap<Entry<String,String>,String>();
+      table2Expectations.put(Maps.immutableEntry("foo", "col1"), "val1");
+      table2Expectations.put(Maps.immutableEntry("bar", "col1"), "val1");
+
+      Scanner s = connector.createScanner(table1, new Authorizations());
+      s.setRange(new Range());
+      Map<Entry<String,String>,String> actual = new HashMap<Entry<String,String>,String>();
+      for (Entry<Key,Value> entry : s) {
+        actual.put(Maps.immutableEntry(entry.getKey().getRow().toString(), entry.getKey().getColumnFamily().toString()), entry.getValue().toString());
+      }
+
+      Assert.assertEquals("Differing results for " + table1, table1Expectations, actual);
+
+      s = connector.createScanner(table2, new Authorizations());
+      s.setRange(new Range());
+      actual = new HashMap<Entry<String,String>,String>();
+      for (Entry<Key,Value> entry : s) {
+        actual.put(Maps.immutableEntry(entry.getKey().getRow().toString(), entry.getKey().getColumnFamily().toString()), entry.getValue().toString());
+      }
+
+      Assert.assertEquals("Differing results for " + table2, table2Expectations, actual);
+
+    } finally {
+      if (null != mtbw) {
+        mtbw.close();
+      }
+    }
+  }
+
+  @Test
+  public void testTableRenameSameWriters() throws Exception {
+
+    try {
+      final String[] names = getUniqueNames(4);
+      final String table1 = names[0], table2 = names[1];
+      final String newTable1 = names[2], newTable2 = names[3];
+
+      TableOperations tops = connector.tableOperations();
+      tops.create(table1);
+      tops.create(table2);
+
+      BatchWriter bw1 = mtbw.getBatchWriter(table1), bw2 = mtbw.getBatchWriter(table2);
+
+      Mutation m1 = new Mutation("foo");
+      m1.put("col1", "", "val1");
+      m1.put("col2", "", "val2");
+
+      bw1.addMutation(m1);
+      bw2.addMutation(m1);
+
+      tops.rename(table1, newTable1);
+      tops.rename(table2, newTable2);
+
+      Mutation m2 = new Mutation("bar");
+      m2.put("col1", "", "val1");
+      m2.put("col2", "", "val2");
+
+      bw1.addMutation(m2);
+      bw2.addMutation(m2);
+
+      mtbw.close();
+
+      Map<Entry<String,String>,String> expectations = new HashMap<Entry<String,String>,String>();
+      expectations.put(Maps.immutableEntry("foo", "col1"), "val1");
+      expectations.put(Maps.immutableEntry("foo", "col2"), "val2");
+      expectations.put(Maps.immutableEntry("bar", "col1"), "val1");
+      expectations.put(Maps.immutableEntry("bar", "col2"), "val2");
+
+      for (String table : Arrays.asList(newTable1, newTable2)) {
+        Scanner s = connector.createScanner(table, new Authorizations());
+        s.setRange(new Range());
+        Map<Entry<String,String>,String> actual = new HashMap<Entry<String,String>,String>();
+        for (Entry<Key,Value> entry : s) {
+          actual.put(Maps.immutableEntry(entry.getKey().getRow().toString(), entry.getKey().getColumnFamily().toString()), entry.getValue().toString());
+        }
+
+        Assert.assertEquals("Differing results for " + table, expectations, actual);
+      }
+    } finally {
+      if (null != mtbw) {
+        mtbw.close();
+      }
+    }
+  }
+
+  @Test
+  public void testTableRenameNewWriters() throws Exception {
+
+    try {
+      final String[] names = getUniqueNames(4);
+      final String table1 = names[0], table2 = names[1];
+      final String newTable1 = names[2], newTable2 = names[3];
+
+      TableOperations tops = connector.tableOperations();
+      tops.create(table1);
+      tops.create(table2);
+
+      BatchWriter bw1 = mtbw.getBatchWriter(table1), bw2 = mtbw.getBatchWriter(table2);
+
+      Mutation m1 = new Mutation("foo");
+      m1.put("col1", "", "val1");
+      m1.put("col2", "", "val2");
+
+      bw1.addMutation(m1);
+      bw2.addMutation(m1);
+
+      tops.rename(table1, newTable1);
+
+      // MTBW is still caching this name to the correct table, but we should invalidate its cache
+      // after seeing the rename
+      try {
+        bw1 = mtbw.getBatchWriter(table1);
+        Assert.fail("Should not be able to find this table");
+      } catch (TableNotFoundException e) {
+        // pass
+      }
+
+      tops.rename(table2, newTable2);
+
+      try {
+        bw2 = mtbw.getBatchWriter(table2);
+        Assert.fail("Should not be able to find this table");
+      } catch (TableNotFoundException e) {
+        // pass
+      }
+
+      bw1 = mtbw.getBatchWriter(newTable1);
+      bw2 = mtbw.getBatchWriter(newTable2);
+
+      Mutation m2 = new Mutation("bar");
+      m2.put("col1", "", "val1");
+      m2.put("col2", "", "val2");
+
+      bw1.addMutation(m2);
+      bw2.addMutation(m2);
+
+      mtbw.close();
+
+      Map<Entry<String,String>,String> expectations = new HashMap<Entry<String,String>,String>();
+      expectations.put(Maps.immutableEntry("foo", "col1"), "val1");
+      expectations.put(Maps.immutableEntry("foo", "col2"), "val2");
+      expectations.put(Maps.immutableEntry("bar", "col1"), "val1");
+      expectations.put(Maps.immutableEntry("bar", "col2"), "val2");
+
+      for (String table : Arrays.asList(newTable1, newTable2)) {
+        Scanner s = connector.createScanner(table, new Authorizations());
+        s.setRange(new Range());
+        Map<Entry<String,String>,String> actual = new HashMap<Entry<String,String>,String>();
+        for (Entry<Key,Value> entry : s) {
+          actual.put(Maps.immutableEntry(entry.getKey().getRow().toString(), entry.getKey().getColumnFamily().toString()), entry.getValue().toString());
+        }
+
+        Assert.assertEquals("Differing results for " + table, expectations, actual);
+      }
+    } finally {
+      if (null != mtbw) {
+        mtbw.close();
+      }
+    }
+  }
+
+  @Test
+  public void testTableRenameNewWritersNoCaching() throws Exception {
+    mtbw = getMultiTableBatchWriter(0);
+
+    try {
+      final String[] names = getUniqueNames(4);
+      final String table1 = names[0], table2 = names[1];
+      final String newTable1 = names[2], newTable2 = names[3];
+
+      TableOperations tops = connector.tableOperations();
+      tops.create(table1);
+      tops.create(table2);
+
+      BatchWriter bw1 = mtbw.getBatchWriter(table1), bw2 = mtbw.getBatchWriter(table2);
+
+      Mutation m1 = new Mutation("foo");
+      m1.put("col1", "", "val1");
+      m1.put("col2", "", "val2");
+
+      bw1.addMutation(m1);
+      bw2.addMutation(m1);
+
+      tops.rename(table1, newTable1);
+      tops.rename(table2, newTable2);
+
+      try {
+        bw1 = mtbw.getBatchWriter(table1);
+        Assert.fail("Should not have gotten batchwriter for " + table1);
+      } catch (TableNotFoundException e) {
+        // Pass
+      }
+
+      try {
+        bw2 = mtbw.getBatchWriter(table2);
+      } catch (TableNotFoundException e) {
+        // Pass
+      }
+    } finally {
+      if (null != mtbw) {
+        mtbw.close();
+      }
+    }
+  }
+
+  @Test
+  public void testTableDelete() throws Exception {
+    boolean mutationsRejected = false;
+
+    try {
+      final String[] names = getUniqueNames(2);
+      final String table1 = names[0], table2 = names[1];
+
+      TableOperations tops = connector.tableOperations();
+      tops.create(table1);
+      tops.create(table2);
+
+      BatchWriter bw1 = mtbw.getBatchWriter(table1), bw2 = mtbw.getBatchWriter(table2);
+
+      Mutation m1 = new Mutation("foo");
+      m1.put("col1", "", "val1");
+      m1.put("col2", "", "val2");
+
+      bw1.addMutation(m1);
+      bw2.addMutation(m1);
+
+      tops.delete(table1);
+      tops.delete(table2);
+
+      Mutation m2 = new Mutation("bar");
+      m2.put("col1", "", "val1");
+      m2.put("col2", "", "val2");
+
+      try {
+        bw1.addMutation(m2);
+        bw2.addMutation(m2);
+      } catch (MutationsRejectedException e) {
+        // Pass - Mutations might flush immediately
+        mutationsRejected = true;
+      }
+
+    } finally {
+      if (null != mtbw) {
+        try {
+          // Mutations might have flushed before the table offline occurred
+          mtbw.close();
+        } catch (MutationsRejectedException e) {
+          // Pass
+          mutationsRejected = true;
+        }
+      }
+    }
+
+    Assert.assertTrue("Expected mutations to be rejected.", mutationsRejected);
+  }
+
+  @Test
+  public void testOfflineTable() throws Exception {
+    boolean mutationsRejected = false;
+
+    try {
+      final String[] names = getUniqueNames(2);
+      final String table1 = names[0], table2 = names[1];
+
+      TableOperations tops = connector.tableOperations();
+      tops.create(table1);
+      tops.create(table2);
+
+      BatchWriter bw1 = mtbw.getBatchWriter(table1), bw2 = mtbw.getBatchWriter(table2);
+
+      Mutation m1 = new Mutation("foo");
+      m1.put("col1", "", "val1");
+      m1.put("col2", "", "val2");
+
+      bw1.addMutation(m1);
+      bw2.addMutation(m1);
+
+      tops.offline(table1, true);
+      tops.offline(table2, true);
+
+      Mutation m2 = new Mutation("bar");
+      m2.put("col1", "", "val1");
+      m2.put("col2", "", "val2");
+
+      try {
+        bw1.addMutation(m2);
+        bw2.addMutation(m2);
+      } catch (MutationsRejectedException e) {
+        // Pass -- Mutations might flush immediately and fail because of offline table
+        mutationsRejected = true;
+      }
+    } finally {
+      if (null != mtbw) {
+        try {
+          mtbw.close();
+        } catch (MutationsRejectedException e) {
+          // Pass
+          mutationsRejected = true;
+        }
+      }
+    }
+
+    Assert.assertTrue("Expected mutations to be rejected.", mutationsRejected);
+  }
+
+  @Test
+  public void testOfflineTableWithCache() throws Exception {
+    boolean mutationsRejected = false;
+
+    try {
+      final String[] names = getUniqueNames(2);
+      final String table1 = names[0], table2 = names[1];
+
+      TableOperations tops = connector.tableOperations();
+      tops.create(table1);
+      tops.create(table2);
+
+      BatchWriter bw1 = mtbw.getBatchWriter(table1), bw2 = mtbw.getBatchWriter(table2);
+
+      Mutation m1 = new Mutation("foo");
+      m1.put("col1", "", "val1");
+      m1.put("col2", "", "val2");
+
+      bw1.addMutation(m1);
+      bw2.addMutation(m1);
+
+      tops.offline(table1);
+
+      try {
+        bw1 = mtbw.getBatchWriter(table1);
+      } catch (TableOfflineException e) {
+        // pass
+        mutationsRejected = true;
+      }
+
+      tops.offline(table2);
+
+      try {
+        bw2 = mtbw.getBatchWriter(table2);
+      } catch (TableOfflineException e) {
+        // pass
+        mutationsRejected = true;
+      }
+    } finally {
+      if (null != mtbw) {
+        try {
+          // Mutations might have flushed before the table offline occurred
+          mtbw.close();
+        } catch (MutationsRejectedException e) {
+          // Pass
+          mutationsRejected = true;
+        }
+      }
+    }
+
+    Assert.assertTrue("Expected mutations to be rejected.", mutationsRejected);
+  }
+
+  @Test
+  public void testOfflineTableWithoutCache() throws Exception {
+    mtbw = getMultiTableBatchWriter(0);
+    boolean mutationsRejected = false;
+
+    try {
+      final String[] names = getUniqueNames(2);
+      final String table1 = names[0], table2 = names[1];
+
+      TableOperations tops = connector.tableOperations();
+      tops.create(table1);
+      tops.create(table2);
+
+      BatchWriter bw1 = mtbw.getBatchWriter(table1), bw2 = mtbw.getBatchWriter(table2);
+
+      Mutation m1 = new Mutation("foo");
+      m1.put("col1", "", "val1");
+      m1.put("col2", "", "val2");
+
+      bw1.addMutation(m1);
+      bw2.addMutation(m1);
+
+      // Mutations might or might not flush before tables goes offline
+      tops.offline(table1);
+      tops.offline(table2);
+
+      try {
+        bw1 = mtbw.getBatchWriter(table1);
+        Assert.fail(table1 + " should be offline");
+      } catch (TableOfflineException e) {
+        // pass
+        mutationsRejected = true;
+      }
+
+      try {
+        bw2 = mtbw.getBatchWriter(table2);
+        Assert.fail(table1 + " should be offline");
+      } catch (TableOfflineException e) {
+        // pass
+        mutationsRejected = true;
+      }
+    } finally {
+      if (null != mtbw) {
+        try {
+          // Mutations might have flushed before the table offline occurred
+          mtbw.close();
+        } catch (MutationsRejectedException e) {
+          // Pass
+          mutationsRejected = true;
+        }
+      }
+    }
+
+    Assert.assertTrue("Expected mutations to be rejected.", mutationsRejected);
+  }
+}

http://git-wip-us.apache.org/repos/asf/accumulo/blob/01ae5b85/test/src/main/java/org/apache/accumulo/test/MultiTableRecoveryIT.java
----------------------------------------------------------------------
diff --git a/test/src/main/java/org/apache/accumulo/test/MultiTableRecoveryIT.java b/test/src/main/java/org/apache/accumulo/test/MultiTableRecoveryIT.java
new file mode 100644
index 0000000..37e4957
--- /dev/null
+++ b/test/src/main/java/org/apache/accumulo/test/MultiTableRecoveryIT.java
@@ -0,0 +1,134 @@
+/*
+ * 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;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+
+import java.util.Map.Entry;
+import java.util.Random;
+import java.util.concurrent.atomic.AtomicBoolean;
+
+import org.apache.accumulo.core.client.BatchWriter;
+import org.apache.accumulo.core.client.Connector;
+import org.apache.accumulo.core.client.Scanner;
+import org.apache.accumulo.core.conf.Property;
+import org.apache.accumulo.core.data.Key;
+import org.apache.accumulo.core.data.Mutation;
+import org.apache.accumulo.core.data.Value;
+import org.apache.accumulo.core.metadata.MetadataTable;
+import org.apache.accumulo.core.security.Authorizations;
+import org.apache.accumulo.core.util.UtilWaitThread;
+import org.apache.accumulo.minicluster.ServerType;
+import org.apache.accumulo.minicluster.impl.MiniAccumuloConfigImpl;
+import org.apache.accumulo.test.functional.ConfigurableMacBase;
+import org.apache.hadoop.conf.Configuration;
+import org.apache.hadoop.fs.RawLocalFileSystem;
+import org.junit.Test;
+
+import com.google.common.collect.Iterators;
+
+public class MultiTableRecoveryIT extends ConfigurableMacBase {
+
+  @Override
+  protected void configure(MiniAccumuloConfigImpl cfg, Configuration hadoopCoreSite) {
+    cfg.setProperty(Property.INSTANCE_ZK_TIMEOUT, "5s");
+
+    // use raw local file system so walogs sync and flush will work
+    hadoopCoreSite.set("fs.file.impl", RawLocalFileSystem.class.getName());
+  }
+
+  @Test(timeout = 4 * 60 * 1000)
+  public void testRecoveryOverMultipleTables() throws Exception {
+    final int N = 3;
+    final Connector c = getConnector();
+    final String[] tables = getUniqueNames(N);
+    final BatchWriter[] writers = new BatchWriter[N];
+    final byte[][] values = new byte[N][];
+    int i = 0;
+    System.out.println("Creating tables");
+    for (String tableName : tables) {
+      c.tableOperations().create(tableName);
+      values[i] = Integer.toString(i).getBytes();
+      writers[i] = c.createBatchWriter(tableName, null);
+      i++;
+    }
+    System.out.println("Creating agitator");
+    final AtomicBoolean stop = new AtomicBoolean(false);
+    final Thread agitator = agitator(stop);
+    agitator.start();
+    System.out.println("writing");
+    final Random random = new Random();
+    for (i = 0; i < 1_000_000; i++) {
+      // make non-negative avoiding Math.abs, because that can still be negative
+      long randomRow = random.nextLong() & Long.MAX_VALUE;
+      assertTrue(randomRow >= 0);
+      final int table = (int) (randomRow % N);
+      final Mutation m = new Mutation(Long.toHexString(randomRow));
+      m.put(new byte[0], new byte[0], values[table]);
+      writers[table].addMutation(m);
+      if (i % 10_000 == 0) {
+        System.out.println("flushing");
+        for (int w = 0; w < N; w++) {
+          writers[w].flush();
+        }
+      }
+    }
+    System.out.println("closing");
+    for (int w = 0; w < N; w++) {
+      writers[w].close();
+    }
+    System.out.println("stopping the agitator");
+    stop.set(true);
+    agitator.join();
+    System.out.println("checking the data");
+    long count = 0;
+    for (int w = 0; w < N; w++) {
+      Scanner scanner = c.createScanner(tables[w], Authorizations.EMPTY);
+      for (Entry<Key,Value> entry : scanner) {
+        int value = Integer.parseInt(entry.getValue().toString());
+        assertEquals(w, value);
+        count++;
+      }
+      scanner.close();
+    }
+    assertEquals(1_000_000, count);
+  }
+
+  private Thread agitator(final AtomicBoolean stop) {
+    return new Thread() {
+      @Override
+      public void run() {
+        try {
+          int i = 0;
+          while (!stop.get()) {
+            UtilWaitThread.sleep(10 * 1000);
+            System.out.println("Restarting");
+            getCluster().getClusterControl().stop(ServerType.TABLET_SERVER);
+            getCluster().start();
+            // read the metadata table to know everything is back up
+            Iterators.size(getConnector().createScanner(MetadataTable.NAME, Authorizations.EMPTY).iterator());
+            i++;
+          }
+          System.out.println("Restarted " + i + " times");
+        } catch (Exception ex) {
+          log.error("{}", ex.getMessage(), ex);
+        }
+      }
+    };
+  }
+}

http://git-wip-us.apache.org/repos/asf/accumulo/blob/01ae5b85/test/src/main/java/org/apache/accumulo/test/NamespacesIT.java
----------------------------------------------------------------------
diff --git a/test/src/main/java/org/apache/accumulo/test/NamespacesIT.java b/test/src/main/java/org/apache/accumulo/test/NamespacesIT.java
new file mode 100644
index 0000000..0ecdd0d
--- /dev/null
+++ b/test/src/main/java/org/apache/accumulo/test/NamespacesIT.java
@@ -0,0 +1,1362 @@
+/*
+ * 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;
+
+import static java.nio.charset.StandardCharsets.UTF_8;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+
+import java.io.IOException;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.EnumSet;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.Set;
+import java.util.SortedSet;
+import java.util.TreeSet;
+
+import org.apache.accumulo.cluster.ClusterUser;
+import org.apache.accumulo.core.client.AccumuloException;
+import org.apache.accumulo.core.client.AccumuloSecurityException;
+import org.apache.accumulo.core.client.BatchWriter;
+import org.apache.accumulo.core.client.BatchWriterConfig;
+import org.apache.accumulo.core.client.Connector;
+import org.apache.accumulo.core.client.IteratorSetting;
+import org.apache.accumulo.core.client.MutationsRejectedException;
+import org.apache.accumulo.core.client.NamespaceExistsException;
+import org.apache.accumulo.core.client.NamespaceNotEmptyException;
+import org.apache.accumulo.core.client.NamespaceNotFoundException;
+import org.apache.accumulo.core.client.Scanner;
+import org.apache.accumulo.core.client.TableExistsException;
+import org.apache.accumulo.core.client.TableNotFoundException;
+import org.apache.accumulo.core.client.admin.NamespaceOperations;
+import org.apache.accumulo.core.client.admin.NewTableConfiguration;
+import org.apache.accumulo.core.client.admin.TableOperations;
+import org.apache.accumulo.core.client.impl.Namespaces;
+import org.apache.accumulo.core.client.impl.Tables;
+import org.apache.accumulo.core.client.impl.thrift.TableOperation;
+import org.apache.accumulo.core.client.impl.thrift.TableOperationExceptionType;
+import org.apache.accumulo.core.client.impl.thrift.ThriftTableOperationException;
+import org.apache.accumulo.core.client.security.SecurityErrorCode;
+import org.apache.accumulo.core.client.security.tokens.PasswordToken;
+import org.apache.accumulo.core.conf.Property;
+import org.apache.accumulo.core.data.Key;
+import org.apache.accumulo.core.data.Mutation;
+import org.apache.accumulo.core.data.Range;
+import org.apache.accumulo.core.data.Value;
+import org.apache.accumulo.core.iterators.Filter;
+import org.apache.accumulo.core.iterators.IteratorUtil.IteratorScope;
+import org.apache.accumulo.core.iterators.SortedKeyValueIterator;
+import org.apache.accumulo.core.iterators.user.VersioningIterator;
+import org.apache.accumulo.core.metadata.MetadataTable;
+import org.apache.accumulo.core.metadata.RootTable;
+import org.apache.accumulo.core.security.Authorizations;
+import org.apache.accumulo.core.security.NamespacePermission;
+import org.apache.accumulo.core.security.SystemPermission;
+import org.apache.accumulo.core.security.TablePermission;
+import org.apache.accumulo.core.util.UtilWaitThread;
+import org.apache.accumulo.examples.simple.constraints.NumericValueConstraint;
+import org.apache.accumulo.harness.AccumuloClusterHarness;
+import org.apache.hadoop.io.Text;
+import org.junit.After;
+import org.junit.Assume;
+import org.junit.Before;
+import org.junit.Test;
+
+// Testing default namespace configuration with inheritance requires altering the system state and restoring it back to normal
+// Punt on this for now and just let it use a minicluster.
+public class NamespacesIT extends AccumuloClusterHarness {
+
+  private Connector c;
+  private String namespace;
+
+  @Override
+  public int defaultTimeoutSeconds() {
+    return 60;
+  }
+
+  @Before
+  public void setupConnectorAndNamespace() throws Exception {
+    Assume.assumeTrue(ClusterType.MINI == getClusterType());
+
+    // prepare a unique namespace and get a new root connector for each test
+    c = getConnector();
+    namespace = "ns_" + getUniqueNames(1)[0];
+  }
+
+  @After
+  public void swingMj├Âlnir() throws Exception {
+    if (null == c) {
+      return;
+    }
+    // clean up any added tables, namespaces, and users, after each test
+    for (String t : c.tableOperations().list())
+      if (!Tables.qualify(t).getFirst().equals(Namespaces.ACCUMULO_NAMESPACE))
+        c.tableOperations().delete(t);
+    assertEquals(3, c.tableOperations().list().size());
+    for (String n : c.namespaceOperations().list())
+      if (!n.equals(Namespaces.ACCUMULO_NAMESPACE) && !n.equals(Namespaces.DEFAULT_NAMESPACE))
+        c.namespaceOperations().delete(n);
+    assertEquals(2, c.namespaceOperations().list().size());
+    for (String u : c.securityOperations().listLocalUsers())
+      if (!getAdminPrincipal().equals(u))
+        c.securityOperations().dropLocalUser(u);
+    assertEquals(1, c.securityOperations().listLocalUsers().size());
+  }
+
+  @Test
+  public void checkReservedNamespaces() throws Exception {
+    assertEquals(c.namespaceOperations().defaultNamespace(), Namespaces.DEFAULT_NAMESPACE);
+    assertEquals(c.namespaceOperations().systemNamespace(), Namespaces.ACCUMULO_NAMESPACE);
+  }
+
+  @Test
+  public void checkBuiltInNamespaces() throws Exception {
+    assertTrue(c.namespaceOperations().exists(Namespaces.DEFAULT_NAMESPACE));
+    assertTrue(c.namespaceOperations().exists(Namespaces.ACCUMULO_NAMESPACE));
+  }
+
+  @Test
+  public void createTableInDefaultNamespace() throws Exception {
+    String tableName = "1";
+    c.tableOperations().create(tableName);
+    assertTrue(c.tableOperations().exists(tableName));
+  }
+
+  @Test(expected = AccumuloException.class)
+  public void createTableInAccumuloNamespace() throws Exception {
+    String tableName = Namespaces.ACCUMULO_NAMESPACE + ".1";
+    assertFalse(c.tableOperations().exists(tableName));
+    c.tableOperations().create(tableName); // should fail
+  }
+
+  @Test(expected = AccumuloSecurityException.class)
+  public void deleteDefaultNamespace() throws Exception {
+    c.namespaceOperations().delete(Namespaces.DEFAULT_NAMESPACE); // should fail
+  }
+
+  @Test(expected = AccumuloSecurityException.class)
+  public void deleteAccumuloNamespace() throws Exception {
+    c.namespaceOperations().delete(Namespaces.ACCUMULO_NAMESPACE); // should fail
+  }
+
+  @Test
+  public void createTableInMissingNamespace() throws Exception {
+    String t = namespace + ".1";
+    assertFalse(c.namespaceOperations().exists(namespace));
+    assertFalse(c.tableOperations().exists(t));
+    try {
+      c.tableOperations().create(t);
+      fail();
+    } catch (AccumuloException e) {
+      assertEquals(NamespaceNotFoundException.class.getName(), e.getCause().getClass().getName());
+      assertFalse(c.namespaceOperations().exists(namespace));
+      assertFalse(c.tableOperations().exists(t));
+    }
+  }
+
+  @Test
+  public void createAndDeleteNamespace() throws Exception {
+    String t1 = namespace + ".1";
+    String t2 = namespace + ".2";
+    assertFalse(c.namespaceOperations().exists(namespace));
+    assertFalse(c.tableOperations().exists(t1));
+    assertFalse(c.tableOperations().exists(t2));
+    try {
+      c.namespaceOperations().delete(namespace);
+    } catch (NamespaceNotFoundException e) {}
+    try {
+      c.tableOperations().delete(t1);
+    } catch (TableNotFoundException e) {
+      assertEquals(NamespaceNotFoundException.class.getName(), e.getCause().getClass().getName());
+    }
+    c.namespaceOperations().create(namespace);
+    assertTrue(c.namespaceOperations().exists(namespace));
+    assertFalse(c.tableOperations().exists(t1));
+    assertFalse(c.tableOperations().exists(t2));
+    c.tableOperations().create(t1);
+    assertTrue(c.namespaceOperations().exists(namespace));
+    assertTrue(c.tableOperations().exists(t1));
+    assertFalse(c.tableOperations().exists(t2));
+    c.tableOperations().create(t2);
+    assertTrue(c.namespaceOperations().exists(namespace));
+    assertTrue(c.tableOperations().exists(t1));
+    assertTrue(c.tableOperations().exists(t2));
+    c.tableOperations().delete(t1);
+    assertTrue(c.namespaceOperations().exists(namespace));
+    assertFalse(c.tableOperations().exists(t1));
+    assertTrue(c.tableOperations().exists(t2));
+    c.tableOperations().delete(t2);
+    assertTrue(c.namespaceOperations().exists(namespace));
+    assertFalse(c.tableOperations().exists(t1));
+    assertFalse(c.tableOperations().exists(t2));
+    c.namespaceOperations().delete(namespace);
+    assertFalse(c.namespaceOperations().exists(namespace));
+    assertFalse(c.tableOperations().exists(t1));
+    assertFalse(c.tableOperations().exists(t2));
+  }
+
+  @Test(expected = NamespaceNotEmptyException.class)
+  public void deleteNonEmptyNamespace() throws Exception {
+    String tableName1 = namespace + ".1";
+    assertFalse(c.namespaceOperations().exists(namespace));
+    assertFalse(c.tableOperations().exists(tableName1));
+    c.namespaceOperations().create(namespace);
+    c.tableOperations().create(tableName1);
+    assertTrue(c.namespaceOperations().exists(namespace));
+    assertTrue(c.tableOperations().exists(tableName1));
+    c.namespaceOperations().delete(namespace); // should fail
+  }
+
+  @Test
+  public void verifyPropertyInheritance() throws Exception {
+    String t0 = "0";
+    String t1 = namespace + ".1";
+    String t2 = namespace + ".2";
+
+    String k = Property.TABLE_SCAN_MAXMEM.getKey();
+    String v = "42K";
+
+    assertFalse(c.namespaceOperations().exists(namespace));
+    assertFalse(c.tableOperations().exists(t1));
+    assertFalse(c.tableOperations().exists(t2));
+    c.namespaceOperations().create(namespace);
+    c.tableOperations().create(t1);
+    c.tableOperations().create(t0);
+    assertTrue(c.namespaceOperations().exists(namespace));
+    assertTrue(c.tableOperations().exists(t1));
+    assertTrue(c.tableOperations().exists(t0));
+
+    // verify no property
+    assertFalse(checkNamespaceHasProp(namespace, k, v));
+    assertFalse(checkTableHasProp(t1, k, v));
+    assertFalse(checkNamespaceHasProp(Namespaces.DEFAULT_NAMESPACE, k, v));
+    assertFalse(checkTableHasProp(t0, k, v));
+
+    // set property and verify
+    c.namespaceOperations().setProperty(namespace, k, v);
+    assertTrue(checkNamespaceHasProp(namespace, k, v));
+    assertTrue(checkTableHasProp(t1, k, v));
+    assertFalse(checkNamespaceHasProp(Namespaces.DEFAULT_NAMESPACE, k, v));
+    assertFalse(checkTableHasProp(t0, k, v));
+
+    // add a new table to namespace and verify
+    assertFalse(c.tableOperations().exists(t2));
+    c.tableOperations().create(t2);
+    assertTrue(c.tableOperations().exists(t2));
+    assertTrue(checkNamespaceHasProp(namespace, k, v));
+    assertTrue(checkTableHasProp(t1, k, v));
+    assertTrue(checkTableHasProp(t2, k, v));
+    assertFalse(checkNamespaceHasProp(Namespaces.DEFAULT_NAMESPACE, k, v));
+    assertFalse(checkTableHasProp(t0, k, v));
+
+    // remove property and verify
+    c.namespaceOperations().removeProperty(namespace, k);
+    assertFalse(checkNamespaceHasProp(namespace, k, v));
+    assertFalse(checkTableHasProp(t1, k, v));
+    assertFalse(checkTableHasProp(t2, k, v));
+    assertFalse(checkNamespaceHasProp(Namespaces.DEFAULT_NAMESPACE, k, v));
+    assertFalse(checkTableHasProp(t0, k, v));
+
+    // set property on default namespace and verify
+    c.namespaceOperations().setProperty(Namespaces.DEFAULT_NAMESPACE, k, v);
+    assertFalse(checkNamespaceHasProp(namespace, k, v));
+    assertFalse(checkTableHasProp(t1, k, v));
+    assertFalse(checkTableHasProp(t2, k, v));
+    assertTrue(checkNamespaceHasProp(Namespaces.DEFAULT_NAMESPACE, k, v));
+    assertTrue(checkTableHasProp(t0, k, v));
+
+    // test that table properties override namespace properties
+    String k2 = Property.TABLE_FILE_MAX.getKey();
+    String v2 = "42";
+    String table_v2 = "13";
+
+    // set new property on some
+    c.namespaceOperations().setProperty(namespace, k2, v2);
+    c.tableOperations().setProperty(t2, k2, table_v2);
+    assertTrue(checkNamespaceHasProp(namespace, k2, v2));
+    assertTrue(checkTableHasProp(t1, k2, v2));
+    assertTrue(checkTableHasProp(t2, k2, table_v2));
+
+    c.tableOperations().delete(t1);
+    c.tableOperations().delete(t2);
+    c.tableOperations().delete(t0);
+    c.namespaceOperations().delete(namespace);
+  }
+
+  @Test
+  public void verifyIteratorInheritance() throws Exception {
+    String t1 = namespace + ".1";
+    c.namespaceOperations().create(namespace);
+    c.tableOperations().create(t1);
+    String iterName = namespace + "_iter";
+
+    BatchWriter bw = c.createBatchWriter(t1, new BatchWriterConfig());
+    Mutation m = new Mutation("r");
+    m.put("a", "b", new Value("abcde".getBytes()));
+    bw.addMutation(m);
+    bw.flush();
+    bw.close();
+
+    IteratorSetting setting = new IteratorSetting(250, iterName, SimpleFilter.class.getName());
+
+    // verify can see inserted entry
+    Scanner s = c.createScanner(t1, Authorizations.EMPTY);
+    assertTrue(s.iterator().hasNext());
+    assertFalse(c.namespaceOperations().listIterators(namespace).containsKey(iterName));
+    assertFalse(c.tableOperations().listIterators(t1).containsKey(iterName));
+
+    // verify entry is filtered out (also, verify conflict checking API)
+    c.namespaceOperations().checkIteratorConflicts(namespace, setting, EnumSet.allOf(IteratorScope.class));
+    c.namespaceOperations().attachIterator(namespace, setting);
+    UtilWaitThread.sleep(2 * 1000);
+    try {
+      c.namespaceOperations().checkIteratorConflicts(namespace, setting, EnumSet.allOf(IteratorScope.class));
+      fail();
+    } catch (AccumuloException e) {
+      assertEquals(IllegalArgumentException.class.getName(), e.getCause().getClass().getName());
+    }
+    IteratorSetting setting2 = c.namespaceOperations().getIteratorSetting(namespace, setting.getName(), IteratorScope.scan);
+    assertEquals(setting, setting2);
+    assertTrue(c.namespaceOperations().listIterators(namespace).containsKey(iterName));
+    assertTrue(c.tableOperations().listIterators(t1).containsKey(iterName));
+    s = c.createScanner(t1, Authorizations.EMPTY);
+    assertFalse(s.iterator().hasNext());
+
+    // verify can see inserted entry again
+    c.namespaceOperations().removeIterator(namespace, setting.getName(), EnumSet.allOf(IteratorScope.class));
+    UtilWaitThread.sleep(2 * 1000);
+    assertFalse(c.namespaceOperations().listIterators(namespace).containsKey(iterName));
+    assertFalse(c.tableOperations().listIterators(t1).containsKey(iterName));
+    s = c.createScanner(t1, Authorizations.EMPTY);
+    assertTrue(s.iterator().hasNext());
+  }
+
+  @Test
+  public void cloneTable() throws Exception {
+    String namespace2 = namespace + "_clone";
+    String t1 = namespace + ".1";
+    String t2 = namespace + ".2";
+    String t3 = namespace2 + ".2";
+    String k1 = Property.TABLE_FILE_MAX.getKey();
+    String k2 = Property.TABLE_FILE_REPLICATION.getKey();
+    String k1v1 = "55";
+    String k1v2 = "66";
+    String k2v1 = "5";
+    String k2v2 = "6";
+
+    c.namespaceOperations().create(namespace);
+    c.tableOperations().create(t1);
+    assertTrue(c.tableOperations().exists(t1));
+    assertFalse(c.namespaceOperations().exists(namespace2));
+    assertFalse(c.tableOperations().exists(t2));
+    assertFalse(c.tableOperations().exists(t3));
+
+    try {
+      // try to clone before namespace exists
+      c.tableOperations().clone(t1, t3, false, null, null); // should fail
+      fail();
+    } catch (AccumuloException e) {
+      assertEquals(NamespaceNotFoundException.class.getName(), e.getCause().getClass().getName());
+    }
+
+    // try to clone before when target tables exist
+    c.namespaceOperations().create(namespace2);
+    c.tableOperations().create(t2);
+    c.tableOperations().create(t3);
+    for (String t : Arrays.asList(t2, t3)) {
+      try {
+        c.tableOperations().clone(t1, t, false, null, null); // should fail
+        fail();
+      } catch (TableExistsException e) {
+        c.tableOperations().delete(t);
+      }
+    }
+
+    assertTrue(c.tableOperations().exists(t1));
+    assertTrue(c.namespaceOperations().exists(namespace2));
+    assertFalse(c.tableOperations().exists(t2));
+    assertFalse(c.tableOperations().exists(t3));
+
+    // set property with different values in two namespaces and a separate property with different values on the table and both namespaces
+    assertFalse(checkNamespaceHasProp(namespace, k1, k1v1));
+    assertFalse(checkNamespaceHasProp(namespace2, k1, k1v2));
+    assertFalse(checkTableHasProp(t1, k1, k1v1));
+    assertFalse(checkTableHasProp(t1, k1, k1v2));
+    assertFalse(checkNamespaceHasProp(namespace, k2, k2v1));
+    assertFalse(checkNamespaceHasProp(namespace2, k2, k2v1));
+    assertFalse(checkTableHasProp(t1, k2, k2v1));
+    assertFalse(checkTableHasProp(t1, k2, k2v2));
+    c.namespaceOperations().setProperty(namespace, k1, k1v1);
+    c.namespaceOperations().setProperty(namespace2, k1, k1v2);
+    c.namespaceOperations().setProperty(namespace, k2, k2v1);
+    c.namespaceOperations().setProperty(namespace2, k2, k2v1);
+    c.tableOperations().setProperty(t1, k2, k2v2);
+    assertTrue(checkNamespaceHasProp(namespace, k1, k1v1));
+    assertTrue(checkNamespaceHasProp(namespace2, k1, k1v2));
+    assertTrue(checkTableHasProp(t1, k1, k1v1));
+    assertFalse(checkTableHasProp(t1, k1, k1v2));
+    assertTrue(checkNamespaceHasProp(namespace, k2, k2v1));
+    assertTrue(checkNamespaceHasProp(namespace2, k2, k2v1));
+    assertFalse(checkTableHasProp(t1, k2, k2v1));
+    assertTrue(checkTableHasProp(t1, k2, k2v2));
+
+    // clone twice, once in same namespace, once in another
+    for (String t : Arrays.asList(t2, t3))
+      c.tableOperations().clone(t1, t, false, null, null);
+
+    assertTrue(c.namespaceOperations().exists(namespace2));
+    assertTrue(c.tableOperations().exists(t1));
+    assertTrue(c.tableOperations().exists(t2));
+    assertTrue(c.tableOperations().exists(t3));
+
+    // verify the properties got transferred
+    assertTrue(checkTableHasProp(t1, k1, k1v1));
+    assertTrue(checkTableHasProp(t2, k1, k1v1));
+    assertTrue(checkTableHasProp(t3, k1, k1v2));
+    assertTrue(checkTableHasProp(t1, k2, k2v2));
+    assertTrue(checkTableHasProp(t2, k2, k2v2));
+    assertTrue(checkTableHasProp(t3, k2, k2v2));
+  }
+
+  @Test
+  public void renameNamespaceWithTable() throws Exception {
+    String namespace2 = namespace + "_renamed";
+    String t1 = namespace + ".t";
+    String t2 = namespace2 + ".t";
+
+    c.namespaceOperations().create(namespace);
+    c.tableOperations().create(t1);
+    assertTrue(c.namespaceOperations().exists(namespace));
+    assertTrue(c.tableOperations().exists(t1));
+    assertFalse(c.namespaceOperations().exists(namespace2));
+    assertFalse(c.tableOperations().exists(t2));
+
+    String namespaceId = c.namespaceOperations().namespaceIdMap().get(namespace);
+    String tableId = c.tableOperations().tableIdMap().get(t1);
+
+    c.namespaceOperations().rename(namespace, namespace2);
+    assertFalse(c.namespaceOperations().exists(namespace));
+    assertFalse(c.tableOperations().exists(t1));
+    assertTrue(c.namespaceOperations().exists(namespace2));
+    assertTrue(c.tableOperations().exists(t2));
+
+    // verify id's didn't change
+    String namespaceId2 = c.namespaceOperations().namespaceIdMap().get(namespace2);
+    String tableId2 = c.tableOperations().tableIdMap().get(t2);
+
+    assertEquals(namespaceId, namespaceId2);
+    assertEquals(tableId, tableId2);
+  }
+
+  @Test
+  public void verifyConstraintInheritance() throws Exception {
+    String t1 = namespace + ".1";
+    c.namespaceOperations().create(namespace);
+    c.tableOperations().create(t1, new NewTableConfiguration().withoutDefaultIterators());
+    String constraintClassName = NumericValueConstraint.class.getName();
+
+    assertFalse(c.namespaceOperations().listConstraints(namespace).containsKey(constraintClassName));
+    assertFalse(c.tableOperations().listConstraints(t1).containsKey(constraintClassName));
+
+    c.namespaceOperations().addConstraint(namespace, constraintClassName);
+    assertTrue(c.namespaceOperations().listConstraints(namespace).containsKey(constraintClassName));
+    assertTrue(c.tableOperations().listConstraints(t1).containsKey(constraintClassName));
+    int num = c.namespaceOperations().listConstraints(namespace).get(constraintClassName);
+    assertEquals(num, (int) c.tableOperations().listConstraints(t1).get(constraintClassName));
+    // doesn't take effect immediately, needs time to propagate to tserver's ZooKeeper cache
+    UtilWaitThread.sleep(250);
+
+    Mutation m1 = new Mutation("r1");
+    Mutation m2 = new Mutation("r2");
+    Mutation m3 = new Mutation("r3");
+    m1.put("a", "b", new Value("abcde".getBytes(UTF_8)));
+    m2.put("e", "f", new Value("123".getBytes(UTF_8)));
+    m3.put("c", "d", new Value("zyxwv".getBytes(UTF_8)));
+    BatchWriter bw = c.createBatchWriter(t1, new BatchWriterConfig());
+    bw.addMutations(Arrays.asList(m1, m2, m3));
+    try {
+      bw.close();
+      fail();
+    } catch (MutationsRejectedException e) {
+      assertEquals(1, e.getConstraintViolationSummaries().size());
+      assertEquals(2, e.getConstraintViolationSummaries().get(0).getNumberOfViolatingMutations());
+    }
+    c.namespaceOperations().removeConstraint(namespace, num);
+    assertFalse(c.namespaceOperations().listConstraints(namespace).containsKey(constraintClassName));
+    assertFalse(c.tableOperations().listConstraints(t1).containsKey(constraintClassName));
+    // doesn't take effect immediately, needs time to propagate to tserver's ZooKeeper cache
+    UtilWaitThread.sleep(250);
+
+    bw = c.createBatchWriter(t1, new BatchWriterConfig());
+    bw.addMutations(Arrays.asList(m1, m2, m3));
+    bw.close();
+  }
+
+  @Test
+  public void renameTable() throws Exception {
+    String namespace2 = namespace + "_renamed";
+    String t1 = namespace + ".1";
+    String t2 = namespace2 + ".2";
+    String t3 = namespace + ".3";
+    String t4 = namespace + ".4";
+    String t5 = "5";
+
+    c.namespaceOperations().create(namespace);
+    c.namespaceOperations().create(namespace2);
+
+    assertTrue(c.namespaceOperations().exists(namespace));
+    assertTrue(c.namespaceOperations().exists(namespace2));
+    assertFalse(c.tableOperations().exists(t1));
+    assertFalse(c.tableOperations().exists(t2));
+    assertFalse(c.tableOperations().exists(t3));
+    assertFalse(c.tableOperations().exists(t4));
+    assertFalse(c.tableOperations().exists(t5));
+
+    c.tableOperations().create(t1);
+
+    try {
+      c.tableOperations().rename(t1, t2);
+      fail();
+    } catch (AccumuloException e) {
+      // this is expected, because we don't allow renames across namespaces
+      assertEquals(ThriftTableOperationException.class.getName(), e.getCause().getClass().getName());
+      assertEquals(TableOperation.RENAME, ((ThriftTableOperationException) e.getCause()).getOp());
+      assertEquals(TableOperationExceptionType.INVALID_NAME, ((ThriftTableOperationException) e.getCause()).getType());
+    }
+
+    try {
+      c.tableOperations().rename(t1, t5);
+      fail();
+    } catch (AccumuloException e) {
+      // this is expected, because we don't allow renames across namespaces
+      assertEquals(ThriftTableOperationException.class.getName(), e.getCause().getClass().getName());
+      assertEquals(TableOperation.RENAME, ((ThriftTableOperationException) e.getCause()).getOp());
+      assertEquals(TableOperationExceptionType.INVALID_NAME, ((ThriftTableOperationException) e.getCause()).getType());
+    }
+
+    assertTrue(c.tableOperations().exists(t1));
+    assertFalse(c.tableOperations().exists(t2));
+    assertFalse(c.tableOperations().exists(t3));
+    assertFalse(c.tableOperations().exists(t4));
+    assertFalse(c.tableOperations().exists(t5));
+
+    // fully qualified rename
+    c.tableOperations().rename(t1, t3);
+    assertFalse(c.tableOperations().exists(t1));
+    assertFalse(c.tableOperations().exists(t2));
+    assertTrue(c.tableOperations().exists(t3));
+    assertFalse(c.tableOperations().exists(t4));
+    assertFalse(c.tableOperations().exists(t5));
+  }
+
+  private void loginAs(ClusterUser user) throws IOException {
+    user.getToken();
+  }
+
+  /**
+   * Tests new Namespace permissions as well as modifications to Table permissions because of namespaces. Checks each permission to first make sure the user
+   * doesn't have permission to perform the action, then root grants them the permission and we check to make sure they could perform the action.
+   */
+  @Test
+  public void testPermissions() throws Exception {
+    ClusterUser user1 = getUser(0), user2 = getUser(1), root = getAdminUser();
+    String u1 = user1.getPrincipal();
+    String u2 = user2.getPrincipal();
+    PasswordToken pass = (null != user1.getPassword() ? new PasswordToken(user1.getPassword()) : null);
+
+    String n1 = namespace;
+    String t1 = n1 + ".1";
+    String t2 = n1 + ".2";
+    String t3 = n1 + ".3";
+
+    String n2 = namespace + "_2";
+
+    loginAs(root);
+    c.namespaceOperations().create(n1);
+    c.tableOperations().create(t1);
+
+    c.securityOperations().createLocalUser(u1, pass);
+
+    loginAs(user1);
+    Connector user1Con = c.getInstance().getConnector(u1, user1.getToken());
+
+    try {
+      user1Con.tableOperations().create(t2);
+      fail();
+    } catch (AccumuloSecurityException e) {
+      expectPermissionDenied(e);
+    }
+
+    loginAs(root);
+    c.securityOperations().grantNamespacePermission(u1, n1, NamespacePermission.CREATE_TABLE);
+    loginAs(user1);
+    user1Con.tableOperations().create(t2);
+    loginAs(root);
+    assertTrue(c.tableOperations().list().contains(t2));
+    c.securityOperations().revokeNamespacePermission(u1, n1, NamespacePermission.CREATE_TABLE);
+
+    loginAs(user1);
+    try {
+      user1Con.tableOperations().delete(t1);
+      fail();
+    } catch (AccumuloSecurityException e) {
+      expectPermissionDenied(e);
+    }
+
+    loginAs(root);
+    c.securityOperations().grantNamespacePermission(u1, n1, NamespacePermission.DROP_TABLE);
+    loginAs(user1);
+    user1Con.tableOperations().delete(t1);
+    loginAs(root);
+    assertTrue(!c.tableOperations().list().contains(t1));
+    c.securityOperations().revokeNamespacePermission(u1, n1, NamespacePermission.DROP_TABLE);
+
+    c.tableOperations().create(t3);
+    BatchWriter bw = c.createBatchWriter(t3, null);
+    Mutation m = new Mutation("row");
+    m.put("cf", "cq", "value");
+    bw.addMutation(m);
+    bw.close();
+
+    loginAs(user1);
+    Iterator<Entry<Key,Value>> i = user1Con.createScanner(t3, new Authorizations()).iterator();
+    try {
+      i.next();
+      fail();
+    } catch (RuntimeException e) {
+      assertEquals(AccumuloSecurityException.class.getName(), e.getCause().getClass().getName());
+      expectPermissionDenied((AccumuloSecurityException) e.getCause());
+    }
+
+    loginAs(user1);
+    m = new Mutation(u1);
+    m.put("cf", "cq", "turtles");
+    bw = user1Con.createBatchWriter(t3, null);
+    try {
+      bw.addMutation(m);
+      bw.close();
+      fail();
+    } catch (MutationsRejectedException e) {
+      assertEquals(1, e.getSecurityErrorCodes().size());
+      assertEquals(1, e.getSecurityErrorCodes().entrySet().iterator().next().getValue().size());
+      switch (e.getSecurityErrorCodes().entrySet().iterator().next().getValue().iterator().next()) {
+        case PERMISSION_DENIED:
+          break;
+        default:
+          fail();
+      }
+    }
+
+    loginAs(root);
+    c.securityOperations().grantNamespacePermission(u1, n1, NamespacePermission.READ);
+    loginAs(user1);
+    i = user1Con.createScanner(t3, new Authorizations()).iterator();
+    assertTrue(i.hasNext());
+    loginAs(root);
+    c.securityOperations().revokeNamespacePermission(u1, n1, NamespacePermission.READ);
+    c.securityOperations().grantNamespacePermission(u1, n1, NamespacePermission.WRITE);
+
+    loginAs(user1);
+    m = new Mutation(u1);
+    m.put("cf", "cq", "turtles");
+    bw = user1Con.createBatchWriter(t3, null);
+    bw.addMutation(m);
+    bw.close();
+    loginAs(root);
+    c.securityOperations().revokeNamespacePermission(u1, n1, NamespacePermission.WRITE);
+
+    loginAs(user1);
+    try {
+      user1Con.tableOperations().setProperty(t3, Property.TABLE_FILE_MAX.getKey(), "42");
+      fail();
+    } catch (AccumuloSecurityException e) {
+      expectPermissionDenied(e);
+    }
+
+    loginAs(root);
+    c.securityOperations().grantNamespacePermission(u1, n1, NamespacePermission.ALTER_TABLE);
+    loginAs(user1);
+    user1Con.tableOperations().setProperty(t3, Property.TABLE_FILE_MAX.getKey(), "42");
+    user1Con.tableOperations().removeProperty(t3, Property.TABLE_FILE_MAX.getKey());
+    loginAs(root);
+    c.securityOperations().revokeNamespacePermission(u1, n1, NamespacePermission.ALTER_TABLE);
+
+    loginAs(user1);
+    try {
+      user1Con.namespaceOperations().setProperty(n1, Property.TABLE_FILE_MAX.getKey(), "55");
+      fail();
+    } catch (AccumuloSecurityException e) {
+      expectPermissionDenied(e);
+    }
+
+    loginAs(root);
+    c.securityOperations().grantNamespacePermission(u1, n1, NamespacePermission.ALTER_NAMESPACE);
+    loginAs(user1);
+    user1Con.namespaceOperations().setProperty(n1, Property.TABLE_FILE_MAX.getKey(), "42");
+    user1Con.namespaceOperations().removeProperty(n1, Property.TABLE_FILE_MAX.getKey());
+    loginAs(root);
+    c.securityOperations().revokeNamespacePermission(u1, n1, NamespacePermission.ALTER_NAMESPACE);
+
+    loginAs(root);
+    c.securityOperations().createLocalUser(u2, (root.getPassword() == null ? null : new PasswordToken(user2.getPassword())));
+    loginAs(user1);
+    try {
+      user1Con.securityOperations().grantNamespacePermission(u2, n1, NamespacePermission.ALTER_NAMESPACE);
+      fail();
+    } catch (AccumuloSecurityException e) {
+      expectPermissionDenied(e);
+    }
+
+    loginAs(root);
+    c.securityOperations().grantNamespacePermission(u1, n1, NamespacePermission.GRANT);
+    loginAs(user1);
+    user1Con.securityOperations().grantNamespacePermission(u2, n1, NamespacePermission.ALTER_NAMESPACE);
+    user1Con.securityOperations().revokeNamespacePermission(u2, n1, NamespacePermission.ALTER_NAMESPACE);
+    loginAs(root);
+    c.securityOperations().revokeNamespacePermission(u1, n1, NamespacePermission.GRANT);
+
+    loginAs(user1);
+    try {
+      user1Con.namespaceOperations().create(n2);
+      fail();
+    } catch (AccumuloSecurityException e) {
+      expectPermissionDenied(e);
+    }
+
+    loginAs(root);
+    c.securityOperations().grantSystemPermission(u1, SystemPermission.CREATE_NAMESPACE);
+    loginAs(user1);
+    user1Con.namespaceOperations().create(n2);
+    loginAs(root);
+    c.securityOperations().revokeSystemPermission(u1, SystemPermission.CREATE_NAMESPACE);
+
+    c.securityOperations().revokeNamespacePermission(u1, n2, NamespacePermission.DROP_NAMESPACE);
+    loginAs(user1);
+    try {
+      user1Con.namespaceOperations().delete(n2);
+      fail();
+    } catch (AccumuloSecurityException e) {
+      expectPermissionDenied(e);
+    }
+
+    loginAs(root);
+    c.securityOperations().grantSystemPermission(u1, SystemPermission.DROP_NAMESPACE);
+    loginAs(user1);
+    user1Con.namespaceOperations().delete(n2);
+    loginAs(root);
+    c.securityOperations().revokeSystemPermission(u1, SystemPermission.DROP_NAMESPACE);
+
+    loginAs(user1);
+    try {
+      user1Con.namespaceOperations().setProperty(n1, Property.TABLE_FILE_MAX.getKey(), "33");
+      fail();
+    } catch (AccumuloSecurityException e) {
+      expectPermissionDenied(e);
+    }
+
+    loginAs(root);
+    c.securityOperations().grantSystemPermission(u1, SystemPermission.ALTER_NAMESPACE);
+    loginAs(user1);
+    user1Con.namespaceOperations().setProperty(n1, Property.TABLE_FILE_MAX.getKey(), "33");
+    user1Con.namespaceOperations().removeProperty(n1, Property.TABLE_FILE_MAX.getKey());
+    loginAs(root);
+    c.securityOperations().revokeSystemPermission(u1, SystemPermission.ALTER_NAMESPACE);
+  }
+
+  @Test
+  public void verifySystemPropertyInheritance() throws Exception {
+    String t1 = "1";
+    String t2 = namespace + "." + t1;
+    c.tableOperations().create(t1);
+    c.namespaceOperations().create(namespace);
+    c.tableOperations().create(t2);
+
+    // verify iterator inheritance
+    _verifySystemPropertyInheritance(t1, t2, Property.TABLE_ITERATOR_PREFIX.getKey() + "scan.sum", "20," + SimpleFilter.class.getName(), false);
+
+    // verify constraint inheritance
+    _verifySystemPropertyInheritance(t1, t2, Property.TABLE_CONSTRAINT_PREFIX.getKey() + "42", NumericValueConstraint.class.getName(), false);
+
+    // verify other inheritance
+    _verifySystemPropertyInheritance(t1, t2, Property.TABLE_LOCALITY_GROUP_PREFIX.getKey() + "dummy", "dummy", true);
+  }
+
+  private void _verifySystemPropertyInheritance(String defaultNamespaceTable, String namespaceTable, String k, String v, boolean systemNamespaceShouldInherit)
+      throws Exception {
+    // nobody should have any of these properties yet
+    assertFalse(c.instanceOperations().getSystemConfiguration().containsValue(v));
+    assertFalse(checkNamespaceHasProp(Namespaces.ACCUMULO_NAMESPACE, k, v));
+    assertFalse(checkTableHasProp(RootTable.NAME, k, v));
+    assertFalse(checkTableHasProp(MetadataTable.NAME, k, v));
+    assertFalse(checkNamespaceHasProp(Namespaces.DEFAULT_NAMESPACE, k, v));
+    assertFalse(checkTableHasProp(defaultNamespaceTable, k, v));
+    assertFalse(checkNamespaceHasProp(namespace, k, v));
+    assertFalse(checkTableHasProp(namespaceTable, k, v));
+
+    // set the filter, verify that accumulo namespace is the only one unaffected
+    c.instanceOperations().setProperty(k, v);
+    // doesn't take effect immediately, needs time to propagate to tserver's ZooKeeper cache
+    UtilWaitThread.sleep(250);
+    assertTrue(c.instanceOperations().getSystemConfiguration().containsValue(v));
+    assertEquals(systemNamespaceShouldInherit, checkNamespaceHasProp(Namespaces.ACCUMULO_NAMESPACE, k, v));
+    assertEquals(systemNamespaceShouldInherit, checkTableHasProp(RootTable.NAME, k, v));
+    assertEquals(systemNamespaceShouldInherit, checkTableHasProp(MetadataTable.NAME, k, v));
+    assertTrue(checkNamespaceHasProp(Namespaces.DEFAULT_NAMESPACE, k, v));
+    assertTrue(checkTableHasProp(defaultNamespaceTable, k, v));
+    assertTrue(checkNamespaceHasProp(namespace, k, v));
+    assertTrue(checkTableHasProp(namespaceTable, k, v));
+
+    // verify it is no longer inherited
+    c.instanceOperations().removeProperty(k);
+    // doesn't take effect immediately, needs time to propagate to tserver's ZooKeeper cache
+    UtilWaitThread.sleep(250);
+    assertFalse(c.instanceOperations().getSystemConfiguration().containsValue(v));
+    assertFalse(checkNamespaceHasProp(Namespaces.ACCUMULO_NAMESPACE, k, v));
+    assertFalse(checkTableHasProp(RootTable.NAME, k, v));
+    assertFalse(checkTableHasProp(MetadataTable.NAME, k, v));
+    assertFalse(checkNamespaceHasProp(Namespaces.DEFAULT_NAMESPACE, k, v));
+    assertFalse(checkTableHasProp(defaultNamespaceTable, k, v));
+    assertFalse(checkNamespaceHasProp(namespace, k, v));
+    assertFalse(checkTableHasProp(namespaceTable, k, v));
+  }
+
+  @Test
+  public void listNamespaces() throws Exception {
+    SortedSet<String> namespaces = c.namespaceOperations().list();
+    Map<String,String> map = c.namespaceOperations().namespaceIdMap();
+    assertEquals(2, namespaces.size());
+    assertEquals(2, map.size());
+    assertTrue(namespaces.contains(Namespaces.ACCUMULO_NAMESPACE));
+    assertTrue(namespaces.contains(Namespaces.DEFAULT_NAMESPACE));
+    assertFalse(namespaces.contains(namespace));
+    assertEquals(Namespaces.ACCUMULO_NAMESPACE_ID, map.get(Namespaces.ACCUMULO_NAMESPACE));
+    assertEquals(Namespaces.DEFAULT_NAMESPACE_ID, map.get(Namespaces.DEFAULT_NAMESPACE));
+    assertNull(map.get(namespace));
+
+    c.namespaceOperations().create(namespace);
+    namespaces = c.namespaceOperations().list();
+    map = c.namespaceOperations().namespaceIdMap();
+    assertEquals(3, namespaces.size());
+    assertEquals(3, map.size());
+    assertTrue(namespaces.contains(Namespaces.ACCUMULO_NAMESPACE));
+    assertTrue(namespaces.contains(Namespaces.DEFAULT_NAMESPACE));
+    assertTrue(namespaces.contains(namespace));
+    assertEquals(Namespaces.ACCUMULO_NAMESPACE_ID, map.get(Namespaces.ACCUMULO_NAMESPACE));
+    assertEquals(Namespaces.DEFAULT_NAMESPACE_ID, map.get(Namespaces.DEFAULT_NAMESPACE));
+    assertNotNull(map.get(namespace));
+
+    c.namespaceOperations().delete(namespace);
+    namespaces = c.namespaceOperations().list();
+    map = c.namespaceOperations().namespaceIdMap();
+    assertEquals(2, namespaces.size());
+    assertEquals(2, map.size());
+    assertTrue(namespaces.contains(Namespaces.ACCUMULO_NAMESPACE));
+    assertTrue(namespaces.contains(Namespaces.DEFAULT_NAMESPACE));
+    assertFalse(namespaces.contains(namespace));
+    assertEquals(Namespaces.ACCUMULO_NAMESPACE_ID, map.get(Namespaces.ACCUMULO_NAMESPACE));
+    assertEquals(Namespaces.DEFAULT_NAMESPACE_ID, map.get(Namespaces.DEFAULT_NAMESPACE));
+    assertNull(map.get(namespace));
+  }
+
+  @Test
+  public void loadClass() throws Exception {
+    assertTrue(c.namespaceOperations().testClassLoad(Namespaces.DEFAULT_NAMESPACE, VersioningIterator.class.getName(), SortedKeyValueIterator.class.getName()));
+    assertFalse(c.namespaceOperations().testClassLoad(Namespaces.DEFAULT_NAMESPACE, "dummy", SortedKeyValueIterator.class.getName()));
+    try {
+      c.namespaceOperations().testClassLoad(namespace, "dummy", "dummy");
+      fail();
+    } catch (NamespaceNotFoundException e) {
+      // expected, ignore
+    }
+  }
+
+  @Test
+  public void testModifyingPermissions() throws Exception {
+    String tableName = namespace + ".modify";
+    c.namespaceOperations().create(namespace);
+    c.tableOperations().create(tableName);
+    assertTrue(c.securityOperations().hasTablePermission(c.whoami(), tableName, TablePermission.READ));
+    c.securityOperations().revokeTablePermission(c.whoami(), tableName, TablePermission.READ);
+    assertFalse(c.securityOperations().hasTablePermission(c.whoami(), tableName, TablePermission.READ));
+    c.securityOperations().grantTablePermission(c.whoami(), tableName, TablePermission.READ);
+    assertTrue(c.securityOperations().hasTablePermission(c.whoami(), tableName, TablePermission.READ));
+    c.tableOperations().delete(tableName);
+
+    try {
+      c.securityOperations().hasTablePermission(c.whoami(), tableName, TablePermission.READ);
+      fail();
+    } catch (Exception e) {
+      if (!(e instanceof AccumuloSecurityException) || !((AccumuloSecurityException) e).getSecurityErrorCode().equals(SecurityErrorCode.TABLE_DOESNT_EXIST))
+        throw new Exception("Has permission resulted in " + e.getClass().getName(), e);
+    }
+
+    try {
+      c.securityOperations().grantTablePermission(c.whoami(), tableName, TablePermission.READ);
+      fail();
+    } catch (Exception e) {
+      if (!(e instanceof AccumuloSecurityException) || !((AccumuloSecurityException) e).getSecurityErrorCode().equals(SecurityErrorCode.TABLE_DOESNT_EXIST))
+        throw new Exception("Has permission resulted in " + e.getClass().getName(), e);
+    }
+
+    try {
+      c.securityOperations().revokeTablePermission(c.whoami(), tableName, TablePermission.READ);
+      fail();
+    } catch (Exception e) {
+      if (!(e instanceof AccumuloSecurityException) || !((AccumuloSecurityException) e).getSecurityErrorCode().equals(SecurityErrorCode.TABLE_DOESNT_EXIST))
+        throw new Exception("Has permission resulted in " + e.getClass().getName(), e);
+    }
+
+    assertTrue(c.securityOperations().hasNamespacePermission(c.whoami(), namespace, NamespacePermission.READ));
+    c.securityOperations().revokeNamespacePermission(c.whoami(), namespace, NamespacePermission.READ);
+    assertFalse(c.securityOperations().hasNamespacePermission(c.whoami(), namespace, NamespacePermission.READ));
+    c.securityOperations().grantNamespacePermission(c.whoami(), namespace, NamespacePermission.READ);
+    assertTrue(c.securityOperations().hasNamespacePermission(c.whoami(), namespace, NamespacePermission.READ));
+
+    c.namespaceOperations().delete(namespace);
+
+    try {
+      c.securityOperations().hasTablePermission(c.whoami(), tableName, TablePermission.READ);
+      fail();
+    } catch (Exception e) {
+      if (!(e instanceof AccumuloSecurityException) || !((AccumuloSecurityException) e).getSecurityErrorCode().equals(SecurityErrorCode.TABLE_DOESNT_EXIST))
+        throw new Exception("Has permission resulted in " + e.getClass().getName(), e);
+    }
+
+    try {
+      c.securityOperations().grantTablePermission(c.whoami(), tableName, TablePermission.READ);
+      fail();
+    } catch (Exception e) {
+      if (!(e instanceof AccumuloSecurityException) || !((AccumuloSecurityException) e).getSecurityErrorCode().equals(SecurityErrorCode.TABLE_DOESNT_EXIST))
+        throw new Exception("Has permission resulted in " + e.getClass().getName(), e);
+    }
+
+    try {
+      c.securityOperations().revokeTablePermission(c.whoami(), tableName, TablePermission.READ);
+      fail();
+    } catch (Exception e) {
+      if (!(e instanceof AccumuloSecurityException) || !((AccumuloSecurityException) e).getSecurityErrorCode().equals(SecurityErrorCode.TABLE_DOESNT_EXIST))
+        throw new Exception("Has permission resulted in " + e.getClass().getName(), e);
+    }
+
+    try {
+      c.securityOperations().hasNamespacePermission(c.whoami(), namespace, NamespacePermission.READ);
+      fail();
+    } catch (Exception e) {
+      if (!(e instanceof AccumuloSecurityException) || !((AccumuloSecurityException) e).getSecurityErrorCode().equals(SecurityErrorCode.NAMESPACE_DOESNT_EXIST))
+        throw new Exception("Has permission resulted in " + e.getClass().getName(), e);
+    }
+
+    try {
+      c.securityOperations().grantNamespacePermission(c.whoami(), namespace, NamespacePermission.READ);
+      fail();
+    } catch (Exception e) {
+      if (!(e instanceof AccumuloSecurityException) || !((AccumuloSecurityException) e).getSecurityErrorCode().equals(SecurityErrorCode.NAMESPACE_DOESNT_EXIST))
+        throw new Exception("Has permission resulted in " + e.getClass().getName(), e);
+    }
+
+    try {
+      c.securityOperations().revokeNamespacePermission(c.whoami(), namespace, NamespacePermission.READ);
+      fail();
+    } catch (Exception e) {
+      if (!(e instanceof AccumuloSecurityException) || !((AccumuloSecurityException) e).getSecurityErrorCode().equals(SecurityErrorCode.NAMESPACE_DOESNT_EXIST))
+        throw new Exception("Has permission resulted in " + e.getClass().getName(), e);
+    }
+
+  }
+
+  @Test
+  public void verifyTableOperationsExceptions() throws Exception {
+    String tableName = namespace + ".1";
+    IteratorSetting setting = new IteratorSetting(200, VersioningIterator.class);
+    Text a = new Text("a");
+    Text z = new Text("z");
+    TableOperations ops = c.tableOperations();
+
+    // this one doesn't throw an exception, so don't fail; just check that it works
+    assertFalse(ops.exists(tableName));
+
+    // table operations that should throw an AccumuloException caused by NamespaceNotFoundException
+    int numRun = 0;
+    ACCUMULOEXCEPTIONS_NAMESPACENOTFOUND: for (int i = 0;; ++i)
+      try {
+        switch (i) {
+          case 0:
+            ops.create(tableName);
+            fail();
+            break;
+          case 1:
+            ops.create("a");
+            ops.clone("a", tableName, true, Collections.<String,String> emptyMap(), Collections.<String> emptySet());
+            fail();
+            break;
+          case 2:
+            ops.importTable(tableName, System.getProperty("user.dir") + "/target");
+            fail();
+            break;
+          default:
+            // break out of infinite loop
+            assertEquals(3, i); // check test integrity
+            assertEquals(3, numRun); // check test integrity
+            break ACCUMULOEXCEPTIONS_NAMESPACENOTFOUND;
+        }
+      } catch (Exception e) {
+        numRun++;
+        if (!(e instanceof AccumuloException) || !(e.getCause() instanceof NamespaceNotFoundException))
+          throw new Exception("Case " + i + " resulted in " + e.getClass().getName(), e);
+      }
+
+    // table operations that should throw an AccumuloException caused by a TableNotFoundException caused by a NamespaceNotFoundException
+    // these are here because we didn't declare TableNotFoundException in the API :(
+    numRun = 0;
+    ACCUMULOEXCEPTIONS_TABLENOTFOUND: for (int i = 0;; ++i)
+      try {
+        switch (i) {
+          case 0:
+            ops.removeConstraint(tableName, 0);
+            fail();
+            break;
+          case 1:
+            ops.removeProperty(tableName, "a");
+            fail();
+            break;
+          case 2:
+            ops.setProperty(tableName, "a", "b");
+            fail();
+            break;
+          default:
+            // break out of infinite loop
+            assertEquals(3, i); // check test integrity
+            assertEquals(3, numRun); // check test integrity
+            break ACCUMULOEXCEPTIONS_TABLENOTFOUND;
+        }
+      } catch (Exception e) {
+        numRun++;
+        if (!(e instanceof AccumuloException) || !(e.getCause() instanceof TableNotFoundException)
+            || !(e.getCause().getCause() instanceof NamespaceNotFoundException))
+          throw new Exception("Case " + i + " resulted in " + e.getClass().getName(), e);
+      }
+
+    // table operations that should throw a TableNotFoundException caused by NamespaceNotFoundException
+    numRun = 0;
+    TABLENOTFOUNDEXCEPTIONS: for (int i = 0;; ++i)
+      try {
+        switch (i) {
+          case 0:
+            ops.addConstraint(tableName, NumericValueConstraint.class.getName());
+            fail();
+            break;
+          case 1:
+            ops.addSplits(tableName, new TreeSet<Text>());
+            fail();
+            break;
+          case 2:
+            ops.attachIterator(tableName, setting);
+            fail();
+            break;
+          case 3:
+            ops.cancelCompaction(tableName);
+            fail();
+            break;
+          case 4:
+            ops.checkIteratorConflicts(tableName, setting, EnumSet.allOf(IteratorScope.class));
+            fail();
+            break;
+          case 5:
+            ops.clearLocatorCache(tableName);
+            fail();
+            break;
+          case 6:
+            ops.clone(tableName, "2", true, Collections.<String,String> emptyMap(), Collections.<String> emptySet());
+            fail();
+            break;
+          case 7:
+            ops.compact(tableName, a, z, true, true);
+            fail();
+            break;
+          case 8:
+            ops.delete(tableName);
+            fail();
+            break;
+          case 9:
+            ops.deleteRows(tableName, a, z);
+            fail();
+            break;
+          case 10:
+            ops.splitRangeByTablets(tableName, new Range(), 10);
+            fail();
+            break;
+          case 11:
+            ops.exportTable(tableName, namespace + "_dir");
+            fail();
+            break;
+          case 12:
+            ops.flush(tableName, a, z, true);
+            fail();
+            break;
+          case 13:
+            ops.getDiskUsage(Collections.singleton(tableName));
+            fail();
+            break;
+          case 14:
+            ops.getIteratorSetting(tableName, "a", IteratorScope.scan);
+            fail();
+            break;
+          case 15:
+            ops.getLocalityGroups(tableName);
+            fail();
+            break;
+          case 16:
+            ops.getMaxRow(tableName, Authorizations.EMPTY, a, true, z, true);
+            fail();
+            break;
+          case 17:
+            ops.getProperties(tableName);
+            fail();
+            break;
+          case 18:
+            ops.importDirectory(tableName, "", "", false);
+            fail();
+            break;
+          case 19:
+            ops.testClassLoad(tableName, VersioningIterator.class.getName(), SortedKeyValueIterator.class.getName());
+            fail();
+            break;
+          case 20:
+            ops.listConstraints(tableName);
+            fail();
+            break;
+          case 21:
+            ops.listIterators(tableName);
+            fail();
+            break;
+          case 22:
+            ops.listSplits(tableName);
+            fail();
+            break;
+          case 23:
+            ops.merge(tableName, a, z);
+            fail();
+            break;
+          case 24:
+            ops.offline(tableName, true);
+            fail();
+            break;
+          case 25:
+            ops.online(tableName, true);
+            fail();
+            break;
+          case 26:
+            ops.removeIterator(tableName, "a", EnumSet.of(IteratorScope.scan));
+            fail();
+            break;
+          case 27:
+            ops.rename(tableName, tableName + "2");
+            fail();
+            break;
+          case 28:
+            ops.setLocalityGroups(tableName, Collections.<String,Set<Text>> emptyMap());
+            fail();
+            break;
+          default:
+            // break out of infinite loop
+            assertEquals(29, i); // check test integrity
+            assertEquals(29, numRun); // check test integrity
+            break TABLENOTFOUNDEXCEPTIONS;
+        }
+      } catch (Exception e) {
+        numRun++;
+        if (!(e instanceof TableNotFoundException) || !(e.getCause() instanceof NamespaceNotFoundException))
+          throw new Exception("Case " + i + " resulted in " + e.getClass().getName(), e);
+      }
+  }
+
+  @Test
+  public void verifyNamespaceOperationsExceptions() throws Exception {
+    IteratorSetting setting = new IteratorSetting(200, VersioningIterator.class);
+    NamespaceOperations ops = c.namespaceOperations();
+
+    // this one doesn't throw an exception, so don't fail; just check that it works
+    assertFalse(ops.exists(namespace));
+
+    // namespace operations that should throw a NamespaceNotFoundException
+    int numRun = 0;
+    NAMESPACENOTFOUND: for (int i = 0;; ++i)
+      try {
+        switch (i) {
+          case 0:
+            ops.addConstraint(namespace, NumericValueConstraint.class.getName());
+            fail();
+            break;
+          case 1:
+            ops.attachIterator(namespace, setting);
+            fail();
+            break;
+          case 2:
+            ops.checkIteratorConflicts(namespace, setting, EnumSet.of(IteratorScope.scan));
+            fail();
+            break;
+          case 3:
+            ops.delete(namespace);
+            fail();
+            break;
+          case 4:
+            ops.getIteratorSetting(namespace, "thing", IteratorScope.scan);
+            fail();
+            break;
+          case 5:
+            ops.getProperties(namespace);
+            fail();
+            break;
+          case 6:
+            ops.listConstraints(namespace);
+            fail();
+            break;
+          case 7:
+            ops.listIterators(namespace);
+            fail();
+            break;
+          case 8:
+            ops.removeConstraint(namespace, 1);
+            fail();
+            break;
+          case 9:
+            ops.removeIterator(namespace, "thing", EnumSet.allOf(IteratorScope.class));
+            fail();
+            break;
+          case 10:
+            ops.removeProperty(namespace, "a");
+            fail();
+            break;
+          case 11:
+            ops.rename(namespace, namespace + "2");
+            fail();
+            break;
+          case 12:
+            ops.setProperty(namespace, "k", "v");
+            fail();
+            break;
+          case 13:
+            ops.testClassLoad(namespace, VersioningIterator.class.getName(), SortedKeyValueIterator.class.getName());
+            fail();
+            break;
+          default:
+            // break out of infinite loop
+            assertEquals(14, i); // check test integrity
+            assertEquals(14, numRun); // check test integrity
+            break NAMESPACENOTFOUND;
+        }
+      } catch (Exception e) {
+        numRun++;
+        if (!(e instanceof NamespaceNotFoundException))
+          throw new Exception("Case " + i + " resulted in " + e.getClass().getName(), e);
+      }
+
+    // namespace operations that should throw a NamespaceExistsException
+    numRun = 0;
+    NAMESPACEEXISTS: for (int i = 0;; ++i)
+      try {
+        switch (i) {
+          case 0:
+            ops.create(namespace + "0");
+            ops.create(namespace + "0"); // should fail here
+            fail();
+            break;
+          case 1:
+            ops.create(namespace + i + "_1");
+            ops.create(namespace + i + "_2");
+            ops.rename(namespace + i + "_1", namespace + i + "_2"); // should fail here
+            fail();
+            break;
+          case 2:
+            ops.create(Namespaces.DEFAULT_NAMESPACE);
+            fail();
+            break;
+          case 3:
+            ops.create(Namespaces.ACCUMULO_NAMESPACE);
+            fail();
+            break;
+          case 4:
+            ops.create(namespace + i + "_1");
+            ops.rename(namespace + i + "_1", Namespaces.DEFAULT_NAMESPACE); // should fail here
+            fail();
+            break;
+          case 5:
+            ops.create(namespace + i + "_1");
+            ops.rename(namespace + i + "_1", Namespaces.ACCUMULO_NAMESPACE); // should fail here
+            fail();
+            break;
+          default:
+            // break out of infinite loop
+            assertEquals(6, i); // check test integrity
+            assertEquals(6, numRun); // check test integrity
+            break NAMESPACEEXISTS;
+        }
+      } catch (Exception e) {
+        numRun++;
+        if (!(e instanceof NamespaceExistsException))
+          throw new Exception("Case " + i + " resulted in " + e.getClass().getName(), e);
+      }
+  }
+
+  private boolean checkTableHasProp(String t, String propKey, String propVal) {
+    return checkHasProperty(t, propKey, propVal, true);
+  }
+
+  private boolean checkNamespaceHasProp(String n, String propKey, String propVal) {
+    return checkHasProperty(n, propKey, propVal, false);
+  }
+
+  private boolean checkHasProperty(String name, String propKey, String propVal, boolean nameIsTable) {
+    try {
+      Iterable<Entry<String,String>> iterable = nameIsTable ? c.tableOperations().getProperties(name) : c.namespaceOperations().getProperties(name);
+      for (Entry<String,String> e : iterable)
+        if (propKey.equals(e.getKey()))
+          return propVal.equals(e.getValue());
+      return false;
+    } catch (Exception e) {
+      fail();
+      return false;
+    }
+  }
+
+  public static class SimpleFilter extends Filter {
+    @Override
+    public boolean accept(Key k, Value v) {
+      if (k.getColumnFamily().toString().equals("a"))
+        return false;
+      return true;
+    }
+  }
+
+  private void expectPermissionDenied(AccumuloSecurityException sec) {
+    assertEquals(sec.getSecurityErrorCode().getClass(), SecurityErrorCode.class);
+    switch (sec.getSecurityErrorCode()) {
+      case PERMISSION_DENIED:
+        break;
+      default:
+        fail();
+    }
+  }
+
+}

http://git-wip-us.apache.org/repos/asf/accumulo/blob/01ae5b85/test/src/main/java/org/apache/accumulo/test/RecoveryCompactionsAreFlushesIT.java
----------------------------------------------------------------------
diff --git a/test/src/main/java/org/apache/accumulo/test/RecoveryCompactionsAreFlushesIT.java b/test/src/main/java/org/apache/accumulo/test/RecoveryCompactionsAreFlushesIT.java
new file mode 100644
index 0000000..60b3cf7
--- /dev/null
+++ b/test/src/main/java/org/apache/accumulo/test/RecoveryCompactionsAreFlushesIT.java
@@ -0,0 +1,101 @@
+/*
+ * 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;
+
+import java.util.Map.Entry;
+
+import org.apache.accumulo.cluster.ClusterControl;
+import org.apache.accumulo.core.client.BatchWriter;
+import org.apache.accumulo.core.client.BatchWriterConfig;
+import org.apache.accumulo.core.client.Connector;
+import org.apache.accumulo.core.client.Scanner;
+import org.apache.accumulo.core.conf.Property;
+import org.apache.accumulo.core.data.Key;
+import org.apache.accumulo.core.data.Mutation;
+import org.apache.accumulo.core.data.Value;
+import org.apache.accumulo.core.metadata.MetadataTable;
+import org.apache.accumulo.core.metadata.schema.MetadataSchema;
+import org.apache.accumulo.core.security.Authorizations;
+import org.apache.accumulo.harness.AccumuloClusterHarness;
+import org.apache.accumulo.minicluster.ServerType;
+import org.apache.accumulo.minicluster.impl.MiniAccumuloConfigImpl;
+import org.apache.hadoop.conf.Configuration;
+import org.apache.hadoop.fs.RawLocalFileSystem;
+import org.junit.Assert;
+import org.junit.Test;
+
+import com.google.common.collect.Iterators;
+
+// Accumulo3010
+public class RecoveryCompactionsAreFlushesIT extends AccumuloClusterHarness {
+
+  @Override
+  public int defaultTimeoutSeconds() {
+    return 60;
+  }
+
+  @Override
+  public void configureMiniCluster(MiniAccumuloConfigImpl cfg, Configuration hadoopCoreSite) {
+    cfg.setNumTservers(1);
+    cfg.setProperty(Property.INSTANCE_ZK_TIMEOUT, "5s");
+    // file system supports recovery
+    hadoopCoreSite.set("fs.file.impl", RawLocalFileSystem.class.getName());
+  }
+
+  @Test
+  public void test() throws Exception {
+    // create a table
+    String tableName = getUniqueNames(1)[0];
+    Connector c = getConnector();
+    c.tableOperations().create(tableName);
+    c.tableOperations().setProperty(tableName, Property.TABLE_MAJC_RATIO.getKey(), "100");
+    c.tableOperations().setProperty(tableName, Property.TABLE_FILE_MAX.getKey(), "3");
+    // create 3 flush files
+    BatchWriter bw = c.createBatchWriter(tableName, new BatchWriterConfig());
+    Mutation m = new Mutation("a");
+    m.put("b", "c", new Value("v".getBytes()));
+    for (int i = 0; i < 3; i++) {
+      bw.addMutation(m);
+      bw.flush();
+      c.tableOperations().flush(tableName, null, null, true);
+    }
+    // create an unsaved mutation
+    bw.addMutation(m);
+    bw.close();
+
+    ClusterControl control = cluster.getClusterControl();
+
+    // kill the tablet servers
+    control.stopAllServers(ServerType.TABLET_SERVER);
+
+    // recover
+    control.startAllServers(ServerType.TABLET_SERVER);
+
+    // ensure the table is readable
+    Iterators.size(c.createScanner(tableName, Authorizations.EMPTY).iterator());
+
+    // ensure that the recovery was not a merging minor compaction
+    Scanner s = c.createScanner(MetadataTable.NAME, Authorizations.EMPTY);
+    s.fetchColumnFamily(MetadataSchema.TabletsSection.DataFileColumnFamily.NAME);
+    for (Entry<Key,Value> entry : s) {
+      String filename = entry.getKey().getColumnQualifier().toString();
+      String parts[] = filename.split("/");
+      Assert.assertFalse(parts[parts.length - 1].startsWith("M"));
+    }
+  }
+
+}


Mime
View raw message