sentry-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From co...@apache.org
Subject [09/44] sentry git commit: SENTRY-1287: Create sentry-service-server module(Colin Ma, reviewed by Dapeng Sun)
Date Fri, 24 Jun 2016 06:00:38 GMT
http://git-wip-us.apache.org/repos/asf/sentry/blob/e72e6eac/sentry-service/sentry-service-server/src/test/java/org/apache/sentry/provider/db/generic/tools/TestSentryShellKafka.java
----------------------------------------------------------------------
diff --git a/sentry-service/sentry-service-server/src/test/java/org/apache/sentry/provider/db/generic/tools/TestSentryShellKafka.java b/sentry-service/sentry-service-server/src/test/java/org/apache/sentry/provider/db/generic/tools/TestSentryShellKafka.java
new file mode 100644
index 0000000..7db5426
--- /dev/null
+++ b/sentry-service/sentry-service-server/src/test/java/org/apache/sentry/provider/db/generic/tools/TestSentryShellKafka.java
@@ -0,0 +1,542 @@
+/**
+ * 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.sentry.provider.db.generic.tools;
+
+import com.google.common.collect.Sets;
+import com.google.common.io.Files;
+import org.apache.commons.io.FileUtils;
+import org.apache.sentry.core.common.exception.SentryUserException;
+import org.apache.sentry.core.model.kafka.validator.KafkaPrivilegeValidator;
+import org.apache.sentry.provider.db.generic.service.thrift.SentryGenericServiceIntegrationBase;
+import org.apache.sentry.provider.db.generic.service.thrift.TSentryPrivilege;
+import org.apache.sentry.provider.db.generic.service.thrift.TSentryRole;
+import org.apache.sentry.provider.db.tools.SentryShellCommon;
+import org.apache.shiro.config.ConfigurationException;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+
+import java.io.ByteArrayOutputStream;
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.PrintStream;
+import java.util.Arrays;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.Set;
+
+import static org.junit.Assert.*;
+
+public class TestSentryShellKafka extends SentryGenericServiceIntegrationBase {
+  private File confDir;
+  private File confPath;
+  private static String TEST_ROLE_NAME_1 = "testRole1";
+  private static String TEST_ROLE_NAME_2 = "testRole2";
+  private static String KAFKA = "kafka";
+  private String requestorName = "";
+  private String service = "kafka1";
+
+  @Before
+  public void prepareForTest() throws Exception {
+    confDir = Files.createTempDir();
+    confPath = new File(confDir, "sentry-site.xml");
+    if (confPath.createNewFile()) {
+      FileOutputStream to = new FileOutputStream(confPath);
+      conf.writeXml(to);
+      to.close();
+    }
+    requestorName = clientUgi.getShortUserName();//.getProperty("user.name", "");
+    Set<String> requestorUserGroupNames = Sets.newHashSet(ADMIN_GROUP);
+    setLocalGroupMapping(requestorName, requestorUserGroupNames);
+    // add ADMIN_USER for the after() in SentryServiceIntegrationBase
+    setLocalGroupMapping(ADMIN_USER, requestorUserGroupNames);
+    writePolicyFile();
+  }
+
+  @After
+  public void clearTestData() throws Exception {
+    FileUtils.deleteQuietly(confDir);
+  }
+
+  @Test
+  public void testCreateDropRole() throws Exception {
+    runTestAsSubject(new TestOperation() {
+      @Override
+      public void runTestAsSubject() throws Exception {
+        // test: create role with -cr
+        String[] args = { "-cr", "-r", TEST_ROLE_NAME_1, "-conf", confPath.getAbsolutePath() };
+        SentryShellKafka.main(args);
+        // test: create role with --create_role
+        args = new String[] { "--create_role", "-r", TEST_ROLE_NAME_2, "-conf",
+            confPath.getAbsolutePath() };
+        SentryShellKafka.main(args);
+
+        // validate the result, list roles with -lr
+        args = new String[] { "-lr", "-conf", confPath.getAbsolutePath() };
+        SentryShellKafka sentryShell = new SentryShellKafka();
+        Set<String> roleNames = getShellResultWithOSRedirect(sentryShell, args, true);
+        validateRoleNames(roleNames, TEST_ROLE_NAME_1, TEST_ROLE_NAME_2);
+
+        // validate the result, list roles with --list_role
+        args = new String[] { "--list_role", "-conf", confPath.getAbsolutePath() };
+        sentryShell = new SentryShellKafka();
+        roleNames = getShellResultWithOSRedirect(sentryShell, args, true);
+        validateRoleNames(roleNames, TEST_ROLE_NAME_1, TEST_ROLE_NAME_2);
+
+        // test: drop role with -dr
+        args = new String[] { "-dr", "-r", TEST_ROLE_NAME_1, "-conf", confPath.getAbsolutePath() };
+        SentryShellKafka.main(args);
+        // test: drop role with --drop_role
+        args = new String[] { "--drop_role", "-r", TEST_ROLE_NAME_2, "-conf",
+            confPath.getAbsolutePath() };
+        SentryShellKafka.main(args);
+
+        // validate the result
+        Set<TSentryRole> roles = client.listAllRoles(requestorName, KAFKA);
+        assertEquals("Incorrect number of roles", 0, roles.size());
+      }
+    });
+  }
+
+  @Test
+  public void testAddDeleteRoleForGroup() throws Exception {
+    runTestAsSubject(new TestOperation() {
+      @Override
+      public void runTestAsSubject() throws Exception {
+        // Group names are case sensitive - mixed case names should work
+        String TEST_GROUP_1 = "testGroup1";
+        String TEST_GROUP_2 = "testGroup2";
+        String TEST_GROUP_3 = "testGroup3";
+
+        // create the role for test
+        client.createRole(requestorName, TEST_ROLE_NAME_1, KAFKA);
+        client.createRole(requestorName, TEST_ROLE_NAME_2, KAFKA);
+        // test: add role to group with -arg
+        String[] args = { "-arg", "-r", TEST_ROLE_NAME_1, "-g", TEST_GROUP_1, "-conf",
+            confPath.getAbsolutePath() };
+        SentryShellKafka.main(args);
+        // test: add role to multiple groups
+        args = new String[] { "-arg", "-r", TEST_ROLE_NAME_1, "-g", TEST_GROUP_2 + "," + TEST_GROUP_3,
+            "-conf",
+            confPath.getAbsolutePath() };
+        SentryShellKafka.main(args);
+        // test: add role to group with --add_role_group
+        args = new String[] { "--add_role_group", "-r", TEST_ROLE_NAME_2, "-g", TEST_GROUP_1,
+            "-conf",
+            confPath.getAbsolutePath() };
+        SentryShellKafka.main(args);
+
+        // validate the result list roles with -lr and -g
+        args = new String[] { "-lr", "-g", TEST_GROUP_1, "-conf", confPath.getAbsolutePath() };
+        SentryShellKafka sentryShell = new SentryShellKafka();
+        Set<String> roleNames = getShellResultWithOSRedirect(sentryShell, args, true);
+        validateRoleNames(roleNames, TEST_ROLE_NAME_1, TEST_ROLE_NAME_2);
+
+        // list roles with --list_role and -g
+        args = new String[] { "--list_role", "-g", TEST_GROUP_2, "-conf",
+            confPath.getAbsolutePath() };
+        sentryShell = new SentryShellKafka();
+        roleNames = getShellResultWithOSRedirect(sentryShell, args, true);
+        validateRoleNames(roleNames, TEST_ROLE_NAME_1);
+
+        args = new String[] { "--list_role", "-g", TEST_GROUP_3, "-conf",
+            confPath.getAbsolutePath() };
+        sentryShell = new SentryShellKafka();
+        roleNames = getShellResultWithOSRedirect(sentryShell, args, true);
+        validateRoleNames(roleNames, TEST_ROLE_NAME_1);
+
+        // test: delete role from group with -drg
+        args = new String[] { "-drg", "-r", TEST_ROLE_NAME_1, "-g", TEST_GROUP_1, "-conf",
+            confPath.getAbsolutePath() };
+        SentryShellKafka.main(args);
+        // test: delete role to multiple groups
+        args = new String[] { "-drg", "-r", TEST_ROLE_NAME_1, "-g", TEST_GROUP_2 + "," + TEST_GROUP_3,
+            "-conf",
+            confPath.getAbsolutePath() };
+        SentryShellKafka.main(args);
+        // test: delete role from group with --delete_role_group
+        args = new String[] { "--delete_role_group", "-r", TEST_ROLE_NAME_2, "-g", TEST_GROUP_1,
+            "-conf", confPath.getAbsolutePath() };
+        SentryShellKafka.main(args);
+
+        // validate the result
+        Set<TSentryRole> roles = client.listRolesByGroupName(requestorName, TEST_GROUP_1, KAFKA);
+        assertEquals("Incorrect number of roles", 0, roles.size());
+        roles = client.listRolesByGroupName(requestorName, TEST_GROUP_2, KAFKA);
+        assertEquals("Incorrect number of roles", 0, roles.size());
+        roles = client.listRolesByGroupName(requestorName, TEST_GROUP_3, KAFKA);
+        assertEquals("Incorrect number of roles", 0, roles.size());
+        // clear the test data
+        client.dropRole(requestorName, TEST_ROLE_NAME_1, KAFKA);
+        client.dropRole(requestorName, TEST_ROLE_NAME_2, KAFKA);
+      }
+    });
+  }
+
+  @Test
+  public void testCaseSensitiveGroupName() throws Exception {
+    runTestAsSubject(new TestOperation() {
+      @Override
+      public void runTestAsSubject() throws Exception {
+
+        // create the role for test
+        client.createRole(requestorName, TEST_ROLE_NAME_1, KAFKA);
+        // add role to a group (lower case)
+        String[] args = {"-arg", "-r", TEST_ROLE_NAME_1, "-g", "group1", "-conf",
+            confPath.getAbsolutePath()};
+        SentryShellKafka.main(args);
+
+        // validate the roles when group name is same case as above
+        args = new String[]{"-lr", "-g", "group1", "-conf", confPath.getAbsolutePath()};
+        SentryShellKafka sentryShell = new SentryShellKafka();
+        Set<String> roleNames = getShellResultWithOSRedirect(sentryShell, args, true);
+        validateRoleNames(roleNames, TEST_ROLE_NAME_1);
+
+        // roles should be empty when group name is different case than above
+        args = new String[]{"-lr", "-g", "GROUP1", "-conf", confPath.getAbsolutePath()};
+        roleNames = getShellResultWithOSRedirect(sentryShell, args, true);
+        validateRoleNames(roleNames);
+      }
+    });
+  }
+
+  public static String grant(boolean shortOption) {
+    return shortOption ? "-gpr" : "--grant_privilege_role";
+  }
+
+  public static String revoke(boolean shortOption) {
+    return shortOption ? "-rpr" : "--revoke_privilege_role";
+  }
+
+  public static String list(boolean shortOption) {
+    return shortOption ? "-lp" : "--list_privilege";
+  }
+
+  private void assertGrantRevokePrivilege(final boolean shortOption) throws Exception {
+    runTestAsSubject(new TestOperation() {
+      @Override
+      public void runTestAsSubject() throws Exception {
+        // create the role for test
+        client.createRole(requestorName, TEST_ROLE_NAME_1, KAFKA);
+        client.createRole(requestorName, TEST_ROLE_NAME_2, KAFKA);
+
+        String [] privs = {
+            "HOST=*->CLUSTER=kafka-cluster->action=read",
+            "HOST=h1->TOPIC=t1->action=write",
+            "HOST=*->CONSUMERGROUP=cg1->action=read",
+            "CLUSTER=kafka-cluster->action=write",
+            "CONSUMERGROUP=cg2->action=write"
+        };
+        for (int i = 0; i < privs.length; ++i) {
+          // test: grant privilege to role
+          String [] args = new String [] { grant(shortOption), "-r", TEST_ROLE_NAME_1, "-p",
+            privs[ i ],
+            "-conf", confPath.getAbsolutePath() };
+          SentryShellKafka.main(args);
+        }
+
+        // test the list privilege
+        String [] args = new String[] { list(shortOption), "-r", TEST_ROLE_NAME_1, "-conf", confPath.getAbsolutePath() };
+        SentryShellKafka sentryShell = new SentryShellKafka();
+        Set<String> privilegeStrs = getShellResultWithOSRedirect(sentryShell, args, true);
+
+        assertEquals("Incorrect number of privileges", privs.length, privilegeStrs.size());
+        for (int i = 0; i < privs.length; ++i) {
+          assertTrue("Expected privilege: " + privs[i] + " in " + Arrays.toString(privilegeStrs.toArray()), privilegeStrs.contains(privs[i].startsWith("HOST=") ? privs[i] : "HOST=*->" + privs[i]));
+        }
+
+        for (int i = 0; i < privs.length; ++i) {
+          args = new String[] { revoke(shortOption), "-r", TEST_ROLE_NAME_1, "-p",
+            privs[ i ], "-conf",
+            confPath.getAbsolutePath() };
+          SentryShellKafka.main(args);
+          Set<TSentryPrivilege> privileges = client.listPrivilegesByRoleName(requestorName,
+            TEST_ROLE_NAME_1, KAFKA, service);
+          assertEquals("Incorrect number of privileges. Received privileges: " + Arrays.toString(privileges.toArray()), privs.length - (i + 1), privileges.size());
+        }
+
+        // clear the test data
+        client.dropRole(requestorName, TEST_ROLE_NAME_1, KAFKA);
+        client.dropRole(requestorName, TEST_ROLE_NAME_2, KAFKA);
+      }
+    });
+  }
+
+
+  @Test
+  public void testGrantRevokePrivilegeWithShortOption() throws Exception {
+    assertGrantRevokePrivilege(true);
+  }
+
+  @Test
+  public void testGrantRevokePrivilegeWithLongOption() throws Exception {
+    assertGrantRevokePrivilege(false);
+  }
+
+
+  @Test
+  public void testNegativeCaseWithInvalidArgument() throws Exception {
+    runTestAsSubject(new TestOperation() {
+      @Override
+      public void runTestAsSubject() throws Exception {
+        client.createRole(requestorName, TEST_ROLE_NAME_1, KAFKA);
+        // test: create duplicate role with -cr
+        String[] args = { "-cr", "-r", TEST_ROLE_NAME_1, "-conf", confPath.getAbsolutePath() };
+        SentryShellKafka sentryShell = new SentryShellKafka();
+        try {
+          sentryShell.executeShell(args);
+          fail("Exception should be thrown for creating duplicate role");
+        } catch (SentryUserException e) {
+          // expected exception
+        } catch (Exception e) {
+          fail ("Unexpected exception received. " + e);
+        }
+
+        // test: drop non-exist role with -dr
+        args = new String[] { "-dr", "-r", TEST_ROLE_NAME_2, "-conf", confPath.getAbsolutePath() };
+        sentryShell = new SentryShellKafka();
+        try {
+          sentryShell.executeShell(args);
+          fail("Exception should be thrown for dropping non-exist role");
+        } catch (SentryUserException e) {
+          // excepted exception
+        } catch (Exception e) {
+          fail ("Unexpected exception received. " + e);
+        }
+
+        // test: add non-exist role to group with -arg
+        args = new String[] { "-arg", "-r", TEST_ROLE_NAME_2, "-g", "testGroup1", "-conf",
+            confPath.getAbsolutePath() };
+        sentryShell = new SentryShellKafka();
+        try {
+          sentryShell.executeShell(args);
+          fail("Exception should be thrown for granting non-exist role to group");
+        } catch (SentryUserException e) {
+          // excepted exception
+        } catch (Exception e) {
+          fail ("Unexpected exception received. " + e);
+        }
+
+        // test: drop group from non-exist role with -drg
+        args = new String[] { "-drg", "-r", TEST_ROLE_NAME_2, "-g", "testGroup1", "-conf",
+            confPath.getAbsolutePath() };
+        sentryShell = new SentryShellKafka();
+        try {
+          sentryShell.executeShell(args);
+          fail("Exception should be thrown for drop group from non-exist role");
+        } catch (SentryUserException e) {
+          // excepted exception
+        } catch (Exception e) {
+          fail ("Unexpected exception received. " + e);
+        }
+
+        // test: grant privilege to role with the error privilege format
+        args = new String[] { "-gpr", "-r", TEST_ROLE_NAME_1, "-p", "serverserver1->action=all",
+            "-conf", confPath.getAbsolutePath() };
+        sentryShell = new SentryShellKafka();
+        try {
+          sentryShell.executeShell(args);
+          fail("Exception should be thrown for the error privilege format, invalid key value.");
+        } catch (IllegalArgumentException e) {
+          // excepted exception
+        } catch (Exception e) {
+          fail ("Unexpected exception received. " + e);
+        }
+
+        // test: grant privilege to role with the error privilege hierarchy
+        args = new String[] { "-gpr", "-r", TEST_ROLE_NAME_1, "-p",
+            "consumergroup=cg1->host=h1->action=create", "-conf",
+            confPath.getAbsolutePath() };
+        sentryShell = new SentryShellKafka();
+        try {
+          sentryShell.executeShell(args);
+          fail("Exception should be thrown for the error privilege format, invalid key value.");
+        } catch (ConfigurationException e) {
+          // expected exception
+        } catch (Exception e) {
+          fail ("Unexpected exception received. " + e);
+        }
+
+        // clear the test data
+        client.dropRole(requestorName, TEST_ROLE_NAME_1, KAFKA);
+      }
+    });
+  }
+
+  @Test
+  public void testNegativeCaseWithoutRequiredArgument() throws Exception {
+    runTestAsSubject(new TestOperation() {
+      @Override
+      public void runTestAsSubject() throws Exception {
+        String strOptionConf = "conf";
+        client.createRole(requestorName, TEST_ROLE_NAME_1, KAFKA);
+        // test: the conf is required argument
+        String[] args = { "-cr", "-r", TEST_ROLE_NAME_1 };
+        SentryShellKafka sentryShell = new SentryShellKafka();
+        validateMissingParameterMsg(sentryShell, args,
+                SentryShellCommon.PREFIX_MESSAGE_MISSING_OPTION + strOptionConf);
+
+        // test: -r is required when create role
+        args = new String[] { "-cr", "-conf", confPath.getAbsolutePath() };
+        sentryShell = new SentryShellKafka();
+        validateMissingParameterMsg(sentryShell, args,
+                SentryShellCommon.PREFIX_MESSAGE_MISSING_OPTION + SentryShellCommon.OPTION_DESC_ROLE_NAME);
+
+        // test: -r is required when drop role
+        args = new String[] { "-dr", "-conf", confPath.getAbsolutePath() };
+        sentryShell = new SentryShellKafka();
+        validateMissingParameterMsg(sentryShell, args,
+                SentryShellCommon.PREFIX_MESSAGE_MISSING_OPTION + SentryShellCommon.OPTION_DESC_ROLE_NAME);
+
+        // test: -r is required when add role to group
+        args = new String[] { "-arg", "-g", "testGroup1", "-conf", confPath.getAbsolutePath() };
+        sentryShell = new SentryShellKafka();
+        validateMissingParameterMsg(sentryShell, args,
+                SentryShellCommon.PREFIX_MESSAGE_MISSING_OPTION + SentryShellCommon.OPTION_DESC_ROLE_NAME);
+
+        // test: -g is required when add role to group
+        args = new String[] { "-arg", "-r", TEST_ROLE_NAME_2, "-conf", confPath.getAbsolutePath() };
+        sentryShell = new SentryShellKafka();
+        validateMissingParameterMsg(sentryShell, args,
+                SentryShellCommon.PREFIX_MESSAGE_MISSING_OPTION + SentryShellCommon.OPTION_DESC_GROUP_NAME);
+
+        // test: -r is required when delete role from group
+        args = new String[] { "-drg", "-g", "testGroup1", "-conf", confPath.getAbsolutePath() };
+        sentryShell = new SentryShellKafka();
+        validateMissingParameterMsg(sentryShell, args,
+                SentryShellCommon.PREFIX_MESSAGE_MISSING_OPTION + SentryShellCommon.OPTION_DESC_ROLE_NAME);
+
+        // test: -g is required when delete role from group
+        args = new String[] { "-drg", "-r", TEST_ROLE_NAME_2, "-conf", confPath.getAbsolutePath() };
+        sentryShell = new SentryShellKafka();
+        validateMissingParameterMsg(sentryShell, args,
+                SentryShellCommon.PREFIX_MESSAGE_MISSING_OPTION + SentryShellCommon.OPTION_DESC_GROUP_NAME);
+
+        // test: -r is required when grant privilege to role
+        args = new String[] { "-gpr", "-p", "server=server1", "-conf", confPath.getAbsolutePath() };
+        sentryShell = new SentryShellKafka();
+        validateMissingParameterMsg(sentryShell, args,
+                SentryShellCommon.PREFIX_MESSAGE_MISSING_OPTION + SentryShellCommon.OPTION_DESC_ROLE_NAME);
+
+        // test: -p is required when grant privilege to role
+        args = new String[] { "-gpr", "-r", TEST_ROLE_NAME_1, "-conf", confPath.getAbsolutePath() };
+        sentryShell = new SentryShellKafka();
+        validateMissingParameterMsg(sentryShell, args,
+                SentryShellCommon.PREFIX_MESSAGE_MISSING_OPTION + SentryShellCommon.OPTION_DESC_PRIVILEGE);
+
+        // test: action is required in privilege
+        args = new String[] { "-gpr", "-r", TEST_ROLE_NAME_1, "-conf", confPath.getAbsolutePath(), "-p", "host=*->topic=t1" };
+        sentryShell = new SentryShellKafka();
+         try {
+          getShellResultWithOSRedirect(sentryShell, args, false);
+          fail("Expected IllegalArgumentException");
+        } catch (ConfigurationException e) {
+           assert(("Kafka privilege must end with a valid action.\n" + KafkaPrivilegeValidator.KafkaPrivilegeHelpMsg).equals(e.getMessage()));
+        } catch (Exception e) {
+           fail ("Unexpected exception received. " + e);
+         }
+
+        // test: -r is required when revoke privilege from role
+        args = new String[] { "-rpr", "-p", "host=h1", "-conf", confPath.getAbsolutePath() };
+        sentryShell = new SentryShellKafka();
+        validateMissingParameterMsg(sentryShell, args,
+                SentryShellCommon.PREFIX_MESSAGE_MISSING_OPTION + SentryShellCommon.OPTION_DESC_ROLE_NAME);
+
+        // test: -p is required when revoke privilege from role
+        args = new String[] { "-rpr", "-r", TEST_ROLE_NAME_1, "-conf", confPath.getAbsolutePath() };
+        sentryShell = new SentryShellKafka();
+        validateMissingParameterMsg(sentryShell, args,
+                SentryShellCommon.PREFIX_MESSAGE_MISSING_OPTION + SentryShellCommon.OPTION_DESC_PRIVILEGE);
+
+        // test: command option is required for shell
+        args = new String[] {"-conf", confPath.getAbsolutePath() };
+        sentryShell = new SentryShellKafka();
+        validateMissingParameterMsgsContains(sentryShell, args,
+                SentryShellCommon.PREFIX_MESSAGE_MISSING_OPTION + "[",
+                "-arg Add role to group",
+                "-cr Create role",
+                "-rpr Revoke privilege from role",
+                "-drg Delete role from group",
+                "-lr List role",
+                "-lp List privilege",
+                "-gpr Grant privilege to role",
+                "-dr Drop role");
+
+        // clear the test data
+        client.dropRole(requestorName, TEST_ROLE_NAME_1, KAFKA);
+      }
+    });
+  }
+
+  // redirect the System.out to ByteArrayOutputStream, then execute the command and parse the result.
+  private Set<String> getShellResultWithOSRedirect(SentryShellKafka sentryShell,
+      String[] args, boolean expectedExecuteResult) throws Exception {
+    PrintStream oldOut = System.out;
+    ByteArrayOutputStream outContent = new ByteArrayOutputStream();
+    System.setOut(new PrintStream(outContent));
+    assertEquals(expectedExecuteResult, sentryShell.executeShell(args));
+    Set<String> resultSet = Sets.newHashSet(outContent.toString().split("\n"));
+    System.setOut(oldOut);
+    return resultSet;
+  }
+
+  private void validateRoleNames(Set<String> roleNames, String ... expectedRoleNames) {
+    if (expectedRoleNames != null && expectedRoleNames.length > 0) {
+      assertEquals("Found: " + roleNames.size() + " roles, expected: " + expectedRoleNames.length,
+          expectedRoleNames.length, roleNames.size());
+      Set<String> lowerCaseRoles = new HashSet<String>();
+      for (String role : roleNames) {
+        lowerCaseRoles.add(role.toLowerCase());
+      }
+
+      for (String expectedRole : expectedRoleNames) {
+        assertTrue("Expected role: " + expectedRole,
+            lowerCaseRoles.contains(expectedRole.toLowerCase()));
+      }
+    }
+  }
+
+  private void validateMissingParameterMsg(SentryShellKafka sentryShell, String[] args,
+      String expectedErrorMsg) throws Exception {
+    Set<String> errorMsgs = getShellResultWithOSRedirect(sentryShell, args, false);
+    assertTrue("Expected error message: " + expectedErrorMsg, errorMsgs.contains(expectedErrorMsg));
+  }
+
+  private void validateMissingParameterMsgsContains(SentryShellKafka sentryShell, String[] args,
+      String ... expectedErrorMsgsContains) throws Exception {
+    Set<String> errorMsgs = getShellResultWithOSRedirect(sentryShell, args, false);
+    boolean foundAllMessages = false;
+    Iterator<String> it = errorMsgs.iterator();
+    while (it.hasNext()) {
+      String errorMessage = it.next();
+      boolean missingExpected = false;
+      for (String expectedContains : expectedErrorMsgsContains) {
+        if (!errorMessage.contains(expectedContains)) {
+          missingExpected = true;
+          break;
+        }
+      }
+      if (!missingExpected) {
+        foundAllMessages = true;
+        break;
+      }
+    }
+    assertTrue(foundAllMessages);
+  }
+}

http://git-wip-us.apache.org/repos/asf/sentry/blob/e72e6eac/sentry-service/sentry-service-server/src/test/java/org/apache/sentry/provider/db/generic/tools/TestSentryShellSolr.java
----------------------------------------------------------------------
diff --git a/sentry-service/sentry-service-server/src/test/java/org/apache/sentry/provider/db/generic/tools/TestSentryShellSolr.java b/sentry-service/sentry-service-server/src/test/java/org/apache/sentry/provider/db/generic/tools/TestSentryShellSolr.java
new file mode 100644
index 0000000..d4e26e8
--- /dev/null
+++ b/sentry-service/sentry-service-server/src/test/java/org/apache/sentry/provider/db/generic/tools/TestSentryShellSolr.java
@@ -0,0 +1,525 @@
+/**
+ * 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.sentry.provider.db.generic.tools;
+
+import com.google.common.io.Files;
+import com.google.common.collect.Sets;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+
+import java.io.ByteArrayOutputStream;
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.PrintStream;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.Set;
+
+import org.apache.commons.io.FileUtils;
+import org.apache.sentry.core.common.exception.SentryUserException;
+import org.apache.sentry.provider.db.generic.service.thrift.SentryGenericServiceIntegrationBase;
+import org.apache.sentry.provider.db.generic.service.thrift.TSentryRole;
+import org.apache.sentry.provider.db.generic.service.thrift.TSentryPrivilege;
+import org.apache.sentry.provider.db.tools.SentryShellCommon;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+
+public class TestSentryShellSolr extends SentryGenericServiceIntegrationBase {
+  private File confDir;
+  private File confPath;
+  private static String TEST_ROLE_NAME_1 = "testRole1";
+  private static String TEST_ROLE_NAME_2 = "testRole2";
+  private String requestorName = "";
+  private String service = "service1";
+
+  @Before
+  public void prepareForTest() throws Exception {
+    confDir = Files.createTempDir();
+    confPath = new File(confDir, "sentry-site.xml");
+    if (confPath.createNewFile()) {
+      FileOutputStream to = new FileOutputStream(confPath);
+      conf.writeXml(to);
+      to.close();
+    }
+    requestorName = clientUgi.getShortUserName();//System.getProperty("user.name", "");
+    Set<String> requestorUserGroupNames = Sets.newHashSet(ADMIN_GROUP);
+    setLocalGroupMapping(requestorName, requestorUserGroupNames);
+    // add ADMIN_USER for the after() in SentryServiceIntegrationBase
+    setLocalGroupMapping(ADMIN_USER, requestorUserGroupNames);
+    writePolicyFile();
+  }
+
+  @After
+  public void clearTestData() throws Exception {
+    FileUtils.deleteQuietly(confDir);
+  }
+
+  @Test
+  public void testCreateDropRole() throws Exception {
+    runTestAsSubject(new TestOperation() {
+      @Override
+      public void runTestAsSubject() throws Exception {
+        // test: create role with -cr
+        String[] args = { "-cr", "-r", TEST_ROLE_NAME_1, "-conf", confPath.getAbsolutePath() };
+        SentryShellSolr.main(args);
+        // test: create role with --create_role
+        args = new String[] { "--create_role", "-r", TEST_ROLE_NAME_2, "-conf",
+            confPath.getAbsolutePath() };
+        SentryShellSolr.main(args);
+
+        // validate the result, list roles with -lr
+        args = new String[] { "-lr", "-conf", confPath.getAbsolutePath() };
+        SentryShellSolr sentryShell = new SentryShellSolr();
+        Set<String> roleNames = getShellResultWithOSRedirect(sentryShell, args, true);
+        validateRoleNames(roleNames, TEST_ROLE_NAME_1, TEST_ROLE_NAME_2);
+
+        // validate the result, list roles with --list_role
+        args = new String[] { "--list_role", "-conf", confPath.getAbsolutePath() };
+        sentryShell = new SentryShellSolr();
+        roleNames = getShellResultWithOSRedirect(sentryShell, args, true);
+        validateRoleNames(roleNames, TEST_ROLE_NAME_1, TEST_ROLE_NAME_2);
+
+        // test: drop role with -dr
+        args = new String[] { "-dr", "-r", TEST_ROLE_NAME_1, "-conf", confPath.getAbsolutePath() };
+        SentryShellSolr.main(args);
+        // test: drop role with --drop_role
+        args = new String[] { "--drop_role", "-r", TEST_ROLE_NAME_2, "-conf",
+            confPath.getAbsolutePath() };
+        SentryShellSolr.main(args);
+
+        // validate the result
+        Set<TSentryRole> roles = client.listAllRoles(requestorName, SOLR);
+        assertEquals("Incorrect number of roles", 0, roles.size());
+      }
+    });
+  }
+
+  @Test
+  public void testAddDeleteRoleForGroup() throws Exception {
+    runTestAsSubject(new TestOperation() {
+      @Override
+      public void runTestAsSubject() throws Exception {
+        // Group names are case sensitive - mixed case names should work
+        String TEST_GROUP_1 = "testGroup1";
+        String TEST_GROUP_2 = "testGroup2";
+        String TEST_GROUP_3 = "testGroup3";
+
+        // create the role for test
+        client.createRole(requestorName, TEST_ROLE_NAME_1, SOLR);
+        client.createRole(requestorName, TEST_ROLE_NAME_2, SOLR);
+        // test: add role to group with -arg
+        String[] args = { "-arg", "-r", TEST_ROLE_NAME_1, "-g", TEST_GROUP_1, "-conf",
+            confPath.getAbsolutePath() };
+        SentryShellSolr.main(args);
+        // test: add role to multiple groups
+        args = new String[] { "-arg", "-r", TEST_ROLE_NAME_1, "-g", TEST_GROUP_2 + "," + TEST_GROUP_3,
+            "-conf",
+            confPath.getAbsolutePath() };
+        SentryShellSolr.main(args);
+        // test: add role to group with --add_role_group
+        args = new String[] { "--add_role_group", "-r", TEST_ROLE_NAME_2, "-g", TEST_GROUP_1,
+            "-conf",
+            confPath.getAbsolutePath() };
+        SentryShellSolr.main(args);
+
+        // validate the result list roles with -lr and -g
+        args = new String[] { "-lr", "-g", TEST_GROUP_1, "-conf", confPath.getAbsolutePath() };
+        SentryShellSolr sentryShell = new SentryShellSolr();
+        Set<String> roleNames = getShellResultWithOSRedirect(sentryShell, args, true);
+        validateRoleNames(roleNames, TEST_ROLE_NAME_1, TEST_ROLE_NAME_2);
+
+        // list roles with --list_role and -g
+        args = new String[] { "--list_role", "-g", TEST_GROUP_2, "-conf",
+            confPath.getAbsolutePath() };
+        sentryShell = new SentryShellSolr();
+        roleNames = getShellResultWithOSRedirect(sentryShell, args, true);
+        validateRoleNames(roleNames, TEST_ROLE_NAME_1);
+
+        args = new String[] { "--list_role", "-g", TEST_GROUP_3, "-conf",
+            confPath.getAbsolutePath() };
+        sentryShell = new SentryShellSolr();
+        roleNames = getShellResultWithOSRedirect(sentryShell, args, true);
+        validateRoleNames(roleNames, TEST_ROLE_NAME_1);
+
+        // test: delete role from group with -drg
+        args = new String[] { "-drg", "-r", TEST_ROLE_NAME_1, "-g", TEST_GROUP_1, "-conf",
+            confPath.getAbsolutePath() };
+        SentryShellSolr.main(args);
+        // test: delete role to multiple groups
+        args = new String[] { "-drg", "-r", TEST_ROLE_NAME_1, "-g", TEST_GROUP_2 + "," + TEST_GROUP_3,
+            "-conf",
+            confPath.getAbsolutePath() };
+        SentryShellSolr.main(args);
+        // test: delete role from group with --delete_role_group
+        args = new String[] { "--delete_role_group", "-r", TEST_ROLE_NAME_2, "-g", TEST_GROUP_1,
+            "-conf", confPath.getAbsolutePath() };
+        SentryShellSolr.main(args);
+
+        // validate the result
+        Set<TSentryRole> roles = client.listRolesByGroupName(requestorName, TEST_GROUP_1, SOLR);
+        assertEquals("Incorrect number of roles", 0, roles.size());
+        roles = client.listRolesByGroupName(requestorName, TEST_GROUP_2, SOLR);
+        assertEquals("Incorrect number of roles", 0, roles.size());
+        roles = client.listRolesByGroupName(requestorName, TEST_GROUP_3, SOLR);
+        assertEquals("Incorrect number of roles", 0, roles.size());
+        // clear the test data
+        client.dropRole(requestorName, TEST_ROLE_NAME_1, SOLR);
+        client.dropRole(requestorName, TEST_ROLE_NAME_2, SOLR);
+      }
+    });
+  }
+
+  @Test
+  public void testCaseSensitiveGroupName() throws Exception {
+    runTestAsSubject(new TestOperation() {
+      @Override
+      public void runTestAsSubject() throws Exception {
+
+        // create the role for test
+        client.createRole(requestorName, TEST_ROLE_NAME_1, SOLR);
+        // add role to a group (lower case)
+        String[] args = { "-arg", "-r", TEST_ROLE_NAME_1, "-g", "group1", "-conf",
+            confPath.getAbsolutePath() };
+        SentryShellSolr.main(args);
+
+        // validate the roles when group name is same case as above
+        args = new String[] { "-lr", "-g", "group1", "-conf", confPath.getAbsolutePath() };
+        SentryShellSolr sentryShell = new SentryShellSolr();
+        Set<String> roleNames = getShellResultWithOSRedirect(sentryShell, args, true);
+        validateRoleNames(roleNames, TEST_ROLE_NAME_1);
+
+        // roles should be empty when group name is different case than above
+        args = new String[] { "-lr", "-g", "GROUP1", "-conf", confPath.getAbsolutePath() };
+        roleNames = getShellResultWithOSRedirect(sentryShell, args, true);
+        validateRoleNames(roleNames);
+      }
+      });
+    }
+
+  public static String grant(boolean shortOption) {
+    return shortOption ? "-gpr" : "--grant_privilege_role";
+  }
+
+  public static String revoke(boolean shortOption) {
+    return shortOption ? "-rpr" : "--revoke_privilege_role";
+  }
+
+  public static String list(boolean shortOption) {
+    return shortOption ? "-lp" : "--list_privilege";
+  }
+
+  private void assertGrantRevokePrivilege(final boolean shortOption) throws Exception {
+    runTestAsSubject(new TestOperation() {
+      @Override
+      public void runTestAsSubject() throws Exception {
+        // create the role for test
+        client.createRole(requestorName, TEST_ROLE_NAME_1, SOLR);
+        client.createRole(requestorName, TEST_ROLE_NAME_2, SOLR);
+
+        String [] privs = {
+          "Collection=*->action=*",
+          "Collection=collection2->action=update",
+          "Collection=collection3->action=query",
+        };
+        for (int i = 0; i < privs.length; ++i) {
+          // test: grant privilege to role
+          String [] args = new String [] { grant(shortOption), "-r", TEST_ROLE_NAME_1, "-p",
+            privs[ i ],
+            "-conf", confPath.getAbsolutePath() };
+          SentryShellSolr.main(args);
+        }
+
+        // test the list privilege
+        String [] args = new String[] { list(shortOption), "-r", TEST_ROLE_NAME_1, "-conf", confPath.getAbsolutePath() };
+        SentryShellSolr sentryShell = new SentryShellSolr();
+        Set<String> privilegeStrs = getShellResultWithOSRedirect(sentryShell, args, true);
+        assertEquals("Incorrect number of privileges", privs.length, privilegeStrs.size());
+        for (int i = 0; i < privs.length; ++i) {
+          assertTrue("Expected privilege: " + privs[ i ], privilegeStrs.contains(privs[ i ]));
+        }
+
+        for (int i = 0; i < privs.length; ++i) {
+          args = new String[] { revoke(shortOption), "-r", TEST_ROLE_NAME_1, "-p",
+            privs[ i ], "-conf",
+            confPath.getAbsolutePath() };
+          SentryShellSolr.main(args);
+          Set<TSentryPrivilege> privileges = client.listPrivilegesByRoleName(requestorName,
+            TEST_ROLE_NAME_1, SOLR, service);
+          assertEquals("Incorrect number of privileges", privs.length - (i + 1), privileges.size());
+        }
+
+        // clear the test data
+        client.dropRole(requestorName, TEST_ROLE_NAME_1, SOLR);
+        client.dropRole(requestorName, TEST_ROLE_NAME_2, SOLR);
+      }
+    });
+  }
+
+
+  @Test
+  public void testGrantRevokePrivilegeWithShortOption() throws Exception {
+    assertGrantRevokePrivilege(true);
+  }
+
+  @Test
+  public void testGrantRevokePrivilegeWithLongOption() throws Exception {
+    assertGrantRevokePrivilege(false);
+  }
+
+
+  @Test
+  public void testNegativeCaseWithInvalidArgument() throws Exception {
+    runTestAsSubject(new TestOperation() {
+      @Override
+      public void runTestAsSubject() throws Exception {
+        client.createRole(requestorName, TEST_ROLE_NAME_1, SOLR);
+        // test: create duplicate role with -cr
+        String[] args = { "-cr", "-r", TEST_ROLE_NAME_1, "-conf", confPath.getAbsolutePath() };
+        SentryShellSolr sentryShell = new SentryShellSolr();
+        try {
+          sentryShell.executeShell(args);
+          fail("Exception should be thrown for creating duplicate role");
+        } catch (SentryUserException e) {
+          // expected exception
+        }
+
+        // test: drop non-exist role with -dr
+        args = new String[] { "-dr", "-r", TEST_ROLE_NAME_2, "-conf", confPath.getAbsolutePath() };
+        sentryShell = new SentryShellSolr();
+        try {
+          sentryShell.executeShell(args);
+          fail("Exception should be thrown for dropping non-exist role");
+        } catch (SentryUserException e) {
+          // excepted exception
+        }
+
+        // test: add non-exist role to group with -arg
+        args = new String[] { "-arg", "-r", TEST_ROLE_NAME_2, "-g", "testGroup1", "-conf",
+            confPath.getAbsolutePath() };
+        sentryShell = new SentryShellSolr();
+        try {
+          sentryShell.executeShell(args);
+          fail("Exception should be thrown for granting non-exist role to group");
+        } catch (SentryUserException e) {
+          // excepted exception
+        }
+
+        // test: drop group from non-exist role with -drg
+        args = new String[] { "-drg", "-r", TEST_ROLE_NAME_2, "-g", "testGroup1", "-conf",
+            confPath.getAbsolutePath() };
+        sentryShell = new SentryShellSolr();
+        try {
+          sentryShell.executeShell(args);
+          fail("Exception should be thrown for drop group from non-exist role");
+        } catch (SentryUserException e) {
+          // excepted exception
+        }
+
+        // test: grant privilege to role with the error privilege format
+        args = new String[] { "-gpr", "-r", TEST_ROLE_NAME_1, "-p", "serverserver1->action=*",
+            "-conf", confPath.getAbsolutePath() };
+        sentryShell = new SentryShellSolr();
+        try {
+          sentryShell.executeShell(args);
+          fail("Exception should be thrown for the error privilege format, invalid key value.");
+        } catch (IllegalArgumentException e) {
+          // excepted exception
+        }
+
+        // test: grant privilege to role with the error privilege hierarchy
+        args = new String[] { "-gpr", "-r", TEST_ROLE_NAME_1, "-p",
+            "server=server1->table=tbl1->column=col2->action=insert", "-conf",
+            confPath.getAbsolutePath() };
+        sentryShell = new SentryShellSolr();
+        try {
+          sentryShell.executeShell(args);
+          fail("Exception should be thrown for the error privilege format, invalid key value.");
+        } catch (IllegalArgumentException e) {
+          // expected exception
+        }
+
+        // clear the test data
+        client.dropRole(requestorName, TEST_ROLE_NAME_1, SOLR);
+      }
+    });
+  }
+
+  @Test
+  public void testNegativeCaseWithoutRequiredArgument() throws Exception {
+    runTestAsSubject(new TestOperation() {
+      @Override
+      public void runTestAsSubject() throws Exception {
+        String strOptionConf = "conf";
+        client.createRole(requestorName, TEST_ROLE_NAME_1, SOLR);
+        // test: the conf is required argument
+        String[] args = { "-cr", "-r", TEST_ROLE_NAME_1 };
+        SentryShellSolr sentryShell = new SentryShellSolr();
+        validateMissingParameterMsg(sentryShell, args,
+                SentryShellCommon.PREFIX_MESSAGE_MISSING_OPTION + strOptionConf);
+
+        // test: -r is required when create role
+        args = new String[] { "-cr", "-conf", confPath.getAbsolutePath() };
+        sentryShell = new SentryShellSolr();
+        validateMissingParameterMsg(sentryShell, args,
+                SentryShellCommon.PREFIX_MESSAGE_MISSING_OPTION + SentryShellCommon.OPTION_DESC_ROLE_NAME);
+
+        // test: -r is required when drop role
+        args = new String[] { "-dr", "-conf", confPath.getAbsolutePath() };
+        sentryShell = new SentryShellSolr();
+        validateMissingParameterMsg(sentryShell, args,
+                SentryShellCommon.PREFIX_MESSAGE_MISSING_OPTION + SentryShellCommon.OPTION_DESC_ROLE_NAME);
+
+        // test: -r is required when add role to group
+        args = new String[] { "-arg", "-g", "testGroup1", "-conf", confPath.getAbsolutePath() };
+        sentryShell = new SentryShellSolr();
+        validateMissingParameterMsg(sentryShell, args,
+                SentryShellCommon.PREFIX_MESSAGE_MISSING_OPTION + SentryShellCommon.OPTION_DESC_ROLE_NAME);
+
+        // test: -g is required when add role to group
+        args = new String[] { "-arg", "-r", TEST_ROLE_NAME_2, "-conf", confPath.getAbsolutePath() };
+        sentryShell = new SentryShellSolr();
+        validateMissingParameterMsg(sentryShell, args,
+                SentryShellCommon.PREFIX_MESSAGE_MISSING_OPTION + SentryShellCommon.OPTION_DESC_GROUP_NAME);
+
+        // test: -r is required when delete role from group
+        args = new String[] { "-drg", "-g", "testGroup1", "-conf", confPath.getAbsolutePath() };
+        sentryShell = new SentryShellSolr();
+        validateMissingParameterMsg(sentryShell, args,
+                SentryShellCommon.PREFIX_MESSAGE_MISSING_OPTION + SentryShellCommon.OPTION_DESC_ROLE_NAME);
+
+        // test: -g is required when delete role from group
+        args = new String[] { "-drg", "-r", TEST_ROLE_NAME_2, "-conf", confPath.getAbsolutePath() };
+        sentryShell = new SentryShellSolr();
+        validateMissingParameterMsg(sentryShell, args,
+                SentryShellCommon.PREFIX_MESSAGE_MISSING_OPTION + SentryShellCommon.OPTION_DESC_GROUP_NAME);
+
+        // test: -r is required when grant privilege to role
+        args = new String[] { "-gpr", "-p", "server=server1", "-conf", confPath.getAbsolutePath() };
+        sentryShell = new SentryShellSolr();
+        validateMissingParameterMsg(sentryShell, args,
+                SentryShellCommon.PREFIX_MESSAGE_MISSING_OPTION + SentryShellCommon.OPTION_DESC_ROLE_NAME);
+
+        // test: -p is required when grant privilege to role
+        args = new String[] { "-gpr", "-r", TEST_ROLE_NAME_1, "-conf", confPath.getAbsolutePath() };
+        sentryShell = new SentryShellSolr();
+        validateMissingParameterMsg(sentryShell, args,
+                SentryShellCommon.PREFIX_MESSAGE_MISSING_OPTION + SentryShellCommon.OPTION_DESC_PRIVILEGE);
+
+        // test: action is required in privilege
+        args = new String[] { "-gpr", "-r", TEST_ROLE_NAME_1, "-conf", confPath.getAbsolutePath(), "-p", "collection=collection1" };
+        sentryShell = new SentryShellSolr();
+         try {
+          getShellResultWithOSRedirect(sentryShell, args, false);
+          fail("Expected IllegalArgumentException");
+        } catch (IllegalArgumentException e) {
+          assert("Privilege is invalid: action required but not specified.".equals(e.getMessage()));
+        }
+
+        // test: -r is required when revoke privilege from role
+        args = new String[] { "-rpr", "-p", "server=server1", "-conf", confPath.getAbsolutePath() };
+        sentryShell = new SentryShellSolr();
+        validateMissingParameterMsg(sentryShell, args,
+                SentryShellCommon.PREFIX_MESSAGE_MISSING_OPTION + SentryShellCommon.OPTION_DESC_ROLE_NAME);
+
+        // test: -p is required when revoke privilege from role
+        args = new String[] { "-rpr", "-r", TEST_ROLE_NAME_1, "-conf", confPath.getAbsolutePath() };
+        sentryShell = new SentryShellSolr();
+        validateMissingParameterMsg(sentryShell, args,
+                SentryShellCommon.PREFIX_MESSAGE_MISSING_OPTION + SentryShellCommon.OPTION_DESC_PRIVILEGE);
+
+        // test: command option is required for shell
+        args = new String[] {"-conf", confPath.getAbsolutePath() };
+        sentryShell = new SentryShellSolr();
+        validateMissingParameterMsgsContains(sentryShell, args,
+                SentryShellCommon.PREFIX_MESSAGE_MISSING_OPTION + "[",
+                "-arg Add role to group",
+                "-cr Create role",
+                "-rpr Revoke privilege from role",
+                "-drg Delete role from group",
+                "-lr List role",
+                "-lp List privilege",
+                "-gpr Grant privilege to role",
+                "-dr Drop role");
+
+        // clear the test data
+        client.dropRole(requestorName, TEST_ROLE_NAME_1, SOLR);
+      }
+    });
+  }
+
+  // redirect the System.out to ByteArrayOutputStream, then execute the command and parse the result.
+  private Set<String> getShellResultWithOSRedirect(SentryShellSolr sentryShell,
+      String[] args, boolean expectedExecuteResult) throws Exception {
+    PrintStream oldOut = System.out;
+    ByteArrayOutputStream outContent = new ByteArrayOutputStream();
+    System.setOut(new PrintStream(outContent));
+    assertEquals(expectedExecuteResult, sentryShell.executeShell(args));
+    Set<String> resultSet = Sets.newHashSet(outContent.toString().split("\n"));
+    System.setOut(oldOut);
+    return resultSet;
+  }
+
+  private void validateRoleNames(Set<String> roleNames, String ... expectedRoleNames) {
+    if (expectedRoleNames != null && expectedRoleNames.length > 0) {
+      assertEquals("Found: " + roleNames.size() + " roles, expected: " + expectedRoleNames.length,
+          expectedRoleNames.length, roleNames.size());
+      Set<String> lowerCaseRoles = new HashSet<String>();
+      for (String role : roleNames) {
+        lowerCaseRoles.add(role.toLowerCase());
+      }
+
+      for (String expectedRole : expectedRoleNames) {
+        assertTrue("Expected role: " + expectedRole,
+            lowerCaseRoles.contains(expectedRole.toLowerCase()));
+      }
+    }
+  }
+
+  private void validateMissingParameterMsg(SentryShellSolr sentryShell, String[] args,
+      String expectedErrorMsg) throws Exception {
+    Set<String> errorMsgs = getShellResultWithOSRedirect(sentryShell, args, false);
+    assertTrue("Expected error message: " + expectedErrorMsg, errorMsgs.contains(expectedErrorMsg));
+  }
+
+  private void validateMissingParameterMsgsContains(SentryShellSolr sentryShell, String[] args,
+      String ... expectedErrorMsgsContains) throws Exception {
+    Set<String> errorMsgs = getShellResultWithOSRedirect(sentryShell, args, false);
+    boolean foundAllMessages = false;
+    Iterator<String> it = errorMsgs.iterator();
+    while (it.hasNext()) {
+      String errorMessage = it.next();
+      boolean missingExpected = false;
+      for (String expectedContains : expectedErrorMsgsContains) {
+        if (!errorMessage.contains(expectedContains)) {
+          missingExpected = true;
+          break;
+        }
+      }
+      if (!missingExpected) {
+        foundAllMessages = true;
+        break;
+      }
+    }
+    assertTrue(foundAllMessages);
+  }
+}

http://git-wip-us.apache.org/repos/asf/sentry/blob/e72e6eac/sentry-service/sentry-service-server/src/test/java/org/apache/sentry/provider/db/log/appender/TestRollingFileWithoutDeleteAppender.java
----------------------------------------------------------------------
diff --git a/sentry-service/sentry-service-server/src/test/java/org/apache/sentry/provider/db/log/appender/TestRollingFileWithoutDeleteAppender.java b/sentry-service/sentry-service-server/src/test/java/org/apache/sentry/provider/db/log/appender/TestRollingFileWithoutDeleteAppender.java
new file mode 100644
index 0000000..50785fd
--- /dev/null
+++ b/sentry-service/sentry-service-server/src/test/java/org/apache/sentry/provider/db/log/appender/TestRollingFileWithoutDeleteAppender.java
@@ -0,0 +1,103 @@
+/**
+ * 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.sentry.provider.db.log.appender;
+
+import java.io.File;
+
+import org.apache.commons.io.FileUtils;
+import org.apache.log4j.Logger;
+import org.apache.log4j.PatternLayout;
+import org.junit.After;
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Test;
+
+import com.google.common.io.Files;
+
+public class TestRollingFileWithoutDeleteAppender {
+  private Logger sentryLogger = Logger.getRootLogger();
+  private File dataDir;
+
+  @Before
+  public void init() {
+    dataDir = Files.createTempDir();
+  }
+
+  @Test
+  public void testRollOver() throws Throwable {
+    if (dataDir == null) {
+      Assert.fail("Excepted temp folder for audit log is created.");
+    }
+    RollingFileWithoutDeleteAppender appender = new RollingFileWithoutDeleteAppender(
+        new PatternLayout("%m%n"), dataDir.getPath() + "/auditLog.log");
+    appender.setMaximumFileSize(100);
+    sentryLogger.addAppender(appender);
+    // Write exactly 10 bytes with each log
+    for (int i = 0; i < 99; i++) {
+      if (i < 10) {
+        sentryLogger.debug("Hello---" + i);
+      } else if (i < 100) {
+        sentryLogger.debug("Hello--" + i);
+      }
+    }
+
+    if (dataDir != null) {
+      File[] files = dataDir.listFiles();
+      if (files != null) {
+        Assert.assertEquals(files.length, 10);
+      } else {
+        Assert.fail("Excepted 10 log files.");
+      }
+    } else {
+      Assert.fail("Excepted 10 log files.");
+    }
+
+  }
+
+  /***
+   * Generate log enough to cause a single rollover. Verify the file name format
+   * @throws Throwable
+   */
+  @Test
+  public void testFileNamePattern() throws Throwable {
+    if (dataDir == null) {
+      Assert.fail("Excepted temp folder for audit log is created.");
+    }
+    RollingFileWithoutDeleteAppender appender = new RollingFileWithoutDeleteAppender(
+        new PatternLayout("%m%n"), dataDir.getPath() + "/auditLog.log");
+    appender.setMaximumFileSize(10);
+    sentryLogger.addAppender(appender);
+    sentryLogger.debug("123456789012345");
+    File[] files = dataDir.listFiles();
+    if (files != null) {
+      Assert.assertEquals(files.length, 2);
+      Assert.assertTrue(files[0].getName().contains("auditLog.log."));
+      Assert.assertTrue(files[1].getName().contains("auditLog.log."));
+    } else {
+      Assert.fail("Excepted 2 log files.");
+    }
+  }
+
+  @After
+  public void destroy() {
+    if (dataDir != null) {
+      FileUtils.deleteQuietly(dataDir);
+    }
+  }
+}

