You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@sentry.apache.org by ak...@apache.org on 2017/07/28 17:06:24 UTC
[06/50] [abbrv] sentry git commit: SENTRY-1630: out of sequence error
in HMSFollower (Alex Kolbasov, reviewed by Vamsee Yarlagadda and Na Li)
http://git-wip-us.apache.org/repos/asf/sentry/blob/747c2260/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..9d7bddd
--- /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, Set<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, Set<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, Set<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));
+ }
+ }
+ }
+
+}