Copilot commented on code in PR #425:
URL: https://github.com/apache/atlas/pull/425#discussion_r2270244477
##########
addons/hive-bridge/src/test/java/org/apache/atlas/hive/hook/events/DropDatabaseTest.java:
##########
@@ -0,0 +1,273 @@
+package org.apache.atlas.hive.hook.events;
+
+import org.apache.atlas.hive.hook.AtlasHiveHookContext;
+import org.apache.atlas.model.notification.HookNotification;
+import
org.apache.atlas.model.notification.HookNotification.EntityDeleteRequestV2;
+import org.apache.hadoop.hive.metastore.api.Database;
+import org.apache.hadoop.hive.metastore.events.DropDatabaseEvent;
+import org.apache.hadoop.hive.ql.hooks.Entity;
+import org.apache.hadoop.hive.ql.hooks.WriteEntity;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.testng.annotations.BeforeMethod;
+import org.testng.annotations.Test;
+
+import java.util.*;
+
+import static org.mockito.Mockito.*;
+import static org.testng.AssertJUnit.*;
+
+public class DropDatabaseTest {
+ private static final Logger LOG =
LoggerFactory.getLogger(DropDatabaseTest.class);
+
+ @Mock
+ private AtlasHiveHookContext context;
+
+ private DropDatabase dropDatabase;
+
+ @BeforeMethod
+ public void setUp() {
+ MockitoAnnotations.initMocks(this);
+ }
+
+ @Test
+ public void testConstructor() {
+ // Test constructor
+ dropDatabase = new DropDatabase(context);
+ assertNotNull(dropDatabase);
+ assertEquals(context, dropDatabase.getContext());
+ LOG.info("Constructor test passed");
+ }
+
+ @Test
+ public void testGetNotificationMessages_MetastoreHook_WithValidDatabase() {
+ // Setup
+ when(context.isMetastoreHook()).thenReturn(true);
+
+ DropDatabaseEvent dbEvent = mock(DropDatabaseEvent.class);
+ Database db = mock(Database.class);
+
+ when(dbEvent.getDatabase()).thenReturn(db);
+ when(db.getName()).thenReturn("testDb");
+ when(context.getMetastoreEvent()).thenReturn(dbEvent);
+ when(context.getMetadataNamespace()).thenReturn("test_cluster");
+
+ dropDatabase = new DropDatabase(context);
+
+ // Execute
+ List<HookNotification> notifications =
dropDatabase.getNotificationMessages();
+
+ // Verify
+ assertNotNull(notifications);
+ assertEquals(1, notifications.size());
+ assertTrue(notifications.get(0) instanceof EntityDeleteRequestV2);
+
+// verify(context).removeFromKnownDatabase(anyString());
Review Comment:
Remove commented-out verification code or uncomment it if the verification
is needed for the test.
```suggestion
verify(context).removeFromKnownDatabase(anyString());
```
##########
addons/hive-bridge/src/test/java/org/apache/atlas/hive/hook/events/CreateTableTest.java:
##########
@@ -0,0 +1,790 @@
+package org.apache.atlas.hive.hook.events;
+
+import org.apache.atlas.hive.hook.AtlasHiveHookContext;
+import org.apache.atlas.model.instance.AtlasEntity;
+import org.apache.atlas.model.instance.AtlasEntity.AtlasEntitiesWithExtInfo;
+import org.apache.atlas.model.notification.HookNotification;
+import org.apache.hadoop.hive.metastore.TableType;
+import org.apache.hadoop.hive.metastore.api.StorageDescriptor;
+import org.apache.hadoop.hive.metastore.events.AlterTableEvent;
+import org.apache.hadoop.hive.metastore.events.CreateTableEvent;
+import org.apache.hadoop.hive.ql.hooks.Entity;
+import org.apache.hadoop.hive.ql.hooks.WriteEntity;
+import org.apache.hadoop.hive.ql.metadata.Hive;
+import org.apache.hadoop.hive.ql.metadata.Table;
+import org.apache.hadoop.hive.ql.plan.HiveOperation;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+import org.testng.AssertJUnit;
+import org.testng.annotations.BeforeMethod;
+import org.testng.annotations.Test;
+
+import java.lang.reflect.Method;
+import java.util.*;
+
+import static org.mockito.Mockito.*;
+import static org.junit.Assert.assertNotNull;
+
+public class CreateTableTest {
+
+ @Mock
+ AtlasHiveHookContext context;
+
+ @Mock
+ CreateTableEvent createTableEvent;
+
+ @Mock
+ AlterTableEvent alterTableEvent;
+
+ @Mock
+ Hive hive;
+
+ CreateTable createTable;
+
+ @BeforeMethod
+ public void setUp() {
+ MockitoAnnotations.initMocks(this);
+ createTable = new CreateTable(context);
+ }
+
+ // =================== Constructor Tests ===================
+ @Test
+ public void testConstructor() {
+ CreateTable createTable = new CreateTable(context);
+ AssertJUnit.assertNotNull("CreateTable instance should be created",
createTable);
+ }
+
+ // =================== getNotificationMessages Tests ===================
+ @Test
+ public void testGetNotificationMessages_MetastoreHook_WithEntities()
throws Exception {
+ when(context.isMetastoreHook()).thenReturn(true);
+
+ CreateTable createTable = spy(new CreateTable(context));
+
+ AtlasEntitiesWithExtInfo mockEntities = new AtlasEntitiesWithExtInfo();
+ AtlasEntity tblEntity = new AtlasEntity("hive_table");
+ tblEntity.setAttribute("qualifiedName", "default.test_table@cm");
+ mockEntities.addEntity(tblEntity);
+
+ doReturn(mockEntities).when(createTable).getHiveMetastoreEntities();
+ doReturn("test_user").when(createTable).getUserName();
+
+ List<HookNotification> notifications =
createTable.getNotificationMessages();
+
+ AssertJUnit.assertNotNull(notifications);
+ AssertJUnit.assertEquals(1, notifications.size());
+ AssertJUnit.assertTrue(notifications.get(0) instanceof
HookNotification.EntityCreateRequestV2);
+ }
+
+ @Test
+ public void testGetNotificationMessages_NonMetastoreHook_WithEntities()
throws Exception {
+ when(context.isMetastoreHook()).thenReturn(false);
+
+ CreateTable createTable = spy(new CreateTable(context));
+
+ AtlasEntitiesWithExtInfo mockEntities = new AtlasEntitiesWithExtInfo();
+ AtlasEntity tblEntity = new AtlasEntity("hive_table");
+ tblEntity.setAttribute("qualifiedName", "default.test_table@cm");
+ mockEntities.addEntity(tblEntity);
+
+ doReturn(mockEntities).when(createTable).getHiveEntities();
+ doReturn("test_user").when(createTable).getUserName();
+
+ List<HookNotification> notifications =
createTable.getNotificationMessages();
+
+ AssertJUnit.assertNotNull(notifications);
+ AssertJUnit.assertEquals(1, notifications.size());
+ AssertJUnit.assertTrue(notifications.get(0) instanceof
HookNotification.EntityCreateRequestV2);
+ }
+
+ @Test
+ public void testGetNotificationMessages_EmptyEntities() throws Exception {
+ when(context.isMetastoreHook()).thenReturn(true);
+
+ CreateTable createTable = spy(new CreateTable(context));
+
+ AtlasEntitiesWithExtInfo emptyEntities = new
AtlasEntitiesWithExtInfo();
+ doReturn(emptyEntities).when(createTable).getHiveMetastoreEntities();
+
+ List<HookNotification> notifications =
createTable.getNotificationMessages();
+
+ AssertJUnit.assertNull("Expected null notifications for empty
entities", notifications);
+ }
+
+ @Test
+ public void testGetNotificationMessages_NullEntities() throws Exception {
+ when(context.isMetastoreHook()).thenReturn(true);
+
+ CreateTable createTable = spy(new CreateTable(context));
+ doReturn(null).when(createTable).getHiveMetastoreEntities();
+
+ List<HookNotification> notifications =
createTable.getNotificationMessages();
+
+ AssertJUnit.assertNull("Expected null notifications for null
entities", notifications);
+ }
+
+ @Test
+ public void testGetNotificationMessages_NonMetastoreHook_NullEntities()
throws Exception {
+ when(context.isMetastoreHook()).thenReturn(false);
+
+ CreateTable createTable = spy(new CreateTable(context));
+ doReturn(null).when(createTable).getHiveEntities();
+
+ List<HookNotification> notifications =
createTable.getNotificationMessages();
+
+ AssertJUnit.assertNull("Expected null notifications for null
entities", notifications);
+ }
+
+ // =================== getHiveMetastoreEntities Tests ===================
+/* @Test
Review Comment:
Multiple commented-out test methods should be removed or properly
implemented. This reduces code maintainability and can cause confusion.
##########
addons/hive-bridge/src/test/java/org/apache/atlas/hive/hook/events/BaseHiveEventTest.java:
##########
@@ -0,0 +1,1328 @@
+package org.apache.atlas.hive.hook.events;
+
+import org.apache.atlas.hive.hook.AtlasHiveHookContext;
+import org.apache.atlas.hive.hook.HiveHook.PreprocessAction;
+import org.apache.atlas.model.instance.AtlasEntity;
+import org.apache.atlas.model.instance.AtlasEntity.AtlasEntitiesWithExtInfo;
+import org.apache.atlas.model.instance.AtlasEntity.AtlasEntityWithExtInfo;
+import org.apache.atlas.model.instance.AtlasObjectId;
+import org.apache.atlas.model.notification.HookNotification;
+import org.apache.hadoop.fs.Path;
+import org.apache.hadoop.hive.metastore.TableType;
+import org.apache.hadoop.hive.metastore.api.Database;
+import org.apache.hadoop.hive.metastore.api.FieldSchema;
+import org.apache.hadoop.hive.metastore.api.SerDeInfo;
+import org.apache.hadoop.hive.metastore.api.StorageDescriptor;
+import org.apache.hadoop.hive.ql.hooks.Entity;
+import org.apache.hadoop.hive.ql.hooks.HookContext;
+import org.apache.hadoop.hive.ql.hooks.LineageInfo;
+import org.apache.hadoop.hive.ql.hooks.LineageInfo.BaseColumnInfo;
+import org.apache.hadoop.hive.ql.hooks.LineageInfo.DependencyKey;
+import org.apache.hadoop.hive.ql.hooks.ReadEntity;
+import org.apache.hadoop.hive.ql.hooks.WriteEntity;
+import org.apache.hadoop.hive.ql.metadata.Hive;
+import org.apache.hadoop.hive.ql.metadata.Table;
+import org.apache.hadoop.hive.ql.plan.HiveOperation;
+import org.apache.hadoop.hive.ql.session.SessionState;
+import org.apache.hadoop.security.UserGroupInformation;
+import org.mockito.Mock;
+import org.mockito.Mockito;
+import org.mockito.MockitoAnnotations;
+import org.testng.AssertJUnit;
+import org.testng.annotations.BeforeMethod;
+import org.testng.annotations.Test;
+
+import java.io.IOException;
+import java.net.URI;
+import java.util.*;
+import java.util.HashMap;
+
+import static org.mockito.Matchers.*;
+import static org.mockito.Mockito.when;
+import static org.mockito.Mockito.doNothing;
+
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.doThrow;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+public class BaseHiveEventTest {
+
+ @Mock
+ AtlasHiveHookContext context;
+
+ @Mock
+ Hive hive;
+
+ Table table;
+
+ @Mock
+ Database database;
+
+ @Mock
+ HookContext hookContext;
+
+ @Mock
+ Entity entity;
+
+ @Mock
+ ReadEntity readEntity;
+
+ @Mock
+ WriteEntity writeEntity;
+
+ @Mock
+ LineageInfo lineageInfo;
+
+ @Mock
+ UserGroupInformation ugi;
+
+ @Mock
+ SessionState sessionState;
+
+ // Concrete implementation of BaseHiveEvent for testing
+ private static class TestableBaseHiveEvent extends BaseHiveEvent {
+ public TestableBaseHiveEvent(AtlasHiveHookContext context) {
+ super(context);
+ }
+
+ @Override
+ public List<HookNotification> getNotificationMessages() throws
Exception {
+ return Collections.emptyList();
+ }
+ }
+
+ private TestableBaseHiveEvent baseHiveEvent;
+
+ @BeforeMethod
+ public void setUp() {
+ MockitoAnnotations.initMocks(this);
+
+ // Create a real Table object with a mocked tTable to avoid NPE issues
+ org.apache.hadoop.hive.metastore.api.Table tTable =
mock(org.apache.hadoop.hive.metastore.api.Table.class);
+ when(tTable.getTableName()).thenReturn("test_table");
+ when(tTable.getCreateTime()).thenReturn(1000);
+ when(tTable.getDbName()).thenReturn("default");
+
+ // Create a real Table object and then spy on it
+ table = spy(new Table(tTable));
+
+ // Mock required context methods for BaseHiveEvent constructor
+ when(context.isSkipTempTables()).thenReturn(false);
+ when(context.isMetastoreHook()).thenReturn(false); // Ensure it's not
a metastore hook
+ baseHiveEvent = new TestableBaseHiveEvent(context);
+ }
+
+ // ========== CONSTRUCTOR TESTS ==========
+
+ @Test
+ public void testConstructor() {
+ when(context.isSkipTempTables()).thenReturn(true);
+ TestableBaseHiveEvent event = new TestableBaseHiveEvent(context);
+
+ AssertJUnit.assertNotNull("BaseHiveEvent should be instantiated",
event);
+ AssertJUnit.assertEquals("Context should be set", context,
event.getContext());
+ }
+
+ @Test(expectedExceptions = NullPointerException.class)
+ public void testConstructorWithNullContext() {
+ new TestableBaseHiveEvent(null);
+ }
+
+ // ========== UTILITY METHOD TESTS ==========
+
+ @Test
+ public void testGetTableCreateTime() {
+ org.apache.hadoop.hive.metastore.api.Table metastoreTable =
mock(org.apache.hadoop.hive.metastore.api.Table.class);
+ when(metastoreTable.getCreateTime()).thenReturn(1000);
+ when(table.getTTable()).thenReturn(metastoreTable);
+
+ long createTime = BaseHiveEvent.getTableCreateTime(table);
+
+ AssertJUnit.assertEquals("Create time should be converted from seconds
to milliseconds",
+ 1000 * BaseHiveEvent.MILLIS_CONVERT_FACTOR, createTime);
+ }
+
+ @Test
+ public void testGetTableCreateTime_NullTTable() {
+ when(table.getTTable()).thenReturn(null);
+
+ long createTime = BaseHiveEvent.getTableCreateTime(table);
+
+ AssertJUnit.assertTrue("Should return current time when TTable is
null",
+ createTime > 0 && createTime <= System.currentTimeMillis());
+ }
+
+ @Test
+ public void testGetTableOwner() {
+ org.apache.hadoop.hive.metastore.api.Table metastoreTable =
mock(org.apache.hadoop.hive.metastore.api.Table.class);
+ when(table.getTTable()).thenReturn(metastoreTable);
+ when(table.getOwner()).thenReturn("test_user");
+
+ String owner = BaseHiveEvent.getTableOwner(table);
+
+ AssertJUnit.assertEquals("Should return table owner", "test_user",
owner);
+ }
+
+ @Test
+ public void testGetTableOwner_NullTTable() {
+ when(table.getTTable()).thenReturn(null);
+
+ String owner = BaseHiveEvent.getTableOwner(table);
+
+ AssertJUnit.assertEquals("Should return empty string when TTable is
null", "", owner);
+ }
+
+ @Test
+ public void testGetObjectIds() {
+ AtlasEntity entity1 = new AtlasEntity("type1");
+ entity1.setAttribute("qualifiedName", "entity1@cluster");
+ AtlasEntity entity2 = new AtlasEntity("type2");
+ entity2.setAttribute("qualifiedName", "entity2@cluster");
+
+ List<AtlasEntity> entities = Arrays.asList(entity1, entity2);
+
+ List<AtlasObjectId> objectIds = BaseHiveEvent.getObjectIds(entities);
+
+ AssertJUnit.assertEquals("Should return correct number of object IDs",
2, objectIds.size());
+ AssertJUnit.assertEquals("First object ID type should match", "type1",
objectIds.get(0).getTypeName());
+ AssertJUnit.assertEquals("Second object ID type should match",
"type2", objectIds.get(1).getTypeName());
+ }
+
+ @Test
+ public void testGetObjectIds_EmptyList() {
+ List<AtlasObjectId> objectIds =
BaseHiveEvent.getObjectIds(Collections.emptyList());
+
+ AssertJUnit.assertTrue("Should return empty list",
objectIds.isEmpty());
+ }
+
+ @Test
+ public void testGetObjectIds_NullList() {
+ List<AtlasObjectId> objectIds = BaseHiveEvent.getObjectIds(null);
+
+ AssertJUnit.assertTrue("Should return empty list for null input",
objectIds.isEmpty());
+ }
+
+ // ========== ENTITY PROCESSING TESTS ==========
+
+ @Test
+ public void testAddProcessedEntities() throws Exception {
+ AtlasEntitiesWithExtInfo entitiesWithExtInfo = new
AtlasEntitiesWithExtInfo();
+
+ AtlasEntity contextEntity = new AtlasEntity("test_type");
+ contextEntity.setAttribute("qualifiedName", "test@cluster");
+ List<AtlasEntity> contextEntities = Arrays.asList(contextEntity);
+
+ when(context.getEntities()).thenReturn(contextEntities);
+
+ // Use generic safe matcher instead of anyCollection()
+
doNothing().when(context).addToKnownEntities(Mockito.<Collection<AtlasEntity>>any());
+
+ baseHiveEvent.addProcessedEntities(entitiesWithExtInfo);
+
+
+ AssertJUnit.assertEquals("Should have referred entities", 1,
+ entitiesWithExtInfo.getReferredEntities().size());
+ }
+
+
+
+
+ @Test
+ public void testGetInputOutputEntity_DfsDir() throws Exception {
+ URI location = URI.create("hdfs://namenode:9000/test/path");
+ when(entity.getType()).thenReturn(Entity.Type.DFS_DIR);
+ when(entity.getLocation()).thenReturn(location);
+
+ when(context.getMetadataNamespace()).thenReturn("cluster");
+ when(context.isConvertHdfsPathToLowerCase()).thenReturn(true);
+ when(context.getQNameToEntityMap()).thenReturn(new HashMap<>());
+
when(context.getAwsS3AtlasModelVersion()).thenReturn(String.valueOf(1));
+
+ AtlasEntity result = baseHiveEvent.getInputOutputEntity(entity, new
AtlasEntitiesWithExtInfo(), false);
+
+ AssertJUnit.assertNotNull("Should return path entity", result);
+ }
+
+ @Test
+ public void testGetInputOutputEntity_SkipTempTable() throws Exception {
+ // Mock the underlying metastore Table
+
+ org.apache.hadoop.hive.metastore.api.Table metastoreTable =
mock(org.apache.hadoop.hive.metastore.api.Table.class);
+ Table tableSpy = spy(new Table(metastoreTable));
+ when(entity.getType()).thenReturn(Entity.Type.TABLE);
+ when(entity.getTable()).thenReturn(tableSpy);
+ when(tableSpy.isTemporary()).thenReturn(true);
+ when(metastoreTable.getTableName()).thenReturn("test_table");
+ when(context.isSkipTempTables()).thenReturn(true);
+ when(tableSpy.getDbName()).thenReturn("default"); // Mock getDbName to
avoid potential NPE
+ when(context.getEntity(any(String.class))).thenReturn(null); // Mock
entity lookup
+ doNothing().when(context).putEntity(any(String.class),
any(AtlasEntity.class)); // Mock entity storage
+
+ // Debug: Verify mock setup
+ AssertJUnit.assertEquals("Verify entity type", Entity.Type.TABLE,
entity.getType());
+// AssertJUnit.assertEquals("Verify table is temporary", true,
table.isTemporary());
+ AssertJUnit.assertEquals("Verify table name", "test_table",
metastoreTable.getTableName());
+
+ AtlasEntity result = baseHiveEvent.getInputOutputEntity(entity, new
AtlasEntitiesWithExtInfo(), true);
+
+ AssertJUnit.assertNull("Should return null for temp table when
skipTempTables=true", result);
+ }
+
+ // ========== DATABASE ENTITY TESTS ==========
+
+ @Test
+ public void testToDbEntity() throws Exception {
+ when(database.getName()).thenReturn("test_db");
+ when(database.getDescription()).thenReturn("Test database");
+ when(database.getOwnerName()).thenReturn("test_owner");
+
when(database.getLocationUri()).thenReturn("hdfs://namenode:9000/warehouse/test_db");
+ when(database.getParameters()).thenReturn(new HashMap<>());
+
+ when(context.getQualifiedName(database)).thenReturn("test_db@cluster");
+ when(context.getMetadataNamespace()).thenReturn("cluster");
+ when(context.isKnownDatabase(anyString())).thenReturn(false);
+ when(context.getEntity(anyString())).thenReturn(null);
+ doNothing().when(context).putEntity(anyString(),
any(AtlasEntity.class));
+
+ AtlasEntity result = baseHiveEvent.toDbEntity(database);
+
+ AssertJUnit.assertNotNull("Should return database entity", result);
+ AssertJUnit.assertEquals("Should be hive_db type", "hive_db",
result.getTypeName());
+ AssertJUnit.assertEquals("Should have correct name", "test_db",
result.getAttribute("name"));
+ AssertJUnit.assertEquals("Should have correct owner", "test_owner",
result.getAttribute("owner"));
+ AssertJUnit.assertEquals("Should have correct description", "Test
database", result.getAttribute("description"));
+ }
+
+ @Test
+ public void testToDbEntity_KnownDatabase() throws Exception {
+ when(database.getName()).thenReturn("test_db");
+ when(context.getQualifiedName(database)).thenReturn("test_db@cluster");
+ when(context.isKnownDatabase("test_db@cluster")).thenReturn(true);
+ when(context.getEntity("test_db@cluster")).thenReturn(null);
+ when(context.getMetadataNamespace()).thenReturn("cluster");
+ doNothing().when(context).putEntity(anyString(),
any(AtlasEntity.class));
+
+ AtlasEntity result = baseHiveEvent.toDbEntity(database);
+
+ AssertJUnit.assertNotNull("Should return database entity", result);
+ AssertJUnit.assertNull("Should have null guid for known database",
result.getGuid());
+ }
+
+ // ========== TABLE ENTITY TESTS ==========
+
+ @Test
+ public void testToTableEntity() throws Exception {
+ setupTableMocks();
+ setupDatabaseMocks();
+
+ when(context.getHive()).thenReturn(hive);
+ when(hive.getDatabase("default")).thenReturn(database);
+
+ // Mock dbEntity for AtlasTypeUtil.getObjectId(dbEntity)
+ AtlasEntity dbEntity = new AtlasEntity("hive_db");
+ dbEntity.setAttribute("qualifiedName", "default@cluster");
+ when(context.getEntity("default@cluster")).thenReturn(dbEntity);
+
+ // Debug: Verify mock setup
+ AssertJUnit.assertEquals("Verify table name", "test_table",
table.getTTable().getTableName());
+ AssertJUnit.assertEquals("Verify db name", "default",
table.getDbName());
+
+ AssertJUnit.assertEquals("Verify qualified name",
"default.test_table@cluster", context.getQualifiedName(table));
+
+ AtlasEntityWithExtInfo result = baseHiveEvent.toTableEntity(table);
+
+ AssertJUnit.assertNotNull("Should return table entity with ext info",
result);
+ AssertJUnit.assertNotNull("Should have entity", result.getEntity());
+ AssertJUnit.assertEquals("Should be hive_table type", "hive_table",
result.getEntity().getTypeName());
+ }
+
+
+
+ /* @Test
Review Comment:
Multiple large blocks of commented-out test methods should be removed to
improve code maintainability.
##########
addons/hive-bridge/src/test/java/org/apache/atlas/hive/hook/events/DropTableTest.java:
##########
@@ -0,0 +1,481 @@
+package org.apache.atlas.hive.hook.events;
+
+import org.apache.atlas.hive.hook.AtlasHiveHookContext;
+import org.apache.atlas.model.instance.AtlasObjectId;
+import org.apache.atlas.model.notification.HookNotification;
+import
org.apache.atlas.model.notification.HookNotification.EntityDeleteRequestV2;
+import org.apache.hadoop.hive.metastore.api.FieldSchema;
+import org.apache.hadoop.hive.metastore.api.SerDeInfo;
+import org.apache.hadoop.hive.metastore.api.StorageDescriptor;
+import org.apache.hadoop.hive.metastore.events.DropTableEvent;
+import org.apache.hadoop.hive.ql.hooks.Entity;
+import org.apache.hadoop.hive.ql.hooks.WriteEntity;
+import org.apache.hadoop.hive.ql.metadata.Table;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.testng.AssertJUnit;
+import org.testng.annotations.BeforeMethod;
+import org.testng.annotations.Test;
+
+import java.util.*;
+
+import static org.apache.hadoop.hive.metastore.TableType.MANAGED_TABLE;
+import static org.mockito.Mockito.*;
+
+public class DropTableTest {
+ private static final Logger LOG =
LoggerFactory.getLogger(DropTableTest.class);
+
+ @Mock
+ AtlasHiveHookContext context;
+
+ @Mock
+ DropTableEvent dropTableEvent;
+
+ @Mock
+ Table table;
+
+ @BeforeMethod
+ public void setUp() {
+ MockitoAnnotations.initMocks(this);
+ }
+
+ // ========== CONSTRUCTOR TESTS ==========
+
+ @Test
+ public void testConstructor() {
+ DropTable dropTable = new DropTable(context);
+ AssertJUnit.assertNotNull("DropTable should be instantiated",
dropTable);
+ AssertJUnit.assertTrue("DropTable should extend BaseHiveEvent",
+ dropTable instanceof BaseHiveEvent);
+ }
+
+ @Test(expectedExceptions = NullPointerException.class)
+ public void testConstructorWithNullContext() {
+ new DropTable(null);
+ }
+
+ // ========== getNotificationMessages() TESTS ==========
+
+ @Test
+ public void testGetNotificationMessages_MetastoreHook() throws Exception {
+ when(context.isMetastoreHook()).thenReturn(true);
+
+ DropTable dropTable = spy(new DropTable(context));
+
+ // Mock getHiveMetastoreEntities to return some entities
+ List<AtlasObjectId> mockEntities = Arrays.asList(
+ new AtlasObjectId("hive_table", "qualifiedName",
"default.test_table@cluster")
+ );
+ doReturn(mockEntities).when(dropTable).getHiveMetastoreEntities();
+
+ // Mock getUserName
+ doReturn("test_user").when(dropTable).getUserName();
+
+ List<HookNotification> notifications =
dropTable.getNotificationMessages();
+
+ AssertJUnit.assertNotNull("Notifications should not be null",
notifications);
+ AssertJUnit.assertEquals("Should have one notification", 1,
notifications.size());
+ AssertJUnit.assertTrue("Should be EntityDeleteRequestV2",
+ notifications.get(0) instanceof EntityDeleteRequestV2);
+
+ EntityDeleteRequestV2 deleteRequest = (EntityDeleteRequestV2)
notifications.get(0);
+ AssertJUnit.assertEquals("User should be test_user", "test_user",
deleteRequest.getUser());
+ AssertJUnit.assertEquals("Should have one entity to delete", 1,
deleteRequest.getEntities().size());
+
+ verify(dropTable).getHiveMetastoreEntities();
+ verify(dropTable, never()).getHiveEntities();
+ }
+
+ @Test
+ public void testGetNotificationMessages_NonMetastoreHook() throws
Exception {
+ when(context.isMetastoreHook()).thenReturn(false);
+
+ DropTable dropTable = spy(new DropTable(context));
+
+ // Mock getHiveEntities to return some entities
+ List<AtlasObjectId> mockEntities = Arrays.asList(
+ new AtlasObjectId("hive_table", "qualifiedName",
"default.test_table@cluster")
+ );
+ doReturn(mockEntities).when(dropTable).getHiveEntities();
+
+ // Mock getUserName
+ doReturn("test_user").when(dropTable).getUserName();
+
+ List<HookNotification> notifications =
dropTable.getNotificationMessages();
+
+ AssertJUnit.assertNotNull("Notifications should not be null",
notifications);
+ AssertJUnit.assertEquals("Should have one notification", 1,
notifications.size());
+ AssertJUnit.assertTrue("Should be EntityDeleteRequestV2",
+ notifications.get(0) instanceof EntityDeleteRequestV2);
+
+ verify(dropTable).getHiveEntities();
+ verify(dropTable, never()).getHiveMetastoreEntities();
+ }
+
+ @Test
+ public void testGetNotificationMessages_EmptyEntities() throws Exception {
+ when(context.isMetastoreHook()).thenReturn(true);
+
+ DropTable dropTable = spy(new DropTable(context));
+
+ // Mock getHiveMetastoreEntities to return empty list
+
doReturn(Collections.emptyList()).when(dropTable).getHiveMetastoreEntities();
+
+ List<HookNotification> notifications =
dropTable.getNotificationMessages();
+
+ AssertJUnit.assertNull("Notifications should be null when no
entities", notifications);
+ }
+
+ @Test
+ public void testGetNotificationMessages_NullEntities() throws Exception {
+ when(context.isMetastoreHook()).thenReturn(false);
+
+ DropTable dropTable = spy(new DropTable(context));
+
+ // Mock getHiveEntities to return null
+ doReturn(null).when(dropTable).getHiveEntities();
+
+ List<HookNotification> notifications =
dropTable.getNotificationMessages();
+
+ AssertJUnit.assertNull("Notifications should be null when entities are
null", notifications);
+ }
+
+ @Test
+ public void testGetNotificationMessages_MultipleEntities() throws
Exception {
+ when(context.isMetastoreHook()).thenReturn(true);
+
+ DropTable dropTable = spy(new DropTable(context));
+
+ // Mock getHiveMetastoreEntities to return multiple entities
+ List<AtlasObjectId> mockEntities = Arrays.asList(
+ new AtlasObjectId("hive_table", "qualifiedName",
"default.table1@cluster"),
+ new AtlasObjectId("hive_table", "qualifiedName",
"default.table2@cluster")
+ );
+ doReturn(mockEntities).when(dropTable).getHiveMetastoreEntities();
+
+ // Mock getUserName
+ doReturn("test_user").when(dropTable).getUserName();
+
+ List<HookNotification> notifications =
dropTable.getNotificationMessages();
+
+ AssertJUnit.assertNotNull("Notifications should not be null",
notifications);
+ AssertJUnit.assertEquals("Should have two notifications", 2,
notifications.size());
+
+ // Verify each notification is correct
+ for (HookNotification notification : notifications) {
+ AssertJUnit.assertTrue("Should be EntityDeleteRequestV2",
+ notification instanceof EntityDeleteRequestV2);
+ EntityDeleteRequestV2 deleteRequest = (EntityDeleteRequestV2)
notification;
+ AssertJUnit.assertEquals("User should be test_user", "test_user",
deleteRequest.getUser());
+ AssertJUnit.assertEquals("Should have one entity to delete", 1,
deleteRequest.getEntities().size());
+ }
+ }
+
+ // ========== getHiveMetastoreEntities() TESTS ==========
+
+ @Test
+ public void testGetHiveMetastoreEntities_Success() throws Exception {
+ // Setup metastore event
+ when(context.getMetastoreEvent()).thenReturn(dropTableEvent);
+
+ // Create mock metastore table
+ org.apache.hadoop.hive.metastore.api.Table metastoreTable =
createMockMetastoreTable("test_table");
+ when(dropTableEvent.getTable()).thenReturn(metastoreTable);
+
+ DropTable dropTable = spy(new DropTable(context));
+
+ // Mock getQualifiedName to avoid complex dependencies
+
doReturn("default.test_table@cluster").when(dropTable).getQualifiedName(any(Table.class));
+
+ List<AtlasObjectId> entities = dropTable.getHiveMetastoreEntities();
+
+ AssertJUnit.assertNotNull("Entities should not be null", entities);
+ AssertJUnit.assertEquals("Should have one entity", 1, entities.size());
+
+ AtlasObjectId entity = entities.get(0);
+ AssertJUnit.assertEquals("Should be hive_table type", "hive_table",
entity.getTypeName());
+ AssertJUnit.assertEquals("Should have correct qualified name",
"default.test_table@cluster",
+ entity.getUniqueAttributes().get("qualifiedName"));
+
+ // Verify context.removeFromKnownTable was called
+ verify(context).removeFromKnownTable("default.test_table@cluster");
+ }
+
+ @Test
+ public void testGetHiveMetastoreEntities_DifferentTableName() throws
Exception {
+ // Setup metastore event
+ when(context.getMetastoreEvent()).thenReturn(dropTableEvent);
+
+ // Create mock metastore table with different name
+ org.apache.hadoop.hive.metastore.api.Table metastoreTable =
createMockMetastoreTable("another_table");
+ when(dropTableEvent.getTable()).thenReturn(metastoreTable);
+
+ DropTable dropTable = spy(new DropTable(context));
+
+ // Mock getQualifiedName
+
doReturn("prod.another_table@cluster2").when(dropTable).getQualifiedName(any(Table.class));
+
+ List<AtlasObjectId> entities = dropTable.getHiveMetastoreEntities();
+
+ AssertJUnit.assertNotNull("Entities should not be null", entities);
+ AssertJUnit.assertEquals("Should have one entity", 1, entities.size());
+
+ AtlasObjectId entity = entities.get(0);
+ AssertJUnit.assertEquals("Should be hive_table type", "hive_table",
entity.getTypeName());
+ AssertJUnit.assertEquals("Should have correct qualified name",
"prod.another_table@cluster2",
+ entity.getUniqueAttributes().get("qualifiedName"));
+
+ // Verify context.removeFromKnownTable was called with correct name
+ verify(context).removeFromKnownTable("prod.another_table@cluster2");
+ }
+
+ // ========== getHiveEntities() TESTS ==========
+
+ @Test
+ public void testGetHiveEntities_Success() throws Exception {
+ // Setup output entities
+ WriteEntity outputEntity = mock(WriteEntity.class);
+ when(outputEntity.getType()).thenReturn(Entity.Type.TABLE);
+ when(outputEntity.getTable()).thenReturn(table);
+ Set<WriteEntity> outputs = Collections.singleton(outputEntity);
+
+ DropTable dropTable = spy(new DropTable(context));
+ doReturn(outputs).when(dropTable).getOutputs();
+
+ // Mock getQualifiedName
+
doReturn("default.test_table@cluster").when(dropTable).getQualifiedName(table);
+
+ List<AtlasObjectId> entities = dropTable.getHiveEntities();
+
+ AssertJUnit.assertNotNull("Entities should not be null", entities);
+ AssertJUnit.assertEquals("Should have one entity", 1, entities.size());
+
+ AtlasObjectId entity = entities.get(0);
+ AssertJUnit.assertEquals("Should be hive_table type", "hive_table",
entity.getTypeName());
+ AssertJUnit.assertEquals("Should have correct qualified name",
"default.test_table@cluster",
+ entity.getUniqueAttributes().get("qualifiedName"));
+
+ // Verify context.removeFromKnownTable was called
+ verify(context).removeFromKnownTable("default.test_table@cluster");
+ }
+
+ @Test
+ public void testGetHiveEntities_EmptyOutputs() throws Exception {
+ DropTable dropTable = spy(new DropTable(context));
+ doReturn(Collections.emptySet()).when(dropTable).getOutputs();
+
+ List<AtlasObjectId> entities = dropTable.getHiveEntities();
+
+ AssertJUnit.assertNotNull("Entities should not be null", entities);
+ AssertJUnit.assertTrue("Entities should be empty", entities.isEmpty());
+
+ // Verify no calls to removeFromKnownTable
+ verify(context, never()).removeFromKnownTable(any(String.class));
+ }
+
+ @Test
+ public void testGetHiveEntities_NonTableEntity() throws Exception {
+ // Setup output entities with non-table type
+ WriteEntity outputEntity = mock(WriteEntity.class);
+ when(outputEntity.getType()).thenReturn(Entity.Type.DATABASE);
+ Set<WriteEntity> outputs = Collections.singleton(outputEntity);
+
+ DropTable dropTable = spy(new DropTable(context));
+ doReturn(outputs).when(dropTable).getOutputs();
+
+ List<AtlasObjectId> entities = dropTable.getHiveEntities();
+
+ AssertJUnit.assertNotNull("Entities should not be null", entities);
+ AssertJUnit.assertTrue("Entities should be empty", entities.isEmpty());
+
+ // Verify no calls to removeFromKnownTable
+ verify(context, never()).removeFromKnownTable(any(String.class));
+ }
+
+ @Test
+ public void testGetHiveEntities_MultipleTables() throws Exception {
+ // Setup multiple table entities
+ WriteEntity table1Entity = mock(WriteEntity.class);
+ when(table1Entity.getType()).thenReturn(Entity.Type.TABLE);
+ Table table1 = mock(Table.class);
+ when(table1Entity.getTable()).thenReturn(table1);
+
+ WriteEntity table2Entity = mock(WriteEntity.class);
+ when(table2Entity.getType()).thenReturn(Entity.Type.TABLE);
+ Table table2 = mock(Table.class);
+ when(table2Entity.getTable()).thenReturn(table2);
+
+ Set<WriteEntity> outputs = new HashSet<>(Arrays.asList(table1Entity,
table2Entity));
+
+ DropTable dropTable = spy(new DropTable(context));
+ doReturn(outputs).when(dropTable).getOutputs();
+
+ // Mock getQualifiedName for both tables
+
doReturn("default.table1@cluster").when(dropTable).getQualifiedName(table1);
+
doReturn("default.table2@cluster").when(dropTable).getQualifiedName(table2);
+
+ List<AtlasObjectId> entities = dropTable.getHiveEntities();
+
+ AssertJUnit.assertNotNull("Entities should not be null", entities);
+ AssertJUnit.assertEquals("Should have two entities", 2,
entities.size());
+
+ // Verify both entities have correct type
+ for (AtlasObjectId entity : entities) {
+ AssertJUnit.assertEquals("Should be hive_table type",
"hive_table", entity.getTypeName());
+ }
+
+ // Verify context.removeFromKnownTable was called for both tables
+ verify(context).removeFromKnownTable("default.table1@cluster");
+ verify(context).removeFromKnownTable("default.table2@cluster");
+ }
+
+ @Test
+ public void testGetHiveEntities_MixedEntityTypes() throws Exception {
+ // Setup mixed entity types
+ WriteEntity tableEntity = mock(WriteEntity.class);
+ when(tableEntity.getType()).thenReturn(Entity.Type.TABLE);
+ when(tableEntity.getTable()).thenReturn(table);
+
+ WriteEntity dbEntity = mock(WriteEntity.class);
+ when(dbEntity.getType()).thenReturn(Entity.Type.DATABASE);
+
+ WriteEntity partitionEntity = mock(WriteEntity.class);
+ when(partitionEntity.getType()).thenReturn(Entity.Type.PARTITION);
+
+ Set<WriteEntity> outputs = new HashSet<>(Arrays.asList(tableEntity,
dbEntity, partitionEntity));
+
+ DropTable dropTable = spy(new DropTable(context));
+ doReturn(outputs).when(dropTable).getOutputs();
+
+ // Mock getQualifiedName for table only
+
doReturn("default.test_table@cluster").when(dropTable).getQualifiedName(table);
+
+ List<AtlasObjectId> entities = dropTable.getHiveEntities();
+
+ AssertJUnit.assertNotNull("Entities should not be null", entities);
+ AssertJUnit.assertEquals("Should have one entity (only table)", 1,
entities.size());
+
+ AtlasObjectId entity = entities.get(0);
+ AssertJUnit.assertEquals("Should be hive_table type", "hive_table",
entity.getTypeName());
+ AssertJUnit.assertEquals("Should have correct qualified name",
"default.test_table@cluster",
+ entity.getUniqueAttributes().get("qualifiedName"));
+
+ // Verify context.removeFromKnownTable was called only for table
+ verify(context).removeFromKnownTable("default.test_table@cluster");
+ verify(context, times(1)).removeFromKnownTable(any(String.class));
+ }
+
+/* @Test
Review Comment:
Remove commented-out test method or uncomment and implement it properly.
Commented code reduces maintainability.
```suggestion
@Test
```
##########
addons/hive-bridge/src/test/java/org/apache/atlas/hive/hook/events/CreateDatabaseTest.java:
##########
@@ -0,0 +1,184 @@
+package org.apache.atlas.hive.hook.events;
+
+import org.apache.atlas.hive.bridge.HiveMetaStoreBridge;
+import org.apache.atlas.hive.hook.AtlasHiveHookContext;
+import org.apache.atlas.hive.hook.HiveHook;
+import org.apache.atlas.model.instance.AtlasEntity;
+import org.apache.atlas.model.instance.AtlasObjectId;
+import org.apache.atlas.model.notification.HookNotification;
+import org.apache.atlas.type.AtlasTypeUtil;
+import org.apache.hadoop.hive.metastore.IHMSHandler;
+import org.apache.hadoop.hive.metastore.api.Database;
+//import org.apache.hadoop.hive.metastore.api.DatabaseType;
+import org.apache.hadoop.hive.metastore.api.PrincipalType;
+import org.apache.hadoop.hive.metastore.events.CreateDatabaseEvent;
+import org.apache.hadoop.hive.ql.hooks.Entity;
+import org.apache.hadoop.hive.ql.hooks.HookContext;
+import org.apache.hadoop.hive.ql.hooks.WriteEntity;
+import org.apache.hadoop.hive.ql.metadata.Hive;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.testng.annotations.Test;
+
+import java.util.*;
+
+import static org.mockito.Mockito.*;
+import static org.testng.AssertJUnit.*;
+
+public class CreateDatabaseTest {
+ private static final Logger LOG =
LoggerFactory.getLogger(CreateDatabaseTest.class);
+
+ CreateDatabase createDatabase;
+
+ @Mock
+ AtlasHiveHookContext context;
+
+ @Test
+ public void testGetNotificationMessagesGHMS() throws Exception {
+ MockitoAnnotations.initMocks(this);
+
+ when(context.isMetastoreHook()).thenReturn(true);
+
+ CreateDatabaseEvent createDatabaseEvent =
mock(CreateDatabaseEvent.class);
+ when(context.getMetastoreEvent()).thenReturn(createDatabaseEvent);
+
+ HiveHook hook = mock(HiveHook.class);
+ when(hook.getMetadataNamespace()).thenReturn("cm");
+
+ Database database = mock(Database.class);
+ when(createDatabaseEvent.getDatabase()).thenReturn(database);
+ database.setName("hive");
+ when(database.getName()).thenReturn("jacocoDb");
+ when(database.getDescription()).thenReturn(null);
+
when(database.getLocationUri()).thenReturn("hdfs://ccycloud-1.fsknox.root.comops.site:8020/warehouse/tablespace/external/hive/jacocoDb");
+
+ Map<String, String> parameters = new HashMap<>();
+ parameters.put("comment", "Similar to Default Hive database");
+ parameters.put("owner_name", "public");
+ parameters.put("owner_type", "ROLE");
+ when(database.getParameters()).thenReturn(parameters);
+
+ when(database.getOwnerName()).thenReturn("hive");
+ when(database.getOwnerType()).thenReturn(PrincipalType.USER);
+
+ when(database.getCatalogName()).thenReturn("hive");
+// when(database.getCreateTime()).thenReturn(1753349206);
Review Comment:
Remove commented-out mock setup code or uncomment it if needed for the test.
```suggestion
```
##########
addons/hive-bridge/src/test/java/org/apache/atlas/hive/hook/events/CreateTableTest.java:
##########
@@ -0,0 +1,790 @@
+package org.apache.atlas.hive.hook.events;
+
+import org.apache.atlas.hive.hook.AtlasHiveHookContext;
+import org.apache.atlas.model.instance.AtlasEntity;
+import org.apache.atlas.model.instance.AtlasEntity.AtlasEntitiesWithExtInfo;
+import org.apache.atlas.model.notification.HookNotification;
+import org.apache.hadoop.hive.metastore.TableType;
+import org.apache.hadoop.hive.metastore.api.StorageDescriptor;
+import org.apache.hadoop.hive.metastore.events.AlterTableEvent;
+import org.apache.hadoop.hive.metastore.events.CreateTableEvent;
+import org.apache.hadoop.hive.ql.hooks.Entity;
+import org.apache.hadoop.hive.ql.hooks.WriteEntity;
+import org.apache.hadoop.hive.ql.metadata.Hive;
+import org.apache.hadoop.hive.ql.metadata.Table;
+import org.apache.hadoop.hive.ql.plan.HiveOperation;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+import org.testng.AssertJUnit;
+import org.testng.annotations.BeforeMethod;
+import org.testng.annotations.Test;
+
+import java.lang.reflect.Method;
+import java.util.*;
+
+import static org.mockito.Mockito.*;
+import static org.junit.Assert.assertNotNull;
Review Comment:
[nitpick] Mixed usage of TestNG and JUnit assertions. The file primarily
uses TestNG's AssertJUnit but also imports JUnit's Assert. Consider
standardizing on one assertion library for consistency.
```suggestion
```
##########
addons/hive-bridge/src/test/java/org/apache/atlas/hive/hook/events/CreateDatabaseTest.java:
##########
@@ -0,0 +1,184 @@
+package org.apache.atlas.hive.hook.events;
+
+import org.apache.atlas.hive.bridge.HiveMetaStoreBridge;
+import org.apache.atlas.hive.hook.AtlasHiveHookContext;
+import org.apache.atlas.hive.hook.HiveHook;
+import org.apache.atlas.model.instance.AtlasEntity;
+import org.apache.atlas.model.instance.AtlasObjectId;
+import org.apache.atlas.model.notification.HookNotification;
+import org.apache.atlas.type.AtlasTypeUtil;
+import org.apache.hadoop.hive.metastore.IHMSHandler;
+import org.apache.hadoop.hive.metastore.api.Database;
+//import org.apache.hadoop.hive.metastore.api.DatabaseType;
Review Comment:
Remove unused commented import statement.
```suggestion
```
##########
addons/hive-bridge/src/test/java/org/apache/atlas/hive/hook/events/CreateHiveProcessTest.java:
##########
@@ -0,0 +1,1770 @@
+package org.apache.atlas.hive.hook.events;
+
+import org.apache.atlas.hive.hook.AtlasHiveHookContext;
+import org.apache.atlas.model.instance.AtlasEntity;
+import org.apache.atlas.model.instance.AtlasEntity.AtlasEntitiesWithExtInfo;
+import org.apache.atlas.model.notification.HookNotification;
+import
org.apache.atlas.model.notification.HookNotification.EntityCreateRequestV2;
+import org.apache.hadoop.hive.ql.hooks.Entity;
+import org.apache.hadoop.hive.ql.hooks.LineageInfo;
+import org.apache.hadoop.hive.ql.hooks.LineageInfo.BaseColumnInfo;
+import org.apache.hadoop.hive.ql.hooks.LineageInfo.Dependency;
+import org.apache.hadoop.hive.ql.hooks.LineageInfo.DependencyKey;
+import org.apache.hadoop.hive.ql.hooks.ReadEntity;
+import org.apache.hadoop.hive.ql.hooks.WriteEntity;
+import org.apache.hadoop.hive.ql.plan.HiveOperation;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.testng.AssertJUnit;
+import org.testng.annotations.BeforeMethod;
+import org.testng.annotations.Test;
+
+import java.lang.reflect.Method;
+import java.util.*;
+
+import static org.mockito.Mockito.*;
+import static org.testng.AssertJUnit.*;
+
+public class CreateHiveProcessTest {
+ private static final Logger LOG =
LoggerFactory.getLogger(CreateHiveProcessTest.class);
+
+ @Mock
+ AtlasHiveHookContext context;
+
+ @Mock
+ ReadEntity readEntity;
+
+ @Mock
+ WriteEntity writeEntity;
+
+ @Mock
+ LineageInfo lineageInfo;
+
+ @Mock
+ DependencyKey dependencyKey;
+
+ @Mock
+ Dependency dependency;
+
+ @Mock
+ BaseColumnInfo baseColumnInfo;
+
+
+
+ @BeforeMethod
+ public void setUp() {
+ MockitoAnnotations.initMocks(this);
+
+ // Mock context.getHiveOperation() to prevent NPEs in isDdlOperation
method
+ when(context.getHiveOperation()).thenReturn(HiveOperation.QUERY);
+ }
+
+ // ========== CONSTRUCTOR TESTS ==========
+
+ @Test
+ public void testConstructor() {
+ CreateHiveProcess createHiveProcess = new CreateHiveProcess(context);
+ AssertJUnit.assertNotNull("CreateHiveProcess should be instantiated",
createHiveProcess);
+ assertTrue("CreateHiveProcess should extend BaseHiveEvent",
+ createHiveProcess instanceof BaseHiveEvent);
+ }
+
+ @Test(expectedExceptions = NullPointerException.class)
+ public void testConstructorWithNullContext() {
+ new CreateHiveProcess(null);
+ }
+
+ // ========== getNotificationMessages() TESTS ==========
+
+ @Test
+ public void testGetNotificationMessages_WithEntities() throws Exception {
+ CreateHiveProcess createHiveProcess = spy(new
CreateHiveProcess(context));
+
+ // Mock getEntities to return some entities
+ AtlasEntitiesWithExtInfo mockEntities = new AtlasEntitiesWithExtInfo();
+ AtlasEntity entity = new AtlasEntity("hive_process");
+ entity.setAttribute("qualifiedName", "test.process@cluster");
+ mockEntities.addEntity(entity);
+
+ doReturn(mockEntities).when(createHiveProcess).getEntities();
+ doReturn("test_user").when(createHiveProcess).getUserName();
+
+ List<HookNotification> notifications =
createHiveProcess.getNotificationMessages();
+
+ AssertJUnit.assertNotNull("Notifications should not be null",
notifications);
+ AssertJUnit.assertEquals("Should have one notification", 1,
notifications.size());
+ assertTrue("Should be EntityCreateRequestV2",
+ notifications.get(0) instanceof EntityCreateRequestV2);
+
+ EntityCreateRequestV2 createRequest = (EntityCreateRequestV2)
notifications.get(0);
+ AssertJUnit.assertEquals("User should be test_user", "test_user",
createRequest.getUser());
+ AssertJUnit.assertNotNull("Entities should not be null",
createRequest.getEntities());
+ }
+
+ @Test
+ public void testGetNotificationMessages_EmptyEntities() throws Exception {
+ CreateHiveProcess createHiveProcess = spy(new
CreateHiveProcess(context));
+
+ // Mock getEntities to return empty entities
+ AtlasEntitiesWithExtInfo mockEntities = new AtlasEntitiesWithExtInfo();
+ doReturn(mockEntities).when(createHiveProcess).getEntities();
+
+ List<HookNotification> notifications =
createHiveProcess.getNotificationMessages();
+
+ assertNull("Notifications should be null when entities are empty",
notifications);
+ }
+
+ @Test
+ public void testGetNotificationMessages_NullEntities() throws Exception {
+ CreateHiveProcess createHiveProcess = spy(new
CreateHiveProcess(context));
+
+ // Mock getEntities to return null
+ doReturn(null).when(createHiveProcess).getEntities();
+
+ List<HookNotification> notifications =
createHiveProcess.getNotificationMessages();
+
+ assertNull("Notifications should be null when entities are null",
notifications);
+ }
+
+ // ========== getEntities() TESTS ==========
+
+ @Test
+ public void testGetEntities_SkipProcess() throws Exception {
+ CreateHiveProcess createHiveProcess = spy(new
CreateHiveProcess(context));
+
+ // Set up empty inputs and outputs to make skipProcess return true
+ doReturn(Collections.emptySet()).when(createHiveProcess).getInputs();
+ doReturn(Collections.emptySet()).when(createHiveProcess).getOutputs();
+
+ // Use reflection to call private method 'skipProcess'
+ Method skipProcessMethod =
CreateHiveProcess.class.getDeclaredMethod("skipProcess");
+ skipProcessMethod.setAccessible(true);
+
+ // Now skipProcess should return true due to empty inputs/outputs
+ boolean skip = (boolean) skipProcessMethod.invoke(createHiveProcess);
+ assertTrue("skipProcess() should return true for empty
inputs/outputs", skip);
+
+ // Now call getEntities (it will internally call skipProcess())
+ AtlasEntitiesWithExtInfo entities = createHiveProcess.getEntities();
+
+ assertNull("Entities should be null when process is skipped",
entities);
+ }
+
+
+ @Test
+ public void testGetEntities_EmptyInputsAndOutputs() throws Exception {
+ CreateHiveProcess createHiveProcess = spy(new
CreateHiveProcess(context));
+
+ // Prepare empty inputs/outputs
+ doReturn(Collections.emptySet()).when(createHiveProcess).getInputs();
+ doReturn(Collections.emptySet()).when(createHiveProcess).getOutputs();
+
+ // Mock context methods
+ when(context.isSkippedInputEntity()).thenReturn(false);
+ when(context.isSkippedOutputEntity()).thenReturn(false);
+ when(context.isMetastoreHook()).thenReturn(false);
+
+ // Use reflection to ensure skipProcess returns true (due to empty
inputs/outputs)
+ Method skipProcessMethod =
CreateHiveProcess.class.getDeclaredMethod("skipProcess");
+ skipProcessMethod.setAccessible(true);
+ boolean skip = (boolean) skipProcessMethod.invoke(createHiveProcess);
+ assertTrue("skipProcess should return true for empty inputs/outputs",
skip);
+
+ // Now run getEntities()
+ AtlasEntitiesWithExtInfo entities = createHiveProcess.getEntities();
+
+ assertNull("Entities should be null when inputs and outputs are
empty", entities);
+ }
+
+
+ @Test
+ public void testGetEntities_WithSkippedInputEntity() throws Exception {
+ CreateHiveProcess createHiveProcess = spy(new
CreateHiveProcess(context));
+
+ // Prepare empty inputs but some outputs
+ doReturn(Collections.emptySet()).when(createHiveProcess).getInputs();
+ Set<WriteEntity> outputs = Collections.singleton(writeEntity);
+ doReturn(outputs).when(createHiveProcess).getOutputs();
+
+ // Mock getQualifiedName and getInputOutputEntity
+
doReturn("default.test_table@cluster").when(createHiveProcess).getQualifiedName(writeEntity);
+ AtlasEntity outputEntity = new AtlasEntity("hive_table");
+
doReturn(outputEntity).when(createHiveProcess).getInputOutputEntity(eq(writeEntity),
any(), anyBoolean());
+
+ // Mock context methods
+ when(context.isSkippedInputEntity()).thenReturn(true);
+ when(context.isMetastoreHook()).thenReturn(false);
+
+ // Reflection: ensure skipProcess returns false (has outputs but no
inputs)
+ Method skipProcessMethod =
CreateHiveProcess.class.getDeclaredMethod("skipProcess");
+ skipProcessMethod.setAccessible(true);
+ boolean skip = (boolean) skipProcessMethod.invoke(createHiveProcess);
+ assertFalse("skipProcess should return false when there are outputs
but no inputs", skip);
+
+ // Reflection: ensure isDdlOperation returns false
+ Method isDdlOperationMethod =
CreateHiveProcess.class.getDeclaredMethod("isDdlOperation", AtlasEntity.class);
+ isDdlOperationMethod.setAccessible(true);
+ boolean ddlOp = (boolean)
isDdlOperationMethod.invoke(createHiveProcess, outputEntity);
+ assertFalse("isDdlOperation should return false in this scenario",
ddlOp);
+
+ // Now run getEntities()
+ AtlasEntitiesWithExtInfo entities = createHiveProcess.getEntities();
+
+ assertNull("Entities should be null when input entity is skipped",
entities);
+ }
+
+
+
+ @Test
+ public void testGetEntities_WithSkippedOutputEntity() throws Exception {
+ CreateHiveProcess createHiveProcess = spy(new
CreateHiveProcess(context));
+
+ // Prepare some inputs but empty outputs
+ Set<ReadEntity> inputs = Collections.singleton(readEntity);
+ doReturn(inputs).when(createHiveProcess).getInputs();
+ doReturn(Collections.emptySet()).when(createHiveProcess).getOutputs();
+
+ // Mock getQualifiedName to avoid NPE in BaseHiveEvent.getQualifiedName
+
doReturn("default.input_table@cluster").when(createHiveProcess).getQualifiedName(readEntity);
+
+ // Mock getInputOutputEntity to avoid NPE in
BaseHiveEvent.getInputOutputEntity
+ AtlasEntity inputEntity = new AtlasEntity("hive_table");
+
doReturn(inputEntity).when(createHiveProcess).getInputOutputEntity(eq(readEntity),
any(), anyBoolean());
+
+ // Mock entity type and direct flag
+
when(readEntity.getType()).thenReturn(org.apache.hadoop.hive.ql.hooks.Entity.Type.TABLE);
+ when(readEntity.isDirect()).thenReturn(true);
+
+ // Mock context methods
+ when(context.isSkippedOutputEntity()).thenReturn(true);
+ when(context.isMetastoreHook()).thenReturn(false);
+
+ // Reflection: ensure skipProcess returns false (has inputs but no
outputs)
+ Method skipProcessMethod =
CreateHiveProcess.class.getDeclaredMethod("skipProcess");
+ skipProcessMethod.setAccessible(true);
+ boolean skip = (boolean) skipProcessMethod.invoke(createHiveProcess);
+ assertFalse("skipProcess should return false when there are inputs but
no outputs", skip);
+
+ // Now run getEntities()
+ AtlasEntitiesWithExtInfo entities = createHiveProcess.getEntities();
+
+ assertNull("Entities should be null when output entity is skipped",
entities);
+ }
+
+
+ @Test
+ public void testGetEntities_SuccessfulProcessCreation() throws Exception {
+ CreateHiveProcess createHiveProcess = spy(new
CreateHiveProcess(context));
+
+ // Mock inputs and outputs
+ Set<ReadEntity> inputs = Collections.singleton(readEntity);
+ Set<WriteEntity> outputs = Collections.singleton(writeEntity);
+ doReturn(inputs).when(createHiveProcess).getInputs();
+ doReturn(outputs).when(createHiveProcess).getOutputs();
+
+ // Mock getQualifiedName for entities
+
doReturn("default.input_table@cluster").when(createHiveProcess).getQualifiedName(readEntity);
+
doReturn("default.output_table@cluster").when(createHiveProcess).getQualifiedName(writeEntity);
+
+ // Mock getInputOutputEntity
+ AtlasEntity inputEntity = new AtlasEntity("hive_table");
+ AtlasEntity outputEntity = new AtlasEntity("hive_table");
+
doReturn(inputEntity).when(createHiveProcess).getInputOutputEntity(eq(readEntity),
any(), anyBoolean());
+
doReturn(outputEntity).when(createHiveProcess).getInputOutputEntity(eq(writeEntity),
any(), anyBoolean());
+
+ // Mock entity types and flags
+
when(readEntity.getType()).thenReturn(org.apache.hadoop.hive.ql.hooks.Entity.Type.TABLE);
+
when(writeEntity.getType()).thenReturn(org.apache.hadoop.hive.ql.hooks.Entity.Type.TABLE);
+ when(readEntity.isDirect()).thenReturn(true);
+
+ // Mock context methods
+ when(context.isSkippedInputEntity()).thenReturn(false);
+ when(context.isSkippedOutputEntity()).thenReturn(false);
+ when(context.isMetastoreHook()).thenReturn(false);
+
+ // Reflection: ensure skipProcess returns false (has both inputs and
outputs)
+ Method skipProcessMethod =
CreateHiveProcess.class.getDeclaredMethod("skipProcess");
+ skipProcessMethod.setAccessible(true);
+ boolean skip = (boolean) skipProcessMethod.invoke(createHiveProcess);
+ assertFalse("skipProcess should return false when there are both
inputs and outputs", skip);
+
+ // Reflection: ensure isDdlOperation returns false
+ Method isDdlMethod =
CreateHiveProcess.class.getDeclaredMethod("isDdlOperation", AtlasEntity.class);
+ isDdlMethod.setAccessible(true);
+ boolean isDdl = (boolean) isDdlMethod.invoke(createHiveProcess,
outputEntity);
+ assertFalse("isDdlOperation should return false in this scenario",
isDdl);
+
+ // Mock process creation methods
+ AtlasEntity processEntity = new AtlasEntity("hive_process");
+ processEntity.setAttribute("qualifiedName", "test_process@cluster");
+
doReturn(processEntity).when(createHiveProcess).getHiveProcessEntity(anyList(),
anyList());
+
+ AtlasEntity processExecutionEntity = new
AtlasEntity("hive_process_execution");
+
doReturn(processExecutionEntity).when(createHiveProcess).getHiveProcessExecutionEntity(processEntity);
+
+ // Mock methods needed by getHiveProcessExecutionEntity
+ doReturn("test_user").when(createHiveProcess).getUserName();
+ doReturn("query_123").when(createHiveProcess).getQueryId();
+ doReturn("SELECT * FROM
table").when(createHiveProcess).getQueryString();
+ doReturn(System.currentTimeMillis() -
5000).when(createHiveProcess).getQueryStartTime();
+ when(context.getHostName()).thenReturn("test_host");
+
+ // Reflection: invoke processColumnLineage without doing anything
+ Method processColumnLineageMethod =
+
CreateHiveProcess.class.getDeclaredMethod("processColumnLineage",
AtlasEntity.class, AtlasEntitiesWithExtInfo.class);
+ processColumnLineageMethod.setAccessible(true);
+ // No-op, we don't actually execute it in the test
+
+ // Mock addProcessedEntities to do nothing
+ doNothing().when(createHiveProcess).addProcessedEntities(any());
+
+ // Now run getEntities()
+ AtlasEntitiesWithExtInfo entities = createHiveProcess.getEntities();
+
+ AssertJUnit.assertNotNull("Entities should not be null", entities);
+ AssertJUnit.assertNotNull("Entities list should not be null",
entities.getEntities());
+ assertTrue("Should contain process entities",
entities.getEntities().size() >= 2);
+
+ // Verify process and process execution entities exist
+ boolean hasProcess = entities.getEntities().stream()
+ .anyMatch(entity ->
"hive_process".equals(entity.getTypeName()));
+ boolean hasProcessExecution = entities.getEntities().stream()
+ .anyMatch(entity ->
"hive_process_execution".equals(entity.getTypeName()));
+
+ assertTrue("Should contain hive_process entity", hasProcess);
+ assertTrue("Should contain hive_process_execution entity",
hasProcessExecution);
+ }
+
+
+ @Test
+ public void testGetEntities_MetastoreHook() throws Exception {
+ CreateHiveProcess createHiveProcess = spy(new
CreateHiveProcess(context));
+
+ // Mock outputs
+ Set<WriteEntity> outputs = Collections.singleton(writeEntity);
+ doReturn(Collections.emptySet()).when(createHiveProcess).getInputs();
+ doReturn(outputs).when(createHiveProcess).getOutputs();
+
+ // Mock getQualifiedName
+
doReturn("default.output_table@cluster").when(createHiveProcess).getQualifiedName(writeEntity);
+
+ // Mock getInputOutputEntity
+ AtlasEntity outputEntity = new AtlasEntity("hive_table");
+
doReturn(outputEntity).when(createHiveProcess).getInputOutputEntity(eq(writeEntity),
any(), anyBoolean());
+
+ // Reflection: ensure skipProcess returns false (has outputs but no
inputs)
+ Method skipProcessMethod =
CreateHiveProcess.class.getDeclaredMethod("skipProcess");
+ skipProcessMethod.setAccessible(true);
+ boolean skip = (boolean) skipProcessMethod.invoke(createHiveProcess);
+ assertFalse("skipProcess should return false when there are outputs
but no inputs", skip);
+
+ // Reflection: ensure isDdlOperation returns false
+ Method isDdlMethod =
CreateHiveProcess.class.getDeclaredMethod("isDdlOperation", AtlasEntity.class);
+ isDdlMethod.setAccessible(true);
+ boolean isDdl = (boolean) isDdlMethod.invoke(createHiveProcess,
outputEntity);
+ assertFalse("isDdlOperation should return false in this scenario",
isDdl);
+
+ // Mock context methods - metastore hook
+ when(context.isMetastoreHook()).thenReturn(true);
+
+ // Call method under test
+ AtlasEntitiesWithExtInfo entities = createHiveProcess.getEntities();
+
+ // Verify
+ assertNull("Entities should be null for metastore hook with empty
inputs", entities);
+ }
+
+
+ @Test
+ public void testGetEntities_WithDDLOperation() throws Exception {
+ CreateHiveProcess createHiveProcess = spy(new
CreateHiveProcess(context));
+
+ // Mock outputs
+ Set<WriteEntity> outputs = Collections.singleton(writeEntity);
+ doReturn(Collections.emptySet()).when(createHiveProcess).getInputs();
+ doReturn(outputs).when(createHiveProcess).getOutputs();
+
+ // Mock getQualifiedName
+
doReturn("default.output_table@cluster").when(createHiveProcess).getQualifiedName(writeEntity);
+
+ // Mock getInputOutputEntity
+ AtlasEntity outputEntity = new AtlasEntity("hive_table");
+
doReturn(outputEntity).when(createHiveProcess).getInputOutputEntity(eq(writeEntity),
any(), anyBoolean());
+
+ // --- Reflection to make skipProcess return false ---
+ Method skipProcessMethod =
CreateHiveProcess.class.getDeclaredMethod("skipProcess");
+ skipProcessMethod.setAccessible(true);
+ assertFalse((boolean) skipProcessMethod.invoke(createHiveProcess));
+
+ // Mock context to return a DDL operation
+
when(context.getHiveOperation()).thenReturn(HiveOperation.CREATETABLE_AS_SELECT);
+
+ // --- Reflection to make isDdlOperation return true ---
+ Method isDdlMethod =
CreateHiveProcess.class.getDeclaredMethod("isDdlOperation", AtlasEntity.class);
+ isDdlMethod.setAccessible(true);
+ assertTrue("Expected DDL operation", (boolean)
isDdlMethod.invoke(createHiveProcess, outputEntity));
+
+ // Mock createHiveDDLEntity (this is public/protected so mocking is
fine)
+ AtlasEntity ddlEntity = new AtlasEntity("hive_ddl");
+
doReturn(ddlEntity).when(createHiveProcess).createHiveDDLEntity(outputEntity);
+
+ // Mock context methods
+ when(context.isMetastoreHook()).thenReturn(true);
+
+ // Call method under test
+ AtlasEntitiesWithExtInfo entities = createHiveProcess.getEntities();
+
+ // Assert expected behavior
+ assertNull("Entities should be null for metastore hook with empty
inputs", entities);
+ }
+
+
+ // ========== HELPER METHOD TESTS ==========
+
+ @Test
+ public void testCheckIfOnlySelfLineagePossible_True() throws Exception {
+ CreateHiveProcess createHiveProcess = new CreateHiveProcess(context);
+
+ // Use reflection to access private method
+ Method method = CreateHiveProcess.class.getDeclaredMethod(
+ "checkIfOnlySelfLineagePossible", String.class, Map.class);
+ method.setAccessible(true);
+
+ Map<String, Entity> inputByQualifiedName = new HashMap<>();
+ inputByQualifiedName.put("default.table@cluster", readEntity);
+
+ boolean result = (boolean) method.invoke(createHiveProcess,
"default.table@cluster", inputByQualifiedName);
+
+ assertTrue("Should return true for self lineage", result);
+ }
+
+ @Test
+ public void testCheckIfOnlySelfLineagePossible_False() throws Exception {
+ CreateHiveProcess createHiveProcess = new CreateHiveProcess(context);
+
+ // Use reflection to access private method
+ Method method = CreateHiveProcess.class.getDeclaredMethod(
+ "checkIfOnlySelfLineagePossible", String.class, Map.class);
+ method.setAccessible(true);
+
+ Map<String, Entity> inputByQualifiedName = new HashMap<>();
+ inputByQualifiedName.put("default.input_table@cluster", readEntity);
+
+ boolean result = (boolean) method.invoke(createHiveProcess,
"default.output_table@cluster", inputByQualifiedName);
+
+ assertFalse("Should return false for different table", result);
+ }
+
+ @Test
+ public void testCheckIfOnlySelfLineagePossible_MultipleInputs() throws
Exception {
+ CreateHiveProcess createHiveProcess = new CreateHiveProcess(context);
+
+ // Use reflection to access private method
+ Method method = CreateHiveProcess.class.getDeclaredMethod(
+ "checkIfOnlySelfLineagePossible", String.class, Map.class);
+ method.setAccessible(true);
+
+ Map<String, Entity> inputByQualifiedName = new HashMap<>();
+ inputByQualifiedName.put("default.table1@cluster", readEntity);
+ inputByQualifiedName.put("default.table2@cluster",
mock(ReadEntity.class));
+
+ boolean result = (boolean) method.invoke(createHiveProcess,
"default.table1@cluster", inputByQualifiedName);
+
+ assertFalse("Should return false for multiple inputs", result);
+ }
+
+ @Test
+ public void testSkipProcess_EmptyInputsAndOutputs() throws Exception {
+ CreateHiveProcess createHiveProcess = spy(new
CreateHiveProcess(context));
+
+ // Mock empty inputs and outputs
+ doReturn(Collections.emptySet()).when(createHiveProcess).getInputs();
+ doReturn(Collections.emptySet()).when(createHiveProcess).getOutputs();
+
+ // Use reflection to access private method
+ Method method =
CreateHiveProcess.class.getDeclaredMethod("skipProcess");
+ method.setAccessible(true);
+
+ boolean result = (boolean) method.invoke(createHiveProcess);
+
+ assertTrue("Should skip process when inputs and outputs are empty",
result);
+ }
+
+ @Test
+ public void testSkipProcess_QueryWithTempDirectory() throws Exception {
+ CreateHiveProcess createHiveProcess = spy(new
CreateHiveProcess(context));
+
+ // Mock inputs and outputs
+ doReturn(Collections.emptySet()).when(createHiveProcess).getInputs();
+
+ WriteEntity tempOutput = mock(WriteEntity.class);
+ when(tempOutput.getType()).thenReturn(Entity.Type.DFS_DIR);
+
when(tempOutput.getWriteType()).thenReturn(WriteEntity.WriteType.PATH_WRITE);
+ when(tempOutput.isTempURI()).thenReturn(true);
+
+ Set<WriteEntity> outputs = Collections.singleton(tempOutput);
+ doReturn(outputs).when(createHiveProcess).getOutputs();
+
+ // Mock context
+ doReturn(context).when(createHiveProcess).getContext();
+ when(context.getHiveOperation()).thenReturn(HiveOperation.QUERY);
+
+ // Use reflection to access private method
+ Method method =
CreateHiveProcess.class.getDeclaredMethod("skipProcess");
+ method.setAccessible(true);
+
+ boolean result = (boolean) method.invoke(createHiveProcess);
+
+ assertTrue("Should skip process for query with temp directory",
result);
+ }
+
+ @Test
+ public void testSkipProcess_DeleteOperation() throws Exception {
+ CreateHiveProcess createHiveProcess = spy(new
CreateHiveProcess(context));
+
+ // Mock inputs and outputs
+ doReturn(Collections.emptySet()).when(createHiveProcess).getInputs();
+
+ WriteEntity deleteOutput = mock(WriteEntity.class);
+ when(deleteOutput.getType()).thenReturn(Entity.Type.TABLE);
+
when(deleteOutput.getWriteType()).thenReturn(WriteEntity.WriteType.DELETE);
+
+ Set<WriteEntity> outputs = Collections.singleton(deleteOutput);
+ doReturn(outputs).when(createHiveProcess).getOutputs();
+
+ // Mock context
+ doReturn(context).when(createHiveProcess).getContext();
+ when(context.getHiveOperation()).thenReturn(HiveOperation.QUERY);
+
+ // Use reflection to access private method
+ Method method =
CreateHiveProcess.class.getDeclaredMethod("skipProcess");
+ method.setAccessible(true);
+
+ boolean result = (boolean) method.invoke(createHiveProcess);
+
+ assertTrue("Should skip process for DELETE operation", result);
+ }
+
+ @Test
+ public void testSkipProcess_UpdateOperation() throws Exception {
+ CreateHiveProcess createHiveProcess = spy(new
CreateHiveProcess(context));
+
+ // Mock inputs and outputs
+ doReturn(Collections.emptySet()).when(createHiveProcess).getInputs();
+
+ WriteEntity updateOutput = mock(WriteEntity.class);
+ when(updateOutput.getType()).thenReturn(Entity.Type.TABLE);
+
when(updateOutput.getWriteType()).thenReturn(WriteEntity.WriteType.UPDATE);
+
+ Set<WriteEntity> outputs = Collections.singleton(updateOutput);
+ doReturn(outputs).when(createHiveProcess).getOutputs();
+
+ // Mock context
+ doReturn(context).when(createHiveProcess).getContext();
+ when(context.getHiveOperation()).thenReturn(HiveOperation.QUERY);
+
+ // Use reflection to access private method
+ Method method =
CreateHiveProcess.class.getDeclaredMethod("skipProcess");
+ method.setAccessible(true);
+
+ boolean result = (boolean) method.invoke(createHiveProcess);
+
+ assertTrue("Should skip process for UPDATE operation", result);
+ }
+
+ @Test
+ public void testSkipProcess_RegularQuery() throws Exception {
+ CreateHiveProcess createHiveProcess = spy(new
CreateHiveProcess(context));
+
+ // Mock inputs and outputs
+ Set<ReadEntity> inputs = Collections.singleton(readEntity);
+ doReturn(inputs).when(createHiveProcess).getInputs();
+
+ WriteEntity normalOutput = mock(WriteEntity.class);
+ when(normalOutput.getType()).thenReturn(Entity.Type.TABLE);
+
when(normalOutput.getWriteType()).thenReturn(WriteEntity.WriteType.INSERT);
+
+ Set<WriteEntity> outputs = Collections.singleton(normalOutput);
+ doReturn(outputs).when(createHiveProcess).getOutputs();
+
+ // Use reflection to access private method
+ Method method =
CreateHiveProcess.class.getDeclaredMethod("skipProcess");
+ method.setAccessible(true);
+
+ boolean result = (boolean) method.invoke(createHiveProcess);
+
+ assertFalse("Should not skip process for regular query", result);
+ }
+
+ @Test
+ public void testIsDdlOperation_CreateTableAsSelect() throws Exception {
+ CreateHiveProcess createHiveProcess = spy(new
CreateHiveProcess(context));
+
+ AtlasEntity entity = new AtlasEntity("hive_table");
+
+ // Mock context
+ when(context.isMetastoreHook()).thenReturn(false);
+
when(context.getHiveOperation()).thenReturn(HiveOperation.CREATETABLE_AS_SELECT);
+
+ // Use reflection to access private method
+ Method method =
CreateHiveProcess.class.getDeclaredMethod("isDdlOperation", AtlasEntity.class);
+ method.setAccessible(true);
+
+ boolean result = (boolean) method.invoke(createHiveProcess, entity);
+
+ assertTrue("Should be DDL operation for CREATETABLE_AS_SELECT",
result);
+ }
+
+ @Test
+ public void testIsDdlOperation_CreateView() throws Exception {
+ CreateHiveProcess createHiveProcess = spy(new
CreateHiveProcess(context));
+
+ AtlasEntity entity = new AtlasEntity("hive_table");
+
+ // Mock context
+ when(context.isMetastoreHook()).thenReturn(false);
+ when(context.getHiveOperation()).thenReturn(HiveOperation.CREATEVIEW);
+
+ // Use reflection to access private method
+ Method method =
CreateHiveProcess.class.getDeclaredMethod("isDdlOperation", AtlasEntity.class);
+ method.setAccessible(true);
+
+ boolean result = (boolean) method.invoke(createHiveProcess, entity);
+
+ assertTrue("Should be DDL operation for CREATEVIEW", result);
+ }
+
+ @Test
+ public void testIsDdlOperation_AlterViewAs() throws Exception {
+ CreateHiveProcess createHiveProcess = spy(new
CreateHiveProcess(context));
+
+ AtlasEntity entity = new AtlasEntity("hive_table");
+
+ // Mock context
+ when(context.isMetastoreHook()).thenReturn(false);
+
when(context.getHiveOperation()).thenReturn(HiveOperation.ALTERVIEW_AS);
+
+ // Use reflection to access private method
+ Method method =
CreateHiveProcess.class.getDeclaredMethod("isDdlOperation", AtlasEntity.class);
+ method.setAccessible(true);
+
+ boolean result = (boolean) method.invoke(createHiveProcess, entity);
+
+ assertTrue("Should be DDL operation for ALTERVIEW_AS", result);
+ }
+
+ @Test
+ public void testIsDdlOperation_CreateMaterializedView() throws Exception {
+ CreateHiveProcess createHiveProcess = spy(new
CreateHiveProcess(context));
+
+ AtlasEntity entity = new AtlasEntity("hive_table");
+
+ // Mock context
+ when(context.isMetastoreHook()).thenReturn(false);
+
when(context.getHiveOperation()).thenReturn(HiveOperation.CREATE_MATERIALIZED_VIEW);
+
+ // Use reflection to access private method
+ Method method =
CreateHiveProcess.class.getDeclaredMethod("isDdlOperation", AtlasEntity.class);
+ method.setAccessible(true);
+
+ boolean result = (boolean) method.invoke(createHiveProcess, entity);
+
+ assertTrue("Should be DDL operation for CREATE_MATERIALIZED_VIEW",
result);
+ }
+
+ @Test
+ public void testIsDdlOperation_MetastoreHook() throws Exception {
+ CreateHiveProcess createHiveProcess = spy(new
CreateHiveProcess(context));
+
+ AtlasEntity entity = new AtlasEntity("hive_table");
+
+ // Mock context - metastore hook
+ when(context.isMetastoreHook()).thenReturn(true);
+
when(context.getHiveOperation()).thenReturn(HiveOperation.CREATETABLE_AS_SELECT);
+
+ // Use reflection to access private method
+ Method method =
CreateHiveProcess.class.getDeclaredMethod("isDdlOperation", AtlasEntity.class);
+ method.setAccessible(true);
+
+ boolean result = (boolean) method.invoke(createHiveProcess, entity);
+
+ assertFalse("Should not be DDL operation for metastore hook", result);
+ }
+
+ @Test
+ public void testIsDdlOperation_RegularOperation() throws Exception {
+ CreateHiveProcess createHiveProcess = spy(new
CreateHiveProcess(context));
+
+ AtlasEntity entity = new AtlasEntity("hive_table");
+
+ // Mock context
+ when(context.isMetastoreHook()).thenReturn(false);
+ when(context.getHiveOperation()).thenReturn(HiveOperation.QUERY);
+
+ // Use reflection to access private method
+ Method method =
CreateHiveProcess.class.getDeclaredMethod("isDdlOperation", AtlasEntity.class);
+ method.setAccessible(true);
+
+ boolean result = (boolean) method.invoke(createHiveProcess, entity);
+
+ assertFalse("Should not be DDL operation for regular query", result);
+ }
+
+ @Test
+ public void testIsDdlOperation_NullEntity() throws Exception {
+ CreateHiveProcess createHiveProcess = spy(new
CreateHiveProcess(context));
+
+ // Use reflection to access private method
+ Method method =
CreateHiveProcess.class.getDeclaredMethod("isDdlOperation", AtlasEntity.class);
+ method.setAccessible(true);
+
+ boolean result = (boolean) method.invoke(createHiveProcess,
(AtlasEntity) null);
+
+ assertFalse("Should not be DDL operation for null entity", result);
+ }
+
+ // ========== COLUMN LINEAGE TESTS ==========
+
+ @Test
+ public void testProcessColumnLineage_NullLineageInfo() throws Exception {
+ CreateHiveProcess createHiveProcess = spy(new
CreateHiveProcess(context));
+
+ // Prepare inputs/outputs first
+ Set<WriteEntity> outputs = Collections.singleton(writeEntity);
+ doReturn(Collections.emptySet()).when(createHiveProcess).getInputs();
+ doReturn(outputs).when(createHiveProcess).getOutputs();
+
+ // --- Reflection to force skipProcess to return false ---
+ Method skipProcessMethod =
CreateHiveProcess.class.getDeclaredMethod("skipProcess");
+ skipProcessMethod.setAccessible(true);
+ assertFalse("skipProcess should return false", (boolean)
skipProcessMethod.invoke(createHiveProcess));
+
+ // Mock getQualifiedName
+
doReturn("default.output_table@cluster").when(createHiveProcess).getQualifiedName(writeEntity);
+
+ // Mock getInputOutputEntity
+ AtlasEntity outputEntity = new AtlasEntity("hive_table");
+
doReturn(outputEntity).when(createHiveProcess).getInputOutputEntity(eq(writeEntity),
any(), anyBoolean());
+
+ // --- Reflection to force isDdlOperation to return false ---
+ Method ddlMethod =
CreateHiveProcess.class.getDeclaredMethod("isDdlOperation", AtlasEntity.class);
+ ddlMethod.setAccessible(true);
+ assertFalse("Expected non-DDL operation", (boolean)
ddlMethod.invoke(createHiveProcess, outputEntity));
+
+ // Mock entity type
+
when(writeEntity.getType()).thenReturn(org.apache.hadoop.hive.ql.hooks.Entity.Type.TABLE);
+
+ // Context settings
+ when(context.isMetastoreHook()).thenReturn(false);
+ when(context.isSkippedInputEntity()).thenReturn(false);
+ when(context.isSkippedOutputEntity()).thenReturn(false);
+
+ // Mock process entity creation
+ AtlasEntity processEntity = new AtlasEntity("hive_process");
+ processEntity.setAttribute("qualifiedName", "test_process@cluster");
+
doReturn(processEntity).when(createHiveProcess).getHiveProcessEntity(anyList(),
anyList());
+
+ AtlasEntity processExecutionEntity = new
AtlasEntity("hive_process_execution");
+
doReturn(processExecutionEntity).when(createHiveProcess).getHiveProcessExecutionEntity(processEntity);
+
+ // Mock required getters
+ doReturn("test_user").when(createHiveProcess).getUserName();
+ doReturn("query_123").when(createHiveProcess).getQueryId();
+ doReturn("SELECT * FROM
table").when(createHiveProcess).getQueryString();
+ doReturn(System.currentTimeMillis() -
5000).when(createHiveProcess).getQueryStartTime();
+ when(context.getHostName()).thenReturn("test_host");
+
+ // Null lineage info (triggers early return in processColumnLineage)
+ doReturn(null).when(createHiveProcess).getLineageInfo();
+
+ doNothing().when(createHiveProcess).addProcessedEntities(any());
+
+ // Run test
+ AtlasEntitiesWithExtInfo entities = createHiveProcess.getEntities();
+
+ assertNotNull("Entities should not be null", entities);
+ // We don't assert column lineage here because getLineageInfo is null
+ }
+
+
+ @Test
+ public void testProcessColumnLineage_EmptyLineageInfo() throws Exception {
+ CreateHiveProcess createHiveProcess = spy(new
CreateHiveProcess(context));
+
+ Set<WriteEntity> outputs = Collections.singleton(writeEntity);
+ doReturn(Collections.emptySet()).when(createHiveProcess).getInputs();
+ doReturn(outputs).when(createHiveProcess).getOutputs();
+
+ // Just call skipProcess via reflection to verify it's false (no
stubbing needed)
+ Method skipProcessMethod =
CreateHiveProcess.class.getDeclaredMethod("skipProcess");
+ skipProcessMethod.setAccessible(true);
+ assertFalse((boolean) skipProcessMethod.invoke(createHiveProcess));
+
+
doReturn("default.output_table@cluster").when(createHiveProcess).getQualifiedName(writeEntity);
+
+ AtlasEntity outputEntity = new AtlasEntity("hive_table");
+
doReturn(outputEntity).when(createHiveProcess).getInputOutputEntity(eq(writeEntity),
any(), anyBoolean());
+
+ // Check isDdlOperation via reflection instead of stubbing
+ Method ddlMethod =
CreateHiveProcess.class.getDeclaredMethod("isDdlOperation", AtlasEntity.class);
+ ddlMethod.setAccessible(true);
+ assertFalse((boolean) ddlMethod.invoke(createHiveProcess,
outputEntity));
+
+
when(writeEntity.getType()).thenReturn(org.apache.hadoop.hive.ql.hooks.Entity.Type.TABLE);
+
+ when(context.isMetastoreHook()).thenReturn(false);
+ when(context.isSkippedInputEntity()).thenReturn(false);
+ when(context.isSkippedOutputEntity()).thenReturn(false);
+
+ AtlasEntity processEntity = new AtlasEntity("hive_process");
+ processEntity.setAttribute("qualifiedName", "test_process@cluster");
+
doReturn(processEntity).when(createHiveProcess).getHiveProcessEntity(anyList(),
anyList());
+
+ AtlasEntity processExecutionEntity = new
AtlasEntity("hive_process_execution");
+
doReturn(processExecutionEntity).when(createHiveProcess).getHiveProcessExecutionEntity(processEntity);
+
+ doReturn("test_user").when(createHiveProcess).getUserName();
+ doReturn("query_123").when(createHiveProcess).getQueryId();
+ doReturn("SELECT * FROM
table").when(createHiveProcess).getQueryString();
+ doReturn(System.currentTimeMillis() -
5000).when(createHiveProcess).getQueryStartTime();
+ when(context.getHostName()).thenReturn("test_host");
+
+ LineageInfo emptyLineageInfo = new LineageInfo();
+ doReturn(emptyLineageInfo).when(createHiveProcess).getLineageInfo();
+ doNothing().when(createHiveProcess).addProcessedEntities(any());
+
+ AtlasEntitiesWithExtInfo entities = createHiveProcess.getEntities();
+
+ assertNotNull("Entities should not be null", entities);
+ }
+
+
+ @Test
+ public void testGetBaseCols_NullDependency() throws Exception {
+ CreateHiveProcess createHiveProcess = new CreateHiveProcess(context);
+
+ // Use reflection to access private method
+ Method method =
CreateHiveProcess.class.getDeclaredMethod("getBaseCols", Dependency.class);
+ method.setAccessible(true);
+
+ Collection<BaseColumnInfo> result = (Collection<BaseColumnInfo>)
method.invoke(createHiveProcess, (Dependency) null);
+
+ AssertJUnit.assertNotNull("Result should not be null", result);
+ assertTrue("Result should be empty", result.isEmpty());
+ }
+
+ @Test
+ public void testGetBaseCols_ValidDependency() throws Exception {
+ CreateHiveProcess createHiveProcess = new CreateHiveProcess(context);
+
+ // Create a mock dependency that has getBaseCols method
+ Dependency mockDependency = mock(Dependency.class);
+ BaseColumnInfo baseCol1 = mock(BaseColumnInfo.class);
+ BaseColumnInfo baseCol2 = mock(BaseColumnInfo.class);
+ Collection<BaseColumnInfo> expectedBaseCols = Arrays.asList(baseCol1,
baseCol2);
+
+ // Use reflection to access private method
+ Method method =
CreateHiveProcess.class.getDeclaredMethod("getBaseCols", Dependency.class);
+ method.setAccessible(true);
+
+ // Since we can't easily mock the reflection, let's just test that it
doesn't crash
+ Collection<BaseColumnInfo> result = (Collection<BaseColumnInfo>)
method.invoke(createHiveProcess, mockDependency);
+
+ AssertJUnit.assertNotNull("Result should not be null", result);
+ // Result will be empty because the mock doesn't have the actual
getBaseCols method
+ assertTrue("Result should be empty for mock dependency",
result.isEmpty());
+ }
+
+ @Test
+ public void testGetBaseCols_NonCollectionReturn() throws Exception {
+ CreateHiveProcess createHiveProcess = new CreateHiveProcess(context);
+
+ // Test with a dependency that would return non-Collection type
+ Dependency mockDependency = mock(Dependency.class);
+
+ // Use reflection to access private method
+ Method method =
CreateHiveProcess.class.getDeclaredMethod("getBaseCols", Dependency.class);
+ method.setAccessible(true);
+
+ Collection<BaseColumnInfo> result = (Collection<BaseColumnInfo>)
method.invoke(createHiveProcess, mockDependency);
+
+ AssertJUnit.assertNotNull("Result should not be null", result);
+ assertTrue("Result should be empty due to reflection limitations",
result.isEmpty());
+ }
+
+ private static Object invokePrivate(Object target, String methodName,
Class<?>[] paramTypes, Object... args) throws Exception {
+ // Get the method from the original class, not the spy class
+ Method m = CreateHiveProcess.class.getDeclaredMethod(methodName,
paramTypes);
+ m.setAccessible(true);
+ return m.invoke(target, args);
+ }
+
+ @SuppressWarnings("unchecked")
+ @Test
+ public void testProcessColumnLineage_WithValidLineageInfo() throws
Exception {
+ CreateHiveProcess createHiveProcess = spy(new
CreateHiveProcess(context));
+
+ Set<WriteEntity> outputs = Collections.singleton(writeEntity);
+ doReturn(Collections.emptySet()).when(createHiveProcess).getInputs();
+ doReturn(outputs).when(createHiveProcess).getOutputs();
+
+ // Call skipProcess via reflection to assert its result instead of
stubbing
+ assertFalse((boolean) invokePrivate(createHiveProcess, "skipProcess",
new Class<?>[]{}));
+
+
doReturn("default.output_table@cluster").when(createHiveProcess).getQualifiedName(writeEntity);
+
+ AtlasEntity outputEntity = new AtlasEntity("hive_table");
+
doReturn(outputEntity).when(createHiveProcess).getInputOutputEntity(eq(writeEntity),
any(), anyBoolean());
+
+ // Call isDdlOperation via reflection instead of stubbing
+ assertFalse((boolean) invokePrivate(createHiveProcess,
"isDdlOperation", new Class<?>[]{AtlasEntity.class}, outputEntity));
+
+
when(writeEntity.getType()).thenReturn(org.apache.hadoop.hive.ql.hooks.Entity.Type.TABLE);
+
+ when(context.isMetastoreHook()).thenReturn(false);
+ when(context.isSkippedInputEntity()).thenReturn(false);
+ when(context.isSkippedOutputEntity()).thenReturn(false);
+
+ AtlasEntity processEntity = new AtlasEntity("hive_process");
+ processEntity.setAttribute("qualifiedName", "test_process@cluster");
+
doReturn(processEntity).when(createHiveProcess).getHiveProcessEntity(anyList(),
anyList());
+
+ AtlasEntity processExecutionEntity = new
AtlasEntity("hive_process_execution");
+
doReturn(processExecutionEntity).when(createHiveProcess).getHiveProcessExecutionEntity(processEntity);
+
+ doReturn("test_user").when(createHiveProcess).getUserName();
+ doReturn("query_123").when(createHiveProcess).getQueryId();
+ doReturn("SELECT * FROM
table").when(createHiveProcess).getQueryString();
+ doReturn(System.currentTimeMillis() -
5000).when(createHiveProcess).getQueryStartTime();
+ when(context.getHostName()).thenReturn("test_host");
+
+ LineageInfo lineageInfo = mock(LineageInfo.class);
+ DependencyKey depKey = mock(DependencyKey.class);
+ Dependency dependency = mock(Dependency.class);
+ BaseColumnInfo baseColInfo = mock(BaseColumnInfo.class);
+
+ Map<DependencyKey, Dependency> lineageMap = new HashMap<>();
+ lineageMap.put(depKey, dependency);
+ when(lineageInfo.entrySet()).thenReturn(lineageMap.entrySet());
+
+
doReturn("default.output_table.col1@cluster").when(createHiveProcess).getQualifiedName(depKey);
+
doReturn("default.input_table.col1@cluster").when(createHiveProcess).getQualifiedName(baseColInfo);
+
+ // Instead of stubbing getBaseCols (private), set up reflection check
+ Collection<BaseColumnInfo> baseCols = Arrays.asList(baseColInfo);
+ // call: (Collection<BaseColumnInfo>) invokePrivate(createHiveProcess,
"getBaseCols", new Class<?>[]{Dependency.class}, dependency)
+ // For actual testing, you might need to restructure code so
getBaseCols isn't private.
+
+
when(dependency.getType()).thenReturn(LineageInfo.DependencyType.SIMPLE);
+ when(dependency.getExpr()).thenReturn("col1");
+
+ AtlasEntity outputColumn = new AtlasEntity("hive_column");
+ outputColumn.setAttribute("name", "col1");
+ outputColumn.setAttribute("qualifiedName",
"default.output_table.col1@cluster");
+
+ AtlasEntity inputColumn = new AtlasEntity("hive_column");
+ inputColumn.setAttribute("name", "col1");
+ inputColumn.setAttribute("qualifiedName",
"default.input_table.col1@cluster");
+
+
when(context.getEntity("default.output_table.col1@cluster")).thenReturn(outputColumn);
+
when(context.getEntity("default.input_table.col1@cluster")).thenReturn(inputColumn);
+
+ when(context.getSkipHiveColumnLineageHive20633()).thenReturn(false);
+
+ doReturn(lineageInfo).when(createHiveProcess).getLineageInfo();
+ doNothing().when(createHiveProcess).addProcessedEntities(any());
+
+ AtlasEntitiesWithExtInfo entities = createHiveProcess.getEntities();
+
+ assertNotNull("Entities should not be null", entities);
+// assertTrue("Should contain column lineage entities",
+// entities.getEntities().stream()
+// .anyMatch(entity ->
entity.getTypeName().contains("column_lineage")));
+ }
+
+
+ @Test
+ public void testProcessColumnLineage_NonExistentOutputColumn() throws
Exception {
+ CreateHiveProcess createHiveProcess = spy(new
CreateHiveProcess(context));
+
+ // Use reflection to ensure skipProcess() returns false
+ Method skipProcessMethod =
CreateHiveProcess.class.getDeclaredMethod("skipProcess");
+ skipProcessMethod.setAccessible(true);
+ // Here you don't actually change the method — but you can test its
return
+ // Or if you want to bypass logic, you'll have to structure inputs so
skipProcess naturally returns false.
+
+ // Prepare inputs/outputs
+ Set<WriteEntity> outputs = Collections.singleton(writeEntity);
+ doReturn(Collections.emptySet()).when(createHiveProcess).getInputs();
+ doReturn(outputs).when(createHiveProcess).getOutputs();
+
+
doReturn("default.output_table@cluster").when(createHiveProcess).getQualifiedName(writeEntity);
+
+ AtlasEntity outputEntity = new AtlasEntity("hive_table");
+
+ // Call private isDdlOperation(AtlasEntity) via reflection
+ Method isDdlOperationMethod =
CreateHiveProcess.class.getDeclaredMethod("isDdlOperation", AtlasEntity.class);
+ isDdlOperationMethod.setAccessible(true);
+ boolean isDdl = (boolean)
isDdlOperationMethod.invoke(createHiveProcess, outputEntity);
+ AssertJUnit.assertFalse("Expected isDdlOperation to return false",
isDdl);
+
+
doReturn(outputEntity).when(createHiveProcess).getInputOutputEntity(eq(writeEntity),
any(), anyBoolean());
+
when(writeEntity.getType()).thenReturn(org.apache.hadoop.hive.ql.hooks.Entity.Type.TABLE);
+
+ when(context.isMetastoreHook()).thenReturn(false);
+ when(context.isSkippedInputEntity()).thenReturn(false);
+ when(context.isSkippedOutputEntity()).thenReturn(false);
+
+ AtlasEntity processEntity = new AtlasEntity("hive_process");
+ processEntity.setAttribute("qualifiedName", "test_process@cluster");
+
doReturn(processEntity).when(createHiveProcess).getHiveProcessEntity(anyList(),
anyList());
+
+ AtlasEntity processExecutionEntity = new
AtlasEntity("hive_process_execution");
+
doReturn(processExecutionEntity).when(createHiveProcess).getHiveProcessExecutionEntity(processEntity);
+
+ // Mock methods needed for process execution
+ doReturn("test_user").when(createHiveProcess).getUserName();
+ doReturn("query_123").when(createHiveProcess).getQueryId();
+ doReturn("SELECT * FROM
table").when(createHiveProcess).getQueryString();
+ doReturn(System.currentTimeMillis() -
5000).when(createHiveProcess).getQueryStartTime();
+ when(context.getHostName()).thenReturn("test_host");
+
+ // Create mock lineage info with dependencies
+ LineageInfo lineageInfo = mock(LineageInfo.class);
+ DependencyKey depKey = mock(DependencyKey.class);
+ Dependency dependency = mock(Dependency.class);
+
+ Map<DependencyKey, Dependency> lineageMap = new HashMap<>();
+ lineageMap.put(depKey, dependency);
+ when(lineageInfo.entrySet()).thenReturn(lineageMap.entrySet());
+
+
doReturn("default.output_table.non_existent_col@cluster").when(createHiveProcess).getQualifiedName(depKey);
+
+ // Mock context.getEntity to return null for non-existent column
+
when(context.getEntity("default.output_table.non_existent_col@cluster")).thenReturn(null);
+
+ doReturn(lineageInfo).when(createHiveProcess).getLineageInfo();
+ doNothing().when(createHiveProcess).addProcessedEntities(any());
+
+ AtlasEntitiesWithExtInfo entities = createHiveProcess.getEntities();
+
+ AssertJUnit.assertNotNull("Entities should not be null", entities);
+ boolean hasColumnLineage = entities.getEntities().stream()
+ .anyMatch(entity ->
entity.getTypeName().contains("column_lineage"));
+ assertFalse("Should not contain column lineage entities due to
non-existent output column", hasColumnLineage);
+ }
+
+
+ @Test
+ public void testProcessColumnLineage_SkipDueToThreshold() throws Exception
{
+ // Mock common Hive context stuff
+ when(context.isMetastoreHook()).thenReturn(false);
+ when(context.isSkippedInputEntity()).thenReturn(false);
+ when(context.isSkippedOutputEntity()).thenReturn(false);
+
when(writeEntity.getType()).thenReturn(org.apache.hadoop.hive.ql.hooks.Entity.Type.TABLE);
+ when(context.getHostName()).thenReturn("test_host");
+
+ // Create mock lineage objects
+ BaseColumnInfo baseColInfo1 = mock(BaseColumnInfo.class);
+ BaseColumnInfo baseColInfo2 = mock(BaseColumnInfo.class);
+ BaseColumnInfo baseColInfo3 = mock(BaseColumnInfo.class);
+ DependencyKey depKey = mock(DependencyKey.class);
+ Dependency dependency = mock(Dependency.class);
+
+ // Use spy instead of anonymous subclass
+ CreateHiveProcess createHiveProcess = spy(new
CreateHiveProcess(context));
+
+ // Create mock dependency with getBaseCols method
+ Dependency testDependency = mock(Dependency.class);
+
when(testDependency.getType()).thenReturn(LineageInfo.DependencyType.SIMPLE);
+ when(testDependency.getExpr()).thenReturn("col1 + col2 + col3");
+ // Add getBaseCols method to the mock
+ doReturn(new HashSet<>(Arrays.asList(baseColInfo1, baseColInfo2,
baseColInfo3))).when(testDependency).getBaseCols();
+
+ // Outputs and inputs
+ Set<WriteEntity> outputs = Collections.singleton(writeEntity);
+ doReturn(Collections.emptySet()).when(createHiveProcess).getInputs();
+ doReturn(outputs).when(createHiveProcess).getOutputs();
+
doReturn("default.output_table@cluster").when(createHiveProcess).getQualifiedName(writeEntity);
+
+ AtlasEntity outputEntity = new AtlasEntity("hive_table");
+
doReturn(outputEntity).when(createHiveProcess).getInputOutputEntity(eq(writeEntity),
any(), anyBoolean());
+
+ // Mock Hive process entities
+ AtlasEntity processEntity = new AtlasEntity("hive_process");
+ processEntity.setAttribute("qualifiedName", "test_process@cluster");
+
doReturn(processEntity).when(createHiveProcess).getHiveProcessEntity(anyList(),
anyList());
+
+ AtlasEntity processExecutionEntity = new
AtlasEntity("hive_process_execution");
+
doReturn(processExecutionEntity).when(createHiveProcess).getHiveProcessExecutionEntity(processEntity);
+
+ // Mock user/query info
+ doReturn("test_user").when(createHiveProcess).getUserName();
+ doReturn("query_123").when(createHiveProcess).getQueryId();
+ doReturn("SELECT * FROM
table").when(createHiveProcess).getQueryString();
+ doReturn(System.currentTimeMillis() -
5000).when(createHiveProcess).getQueryStartTime();
+
+ // Setup LineageInfo with concrete dependency
+ LineageInfo lineageInfo = mock(LineageInfo.class);
+ Map<DependencyKey, Dependency> lineageMap = new HashMap<>();
+ lineageMap.put(depKey, testDependency);
+ when(lineageInfo.entrySet()).thenReturn(lineageMap.entrySet());
+
+
doReturn("default.output_table.col1@cluster").when(createHiveProcess).getQualifiedName(depKey);
+
doReturn("default.input_table.col1@cluster").when(createHiveProcess).getQualifiedName(baseColInfo1);
+
doReturn("default.input_table.col2@cluster").when(createHiveProcess).getQualifiedName(baseColInfo2);
+
doReturn("default.input_table.col3@cluster").when(createHiveProcess).getQualifiedName(baseColInfo3);
+
+ // Mock context entities for columns
+ AtlasEntity outputColumn = new AtlasEntity("hive_column");
+ outputColumn.setAttribute("name", "col1");
+ outputColumn.setAttribute("qualifiedName",
"default.output_table.col1@cluster");
+
+ AtlasEntity inputColumn1 = new AtlasEntity("hive_column");
+ AtlasEntity inputColumn2 = new AtlasEntity("hive_column");
+ AtlasEntity inputColumn3 = new AtlasEntity("hive_column");
+
+
when(context.getEntity("default.output_table.col1@cluster")).thenReturn(outputColumn);
+
when(context.getEntity("default.input_table.col1@cluster")).thenReturn(inputColumn1);
+
when(context.getEntity("default.input_table.col2@cluster")).thenReturn(inputColumn2);
+
when(context.getEntity("default.input_table.col3@cluster")).thenReturn(inputColumn3);
+
+ // Skip column lineage threshold settings
+ when(context.getSkipHiveColumnLineageHive20633()).thenReturn(true);
+
when(context.getSkipHiveColumnLineageHive20633InputsThreshold()).thenReturn(2);
// lower than actual cols
+
+ doReturn(lineageInfo).when(createHiveProcess).getLineageInfo();
+ doNothing().when(createHiveProcess).addProcessedEntities(any());
+
+ // Execute
+ AtlasEntitiesWithExtInfo entities = createHiveProcess.getEntities();
+
+ AssertJUnit.assertNotNull("Entities should not be null", entities);
+ boolean hasColumnLineage = entities.getEntities().stream()
+ .anyMatch(entity ->
entity.getTypeName().contains("column_lineage"));
+ assertFalse("Should not contain column lineage entities due to
threshold", hasColumnLineage);
+ }
+
+
+ @Test
+ public void testProcessColumnLineage_DuplicateOutputColumn() throws
Exception {
+ CreateHiveProcess createHiveProcess = spy(new
CreateHiveProcess(context));
+
+ // Prepare reflection for private methods
+ Method skipProcessMethod =
CreateHiveProcess.class.getDeclaredMethod("skipProcess");
+ skipProcessMethod.setAccessible(true);
+
+ Method isDdlOperationMethod =
CreateHiveProcess.class.getDeclaredMethod("isDdlOperation", AtlasEntity.class);
+ isDdlOperationMethod.setAccessible(true);
+
+ Method getBaseColsMethod =
CreateHiveProcess.class.getDeclaredMethod("getBaseCols",
LineageInfo.Dependency.class);
+ getBaseColsMethod.setAccessible(true);
+
+ // ---- Setup for test ----
+ // We want skipProcess() to return false (no skip)
+// assertFalse((boolean) skipProcessMethod.invoke(createHiveProcess));
+
+ Set<WriteEntity> outputs = Collections.singleton(writeEntity);
+ doReturn(Collections.emptySet()).when(createHiveProcess).getInputs();
+ doReturn(outputs).when(createHiveProcess).getOutputs();
+
+
doReturn("default.output_table@cluster").when(createHiveProcess).getQualifiedName(writeEntity);
+
+ AtlasEntity outputEntity = new AtlasEntity("hive_table");
+
doReturn(outputEntity).when(createHiveProcess).getInputOutputEntity(eq(writeEntity),
any(), anyBoolean());
+
+ // We want isDdlOperation(outputEntity) to return false
+ assertFalse((boolean) isDdlOperationMethod.invoke(createHiveProcess,
outputEntity));
+
+
when(writeEntity.getType()).thenReturn(org.apache.hadoop.hive.ql.hooks.Entity.Type.TABLE);
+ when(context.isMetastoreHook()).thenReturn(false);
+ when(context.isSkippedInputEntity()).thenReturn(false);
+ when(context.isSkippedOutputEntity()).thenReturn(false);
+
+ AtlasEntity processEntity = new AtlasEntity("hive_process");
+ processEntity.setAttribute("qualifiedName", "test_process@cluster");
+
doReturn(processEntity).when(createHiveProcess).getHiveProcessEntity(anyList(),
anyList());
+
+ AtlasEntity processExecutionEntity = new
AtlasEntity("hive_process_execution");
+
doReturn(processExecutionEntity).when(createHiveProcess).getHiveProcessExecutionEntity(processEntity);
+
+ // Mock methods needed for process execution
+ doReturn("test_user").when(createHiveProcess).getUserName();
+ doReturn("query_123").when(createHiveProcess).getQueryId();
+ doReturn("SELECT * FROM
table").when(createHiveProcess).getQueryString();
+ doReturn(System.currentTimeMillis() -
5000).when(createHiveProcess).getQueryStartTime();
+ when(context.getHostName()).thenReturn("test_host");
+
+ // Create mock lineage info with duplicate dependencies
+ LineageInfo lineageInfo = mock(LineageInfo.class);
+ DependencyKey depKey1 = mock(DependencyKey.class);
+ DependencyKey depKey2 = mock(DependencyKey.class);
+ Dependency dependency1 = mock(Dependency.class);
+ Dependency dependency2 = mock(Dependency.class);
+ BaseColumnInfo baseColInfo = mock(BaseColumnInfo.class);
+
+ Map<DependencyKey, Dependency> lineageMap = new LinkedHashMap<>();
+ lineageMap.put(depKey1, dependency1);
+ lineageMap.put(depKey2, dependency2); // Duplicate output column
+ when(lineageInfo.entrySet()).thenReturn(lineageMap.entrySet());
+
+ String outputColName = "default.output_table.col1@cluster";
+
doReturn(outputColName).when(createHiveProcess).getQualifiedName(depKey1);
+
doReturn(outputColName).when(createHiveProcess).getQualifiedName(depKey2);
+
doReturn("default.input_table.col1@cluster").when(createHiveProcess).getQualifiedName(baseColInfo);
+
+ // Mock getBaseCols method for both dependencies
+ doReturn(new
HashSet<>(Arrays.asList(baseColInfo))).when(dependency1).getBaseCols();
+ doReturn(new
HashSet<>(Arrays.asList(baseColInfo))).when(dependency2).getBaseCols();
+
+
when(dependency1.getType()).thenReturn(LineageInfo.DependencyType.SIMPLE);
+ when(dependency1.getExpr()).thenReturn("col1");
+
when(dependency2.getType()).thenReturn(LineageInfo.DependencyType.SIMPLE);
+ when(dependency2.getExpr()).thenReturn("col1");
+
+ // Mock context.getEntity for columns
+ AtlasEntity outputColumn = new AtlasEntity("hive_column");
+ outputColumn.setAttribute("name", "col1");
+ outputColumn.setAttribute("qualifiedName", outputColName);
+
+ AtlasEntity inputColumn = new AtlasEntity("hive_column");
+ inputColumn.setAttribute("name", "col1");
+ inputColumn.setAttribute("qualifiedName",
"default.input_table.col1@cluster");
+
+ when(context.getEntity(outputColName)).thenReturn(outputColumn);
+
when(context.getEntity("default.input_table.col1@cluster")).thenReturn(inputColumn);
+
+ when(context.getSkipHiveColumnLineageHive20633()).thenReturn(false);
+
+ doReturn(lineageInfo).when(createHiveProcess).getLineageInfo();
+ doNothing().when(createHiveProcess).addProcessedEntities(any());
+
+ // ---- Execute & Verify ----
+ AtlasEntitiesWithExtInfo entities = createHiveProcess.getEntities();
+ assertNotNull("Entities should not be null", entities);
+
+ long columnLineageCount = entities.getEntities().stream()
+ .filter(entity ->
entity.getTypeName().contains("column_lineage"))
+ .count();
+ assertEquals("Should contain only one column lineage entity due to
duplicate handling", 1, columnLineageCount);
+ }
+
+
+
+
+ @Test
+ public void testProcessColumnLineage_EmptyInputColumns() throws Exception {
+ CreateHiveProcess createHiveProcess = spy(new
CreateHiveProcess(context));
+
+ // Prepare reflection for private methods
+ Method skipProcessMethod =
CreateHiveProcess.class.getDeclaredMethod("skipProcess");
+ skipProcessMethod.setAccessible(true);
+
+ Method isDdlOperationMethod =
CreateHiveProcess.class.getDeclaredMethod("isDdlOperation", AtlasEntity.class);
+ isDdlOperationMethod.setAccessible(true);
+
+ Method getBaseColsMethod =
CreateHiveProcess.class.getDeclaredMethod("getBaseCols",
LineageInfo.Dependency.class);
+ getBaseColsMethod.setAccessible(true);
+
+ // ---- Test scenario where input columns list is empty ----
+ // Call skipProcess() to ensure no skip (false)
+// assertFalse((boolean) skipProcessMethod.invoke(createHiveProcess));
+
+ Set<WriteEntity> outputs = Collections.singleton(writeEntity);
+ doReturn(Collections.emptySet()).when(createHiveProcess).getInputs();
+ doReturn(outputs).when(createHiveProcess).getOutputs();
+
+
doReturn("default.output_table@cluster").when(createHiveProcess).getQualifiedName(writeEntity);
+
+ AtlasEntity outputEntity = new AtlasEntity("hive_table");
+ doReturn(outputEntity).when(createHiveProcess)
+ .getInputOutputEntity(eq(writeEntity), any(), anyBoolean());
+
+ // Call isDdlOperation(outputEntity) to ensure it's false
+ assertFalse((boolean) isDdlOperationMethod.invoke(createHiveProcess,
outputEntity));
+
+
when(writeEntity.getType()).thenReturn(org.apache.hadoop.hive.ql.hooks.Entity.Type.TABLE);
+
+ when(context.isMetastoreHook()).thenReturn(false);
+ when(context.isSkippedInputEntity()).thenReturn(false);
+ when(context.isSkippedOutputEntity()).thenReturn(false);
+
+ AtlasEntity processEntity = new AtlasEntity("hive_process");
+ processEntity.setAttribute("qualifiedName", "test_process@cluster");
+
doReturn(processEntity).when(createHiveProcess).getHiveProcessEntity(anyList(),
anyList());
+
+ AtlasEntity processExecutionEntity = new
AtlasEntity("hive_process_execution");
+
doReturn(processExecutionEntity).when(createHiveProcess).getHiveProcessExecutionEntity(processEntity);
+
+ // Mock methods needed for process execution
+ doReturn("test_user").when(createHiveProcess).getUserName();
+ doReturn("query_123").when(createHiveProcess).getQueryId();
+ doReturn("SELECT * FROM
table").when(createHiveProcess).getQueryString();
+ doReturn(System.currentTimeMillis() -
5000).when(createHiveProcess).getQueryStartTime();
+ when(context.getHostName()).thenReturn("test_host");
+
+ // Create mock lineage info with dependencies
+ LineageInfo lineageInfo = mock(LineageInfo.class);
+ DependencyKey depKey = mock(DependencyKey.class);
+ Dependency dependency = mock(Dependency.class);
+ BaseColumnInfo baseColInfo = mock(BaseColumnInfo.class);
+
+ Map<DependencyKey, Dependency> lineageMap = new HashMap<>();
+ lineageMap.put(depKey, dependency);
+ when(lineageInfo.entrySet()).thenReturn(lineageMap.entrySet());
+
+
doReturn("default.output_table.col1@cluster").when(createHiveProcess).getQualifiedName(depKey);
+
doReturn("default.input_table.non_existent_col@cluster").when(createHiveProcess).getQualifiedName(baseColInfo);
+
+ // Call getBaseCols(dependency) via reflection (instead of mocking)
+ @SuppressWarnings("unchecked")
+ Collection<BaseColumnInfo> baseCols = (Collection<BaseColumnInfo>)
+ getBaseColsMethod.invoke(createHiveProcess, dependency);
+
+ // We still need a predictable baseCols here for the test scenario:
+ // Force baseCols to return the mocked BaseColumnInfo even though real
method runs
+ baseCols = Arrays.asList(baseColInfo);
+
+ // Mock context.getEntity for columns
+ AtlasEntity outputColumn = new AtlasEntity("hive_column");
+ outputColumn.setAttribute("name", "col1");
+ outputColumn.setAttribute("qualifiedName",
"default.output_table.col1@cluster");
+
+
when(context.getEntity("default.output_table.col1@cluster")).thenReturn(outputColumn);
+
when(context.getEntity("default.input_table.non_existent_col@cluster")).thenReturn(null);
+
+ // Mock skip column lineage settings
+ when(context.getSkipHiveColumnLineageHive20633()).thenReturn(false);
+
+ doReturn(lineageInfo).when(createHiveProcess).getLineageInfo();
+ doNothing().when(createHiveProcess).addProcessedEntities(any());
+
+ // ---- Execute & Verify ----
+ AtlasEntitiesWithExtInfo entities = createHiveProcess.getEntities();
+
+ assertNotNull("Entities should not be null", entities);
+ boolean hasColumnLineage = entities.getEntities().stream()
+ .anyMatch(entity ->
entity.getTypeName().contains("column_lineage"));
+ assertFalse("Should not contain column lineage entities due to empty
input columns", hasColumnLineage);
+ }
+
+
+ // ========== INTEGRATION TESTS ==========
+
+ @Test
+ public void testFullWorkflow_SimpleProcess() throws Exception {
+ CreateHiveProcess createHiveProcess = spy(new
CreateHiveProcess(context));
+
+ // --- Reflection for private methods ---
+ Method skipProcessMethod =
CreateHiveProcess.class.getDeclaredMethod("skipProcess");
+ skipProcessMethod.setAccessible(true);
+
+ Method isDdlOperationMethod =
CreateHiveProcess.class.getDeclaredMethod(
+ "isDdlOperation", AtlasEntity.class
+ );
+ isDdlOperationMethod.setAccessible(true);
+
+ Method processColumnLineageMethod =
CreateHiveProcess.class.getDeclaredMethod(
+ "processColumnLineage", AtlasEntity.class,
AtlasEntitiesWithExtInfo.class
+ );
+ processColumnLineageMethod.setAccessible(true);
+
+ // --- Mock inputs and outputs ---
+ Set<ReadEntity> inputs = Collections.singleton(readEntity);
+ Set<WriteEntity> outputs = Collections.singleton(writeEntity);
+ doReturn(inputs).when(createHiveProcess).getInputs();
+ doReturn(outputs).when(createHiveProcess).getOutputs();
+
+ // Mock getQualifiedName
+
doReturn("default.input_table@cluster").when(createHiveProcess).getQualifiedName(readEntity);
+
doReturn("default.output_table@cluster").when(createHiveProcess).getQualifiedName(writeEntity);
+
+ // Mock getInputOutputEntity
+ AtlasEntity inputEntity = new AtlasEntity("hive_table");
+ inputEntity.setAttribute("qualifiedName",
"default.input_table@cluster");
+ AtlasEntity outputEntity = new AtlasEntity("hive_table");
+ outputEntity.setAttribute("qualifiedName",
"default.output_table@cluster");
+
doReturn(inputEntity).when(createHiveProcess).getInputOutputEntity(eq(readEntity),
any(), anyBoolean());
+
doReturn(outputEntity).when(createHiveProcess).getInputOutputEntity(eq(writeEntity),
any(), anyBoolean());
+
+ // Use reflection to assert isDdlOperation == false
+ boolean ddl = (boolean) isDdlOperationMethod.invoke(createHiveProcess,
outputEntity);
+ AssertJUnit.assertFalse("isDdlOperation should be false", ddl);
+
+ // Mock entity types
+
when(readEntity.getType()).thenReturn(org.apache.hadoop.hive.ql.hooks.Entity.Type.TABLE);
+
when(writeEntity.getType()).thenReturn(org.apache.hadoop.hive.ql.hooks.Entity.Type.TABLE);
+
+ // Mock isDirect
+ when(readEntity.isDirect()).thenReturn(true);
+
+ // Mock context methods
+ when(context.isSkippedInputEntity()).thenReturn(false);
+ when(context.isSkippedOutputEntity()).thenReturn(false);
+ when(context.isMetastoreHook()).thenReturn(false);
+
+ // Mock process creation
+ AtlasEntity processEntity = new AtlasEntity("hive_process");
+ processEntity.setAttribute("qualifiedName", "test_process@cluster");
+
doReturn(processEntity).when(createHiveProcess).getHiveProcessEntity(anyList(),
anyList());
+
+ AtlasEntity processExecutionEntity = new
AtlasEntity("hive_process_execution");
+
doReturn(processExecutionEntity).when(createHiveProcess).getHiveProcessExecutionEntity(processEntity);
+
+ // Mock methods needed by getHiveProcessExecutionEntity
+ doReturn("test_user").when(createHiveProcess).getUserName();
+ doReturn("query_123").when(createHiveProcess).getQueryId();
+ doReturn("SELECT * FROM
table").when(createHiveProcess).getQueryString();
+ doReturn(System.currentTimeMillis() -
5000).when(createHiveProcess).getQueryStartTime();
+ when(context.getHostName()).thenReturn("test_host");
+
+ // Instead of mocking processColumnLineage, just call it via reflection
+ AtlasEntitiesWithExtInfo entities = new AtlasEntitiesWithExtInfo();
+ processColumnLineageMethod.invoke(createHiveProcess, processEntity,
entities);
+
+ // Also test skipProcess via reflection
+ boolean skip = (boolean) skipProcessMethod.invoke(createHiveProcess);
+ AssertJUnit.assertFalse("skipProcess should be false", skip);
+
+ // Execute workflow
+ List<HookNotification> notifications =
createHiveProcess.getNotificationMessages();
+
+ // Verify results
+ AssertJUnit.assertNotNull("Notifications should not be null",
notifications);
+ AssertJUnit.assertEquals("Should have one notification", 1,
notifications.size());
+ assertTrue("Should be EntityCreateRequestV2",
+ notifications.get(0) instanceof EntityCreateRequestV2);
+
+ EntityCreateRequestV2 createRequest = (EntityCreateRequestV2)
notifications.get(0);
+ AssertJUnit.assertEquals("User should be test_user", "test_user",
createRequest.getUser());
+ AssertJUnit.assertNotNull("Entities should not be null",
createRequest.getEntities());
+ assertTrue("Should contain entities",
+ createRequest.getEntities().getEntities().size() > 0);
+ }
+
+
+
+ // ========== ADDITIONAL COVERAGE TESTS ==========
+
+ @Test
+ public void testGetEntities_WithNonDirectInput() throws Exception {
+ CreateHiveProcess createHiveProcess = spy(new
CreateHiveProcess(context));
+
+ // --- Reflection access to private methods ---
+ Method skipProcessMethod =
CreateHiveProcess.class.getDeclaredMethod("skipProcess");
+ skipProcessMethod.setAccessible(true);
+
+ Method isDdlOperationMethod =
CreateHiveProcess.class.getDeclaredMethod(
+ "isDdlOperation", AtlasEntity.class
+ );
+ isDdlOperationMethod.setAccessible(true);
+
+ Method processColumnLineageMethod =
CreateHiveProcess.class.getDeclaredMethod(
+ "processColumnLineage", AtlasEntity.class,
AtlasEntitiesWithExtInfo.class
+ );
+ processColumnLineageMethod.setAccessible(true);
+
+ // --- Mock inputs and outputs ---
+ Set<ReadEntity> inputs = Collections.singleton(readEntity);
+ Set<WriteEntity> outputs = Collections.singleton(writeEntity);
+ doReturn(inputs).when(createHiveProcess).getInputs();
+ doReturn(outputs).when(createHiveProcess).getOutputs();
+
+ // Mock getQualifiedName
+
doReturn("default.input_table@cluster").when(createHiveProcess).getQualifiedName(readEntity);
+
doReturn("default.output_table@cluster").when(createHiveProcess).getQualifiedName(writeEntity);
+
+ // Mock getInputOutputEntity
+ AtlasEntity inputEntity = new AtlasEntity("hive_table");
+ AtlasEntity outputEntity = new AtlasEntity("hive_table");
+
doReturn(inputEntity).when(createHiveProcess).getInputOutputEntity(eq(readEntity),
any(), anyBoolean());
+
doReturn(outputEntity).when(createHiveProcess).getInputOutputEntity(eq(writeEntity),
any(), anyBoolean());
+
+ // --- Directly verify private methods before execution ---
+ boolean skip = (boolean) skipProcessMethod.invoke(createHiveProcess);
+ AssertJUnit.assertFalse("skipProcess should return false", skip);
+
+ boolean ddl = (boolean) isDdlOperationMethod.invoke(createHiveProcess,
outputEntity);
+ AssertJUnit.assertFalse("isDdlOperation should return false", ddl);
+
+ // Mock entity types to avoid switch NPE
+
when(readEntity.getType()).thenReturn(org.apache.hadoop.hive.ql.hooks.Entity.Type.TABLE);
+
when(writeEntity.getType()).thenReturn(org.apache.hadoop.hive.ql.hooks.Entity.Type.TABLE);
+
+ // isDirect = false means input should be excluded
+ when(readEntity.isDirect()).thenReturn(false);
+
+ // Mock context methods
+ when(context.isSkippedInputEntity()).thenReturn(false);
+ when(context.isSkippedOutputEntity()).thenReturn(false);
+ when(context.isMetastoreHook()).thenReturn(false);
+
+ // Mock process creation
+ AtlasEntity processEntity = new AtlasEntity("hive_process");
+ processEntity.setAttribute("qualifiedName", "test_process@cluster");
+
doReturn(processEntity).when(createHiveProcess).getHiveProcessEntity(anyList(),
anyList());
+
+ AtlasEntity processExecutionEntity = new
AtlasEntity("hive_process_execution");
+
doReturn(processExecutionEntity).when(createHiveProcess).getHiveProcessExecutionEntity(processEntity);
+
+ // Mock other helper methods for process creation
+ doReturn("test_user").when(createHiveProcess).getUserName();
+ doReturn("query_123").when(createHiveProcess).getQueryId();
+ doReturn("SELECT * FROM
table").when(createHiveProcess).getQueryString();
+ doReturn(System.currentTimeMillis() -
5000).when(createHiveProcess).getQueryStartTime();
+ when(context.getHostName()).thenReturn("test_host");
+
+ // Instead of mocking processColumnLineage, just call it via reflection
+ AtlasEntitiesWithExtInfo entitiesForReflection = new
AtlasEntitiesWithExtInfo();
+ processColumnLineageMethod.invoke(createHiveProcess, processEntity,
entitiesForReflection);
+
+ // We still mock addProcessedEntities (not private)
+ doNothing().when(createHiveProcess).addProcessedEntities(any());
+
+ // Execute
+ AtlasEntitiesWithExtInfo entities = createHiveProcess.getEntities();
+
+ AssertJUnit.assertNotNull("Entities should not be null", entities);
+ // Should still create process with output but no inputs due to
isDirect=false
+ }
+
+
+ @Test
+ public void testGetEntities_NullQualifiedName() throws Exception {
+ CreateHiveProcess createHiveProcess = spy(new
CreateHiveProcess(context));
+
+ // --- Reflection for skipProcess() ---
+ Method skipProcessMethod =
CreateHiveProcess.class.getDeclaredMethod("skipProcess");
+ skipProcessMethod.setAccessible(true);
+
+ // Call skipProcess() and assert expected
+ boolean skip = (boolean) skipProcessMethod.invoke(createHiveProcess);
+ AssertJUnit.assertTrue("skipProcess should return true for empty
inputs/outputs", skip);
+
+ // --- Mock inputs and outputs ---
+ Set<ReadEntity> inputs = Collections.singleton(readEntity);
+ Set<WriteEntity> outputs = Collections.singleton(writeEntity);
+ doReturn(inputs).when(createHiveProcess).getInputs();
+ doReturn(outputs).when(createHiveProcess).getOutputs();
+
+ // Mock getQualifiedName to return null (both input and output)
+ doReturn(null).when(createHiveProcess).getQualifiedName(readEntity);
+ doReturn(null).when(createHiveProcess).getQualifiedName(writeEntity);
+
+ // Mock context methods
+ when(context.isSkippedInputEntity()).thenReturn(false);
+ when(context.isSkippedOutputEntity()).thenReturn(false);
+ when(context.isMetastoreHook()).thenReturn(false);
+
+ // Execute
+ AtlasEntitiesWithExtInfo entities = createHiveProcess.getEntities();
+
+ // Assert outcome
+ assertNull("Entities should be null when qualified names are null",
entities);
+ }
+
+ /* @Test
+ public void testGetEntities_SelfLineageScenario() throws Exception {
+ CreateHiveProcess createHiveProcess = spy(new
CreateHiveProcess(context));
+
+ // Mock skipProcess to return false
+ doReturn(false).when(createHiveProcess).skipProcess();
+
+ // Mock inputs and outputs with same qualified name (self lineage)
+ Set<ReadEntity> inputs = Collections.singleton(readEntity);
+ Set<WriteEntity> outputs = Collections.singleton(writeEntity);
+ doReturn(inputs).when(createHiveProcess).getInputs();
+ doReturn(outputs).when(createHiveProcess).getOutputs();
+
+ // Same qualified name for input and output (this triggers the
self-lineage logic)
+ String sameQualifiedName = "default.same_table@cluster";
+
doReturn(sameQualifiedName).when(createHiveProcess).getQualifiedName(readEntity);
+
doReturn(sameQualifiedName).when(createHiveProcess).getQualifiedName(writeEntity);
+
+ // Mock getInputOutputEntity for output - this gets called first
+ AtlasEntity outputEntity = new AtlasEntity("hive_table");
+
doReturn(outputEntity).when(createHiveProcess).getInputOutputEntity(eq(writeEntity),
any(), anyBoolean());
+
+ // Mock isDdlOperation to avoid NPE
+ doReturn(false).when(createHiveProcess).isDdlOperation(outputEntity);
+
+ // Mock entity types to avoid switch statement NPE
+
when(readEntity.getType()).thenReturn(org.apache.hadoop.hive.ql.hooks.Entity.Type.TABLE);
+
when(writeEntity.getType()).thenReturn(org.apache.hadoop.hive.ql.hooks.Entity.Type.TABLE);
+
+ // Mock isDirect
+ when(readEntity.isDirect()).thenReturn(true);
+
+ // Mock context methods
+ when(context.isSkippedInputEntity()).thenReturn(false);
+ when(context.isSkippedOutputEntity()).thenReturn(false);
+ when(context.isMetastoreHook()).thenReturn(false);
+
+ AtlasEntitiesWithExtInfo entities = createHiveProcess.getEntities();
+
+ // The checkIfOnlySelfLineagePossible method should detect this as
self-lineage and skip processing
+ // So we should get null result due to skipProcess logic
+ AssertJUnit.assertNull("Entities should be null for self lineage
scenario", entities);
+ }*/
+
Review Comment:
Large block of commented-out test code should be removed to improve
maintainability.
```suggestion
```
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: [email protected]
For queries about this service, please contact Infrastructure at:
[email protected]