You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@sentry.apache.org by sp...@apache.org on 2018/05/31 03:32:00 UTC
[22/86] sentry git commit: Revert "SENTRY-2208: Refactor out Sentry
service into own module from sentry-provider-db (Anthony Young-Garner,
reviewed by Sergio Pena, Steve Moist, Na Li)"
http://git-wip-us.apache.org/repos/asf/sentry/blob/9351d19d/sentry-provider/sentry-provider-db/src/test/java/org/apache/sentry/service/thrift/TestFullUpdateInitializer.java
----------------------------------------------------------------------
diff --git a/sentry-provider/sentry-provider-db/src/test/java/org/apache/sentry/service/thrift/TestFullUpdateInitializer.java b/sentry-provider/sentry-provider-db/src/test/java/org/apache/sentry/service/thrift/TestFullUpdateInitializer.java
new file mode 100644
index 0000000..589acbe
--- /dev/null
+++ b/sentry-provider/sentry-provider-db/src/test/java/org/apache/sentry/service/thrift/TestFullUpdateInitializer.java
@@ -0,0 +1,346 @@
+/**
+ * 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.service.thrift;
+
+import com.google.common.collect.Lists;
+import com.google.common.collect.Sets;
+import org.apache.hadoop.conf.Configuration;
+import org.apache.hadoop.hive.metastore.HiveMetaStoreClient;
+import org.apache.hadoop.hive.metastore.api.Database;
+import org.apache.hadoop.hive.metastore.api.MetaException;
+import org.apache.hadoop.hive.metastore.api.Partition;
+import org.apache.hadoop.hive.metastore.api.StorageDescriptor;
+import org.apache.hadoop.hive.metastore.api.Table;
+import org.apache.thrift.TException;
+import org.junit.Assert;
+import org.junit.Test;
+import org.mockito.Mockito;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+public class TestFullUpdateInitializer {
+
+ private static Configuration conf = new Configuration();
+
+ static {
+ conf.setInt(org.apache.sentry.hdfs.ServiceConstants.ServerConfig
+ .SENTRY_HDFS_SYNC_METASTORE_CACHE_MAX_PART_PER_RPC, 1);
+ conf.setInt(org.apache.sentry.hdfs.ServiceConstants.ServerConfig
+ .SENTRY_HDFS_SYNC_METASTORE_CACHE_MAX_TABLES_PER_RPC, 1);
+ conf.setInt(org.apache.sentry.hdfs.ServiceConstants.ServerConfig
+ .SENTRY_HDFS_SYNC_METASTORE_CACHE_INIT_THREADS, 8);
+ }
+
+ /**
+ * Representation of a Hive table. A table has a name and a list of partitions.
+ */
+ private static class HiveTable {
+ String name;
+ List<String> partitions;
+
+ HiveTable(String name) {
+ this.name = name;
+ this.partitions = new ArrayList<>();
+ }
+
+ HiveTable(String name, List<String> partitions) {
+ this.name = name;
+ this.partitions = partitions;
+ if (this.partitions == null) {
+ this.partitions = new ArrayList<>();
+ }
+ }
+
+ HiveTable add(String partition) {
+ partitions.add(partition);
+ return this;
+ }
+ }
+
+ /**
+ * Representation of a Hive database. A database has a name and a list of tables
+ */
+ private static class HiveDb {
+ String name;
+ Collection<HiveTable> tables;
+
+ HiveDb(String name) {
+ this.name = name;
+ tables = new ArrayList<>();
+ }
+
+ HiveDb(String name, Collection<HiveTable> tables) {
+ this.name = name;
+ this.tables = tables;
+ if (this.tables == null) {
+ this.tables = new ArrayList<>();
+ }
+ }
+
+ void add(HiveTable table) {
+ this.tables.add(table);
+ }
+ }
+
+ /**
+ * Representation of a full Hive snapshot. A snapshot is collection of databases
+ */
+ private static class HiveSnapshot {
+ List<HiveDb> databases = new ArrayList<>();
+
+ HiveSnapshot() {
+ }
+
+ HiveSnapshot(Collection<HiveDb> dblist) {
+ if (dblist != null) {
+ databases.addAll(dblist);
+ }
+ }
+
+ HiveSnapshot add(HiveDb db) {
+ this.databases.add(db);
+ return this;
+ }
+ }
+
+ /**
+ * Convert Hive snapshot to mock client that will return proper values
+ * for the snapshot.
+ */
+ private static class MockClient {
+ HiveMetaStoreClient client;
+
+ MockClient(HiveSnapshot snapshot) throws TException {
+ client = Mockito.mock(HiveMetaStoreClient.class);
+ List<String> dbNames = new ArrayList<>(snapshot.databases.size());
+ // Walk over all databases and mock appropriate objects
+ for (HiveDb mdb: snapshot.databases) {
+ String dbName = mdb.name;
+ dbNames.add(dbName);
+ Database db = makeDb(dbName);
+ Mockito.when(client.getDatabase(dbName)).thenReturn(db);
+ List<String> tableNames = new ArrayList<>(mdb.tables.size());
+ // Walk over all tables for the database and mock appropriate objects
+ for (HiveTable table: mdb.tables) {
+ String tableName = table.name;
+ tableNames.add(tableName);
+ Table mockTable = makeTable(dbName, tableName);
+ Mockito.when(client.getTableObjectsByName(dbName,
+ Lists.newArrayList(tableName)))
+ .thenReturn(Lists.newArrayList(mockTable));
+ Mockito.when(client.listPartitionNames(dbName, tableName, (short) -1))
+ .thenReturn(table.partitions);
+ // Walk across all partitions and mock appropriate objects
+ for (String partName: table.partitions) {
+ Partition p = makePartition(dbName, tableName, partName);
+ Mockito.when(client.getPartitionsByNames(dbName, tableName,
+ Lists.<String>newArrayList(partName)))
+ .thenReturn(Lists.<Partition>newArrayList(p));
+ }
+ }
+ Mockito.when(client.getAllTables(dbName)).thenReturn(tableNames);
+ }
+ // Return all database names
+ Mockito.when(client.getAllDatabases()).thenReturn(dbNames);
+ }
+ }
+
+ private static class MockHMSClientFactory implements HiveConnectionFactory {
+
+ private final HiveMetaStoreClient mClient;
+
+ private MockHMSClientFactory(MockClient mClient) {
+ this.mClient = mClient.client;
+ }
+
+ private MockHMSClientFactory(HiveMetaStoreClient client) {
+ this.mClient = client;
+ }
+
+ @Override
+ public HMSClient connect() throws IOException, InterruptedException, MetaException {
+ return new HMSClient(mClient);
+ }
+
+ @Override
+ public void close() throws Exception {
+ }
+ }
+
+ /**
+ * Create mock database with the given name
+ * @param name Database name
+ * @return Mock database object
+ */
+ private static Database makeDb(String name) {
+ Database db = Mockito.mock(Database.class);
+ Mockito.when(db.getName()).thenReturn(name);
+ Mockito.when(db.getLocationUri()).thenReturn("hdfs:///" + name);
+ return db;
+ }
+
+ /**
+ * Create mock table
+ * @param dbName db for this table
+ * @param tableName name of the table
+ * @return mock table object
+ */
+ private static Table makeTable(String dbName, String tableName) {
+ Table table = Mockito.mock(Table.class);
+ Mockito.when(table.getDbName()).thenReturn(dbName);
+ Mockito.when(table.getTableName()).thenReturn(tableName);
+ StorageDescriptor sd = Mockito.mock(StorageDescriptor.class);
+ Mockito.when(sd.getLocation()).thenReturn(
+ String.format("hdfs:///%s/%s", dbName, tableName));
+ Mockito.when(table.getSd()).thenReturn(sd);
+ return table;
+ }
+
+ /**
+ * Create mock partition
+ * @param dbName database for this partition
+ * @param tableName table for this partition
+ * @param partName partition name
+ * @return mock partition object
+ */
+ private static Partition makePartition(String dbName, String tableName, String partName) {
+ Partition partition = Mockito.mock(Partition.class);
+ StorageDescriptor sd = Mockito.mock(StorageDescriptor.class);
+ Mockito.when(sd.getLocation()).thenReturn(
+ String.format("hdfs:///%s/%s/%s", dbName, tableName, partName));
+ Mockito.when(partition.getSd()).thenReturn(sd);
+ return partition;
+ }
+
+ @Test
+ // Test basic operation with small database
+ public void testSimple() throws Exception {
+ HiveTable tab21 = new HiveTable("tab21");
+ HiveTable tab31 = new HiveTable("tab31").add("part311").add("part312");
+ HiveDb db3 = new HiveDb("db3", Lists.newArrayList(tab31));
+ HiveDb db2 = new HiveDb("db2", Lists.newArrayList(tab21));
+ HiveDb db1 = new HiveDb("db1");
+ HiveSnapshot snap = new HiveSnapshot().add(db1).add(db2).add(db3);
+ MockClient c = new MockClient(snap);
+
+ Map<String, Collection<String>> update;
+ try(FullUpdateInitializer cacheInitializer =
+ new FullUpdateInitializer(new MockHMSClientFactory(c), conf)) {
+ update = cacheInitializer.getFullHMSSnapshot();
+ }
+ Assert.assertEquals(5, update.size());
+ Assert.assertEquals(Sets.newHashSet("db1"), update.get("db1"));
+ Assert.assertEquals(Sets.newHashSet("db2"), update.get("db2"));
+ Assert.assertEquals(Sets.newHashSet("db3"), update.get("db3"));
+ Assert.assertEquals(Sets.newHashSet("db2/tab21"), update.get("db2.tab21"));
+ Assert.assertEquals(Sets.newHashSet("db3/tab31",
+ "db3/tab31/part311", "db3/tab31/part312"), update.get("db3.tab31"));
+ }
+
+ @Test
+ // Test that invalid paths are handled correctly
+ public void testInvalidPaths() throws Exception {
+ //Set up mocks: db1.tb1, with tb1 returning a wrong dbname (db2)
+ Database db1 = makeDb("db1");
+
+ Table tab1 = Mockito.mock(Table.class);
+ //Return a wrong db name, so that this triggers an exception
+ Mockito.when(tab1.getDbName()).thenReturn("db2");
+ Mockito.when(tab1.getTableName()).thenReturn("tab1");
+
+ HiveMetaStoreClient client = Mockito.mock(HiveMetaStoreClient.class);
+ Mockito.when(client.getAllDatabases()).thenReturn(Lists.newArrayList("db1"));
+ Mockito.when(client.getDatabase("db1")).thenReturn(db1);
+
+ Table tab12 = Mockito.mock(Table.class);
+ Mockito.when(tab12.getDbName()).thenReturn("db1");
+ Mockito.when(tab12.getTableName()).thenReturn("tab21");
+ StorageDescriptor sd21 = Mockito.mock(StorageDescriptor.class);
+ Mockito.when(sd21.getLocation()).thenReturn("hdfs:///db1/tab21");
+ Mockito.when(tab12.getSd()).thenReturn(sd21);
+
+ Mockito.when(client.getTableObjectsByName("db1",
+ Lists.newArrayList("tab1"))).thenReturn(Lists.newArrayList(tab1));
+ Mockito.when(client.getTableObjectsByName("db1",
+ Lists.newArrayList("tab12"))).thenReturn(Lists.newArrayList(tab12));
+ Mockito.when(client.getAllTables("db1")).
+ thenReturn(Lists.newArrayList("tab1", "tab12"));
+
+
+ Map<String, Collection<String>> update;
+ try(FullUpdateInitializer cacheInitializer =
+ new FullUpdateInitializer(new MockHMSClientFactory(client), conf)) {
+ update = cacheInitializer.getFullHMSSnapshot();
+ }
+ Assert.assertEquals(2, update.size());
+ Assert.assertEquals(Sets.newHashSet("db1"), update.get("db1"));
+ Assert.assertEquals(Sets.newHashSet("db1/tab21"), update.get("db1.tab21"));
+ }
+
+ @Test
+ // Test handling of a big tables and partitions
+ public void testBig() throws Exception {
+ int ndbs = 3;
+ int ntables = 51;
+ int nparts = 131;
+
+ HiveSnapshot snap = new HiveSnapshot();
+
+ for (int i = 0; i < ndbs; i++) {
+ HiveDb db = new HiveDb("db" + i);
+ for (int j = 0; j < ntables; j++) {
+ HiveTable table = new HiveTable("table" + i + j);
+ for (int k = 0; k < nparts; k++) {
+ table.add("part" + i + j + k);
+ }
+ db.add(table);
+ }
+ snap.add(db);
+ }
+ MockClient c = new MockClient(snap);
+ Map<String, Collection<String>> update;
+ try(FullUpdateInitializer cacheInitializer =
+ new FullUpdateInitializer(new MockHMSClientFactory(c), conf)) {
+ update = cacheInitializer.getFullHMSSnapshot();
+ }
+ Assert.assertEquals((ntables * ndbs) + ndbs, update.size());
+ for (int i = 0; i < ndbs; i++) {
+ String dbName = "db" + i;
+ Assert.assertEquals(Sets.newHashSet(dbName), update.get(dbName));
+
+ for (int j = 0; j < ntables; j++) {
+ String tableName = "table" + i + j;
+ Set<String> values = new HashSet<>();
+ values.add(String.format("%s/%s", dbName, tableName));
+ for (int k = 0; k < nparts; k++) {
+ String partName = "part" + i + j + k;
+ values.add(String.format("%s/%s/%s", dbName, tableName, partName));
+ }
+ String authz = dbName + "." + tableName;
+ Assert.assertEquals(values, update.get(authz));
+ }
+ }
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/sentry/blob/9351d19d/sentry-provider/sentry-provider-db/src/test/java/org/apache/sentry/service/thrift/TestFullUpdateModifier.java
----------------------------------------------------------------------
diff --git a/sentry-provider/sentry-provider-db/src/test/java/org/apache/sentry/service/thrift/TestFullUpdateModifier.java b/sentry-provider/sentry-provider-db/src/test/java/org/apache/sentry/service/thrift/TestFullUpdateModifier.java
new file mode 100644
index 0000000..c6be80d
--- /dev/null
+++ b/sentry-provider/sentry-provider-db/src/test/java/org/apache/sentry/service/thrift/TestFullUpdateModifier.java
@@ -0,0 +1,482 @@
+/**
+ * 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.service.thrift;
+
+import org.apache.hadoop.hive.metastore.api.NotificationEvent;
+import org.apache.hadoop.hive.metastore.api.Partition;
+import org.apache.hadoop.hive.metastore.api.StorageDescriptor;
+import org.apache.hadoop.hive.metastore.api.Table;
+import org.apache.hadoop.hive.metastore.messaging.MessageDeserializer;
+import org.apache.sentry.binding.metastore.messaging.json.SentryJSONAddPartitionMessage;
+import org.apache.sentry.binding.metastore.messaging.json.SentryJSONAlterPartitionMessage;
+import org.apache.sentry.binding.metastore.messaging.json.SentryJSONAlterTableMessage;
+import org.apache.sentry.binding.metastore.messaging.json.SentryJSONCreateDatabaseMessage;
+import org.apache.sentry.binding.metastore.messaging.json.SentryJSONCreateTableMessage;
+import org.apache.sentry.binding.metastore.messaging.json.SentryJSONDropDatabaseMessage;
+import org.apache.sentry.binding.metastore.messaging.json.SentryJSONDropPartitionMessage;
+import org.apache.sentry.binding.metastore.messaging.json.SentryJSONDropTableMessage;
+import org.apache.sentry.binding.metastore.messaging.json.SentryJSONMessageDeserializer;
+import org.junit.Test;
+import org.mockito.Mockito;
+
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
+
+import static org.apache.hadoop.hive.metastore.messaging.EventMessage.EventType.*;
+import static org.junit.Assert.*;
+
+public class TestFullUpdateModifier {
+ private static final String SERVER = "s";
+ private static final String PRINCIPAL = "p";
+ private static final String DB = "Db1";
+ private static final String TABLE = "Tab1";
+ private static final String AUTH = DB.toLowerCase() + "." + TABLE.toLowerCase();
+ private static final String PATH = "foo/bar";
+ private static final String LOCATION = uri(PATH);
+
+ private static final Table TABLE_OBJ = new Table(TABLE, DB, "", 0, 0, 0,
+ buildStorageDescriptor(LOCATION), null, null, "", "", "");
+
+ /**
+ * Convert path to HDFS URI
+ */
+ private static final String uri(String path) {
+ return "hdfs:///" + path;
+ }
+
+ /**
+ * Creates a StorageDescriptor using the location as parameter.
+ *
+ * @param location The location string for the StorageDescriptor
+ * @return A StorageDescriptor object
+ */
+ private static StorageDescriptor buildStorageDescriptor(String location) {
+ return new StorageDescriptor(null, location, "", "", false, 0, null, null, null, null);
+ }
+
+ /**
+ * Creates a Table object using the db name, table name and table location as parameters.
+ *
+ * @param dbName The database name string.
+ * @param tableName The table name string.
+ * @param location The table location string.
+ * @return A Table object
+ */
+ private static Table buildTable(String dbName, String tableName, String location) {
+ return new Table(tableName, dbName, "", 0, 0, 0,
+ buildStorageDescriptor(location), null, null, "", "", "");
+ }
+
+ /**
+ * Test create database event. It should add database and its location.
+ * As a result we should have entry {"db1": {foo/bar}}
+ * @throws Exception
+ */
+ @Test
+ public void testCreateDatabase() throws Exception {
+ Map<String, Collection<String>> update = new HashMap<>();
+ NotificationEvent event = new NotificationEvent(0, 0, CREATE_DATABASE.toString(), "");
+ MessageDeserializer deserializer = Mockito.mock(SentryJSONMessageDeserializer.class);
+
+ SentryJSONCreateDatabaseMessage message =
+ new SentryJSONCreateDatabaseMessage(SERVER, PRINCIPAL, DB, 0L, LOCATION);
+ Mockito.when(deserializer.getCreateDatabaseMessage("")).thenReturn(message);
+ FullUpdateModifier.applyEvent(update, event, deserializer);
+ Map<String, Set<String>> expected = new HashMap<>();
+ expected.put(DB.toLowerCase(), Collections.singleton(PATH));
+ assertEquals(expected, update);
+ }
+
+ /**
+ * Test drop database event. It should drop database record.
+ * @throws Exception
+ */
+ @Test
+ public void testDropDatabase() throws Exception {
+ Map<String, Collection<String>> update = new HashMap<>();
+ update.put(DB.toLowerCase(), Collections.singleton(PATH));
+ NotificationEvent event = new NotificationEvent(0, 0, DROP_DATABASE.toString(), "");
+ MessageDeserializer deserializer = Mockito.mock(SentryJSONMessageDeserializer.class);
+
+ SentryJSONDropDatabaseMessage message =
+ new SentryJSONDropDatabaseMessage(SERVER, PRINCIPAL, DB, 0L, LOCATION);
+ Mockito.when(deserializer.getDropDatabaseMessage("")).thenReturn(message);
+ FullUpdateModifier.applyEvent(update, event, deserializer);
+ assertTrue(update.isEmpty());
+ }
+
+ /**
+ * Test drop database event when dropped database location doesn't
+ * match original database location. Should leave update intact.
+ * @throws Exception
+ */
+ @Test
+ public void testDropDatabaseWrongLocation() throws Exception {
+ Map<String, Collection<String>> update = new HashMap<>();
+ update.put(DB.toLowerCase(), Collections.singleton(PATH));
+
+ NotificationEvent event = new NotificationEvent(0, 0, DROP_DATABASE.toString(), "");
+ MessageDeserializer deserializer = Mockito.mock(SentryJSONMessageDeserializer.class);
+
+ SentryJSONDropDatabaseMessage message =
+ new SentryJSONDropDatabaseMessage(SERVER, PRINCIPAL, DB, 0L,
+ "hdfs:///bad/location");
+ Mockito.when(deserializer.getDropDatabaseMessage("")).thenReturn(message);
+ FullUpdateModifier.applyEvent(update, event, deserializer);
+ // DB should stay
+ Map<String, Set<String>> expected = new HashMap<>();
+ expected.put(DB.toLowerCase(), Collections.singleton(PATH));
+ assertEquals(expected, update);
+ }
+
+ /**
+ * Test drop database which has tables/partitions.
+ * Should drop all reated database records but leave unrelated records in place.
+ * @throws Exception
+ */
+ @Test
+ public void testDropDatabaseWithTables() throws Exception {
+ Map<String, Collection<String>> update = new HashMap<>();
+ update.put(DB.toLowerCase(), Collections.singleton(PATH));
+ update.put(AUTH, Collections.singleton(PATH));
+ update.put("unrelated", Collections.singleton(PATH));
+ NotificationEvent event = new NotificationEvent(0, 0, DROP_DATABASE.toString(), "");
+ MessageDeserializer deserializer = Mockito.mock(SentryJSONMessageDeserializer.class);
+
+ SentryJSONDropDatabaseMessage message =
+ new SentryJSONDropDatabaseMessage(SERVER, PRINCIPAL, DB, 0L, LOCATION);
+ Mockito.when(deserializer.getDropDatabaseMessage("")).thenReturn(message);
+ FullUpdateModifier.applyEvent(update, event, deserializer);
+ Map<String, Set<String>> expected = new HashMap<>();
+ expected.put("unrelated", Collections.singleton(PATH));
+ assertEquals(expected, update);
+ }
+
+ /**
+ * Test create table event. It should add table and its location.
+ * As a result we should have entry {"db1.tab1": {foo/bar}}
+ * @throws Exception
+ */
+ @Test
+ public void testCreateTable() throws Exception {
+ Map<String, Collection<String>> update = new HashMap<>();
+ NotificationEvent event = new NotificationEvent(0, 0, CREATE_TABLE.toString(), "");
+ MessageDeserializer deserializer = Mockito.mock(SentryJSONMessageDeserializer.class);
+
+ SentryJSONCreateTableMessage message =
+ new SentryJSONCreateTableMessage(SERVER, PRINCIPAL, TABLE_OBJ, Collections.emptyIterator(), 0L);
+ Mockito.when(deserializer.getCreateTableMessage("")).thenReturn(message);
+ FullUpdateModifier.applyEvent(update, event, deserializer);
+ Map<String, Set<String>> expected = new HashMap<>();
+ expected.put(AUTH, Collections.singleton(PATH));
+ assertEquals(expected, update);
+ }
+
+ /**
+ * Test drop table event. It should drop table record.
+ * @throws Exception
+ */
+ @Test
+ public void testDropTable() throws Exception {
+ Map<String, Collection<String>> update = new HashMap<>();
+ update.put(AUTH, Collections.singleton(PATH));
+ NotificationEvent event = new NotificationEvent(0, 0, DROP_TABLE.toString(), "");
+ MessageDeserializer deserializer = Mockito.mock(SentryJSONMessageDeserializer.class);
+
+ SentryJSONDropTableMessage message =
+ new SentryJSONDropTableMessage(SERVER, PRINCIPAL, DB, TABLE, 0L, LOCATION);
+ Mockito.when(deserializer.getDropTableMessage("")).thenReturn(message);
+ FullUpdateModifier.applyEvent(update, event, deserializer);
+ assertTrue(update.isEmpty());
+ }
+
+ /**
+ * Test drop table event. It should drop table record.
+ * @throws Exception
+ */
+ @Test
+ public void testDropTableWrongLocation() throws Exception {
+ Map<String, Collection<String>> update = new HashMap<>();
+ update.put(AUTH, Collections.singleton(PATH));
+ NotificationEvent event = new NotificationEvent(0, 0, DROP_TABLE.toString(), "");
+ MessageDeserializer deserializer = Mockito.mock(SentryJSONMessageDeserializer.class);
+
+ SentryJSONDropTableMessage message =
+ new SentryJSONDropTableMessage(SERVER, PRINCIPAL, DB, TABLE, 0L,
+ "hdfs:///bad/location");
+ Mockito.when(deserializer.getDropTableMessage("")).thenReturn(message);
+ FullUpdateModifier.applyEvent(update, event, deserializer);
+ // DB should stay
+ assertEquals(Collections.singleton(PATH), update.get(AUTH));
+ assertEquals(1, update.size());
+ }
+
+ /**
+ * Test add partition event. It should add table and its location.
+ * As a result we should have entry {"db1.tab1": {foo/bar, hello/world}}
+ * @throws Exception
+ */
+ @Test
+ public void testAddPartition() throws Exception {
+ Map<String, Collection<String>> update = new HashMap<>();
+ Set<String> locations = new HashSet<>();
+ locations.add(PATH);
+ update.put(AUTH, locations);
+
+ NotificationEvent event = new NotificationEvent(0, 0, ADD_PARTITION.toString(), "");
+ MessageDeserializer deserializer = Mockito.mock(SentryJSONMessageDeserializer.class);
+
+ String partPath = "hello/world";
+ String partLocation = uri(partPath);
+
+ SentryJSONAddPartitionMessage message =
+ new SentryJSONAddPartitionMessage(SERVER, PRINCIPAL, TABLE_OBJ,
+ Collections.emptyIterator(), Collections.emptyIterator(),
+ 0L, Collections.singletonList(partLocation));
+ Mockito.when(deserializer.getAddPartitionMessage("")).thenReturn(message);
+ FullUpdateModifier.applyEvent(update, event, deserializer);
+ Set<String> expected = new HashSet<>(2);
+ expected.add(PATH);
+ expected.add(partPath);
+ assertEquals(expected, update.get(AUTH));
+ }
+
+ /**
+ * Test drop partition event. It should drop partition info from the list of locations.
+ * @throws Exception
+ */
+ @Test
+ public void testDropPartitions() throws Exception {
+ String partPath = "hello/world";
+ String partLocation = uri(partPath);
+ Map<String, Collection<String>> update = new HashMap<>();
+ Set<String> locations = new HashSet<>();
+ locations.add(PATH);
+ locations.add(partPath);
+ update.put(AUTH, locations);
+
+ NotificationEvent event = new NotificationEvent(0, 0, DROP_PARTITION.toString(), "");
+ MessageDeserializer deserializer = Mockito.mock(SentryJSONMessageDeserializer.class);
+
+ SentryJSONDropPartitionMessage message =
+ new SentryJSONDropPartitionMessage(SERVER, PRINCIPAL, TABLE_OBJ,
+ Collections.<Map<String,String>>emptyList(), 0L, Collections.singletonList(partLocation));
+ Mockito.when(deserializer.getDropPartitionMessage("")).thenReturn(message);
+ FullUpdateModifier.applyEvent(update, event, deserializer);
+ assertEquals(Collections.singleton(PATH), update.get(AUTH));
+ }
+
+ /**
+ * Test alter partition event. It should change partition location
+ * @throws Exception
+ */
+ @Test
+ public void testAlterPartition() throws Exception {
+ String partPath = "hello/world";
+ String partLocation = uri(partPath);
+
+ String newPath = "better/world";
+ String newLocation = uri(newPath);
+
+ Map<String, Collection<String>> update = new HashMap<>();
+ Set<String> locations = new HashSet<>();
+ locations.add(PATH);
+ locations.add(partPath);
+ update.put(AUTH, locations);
+
+ NotificationEvent event = new NotificationEvent(0, 0, ALTER_PARTITION.toString(), "");
+ MessageDeserializer deserializer = Mockito.mock(SentryJSONMessageDeserializer.class);
+
+ Partition partitionObjBefore = new Partition(null, DB, TABLE, 0, 0, buildStorageDescriptor(partLocation), null);
+ Partition partitionObjAfter = new Partition(null, DB, TABLE, 0, 0, buildStorageDescriptor(newLocation), null);
+
+ SentryJSONAlterPartitionMessage message =
+ new SentryJSONAlterPartitionMessage(SERVER, PRINCIPAL, TABLE_OBJ,
+ partitionObjBefore, partitionObjAfter, 0L);
+
+ Mockito.when(deserializer.getAlterPartitionMessage("")).thenReturn(message);
+ FullUpdateModifier.applyEvent(update, event, deserializer);
+
+ Set<String> expected = new HashSet<>(2);
+ expected.add(PATH);
+ expected.add(newPath);
+ assertEquals(expected, update.get(AUTH));
+ }
+
+ /**
+ * Test alter table event that changes database name when there are no tables.
+ * @throws Exception
+ */
+ @Test
+ public void testAlterTableChangeDbNameNoTables() throws Exception {
+ Map<String, Collection<String>> update = new HashMap<>();
+ update.put(DB.toLowerCase(), Collections.singleton(PATH));
+ String newDbName = "Db2";
+
+ NotificationEvent event = new NotificationEvent(0, 0, ALTER_TABLE.toString(), "");
+ event.setDbName(newDbName);
+ event.setTableName(TABLE);
+
+ MessageDeserializer deserializer = Mockito.mock(SentryJSONMessageDeserializer.class);
+
+ SentryJSONAlterTableMessage message =
+ new SentryJSONAlterTableMessage(SERVER, PRINCIPAL, TABLE_OBJ, TABLE_OBJ, 0L);
+
+ Mockito.when(deserializer.getAlterTableMessage("")).thenReturn(message);
+ FullUpdateModifier.applyEvent(update, event, deserializer);
+ assertEquals(Collections.singleton(PATH), update.get(newDbName.toLowerCase()));
+ assertFalse(update.containsKey(DB.toLowerCase()));
+ }
+
+ @Test
+ /**
+ * Test alter table event that changes database name when there are tables.
+ * All entries like "dbName.tableName" should have dbName changed to the new name.
+ * @throws Exception
+ */
+ public void testAlterTableChangeDbNameWithTables() throws Exception {
+ Map<String, Collection<String>> update = new HashMap<>();
+ update.put(DB.toLowerCase(), Collections.singleton(PATH));
+ Set<String> locations = new HashSet<>(1);
+ locations.add(PATH);
+ update.put(AUTH, locations);
+
+ String newDbName = "Db2";
+ String newAuth = newDbName.toLowerCase() + "." + TABLE.toLowerCase();
+
+ NotificationEvent event = new NotificationEvent(0, 0, ALTER_TABLE.toString(), "");
+ event.setDbName(newDbName);
+ event.setTableName(TABLE);
+
+ MessageDeserializer deserializer = Mockito.mock(SentryJSONMessageDeserializer.class);
+
+ SentryJSONAlterTableMessage message =
+ new SentryJSONAlterTableMessage(SERVER, PRINCIPAL, TABLE_OBJ, TABLE_OBJ, 0L);
+
+ Mockito.when(deserializer.getAlterTableMessage("")).thenReturn(message);
+ FullUpdateModifier.applyEvent(update, event, deserializer);
+ Map<String, Set<String>> expected = new HashMap<>(2);
+ expected.put(newDbName.toLowerCase(), Collections.singleton(PATH));
+ expected.put(newAuth, Collections.singleton(PATH));
+ assertEquals(expected, update);
+ }
+
+ /**
+ * Test alter table event that changes table name.
+ * @throws Exception
+ */
+ @Test
+ public void testAlterTableChangeTableName() throws Exception {
+ Map<String, Collection<String>> update = new HashMap<>();
+ update.put(DB.toLowerCase(), Collections.singleton(PATH));
+ Set<String> locations = new HashSet<>(1);
+ locations.add(PATH);
+ update.put(AUTH, locations);
+
+ String newTableName = "Table2";
+ String newAuth = DB.toLowerCase() + "." + newTableName.toLowerCase();
+
+ NotificationEvent event = new NotificationEvent(0, 0, ALTER_TABLE.toString(), "");
+ event.setDbName(DB);
+ event.setTableName(newTableName);
+
+ MessageDeserializer deserializer = Mockito.mock(SentryJSONMessageDeserializer.class);
+
+ SentryJSONAlterTableMessage message =
+ new SentryJSONAlterTableMessage(SERVER, PRINCIPAL, TABLE_OBJ, TABLE_OBJ, 0L);
+
+ Mockito.when(deserializer.getAlterTableMessage("")).thenReturn(message);
+ FullUpdateModifier.applyEvent(update, event, deserializer);
+ Map<String, Set<String>> expected = new HashMap<>(2);
+ expected.put(DB.toLowerCase(), Collections.singleton(PATH));
+ expected.put(newAuth, Collections.singleton(PATH));
+ assertEquals(expected, update);
+ }
+
+ /**
+ * Test alter table event that changes object location.
+ * @throws Exception
+ */
+ @Test
+ public void testAlterTableChangeLocation() throws Exception {
+ Map<String, Collection<String>> update = new HashMap<>();
+ update.put(DB.toLowerCase(), Collections.singleton(PATH));
+ Set<String> locations = new HashSet<>(1);
+ locations.add(PATH);
+ update.put(AUTH, locations);
+
+ NotificationEvent event = new NotificationEvent(0, 0, ALTER_TABLE.toString(), "");
+ event.setDbName(DB);
+ event.setTableName(TABLE);
+
+ String newPath = "hello/world";
+ String newLocation = uri(newPath);
+
+ MessageDeserializer deserializer = Mockito.mock(SentryJSONMessageDeserializer.class);
+
+ Table tableWithNewLocation = buildTable(DB, TABLE, newLocation);
+ SentryJSONAlterTableMessage message =
+ new SentryJSONAlterTableMessage(SERVER, PRINCIPAL, TABLE_OBJ, tableWithNewLocation, 0L);
+
+ Mockito.when(deserializer.getAlterTableMessage("")).thenReturn(message);
+ FullUpdateModifier.applyEvent(update, event, deserializer);
+ Map<String, Set<String>> expected = new HashMap<>(2);
+ expected.put(DB.toLowerCase(), Collections.singleton(PATH));
+ expected.put(AUTH.toLowerCase(), Collections.singleton(newPath));
+ assertEquals(expected, update);
+ }
+
+ /**
+ * Test renamePrefixKeys function.
+ * We ask to rename "foo.bar" key to "foo.baz" key.
+ * @throws Exception
+ */
+ @Test
+ public void testRenamePrefixKeys() throws Exception {
+ String oldKey = "foo.";
+ String newKey = "baz.";
+ String postfix = "bar";
+ Map<String, Collection<String>> update = new HashMap<>();
+ update.put(oldKey + postfix , Collections.<String>emptySet());
+ FullUpdateModifier.renamePrefixKeys(update, oldKey, newKey);
+ assertEquals(1, update.size());
+ assertTrue(update.containsKey(newKey + postfix));
+ }
+
+ /**
+ * Test renamePostfixKeys and RenamePrefixKeys functions mwhen the destination keys exist.
+ * Should nto change anything.
+ * We ask to rename "foo.bar" key to "baz.bar" key.
+ * @throws Exception
+ */
+ @Test
+ public void testRenameKeysWithConflicts() throws Exception {
+ Map<String, Collection<String>> update = new HashMap<>();
+ update.put("foo.bar", Collections.<String>emptySet());
+ update.put("baz.bar", Collections.<String>emptySet());
+ Map<String, Collection<String>> expected = new HashMap<>(update);
+
+ FullUpdateModifier.renamePrefixKeys(update, "foo.", "baz.");
+ assertEquals(update, expected);
+ }
+}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/sentry/blob/9351d19d/sentry-provider/sentry-provider-db/src/test/java/org/apache/sentry/service/thrift/TestHiveNotificationFetcher.java
----------------------------------------------------------------------
diff --git a/sentry-provider/sentry-provider-db/src/test/java/org/apache/sentry/service/thrift/TestHiveNotificationFetcher.java b/sentry-provider/sentry-provider-db/src/test/java/org/apache/sentry/service/thrift/TestHiveNotificationFetcher.java
new file mode 100644
index 0000000..83a1bec
--- /dev/null
+++ b/sentry-provider/sentry-provider-db/src/test/java/org/apache/sentry/service/thrift/TestHiveNotificationFetcher.java
@@ -0,0 +1,163 @@
+/*
+ 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
+ <p>
+ http://www.apache.org/licenses/LICENSE-2.0
+ <p>
+ 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.service.thrift;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
+import org.apache.hadoop.hive.metastore.HiveMetaStoreClient;
+import org.apache.hadoop.hive.metastore.IMetaStoreClient.NotificationFilter;
+import org.apache.hadoop.hive.metastore.api.NotificationEvent;
+import org.apache.hadoop.hive.metastore.api.NotificationEventResponse;
+import org.apache.sentry.hdfs.UniquePathsUpdate;
+import org.apache.sentry.provider.db.service.persistent.SentryStore;
+import org.junit.Test;
+import org.mockito.Mockito;
+import org.mockito.invocation.InvocationOnMock;
+import org.mockito.stubbing.Answer;
+
+public class TestHiveNotificationFetcher {
+ @Test
+ public void testGetEmptyNotificationsWhenHmsReturnsANullResponse() throws Exception {
+ SentryStore store = Mockito.mock(SentryStore.class);
+ HiveConnectionFactory hmsConnection = Mockito.mock(HiveConnectionFactory.class);
+ HiveMetaStoreClient hmsClient = Mockito.mock(HiveMetaStoreClient.class);
+
+ Mockito.when(hmsConnection.connect()).thenReturn(new HMSClient(hmsClient));
+
+ try (HiveNotificationFetcher fetcher = new HiveNotificationFetcher(store, hmsConnection)) {
+ List<NotificationEvent> events;
+
+ Mockito.when(hmsClient.getNextNotification(0, Integer.MAX_VALUE, null))
+ .thenReturn(null);
+
+ events = fetcher.fetchNotifications(0);
+ assertTrue(events.isEmpty());
+ }
+ }
+
+ @Test
+ public void testGetEmptyNotificationsWhenHmsReturnsEmptyEvents() throws Exception {
+ SentryStore store = Mockito.mock(SentryStore.class);
+ HiveConnectionFactory hmsConnection = Mockito.mock(HiveConnectionFactory.class);
+ HiveMetaStoreClient hmsClient = Mockito.mock(HiveMetaStoreClient.class);
+
+ Mockito.when(hmsConnection.connect()).thenReturn(new HMSClient(hmsClient));
+
+ try (HiveNotificationFetcher fetcher = new HiveNotificationFetcher(store, hmsConnection)) {
+ List<NotificationEvent> events;
+
+ Mockito.when(hmsClient.getNextNotification(0, Integer.MAX_VALUE, null))
+ .thenReturn(new NotificationEventResponse(Collections.<NotificationEvent>emptyList()));
+
+ events = fetcher.fetchNotifications(0);
+ assertTrue(events.isEmpty());
+ }
+ }
+
+ @Test
+ public void testGetAllNotificationsReturnedByHms() throws Exception {
+ SentryStore store = Mockito.mock(SentryStore.class);
+ HiveConnectionFactory hmsConnection = Mockito.mock(HiveConnectionFactory.class);
+ HiveMetaStoreClient hmsClient = Mockito.mock(HiveMetaStoreClient.class);
+
+ Mockito.when(hmsConnection.connect()).thenReturn(new HMSClient(hmsClient));
+
+ try (HiveNotificationFetcher fetcher = new HiveNotificationFetcher(store, hmsConnection)) {
+ List<NotificationEvent> events;
+
+ Mockito.when(hmsClient.getNextNotification(0, Integer.MAX_VALUE, null))
+ .thenReturn(new NotificationEventResponse(
+ Arrays.<NotificationEvent>asList(
+ new NotificationEvent(1L, 0, "CREATE_DATABASE", ""),
+ new NotificationEvent(2L, 0, "CREATE_TABLE", "")
+ )
+ ));
+
+ events = fetcher.fetchNotifications(0);
+ assertEquals(2, events.size());
+ assertEquals(1, events.get(0).getEventId());
+ assertEquals("CREATE_DATABASE", events.get(0).getEventType());
+ assertEquals(2, events.get(1).getEventId());
+ assertEquals("CREATE_TABLE", events.get(1).getEventType());
+ }
+ }
+
+ @Test
+ public void testGetDuplicatedEventsAndFilterEventsAlreadySeen() throws Exception {
+ final SentryStore store = Mockito.mock(SentryStore.class);
+ HiveConnectionFactory hmsConnection = Mockito.mock(HiveConnectionFactory.class);
+ HiveMetaStoreClient hmsClient = Mockito.mock(HiveMetaStoreClient.class);
+
+ Mockito.when(hmsConnection.connect()).thenReturn(new HMSClient(hmsClient));
+
+ try (HiveNotificationFetcher fetcher = new HiveNotificationFetcher(store, hmsConnection)) {
+ List<NotificationEvent> events;
+
+ /*
+ * Requesting an ID > 0 will request all notifications from 0 again but filter those
+ * already seen notifications with ID = 1
+ */
+
+ // This mock will also test that the NotificationFilter works as expected
+ Mockito.when(hmsClient.getNextNotification(Mockito.eq(0L), Mockito.eq(Integer.MAX_VALUE),
+ (NotificationFilter) Mockito.notNull())).thenAnswer(new Answer<NotificationEventResponse>() {
+ @Override
+ public NotificationEventResponse answer(InvocationOnMock invocation)
+ throws Throwable {
+ NotificationFilter filter = (NotificationFilter) invocation.getArguments()[2];
+ NotificationEventResponse response = new NotificationEventResponse();
+
+ List<NotificationEvent> events = Arrays.<NotificationEvent>asList(
+ new NotificationEvent(1L, 0, "CREATE_DATABASE", ""),
+ new NotificationEvent(1L, 0, "CREATE_TABLE", ""),
+ new NotificationEvent(2L, 0, "ALTER_TABLE", "")
+ );
+
+ for (NotificationEvent event : events) {
+ String hash = UniquePathsUpdate.sha1(event);
+
+ // We simulate that CREATE_DATABASE is already processed
+ if (event.getEventType().equals("CREATE_DATABASE")) {
+ Mockito.when(store.isNotificationProcessed(Mockito.eq(hash))).thenReturn(true);
+ } else {
+ Mockito.when(store.isNotificationProcessed(Mockito.eq(hash))).thenReturn(false);
+ }
+
+ if (filter.accept(event)) {
+ response.addToEvents(event);
+ }
+ }
+
+ return response;
+ }
+ });
+
+ events = fetcher.fetchNotifications(1);
+ assertEquals(2, events.size());
+ assertEquals(1, events.get(0).getEventId());
+ assertEquals("CREATE_TABLE", events.get(0).getEventType());
+ assertEquals(2, events.get(1).getEventId());
+ assertEquals("ALTER_TABLE", events.get(1).getEventType());
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/sentry/blob/9351d19d/sentry-provider/sentry-provider-db/src/test/java/org/apache/sentry/service/thrift/TestSentryHMSClient.java
----------------------------------------------------------------------
diff --git a/sentry-provider/sentry-provider-db/src/test/java/org/apache/sentry/service/thrift/TestSentryHMSClient.java b/sentry-provider/sentry-provider-db/src/test/java/org/apache/sentry/service/thrift/TestSentryHMSClient.java
new file mode 100644
index 0000000..38668ca
--- /dev/null
+++ b/sentry-provider/sentry-provider-db/src/test/java/org/apache/sentry/service/thrift/TestSentryHMSClient.java
@@ -0,0 +1,344 @@
+/*
+ * 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.service.thrift;
+
+import com.google.common.collect.Lists;
+import com.google.common.collect.Sets;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+import org.apache.hadoop.conf.Configuration;
+import org.apache.hadoop.hive.metastore.HiveMetaStoreClient;
+import org.apache.hadoop.hive.metastore.api.CurrentNotificationEventId;
+import org.apache.hadoop.hive.metastore.api.Database;
+import org.apache.hadoop.hive.metastore.api.MetaException;
+import org.apache.hadoop.hive.metastore.api.Partition;
+import org.apache.hadoop.hive.metastore.api.StorageDescriptor;
+import org.apache.hadoop.hive.metastore.api.Table;
+import org.apache.sentry.provider.db.service.persistent.PathsImage;
+import org.apache.thrift.TException;
+import org.junit.Assert;
+import org.junit.BeforeClass;
+import org.junit.Test;
+import org.mockito.Mockito;
+import org.mockito.invocation.InvocationOnMock;
+import org.mockito.stubbing.Answer;
+
+import javax.security.auth.login.LoginException;
+
+/**
+ * Test mocks HiveMetaStoreClient class and tests SentryHMSClient.
+ */
+public class TestSentryHMSClient {
+
+ private static final Configuration conf = new Configuration();
+ private static SentryHMSClient client;
+ private static MockHMSClientFactory hiveConnectionFactory;
+
+ /**
+ * Create mock database with the given name
+ *
+ * @param name Database name
+ * @return Mock database object
+ */
+ private static Database makeDb(String name) {
+ Database db = Mockito.mock(Database.class);
+ Mockito.when(db.getName()).thenReturn(name);
+ Mockito.when(db.getLocationUri()).thenReturn("hdfs:///" + name);
+ return db;
+ }
+
+ /**
+ * Create mock table
+ *
+ * @param dbName db for this table
+ * @param tableName name of the table
+ * @return mock table object
+ */
+ private static Table makeTable(String dbName, String tableName) {
+ Table table = Mockito.mock(Table.class);
+ Mockito.when(table.getDbName()).thenReturn(dbName);
+ Mockito.when(table.getTableName()).thenReturn(tableName);
+ StorageDescriptor sd = Mockito.mock(StorageDescriptor.class);
+ Mockito.when(sd.getLocation()).thenReturn(
+ String.format("hdfs:///%s/%s", dbName, tableName));
+ Mockito.when(table.getSd()).thenReturn(sd);
+ return table;
+ }
+
+ /**
+ * Create mock partition
+ *
+ * @param dbName database for this partition
+ * @param tableName table for this partition
+ * @param partName partition name
+ * @return mock partition object
+ */
+ private static Partition makePartition(String dbName, String tableName, String partName) {
+ Partition partition = Mockito.mock(Partition.class);
+ StorageDescriptor sd = Mockito.mock(StorageDescriptor.class);
+ Mockito.when(sd.getLocation()).thenReturn(
+ String.format("hdfs:///%s/%s/%s", dbName, tableName, partName));
+ Mockito.when(partition.getSd()).thenReturn(sd);
+ return partition;
+ }
+
+ @BeforeClass
+ static public void initialize() throws IOException, LoginException {
+ hiveConnectionFactory = new MockHMSClientFactory();
+ client = new SentryHMSClient(conf, (HiveConnectionFactory)hiveConnectionFactory);
+ }
+
+ /**
+ * Creating snapshot when SentryHMSClient is not connected to HMS
+ */
+ @Test
+ public void testSnapshotCreationWithOutClientConnected() throws Exception {
+ // Make sure that client is not connected
+ Assert.assertFalse(client.isConnected());
+ PathsImage snapshotInfo = client.getFullSnapshot();
+ Assert.assertTrue(snapshotInfo.getPathImage().isEmpty());
+ }
+
+ /**
+ * Creating snapshot when HMS doesn't have any data
+ */
+ @Test
+ public void testSnapshotCreationWithNoHmsData() throws Exception {
+ MockClient mockClient = new MockClient(new HiveSnapshot(), 1);
+ client.setClient(mockClient.client);
+ // Make sure that client is connected
+ Assert.assertTrue(client.isConnected());
+ PathsImage snapshotInfo = client.getFullSnapshot();
+ Assert.assertTrue(snapshotInfo.getPathImage().isEmpty());
+ }
+
+ /**
+ * Creating a snapshot when there is data but there are updates to HMS data mean while
+ */
+ @Test
+ public void testSnapshotCreationWhenDataIsActivelyUpdated() throws Exception {
+ HiveTable tab21 = new HiveTable("tab21");
+ HiveTable tab31 = new HiveTable("tab31").add("part311").add("part312");
+ HiveDb db3 = new HiveDb("db3", Lists.newArrayList(tab31));
+ HiveDb db2 = new HiveDb("db2", Lists.newArrayList(tab21));
+ HiveDb db1 = new HiveDb("db1");
+ HiveSnapshot snap = new HiveSnapshot().add(db1).add(db2).add(db3);
+ final MockClient mockClient = new MockClient(snap, 1);
+
+ client.setClient(mockClient.client);
+ hiveConnectionFactory.setClient(mockClient);
+ // Make sure that client is connected
+ Assert.assertTrue(client.isConnected());
+ PathsImage snapshotInfo = client.getFullSnapshot();
+ // Make sure that snapshot is not empty
+ Assert.assertTrue(!snapshotInfo.getPathImage().isEmpty());
+
+ Mockito.when(mockClient.client.getCurrentNotificationEventId()).
+ thenAnswer(new Answer<CurrentNotificationEventId>() {
+ @Override
+ public CurrentNotificationEventId answer(InvocationOnMock invocation)
+ throws Throwable {
+ return new CurrentNotificationEventId(mockClient.incrementNotificationEventId());
+ }
+
+ });
+
+ snapshotInfo = client.getFullSnapshot();
+ Assert.assertTrue(snapshotInfo.getPathImage().isEmpty());
+ }
+
+ /**
+ * Creating a snapshot when there is data in HMS.
+ */
+ @Test
+ public void testSnapshotCreationSuccess() throws Exception {
+ HiveTable tab21 = new HiveTable("tab21");
+ HiveTable tab31 = new HiveTable("tab31");
+ HiveDb db3 = new HiveDb("db3", Lists.newArrayList(tab31));
+ HiveDb db2 = new HiveDb("db2", Lists.newArrayList(tab21));
+ HiveDb db1 = new HiveDb("db1");
+ HiveSnapshot snap = new HiveSnapshot().add(db1).add(db2).add(db3);
+ MockClient mockClient = new MockClient(snap, 1);
+ Mockito.when(mockClient.client.getCurrentNotificationEventId()).
+ thenReturn(new CurrentNotificationEventId(mockClient.eventId));
+ client.setClient(mockClient.client);
+ hiveConnectionFactory.setClient(mockClient);
+ // Make sure that client is connected
+ Assert.assertTrue(client.isConnected());
+
+ PathsImage snapshotInfo = client.getFullSnapshot();
+ Assert.assertEquals(5, snapshotInfo.getPathImage().size());
+ Assert.assertEquals(Sets.newHashSet("db1"), snapshotInfo.getPathImage().get("db1"));
+ Assert.assertEquals(Sets.newHashSet("db2"), snapshotInfo.getPathImage().get("db2"));
+ Assert.assertEquals(Sets.newHashSet("db3"), snapshotInfo.getPathImage().get("db3"));
+ Assert.assertEquals(Sets.newHashSet("db2/tab21"),
+ snapshotInfo.getPathImage().get("db2.tab21"));
+ Assert.assertEquals(Sets.newHashSet("db3/tab31"), snapshotInfo.getPathImage().get("db3.tab31"));
+ Assert.assertEquals(snapshotInfo.getId(), mockClient.eventId);
+
+ }
+
+ /**
+ * Representation of a Hive table. A table has a name and a list of partitions.
+ */
+ private static class HiveTable {
+
+ private final String name;
+ private final List<String> partitions;
+
+ HiveTable(String name) {
+ this.name = name;
+ this.partitions = new ArrayList<>();
+ }
+
+ HiveTable add(String partition) {
+ partitions.add(partition);
+ return this;
+ }
+ }
+
+ /**
+ * Representation of a Hive database. A database has a name and a list of tables
+ */
+ private static class HiveDb {
+
+ final String name;
+ Collection<HiveTable> tables;
+
+ @SuppressWarnings("SameParameterValue")
+ HiveDb(String name) {
+ this.name = name;
+ tables = new ArrayList<>();
+ }
+
+ HiveDb(String name, Collection<HiveTable> tables) {
+ this.name = name;
+ this.tables = tables;
+ if (this.tables == null) {
+ this.tables = new ArrayList<>();
+ }
+ }
+
+ void add(HiveTable table) {
+ this.tables.add(table);
+ }
+ }
+
+ /**
+ * Representation of a full Hive snapshot. A snapshot is collection of databases
+ */
+ private static class HiveSnapshot {
+
+ final List<HiveDb> databases = new ArrayList<>();
+
+ HiveSnapshot() {
+ }
+
+ HiveSnapshot(Collection<HiveDb> dblist) {
+ if (dblist != null) {
+ databases.addAll(dblist);
+ }
+ }
+
+ HiveSnapshot add(HiveDb db) {
+ this.databases.add(db);
+ return this;
+ }
+ }
+
+ /**
+ * Mock for HMSClientFactory
+ */
+ private static class MockHMSClientFactory implements HiveConnectionFactory {
+
+ private HiveMetaStoreClient mClient;
+
+ public MockHMSClientFactory() {
+ mClient = null;
+ }
+
+ void setClient(MockClient mockClient) {
+ this.mClient = mockClient.client;
+ }
+ @Override
+ public HMSClient connect() throws IOException, InterruptedException, MetaException {
+ return new HMSClient(mClient);
+ }
+
+ @Override
+ public void close() throws Exception {
+ }
+ }
+
+ /**
+ * Convert Hive snapshot to mock client that will return proper values
+ * for the snapshot.
+ */
+ private static class MockClient {
+
+ public HiveMetaStoreClient client;
+ public long eventId;
+
+ MockClient(HiveSnapshot snapshot, long eventId) throws TException {
+ this.eventId = eventId;
+ client = Mockito.mock(HiveMetaStoreClient.class);
+ List<String> dbNames = new ArrayList<>(snapshot.databases.size());
+ // Walk over all databases and mock appropriate objects
+ for (HiveDb mdb : snapshot.databases) {
+ String dbName = mdb.name;
+ dbNames.add(dbName);
+ Database db = makeDb(dbName);
+ Mockito.when(client.getDatabase(dbName)).thenReturn(db);
+ List<String> tableNames = new ArrayList<>(mdb.tables.size());
+ // Walk over all tables for the database and mock appropriate objects
+ for (HiveTable table : mdb.tables) {
+ String tableName = table.name;
+ tableNames.add(tableName);
+ Table mockTable = makeTable(dbName, tableName);
+ Mockito.when(client.getTableObjectsByName(dbName,
+ Lists.newArrayList(tableName)))
+ .thenReturn(Lists.newArrayList(mockTable));
+ Mockito.when(client.listPartitionNames(dbName, tableName, (short) -1))
+ .thenReturn(table.partitions);
+ // Walk across all partitions and mock appropriate objects
+ for (String partName : table.partitions) {
+ Partition p = makePartition(dbName, tableName, partName);
+ Mockito.when(client.getPartitionsByNames(dbName, tableName,
+ Lists.<String>newArrayList(partName)))
+ .thenReturn(Lists.<Partition>newArrayList(p));
+ }
+ }
+ Mockito.when(client.getAllTables(dbName)).thenReturn(tableNames);
+ }
+ // Return all database names
+ Mockito.when(client.getAllDatabases()).thenReturn(dbNames);
+ Mockito.when(client.getCurrentNotificationEventId()).
+ thenReturn(new CurrentNotificationEventId(eventId));
+
+ }
+
+ public Long incrementNotificationEventId() {
+ eventId = eventId + 1;
+ return eventId;
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/sentry/blob/9351d19d/sentry-provider/sentry-provider-db/src/test/java/org/apache/sentry/service/thrift/TestSentryStateBank.java
----------------------------------------------------------------------
diff --git a/sentry-provider/sentry-provider-db/src/test/java/org/apache/sentry/service/thrift/TestSentryStateBank.java b/sentry-provider/sentry-provider-db/src/test/java/org/apache/sentry/service/thrift/TestSentryStateBank.java
new file mode 100644
index 0000000..4f71e1c
--- /dev/null
+++ b/sentry-provider/sentry-provider-db/src/test/java/org/apache/sentry/service/thrift/TestSentryStateBank.java
@@ -0,0 +1,84 @@
+/**
+ * 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.service.thrift;
+
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+import java.util.Arrays;
+import java.util.HashSet;
+import org.junit.Before;
+import org.junit.Test;
+
+/**
+ *
+ */
+public class TestSentryStateBank {
+
+ @Before
+ public void setUp() {
+ SentryStateBank.clearAllStates();
+ }
+
+ @Test
+ public void testEnableState() {
+ SentryStateBank.enableState(TestState.COMPONENT, TestState.FIRST_STATE);
+ assertTrue("Expected FIRST_STATE to be enabled",
+ SentryStateBank.isEnabled(TestState.COMPONENT, TestState.FIRST_STATE));
+ assertFalse("Expected SECOND_STATE to be disabled",
+ SentryStateBank.isEnabled(TestState.COMPONENT, TestState.SECOND_STATE));
+ }
+
+ @Test
+ public void testStatesGetDisabled() {
+ SentryStateBank.enableState(TestState.COMPONENT, TestState.FIRST_STATE);
+ assertTrue("Expected FIRST_STATE to be enabled",
+ SentryStateBank.isEnabled(TestState.COMPONENT, TestState.FIRST_STATE));
+ SentryStateBank.disableState(TestState.COMPONENT, TestState.FIRST_STATE);
+ assertFalse("Expected FIRST_STATE to be disabled",
+ SentryStateBank.isEnabled(TestState.COMPONENT, TestState.FIRST_STATE));
+ }
+
+ @Test
+ public void testCheckMultipleStateCheckSuccess() {
+ SentryStateBank.enableState(TestState.COMPONENT, TestState.FIRST_STATE);
+ SentryStateBank.enableState(TestState.COMPONENT, TestState.SECOND_STATE);
+
+ assertTrue("Expected both FIRST_STATE and SECOND_STATE to be enabled",
+ SentryStateBank.hasStatesEnabled(TestState.COMPONENT, new HashSet<SentryState>(
+ Arrays.asList(TestState.FIRST_STATE, TestState.SECOND_STATE))));
+ }
+
+ @Test
+ public void testCheckMultipleStateCheckFailure() {
+ SentryStateBank.enableState(TestState.COMPONENT, TestState.FIRST_STATE);
+ assertFalse("Expected only FIRST_STATE to be enabled",
+ SentryStateBank.hasStatesEnabled(TestState.COMPONENT, new HashSet<SentryState>(
+ Arrays.asList(TestState.FIRST_STATE, TestState.SECOND_STATE))));
+ }
+
+
+ public enum TestState implements SentryState {
+ FIRST_STATE,
+ SECOND_STATE;
+
+ public static final String COMPONENT = "TestState";
+
+ @Override
+ public long getValue() {
+ return 1 << this.ordinal();
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/sentry/blob/9351d19d/sentry-service/pom.xml
----------------------------------------------------------------------
diff --git a/sentry-service/pom.xml b/sentry-service/pom.xml
index b63467b..0388476 100644
--- a/sentry-service/pom.xml
+++ b/sentry-service/pom.xml
@@ -31,8 +31,6 @@ limitations under the License.
<modules>
<module>sentry-service-api</module>
- <module>sentry-service-server</module>
- <module>sentry-service-client</module>
</modules>
</project>
http://git-wip-us.apache.org/repos/asf/sentry/blob/9351d19d/sentry-service/sentry-service-client/pom.xml
----------------------------------------------------------------------
diff --git a/sentry-service/sentry-service-client/pom.xml b/sentry-service/sentry-service-client/pom.xml
deleted file mode 100644
index a1ae8c8..0000000
--- a/sentry-service/sentry-service-client/pom.xml
+++ /dev/null
@@ -1,69 +0,0 @@
-<?xml version="1.0"?>
-<!--
-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.
--->
-<project xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd" xmlns="http://maven.apache.org/POM/4.0.0"
- xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
- <modelVersion>4.0.0</modelVersion>
- <parent>
- <groupId>org.apache.sentry</groupId>
- <artifactId>sentry-service</artifactId>
- <version>2.1.0-SNAPSHOT</version>
- </parent>
-
- <artifactId>sentry-service-client</artifactId>
- <name>Sentry Service Client</name>
-
- <dependencies>
- <dependency>
- <groupId>commons-lang</groupId>
- <artifactId>commons-lang</artifactId>
- </dependency>
- <dependency>
- <groupId>org.apache.derby</groupId>
- <artifactId>derby</artifactId>
- </dependency>
- <dependency>
- <groupId>org.slf4j</groupId>
- <artifactId>slf4j-api</artifactId>
- </dependency>
- <dependency>
- <groupId>org.slf4j</groupId>
- <artifactId>slf4j-log4j12</artifactId>
- </dependency>
- <dependency>
- <groupId>org.apache.thrift</groupId>
- <artifactId>libfb303</artifactId>
- <version>${libfb303.version}</version>
- </dependency>
- <dependency>
- <groupId>org.apache.thrift</groupId>
- <artifactId>libthrift</artifactId>
- <version>${libthrift.version}</version>
- </dependency>
- <dependency>
- <groupId>org.apache.sentry</groupId>
- <artifactId>sentry-service-api</artifactId>
- <version>${project.version}</version>
- </dependency>
- <dependency>
- <groupId>junit</groupId>
- <artifactId>junit</artifactId>
- <scope>test</scope>
- </dependency>
- </dependencies>
-
-</project>
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/sentry/blob/9351d19d/sentry-service/sentry-service-client/src/main/java/org/apache/sentry/service/thrift/SentryServiceClientFactory.java
----------------------------------------------------------------------
diff --git a/sentry-service/sentry-service-client/src/main/java/org/apache/sentry/service/thrift/SentryServiceClientFactory.java b/sentry-service/sentry-service-client/src/main/java/org/apache/sentry/service/thrift/SentryServiceClientFactory.java
deleted file mode 100644
index d146a0d..0000000
--- a/sentry-service/sentry-service-client/src/main/java/org/apache/sentry/service/thrift/SentryServiceClientFactory.java
+++ /dev/null
@@ -1,111 +0,0 @@
-/**
- * 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
- * <p>
- * http://www.apache.org/licenses/LICENSE-2.0
- * <p>
- * 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.service.thrift;
-
-import org.apache.hadoop.conf.Configuration;
-import org.apache.sentry.core.common.transport.RetryClientInvocationHandler;
-import org.apache.sentry.core.common.transport.SentryPolicyClientTransportConfig;
-import org.apache.sentry.core.common.transport.SentryTransportFactory;
-import org.apache.sentry.core.common.transport.SentryTransportPool;
-import org.apache.sentry.api.service.thrift.SentryPolicyServiceClient;
-import org.apache.sentry.api.service.thrift.SentryPolicyServiceClientDefaultImpl;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import javax.annotation.concurrent.ThreadSafe;
-import java.lang.reflect.Proxy;
-import java.util.concurrent.atomic.AtomicReference;
-
-/**
- * Client factory for Hive clients. The factory uses connection pooling.
- */
-@ThreadSafe
-public final class SentryServiceClientFactory {
- private static final Logger LOGGER = LoggerFactory.getLogger(SentryServiceClientFactory.class);
-
- private static final SentryPolicyClientTransportConfig transportConfig =
- new SentryPolicyClientTransportConfig();
- private final Configuration conf;
- private final SentryTransportPool transportPool;
-
- /** Keep track of singleton instances */
- private static final AtomicReference<SentryServiceClientFactory> clientFactory =
- new AtomicReference<>();
-
- /**
- * Create a client instance. The supplied configuration is only used the first time and
- * ignored afterwords. Tests that want to supply different configurations
- * should call {@link #factoryReset(SentryServiceClientFactory)} to force new configuration
- * read.
- * @param conf Configuration
- * @return client instance
- * @throws Exception
- */
- public static SentryPolicyServiceClient create(Configuration conf) throws Exception {
- SentryServiceClientFactory factory = clientFactory.get();
- if (factory != null) {
- return factory.create();
- }
- factory = new SentryServiceClientFactory(conf);
- boolean ok = clientFactory.compareAndSet(null, factory);
- if (ok) {
- return factory.create();
- }
- // Close old factory
- factory.close();
- return clientFactory.get().create();
- }
-
- /**
- * Create a new instance of the factory which will hand hand off connections from
- * the pool.
- * @param conf Configuration object
- */
- private SentryServiceClientFactory(Configuration conf) {
- this.conf = conf;
-
- transportPool = new SentryTransportPool(conf, transportConfig,
- new SentryTransportFactory(conf, transportConfig));
- }
-
- private SentryPolicyServiceClient create() throws Exception {
- return (SentryPolicyServiceClient) Proxy
- .newProxyInstance(SentryPolicyServiceClientDefaultImpl.class.getClassLoader(),
- SentryPolicyServiceClientDefaultImpl.class.getInterfaces(),
- new RetryClientInvocationHandler(conf,
- new SentryPolicyServiceClientDefaultImpl(conf, transportPool), transportConfig));
- }
-
- /**
- * Reset existing factory and return the old one.
- * Only used by tests.
- */
- public static SentryServiceClientFactory factoryReset(SentryServiceClientFactory factory) {
- LOGGER.debug("factory reset");
- return clientFactory.getAndSet(factory);
- }
-
- public void close() {
- try {
- transportPool.close();
- } catch (Exception e) {
- LOGGER.error("failed to close transport pool", e);
- }
- }
-}
http://git-wip-us.apache.org/repos/asf/sentry/blob/9351d19d/sentry-service/sentry-service-server/pom.xml
----------------------------------------------------------------------
diff --git a/sentry-service/sentry-service-server/pom.xml b/sentry-service/sentry-service-server/pom.xml
deleted file mode 100644
index a103c1e..0000000
--- a/sentry-service/sentry-service-server/pom.xml
+++ /dev/null
@@ -1,321 +0,0 @@
-<?xml version="1.0"?>
-<!--
-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.
--->
-<project xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd" xmlns="http://maven.apache.org/POM/4.0.0"
- xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
- <modelVersion>4.0.0</modelVersion>
- <parent>
- <groupId>org.apache.sentry</groupId>
- <artifactId>sentry-service</artifactId>
- <version>2.1.0-SNAPSHOT</version>
- </parent>
-
- <artifactId>sentry-service-server</artifactId>
- <name>Sentry Service Server</name>
-
- <dependencies>
- <dependency>
- <groupId>commons-lang</groupId>
- <artifactId>commons-lang</artifactId>
- </dependency>
- <dependency>
- <groupId>org.apache.derby</groupId>
- <artifactId>derby</artifactId>
- </dependency>
- <dependency>
- <groupId>org.slf4j</groupId>
- <artifactId>slf4j-api</artifactId>
- </dependency>
- <dependency>
- <groupId>org.slf4j</groupId>
- <artifactId>slf4j-log4j12</artifactId>
- </dependency>
- <dependency>
- <groupId>org.apache.thrift</groupId>
- <artifactId>libfb303</artifactId>
- <version>${libfb303.version}</version>
- </dependency>
- <dependency>
- <groupId>org.apache.thrift</groupId>
- <artifactId>libthrift</artifactId>
- <version>${libthrift.version}</version>
- </dependency>
- <dependency>
- <groupId>org.apache.curator</groupId>
- <artifactId>curator-test</artifactId>
- <scope>test</scope>
- </dependency>
- <dependency>
- <groupId>org.apache.sentry</groupId>
- <artifactId>sentry-service-api</artifactId>
- <version>${project.version}</version>
- </dependency>
- <dependency>
- <groupId>org.apache.sentry</groupId>
- <artifactId>sentry-provider-file</artifactId>
- <version>${project.version}</version>
- </dependency>
- <dependency>
- <groupId>org.apache.sentry</groupId>
- <artifactId>sentry-service-client</artifactId>
- <version>${project.version}</version>
- </dependency>
- <dependency>
- <groupId>org.apache.sentry</groupId>
- <artifactId>sentry-core-common</artifactId>
- <version>${project.version}</version>
- </dependency>
- <dependency>
- <groupId>org.apache.sentry</groupId>
- <artifactId>sentry-core-model-db</artifactId>
- </dependency>
- <dependency>
- <groupId>org.apache.sentry</groupId>
- <artifactId>sentry-core-model-kafka</artifactId>
- </dependency>
- <dependency>
- <groupId>org.apache.sentry</groupId>
- <artifactId>sentry-core-model-solr</artifactId>
- </dependency>
- <dependency>
- <groupId>org.apache.sentry</groupId>
- <artifactId>sentry-core-model-sqoop</artifactId>
- </dependency>
- <dependency>
- <groupId>org.apache.sentry</groupId>
- <artifactId>sentry-hdfs-common</artifactId>
- </dependency>
- <dependency>
- <groupId>org.apache.sentry</groupId>
- <artifactId>sentry-binding-hive-follower</artifactId>
- <version>${project.version}</version>
- <exclusions>
- <exclusion>
- <groupId>org.apache.hive</groupId>
- <artifactId>hive-exec</artifactId>
- </exclusion>
- </exclusions>
- </dependency>
- <dependency>
- <groupId>org.datanucleus</groupId>
- <artifactId>datanucleus-core</artifactId>
- <version>${datanucleus-core.version}</version>
- </dependency>
- <dependency>
- <groupId>org.datanucleus</groupId>
- <artifactId>datanucleus-api-jdo</artifactId>
- <version>${datanucleus-api-jdo.version}</version>
- </dependency>
- <dependency>
- <groupId>org.datanucleus</groupId>
- <artifactId>datanucleus-rdbms</artifactId>
- <version>${datanucleus-rdbms.version}</version>
- </dependency>
- <dependency>
- <groupId>org.datanucleus</groupId>
- <artifactId>javax.jdo</artifactId>
- <version>${datanucleus-jdo.version}</version>
- </dependency>
- <dependency>
- <groupId>org.apache.hive</groupId>
- <artifactId>hive-metastore</artifactId>
- <version>${hive.version}</version>
- <exclusions>
- <!-- This dependency needs to be excluded to avoid compilation errors in the Eclipse build.
- Without this change, the Eclipse build classpath contains this jar file ahead of
- datanucleus javax.jdo*.jar. This error can not be reproduced with the maven build.
- Cause of compilation error : PersistenceManager class provided as part of this version,
- does not implement java.lang.AutoClosable interface. This breaks the usage of
- PersistenceManager inside try-with-resources clause in Sentry TransactionManager class.
- -->
- <exclusion>
- <groupId>javax.jdo</groupId>
- <artifactId>jdo-api</artifactId>
- </exclusion>
- <exclusion>
- <groupId>javax.jdo</groupId>
- <artifactId>jdo2-api</artifactId>
- </exclusion>
- <exclusion>
- <groupId>javax.jdo</groupId>
- <artifactId>jdo2-api-legacy</artifactId>
- </exclusion>
- </exclusions>
- </dependency>
- <dependency>
- <groupId>org.codehaus.jackson</groupId>
- <artifactId>jackson-core-asl</artifactId>
- </dependency>
- <dependency>
- <groupId>org.codehaus.jackson</groupId>
- <artifactId>jackson-mapper-asl</artifactId>
- </dependency>
- <dependency>
- <groupId>io.dropwizard.metrics</groupId>
- <artifactId>metrics-core</artifactId>
- <version>${metrics.version}</version>
- </dependency>
- <dependency>
- <groupId>io.dropwizard.metrics</groupId>
- <artifactId>metrics-servlets</artifactId>
- <version>${metrics.version}</version>
- </dependency>
- <dependency>
- <groupId>io.dropwizard.metrics</groupId>
- <artifactId>metrics-jvm</artifactId>
- <version>${metrics.version}</version>
- </dependency>
- <dependency>
- <groupId>org.eclipse.jetty</groupId>
- <artifactId>jetty-server</artifactId>
- <version>${jetty.version}</version>
- </dependency>
- <dependency>
- <groupId>org.eclipse.jetty</groupId>
- <artifactId>jetty-servlet</artifactId>
- <version>${jetty.version}</version>
- </dependency>
- <dependency>
- <groupId>org.mockito</groupId>
- <artifactId>mockito-all</artifactId>
- <scope>test</scope>
- </dependency>
- <dependency>
- <groupId>org.apache.hadoop</groupId>
- <artifactId>hadoop-minikdc</artifactId>
- <scope>test</scope>
- </dependency>
- <dependency>
- <groupId>junit</groupId>
- <artifactId>junit</artifactId>
- <scope>test</scope>
- </dependency>
- </dependencies>
-
- <build>
- <sourceDirectory>${basedir}/src/main/java</sourceDirectory>
- <testSourceDirectory>${basedir}/src/test/java</testSourceDirectory>
- <resources>
- <resource>
- <directory>../../sentry-service/sentry-service-server/src/main/java/org/apache/sentry/provider/db/service/model</directory>
- <includes>
- <include>package.jdo</include>
- </includes>
- </resource>
- <resource>
- <directory>${basedir}/src/main</directory>
- <includes>
- <include>webapp/*</include>
- <include>webapp/css/*</include>
- </includes>
- </resource>
- </resources>
- <plugins>
- <plugin>
- <groupId>com.google.code.maven-replacer-plugin</groupId>
- <artifactId>replacer</artifactId>
- <version>1.5.2</version>
- <executions>
- <execution>
- <id>replaceTokens</id>
- <phase>clean</phase>
- <goals>
- <goal>replace</goal>
- </goals>
- </execution>
- </executions>
- <configuration>
- <file>${basedir}/src/main/webapp/SentryService.html</file>
- <replacements>
- <replacement>
- <token>%PROJECT_VERSION%</token>
- <value>${version}</value>
- </replacement>
- </replacements>
- </configuration>
- </plugin>
- <plugin>
- <groupId>org.datanucleus</groupId>
- <artifactId>datanucleus-maven-plugin</artifactId>
- <configuration>
- <api>JDO</api>
- <metadataIncludes>**/*.jdo</metadataIncludes>
- <verbose>true</verbose>
- </configuration>
- <executions>
- <execution>
- <phase>process-classes</phase>
- <goals>
- <goal>enhance</goal>
- </goals>
- </execution>
- </executions>
- </plugin>
- <plugin>
- <groupId>org.apache.maven.plugins</groupId>
- <artifactId>maven-shade-plugin</artifactId>
- <version>${maven.shade.plugin.version}</version>
- <executions>
- <execution>
- <id>curator-shade</id>
- <phase>package</phase>
- <goals>
- <goal>shade</goal>
- </goals>
- <configuration>
- <artifactSet>
- <includes>
- <!-- This is needed to support projects running on different versions of curator -->
- <include>org.apache.curator:curator-recipes</include>
- <include>org.apache.curator:curator-x-discovery</include>
- <include>org.apache.curator:curator-framework</include>
- <include>org.apache.curator:curator-client</include>
- </includes>
- </artifactSet>
- <relocations>
- <!-- Adding prefix to the package to make it unique -->
- <relocation>
- <pattern>org.apache.curator</pattern>
- <shadedPattern>sentry.org.apache.curator</shadedPattern>
- </relocation>
- </relocations>
- <shadedArtifactAttached>false</shadedArtifactAttached>
- </configuration>
- </execution>
- </executions>
- </plugin>
- <plugin>
- <groupId>org.apache.maven.plugins</groupId>
- <artifactId>maven-jar-plugin</artifactId>
- <executions>
- <execution>
- <goals>
- <goal>test-jar</goal>
- </goals>
- </execution>
- </executions>
- </plugin>
- <plugin>
- <groupId>org.apache.maven.plugins</groupId>
- <artifactId>maven-surefire-plugin</artifactId>
- <configuration>
- <reuseForks>false</reuseForks>
- </configuration>
- </plugin>
- </plugins>
- </build>
-</project>
\ No newline at end of file