You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@accumulo.apache.org by md...@apache.org on 2014/03/12 21:19:09 UTC

[1/3] git commit: ACCUMULO-2444 unit tests for a.o.o.core.security

Repository: accumulo
Updated Branches:
  refs/heads/1.6.0-SNAPSHOT 6dd1bd3e9 -> c657c5758
  refs/heads/master 20375b6b8 -> 2368eef2f


ACCUMULO-2444 unit tests for a.o.o.core.security


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

Branch: refs/heads/1.6.0-SNAPSHOT
Commit: c657c5758a1ab1224abc3377066699eaf826dd62
Parents: 6dd1bd3
Author: Mike Drob <md...@cloudera.com>
Authored: Mon Mar 10 10:20:36 2014 -0400
Committer: Mike Drob <md...@cloudera.com>
Committed: Wed Mar 12 16:12:57 2014 -0400

----------------------------------------------------------------------
 .../core/security/NamespacePermission.java      |   1 +
 .../core/security/ColumnVisibilityTest.java     |  34 +++++-
 .../core/security/NamespacePermissionsTest.java |  39 +++++++
 .../core/security/VisibilityConstraintTest.java | 106 +++++++++++++++++++
 4 files changed, 178 insertions(+), 2 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/accumulo/blob/c657c575/core/src/main/java/org/apache/accumulo/core/security/NamespacePermission.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/accumulo/core/security/NamespacePermission.java b/core/src/main/java/org/apache/accumulo/core/security/NamespacePermission.java