http://git-wip-us.apache.org/repos/asf/sentry/blob/e72e6eac/sentry-service/sentry-service-server/src/test/java/org/apache/sentry/provider/db/log/entity/TestDbAuditMetadataLogEntity.java
----------------------------------------------------------------------
diff --git a/sentry-service/sentry-service-server/src/test/java/org/apache/sentry/provider/db/log/entity/TestDbAuditMetadataLogEntity.java b/sentry-service/sentry-service-server/src/test/java/org/apache/sentry/provider/db/log/entity/TestDbAuditMetadataLogEntity.java
new file mode 100644
index 0000000..3d15b4f
--- /dev/null
+++ b/sentry-service/sentry-service-server/src/test/java/org/apache/sentry/provider/db/log/entity/TestDbAuditMetadataLogEntity.java
@@ -0,0 +1,67 @@
+/**
+ * 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.sentry.provider.db.log.entity;
+
+import org.apache.sentry.provider.db.log.util.Constants;
+import org.codehaus.jackson.JsonNode;
+import org.codehaus.jackson.node.ContainerNode;
+import org.junit.Assert;
+import org.junit.Test;
+
+public class TestDbAuditMetadataLogEntity {
+
+  @Test
+  public void testToJsonFormatLog() throws Throwable {
+    DBAuditMetadataLogEntity amle = new DBAuditMetadataLogEntity("serviceName", "userName",
+        "impersonator", "ipAddress", "operation", "eventTime", "operationText", "allowed",
+        "objectType", "component", "databaseName", "tableName", "columnName", "resourcePath");
+    String jsonAuditLog = amle.toJsonFormatLog();
+    ContainerNode rootNode = AuditMetadataLogEntity.parse(jsonAuditLog);
+    assertEntryEquals(rootNode, Constants.LOG_FIELD_SERVICE_NAME, "serviceName");
+    assertEntryEquals(rootNode, Constants.LOG_FIELD_USER_NAME, "userName");
+    assertEntryEquals(rootNode, Constants.LOG_FIELD_IMPERSONATOR,
+        "impersonator");
+    assertEntryEquals(rootNode, Constants.LOG_FIELD_IP_ADDRESS, "ipAddress");
+    assertEntryEquals(rootNode, Constants.LOG_FIELD_OPERATION, "operation");
+    assertEntryEquals(rootNode, Constants.LOG_FIELD_EVENT_TIME, "eventTime");
+    assertEntryEquals(rootNode, Constants.LOG_FIELD_OPERATION_TEXT,
+        "operationText");
+    assertEntryEquals(rootNode, Constants.LOG_FIELD_ALLOWED, "allowed");
+    assertEntryEquals(rootNode, Constants.LOG_FIELD_DATABASE_NAME,
+        "databaseName");
+    assertEntryEquals(rootNode, Constants.LOG_FIELD_TABLE_NAME, "tableName");
+    assertEntryEquals(rootNode, Constants.LOG_FIELD_COLUMN_NAME, "columnName");
+    assertEntryEquals(rootNode, Constants.LOG_FIELD_RESOURCE_PATH,
+        "resourcePath");
+    assertEntryEquals(rootNode, Constants.LOG_FIELD_OBJECT_TYPE, "objectType");
+  }
+
+  void assertEntryEquals(ContainerNode rootNode, String key, String value) {
+    JsonNode node = assertNodeContains(rootNode, key);
+    Assert.assertEquals(value, node.getTextValue());
+  }
+
+  private JsonNode assertNodeContains(ContainerNode rootNode, String key) {
+    JsonNode node = rootNode.get(key);
+    if (node == null) {
+      Assert.fail("No entry of name \"" + key + "\" found in " + rootNode.toString());
+    }
+    return node;
+  }
+}

http://git-wip-us.apache.org/repos/asf/sentry/blob/e72e6eac/sentry-service/sentry-service-server/src/test/java/org/apache/sentry/provider/db/log/entity/TestGMAuditMetadataLogEntity.java
----------------------------------------------------------------------
diff --git a/sentry-service/sentry-service-server/src/test/java/org/apache/sentry/provider/db/log/entity/TestGMAuditMetadataLogEntity.java b/sentry-service/sentry-service-server/src/test/java/org/apache/sentry/provider/db/log/entity/TestGMAuditMetadataLogEntity.java
new file mode 100644
index 0000000..62b46f6
--- /dev/null
+++ b/sentry-service/sentry-service-server/src/test/java/org/apache/sentry/provider/db/log/entity/TestGMAuditMetadataLogEntity.java
@@ -0,0 +1,72 @@
+/**
+ * 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.sentry.provider.db.log.entity;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import org.apache.sentry.provider.db.log.util.Constants;
+import org.codehaus.jackson.JsonNode;
+import org.codehaus.jackson.node.ContainerNode;
+import org.junit.Assert;
+import org.junit.Test;
+
+public class TestGMAuditMetadataLogEntity {
+  @Test
+  public void testToJsonFormatLog() throws Throwable {
+
+    Map<String, String> privilegesMap = new HashMap<String, String>();
+    privilegesMap.put("resourceType1", "resourceName1");
+    privilegesMap.put("resourceType2", "resourceName2");
+    privilegesMap.put("resourceType3", "resourceName3");
+    privilegesMap.put("resourceType4", "resourceName4");
+    GMAuditMetadataLogEntity gmamle = new GMAuditMetadataLogEntity("serviceName", "userName",
+        "impersonator", "ipAddress", "operation", "eventTime", "operationText", "allowed",
+        "objectType", "component", privilegesMap);
+    String jsonAuditLog = gmamle.toJsonFormatLog();
+    ContainerNode rootNode = AuditMetadataLogEntity.parse(jsonAuditLog);
+    assertEntryEquals(rootNode, Constants.LOG_FIELD_SERVICE_NAME, "serviceName");
+    assertEntryEquals(rootNode, Constants.LOG_FIELD_USER_NAME, "userName");
+    assertEntryEquals(rootNode, Constants.LOG_FIELD_IMPERSONATOR, "impersonator");
+    assertEntryEquals(rootNode, Constants.LOG_FIELD_IP_ADDRESS, "ipAddress");
+    assertEntryEquals(rootNode, Constants.LOG_FIELD_OPERATION, "operation");
+    assertEntryEquals(rootNode, Constants.LOG_FIELD_EVENT_TIME, "eventTime");
+    assertEntryEquals(rootNode, Constants.LOG_FIELD_OPERATION_TEXT, "operationText");
+    assertEntryEquals(rootNode, Constants.LOG_FIELD_ALLOWED, "allowed");
+    assertEntryEquals(rootNode, Constants.LOG_FIELD_OBJECT_TYPE, "objectType");
+    assertEntryEquals(rootNode, Constants.LOG_FIELD_COMPONENT, "component");
+    assertEntryEquals(rootNode, "resourceType1", "resourceName1");
+    assertEntryEquals(rootNode, "resourceType2", "resourceName2");
+    assertEntryEquals(rootNode, "resourceType3", "resourceName3");
+    assertEntryEquals(rootNode, "resourceType4", "resourceName4");
+  }
+
+  void assertEntryEquals(ContainerNode rootNode, String key, String value) {
+    JsonNode node = assertNodeContains(rootNode, key);
+    Assert.assertEquals(value, node.getTextValue());
+  }
+
+  private JsonNode assertNodeContains(ContainerNode rootNode, String key) {
+    JsonNode node = rootNode.get(key);
+    if (node == null) {
+      Assert.fail("No entry of name \"" + key + "\" found in " + rootNode.toString());
+    }
+    return node;
+  }
+}

http://git-wip-us.apache.org/repos/asf/sentry/blob/e72e6eac/sentry-service/sentry-service-server/src/test/java/org/apache/sentry/provider/db/log/entity/TestJsonLogEntityFactory.java
----------------------------------------------------------------------
diff --git a/sentry-service/sentry-service-server/src/test/java/org/apache/sentry/provider/db/log/entity/TestJsonLogEntityFactory.java b/sentry-service/sentry-service-server/src/test/java/org/apache/sentry/provider/db/log/entity/TestJsonLogEntityFactory.java
new file mode 100644
index 0000000..bf206ea
--- /dev/null
+++ b/sentry-service/sentry-service-server/src/test/java/org/apache/sentry/provider/db/log/entity/TestJsonLogEntityFactory.java
@@ -0,0 +1,272 @@
+/**
+ * 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.sentry.provider.db.log.entity;
+
+import static org.junit.Assert.assertEquals;
+
+import java.util.LinkedHashSet;
+import java.util.Set;
+
+import org.apache.hadoop.conf.Configuration;
+import org.apache.sentry.core.model.db.AccessConstants;
+import org.apache.sentry.provider.db.log.util.Constants;
+import org.apache.sentry.provider.db.service.thrift.TAlterSentryRoleAddGroupsRequest;
+import org.apache.sentry.provider.db.service.thrift.TAlterSentryRoleAddGroupsResponse;
+import org.apache.sentry.provider.db.service.thrift.TAlterSentryRoleDeleteGroupsRequest;
+import org.apache.sentry.provider.db.service.thrift.TAlterSentryRoleDeleteGroupsResponse;
+import org.apache.sentry.provider.db.service.thrift.TAlterSentryRoleGrantPrivilegeRequest;
+import org.apache.sentry.provider.db.service.thrift.TAlterSentryRoleGrantPrivilegeResponse;
+import org.apache.sentry.provider.db.service.thrift.TAlterSentryRoleRevokePrivilegeRequest;
+import org.apache.sentry.provider.db.service.thrift.TAlterSentryRoleRevokePrivilegeResponse;
+import org.apache.sentry.provider.db.service.thrift.TCreateSentryRoleRequest;
+import org.apache.sentry.provider.db.service.thrift.TCreateSentryRoleResponse;
+import org.apache.sentry.provider.db.service.thrift.TDropSentryRoleRequest;
+import org.apache.sentry.provider.db.service.thrift.TDropSentryRoleResponse;
+import org.apache.sentry.provider.db.service.thrift.TSentryGroup;
+import org.apache.sentry.provider.db.service.thrift.TSentryPrivilege;
+import org.apache.sentry.provider.db.service.thrift.ThriftUtil;
+import org.apache.sentry.service.thrift.ServiceConstants.PrivilegeScope;
+import org.apache.sentry.service.thrift.ServiceConstants.ServerConfig;
+import org.apache.sentry.service.thrift.Status;
+import org.junit.BeforeClass;
+import org.junit.Test;
+
+import com.google.common.collect.Sets;
+
+public class TestJsonLogEntityFactory {
+
+  private static Configuration conf;
+
+  private static String TEST_IP = "localhost/127.0.0.1";
+  private static String TEST_IMPERSONATOR = "impersonator";
+  private static String TEST_ROLE_NAME = "testRole";
+  private static String TEST_USER_NAME = "requestUser";
+  private static String TEST_DATABASE_NAME = "testDB";
+  private static String TEST_TABLE_NAME = "testTable";
+  private static String TEST_GROUP = "testGroup";
+
+  @BeforeClass
+  public static void init() {
+    conf = new Configuration();
+    conf.set(ServerConfig.SENTRY_SERVICE_NAME,
+        ServerConfig.SENTRY_SERVICE_NAME_DEFAULT);
+    ThriftUtil.setIpAddress(TEST_IP);
+    ThriftUtil.setImpersonator(TEST_IMPERSONATOR);
+  }
+
+  @Test
+  public void testCreateRole() {
+    TCreateSentryRoleRequest request = new TCreateSentryRoleRequest();
+    TCreateSentryRoleResponse response = new TCreateSentryRoleResponse();
+    request.setRequestorUserName(TEST_USER_NAME);
+    request.setRoleName(TEST_ROLE_NAME);
+    response.setStatus(Status.OK());
+    DBAuditMetadataLogEntity amle = (DBAuditMetadataLogEntity) JsonLogEntityFactory
+        .getInstance().createJsonLogEntity(request, response, conf);
+    assertCommon(amle, Constants.TRUE, Constants.OPERATION_CREATE_ROLE,
+        "CREATE ROLE testRole", null, null, null, Constants.OBJECT_TYPE_ROLE);
+
+    response.setStatus(Status.InvalidInput("", null));
+    amle = (DBAuditMetadataLogEntity) JsonLogEntityFactory.getInstance()
+        .createJsonLogEntity(request, response, conf);
+    assertCommon(amle, Constants.FALSE, Constants.OPERATION_CREATE_ROLE,
+        "CREATE ROLE testRole", null, null, null, Constants.OBJECT_TYPE_ROLE);
+  }
+
+  @Test
+  public void testDropRole() {
+    TDropSentryRoleRequest request = new TDropSentryRoleRequest();
+    TDropSentryRoleResponse response = new TDropSentryRoleResponse();
+    request.setRequestorUserName(TEST_USER_NAME);
+    request.setRoleName(TEST_ROLE_NAME);
+    response.setStatus(Status.OK());
+    DBAuditMetadataLogEntity amle = (DBAuditMetadataLogEntity) JsonLogEntityFactory
+        .getInstance().createJsonLogEntity(request, response, conf);
+    assertCommon(amle, Constants.TRUE, Constants.OPERATION_DROP_ROLE,
+        "DROP ROLE testRole", null, null, null, Constants.OBJECT_TYPE_ROLE);
+
+    response.setStatus(Status.InvalidInput("", null));
+    amle = (DBAuditMetadataLogEntity) JsonLogEntityFactory.getInstance()
+        .createJsonLogEntity(request, response, conf);
+    assertCommon(amle, Constants.FALSE, Constants.OPERATION_DROP_ROLE,
+        "DROP ROLE testRole", null, null, null, Constants.OBJECT_TYPE_ROLE);
+  }
+
+  @Test
+  public void testGrantRole() {
+    TAlterSentryRoleGrantPrivilegeRequest request = new TAlterSentryRoleGrantPrivilegeRequest();
+    request.setRequestorUserName(TEST_USER_NAME);
+    request.setRoleName(TEST_ROLE_NAME);
+
+    TAlterSentryRoleGrantPrivilegeResponse response = new TAlterSentryRoleGrantPrivilegeResponse();
+
+    TSentryPrivilege privilege = getPrivilege(AccessConstants.ALL,
+        PrivilegeScope.DATABASE.name(), TEST_DATABASE_NAME, null, null, null);
+    Set<TSentryPrivilege> privileges = Sets.newHashSet();
+    privileges.add(privilege);
+    request.setPrivileges(privileges);
+    response.setStatus(Status.OK());
+    DBAuditMetadataLogEntity amle = new DBAuditMetadataLogEntity();
+    Set<JsonLogEntity> amles =  JsonLogEntityFactory
+        .getInstance().createJsonLogEntitys(request, response, conf);
+    assertEquals(amles.size(), 1);
+    amle = (DBAuditMetadataLogEntity) amles.iterator().next();
+
+    assertCommon(amle, Constants.TRUE, Constants.OPERATION_GRANT_PRIVILEGE,
+        "GRANT ALL ON DATABASE testDB TO ROLE testRole", TEST_DATABASE_NAME,
+        null, null, Constants.OBJECT_TYPE_PRINCIPAL);
+
+    privilege = getPrivilege(AccessConstants.ALL, PrivilegeScope.TABLE.name(),
+        null, TEST_TABLE_NAME, null, null);
+    privileges = Sets.newHashSet();
+    privileges.add(privilege);
+    request.setPrivileges(privileges);
+    response.setStatus(Status.InvalidInput("", null));
+    amles =  JsonLogEntityFactory.getInstance()
+        .createJsonLogEntitys(request, response, conf);
+    assertEquals(amles.size(), 1);
+    amle = (DBAuditMetadataLogEntity) amles.iterator().next();
+
+    assertCommon(amle, Constants.FALSE, Constants.OPERATION_GRANT_PRIVILEGE,
+        "GRANT ALL ON TABLE testTable TO ROLE testRole", null, TEST_TABLE_NAME,
+        null, Constants.OBJECT_TYPE_PRINCIPAL);
+  }
+
+  @Test
+  public void testRevokeRole() {
+    TAlterSentryRoleRevokePrivilegeRequest request = new TAlterSentryRoleRevokePrivilegeRequest();
+    TAlterSentryRoleRevokePrivilegeResponse response = new TAlterSentryRoleRevokePrivilegeResponse();
+    request.setRequestorUserName(TEST_USER_NAME);
+    request.setRoleName(TEST_ROLE_NAME);
+
+    TSentryPrivilege privilege = getPrivilege(AccessConstants.ALL,
+        PrivilegeScope.DATABASE.name(), TEST_DATABASE_NAME, null, null, null);
+    Set<TSentryPrivilege> privileges = Sets.newHashSet();
+    privileges.add(privilege);
+    request.setPrivileges(privileges);
+    response.setStatus(Status.OK());
+    DBAuditMetadataLogEntity amle = new DBAuditMetadataLogEntity();
+    Set<JsonLogEntity> amles =  JsonLogEntityFactory
+        .getInstance().createJsonLogEntitys(request, response, conf);
+    assertEquals(amles.size(), 1);
+    amle = (DBAuditMetadataLogEntity) amles.iterator().next();
+
+    assertCommon(amle, Constants.TRUE, Constants.OPERATION_REVOKE_PRIVILEGE,
+        "REVOKE ALL ON DATABASE testDB FROM ROLE testRole", TEST_DATABASE_NAME,
+        null, null, Constants.OBJECT_TYPE_PRINCIPAL);
+
+    privilege = getPrivilege(AccessConstants.ALL, PrivilegeScope.TABLE.name(),
+        null, TEST_TABLE_NAME, null, null);
+    privileges = Sets.newHashSet();
+    privileges.add(privilege);
+    request.setPrivileges(privileges);
+    response.setStatus(Status.InvalidInput("", null));
+    amles =  JsonLogEntityFactory.getInstance()
+        .createJsonLogEntitys(request, response, conf);
+    assertEquals(amles.size(), 1);
+    amle = (DBAuditMetadataLogEntity) amles.iterator().next();
+
+    assertCommon(amle, Constants.FALSE, Constants.OPERATION_REVOKE_PRIVILEGE,
+        "REVOKE ALL ON TABLE testTable FROM ROLE testRole", null,
+        TEST_TABLE_NAME, null, Constants.OBJECT_TYPE_PRINCIPAL);
+  }
+
+  @Test
+  public void testAddRole() {
+    TAlterSentryRoleAddGroupsRequest request = new TAlterSentryRoleAddGroupsRequest();
+    TAlterSentryRoleAddGroupsResponse response = new TAlterSentryRoleAddGroupsResponse();
+    request.setRequestorUserName(TEST_USER_NAME);
+    request.setRoleName(TEST_ROLE_NAME);
+    request.setGroups(getGroups());
+    response.setStatus(Status.OK());
+    DBAuditMetadataLogEntity amle = (DBAuditMetadataLogEntity) JsonLogEntityFactory
+        .getInstance().createJsonLogEntity(request, response, conf);
+    assertCommon(amle, Constants.TRUE, Constants.OPERATION_ADD_ROLE,
+        "GRANT ROLE testRole TO GROUP testGroup", null, null, null,
+        Constants.OBJECT_TYPE_ROLE);
+
+    response.setStatus(Status.InvalidInput("", null));
+    amle = (DBAuditMetadataLogEntity) JsonLogEntityFactory.getInstance()
+        .createJsonLogEntity(request, response, conf);
+    assertCommon(amle, Constants.FALSE, Constants.OPERATION_ADD_ROLE,
+        "GRANT ROLE testRole TO GROUP testGroup", null, null, null,
+        Constants.OBJECT_TYPE_ROLE);
+  }
+
+  @Test
+  public void testDeleteRole() {
+    TAlterSentryRoleDeleteGroupsRequest request = new TAlterSentryRoleDeleteGroupsRequest();
+    TAlterSentryRoleDeleteGroupsResponse response = new TAlterSentryRoleDeleteGroupsResponse();
+    request.setRequestorUserName(TEST_USER_NAME);
+    request.setRoleName(TEST_ROLE_NAME);
+    request.setGroups(getGroups());
+    response.setStatus(Status.OK());
+    DBAuditMetadataLogEntity amle = (DBAuditMetadataLogEntity) JsonLogEntityFactory
+        .getInstance().createJsonLogEntity(request, response, conf);
+    assertCommon(amle, Constants.TRUE, Constants.OPERATION_DELETE_ROLE,
+        "REVOKE ROLE testRole FROM GROUP testGroup", null, null, null,
+        Constants.OBJECT_TYPE_ROLE);
+
+    response.setStatus(Status.InvalidInput("", null));
+    amle = (DBAuditMetadataLogEntity) JsonLogEntityFactory.getInstance()
+        .createJsonLogEntity(request, response, conf);
+    assertCommon(amle, Constants.FALSE, Constants.OPERATION_DELETE_ROLE,
+        "REVOKE ROLE testRole FROM GROUP testGroup", null, null, null,
+        Constants.OBJECT_TYPE_ROLE);
+  }
+
+  private void assertCommon(DBAuditMetadataLogEntity amle,
+      String allowedExcepted, String operationExcepted,
+      String operationTextExcepted, String databaseNameExcepted,
+      String tableNameExcepted, String resourcePathExcepted,
+      String objectTypeExcepted) {
+    assertEquals(ServerConfig.SENTRY_SERVICE_NAME_DEFAULT,
+        amle.getServiceName());
+    assertEquals(TEST_IP, amle.getIpAddress());
+    assertEquals(TEST_USER_NAME, amle.getUserName());
+    assertEquals(TEST_IMPERSONATOR, amle.getImpersonator());
+    assertEquals(allowedExcepted, amle.getAllowed());
+    assertEquals(operationExcepted, amle.getOperation());
+    assertEquals(operationTextExcepted, amle.getOperationText());
+    assertEquals(tableNameExcepted, amle.getTableName());
+    assertEquals(databaseNameExcepted, amle.getDatabaseName());
+    assertEquals(resourcePathExcepted, amle.getResourcePath());
+    assertEquals(objectTypeExcepted, amle.getObjectType());
+  }
+
+  private TSentryPrivilege getPrivilege(String action, String privilegeScope,
+      String dbName, String tableName, String serverName, String URI) {
+    TSentryPrivilege privilege = new TSentryPrivilege();
+    privilege.setAction(action);
+    privilege.setPrivilegeScope(privilegeScope);
+    privilege.setDbName(dbName);
+    privilege.setTableName(tableName);
+    privilege.setServerName(serverName);
+    privilege.setURI(URI);
+    return privilege;
+  }
+
+  private Set<TSentryGroup> getGroups() {
+    Set<TSentryGroup> groups = new LinkedHashSet<TSentryGroup>();
+    TSentryGroup group = new TSentryGroup();
+    group.setGroupName(TEST_GROUP);
+    groups.add(group);
+    return groups;
+  }
+}

http://git-wip-us.apache.org/repos/asf/sentry/blob/e72e6eac/sentry-service/sentry-service-server/src/test/java/org/apache/sentry/provider/db/log/entity/TestJsonLogEntityFactoryGM.java
----------------------------------------------------------------------
diff --git a/sentry-service/sentry-service-server/src/test/java/org/apache/sentry/provider/db/log/entity/TestJsonLogEntityFactoryGM.java b/sentry-service/sentry-service-server/src/test/java/org/apache/sentry/provider/db/log/entity/TestJsonLogEntityFactoryGM.java
new file mode 100644
index 0000000..dfae5ab
--- /dev/null
+++ b/sentry-service/sentry-service-server/src/test/java/org/apache/sentry/provider/db/log/entity/TestJsonLogEntityFactoryGM.java
@@ -0,0 +1,259 @@
+/**
+ * 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.sentry.provider.db.log.entity;
+
+import static org.junit.Assert.assertEquals;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import org.apache.hadoop.conf.Configuration;
+import org.apache.sentry.provider.db.generic.service.thrift.TAlterSentryRoleAddGroupsRequest;
+import org.apache.sentry.provider.db.generic.service.thrift.TAlterSentryRoleAddGroupsResponse;
+import org.apache.sentry.provider.db.generic.service.thrift.TAlterSentryRoleDeleteGroupsRequest;
+import org.apache.sentry.provider.db.generic.service.thrift.TAlterSentryRoleDeleteGroupsResponse;
+import org.apache.sentry.provider.db.generic.service.thrift.TAlterSentryRoleGrantPrivilegeRequest;
+import org.apache.sentry.provider.db.generic.service.thrift.TAlterSentryRoleGrantPrivilegeResponse;
+import org.apache.sentry.provider.db.generic.service.thrift.TAlterSentryRoleRevokePrivilegeRequest;
+import org.apache.sentry.provider.db.generic.service.thrift.TAlterSentryRoleRevokePrivilegeResponse;
+import org.apache.sentry.provider.db.generic.service.thrift.TAuthorizable;
+import org.apache.sentry.provider.db.generic.service.thrift.TCreateSentryRoleRequest;
+import org.apache.sentry.provider.db.generic.service.thrift.TCreateSentryRoleResponse;
+import org.apache.sentry.provider.db.generic.service.thrift.TDropSentryRoleRequest;
+import org.apache.sentry.provider.db.generic.service.thrift.TDropSentryRoleResponse;
+import org.apache.sentry.provider.db.generic.service.thrift.TSentryPrivilege;
+import org.apache.sentry.provider.db.log.util.Constants;
+import org.apache.sentry.provider.db.service.thrift.ThriftUtil;
+import org.apache.sentry.service.thrift.ServiceConstants.ServerConfig;
+import org.apache.sentry.service.thrift.Status;
+import org.junit.BeforeClass;
+import org.junit.Test;
+
+public class TestJsonLogEntityFactoryGM {
+
+  private static Configuration conf;
+  private static String TEST_IP = "localhost/127.0.0.1";
+  private static String TEST_IMPERSONATOR = "impersonator";
+  private static String TEST_ROLE_NAME = "testRole";
+  private static String TEST_USER_NAME = "requestUser";
+  private static String TEST_GROUP = "testGroup";
+  private static String TEST_ACTION = "action";
+  private static String TEST_COMPONENT = "component";
+  private static Map<String, String> TEST_PRIVILEGES_MAP = new HashMap<String, String>();
+
+  @BeforeClass
+  public static void init() {
+    conf = new Configuration();
+    conf.set(ServerConfig.SENTRY_SERVICE_NAME, ServerConfig.SENTRY_SERVICE_NAME_DEFAULT);
+    ThriftUtil.setIpAddress(TEST_IP);
+    ThriftUtil.setImpersonator(TEST_IMPERSONATOR);
+    TEST_PRIVILEGES_MAP.put("resourceType1", "resourceName1");
+    TEST_PRIVILEGES_MAP.put("resourceType2", "resourceName2");
+    TEST_PRIVILEGES_MAP.put("resourceType3", "resourceName3");
+  }
+
+  @Test
+  public void testCreateRole() {
+    TCreateSentryRoleRequest request = new TCreateSentryRoleRequest();
+    TCreateSentryRoleResponse response = new TCreateSentryRoleResponse();
+    request.setRequestorUserName(TEST_USER_NAME);
+    request.setRoleName(TEST_ROLE_NAME);
+    response.setStatus(Status.OK());
+    GMAuditMetadataLogEntity amle = (GMAuditMetadataLogEntity) JsonLogEntityFactory.getInstance()
+        .createJsonLogEntity(request, response, conf);
+    assertCommon(amle, Constants.TRUE, Constants.OPERATION_CREATE_ROLE, "CREATE ROLE testRole",
+        Constants.OBJECT_TYPE_ROLE, new HashMap<String, String>());
+
+    response.setStatus(Status.InvalidInput("", null));
+    amle = (GMAuditMetadataLogEntity) JsonLogEntityFactory.getInstance().createJsonLogEntity(
+        request, response, conf);
+    assertCommon(amle, Constants.FALSE, Constants.OPERATION_CREATE_ROLE, "CREATE ROLE testRole",
+        Constants.OBJECT_TYPE_ROLE, new HashMap<String, String>());
+  }
+
+  @Test
+  public void testDropRole() {
+    TDropSentryRoleRequest request = new TDropSentryRoleRequest();
+    TDropSentryRoleResponse response = new TDropSentryRoleResponse();
+    request.setRequestorUserName(TEST_USER_NAME);
+    request.setRoleName(TEST_ROLE_NAME);
+    response.setStatus(Status.OK());
+    GMAuditMetadataLogEntity amle = (GMAuditMetadataLogEntity) JsonLogEntityFactory
+        .getInstance().createJsonLogEntity(request, response, conf);
+    assertCommon(amle, Constants.TRUE, Constants.OPERATION_DROP_ROLE, "DROP ROLE testRole",
+        Constants.OBJECT_TYPE_ROLE, new HashMap<String, String>());
+
+    response.setStatus(Status.InvalidInput("", null));
+    amle = (GMAuditMetadataLogEntity) JsonLogEntityFactory.getInstance().createJsonLogEntity(
+        request, response, conf);
+    assertCommon(amle, Constants.FALSE, Constants.OPERATION_DROP_ROLE, "DROP ROLE testRole",
+        Constants.OBJECT_TYPE_ROLE, new HashMap<String, String>());
+  }
+
+  @Test
+  public void testGrantRole() {
+    TAlterSentryRoleGrantPrivilegeRequest request = new TAlterSentryRoleGrantPrivilegeRequest();
+    request.setRequestorUserName(TEST_USER_NAME);
+    request.setRoleName(TEST_ROLE_NAME);
+
+    TAlterSentryRoleGrantPrivilegeResponse response = new TAlterSentryRoleGrantPrivilegeResponse();
+
+    TSentryPrivilege privilege = getPrivilege();
+    request.setPrivilege(privilege);
+    response.setStatus(Status.OK());
+    GMAuditMetadataLogEntity amle = (GMAuditMetadataLogEntity) JsonLogEntityFactory.getInstance()
+        .createJsonLogEntity(
+        request, response, conf);
+    assertCommon(
+        amle,
+        Constants.TRUE,
+        Constants.OPERATION_GRANT_PRIVILEGE,
+        "GRANT ACTION ON resourceType1 resourceName1 resourceType2 resourceName2 resourceType3 resourceName3 TO ROLE testRole",
+        Constants.OBJECT_TYPE_PRINCIPAL, TEST_PRIVILEGES_MAP);
+
+    response.setStatus(Status.InvalidInput("", null));
+    amle = (GMAuditMetadataLogEntity) JsonLogEntityFactory.getInstance().createJsonLogEntity(
+        request, response, conf);
+    assertCommon(
+        amle,
+        Constants.FALSE,
+        Constants.OPERATION_GRANT_PRIVILEGE,
+        "GRANT ACTION ON resourceType1 resourceName1 resourceType2 resourceName2 resourceType3 resourceName3 TO ROLE testRole",
+        Constants.OBJECT_TYPE_PRINCIPAL, TEST_PRIVILEGES_MAP);
+  }
+
+  @Test
+  public void testRevokeRole() {
+    TAlterSentryRoleRevokePrivilegeRequest request = new TAlterSentryRoleRevokePrivilegeRequest();
+    TAlterSentryRoleRevokePrivilegeResponse response = new TAlterSentryRoleRevokePrivilegeResponse();
+    request.setRequestorUserName(TEST_USER_NAME);
+    request.setRoleName(TEST_ROLE_NAME);
+
+    TSentryPrivilege privilege = getPrivilege();
+    request.setPrivilege(privilege);
+    response.setStatus(Status.OK());
+    GMAuditMetadataLogEntity amle = (GMAuditMetadataLogEntity) JsonLogEntityFactory.getInstance()
+        .createJsonLogEntity(request, response, conf);
+    assertCommon(
+        amle,
+        Constants.TRUE,
+        Constants.OPERATION_REVOKE_PRIVILEGE,
+        "REVOKE ACTION ON resourceType1 resourceName1 resourceType2 resourceName2 resourceType3 resourceName3 FROM ROLE testRole",
+        Constants.OBJECT_TYPE_PRINCIPAL, TEST_PRIVILEGES_MAP);
+
+    response.setStatus(Status.InvalidInput("", null));
+    amle = (GMAuditMetadataLogEntity) JsonLogEntityFactory.getInstance().createJsonLogEntity(
+        request, response, conf);
+
+    assertCommon(
+        amle,
+        Constants.FALSE,
+        Constants.OPERATION_REVOKE_PRIVILEGE,
+        "REVOKE ACTION ON resourceType1 resourceName1 resourceType2 resourceName2 resourceType3 resourceName3 FROM ROLE testRole",
+        Constants.OBJECT_TYPE_PRINCIPAL, TEST_PRIVILEGES_MAP);
+  }
+
+  @Test
+  public void testAddRole() {
+    TAlterSentryRoleAddGroupsRequest request = new TAlterSentryRoleAddGroupsRequest();
+    TAlterSentryRoleAddGroupsResponse response = new TAlterSentryRoleAddGroupsResponse();
+    request.setRequestorUserName(TEST_USER_NAME);
+    request.setRoleName(TEST_ROLE_NAME);
+    request.setGroups(getGroups());
+    response.setStatus(Status.OK());
+    GMAuditMetadataLogEntity amle = (GMAuditMetadataLogEntity) JsonLogEntityFactory.getInstance()
+        .createJsonLogEntity(request, response, conf);
+    assertCommon(amle, Constants.TRUE, Constants.OPERATION_ADD_ROLE,
+        "GRANT ROLE testRole TO GROUP testGroup", Constants.OBJECT_TYPE_ROLE,
+        new HashMap<String, String>());
+
+    response.setStatus(Status.InvalidInput("", null));
+    amle = (GMAuditMetadataLogEntity) JsonLogEntityFactory.getInstance().createJsonLogEntity(
+        request, response, conf);
+    assertCommon(amle, Constants.FALSE, Constants.OPERATION_ADD_ROLE,
+        "GRANT ROLE testRole TO GROUP testGroup", Constants.OBJECT_TYPE_ROLE,
+        new HashMap<String, String>());
+  }
+
+  @Test
+  public void testDeleteRole() {
+    TAlterSentryRoleDeleteGroupsRequest request = new TAlterSentryRoleDeleteGroupsRequest();
+    TAlterSentryRoleDeleteGroupsResponse response = new TAlterSentryRoleDeleteGroupsResponse();
+    request.setRequestorUserName(TEST_USER_NAME);
+    request.setRoleName(TEST_ROLE_NAME);
+    request.setGroups(getGroups());
+    response.setStatus(Status.OK());
+    GMAuditMetadataLogEntity amle = (GMAuditMetadataLogEntity) JsonLogEntityFactory
+        .getInstance().createJsonLogEntity(request, response, conf);
+    assertCommon(amle, Constants.TRUE, Constants.OPERATION_DELETE_ROLE,
+        "REVOKE ROLE testRole FROM GROUP testGroup", Constants.OBJECT_TYPE_ROLE,
+        new HashMap<String, String>());
+
+    response.setStatus(Status.InvalidInput("", null));
+    amle = (GMAuditMetadataLogEntity) JsonLogEntityFactory.getInstance().createJsonLogEntity(
+        request, response, conf);
+    assertCommon(amle, Constants.FALSE, Constants.OPERATION_DELETE_ROLE,
+        "REVOKE ROLE testRole FROM GROUP testGroup", Constants.OBJECT_TYPE_ROLE,
+        new HashMap<String, String>());
+  }
+
+  private void assertCommon(GMAuditMetadataLogEntity amle, String allowedExcepted,
+      String operationExcepted, String operationTextExcepted, String objectTypeExcepted,
+      Map<String, String> privilegesExcepted) {
+    assertEquals(ServerConfig.SENTRY_SERVICE_NAME_DEFAULT, amle.getServiceName());
+    assertEquals(TEST_IP, amle.getIpAddress());
+    assertEquals(TEST_USER_NAME, amle.getUserName());
+    assertEquals(TEST_IMPERSONATOR, amle.getImpersonator());
+    assertEquals(allowedExcepted, amle.getAllowed());
+    assertEquals(operationExcepted, amle.getOperation());
+    assertEquals(operationTextExcepted, amle.getOperationText());
+    assertEquals(objectTypeExcepted, amle.getObjectType());
+    assertPrivilegesMap(privilegesExcepted, amle.getPrivilegesMap());
+  }
+
+  private void assertPrivilegesMap(Map<String, String> privilegesExcepted,
+      Map<String, String> privilegesActual) {
+    assertEquals(privilegesExcepted.size(), privilegesActual.size());
+    for (Map.Entry<String, String> privilege : privilegesExcepted.entrySet()) {
+      assertEquals(privilege.getValue(), privilegesActual.get(privilege.getKey()));
+    }
+  }
+
+  private TSentryPrivilege getPrivilege() {
+    TSentryPrivilege privilege = new TSentryPrivilege();
+    privilege.setAction(TEST_ACTION);
+    privilege.setComponent(TEST_COMPONENT);
+    List<TAuthorizable> authorizables = new ArrayList<TAuthorizable>();
+    authorizables.add(new TAuthorizable("resourceType1", "resourceName1"));
+    authorizables.add(new TAuthorizable("resourceType2", "resourceName2"));
+    authorizables.add(new TAuthorizable("resourceType3", "resourceName3"));
+    privilege.setAuthorizables(authorizables);
+    return privilege;
+  }
+
+  private Set<String> getGroups() {
+    Set<String> groups = new HashSet<String>();
+    groups.add(TEST_GROUP);
+    return groups;
+  }
+}


Mime
View raw message