http://git-wip-us.apache.org/repos/asf/incubator-sentry/blob/bf3eb482/sentry-provider/sentry-provider-db/src/main/resources/sentry_generic_policy_service.thrift
----------------------------------------------------------------------
diff --git 
a/sentry-provider/sentry-provider-db/src/main/resources/sentry_generic_policy_service.thrift
 
b/sentry-provider/sentry-provider-db/src/main/resources/sentry_generic_policy_service.thrift
new file mode 100644
index 0000000..91ff672
--- /dev/null
+++ 
b/sentry-provider/sentry-provider-db/src/main/resources/sentry_generic_policy_service.thrift
@@ -0,0 +1,231 @@
+#!/usr/local/bin/thrift -java
+
+/**
+ * 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.
+ */
+
+#
+# Thrift Service that the MetaStore is built on
+#
+
+include "share/fb303/if/fb303.thrift"
+include "sentry_common_service.thrift"
+include "sentry_policy_service.thrift"
+
+namespace java org.apache.sentry.provider.db.generic.service.thrift
+namespace php sentry.provider.db.service.db.generic.serivce.thrift
+namespace cpp Apache.Sentry.Provider.Db.Generic.Service.Thrift
+
+typedef sentry_common_service.TSentryResponseStatus TSentryResponseStatus
+
+# Represents a new generic model privilege for solr or other component in 
transport 
+# from the client to the server
+enum TSentryGrantOption {
+  TRUE = 1,
+  FALSE = 0,
+  UNSET = -1
+}
+
+# Represents a authorizable resource in the privilege
+# like DATABASE=db1 in the hive, COLLECTION=collection1 in the solr
+struct TAuthorizable {
+1: required string type,
+2: required string name
+}
+
+struct TSentryPrivilege {
+1: required string component,
+2: required string serviceName,
+3: required list<TAuthorizable> authorizables,
+4: required string action,
+5: optional i64 createTime, # Set on server side
+6: optional string grantorPrincipal, # Set on server side
+7: optional TSentryGrantOption grantOption = 
sentry_policy_service.TSentryGrantOption.FALSE
+}
+
+# CREATE ROLE r1
+struct TCreateSentryRoleRequest {
+1: required i32 protocol_version = sentry_common_service.TSENTRY_SERVICE_V2,
+2: required string requestorUserName, # user on whose behalf the request is 
issued
+3: required string roleName,
+4: required string component # The request is issued to which component
+}
+
+struct TCreateSentryRoleResponse {
+1: required TSentryResponseStatus status
+}
+
+# DROP ROLE r1
+struct TDropSentryRoleRequest {
+1: required i32 protocol_version = sentry_common_service.TSENTRY_SERVICE_V2,
+2: required string requestorUserName, # user on whose behalf the request is 
issued
+3: required string roleName,
+4: required string component # The request is issued to which component
+}
+
+struct TDropSentryRoleResponse {
+1: required TSentryResponseStatus status
+}
+
+# GRANT ROLE r1 TO GROUP g1
+struct TAlterSentryRoleAddGroupsRequest {
+1: required i32 protocol_version = sentry_common_service.TSENTRY_SERVICE_V2,
+2: required string requestorUserName, # user on whose behalf the request is 
issued
+3: required string roleName,
+4: required string component, # The request is issued to which component
+5: required set<string> groups
+}
+struct TAlterSentryRoleAddGroupsResponse {
+1: required TSentryResponseStatus status
+}
+
+# REVOLE ROLE r1 FROM GROUP g1
+struct TAlterSentryRoleDeleteGroupsRequest {
+1: required i32 protocol_version = sentry_common_service.TSENTRY_SERVICE_V2,
+2: required string requestorUserName, # user on whose behalf the request is 
issued
+3: required string roleName,
+4: required string component, # The request is issued to which component
+5: required set<string> groups
+}
+struct TAlterSentryRoleDeleteGroupsResponse {
+1: required TSentryResponseStatus status
+}
+
+# GRANT ... ON ... TO ROLE ...
+struct TAlterSentryRoleGrantPrivilegeRequest {
+1: required i32 protocol_version = sentry_common_service.TSENTRY_SERVICE_V2,
+2: required string requestorUserName, # user on whose behalf the request is 
issued
+3: required string roleName,
+4: required string component, # The request is issued to which component
+5: required TSentryPrivilege privilege
+}
+struct TAlterSentryRoleGrantPrivilegeResponse {
+1: required TSentryResponseStatus status
+}
+
+# REVOKE ... ON ... FROM ROLE ...
+struct TAlterSentryRoleRevokePrivilegeRequest {
+1: required i32 protocol_version = sentry_common_service.TSENTRY_SERVICE_V2,
+2: required string requestorUserName, # user on whose behalf the request is 
issued
+3: required string roleName,
+4: required string component, # The request is issued to which component
+5: required TSentryPrivilege privilege
+}
+struct TAlterSentryRoleRevokePrivilegeResponse {
+1: required TSentryResponseStatus status
+}
+
+# SHOW ROLE GRANT
+struct TListSentryRolesRequest {
+1: required i32 protocol_version = sentry_common_service.TSENTRY_SERVICE_V2,
+2: required string requestorUserName, # user on whose behalf the request is 
issued
+3: optional string groupName, # for this group, or all roles for all groups if 
null
+4: required string component # The request is issued to which component
+}
+# used only for TListSentryRolesResponse
+struct TSentryRole {
+1: required string roleName,
+2: required set<string> groups
+}
+
+struct TListSentryRolesResponse {
+1: required TSentryResponseStatus status
+2: optional set<TSentryRole> roles
+}
+# SHOW GRANT
+struct TListSentryPrivilegesRequest {
+1: required i32 protocol_version = sentry_common_service.TSENTRY_SERVICE_V2,
+2: required string requestorUserName, # user on whose behalf the request is 
issued
+3: required string roleName, # get privileges assigned for this role
+4: required string component, # The request is issued to which component
+5: required string serviceName, # The privilege belongs to which service
+6: optional list<TAuthorizable> authorizables # get privileges assigned for 
this authorizable hierarchys
+}
+
+struct TListSentryPrivilegesResponse {
+1: required TSentryResponseStatus status
+2: optional set<TSentryPrivilege> privileges
+}
+
+# Drop privilege
+struct TDropPrivilegesRequest {
+1: required i32 protocol_version = sentry_common_service.TSENTRY_SERVICE_V2,
+2: required string requestorUserName, # user on whose behalf the request is 
issued
+3: required TSentryPrivilege privilege
+4: required string component, # The request is issued to which component
+}
+
+struct TDropPrivilegesResponse {
+1: required TSentryResponseStatus status
+}
+
+# Rename privilege
+struct TRenamePrivilegesRequest {
+1: required i32 protocol_version = sentry_common_service.TSENTRY_SERVICE_V2,
+2: required string requestorUserName, # user on whose behalf the request is 
issued
+3: required string component, # The request is issued to which component
+4: required string serviceName, # The privilege belongs to which service
+5: required list<TAuthorizable>  oldAuthorizables, # get old privileges 
assigned for this authorizable hierarchys
+6: required list<TAuthorizable>  newAuthorizables # change to new authorizable 
hierarchys
+}
+
+struct TRenamePrivilegesResponse {
+1: required TSentryResponseStatus status
+}
+
+# This API was created specifically for ProviderBackend.getPrivileges
+# and is not mean for general purpose privilege retrieval.
+# This request/response pair are created specifically so we can
+# efficiently obtain the specific privilges for a user query
+struct TSentryActiveRoleSet {
+1: required bool all,
+2: required set<string> roles,
+}
+struct TListSentryPrivilegesForProviderRequest {
+1: required i32 protocol_version = sentry_common_service.TSENTRY_SERVICE_V2,
+2: required string component, # The request is issued to which component
+3: required string serviceName, # The privilege belongs to which service
+4: required set<string> groups,
+5: required TSentryActiveRoleSet roleSet,
+6: optional list<TAuthorizable>  authorizables # authorizable hierarchys
+}
+struct TListSentryPrivilegesForProviderResponse {
+1: required TSentryResponseStatus status
+2: required set<string> privileges
+}
+
+service SentryGenericPolicyService
+{
+  TCreateSentryRoleResponse create_sentry_role(1:TCreateSentryRoleRequest 
request)
+  TDropSentryRoleResponse drop_sentry_role(1:TDropSentryRoleRequest request)
+
+  TAlterSentryRoleGrantPrivilegeResponse 
alter_sentry_role_grant_privilege(1:TAlterSentryRoleGrantPrivilegeRequest 
request)
+  TAlterSentryRoleRevokePrivilegeResponse 
alter_sentry_role_revoke_privilege(1:TAlterSentryRoleRevokePrivilegeRequest 
request)
+
+  TAlterSentryRoleAddGroupsResponse 
alter_sentry_role_add_groups(1:TAlterSentryRoleAddGroupsRequest request)
+  TAlterSentryRoleDeleteGroupsResponse 
alter_sentry_role_delete_groups(1:TAlterSentryRoleDeleteGroupsRequest request)
+
+  TListSentryRolesResponse 
list_sentry_roles_by_group(1:TListSentryRolesRequest request)
+
+  TListSentryPrivilegesResponse 
list_sentry_privileges_by_role(1:TListSentryPrivilegesRequest request)
+
+  TListSentryPrivilegesForProviderResponse 
list_sentry_privileges_for_provider(1:TListSentryPrivilegesForProviderRequest 
request)
+
+  TDropPrivilegesResponse drop_sentry_privilege(1:TDropPrivilegesRequest 
request);
+
+  TRenamePrivilegesResponse rename_sentry_privilege(1:TRenamePrivilegesRequest 
request);
+}

http://git-wip-us.apache.org/repos/asf/incubator-sentry/blob/bf3eb482/sentry-provider/sentry-provider-db/src/test/java/org/apache/sentry/provider/db/generic/service/persistent/SentryStoreIntegrationBase.java
----------------------------------------------------------------------
diff --git 
a/sentry-provider/sentry-provider-db/src/test/java/org/apache/sentry/provider/db/generic/service/persistent/SentryStoreIntegrationBase.java
 