index f9f7564..44cee0c 100644
--- a/core/src/main/java/org/apache/accumulo/core/security/NamespacePermission.java
+++ b/core/src/main/java/org/apache/accumulo/core/security/NamespacePermission.java
@@ -80,6 +80,7 @@ public enum NamespacePermission {
    * @throws IndexOutOfBoundsException
    *           if the byte ID is invalid
    */
+  // This method isn't used anywhere, why is it public API?
   public static NamespacePermission getPermissionById(byte id) {
     NamespacePermission result = mapping[id];
     if (result != null)

http://git-wip-us.apache.org/repos/asf/accumulo/blob/c657c575/core/src/test/java/org/apache/accumulo/core/security/ColumnVisibilityTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/org/apache/accumulo/core/security/ColumnVisibilityTest.java b/core/src/test/java/org/apache/accumulo/core/security/ColumnVisibilityTest.java
index 7a6a80d..931ff41 100644
--- a/core/src/test/java/org/apache/accumulo/core/security/ColumnVisibilityTest.java
+++ b/core/src/test/java/org/apache/accumulo/core/security/ColumnVisibilityTest.java
@@ -19,10 +19,16 @@ package org.apache.accumulo.core.security;
 import static org.apache.accumulo.core.security.ColumnVisibility.quote;
 import static org.junit.Assert.assertArrayEquals;
 import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
 import static org.junit.Assert.fail;
 
+import java.util.Comparator;
+
+import org.apache.accumulo.core.Constants;
 import org.apache.accumulo.core.security.ColumnVisibility.Node;
+import org.apache.accumulo.core.security.ColumnVisibility.NodeComparator;
 import org.apache.accumulo.core.security.ColumnVisibility.NodeType;
+import org.apache.hadoop.io.Text;
 import org.junit.Test;
 
 public class ColumnVisibilityTest {
@@ -46,8 +52,14 @@ public class ColumnVisibilityTest {
   @Test
   public void testEmpty() {
     // empty visibility is valid
-    new ColumnVisibility();
-    new ColumnVisibility(new byte[0]);
+    ColumnVisibility a = new ColumnVisibility();
+    ColumnVisibility b = new ColumnVisibility(new byte[0]);
+    ColumnVisibility c = new ColumnVisibility("");
+    ColumnVisibility d = new ColumnVisibility(new Text());
+
+    assertEquals(a, b);
+    assertEquals(a, c);
+    assertEquals(a, d);
   }
 
   @Test
@@ -205,6 +217,24 @@ public class ColumnVisibilityTest {
     assertNode(node.getChildren().get(1).children.get(1), NodeType.TERM, 7, 8);
   }
 
+  @Test
+  public void testEmptyParseTreesAreEqual() {
+    Comparator<Node> comparator = new NodeComparator(new byte[] {});
+    Node empty = new ColumnVisibility().getParseTree();
+    assertEquals(0, comparator.compare(empty, parse("")));
+  }
+
+  @Test
+  public void testParseTreesOrdering() {
+    byte[] expression = "(b&c&d)|((a|m)&y&z)|(e&f)".getBytes(Constants.UTF8);
+    byte[] flattened = new ColumnVisibility(expression).flatten();
+
+    // Convert to String for indexOf convenience
+    String flat = new String(flattened, Constants.UTF8);
+    assertTrue("shortest expressions sort first", flat.indexOf('e') < flat.indexOf('|'));
+    assertTrue("shortest children sort first", flat.indexOf('b') < flat.indexOf('a'));
+  }
+
   private Node parse(String s) {
     ColumnVisibility v = new ColumnVisibility(s);
     return v.getParseTree();

http://git-wip-us.apache.org/repos/asf/accumulo/blob/c657c575/core/src/test/java/org/apache/accumulo/core/security/NamespacePermissionsTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/org/apache/accumulo/core/security/NamespacePermissionsTest.java b/core/src/test/java/org/apache/accumulo/core/security/NamespacePermissionsTest.java
new file mode 100644
index 0000000..223b3ca
--- /dev/null
+++ b/core/src/test/java/org/apache/accumulo/core/security/NamespacePermissionsTest.java
@@ -0,0 +1,39 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.accumulo.core.security;
+
+import static org.junit.Assert.assertTrue;
+
+import java.util.EnumSet;
+
+import org.junit.Test;
+
+public class NamespacePermissionsTest {
+  @Test
+  public void testEnsureEquivalencies() {
+    EnumSet<NamespacePermission> set = EnumSet.allOf(NamespacePermission.class);
+
+    for (TablePermission permission : TablePermission.values()) {
+      set.remove(NamespacePermission.getEquivalent(permission));
+    }
+    for (SystemPermission permission : SystemPermission.values()) {
+      set.remove(NamespacePermission.getEquivalent(permission));
+    }
+
+    assertTrue("All namespace permissions should have equivalent table or system permissions.", set.isEmpty());
+  }
+}

http://git-wip-us.apache.org/repos/asf/accumulo/blob/c657c575/core/src/test/java/org/apache/accumulo/core/security/VisibilityConstraintTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/org/apache/accumulo/core/security/VisibilityConstraintTest.java b/core/src/test/java/org/apache/accumulo/core/security/VisibilityConstraintTest.java
new file mode 100644
index 0000000..de6ca21
--- /dev/null
+++ b/core/src/test/java/org/apache/accumulo/core/security/VisibilityConstraintTest.java
@@ -0,0 +1,106 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.accumulo.core.security;
+
+import static org.easymock.EasyMock.createMock;
+import static org.easymock.EasyMock.createNiceMock;
+import static org.easymock.EasyMock.expect;
+import static org.easymock.EasyMock.replay;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNull;
+
+import java.util.Arrays;
+import java.util.List;
+
+import org.apache.accumulo.core.Constants;
+import org.apache.accumulo.core.constraints.Constraint.Environment;
+import org.apache.accumulo.core.data.ArrayByteSequence;
+import org.apache.accumulo.core.data.Mutation;
+import org.junit.Before;
+import org.junit.Ignore;
+import org.junit.Test;
+
+public class VisibilityConstraintTest {
+
+  VisibilityConstraint vc;
+  Environment env;
+  Mutation mutation;
+
+  static final ColumnVisibility good = new ColumnVisibility("good");
+  static final ColumnVisibility bad = new ColumnVisibility("bad");
+
+  static final String D = "don't care";
+
+  static final List<Short> ENOAUTH = Arrays.asList((short) 2);
+
+  /**
+   * @throws java.lang.Exception
+   */
+  @Before
+  public void setUp() throws Exception {
+    vc = new VisibilityConstraint();
+    mutation = new Mutation("r");
+
+    ArrayByteSequence bs = new ArrayByteSequence("good".getBytes(Constants.UTF8));
+
+    AuthorizationContainer ac = createNiceMock(AuthorizationContainer.class);
+    expect(ac.contains(bs)).andReturn(true);
+    replay(ac);
+
+    env = createMock(Environment.class);
+    expect(env.getAuthorizationsContainer()).andReturn(ac);
+    replay(env);
+  }
+
+  @Test
+  public void testNoVisibility() {
+    mutation.put(D, D, D);
+    assertNull("authorized", vc.check(env, mutation));
+  }
+
+  @Test
+  public void testVisibilityNoAuth() {
+    mutation.put(D, D, bad, D);
+    assertEquals("unauthorized", ENOAUTH, vc.check(env, mutation));
+  }
+
+  @Test
+  public void testGoodVisibilityAuth() {
+    mutation.put(D, D, good, D);
+    assertNull("authorized", vc.check(env, mutation));
+  }
+
+  @Test
+  public void testCachedVisibilities() {
+    mutation.put(D, D, good, "v");
+    mutation.put(D, D, good, "v2");
+    assertNull("authorized", vc.check(env, mutation));
+  }
+
+  @Test
+  public void testMixedVisibilities() {
+    mutation.put(D, D, bad, D);
+    mutation.put(D, D, good, D);
+    assertEquals("unauthorized", ENOAUTH, vc.check(env, mutation));
+  }
+
+  @Test
+  @Ignore
+  public void testMalformedVisibility() {
+    // TODO: ACCUMULO-1006 Should test for returning error code 1, but not sure how since ColumnVisibility won't let us construct a bad one in the first place
+  }
+}


[3/3] git commit: Merge branch '1.6.0-SNAPSHOT'

Posted by md...@apache.org.
Merge branch '1.6.0-SNAPSHOT'


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

Branch: refs/heads/master
Commit: 2368eef2f85aa56c3d3f043ed4e40aa22d30a8f6
Parents: 20375b6 c657c57
Author: Mike Drob <md...@cloudera.com>
Authored: Wed Mar 12 16:17:44 2014 -0400
Committer: Mike Drob <md...@cloudera.com>
Committed: Wed Mar 12 16:17:44 2014 -0400

----------------------------------------------------------------------
 .../core/security/NamespacePermission.java      |   1 +
 .../core/security/ColumnVisibilityTest.java     |  34 +++++-
 .../core/security/NamespacePermissionsTest.java |  39 +++++++
 .../core/security/VisibilityConstraintTest.java | 106 +++++++++++++++++++
 4 files changed, 178 insertions(+), 2 deletions(-)
----------------------------------------------------------------------



[2/3] git commit: ACCUMULO-2444 unit tests for a.o.o.core.security

Posted by md...@apache.org.
ACCUMULO-2444 unit tests for a.o.o.core.security


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

Branch: refs/heads/master
Commit: c657c5758a1ab1224abc3377066699eaf826dd62
Parents: 6dd1bd3
Author: Mike Drob <md...@cloudera.com>
Authored: Mon Mar 10 10:20:36 2014 -0400
Committer: Mike Drob <md...@cloudera.com>
Committed: Wed Mar 12 16:12:57 2014 -0400

----------------------------------------------------------------------
 .../core/security/NamespacePermission.java      |   1 +
 .../core/security/ColumnVisibilityTest.java     |  34 +++++-
 .../core/security/NamespacePermissionsTest.java |  39 +++++++
 .../core/security/VisibilityConstraintTest.java | 106 +++++++++++++++++++
 4 files changed, 178 insertions(+), 2 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/accumulo/blob/c657c575/core/src/main/java/org/apache/accumulo/core/security/NamespacePermission.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/accumulo/core/security/NamespacePermission.java b/core/src/main/java/org/apache/accumulo/core/security/NamespacePermission.java
index f9f7564..44cee0c 100644
--- a/core/src/main/java/org/apache/accumulo/core/security/NamespacePermission.java
+++ b/core/src/main/java/org/apache/accumulo/core/security/NamespacePermission.java
@@ -80,6 +80,7 @@ public enum NamespacePermission {
    * @throws IndexOutOfBoundsException
    *           if the byte ID is invalid
    */
+  // This method isn't used anywhere, why is it public API?
   public static NamespacePermission getPermissionById(byte id) {
     NamespacePermission result = mapping[id];
     if (result != null)

http://git-wip-us.apache.org/repos/asf/accumulo/blob/c657c575/core/src/test/java/org/apache/accumulo/core/security/ColumnVisibilityTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/org/apache/accumulo/core/security/ColumnVisibilityTest.java b/core/src/test/java/org/apache/accumulo/core/security/ColumnVisibilityTest.java
index 7a6a80d..931ff41 100644
--- a/core/src/test/java/org/apache/accumulo/core/security/ColumnVisibilityTest.java
+++ b/core/src/test/java/org/apache/accumulo/core/security/ColumnVisibilityTest.java
@@ -19,10 +19,16 @@ package org.apache.accumulo.core.security;
 import static org.apache.accumulo.core.security.ColumnVisibility.quote;
 import static org.junit.Assert.assertArrayEquals;
 import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
 import static org.junit.Assert.fail;
 
+import java.util.Comparator;
+
+import org.apache.accumulo.core.Constants;
 import org.apache.accumulo.core.security.ColumnVisibility.Node;
+import org.apache.accumulo.core.security.ColumnVisibility.NodeComparator;
 import org.apache.accumulo.core.security.ColumnVisibility.NodeType;
+import org.apache.hadoop.io.Text;
 import org.junit.Test;
 
 public class ColumnVisibilityTest {
@@ -46,8 +52,14 @@ public class ColumnVisibilityTest {
   @Test
   public void testEmpty() {
     // empty visibility is valid
-    new ColumnVisibility();
-    new ColumnVisibility(new byte[0]);
+    ColumnVisibility a = new ColumnVisibility();
+    ColumnVisibility b = new ColumnVisibility(new byte[0]);
+    ColumnVisibility c = new ColumnVisibility("");
+    ColumnVisibility d = new ColumnVisibility(new Text());
+
+    assertEquals(a, b);
+    assertEquals(a, c);
+    assertEquals(a, d);
   }
 
   @Test
@@ -205,6 +217,24 @@ public class ColumnVisibilityTest {
     assertNode(node.getChildren().get(1).children.get(1), NodeType.TERM, 7, 8);
   }
 
+  @Test
+  public void testEmptyParseTreesAreEqual() {
+    Comparator<Node> comparator = new NodeComparator(new byte[] {});
+    Node empty = new ColumnVisibility().getParseTree();
+    assertEquals(0, comparator.compare(empty, parse("")));
+  }
+
+  @Test
+  public void testParseTreesOrdering() {
+    byte[] expression = "(b&c&d)|((a|m)&y&z)|(e&f)".getBytes(Constants.UTF8);
+    byte[] flattened = new ColumnVisibility(expression).flatten();
+
+    // Convert to String for indexOf convenience
+    String flat = new String(flattened, Constants.UTF8);
+    assertTrue("shortest expressions sort first", flat.indexOf('e') < flat.indexOf('|'));
+    assertTrue("shortest children sort first", flat.indexOf('b') < flat.indexOf('a'));
+  }
+
   private Node parse(String s) {
     ColumnVisibility v = new ColumnVisibility(s);
     return v.getParseTree();

http://git-wip-us.apache.org/repos/asf/accumulo/blob/c657c575/core/src/test/java/org/apache/accumulo/core/security/NamespacePermissionsTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/org/apache/accumulo/core/security/NamespacePermissionsTest.java b/core/src/test/java/org/apache/accumulo/core/security/NamespacePermissionsTest.java
new file mode 100644
index 0000000..223b3ca
--- /dev/null
+++ b/core/src/test/java/org/apache/accumulo/core/security/NamespacePermissionsTest.java
@@ -0,0 +1,39 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.accumulo.core.security;
+
+import static org.junit.Assert.assertTrue;
+
+import java.util.EnumSet;
+
+import org.junit.Test;
+
+public class NamespacePermissionsTest {
+  @Test
+  public void testEnsureEquivalencies() {
+    EnumSet<NamespacePermission> set = EnumSet.allOf(NamespacePermission.class);
+
+    for (TablePermission permission : TablePermission.values()) {
+      set.remove(NamespacePermission.getEquivalent(permission));
+    }
+    for (SystemPermission permission : SystemPermission.values()) {
+      set.remove(NamespacePermission.getEquivalent(permission));
+    }
+
+    assertTrue("All namespace permissions should have equivalent table or system permissions.", set.isEmpty());
+  }
+}

http://git-wip-us.apache.org/repos/asf/accumulo/blob/c657c575/core/src/test/java/org/apache/accumulo/core/security/VisibilityConstraintTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/org/apache/accumulo/core/security/VisibilityConstraintTest.java b/core/src/test/java/org/apache/accumulo/core/security/VisibilityConstraintTest.java
new file mode 100644
index 0000000..de6ca21
--- /dev/null
+++ b/core/src/test/java/org/apache/accumulo/core/security/VisibilityConstraintTest.java
@@ -0,0 +1,106 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.accumulo.core.security;
+
+import static org.easymock.EasyMock.createMock;
+import static org.easymock.EasyMock.createNiceMock;
+import static org.easymock.EasyMock.expect;
+import static org.easymock.EasyMock.replay;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNull;
+
+import java.util.Arrays;
+import java.util.List;
+
+import org.apache.accumulo.core.Constants;
+import org.apache.accumulo.core.constraints.Constraint.Environment;
+import org.apache.accumulo.core.data.ArrayByteSequence;
+import org.apache.accumulo.core.data.Mutation;
+import org.junit.Before;
+import org.junit.Ignore;
+import org.junit.Test;
+
+public class VisibilityConstraintTest {
+
+  VisibilityConstraint vc;
+  Environment env;
+  Mutation mutation;
+
+  static final ColumnVisibility good = new ColumnVisibility("good");
+  static final ColumnVisibility bad = new ColumnVisibility("bad");
+
+  static final String D = "don't care";
+
+  static final List<Short> ENOAUTH = Arrays.asList((short) 2);
+
+  /**
+   * @throws java.lang.Exception
+   */
+  @Before
+  public void setUp() throws Exception {
+    vc = new VisibilityConstraint();
+    mutation = new Mutation("r");
+
+    ArrayByteSequence bs = new ArrayByteSequence("good".getBytes(Constants.UTF8));
+
+    AuthorizationContainer ac = createNiceMock(AuthorizationContainer.class);
+    expect(ac.contains(bs)).andReturn(true);
+    replay(ac);
+
+    env = createMock(Environment.class);
+    expect(env.getAuthorizationsContainer()).andReturn(ac);
+    replay(env);
+  }
+
+  @Test
+  public void testNoVisibility() {
+    mutation.put(D, D, D);
+    assertNull("authorized", vc.check(env, mutation));
+  }
+
+  @Test
+  public void testVisibilityNoAuth() {
+    mutation.put(D, D, bad, D);
+    assertEquals("unauthorized", ENOAUTH, vc.check(env, mutation));
+  }
+
+  @Test
+  public void testGoodVisibilityAuth() {
+    mutation.put(D, D, good, D);
+    assertNull("authorized", vc.check(env, mutation));
+  }
+
+  @Test
+  public void testCachedVisibilities() {
+    mutation.put(D, D, good, "v");
+    mutation.put(D, D, good, "v2");
+    assertNull("authorized", vc.check(env, mutation));
+  }
+
+  @Test
+  public void testMixedVisibilities() {
+    mutation.put(D, D, bad, D);
+    mutation.put(D, D, good, D);
+    assertEquals("unauthorized", ENOAUTH, vc.check(env, mutation));
+  }
+
+  @Test
+  @Ignore
+  public void testMalformedVisibility() {
+    // TODO: ACCUMULO-1006 Should test for returning error code 1, but not sure how since ColumnVisibility won't let us construct a bad one in the first place
+  }
+}