/** * 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.hive.hcatalog.api; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNull; import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; import org.apache.hive.hcatalog.messaging.AddPartitionMessage; import org.apache.hive.hcatalog.messaging.CreateDatabaseMessage; import org.apache.hive.hcatalog.messaging.CreateTableMessage; import org.apache.hive.hcatalog.messaging.DropDatabaseMessage; import org.apache.hive.hcatalog.messaging.DropPartitionMessage; import org.apache.hive.hcatalog.messaging.DropTableMessage; import org.apache.hive.hcatalog.messaging.MessageDeserializer; import org.apache.hive.hcatalog.messaging.MessageFactory; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.apache.hadoop.hive.conf.HiveConf; import org.apache.hadoop.hive.metastore.IMetaStoreClient; import org.apache.hadoop.hive.metastore.api.NotificationEvent; import org.apache.hadoop.hive.serde2.typeinfo.TypeInfoFactory; import org.apache.hive.hcatalog.common.HCatConstants; import org.apache.hive.hcatalog.data.schema.HCatFieldSchema; import org.apache.hive.hcatalog.listener.DbNotificationListener; import org.junit.Before; import org.junit.BeforeClass; import org.junit.Test; import java.util.Arrays; import java.util.HashMap; import java.util.List; import java.util.Map; /** * This can't use TestHCatClient because it has to have control over certain conf variables when * the metastore is started. Plus, we don't need a metastore running in another thread. The * local one is fine. */ public class TestHCatClientNotification { private static final Logger LOG = LoggerFactory.getLogger(TestHCatClientNotification.class.getName()); private static HCatClient hCatClient; private static MessageDeserializer md = null; private int startTime; private long firstEventId; @BeforeClass public static void setupClient() throws Exception { HiveConf conf = new HiveConf(); conf.setVar(HiveConf.ConfVars.METASTORE_EVENT_LISTENERS, DbNotificationListener.class.getName()); hCatClient = HCatClient.create(conf); md = MessageFactory.getInstance().getDeserializer(); } @Before public void setup() throws Exception { long now = System.currentTimeMillis() / 1000; startTime = 0; if (now > Integer.MAX_VALUE) fail("Bummer, time has fallen over the edge"); else startTime = (int)now; firstEventId = hCatClient.getCurrentNotificationEventId(); } @Test public void createDatabase() throws Exception { hCatClient.createDatabase(HCatCreateDBDesc.create("myhcatdb").build()); List<HCatNotificationEvent> events = hCatClient.getNextNotification(firstEventId, 0, null); assertEquals(1, events.size()); HCatNotificationEvent event = events.get(0); assertEquals(firstEventId + 1, event.getEventId()); assertTrue(event.getEventTime() >= startTime); assertEquals(HCatConstants.HCAT_CREATE_DATABASE_EVENT, event.getEventType()); assertEquals("myhcatdb", event.getDbName()); assertNull(event.getTableName()); CreateDatabaseMessage createDatabaseMessage = md.getCreateDatabaseMessage(event.getMessage()); assertEquals("myhcatdb", createDatabaseMessage.getDB()); } @Test public void dropDatabase() throws Exception { String dbname = "hcatdropdb"; hCatClient.createDatabase(HCatCreateDBDesc.create(dbname).build()); hCatClient.dropDatabase(dbname, false, HCatClient.DropDBMode.RESTRICT); List<HCatNotificationEvent> events = hCatClient.getNextNotification(firstEventId, 0, null); assertEquals(2, events.size()); HCatNotificationEvent event = events.get(1); assertEquals(firstEventId + 2, event.getEventId()); assertTrue(event.getEventTime() >= startTime); assertEquals(HCatConstants.HCAT_DROP_DATABASE_EVENT, event.getEventType()); assertEquals(dbname, event.getDbName()); assertNull(event.getTableName()); DropDatabaseMessage dropDatabaseMessage = md.getDropDatabaseMessage(event.getMessage()); assertEquals(dbname, dropDatabaseMessage.getDB()); } @Test public void createTable() throws Exception { String dbName = "default"; String tableName = "hcatcreatetable"; HCatTable table = new HCatTable(dbName, tableName); table.cols(Arrays.asList(new HCatFieldSchema("onecol", TypeInfoFactory.stringTypeInfo, ""))); hCatClient.createTable(HCatCreateTableDesc.create(table).build()); List<HCatNotificationEvent> events = hCatClient.getNextNotification(firstEventId, 0, null); assertEquals(1, events.size()); HCatNotificationEvent event = events.get(0); assertEquals(firstEventId + 1, event.getEventId()); assertTrue(event.getEventTime() >= startTime); assertEquals(HCatConstants.HCAT_CREATE_TABLE_EVENT, event.getEventType()); assertEquals(dbName, event.getDbName()); assertEquals("hcatcreatetable", event.getTableName()); // Parse the message field CreateTableMessage createTableMessage = md.getCreateTableMessage(event.getMessage()); assertEquals(dbName, createTableMessage.getDB()); assertEquals(tableName, createTableMessage.getTable()); // fetch the table marked by the message and compare HCatTable createdTable = hCatClient.getTable(dbName,tableName); assertTrue(createdTable.diff(table).equals(HCatTable.NO_DIFF)); } // TODO - Currently no way to test alter table, as this interface doesn't support alter table @Test public void dropTable() throws Exception { String dbName = "default"; String tableName = "hcatdroptable"; HCatTable table = new HCatTable(dbName, tableName); table.cols(Arrays.asList(new HCatFieldSchema("onecol", TypeInfoFactory.stringTypeInfo, ""))); hCatClient.createTable(HCatCreateTableDesc.create(table).build()); hCatClient.dropTable(dbName, tableName, false); List<HCatNotificationEvent> events = hCatClient.getNextNotification(firstEventId, 0, null); assertEquals(2, events.size()); HCatNotificationEvent event = events.get(1); assertEquals(firstEventId + 2, event.getEventId()); assertTrue(event.getEventTime() >= startTime); assertEquals(HCatConstants.HCAT_DROP_TABLE_EVENT, event.getEventType()); assertEquals(dbName, event.getDbName()); assertEquals(tableName, event.getTableName()); DropTableMessage dropTableMessage = md.getDropTableMessage(event.getMessage()); assertEquals(dbName, dropTableMessage.getDB()); assertEquals(tableName, dropTableMessage.getTable()); } @Test public void addPartition() throws Exception { String dbName = "default"; String tableName = "hcataddparttable"; String partColName = "pc"; HCatTable table = new HCatTable(dbName, tableName); table.partCol(new HCatFieldSchema(partColName, TypeInfoFactory.stringTypeInfo, "")); table.cols(Arrays.asList(new HCatFieldSchema("onecol", TypeInfoFactory.stringTypeInfo, ""))); hCatClient.createTable(HCatCreateTableDesc.create(table).build()); String partName = "testpart"; Map<String, String> partSpec = new HashMap<String, String>(1); partSpec.put(partColName, partName); HCatPartition part = new HCatPartition(table, partSpec, null); hCatClient.addPartition(HCatAddPartitionDesc.create(part).build()); List<HCatNotificationEvent> events = hCatClient.getNextNotification(firstEventId, 0, null); assertEquals(2, events.size()); HCatNotificationEvent event = events.get(1); assertEquals(firstEventId + 2, event.getEventId()); assertTrue(event.getEventTime() >= startTime); assertEquals(HCatConstants.HCAT_ADD_PARTITION_EVENT, event.getEventType()); assertEquals("default", event.getDbName()); assertEquals(tableName, event.getTableName()); // Parse the message field AddPartitionMessage addPartitionMessage = md.getAddPartitionMessage(event.getMessage()); assertEquals(dbName, addPartitionMessage.getDB()); assertEquals(tableName, addPartitionMessage.getTable()); List<Map<String,String>> ptndescs = addPartitionMessage.getPartitions(); // fetch the partition referred to by the message and compare HCatPartition addedPart = hCatClient.getPartition(dbName, tableName, ptndescs.get(0)); assertEquals(part.getDatabaseName(), addedPart.getDatabaseName()); assertEquals(part.getTableName(), addedPart.getTableName()); assertEquals(part.getValues(), addedPart.getValues()); assertEquals(part.getColumns(), addedPart.getColumns()); assertEquals(part.getPartColumns(), addedPart.getPartColumns()); assertEquals(part.getLocation(), addedPart.getLocation()); } // TODO - currently no way to test alter partition, as HCatClient doesn't support it. @Test public void dropPartition() throws Exception { String dbName = "default"; String tableName = "hcatdropparttable"; String partColName = "pc"; HCatTable table = new HCatTable(dbName, tableName); table.partCol(new HCatFieldSchema(partColName, TypeInfoFactory.stringTypeInfo, "")); table.cols(Arrays.asList(new HCatFieldSchema("onecol", TypeInfoFactory.stringTypeInfo, ""))); hCatClient.createTable(HCatCreateTableDesc.create(table).build()); String partName = "testpart"; Map<String, String> partSpec = new HashMap<String, String>(1); partSpec.put(partColName, partName); hCatClient.addPartition( HCatAddPartitionDesc.create( new HCatPartition(table, partSpec, null) ).build() ); hCatClient.dropPartitions(dbName, tableName, partSpec, false); List<HCatNotificationEvent> events = hCatClient.getNextNotification(firstEventId, 0, null); assertEquals(3, events.size()); HCatNotificationEvent event = events.get(2); assertEquals(firstEventId + 3, event.getEventId()); assertTrue(event.getEventTime() >= startTime); assertEquals(HCatConstants.HCAT_DROP_PARTITION_EVENT, event.getEventType()); assertEquals(dbName, event.getDbName()); assertEquals(tableName, event.getTableName()); // Parse the message field DropPartitionMessage dropPartitionMessage = md.getDropPartitionMessage(event.getMessage()); assertEquals(dbName, dropPartitionMessage.getDB()); assertEquals(tableName, dropPartitionMessage.getTable()); List<Map<String, String>> droppedPartSpecs = dropPartitionMessage.getPartitions(); assertNotNull(droppedPartSpecs); assertEquals(1,droppedPartSpecs.size()); assertEquals(partSpec,droppedPartSpecs.get(0)); } @Test public void getOnlyMaxEvents() throws Exception { hCatClient.createDatabase(HCatCreateDBDesc.create("hcatdb1").build()); hCatClient.createDatabase(HCatCreateDBDesc.create("hcatdb2").build()); hCatClient.createDatabase(HCatCreateDBDesc.create("hcatdb3").build()); List<HCatNotificationEvent> events = hCatClient.getNextNotification(firstEventId, 2, null); assertEquals(2, events.size()); assertEquals(firstEventId + 1, events.get(0).getEventId()); assertEquals(firstEventId + 2, events.get(1).getEventId()); } @Test public void filter() throws Exception { hCatClient.createDatabase(HCatCreateDBDesc.create("hcatf1").build()); hCatClient.createDatabase(HCatCreateDBDesc.create("hcatf2").build()); hCatClient.dropDatabase("hcatf2", false, HCatClient.DropDBMode.RESTRICT); IMetaStoreClient.NotificationFilter filter = new IMetaStoreClient.NotificationFilter() { @Override public boolean accept(NotificationEvent event) { return event.getEventType().equals(HCatConstants.HCAT_DROP_DATABASE_EVENT); } }; List<HCatNotificationEvent> events = hCatClient.getNextNotification(firstEventId, 0, filter); assertEquals(1, events.size()); assertEquals(firstEventId + 3, events.get(0).getEventId()); } @Test public void filterWithMax() throws Exception { hCatClient.createDatabase(HCatCreateDBDesc.create("hcatm1").build()); hCatClient.createDatabase(HCatCreateDBDesc.create("hcatm2").build()); hCatClient.dropDatabase("hcatm2", false, HCatClient.DropDBMode.RESTRICT); IMetaStoreClient.NotificationFilter filter = new IMetaStoreClient.NotificationFilter() { @Override public boolean accept(NotificationEvent event) { return event.getEventType().equals(HCatConstants.HCAT_CREATE_DATABASE_EVENT); } }; List<HCatNotificationEvent> events = hCatClient.getNextNotification(firstEventId, 1, filter); assertEquals(1, events.size()); assertEquals(firstEventId + 1, events.get(0).getEventId()); } }