b/sentry-provider/sentry-provider-db/src/test/java/org/apache/sentry/provider/db/generic/service/persistent/SentryStoreIntegrationBase.java
new file mode 100644
index 0000000..c65a28f
--- /dev/null
+++ 
b/sentry-provider/sentry-provider-db/src/test/java/org/apache/sentry/provider/db/generic/service/persistent/SentryStoreIntegrationBase.java
@@ -0,0 +1,95 @@
+/**
+ * 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.service.persistent;
+
+import java.io.File;
+
+import org.apache.commons.io.FileUtils;
+import org.apache.hadoop.conf.Configuration;
+import 
org.apache.sentry.provider.db.generic.service.persistent.SentryStoreLayer;
+import org.apache.sentry.provider.file.PolicyFile;
+import org.apache.sentry.service.thrift.ServiceConstants.ServerConfig;
+import org.junit.After;
+import org.junit.Before;
+
+import com.google.common.io.Files;
+
+public abstract class SentryStoreIntegrationBase {
+  protected final String[] adminGroups = {"adminGroup"};
+  private File dataDir;
+  protected SentryStoreLayer sentryStore;
+  private PolicyFile policyFile;
+  private File policyFilePath;
+
+  @Before
+  public void setup() throws Exception {
+    Configuration conf = new Configuration(false);
+    setup(conf);
+    configure(conf);
+    sentryStore = createSentryStore(conf);
+  }
+
+  private void setup(Configuration conf) throws Exception {
+    dataDir = new File(Files.createTempDir(), "sentry_policy_db");
+    conf.set(ServerConfig.SENTRY_VERIFY_SCHEM_VERSION, "false");
+    conf.set(ServerConfig.SENTRY_STORE_JDBC_URL,
+        "jdbc:derby:;databaseName=" + dataDir.getPath() + ";create=true");
+    conf.setStrings(ServerConfig.ADMIN_GROUPS, adminGroups);
+    conf.set(ServerConfig.SENTRY_STORE_GROUP_MAPPING,
+        ServerConfig.SENTRY_STORE_LOCAL_GROUP_MAPPING);
+
+    policyFilePath = new File(Files.createTempDir(), "local_policy_file.ini");
+    conf.set(ServerConfig.SENTRY_STORE_GROUP_MAPPING_RESOURCE,
+        policyFilePath.getPath());
+    policyFile = new PolicyFile();
+    String adminUser = "admin";
+    addGroupsToUser(adminUser, adminGroups);
+    writePolicyFile();
+  }
+
+  @After
+  public void teardown() {
+    if (sentryStore != null) {
+      sentryStore.close();
+    }
+    if (dataDir != null) {
+      FileUtils.deleteQuietly(dataDir);
+    }
+    if (policyFilePath != null) {
+      FileUtils.deleteQuietly(policyFilePath);
+    }
+  }
+
+  public void addGroupsToUser(String user, String... groupNames) {
+    policyFile.addGroupsToUser(user, groupNames);
+  }
+
+  public void writePolicyFile() throws Exception {
+    policyFile.write(policyFilePath);
+  }
+
+  public String[] getAdminGroups() {
+    return adminGroups;
+  }
+
+  public void configure(Configuration conf) throws Exception {
+
+  }
+
+  public abstract SentryStoreLayer createSentryStore(Configuration conf) 
throws Exception;
+}

http://git-wip-us.apache.org/repos/asf/incubator-sentry/blob/bf3eb482/sentry-provider/sentry-provider-db/src/test/java/org/apache/sentry/provider/db/generic/service/persistent/TestDelegateSentryStore.java
----------------------------------------------------------------------
diff --git 
a/sentry-provider/sentry-provider-db/src/test/java/org/apache/sentry/provider/db/generic/service/persistent/TestDelegateSentryStore.java
 
b/sentry-provider/sentry-provider-db/src/test/java/org/apache/sentry/provider/db/generic/service/persistent/TestDelegateSentryStore.java
new file mode 100644
index 0000000..c7c6af7
--- /dev/null
+++ 
b/sentry-provider/sentry-provider-db/src/test/java/org/apache/sentry/provider/db/generic/service/persistent/TestDelegateSentryStore.java
@@ -0,0 +1,175 @@
+/**
+ * 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.service.persistent;
+
+import static junit.framework.Assert.assertEquals;
+import static junit.framework.Assert.fail;
+
+import java.util.Set;
+
+import org.apache.hadoop.conf.Configuration;
+import org.apache.sentry.provider.db.SentryAlreadyExistsException;
+import org.apache.sentry.provider.db.SentryNoSuchObjectException;
+import org.junit.Test;
+
+import com.google.common.collect.Sets;
+
+public class TestDelegateSentryStore extends SentryStoreIntegrationBase{
+  private static final String SEARCH = "solr";
+  @Override
+  public SentryStoreLayer createSentryStore(Configuration conf) throws 
Exception {
+    return new DelegateSentryStore(conf);
+  }
+
+  @Test
+  public void testCreateDropRole() throws Exception {
+    String roleName = "test-drop-role";
+    String grantor = "grantor";
+    long seqId = sentryStore.createRole(SEARCH, roleName, 
grantor).getSequenceId();
+    assertEquals(seqId + 1, sentryStore.dropRole(SEARCH, roleName, 
grantor).getSequenceId());
+  }
+
+  @Test
+  public void testCaseInsensitiveCreateDropRole() throws Exception {
+    String roleName1 = "test";
+    String roleName2 = "TeSt";
+    String grantor = "grantor";
+    sentryStore.createRole(SEARCH, roleName1, grantor);
+    try {
+      sentryStore.createRole(SEARCH, roleName2, grantor);
+      fail("SentryAlreadyExistsException should have been thrown");
+    } catch (SentryAlreadyExistsException e) {
+      //ignore the exception
+    }
+
+    try {
+      sentryStore.dropRole(SEARCH, roleName2, grantor);
+    } catch (SentryNoSuchObjectException e) {
+      fail("SentryNoSuchObjectException shouldn't have been thrown");
+    }
+  }
+
+  @Test(expected=SentryAlreadyExistsException.class)
+  public void testCreateDuplicateRole() throws Exception {
+    String roleName = "test-dup-role";
+    String grantor = "grantor";
+    sentryStore.createRole(SEARCH, roleName, grantor);
+    sentryStore.createRole(SEARCH, roleName, grantor);
+  }
+
+  @Test(expected=SentryNoSuchObjectException.class)
+  public void testDropNotExistRole() throws Exception {
+    String roleName = "not-exist";
+    String grantor = "grantor";
+    sentryStore.dropRole(SEARCH, roleName, grantor);
+  }
+
+  @Test(expected = SentryNoSuchObjectException.class)
+  public void testAddGroupsNonExistantRole()
+      throws Exception {
+    String roleName = "non-existant-role";
+    String grantor = "grantor";
+    sentryStore.alterRoleAddGroups(SEARCH, roleName, Sets.newHashSet("g1"), 
grantor);
+  }
+
+  @Test(expected = SentryNoSuchObjectException.class)
+  public void testDeleteGroupsNonExistantRole()
+      throws Exception {
+    String roleName = "non-existant-role";
+    String grantor = "grantor";
+    sentryStore.alterRoleDeleteGroups(SEARCH, roleName, Sets.newHashSet("g1"), 
grantor);
+  }
+
+  @Test
+  public void testAddDeleteRoleToGroups() throws Exception {
+    String role1 = "r1", role2 = "r2";
+    Set<String> twoGroups = Sets.newHashSet("g1", "g2");
+    Set<String> oneGroup = Sets.newHashSet("g3");
+    String grantor = "grantor";
+
+    sentryStore.createRole(SEARCH, role1, grantor);
+    sentryStore.createRole(SEARCH, role2, grantor);
+
+    sentryStore.alterRoleAddGroups(SEARCH, role1, twoGroups, grantor);
+    assertEquals(twoGroups, 
sentryStore.getGroupsByRoles(SEARCH,Sets.newHashSet(role1)));
+
+    assertEquals(Sets.newHashSet(role1), sentryStore.getRolesByGroups(SEARCH, 
twoGroups));
+
+    sentryStore.alterRoleAddGroups(SEARCH, role2, oneGroup, grantor);
+    assertEquals(oneGroup, sentryStore.getGroupsByRoles(SEARCH, 
Sets.newHashSet(role2)));
+
+    sentryStore.alterRoleDeleteGroups(SEARCH, role1, Sets.newHashSet("g1"), 
grantor);
+    assertEquals(Sets.newHashSet("g2"), sentryStore.getGroupsByRoles(SEARCH, 
Sets.newHashSet(role1)));
+
+    sentryStore.alterRoleDeleteGroups(SEARCH, role2, oneGroup, grantor);
+    assertEquals(Sets.newHashSet(), sentryStore.getGroupsByRoles(SEARCH, 
Sets.newHashSet(role2)));
+  }
+
+  @Test
+  public void testGetRolesByGroupNames() throws Exception {
+    String role1 = "r1", role2 = "r2";
+    Set<String> twoGroups = Sets.newHashSet("g1", "g2");
+    String grantor = "grantor";
+
+    sentryStore.createRole(SEARCH, role1, grantor);
+    sentryStore.createRole(SEARCH, role2, grantor);
+
+    sentryStore.alterRoleAddGroups(SEARCH, role1, twoGroups, grantor);
+    sentryStore.alterRoleAddGroups(SEARCH, role2, twoGroups, grantor);
+
+    assertEquals(Sets.newHashSet(role1,role2), 
sentryStore.getRolesByGroups(SEARCH, twoGroups));
+  }
+
+  @Test
+  public void testGetGroupsByRoleNames() throws Exception {
+    String role1 = "r1", role2 = "r2";
+    Set<String> twoGroups = Sets.newHashSet("g1", "g2");
+    String grantor = "grantor";
+
+    sentryStore.createRole(SEARCH, role1, grantor);
+    sentryStore.createRole(SEARCH, role2, grantor);
+
+    sentryStore.alterRoleAddGroups(SEARCH, role1, twoGroups, grantor);
+    sentryStore.alterRoleAddGroups(SEARCH, role2, twoGroups, grantor);
+
+    assertEquals(twoGroups, sentryStore.getGroupsByRoles(SEARCH, 
Sets.newHashSet(role1)));
+    assertEquals(twoGroups, sentryStore.getGroupsByRoles(SEARCH, 
Sets.newHashSet(role2)));
+    assertEquals(twoGroups, sentryStore.getGroupsByRoles(SEARCH, 
Sets.newHashSet(role1,role2)));
+  }
+
+  @Test
+  public void testGetAllRoles() throws Exception {
+    String role1 = "r1", role2 = "r2";
+    Set<String> twoGroups = Sets.newHashSet("g1", "g2");
+    String grantor = "grantor";
+
+    sentryStore.createRole(SEARCH, role1, grantor);
+    sentryStore.createRole(SEARCH, role2, grantor);
+
+    sentryStore.alterRoleAddGroups(SEARCH, role1, twoGroups, grantor);
+    sentryStore.alterRoleAddGroups(SEARCH, role2, twoGroups, grantor);
+
+    //test get all roles by groupName=null
+    String groupName = null;
+    Set<String> groups = Sets.newHashSet(groupName);
+    assertEquals(Sets.newHashSet(role1,role2), 
sentryStore.getRolesByGroups(SEARCH, groups));
+
+    groups.clear();
+    assertEquals(0, sentryStore.getRolesByGroups(SEARCH, groups).size());
+  }
+}

http://git-wip-us.apache.org/repos/asf/incubator-sentry/blob/bf3eb482/sentry-provider/sentry-provider-db/src/test/java/org/apache/sentry/provider/db/generic/service/persistent/TestPrivilegeOperatePersistence.java
----------------------------------------------------------------------
diff --git 
a/sentry-provider/sentry-provider-db/src/test/java/org/apache/sentry/provider/db/generic/service/persistent/TestPrivilegeOperatePersistence.java
 
b/sentry-provider/sentry-provider-db/src/test/java/org/apache/sentry/provider/db/generic/service/persistent/TestPrivilegeOperatePersistence.java
new file mode 100644
index 0000000..5dc5fde
--- /dev/null
+++ 
b/sentry-provider/sentry-provider-db/src/test/java/org/apache/sentry/provider/db/generic/service/persistent/TestPrivilegeOperatePersistence.java
@@ -0,0 +1,909 @@
+/**
+ * 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.service.persistent;
+
+import static junit.framework.Assert.assertEquals;
+import static junit.framework.Assert.fail;
+
+import java.util.Arrays;
+import java.util.List;
+
+import org.apache.hadoop.conf.Configuration;
+import org.apache.sentry.core.common.Authorizable;
+import org.apache.sentry.core.model.search.Collection;
+import org.apache.sentry.core.model.search.Field;
+import org.apache.sentry.core.model.search.SearchConstants;
+import org.apache.sentry.provider.db.SentryGrantDeniedException;
+import 
org.apache.sentry.provider.db.generic.service.persistent.DelegateSentryStore;
+import 
org.apache.sentry.provider.db.generic.service.persistent.SentryStoreLayer;
+import 
org.apache.sentry.provider.db.generic.service.persistent.PrivilegeObject.Builder;
+import org.junit.Test;
+
+import com.google.common.collect.Sets;
+
+/**
+ * The test cases are used for search component The authorizables are 
COLLECTION and Field
+ * The actions of search privilege are ALL,QUERY and UPDATE
+ */
+public class TestPrivilegeOperatePersistence extends 
SentryStoreIntegrationBase {
+  private static final String SEARCH = "solr";
+  private static final String ADMIN_USER = "solr";
+  private static final String GRANT_OPTION_USER = "user_grant_option";
+  private static final String[] GRANT_OPTION_GROUP = { "group_grant_option" };
+  private static final String NO_GRANT_OPTION_USER = "user_no_grant_option";
+  private static final String[] NO_GRANT_OPTION_GROUP = { 
"group_no_grant_option" };
+
+  private static final String SERVICE = "service";
+  private static final String COLLECTION_NAME = "collection1";
+  private static final String NOT_COLLECTION_NAME = "not_collection1";
+  private static final String FIELD_NAME = "field1";
+  private static final String NOT_FIELD_NAME = "not_field1";
+
+  @Override
+  public void configure(Configuration conf) throws Exception {
+    /**
+     * add the solr user to admin groups
+     */
+    addGroupsToUser(ADMIN_USER, getAdminGroups());
+    writePolicyFile();
+  }
+
+  @Override
+  public SentryStoreLayer createSentryStore(Configuration conf)
+      throws Exception {
+    return new DelegateSentryStore(conf);
+  }
+
+  /**
+   * Grant query privilege to role r1
+   */
+  @Test
+  public void testGrantPrivilege() throws Exception {
+    String roleName = "r1";
+    /**
+     * grantor is admin, there is no need to check grant option
+     */
+    String grantor = ADMIN_USER;
+    PrivilegeObject queryPrivilege = new Builder()
+        .setComponent(SEARCH)
+        .setAction(SearchConstants.QUERY)
+        .setService(SERVICE)
+        .setAuthorizables(Arrays.asList(new Collection(COLLECTION_NAME)))
+        .withGrantOption(null)
+        .build();
+
+    sentryStore.createRole(SEARCH, roleName, grantor);
+    sentryStore.alterRoleGrantPrivilege(SEARCH, roleName, queryPrivilege, 
grantor);
+
+    assertEquals(Sets.newHashSet(queryPrivilege),
+        sentryStore.getPrivilegesByRole(SEARCH, Sets.newHashSet(roleName)));
+
+    PrivilegeObject queryPrivilegeWithOption = new Builder()
+    .setComponent(SEARCH)
+    .setAction(SearchConstants.QUERY)
+    .setService(SERVICE)
+    .setAuthorizables(Arrays.asList(new Collection(COLLECTION_NAME)))
+    .withGrantOption(true)
+    .build();
+
+    sentryStore.alterRoleGrantPrivilege(SEARCH, roleName, 
queryPrivilegeWithOption, grantor);
+
+    assertEquals(Sets.newHashSet(queryPrivilege, queryPrivilegeWithOption),
+        sentryStore.getPrivilegesByRole(SEARCH, Sets.newHashSet(roleName)));
+
+    PrivilegeObject queryPrivilegeWithNoOption = new Builder()
+    .setComponent(SEARCH)
+    .setAction(SearchConstants.QUERY)
+    .setService(SERVICE)
+    .setAuthorizables(Arrays.asList(new Collection(COLLECTION_NAME)))
+    .withGrantOption(false)
+    .build();
+
+    sentryStore.alterRoleGrantPrivilege(SEARCH, roleName, 
queryPrivilegeWithNoOption, grantor);
+
+    assertEquals(Sets.newHashSet(queryPrivilege, queryPrivilegeWithOption, 
queryPrivilegeWithNoOption),
+        sentryStore.getPrivilegesByRole(SEARCH, Sets.newHashSet(roleName)));
+  }
+
+  @Test
+  public void testGrantPrivilegeTwice() throws Exception {
+    String roleName = "r1";
+    /**
+     * grantor is admin, there is no need to check grant option
+     */
+    String grantor = ADMIN_USER;
+    sentryStore.createRole(SEARCH, roleName, grantor);
+
+    PrivilegeObject queryPrivilegeWithOption = new Builder()
+    .setComponent(SEARCH)
+    .setAction(SearchConstants.QUERY)
+    .setService(SERVICE)
+    .setAuthorizables(Arrays.asList(new Collection(COLLECTION_NAME)))
+    .withGrantOption(true)
+    .build();
+
+    sentryStore.alterRoleGrantPrivilege(SEARCH, roleName, 
queryPrivilegeWithOption, grantor);
+    assertEquals(1,sentryStore.getPrivilegesByRole(SEARCH, 
Sets.newHashSet(roleName)).size());
+    //grant again
+    sentryStore.alterRoleGrantPrivilege(SEARCH, roleName, 
queryPrivilegeWithOption, grantor);
+    assertEquals(1,sentryStore.getPrivilegesByRole(SEARCH, 
Sets.newHashSet(roleName)).size());
+
+    PrivilegeObject queryPrivilegeWithNoOption = new Builder()
+    .setComponent(SEARCH)
+    .setAction(SearchConstants.QUERY)
+    .setService(SERVICE)
+    .setAuthorizables(Arrays.asList(new Collection(COLLECTION_NAME)))
+    .withGrantOption(false)
+    .build();
+
+    sentryStore.alterRoleGrantPrivilege(SEARCH, roleName, 
queryPrivilegeWithNoOption, grantor);
+    assertEquals(2,sentryStore.getPrivilegesByRole(SEARCH, 
Sets.newHashSet(roleName)).size());
+    //grant again
+    sentryStore.alterRoleGrantPrivilege(SEARCH, roleName, 
queryPrivilegeWithNoOption, grantor);
+    assertEquals(2,sentryStore.getPrivilegesByRole(SEARCH, 
Sets.newHashSet(roleName)).size());
+
+    PrivilegeObject queryPrivilegeWithNullGrant = new Builder()
+        .setComponent(SEARCH)
+        .setAction(SearchConstants.QUERY)
+        .setService(SERVICE)
+        .setAuthorizables(Arrays.asList(new Collection(COLLECTION_NAME)))
+        .withGrantOption(null)
+        .build();
+
+    sentryStore.alterRoleGrantPrivilege(SEARCH, roleName, 
queryPrivilegeWithNullGrant, grantor);
+
+    assertEquals(3,sentryStore.getPrivilegesByRole(SEARCH, 
Sets.newHashSet(roleName)).size());
+    //grant again
+    sentryStore.alterRoleGrantPrivilege(SEARCH, roleName, 
queryPrivilegeWithNullGrant, grantor);
+    assertEquals(3,sentryStore.getPrivilegesByRole(SEARCH, 
Sets.newHashSet(roleName)).size());
+
+  }
+
+  /**
+   * Grant query privilege to role r1 and there is ALL privilege related this
+   * collection existed
+   */
+  @Test
+  public void testGrantPrivilegeWithAllPrivilegeExist() throws Exception {
+    String roleName = "r1";
+    /**
+     * grantor is admin, there is no need to check grant option
+     */
+    String grantor = ADMIN_USER;
+    PrivilegeObject allPrivilege = new Builder()
+        .setComponent(SEARCH)
+        .setAction(SearchConstants.ALL)
+        .setService(SERVICE)
+        .setAuthorizables(Arrays.asList(new Collection(COLLECTION_NAME)))
+        .build();
+
+    sentryStore.createRole(SEARCH, roleName, grantor);
+    /**
+     * grant all privilege to role r1
+     */
+    sentryStore.alterRoleGrantPrivilege(SEARCH, roleName, allPrivilege, 
grantor);
+    /**
+     * check role r1 truly has the privilege been granted
+     */
+    assertEquals(Sets.newHashSet(allPrivilege),
+        sentryStore.getPrivilegesByRole(SEARCH, Sets.newHashSet(roleName)));
+
+    PrivilegeObject queryPrivilege = new Builder(allPrivilege)
+        .setAction(SearchConstants.QUERY)
+        .build();
+
+    /**
+     * grant query privilege to role r1
+     */
+    sentryStore.alterRoleGrantPrivilege(SEARCH, roleName, queryPrivilege, 
grantor);
+    /**
+     * all privilege has been existed, the query privilege will not persistent
+     */
+    assertEquals(Sets.newHashSet(allPrivilege),
+        sentryStore.getPrivilegesByRole(SEARCH, Sets.newHashSet(roleName)));
+  }
+
+  /**
+   * Grant query privilege to role r1 and there are query and update privileges
+   * related this collection existed
+   */
+  @Test
+  public void testGrantALLPrivilegeWithOtherPrivilegesExist() throws Exception 
{
+    String roleName1 = "r1";
+    String roleName2 = "r2";
+    /**
+     * grantor is admin, there is no need to check grant option
+     */
+    String grantor = ADMIN_USER;
+
+    PrivilegeObject queryPrivilege = new Builder()
+        .setComponent(SEARCH)
+        .setAction(SearchConstants.QUERY)
+        .setService(SERVICE)
+        .setAuthorizables(Arrays.asList(new Collection(COLLECTION_NAME)))
+        .build();
+
+    PrivilegeObject updatePrivilege = new Builder(queryPrivilege)
+        .setAction(SearchConstants.UPDATE)
+        .build();
+
+    sentryStore.createRole(SEARCH, roleName1, grantor);
+    sentryStore.createRole(SEARCH, roleName2, grantor);
+    /**
+     * grant query and update privilege to role r1 and role r2
+     */
+    sentryStore.alterRoleGrantPrivilege(SEARCH, roleName1, queryPrivilege, 
grantor);
+    sentryStore.alterRoleGrantPrivilege(SEARCH, roleName1, 
updatePrivilege,grantor);
+    assertEquals(Sets.newHashSet(queryPrivilege, updatePrivilege),
+        sentryStore.getPrivilegesByRole(SEARCH, Sets.newHashSet(roleName1)));
+
+    sentryStore.alterRoleGrantPrivilege(SEARCH, roleName2, queryPrivilege, 
grantor);
+    sentryStore.alterRoleGrantPrivilege(SEARCH, roleName2, 
updatePrivilege,grantor);
+    assertEquals(Sets.newHashSet(queryPrivilege, updatePrivilege),
+        sentryStore.getPrivilegesByRole(SEARCH, Sets.newHashSet(roleName2)));
+
+    PrivilegeObject allPrivilege = new Builder(queryPrivilege)
+        .setAction(SearchConstants.ALL)
+        .build();
+
+    /**
+     * grant all privilege to role r1
+     */
+    sentryStore.alterRoleGrantPrivilege(SEARCH, roleName1, allPrivilege, 
grantor);
+
+    /**
+     * check the query and update privileges of roleName1 will be removed 
because of ALl privilege
+     * granted
+     */
+    assertEquals(Sets.newHashSet(allPrivilege),
+        sentryStore.getPrivilegesByRole(SEARCH, Sets.newHashSet(roleName1)));
+
+    /**
+     * check the query and update privileges of roleName2 will not affected 
and exist
+     */
+    assertEquals(Sets.newHashSet(queryPrivilege, updatePrivilege),
+        sentryStore.getPrivilegesByRole(SEARCH, Sets.newHashSet(roleName2)));
+  }
+
+  @Test
+  public void testGrantRevokeCheckWithGrantOption() throws Exception {
+
+    addGroupsToUser(GRANT_OPTION_USER, GRANT_OPTION_GROUP);
+    addGroupsToUser(NO_GRANT_OPTION_USER, NO_GRANT_OPTION_GROUP);
+    writePolicyFile();
+
+    String roleName1 = "r1";
+    String roleName2 = "r2";
+    String grantor = "g1";
+    sentryStore.createRole(SEARCH, roleName1, grantor);
+    sentryStore.createRole(SEARCH, roleName2, grantor);
+    /**
+     * grant query privilege to role r1 with grant option
+     */
+    PrivilegeObject queryPrivilege1 = new Builder()
+        .setComponent(SEARCH)
+        .setAction(SearchConstants.QUERY)
+        .setService(SERVICE)
+        .setAuthorizables(Arrays.asList(new Collection(COLLECTION_NAME)))
+        .withGrantOption(true)
+        .build();
+
+    sentryStore.alterRoleGrantPrivilege(SEARCH, roleName1, queryPrivilege1,
+        ADMIN_USER);
+    assertEquals(Sets.newHashSet(queryPrivilege1),
+        sentryStore.getPrivilegesByRole(SEARCH, Sets.newHashSet(roleName1)));
+    /**
+     * grant query privilege to role r2 no grant option
+     */
+    PrivilegeObject queryPrivilege2 = new Builder()
+        .setComponent(SEARCH)
+        .setAction(SearchConstants.QUERY)
+        .setService(SERVICE)
+        .setAuthorizables(Arrays.asList(new Collection(COLLECTION_NAME)))
+        .withGrantOption(false).build();
+
+    sentryStore.alterRoleGrantPrivilege(SEARCH, roleName2, queryPrivilege2,
+        ADMIN_USER);
+    assertEquals(Sets.newHashSet(queryPrivilege2),
+        sentryStore.getPrivilegesByRole(SEARCH, Sets.newHashSet(roleName2)));
+
+    sentryStore.alterRoleAddGroups(SEARCH, roleName1,
+        Sets.newHashSet(GRANT_OPTION_GROUP), grantor);
+    sentryStore.alterRoleAddGroups(SEARCH, roleName2,
+        Sets.newHashSet(NO_GRANT_OPTION_GROUP), grantor);
+
+    String roleName3 = "r3";
+    sentryStore.createRole(SEARCH, roleName3, grantor);
+    /**
+     * the user with grant option grant query privilege to rolr r3
+     */
+    try{
+      sentryStore.alterRoleGrantPrivilege(SEARCH, roleName3, queryPrivilege1,
+          GRANT_OPTION_USER);
+    } catch (SentryGrantDeniedException e) {
+      fail("SentryGrantDeniedException shouldn't have been thrown");
+    }
+
+    /**
+     * the user with grant option revoke query privilege to rolr r3
+     */
+    try{
+      sentryStore.alterRoleRevokePrivilege(SEARCH, roleName3, queryPrivilege1,
+          GRANT_OPTION_USER);
+    } catch (SentryGrantDeniedException e) {
+      fail("SentryGrantDeniedException shouldn't have been thrown");
+    }
+
+    /**
+     * the user with no grant option grant query privilege to rolr r3, it will
+     * throw SentryGrantDeniedException
+     */
+    try {
+      sentryStore.alterRoleGrantPrivilege(SEARCH, roleName3, queryPrivilege2,
+          NO_GRANT_OPTION_USER);
+      fail("SentryGrantDeniedException should have been thrown");
+    } catch (SentryGrantDeniedException e) {
+      //ignore the exception
+    }
+
+    /**
+     * the user with no grant option revoke query privilege to rolr r3, it will
+     * throw SentryGrantDeniedException
+     */
+    try {
+      sentryStore.alterRoleGrantPrivilege(SEARCH, roleName3, queryPrivilege2,
+          NO_GRANT_OPTION_USER);
+      fail("SentryGrantDeniedException should have been thrown");
+    } catch (SentryGrantDeniedException e) {
+      //ignore the exception
+    }
+  }
+
+  @Test
+  public void testGrantWithGrantOption() throws Exception {
+
+    addGroupsToUser(GRANT_OPTION_USER, GRANT_OPTION_GROUP);
+    addGroupsToUser(NO_GRANT_OPTION_USER, NO_GRANT_OPTION_GROUP);
+    writePolicyFile();
+
+    String roleName1 = "r1";
+    String grantor = "g1";
+    sentryStore.createRole(SEARCH, roleName1, grantor);
+    /**
+     * grant query privilege to role r1 with grant option
+     */
+    PrivilegeObject queryPrivilege = new Builder()
+        .setComponent(SEARCH)
+        .setAction(SearchConstants.QUERY)
+        .setService(SERVICE)
+        .setAuthorizables(Arrays.asList(new Collection(COLLECTION_NAME)))
+        .withGrantOption(true)
+        .build();
+
+    sentryStore.alterRoleGrantPrivilege(SEARCH, roleName1, 
queryPrivilege,ADMIN_USER);
+    sentryStore.alterRoleAddGroups(SEARCH, roleName1,
+        Sets.newHashSet(GRANT_OPTION_GROUP), grantor);
+
+    /**
+     * the user with grant option grant query privilege to rolr r2
+     */
+    String roleName2 = "r2";
+    sentryStore.createRole(SEARCH, roleName2, grantor);
+    sentryStore.alterRoleGrantPrivilege(SEARCH, roleName2, queryPrivilege, 
GRANT_OPTION_USER);
+
+    assertEquals(Sets.newHashSet(queryPrivilege),
+        sentryStore.getPrivilegesByRole(SEARCH, Sets.newHashSet(roleName2)));
+
+  }
+
+
+  /**
+   * Grant query and update privileges to role r1 and revoke query privilege
+   * there is left update privilege related to role r1
+   */
+  @Test
+  public void testRevokePrivilege() throws Exception {
+    String roleName = "r1";
+    /**
+     * grantor is admin, there is no need to check grant option
+     */
+    String grantor = ADMIN_USER;
+    PrivilegeObject queryPrivilege = new Builder()
+        .setComponent(SEARCH)
+        .setAction(SearchConstants.QUERY)
+        .setService(SERVICE)
+        .setAuthorizables(Arrays.asList(new Collection(COLLECTION_NAME), new 
Field(FIELD_NAME)))
+        .build();
+
+    PrivilegeObject updatePrivilege = new Builder(queryPrivilege)
+        .setAction(SearchConstants.UPDATE)
+        .build();
+
+    sentryStore.createRole(SEARCH, roleName, grantor);
+    sentryStore.alterRoleGrantPrivilege(SEARCH, roleName, queryPrivilege, 
grantor);
+    sentryStore.alterRoleGrantPrivilege(SEARCH, roleName, updatePrivilege, 
grantor);
+
+    assertEquals(Sets.newHashSet(queryPrivilege,updatePrivilege),
+        sentryStore.getPrivilegesByRole(SEARCH, Sets.newHashSet(roleName)));
+    /**
+     * revoke query privilege
+     */
+    sentryStore.alterRoleRevokePrivilege(SEARCH, roleName, queryPrivilege, 
grantor);
+    assertEquals(Sets.newHashSet(updatePrivilege),
+        sentryStore.getPrivilegesByRole(SEARCH, Sets.newHashSet(roleName)));
+  }
+
+  /**
+   * Grant query and update privileges to role r1 and revoke all privilege,
+   * there is no privilege related to role r1
+   */
+  @Test
+  public void testRevokeAllPrivilege() throws Exception {
+    String roleName = "r1";
+    /**
+     * grantor is admin, there is no need to check grant option
+     */
+    String grantor = ADMIN_USER;
+    PrivilegeObject queryPrivilege = new Builder()
+        .setComponent(SEARCH)
+        .setAction(SearchConstants.QUERY)
+        .setService(SERVICE)
+        .setAuthorizables(Arrays.asList(new Collection(COLLECTION_NAME),new 
Field(FIELD_NAME)))
+        .build();
+
+    PrivilegeObject updatePrivilege = new Builder(queryPrivilege)
+        .setAction(SearchConstants.UPDATE)
+        .build();
+
+    sentryStore.createRole(SEARCH, roleName, grantor);
+
+    sentryStore.alterRoleGrantPrivilege(SEARCH, roleName, queryPrivilege, 
grantor);
+    sentryStore.alterRoleGrantPrivilege(SEARCH, roleName, updatePrivilege, 
grantor);
+
+    assertEquals(Sets.newHashSet(queryPrivilege,updatePrivilege),
+        sentryStore.getPrivilegesByRole(SEARCH, Sets.newHashSet(roleName)));
+    /**
+     * revoke all privilege
+     */
+    PrivilegeObject allPrivilege = new Builder(queryPrivilege)
+        .setAction(SearchConstants.ALL)
+        .build();
+
+    sentryStore.alterRoleRevokePrivilege(SEARCH, roleName, allPrivilege, 
grantor);
+
+    assertEquals(Sets.newHashSet(),
+        sentryStore.getPrivilegesByRole(SEARCH, Sets.newHashSet(roleName)));
+  }
+
+  /**
+   * Grant all privilege to role r1 and revoke query privilege
+   * there is update privilege related to role r1
+   */
+  @Test
+  public void testRevokePrivilegeWithAllPrivilegeExist() throws Exception {
+    String roleName = "r1";
+    /**
+     * grantor is admin, there is no need to check grant option
+     */
+    String grantor = ADMIN_USER;
+    PrivilegeObject allPrivilege = new Builder()
+        .setComponent(SEARCH)
+        .setAction(SearchConstants.QUERY)
+        .setService(SERVICE)
+        .setAuthorizables(Arrays.asList(new Collection(COLLECTION_NAME), new 
Field(FIELD_NAME)))
+        .build();
+
+    sentryStore.createRole(SEARCH, roleName, grantor);
+
+    sentryStore.alterRoleGrantPrivilege(SEARCH, roleName, allPrivilege, 
grantor);
+
+    assertEquals(Sets.newHashSet(allPrivilege),
+        sentryStore.getPrivilegesByRole(SEARCH, Sets.newHashSet(roleName)));
+    /**
+     * revoke update privilege
+     */
+    PrivilegeObject updatePrivilege = new Builder(allPrivilege)
+        .setAction(SearchConstants.UPDATE)
+        .build();
+
+    PrivilegeObject queryPrivilege = new Builder(allPrivilege)
+        .setAction(SearchConstants.QUERY)
+        .build();
+
+    sentryStore.alterRoleRevokePrivilege(SEARCH, roleName, updatePrivilege, 
grantor);
+
+    assertEquals(Sets.newHashSet(queryPrivilege),
+        sentryStore.getPrivilegesByRole(SEARCH, Sets.newHashSet(roleName)));
+  }
+
+  @Test
+  public void testRevokeParentPrivilegeWithChildsExist() throws Exception {
+    String roleName = "r1";
+    /**
+     * grantor is admin, there is no need to check grant option
+     */
+    String grantor = ADMIN_USER;
+    PrivilegeObject updatePrivilege1 = new Builder()
+        .setComponent(SEARCH)
+        .setAction(SearchConstants.UPDATE)
+        .setService(SERVICE)
+        .setAuthorizables(Arrays.asList(new Collection(COLLECTION_NAME), new 
Field(FIELD_NAME)))
+        .build();
+
+    PrivilegeObject queryPrivilege1 = new Builder()
+        .setComponent(SEARCH)
+        .setAction(SearchConstants.QUERY)
+        .setService(SERVICE)
+        .setAuthorizables(Arrays.asList(new Collection(COLLECTION_NAME),new 
Field(FIELD_NAME)))
+        .build();
+
+    PrivilegeObject queryPrivilege2 = new Builder()
+        .setComponent(SEARCH)
+        .setAction(SearchConstants.QUERY)
+        .setService(SERVICE)
+        .setAuthorizables(Arrays.asList(new Collection(NOT_COLLECTION_NAME)))
+        .build();
+
+    sentryStore.createRole(SEARCH, roleName, grantor);
+    sentryStore.alterRoleGrantPrivilege(SEARCH, roleName, updatePrivilege1, 
grantor);
+    sentryStore.alterRoleGrantPrivilege(SEARCH, roleName, queryPrivilege1, 
grantor);
+
+    sentryStore.alterRoleGrantPrivilege(SEARCH, roleName, queryPrivilege2, 
grantor);
+
+    /**
+     * revoke all privilege with collection[COLLECTION_NAME=collection1] and 
its child privileges
+     */
+    PrivilegeObject allPrivilege = new Builder()
+        .setComponent(SEARCH)
+        .setAction(SearchConstants.ALL)
+        .setService(SERVICE)
+        .setAuthorizables(Arrays.asList(new Collection(COLLECTION_NAME)))
+        .build();
+
+    sentryStore.alterRoleRevokePrivilege(SEARCH, roleName, allPrivilege, 
grantor);
+    assertEquals(Sets.newHashSet(queryPrivilege2),
+        sentryStore.getPrivilegesByRole(SEARCH, Sets.newHashSet(roleName)));
+  }
+
+  @Test
+  public void testRevokeWithGrantOption() throws Exception {
+
+    addGroupsToUser(GRANT_OPTION_USER, GRANT_OPTION_GROUP);
+    addGroupsToUser(NO_GRANT_OPTION_USER, NO_GRANT_OPTION_GROUP);
+    writePolicyFile();
+
+    String roleName1 = "r1";
+    String grantor = "g1";
+    sentryStore.createRole(SEARCH, roleName1, grantor);
+    /**
+     * grant query privilege to role r1 with grant option
+     */
+    PrivilegeObject queryPrivilege = new Builder()
+        .setComponent(SEARCH)
+        .setAction(SearchConstants.QUERY)
+        .setService(SERVICE)
+        .setAuthorizables(Arrays.asList(new Collection(COLLECTION_NAME)))
+        .withGrantOption(true)
+        .build();
+
+    sentryStore.alterRoleGrantPrivilege(SEARCH, roleName1, queryPrivilege,
+        ADMIN_USER);
+    assertEquals(Sets.newHashSet(queryPrivilege),
+        sentryStore.getPrivilegesByRole(SEARCH, Sets.newHashSet(roleName1)));
+
+    sentryStore.alterRoleAddGroups(SEARCH, roleName1,
+        Sets.newHashSet(GRANT_OPTION_GROUP), grantor);
+
+    String roleName2 = "r2";
+    sentryStore.createRole(SEARCH, roleName2, grantor);
+    /**
+     * the user with grant option grant query privilege to rolr r2
+     */
+    sentryStore.alterRoleGrantPrivilege(SEARCH, roleName2, queryPrivilege,
+        GRANT_OPTION_USER);
+    assertEquals(Sets.newHashSet(queryPrivilege),
+        sentryStore.getPrivilegesByRole(SEARCH, Sets.newHashSet(roleName2)));
+
+    /**
+     * the user with grant option revoke query privilege to rolr r3
+     */
+    sentryStore.alterRoleRevokePrivilege(SEARCH, roleName2, queryPrivilege, 
GRANT_OPTION_USER);
+    assertEquals(Sets.newHashSet(),
+        sentryStore.getPrivilegesByRole(SEARCH, Sets.newHashSet(roleName2)));
+  }
+
+  @Test
+  public void testDropPrivilege() throws Exception{
+    String roleName1 = "r1";
+    String roleName2 = "r2";
+    String grantor = ADMIN_USER;
+
+    PrivilegeObject queryPrivilege = new Builder()
+        .setComponent(SEARCH)
+        .setAction(SearchConstants.QUERY)
+        .setService(SERVICE)
+        .setAuthorizables(Arrays.asList(new Collection(COLLECTION_NAME), new 
Field(FIELD_NAME)))
+        .build();
+
+    PrivilegeObject updatePrivilege = new Builder(queryPrivilege)
+        .setAction(SearchConstants.UPDATE)
+        .build();
+
+    /**
+     * grant query and update privilege to role r1 and r2
+     */
+    sentryStore.createRole(SEARCH, roleName1, grantor);
+    sentryStore.alterRoleGrantPrivilege(SEARCH, roleName1, queryPrivilege, 
grantor);
+    sentryStore.alterRoleGrantPrivilege(SEARCH, roleName1, updatePrivilege, 
grantor);
+
+    sentryStore.createRole(SEARCH, roleName2, grantor);
+    sentryStore.alterRoleGrantPrivilege(SEARCH, roleName2, queryPrivilege, 
grantor);
+    sentryStore.alterRoleGrantPrivilege(SEARCH, roleName2, updatePrivilege, 
grantor);
+
+    assertEquals(Sets.newHashSet(queryPrivilege,updatePrivilege),
+        sentryStore.getPrivilegesByRole(SEARCH, Sets.newHashSet(roleName1)));
+
+    assertEquals(Sets.newHashSet(queryPrivilege,updatePrivilege),
+        sentryStore.getPrivilegesByRole(SEARCH, Sets.newHashSet(roleName2)));
+    /**
+     * drop query privilege
+     */
+    sentryStore.dropPrivilege(SEARCH, queryPrivilege, grantor);
+
+    assertEquals(Sets.newHashSet(updatePrivilege),
+        sentryStore.getPrivilegesByRole(SEARCH, Sets.newHashSet(roleName1)));
+
+    assertEquals(Sets.newHashSet(updatePrivilege),
+        sentryStore.getPrivilegesByRole(SEARCH, Sets.newHashSet(roleName2)));
+
+    /**
+     * drop ALL privilege
+     */
+    PrivilegeObject allPrivilege = new Builder(queryPrivilege)
+        .setAction(SearchConstants.ALL)
+        .build();
+
+    sentryStore.dropPrivilege(SEARCH, allPrivilege, grantor);
+
+    assertEquals(Sets.newHashSet(),
+        sentryStore.getPrivilegesByRole(SEARCH, Sets.newHashSet(roleName1)));
+
+    assertEquals(Sets.newHashSet(),
+        sentryStore.getPrivilegesByRole(SEARCH, Sets.newHashSet(roleName2)));
+
+    /**
+     * grant query and update field scope[collection1,field1] privilege to 
role r1
+     * drop collection scope[collection1] privilege
+     * there is no privilege
+     */
+    sentryStore.alterRoleGrantPrivilege(SEARCH, roleName1, queryPrivilege, 
grantor);
+    sentryStore.alterRoleGrantPrivilege(SEARCH, roleName1, updatePrivilege, 
grantor);
+
+    PrivilegeObject parentPrivilege = new Builder()
+        .setComponent(SEARCH)
+        .setAction(SearchConstants.ALL)
+        .setService(SERVICE)
+        .setAuthorizables(Arrays.asList(new Collection(COLLECTION_NAME)))
+        .build();
+
+    sentryStore.dropPrivilege(SEARCH, parentPrivilege, grantor);
+    assertEquals(Sets.newHashSet(),
+        sentryStore.getPrivilegesByRole(SEARCH, Sets.newHashSet(roleName1)));
+  }
+
+  @Test
+  public void testRenamePrivilege() throws Exception{
+    String roleName1 = "r1";
+    String roleName2 = "r2";
+    String grantor = ADMIN_USER;
+
+    List<? extends Authorizable> oldAuthoriables = Arrays.asList(new 
Collection(COLLECTION_NAME), new Field(FIELD_NAME));
+    List<? extends Authorizable> newAuthoriables = Arrays.asList(new 
Collection(COLLECTION_NAME), new Field(NOT_FIELD_NAME));
+
+    PrivilegeObject oldQueryPrivilege = new Builder()
+        .setComponent(SEARCH)
+        .setAction(SearchConstants.QUERY)
+        .setService(SERVICE)
+        .setAuthorizables(oldAuthoriables)
+        .build();
+
+    PrivilegeObject oldUpdatePrivilege = new Builder(oldQueryPrivilege)
+        .setAction(SearchConstants.UPDATE)
+        .build();
+
+    PrivilegeObject oldALLPrivilege = new Builder(oldQueryPrivilege)
+        .setAction(SearchConstants.ALL)
+        .build();
+
+
+    PrivilegeObject newQueryPrivilege = new Builder()
+        .setComponent(SEARCH)
+        .setAction(SearchConstants.QUERY)
+        .setService(SERVICE)
+        .setAuthorizables(newAuthoriables)
+        .build();
+
+    PrivilegeObject newUpdatePrivilege = new Builder(newQueryPrivilege)
+        .setAction(SearchConstants.UPDATE)
+        .build();
+
+    PrivilegeObject newALLPrivilege = new Builder(newQueryPrivilege)
+        .setAction(SearchConstants.ALL)
+        .build();
+
+
+    /**
+     * grant query and update privilege to role r1
+     * grant all privilege to role r2
+     */
+    sentryStore.createRole(SEARCH, roleName1, grantor);
+    sentryStore.alterRoleGrantPrivilege(SEARCH, roleName1, oldQueryPrivilege, 
grantor);
+    sentryStore.alterRoleGrantPrivilege(SEARCH, roleName1, oldUpdatePrivilege, 
grantor);
+
+    sentryStore.createRole(SEARCH, roleName2, grantor);
+    sentryStore.alterRoleGrantPrivilege(SEARCH, roleName2, oldALLPrivilege, 
grantor);
+
+    assertEquals(Sets.newHashSet(oldQueryPrivilege,oldUpdatePrivilege),
+        sentryStore.getPrivilegesByRole(SEARCH, Sets.newHashSet(roleName1)));
+
+    assertEquals(Sets.newHashSet(oldALLPrivilege),
+        sentryStore.getPrivilegesByRole(SEARCH, Sets.newHashSet(roleName2)));
+    /**
+     * rename old query privilege to new query privilege
+     */
+    sentryStore.renamePrivilege(SEARCH, SERVICE,
+                                      oldAuthoriables,
+                                      newAuthoriables,
+                                      grantor);
+
+    assertEquals(Sets.newHashSet(newQueryPrivilege,newUpdatePrivilege),
+        sentryStore.getPrivilegesByRole(SEARCH, Sets.newHashSet(roleName1)));
+
+    assertEquals(Sets.newHashSet(newALLPrivilege),
+        sentryStore.getPrivilegesByRole(SEARCH, Sets.newHashSet(roleName2)));
+    /**
+     * rename collection scope[collection=collection1] privilege to 
[collection=not_collection1]
+     * These privileges belong to collection scope[collection=collection1] 
will change to
+     * [collection=not_collection1]
+     */
+
+    List<? extends Authorizable> newAuthoriables1 = Arrays.asList(new 
Collection(NOT_COLLECTION_NAME),new Field(NOT_FIELD_NAME));
+
+    PrivilegeObject newQueryPrivilege1 = new Builder(newQueryPrivilege)
+          .setAuthorizables(newAuthoriables1)
+          .build();
+
+    PrivilegeObject newUpdatePrivilege1 = new Builder(newUpdatePrivilege)
+          .setAuthorizables(newAuthoriables1)
+          .build();
+
+    PrivilegeObject newALLPrivilege1 = new Builder(newALLPrivilege)
+          .setAuthorizables(newAuthoriables1)
+          .build();
+
+    sentryStore.renamePrivilege(SEARCH, SERVICE,
+        Arrays.asList(new Collection(COLLECTION_NAME)),
+        Arrays.asList(new Collection(NOT_COLLECTION_NAME)),
+        grantor);
+
+    assertEquals(Sets.newHashSet(newQueryPrivilege1,newUpdatePrivilege1),
+        sentryStore.getPrivilegesByRole(SEARCH, Sets.newHashSet(roleName1)));
+
+    assertEquals(Sets.newHashSet(newALLPrivilege1),
+        sentryStore.getPrivilegesByRole(SEARCH, Sets.newHashSet(roleName2)));
+  }
+
+  @Test
+  public void testGetPrivilegesByRoleName() throws Exception {
+    String roleName1 = "r1";
+    String roleName2 = "r2";
+    String grantor = "g1";
+
+    PrivilegeObject queryPrivilege = new Builder()
+        .setComponent(SEARCH)
+        .setAction(SearchConstants.QUERY)
+        .setService(SERVICE)
+        .setAuthorizables(Arrays.asList(new Collection(COLLECTION_NAME)))
+        .build();
+
+    sentryStore.createRole(SEARCH, roleName1, grantor);
+    sentryStore.alterRoleGrantPrivilege(SEARCH, roleName1, queryPrivilege,
+        ADMIN_USER);
+
+    PrivilegeObject updatePrivilege = new Builder()
+        .setComponent(SEARCH)
+        .setAction(SearchConstants.QUERY)
+        .setService(SERVICE)
+        .setAuthorizables(Arrays.asList(new Collection(COLLECTION_NAME)))
+        .build();
+
+    sentryStore.createRole(SEARCH, roleName2, grantor);
+    sentryStore.alterRoleGrantPrivilege(SEARCH, roleName2, updatePrivilege,
+        ADMIN_USER);
+
+    assertEquals(Sets.newHashSet(queryPrivilege,updatePrivilege),
+        sentryStore.getPrivilegesByRole(SEARCH, 
Sets.newHashSet(roleName1,roleName2)));
+
+  }
+
+  @Test
+  public void testGetPrivilegesByProvider() throws Exception {
+    String roleName1 = "r1";
+    String roleName2 = "r2";
+    String roleName3 = "r3";
+    String group = "g3";
+    String grantor = ADMIN_USER;
+
+    String service1 = "service1";
+
+    PrivilegeObject queryPrivilege1 = new Builder()
+         .setComponent(SEARCH)
+         .setAction(SearchConstants.QUERY)
+         .setService(service1)
+         .setAuthorizables(Arrays.asList(new Collection(COLLECTION_NAME)))
+         .build();
+
+    PrivilegeObject updatePrivilege1 = new Builder()
+         .setComponent(SEARCH)
+         .setAction(SearchConstants.UPDATE)
+         .setService(service1)
+         .setAuthorizables(Arrays.asList(new Collection(COLLECTION_NAME), new 
Field(FIELD_NAME)))
+         .build();
+
+    PrivilegeObject queryPrivilege2 = new Builder()
+         .setComponent(SEARCH)
+         .setAction(SearchConstants.QUERY)
+         .setService(service1)
+         .setAuthorizables(Arrays.asList(new Collection(COLLECTION_NAME)))
+         .build();
+
+    PrivilegeObject updatePrivilege2 = new Builder()
+         .setComponent(SEARCH)
+         .setAction(SearchConstants.UPDATE)
+         .setService(service1)
+         .setAuthorizables(Arrays.asList(new Collection(COLLECTION_NAME), new 
Field(FIELD_NAME)))
+         .build();
+
+    sentryStore.createRole(SEARCH, roleName1, grantor);
+    sentryStore.createRole(SEARCH, roleName2, grantor);
+    sentryStore.createRole(SEARCH, roleName3, grantor);
+
+    sentryStore.alterRoleAddGroups(SEARCH, roleName3, Sets.newHashSet(group), 
grantor);
+
+    sentryStore.alterRoleGrantPrivilege(SEARCH, roleName1, queryPrivilege1, 
grantor);
+    sentryStore.alterRoleGrantPrivilege(SEARCH, roleName1, updatePrivilege1, 
grantor);
+    sentryStore.alterRoleGrantPrivilege(SEARCH, roleName2, queryPrivilege2, 
grantor);
+    sentryStore.alterRoleGrantPrivilege(SEARCH, roleName3, updatePrivilege2, 
grantor);
+
+    assertEquals(Sets.newHashSet(updatePrivilege1, queryPrivilege1),
+        sentryStore.getPrivilegesByProvider(SEARCH, service1, 
Sets.newHashSet(roleName1), null, null));
+
+    assertEquals(Sets.newHashSet(updatePrivilege1, queryPrivilege1, 
queryPrivilege2),
+        sentryStore.getPrivilegesByProvider(SEARCH, service1, 
Sets.newHashSet(roleName1,roleName2),
+            null, null));
+
+    assertEquals(Sets.newHashSet(updatePrivilege1, queryPrivilege1, 
queryPrivilege2, updatePrivilege2),
+        sentryStore.getPrivilegesByProvider(SEARCH, service1, 
Sets.newHashSet(roleName1,roleName2),
+            Sets.newHashSet(group), null));
+
+    List<? extends Authorizable> authorizables = Arrays.asList(new 
Collection(COLLECTION_NAME), new Field(FIELD_NAME));
+    assertEquals(Sets.newHashSet(updatePrivilege1, updatePrivilege2),
+        sentryStore.getPrivilegesByProvider(SEARCH, service1, 
Sets.newHashSet(roleName1,roleName2),
+            Sets.newHashSet(group), authorizables));
+  }
+}

http://git-wip-us.apache.org/repos/asf/incubator-sentry/blob/bf3eb482/sentry-provider/sentry-provider-db/src/test/java/org/apache/sentry/provider/db/generic/service/persistent/TestSentryGMPrivilege.java
----------------------------------------------------------------------
diff --git 
a/sentry-provider/sentry-provider-db/src/test/java/org/apache/sentry/provider/db/generic/service/persistent/TestSentryGMPrivilege.java
 
b/sentry-provider/sentry-provider-db/src/test/java/org/apache/sentry/provider/db/generic/service/persistent/TestSentryGMPrivilege.java
new file mode 100644
index 0000000..1411692
--- /dev/null
+++ 
b/sentry-provider/sentry-provider-db/src/test/java/org/apache/sentry/provider/db/generic/service/persistent/TestSentryGMPrivilege.java
@@ -0,0 +1,207 @@
+/**
+ * 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.service.persistent;
+
+import static junit.framework.Assert.assertTrue;
+import static junit.framework.Assert.assertFalse;
+import static junit.framework.Assert.fail;
+
+import java.util.Arrays;
+
+import org.apache.sentry.core.model.db.AccessConstants;
+import org.apache.sentry.core.model.search.Collection;
+import org.apache.sentry.core.model.search.Field;
+import org.apache.sentry.core.model.search.SearchConstants;
+import org.apache.sentry.provider.db.service.model.MSentryGMPrivilege;
+import org.junit.Test;
+
+public class TestSentryGMPrivilege {
+
+  @Test
+  public void testValidateAuthorizables() throws Exception {
+    try {
+      MSentryGMPrivilege fieldPrivilege = new MSentryGMPrivilege("solr",
+          "service1", Arrays.asList(new Collection("c1"), new 
Field("f1")),SearchConstants.QUERY, false);
+    } catch (IllegalStateException e) {
+      fail("unexpect happend: it is a validated privilege");
+    }
+
+    try {
+      MSentryGMPrivilege collectionPrivilege = new MSentryGMPrivilege("solr",
+          "service1", Arrays.asList(new Collection(""), new 
Field("f1")),SearchConstants.QUERY, false);
+      fail("unexpect happend: it is not a validated privilege, The empty name 
of authorizable can't be empty");
+    } catch (IllegalStateException e) {
+    }
+
+    try {
+      MSentryGMPrivilege fieldPrivilege = new MSentryGMPrivilege("solr",
+          "service1", Arrays.asList(null, new 
Field("f1")),SearchConstants.QUERY, false);
+      fail("unexpect happend: it is not a validated privilege, The 
authorizable can't be null");
+    } catch (IllegalStateException e) {
+    }
+  }
+
+  @Test
+  public void testImpliesWithServerScope() throws Exception {
+    //The persistent privilege is server scope
+    MSentryGMPrivilege serverPrivilege = new MSentryGMPrivilege("solr",
+        "service1", null,SearchConstants.QUERY, false);
+
+    MSentryGMPrivilege collectionPrivilege = new MSentryGMPrivilege("solr",
+        "service1", Arrays.asList(new Collection("c1")),
+        SearchConstants.QUERY, false);
+    assertTrue(serverPrivilege.implies(collectionPrivilege));
+
+    MSentryGMPrivilege fieldPrivilege = new MSentryGMPrivilege("solr",
+        "service1", Arrays.asList(new Collection("c1"), new Field("f1")),
+        SearchConstants.QUERY, false);
+    assertTrue(serverPrivilege.implies(fieldPrivilege));
+    assertTrue(collectionPrivilege.implies(fieldPrivilege));
+
+    serverPrivilege.setAction(SearchConstants.UPDATE);
+    assertFalse(serverPrivilege.implies(collectionPrivilege));
+    assertFalse(serverPrivilege.implies(fieldPrivilege));
+
+    serverPrivilege.setAction(SearchConstants.ALL);
+    assertTrue(serverPrivilege.implies(collectionPrivilege));
+    assertTrue(serverPrivilege.implies(fieldPrivilege));
+  }
+  /**
+   * The requested privilege has the different authorizable size with the 
persistent privilege
+   * @throws Exception
+   */
+  @Test
+  public void testImpliesDifferentAuthorizable() throws Exception {
+    /**
+     * Test the scope of persistent privilege is the larger than the requested 
privilege
+     */
+    MSentryGMPrivilege serverPrivilege = new MSentryGMPrivilege("solr",
+        "service1", null, SearchConstants.QUERY, false);
+
+    MSentryGMPrivilege collectionPrivilege = new MSentryGMPrivilege("solr",
+        "service1", Arrays.asList(new Collection("c1")),
+        SearchConstants.QUERY, false);
+
+    MSentryGMPrivilege fieldPrivilege = new MSentryGMPrivilege("solr",
+        "service1", Arrays.asList(new Collection("c1"), new Field("f1")),
+        SearchConstants.QUERY, false);
+    assertTrue(serverPrivilege.implies(collectionPrivilege));
+    assertTrue(serverPrivilege.implies(fieldPrivilege));
+    assertTrue(collectionPrivilege.implies(fieldPrivilege));
+    /**
+     * Test the scope of persistent privilege is less than  the request 
privilege
+     */
+    assertFalse(fieldPrivilege.implies(collectionPrivilege));
+    assertFalse(fieldPrivilege.implies(serverPrivilege));
+    assertFalse(collectionPrivilege.implies(serverPrivilege));
+
+    /**
+     * Test the scope of persistent privilege is less than  the request 
privilege,
+     * but the name of left authorizable is ALL
+     */
+    MSentryGMPrivilege fieldAllPrivilege = new MSentryGMPrivilege("solr",
+        "service1", Arrays.asList(new Collection("c1"), new 
Field(AccessConstants.ALL)),
+        SearchConstants.QUERY, false);
+
+    assertTrue(fieldAllPrivilege.implies(collectionPrivilege));
+
+    /**
+     * Test the scope of persistent privilege has the same scope as request 
privilege
+     */
+    MSentryGMPrivilege fieldPrivilege1 = new MSentryGMPrivilege("solr",
+        "service1", Arrays.asList(new Collection("c1"), new Field("f1")),
+        SearchConstants.QUERY, false);
+
+    MSentryGMPrivilege fieldPrivilege2 = new MSentryGMPrivilege("solr",
+        "service1", Arrays.asList(new Collection("c2"), new Field("f2")),
+        SearchConstants.QUERY, false);
+    assertFalse(fieldPrivilege1.implies(fieldPrivilege2));
+  }
+
+  /**
+   * The requested privilege has the same authorizable size as with the 
persistent privilege
+   * @throws Exception
+   */
+  @Test
+  public void testSearchImpliesEqualAuthorizable() throws Exception {
+
+    MSentryGMPrivilege serverPrivilege1 = new MSentryGMPrivilege("solr",
+        "service1", null,SearchConstants.QUERY, false);
+
+    MSentryGMPrivilege serverPrivilege2 = new MSentryGMPrivilege("solr",
+        "service2", null,SearchConstants.QUERY, false);
+
+    assertFalse(serverPrivilege1.implies(serverPrivilege2));
+
+    MSentryGMPrivilege collectionPrivilege1 = new MSentryGMPrivilege("solr",
+        "service1", Arrays.asList(new Collection("c1")),
+        SearchConstants.QUERY, false);
+
+    MSentryGMPrivilege collectionPrivilege2 = new MSentryGMPrivilege("solr",
+        "service1", Arrays.asList(new Collection("c2")),
+        SearchConstants.QUERY, false);
+
+    assertFalse(collectionPrivilege1.implies(collectionPrivilege2));
+
+    MSentryGMPrivilege fieldPrivilege1 = new MSentryGMPrivilege("solr",
+        "service1", Arrays.asList(new Collection("c1"), new Field("f1")),
+        SearchConstants.QUERY, false);
+
+    MSentryGMPrivilege fieldPrivilege2 = new MSentryGMPrivilege("solr",
+        "service1", Arrays.asList(new Collection("c1"), new Field("f2")),
+        SearchConstants.QUERY, false);
+
+    assertFalse(fieldPrivilege1.implies(fieldPrivilege2));
+
+    /**
+     * The authorizables aren't equal,but the persistent privilege has the ALL 
name
+     */
+    collectionPrivilege2.setAuthorizables(Arrays.asList(new 
Collection(AccessConstants.ALL)));
+    collectionPrivilege2.implies(collectionPrivilege1);
+
+    fieldPrivilege2.setAuthorizables(Arrays.asList(new Collection("c1"), new 
Field(AccessConstants.ALL)));
+    fieldPrivilege2.implies(fieldPrivilege1);
+  }
+
+  @Test
+  public void testSearchImpliesAction() throws Exception {
+    /**
+     * action is equal
+     */
+    MSentryGMPrivilege fieldPrivilege1 = new MSentryGMPrivilege("solr",
+        "service1", Arrays.asList(new Collection("c1"), new Field("f2")),
+        SearchConstants.QUERY, false);
+
+    MSentryGMPrivilege fieldPrivilege2 = new MSentryGMPrivilege("solr",
+        "service1", Arrays.asList(new Collection("c1"), new Field("f2")),
+        SearchConstants.QUERY, false);
+
+    assertTrue(fieldPrivilege1.implies(fieldPrivilege2));
+
+    /**
+     * action isn't equal
+     */
+    fieldPrivilege2.setAction(SearchConstants.UPDATE);
+    assertFalse(fieldPrivilege1.implies(fieldPrivilege2));
+    /**
+     * action isn't equal,but the persistent privilege has the ALL action
+     */
+    fieldPrivilege1.setAction(SearchConstants.ALL);
+    assertTrue(fieldPrivilege1.implies(fieldPrivilege2));
+  }
+}

http://git-wip-us.apache.org/repos/asf/incubator-sentry/blob/bf3eb482/sentry-provider/sentry-provider-db/src/test/java/org/apache/sentry/provider/db/generic/service/persistent/TestSentryRole.java
----------------------------------------------------------------------
diff --git 
a/sentry-provider/sentry-provider-db/src/test/java/org/apache/sentry/provider/db/generic/service/persistent/TestSentryRole.java
 
b/sentry-provider/sentry-provider-db/src/test/java/org/apache/sentry/provider/db/generic/service/persistent/TestSentryRole.java
new file mode 100644
index 0000000..f8eecd9
--- /dev/null
+++ 
b/sentry-provider/sentry-provider-db/src/test/java/org/apache/sentry/provider/db/generic/service/persistent/TestSentryRole.java
@@ -0,0 +1,373 @@
+/**
+ * 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.service.persistent;
+
+import static junit.framework.Assert.assertEquals;
+import static junit.framework.Assert.assertTrue;
+import static junit.framework.Assert.fail;
+
+import java.io.File;
+import java.util.Arrays;
+import java.util.Properties;
+
+import javax.jdo.JDOHelper;
+import javax.jdo.PersistenceManager;
+import javax.jdo.PersistenceManagerFactory;
+import javax.jdo.Query;
+import javax.jdo.Transaction;
+
+import org.apache.commons.io.FileUtils;
+import org.apache.sentry.core.model.search.Collection;
+import org.apache.sentry.provider.db.service.model.MSentryGMPrivilege;
+import org.apache.sentry.provider.db.service.model.MSentryPrivilege;
+import org.apache.sentry.provider.db.service.model.MSentryRole;
+import org.apache.sentry.provider.db.service.persistent.SentryStore;
+import org.apache.sentry.service.thrift.ServiceConstants.ServerConfig;
+import org.junit.After;
+import org.junit.AfterClass;
+import org.junit.Before;
+import org.junit.BeforeClass;
+import org.junit.Test;
+
+import com.google.common.base.Preconditions;
+import com.google.common.io.Files;
+/**
+ * The class tests that the new feature SENTRY-398 generic model adds the new 
field in the MSentryRole
+ * will not affect the functionality of the origin hive/impala authorization 
model
+ */
+public class TestSentryRole {
+  private static PersistenceManagerFactory pmf;
+  private static File dataDir;
+
+  @Before
+  public void setup() throws Exception {
+    dataDir = new File(Files.createTempDir(), "sentry_policy_db");
+    Properties prop = new Properties();
+    prop.setProperty(ServerConfig.JAVAX_JDO_URL, "jdbc:derby:;databaseName=" + 
dataDir.getPath() + ";create=true");
+    prop.setProperty(ServerConfig.JAVAX_JDO_USER, "Sentry");
+    prop.setProperty(ServerConfig.JAVAX_JDO_PASS, "Sentry");
+    prop.setProperty(ServerConfig.JAVAX_JDO_DRIVER_NAME, 
"org.apache.derby.jdbc.EmbeddedDriver");
+    prop.setProperty("datanucleus.autoCreateSchema", "true");
+    prop.setProperty("datanucleus.fixedDatastore", "false");
+    prop.setProperty("datanucleus.NontransactionalRead", "false");
+    prop.setProperty("datanucleus.NontransactionalWrite", "false");
+    pmf = JDOHelper.getPersistenceManagerFactory(prop);
+  }
+
+  @After
+  public void tearDown() throws Exception {
+    pmf.close();
+    FileUtils.deleteQuietly(dataDir);
+  }
+
+  @Test
+  public void grantMixedPrivilegeTest() throws Exception {
+    String roleName = "r1";
+    //hive/impala privilege
+    MSentryPrivilege hivePrivilege = new MSentryPrivilege();
+    hivePrivilege.setServerName("hive.server1");
+    hivePrivilege.setDbName("db1");
+    hivePrivilege.setTableName("tb1");
+    hivePrivilege.setPrivilegeScope("table");
+    hivePrivilege.setAction("select");
+    hivePrivilege.setGrantOption(true);
+    //solr privilege
+    MSentryGMPrivilege solrPrivilege = new MSentryGMPrivilege();
+    solrPrivilege.setComponentName("solr");
+    solrPrivilege.setServiceName("solr.server1");
+    solrPrivilege.setAuthorizables(Arrays.asList(new Collection("c1")));
+    solrPrivilege.setAction("query");
+    solrPrivilege.setGrantOption(true);
+
+    PersistenceManager pm = null;
+    //create role
+    pm = openTransaction();
+    pm.makePersistent(new MSentryRole(roleName, System.currentTimeMillis()));
+    commitTransaction(pm);
+    //add hivePrivilege to role
+    pm = openTransaction();
+    MSentryRole role = getMSentryRole(pm, roleName);
+    hivePrivilege.appendRole(role);
+    pm.makePersistent(hivePrivilege);
+    commitTransaction(pm);
+    //check hivePrivlege and solrPrivilege
+    pm = openTransaction();
+    role = getMSentryRole(pm, roleName);
+    pm.retrieve(role);
+    assertEquals(1, role.getPrivileges().size());
+    assertEquals(0, role.getGmPrivileges().size());
+    commitTransaction(pm);
+    //add solrPrivilege to role
+    pm = openTransaction();
+    role = getMSentryRole(pm, roleName);
+    pm.retrieve(role);
+    solrPrivilege.appendRole(role);
+    pm.makePersistent(solrPrivilege);
+    commitTransaction(pm);
+    //check hivePrivlege and solrPrivilege
+    pm = openTransaction();
+    role = getMSentryRole(pm, roleName);
+    pm.retrieve(role);
+    assertEquals(1, role.getPrivileges().size());
+    assertEquals(1, role.getGmPrivileges().size());
+    commitTransaction(pm);
+  }
+
+  @Test
+  public void testWantGrantPrivilegeTwice() throws Exception {
+    String roleName = "r1";
+    //hive/impala privilege
+    MSentryPrivilege hivePrivilege = new MSentryPrivilege();
+    hivePrivilege.setServerName("hive.server1");
+    hivePrivilege.setDbName("db1");
+    hivePrivilege.setTableName("tb1");
+    hivePrivilege.setPrivilegeScope("table");
+    hivePrivilege.setAction("select");
+    hivePrivilege.setURI(SentryStore.NULL_COL);
+    hivePrivilege.setColumnName(SentryStore.NULL_COL);
+    hivePrivilege.setGrantOption(true);
+    //The same hivePrivilege
+    MSentryPrivilege hivePrivilege2 = new MSentryPrivilege(hivePrivilege);
+    //solr privilege
+    MSentryGMPrivilege solrPrivilege = new MSentryGMPrivilege();
+    solrPrivilege.setComponentName("solr");
+    solrPrivilege.setServiceName("solr.server1");
+    solrPrivilege.setAuthorizables(Arrays.asList(new Collection("c1")));
+    solrPrivilege.setAction("query");
+    solrPrivilege.setGrantOption(true);
+    //The same solrPrivilege
+    MSentryGMPrivilege solrPrivilege2 = new MSentryGMPrivilege(solrPrivilege);
+
+    PersistenceManager pm = null;
+    //create role
+    pm = openTransaction();
+    pm.makePersistent(new MSentryRole(roleName, System.currentTimeMillis()));
+    commitTransaction(pm);
+
+    //grant hivePrivilege and solrPrivilege to role
+    pm = openTransaction();
+    MSentryRole role = getMSentryRole(pm, roleName);
+    solrPrivilege.appendRole(role);
+    hivePrivilege.appendRole(role);
+    pm.makePersistent(solrPrivilege);
+    pm.makePersistent(hivePrivilege);
+    commitTransaction(pm);
+    //check
+    pm = openTransaction();
+    role = getMSentryRole(pm, roleName);
+    pm.retrieve(role);
+    assertEquals(1, role.getPrivileges().size());
+    assertEquals(1, role.getGmPrivileges().size());
+    commitTransaction(pm);
+
+    //want to grant the same hivePrivilege and solrPrivilege to role again
+    //hivePrivilege2 is equal to hivePrivilege
+    //solrPrivilege2 is equal to solrPrivilege
+    pm = openTransaction();
+    role = getMSentryRole(pm, roleName);
+    pm.retrieve(role);
+    if (!role.getGmPrivileges().contains(solrPrivilege2)) {
+      fail("unexpect happend: the MSentryGMPrivilege:" + solrPrivilege2 + " 
already be granted");
+    }
+    if (!role.getPrivileges().contains(hivePrivilege2)) {
+      fail("unexpect happend: the MSentryPrivilege:" + hivePrivilege2 + " 
already be granted");
+    }
+    commitTransaction(pm);
+  }
+
+  @Test
+  public void testMixedRevokePrivilege() throws Exception {
+    String roleName = "r1";
+    //hive/impala privilege
+    MSentryPrivilege hivePrivilege = new MSentryPrivilege();
+    hivePrivilege.setServerName("hive.server1");
+    hivePrivilege.setDbName("db1");
+    hivePrivilege.setTableName("tb1");
+    hivePrivilege.setPrivilegeScope("table");
+    hivePrivilege.setAction("select");
+    hivePrivilege.setURI(SentryStore.NULL_COL);
+    hivePrivilege.setColumnName(SentryStore.NULL_COL);
+    hivePrivilege.setGrantOption(true);
+
+    //solr privilege
+    MSentryGMPrivilege solrPrivilege = new MSentryGMPrivilege();
+    solrPrivilege.setComponentName("solr");
+    solrPrivilege.setServiceName("solr.server1");
+    solrPrivilege.setAuthorizables(Arrays.asList(new Collection("c1")));
+    solrPrivilege.setAction("query");
+    solrPrivilege.setGrantOption(true);
+
+    PersistenceManager pm = null;
+    //create role
+    pm = openTransaction();
+    pm.makePersistent(new MSentryRole(roleName, System.currentTimeMillis()));
+    commitTransaction(pm);
+
+    //grant hivePrivilege and solrPrivilege to role
+    pm = openTransaction();
+    MSentryRole role = getMSentryRole(pm, roleName);
+    hivePrivilege.appendRole(role);
+    solrPrivilege.appendRole(role);
+    pm.makePersistent(hivePrivilege);
+    pm.makePersistent(solrPrivilege);
+    commitTransaction(pm);
+
+    //check
+    pm = openTransaction();
+    role = getMSentryRole(pm, roleName);
+    pm.retrieve(role);
+    assertEquals(1, role.getPrivileges().size());
+    assertEquals(1, role.getGmPrivileges().size());
+    commitTransaction(pm);
+
+    //revoke solrPrivilege from role
+    pm = openTransaction();
+    role = getMSentryRole(pm, roleName);
+    solrPrivilege = (MSentryGMPrivilege)role.getGmPrivileges().toArray()[0];
+    solrPrivilege.removeRole(role);
+    pm.makePersistent(solrPrivilege);
+    commitTransaction(pm);
+
+    //check
+    pm = openTransaction();
+    role = getMSentryRole(pm, roleName);
+    pm.retrieve(role);
+    assertEquals(1, role.getPrivileges().size());
+    assertEquals(0, role.getGmPrivileges().size());
+    commitTransaction(pm);
+
+    //revoke hivePrivilege from role
+    pm = openTransaction();
+    role = getMSentryRole(pm, roleName);
+    pm.retrieve(role);
+    hivePrivilege = (MSentryPrivilege)role.getPrivileges().toArray()[0];
+    hivePrivilege.removeRole(role);
+    pm.makePersistent(hivePrivilege);
+    commitTransaction(pm);
+
+    //check
+    pm = openTransaction();
+    role = getMSentryRole(pm, roleName);
+    pm.retrieve(role);
+    assertEquals(0, role.getPrivileges().size());
+    assertEquals(0, role.getGmPrivileges().size());
+    commitTransaction(pm);
+  }
+
+  @Test
+  public void testDeletePrivilegeAndRole() throws Exception {
+    String roleName = "r1";
+    //hive/impala privilege
+    MSentryPrivilege hivePrivilege = new MSentryPrivilege();
+    hivePrivilege.setServerName("hive.server1");
+    hivePrivilege.setDbName("db1");
+    hivePrivilege.setTableName("tb1");
+    hivePrivilege.setPrivilegeScope("table");
+    hivePrivilege.setAction("select");
+    hivePrivilege.setURI(SentryStore.NULL_COL);
+    hivePrivilege.setColumnName(SentryStore.NULL_COL);
+    hivePrivilege.setGrantOption(true);
+
+    //solr privilege
+    MSentryGMPrivilege solrPrivilege = new MSentryGMPrivilege();
+    solrPrivilege.setComponentName("solr");
+    solrPrivilege.setServiceName("solr.server1");
+    solrPrivilege.setAuthorizables(Arrays.asList(new Collection("c1")));
+    solrPrivilege.setAction("query");
+    solrPrivilege.setGrantOption(true);
+
+    PersistenceManager pm = null;
+    //create role
+    pm = openTransaction();
+    pm.makePersistent(new MSentryRole(roleName, System.currentTimeMillis()));
+    commitTransaction(pm);
+
+    //grant hivePrivilege and solrPrivilege to role
+    pm = openTransaction();
+    MSentryRole role = getMSentryRole(pm, roleName);
+    hivePrivilege.appendRole(role);
+    solrPrivilege.appendRole(role);
+    pm.makePersistent(hivePrivilege);
+    pm.makePersistent(solrPrivilege);
+    commitTransaction(pm);
+
+    //check
+    pm = openTransaction();
+    role = getMSentryRole(pm, roleName);
+    pm.retrieve(role);
+    assertEquals(1, role.getPrivileges().size());
+    assertEquals(1, role.getGmPrivileges().size());
+    commitTransaction(pm);
+
+    //remove all privileges
+    pm = openTransaction();
+    role = getMSentryRole(pm, roleName);
+    role.removeGMPrivileges();
+    role.removePrivileges();
+    pm.makePersistent(role);
+    commitTransaction(pm);
+
+    //check
+    pm = openTransaction();
+    role = getMSentryRole(pm, roleName);
+    pm.retrieve(role);
+    assertEquals(0, role.getPrivileges().size());
+    assertEquals(0, role.getGmPrivileges().size());
+    commitTransaction(pm);
+
+    //delete role
+    pm = openTransaction();
+    role = getMSentryRole(pm, roleName);
+    pm.deletePersistent(role);
+    commitTransaction(pm);
+
+    //check
+    pm = openTransaction();
+    role = getMSentryRole(pm, roleName);
+    assertTrue(role == null);
+    commitTransaction(pm);
+  }
+
+  private PersistenceManager openTransaction() {
+    PersistenceManager pm = pmf.getPersistenceManager();
+    Transaction currentTransaction = pm.currentTransaction();
+    currentTransaction.begin();
+    return pm;
+  }
+
+  private void commitTransaction(PersistenceManager pm) {
+    Transaction currentTransaction = pm.currentTransaction();
+    try {
+      Preconditions.checkState(currentTransaction.isActive(), "Transaction is 
not active");
+      currentTransaction.commit();
+    } finally {
+      pm.close();
+    }
+  }
+
+  private MSentryRole getMSentryRole(PersistenceManager pm, String roleName) {
+    Query query = pm.newQuery(MSentryRole.class);
+    query.setFilter("this.roleName == t");
+    query.declareParameters("java.lang.String t");
+    query.setUnique(true);
+    MSentryRole sentryRole = (MSentryRole) query.execute(roleName);
+    return sentryRole;
+  }
+
+
+}

Reply via email to