atlas-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From suma...@apache.org
Subject [1/2] incubator-atlas git commit: ATLAS-1547 Add tests for DeleteHandlerV1 (sumasai via mneethiraj)
Date Wed, 15 Feb 2017 00:37:15 GMT
Repository: incubator-atlas
Updated Branches:
  refs/heads/master c7540b38f -> aa67f8aee


http://git-wip-us.apache.org/repos/asf/incubator-atlas/blob/aa67f8ae/repository/src/test/java/org/apache/atlas/repository/store/graph/v1/AtlasDeleteHandlerV1Test.java
----------------------------------------------------------------------
diff --git a/repository/src/test/java/org/apache/atlas/repository/store/graph/v1/AtlasDeleteHandlerV1Test.java b/repository/src/test/java/org/apache/atlas/repository/store/graph/v1/AtlasDeleteHandlerV1Test.java
new file mode 100644
index 0000000..b35d288
--- /dev/null
+++ b/repository/src/test/java/org/apache/atlas/repository/store/graph/v1/AtlasDeleteHandlerV1Test.java
@@ -0,0 +1,791 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ * <p/>
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * <p/>
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.atlas.repository.store.graph.v1;
+
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableSet;
+import org.apache.atlas.AtlasClient;
+import org.apache.atlas.AtlasException;
+import org.apache.atlas.RepositoryMetadataModule;
+import org.apache.atlas.RequestContextV1;
+import org.apache.atlas.TestUtils;
+import org.apache.atlas.TestUtilsV2;
+import org.apache.atlas.model.instance.AtlasEntity;
+import org.apache.atlas.model.instance.AtlasEntityHeader;
+import org.apache.atlas.model.instance.AtlasStruct;
+import org.apache.atlas.model.instance.EntityMutationResponse;
+import org.apache.atlas.model.instance.EntityMutations;
+import org.apache.atlas.model.typedef.AtlasClassificationDef;
+import org.apache.atlas.model.typedef.AtlasEntityDef;
+import org.apache.atlas.model.typedef.AtlasEnumDef;
+import org.apache.atlas.model.typedef.AtlasStructDef;
+import org.apache.atlas.model.typedef.AtlasTypesDef;
+import org.apache.atlas.repository.Constants;
+import org.apache.atlas.repository.graph.AtlasGraphProvider;
+import org.apache.atlas.repository.graph.GraphBackedSearchIndexer;
+import org.apache.atlas.repository.graph.GraphHelper;
+import org.apache.atlas.repository.graphdb.AtlasGraph;
+import org.apache.atlas.repository.graphdb.AtlasVertex;
+import org.apache.atlas.repository.store.graph.AtlasEntityStore;
+import org.apache.atlas.services.MetadataService;
+import org.apache.atlas.store.AtlasTypeDefStore;
+import org.apache.atlas.type.AtlasEntityType;
+import org.apache.atlas.type.AtlasTypeRegistry;
+import org.apache.atlas.type.AtlasTypeUtil;
+import org.apache.atlas.typesystem.IReferenceableInstance;
+import org.apache.atlas.typesystem.IStruct;
+import org.apache.atlas.typesystem.ITypedReferenceableInstance;
+import org.apache.atlas.typesystem.ITypedStruct;
+import org.apache.atlas.typesystem.Struct;
+import org.apache.atlas.typesystem.exception.EntityNotFoundException;
+import org.apache.atlas.typesystem.persistence.Id;
+import org.apache.atlas.typesystem.types.Multiplicity;
+import org.apache.atlas.typesystem.types.TraitType;
+import org.apache.atlas.typesystem.types.TypeSystem;
+import org.apache.atlas.util.AtlasRepositoryConfiguration;
+import org.testng.Assert;
+import org.testng.annotations.AfterClass;
+import org.testng.annotations.BeforeClass;
+import org.testng.annotations.BeforeTest;
+import org.testng.annotations.Guice;
+import org.testng.annotations.Test;
+
+import javax.inject.Inject;
+
+import java.lang.reflect.Constructor;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import static org.apache.atlas.TestUtils.COLUMNS_ATTR_NAME;
+import static org.apache.atlas.TestUtils.COLUMN_TYPE;
+import static org.apache.atlas.TestUtils.DEPARTMENT_TYPE;
+import static org.apache.atlas.TestUtils.NAME;
+import static org.apache.atlas.TestUtils.TABLE_TYPE;
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertNotEquals;
+import static org.testng.Assert.assertTrue;
+import static org.testng.Assert.fail;
+
+@Guice(modules = RepositoryMetadataModule.class)
+public abstract class AtlasDeleteHandlerV1Test {
+
+    @Inject
+    AtlasTypeRegistry typeRegistry;
+
+    @Inject
+    AtlasTypeDefStore typeDefStore;
+
+    AtlasEntityStore entityStore;
+
+    @Inject
+    MetadataService metadataService;
+
+    private AtlasEntityType compositeMapOwnerType;
+
+    private AtlasEntityType compositeMapValueType;
+
+    private TypeSystem typeSystem = TypeSystem.getInstance();
+
+
+    @BeforeClass
+    public void setUp() throws Exception {
+        metadataService = TestUtils.addSessionCleanupWrapper(metadataService);
+        new GraphBackedSearchIndexer(typeRegistry);
+        final AtlasTypesDef deptTypesDef = TestUtilsV2.defineDeptEmployeeTypes();
+        typeDefStore.createTypesDef(deptTypesDef);
+
+        final AtlasTypesDef hiveTypesDef = TestUtilsV2.defineHiveTypes();
+        typeDefStore.createTypesDef(hiveTypesDef);
+
+        // Define type for map value.
+        AtlasEntityDef mapValueDef = AtlasTypeUtil.createClassTypeDef("CompositeMapValue", "CompositeMapValue" + "_description", "1.0",
+            ImmutableSet.<String>of(),
+            AtlasTypeUtil.createUniqueRequiredAttrDef("name", "string")
+        );
+
+        // Define type with map where the value is a composite class reference to MapValue.
+        AtlasEntityDef mapOwnerDef = AtlasTypeUtil.createClassTypeDef("CompositeMapOwner", "CompositeMapOwner_description",
+            ImmutableSet.<String>of(),
+            AtlasTypeUtil.createUniqueRequiredAttrDef("name", "string"),
+            AtlasTypeUtil.createOptionalAttrDef("map", "map<string,string>")
+        );
+
+        final AtlasTypesDef typesDef = AtlasTypeUtil.getTypesDef(ImmutableList.<AtlasEnumDef>of(),
+            ImmutableList.<AtlasStructDef>of(),
+            ImmutableList.<AtlasClassificationDef>of(),
+            ImmutableList.of(mapValueDef, mapOwnerDef));
+
+        typeDefStore.createTypesDef(typesDef);
+
+        compositeMapOwnerType = typeRegistry.getEntityTypeByName("CompositeMapOwner");
+        compositeMapValueType = typeRegistry.getEntityTypeByName("CompositeMapValue");
+    }
+
+    @BeforeTest
+    public void init() throws Exception {
+
+        final Class<? extends DeleteHandlerV1> deleteHandlerImpl = AtlasRepositoryConfiguration.getDeleteHandlerV1Impl();
+        final Constructor<? extends DeleteHandlerV1> deleteHandlerImplConstructor = deleteHandlerImpl.getConstructor(AtlasTypeRegistry.class);
+        DeleteHandlerV1 deleteHandler = deleteHandlerImplConstructor.newInstance(typeRegistry);
+
+        entityStore = new AtlasEntityStoreV1(deleteHandler, typeRegistry);
+        RequestContextV1.clear();
+
+    }
+
+    @AfterClass
+    public void clear() {
+        AtlasGraphProvider.cleanup();
+    }
+
+    abstract DeleteHandlerV1 getDeleteHandler(AtlasTypeRegistry typeRegistry);
+
+    @Test
+    public void testDeleteAndCreate() throws Exception {
+        init();
+        final AtlasEntity dbEntity = TestUtilsV2.createDBEntity();
+        EntityMutationResponse response = entityStore.createOrUpdate(new AtlasEntityStream(dbEntity));
+
+        init();
+        //delete entity should mark it as deleted
+        EntityMutationResponse deleteResponse = entityStore.deleteById(response.getFirstEntityCreated().getGuid());
+        AtlasEntityHeader dbEntityCreated = response.getFirstEntityCreated();
+        assertEquals(deleteResponse.getEntitiesByOperation(EntityMutations.EntityOperation.DELETE).get(0).getGuid(), dbEntityCreated.getGuid());
+
+        //get entity by unique attribute should throw EntityNotFoundException
+        try {
+            metadataService.getEntityDefinition(TestUtils.DATABASE_TYPE, "name", (String) response.getFirstEntityCreated().getAttribute("name"));
+            fail("Expected EntityNotFoundException");
+        } catch(EntityNotFoundException e) {
+            //expected
+        }
+
+        init();
+        //Create the same entity again, should create new entity
+        AtlasEntity newDBEntity = TestUtilsV2.createDBEntity((String) dbEntity.getAttribute(NAME));
+        EntityMutationResponse newCreationResponse = entityStore.createOrUpdate(new AtlasEntityStream(newDBEntity));
+        assertNotEquals(newCreationResponse.getFirstEntityCreated().getGuid(), response.getFirstEntityCreated().getGuid());
+
+        //TODO - Enable after GET is ready
+        //get by unique attribute should return the new entity
+        ITypedReferenceableInstance instance = metadataService.getEntityDefinitionReference(TestUtils.DATABASE_TYPE, "name", (String) dbEntity.getAttribute("name"));
+        assertEquals(instance.getId()._getId(), newCreationResponse.getFirstEntityCreated().getGuid());
+    }
+
+    @Test
+    public void testDeleteReference() throws Exception {
+        //Deleting column should update table
+        final AtlasEntity dbEntity = TestUtilsV2.createDBEntity();
+
+        init();
+        EntityMutationResponse dbCreationResponse = entityStore.createOrUpdate(new AtlasEntityStream(dbEntity));
+
+        final AtlasEntity tableEntity = TestUtilsV2.createTableEntity(dbEntity);
+        final AtlasEntity columnEntity = TestUtilsV2.createColumnEntity(tableEntity);
+        tableEntity.setAttribute(COLUMNS_ATTR_NAME, Arrays.asList(columnEntity.getAtlasObjectId()));
+
+        AtlasEntity.AtlasEntityWithExtInfo input = new AtlasEntity.AtlasEntityWithExtInfo(tableEntity);
+        input.addReferredEntity(columnEntity);
+
+        init();
+        EntityMutationResponse tblCreationResponse = entityStore.createOrUpdate(new AtlasEntityStream(input));
+        final AtlasEntityHeader columnCreated = tblCreationResponse.getFirstCreatedEntityByTypeName(COLUMN_TYPE);
+        final AtlasEntityHeader tableCreated = tblCreationResponse.getFirstCreatedEntityByTypeName(TABLE_TYPE);
+
+        init();
+        EntityMutationResponse deletionResponse = entityStore.deleteById(columnCreated.getGuid());
+        assertEquals(deletionResponse.getDeletedEntities().size(), 1);
+        assertEquals(deletionResponse.getDeletedEntities().get(0).getGuid(), columnCreated.getGuid());
+        assertEquals(deletionResponse.getUpdatedEntities().size(), 1);
+        assertEquals(deletionResponse.getUpdatedEntities().get(0).getGuid(), tableCreated.getGuid());
+
+        assertEntityDeleted(columnCreated.getGuid());
+
+        //TODO - Fix after GET is ready
+//        ITypedReferenceableInstance tableInstance = repositoryService.getEntityDefinition(tableId);
+//        assertColumnForTestDeleteReference(tableInstance);
+
+        //Deleting table should update process
+        AtlasEntity process = TestUtilsV2.createProcessEntity(null, Arrays.asList(tableCreated.getAtlasObjectId()));
+        init();
+        final EntityMutationResponse processCreationResponse = entityStore.createOrUpdate(new AtlasEntityStream(process));
+
+        init();
+        entityStore.deleteById(tableCreated.getGuid());
+        assertEntityDeleted(tableCreated.getGuid());
+
+        assertTableForTestDeleteReference(tableCreated.getGuid());
+        assertProcessForTestDeleteReference(processCreationResponse.getFirstEntityCreated());
+    }
+
+    @Test
+    public void testDeleteEntities() throws Exception {
+        // Create a table entity, with 3 composite column entities
+        init();
+        final AtlasEntity dbEntity = TestUtilsV2.createDBEntity();
+        EntityMutationResponse dbCreationResponse = entityStore.createOrUpdate(new AtlasEntityStream(dbEntity));
+
+        final AtlasEntity tableEntity = TestUtilsV2.createTableEntity(dbEntity);
+        AtlasEntity.AtlasEntitiesWithExtInfo entitiesInfo = new AtlasEntity.AtlasEntitiesWithExtInfo(tableEntity);
+
+        final AtlasEntity columnEntity1 = TestUtilsV2.createColumnEntity(tableEntity);
+        entitiesInfo.addReferredEntity(columnEntity1);
+        final AtlasEntity columnEntity2 = TestUtilsV2.createColumnEntity(tableEntity);
+        entitiesInfo.addReferredEntity(columnEntity2);
+        final AtlasEntity columnEntity3 = TestUtilsV2.createColumnEntity(tableEntity);
+        entitiesInfo.addReferredEntity(columnEntity3);
+
+        tableEntity.setAttribute(COLUMNS_ATTR_NAME, Arrays.asList(columnEntity1.getAtlasObjectId(), columnEntity2.getAtlasObjectId(), columnEntity3.getAtlasObjectId()));
+
+        init();
+
+        final EntityMutationResponse tblCreationResponse = entityStore.createOrUpdate(new AtlasEntityStream(entitiesInfo));
+
+        final AtlasEntityHeader column1Created = tblCreationResponse.getCreatedEntityByTypeNameAndAttribute(COLUMN_TYPE, NAME, (String) columnEntity1.getAttribute(NAME));
+        final AtlasEntityHeader column2Created = tblCreationResponse.getCreatedEntityByTypeNameAndAttribute(COLUMN_TYPE, NAME, (String) columnEntity2.getAttribute(NAME));
+        final AtlasEntityHeader column3Created = tblCreationResponse.getCreatedEntityByTypeNameAndAttribute(COLUMN_TYPE, NAME, (String) columnEntity3.getAttribute(NAME));
+
+        // Retrieve the table entities from the Repository, to get their guids and the composite column guids.
+        ITypedReferenceableInstance tableInstance = metadataService.getEntityDefinitionReference(TestUtils.TABLE_TYPE, NAME, (String) tableEntity.getAttribute(NAME));
+        List<IReferenceableInstance> columns = (List<IReferenceableInstance>) tableInstance.get(COLUMNS_ATTR_NAME);
+
+        //Delete column
+        String colId = columns.get(0).getId()._getId();
+        String tableId = tableInstance.getId()._getId();
+
+        init();
+
+        EntityMutationResponse deletionResponse = entityStore.deleteById(colId);
+        assertEquals(deletionResponse.getDeletedEntities().size(), 1);
+        assertEquals(deletionResponse.getDeletedEntities().get(0).getGuid(), colId);
+        assertEquals(deletionResponse.getUpdatedEntities().size(), 1);
+        assertEquals(deletionResponse.getUpdatedEntities().get(0).getGuid(), tableId);
+        assertEntityDeleted(colId);
+
+        tableInstance = metadataService.getEntityDefinitionReference(TestUtils.TABLE_TYPE, NAME, (String) tableEntity.getAttribute(NAME));
+        assertDeletedColumn(tableInstance);
+
+        assertTestDisconnectUnidirectionalArrayReferenceFromClassType(
+            (List<ITypedReferenceableInstance>) tableInstance.get("columns"), colId);
+
+        //update by removing a column - col1
+        final AtlasEntity tableEntity1 = TestUtilsV2.createTableEntity(dbEntity, (String) tableEntity.getAttribute(NAME));
+
+        AtlasEntity.AtlasEntitiesWithExtInfo entitiesInfo1 = new AtlasEntity.AtlasEntitiesWithExtInfo(tableEntity1);
+        final AtlasEntity columnEntity3New = TestUtilsV2.createColumnEntity(tableEntity1, (String) column3Created.getAttribute(NAME));
+        tableEntity1.setAttribute(COLUMNS_ATTR_NAME, Arrays.asList(columnEntity3New.getAtlasObjectId()));
+        entitiesInfo1.addReferredEntity(columnEntity3New);
+
+        init();
+        deletionResponse = entityStore.createOrUpdate(new AtlasEntityStream(entitiesInfo1));
+
+        //TODO - enable after fixing unique atribute resolver
+        assertEquals(deletionResponse.getDeletedEntities().size(), 1);
+        assertEquals(deletionResponse.getDeletedEntities().get(0).getGuid(), column2Created.getGuid());
+        assertEntityDeleted(colId);
+
+        // Delete the table entities.  The deletion should cascade to their composite columns.
+        tableInstance = metadataService.getEntityDefinitionReference(TestUtils.TABLE_TYPE, NAME, (String) tableEntity.getAttribute(NAME));
+
+        init();
+        EntityMutationResponse tblDeletionResponse = entityStore.deleteById(tableInstance.getId()._getId());
+        assertEquals(tblDeletionResponse.getDeletedEntities().size(), 2);
+
+        final AtlasEntityHeader tableDeleted = tblDeletionResponse.getFirstDeletedEntityByTypeName(TABLE_TYPE);
+        final AtlasEntityHeader colDeleted = tblDeletionResponse.getFirstDeletedEntityByTypeName(COLUMN_TYPE);
+
+        // Verify that deleteEntities() response has guids for tables and their composite columns.
+        Assert.assertTrue(tableDeleted.getGuid().equals(tableInstance.getId()._getId()));
+        Assert.assertTrue(colDeleted.getGuid().equals(column3Created.getGuid()));
+
+        // Verify that tables and their composite columns have been deleted from the graph Repository.
+        assertEntityDeleted(tableDeleted.getGuid());
+        assertEntityDeleted(colDeleted.getGuid());
+        assertTestDeleteEntities(tableInstance);
+
+    }
+
+    protected abstract void assertDeletedColumn(ITypedReferenceableInstance tableInstance) throws AtlasException;
+
+    protected abstract void assertTestDeleteEntities(ITypedReferenceableInstance tableInstance) throws Exception;
+
+    protected abstract void assertTableForTestDeleteReference(String tableId) throws Exception;
+
+    protected abstract void assertColumnForTestDeleteReference(AtlasEntity tableInstance)
+        throws AtlasException;
+
+    protected abstract void assertProcessForTestDeleteReference(AtlasEntityHeader processInstance) throws Exception;
+
+    protected abstract void assertEntityDeleted(String id) throws Exception;
+
+    String getFirstGuid(Map<String, AtlasEntity> entityMap) {
+        return entityMap.keySet().iterator().next();
+    }
+
+    @Test
+    public void testUpdateEntity_MultiplicityOneNonCompositeReference() throws Exception {
+        AtlasEntity.AtlasEntitiesWithExtInfo hrDept = TestUtilsV2.createDeptEg2();
+        init();
+
+        RequestContextV1.clear();
+        final EntityMutationResponse hrDeptCreationResponse = entityStore.createOrUpdate(new AtlasEntityStream(hrDept));
+        final AtlasEntityHeader deptCreated = hrDeptCreationResponse.getFirstUpdatedEntityByTypeName(DEPARTMENT_TYPE);
+        final AtlasEntityHeader maxEmployeeCreated = hrDeptCreationResponse.getCreatedEntityByTypeNameAndAttribute(TestUtilsV2.EMPLOYEE_TYPE, NAME, "Max");
+        final AtlasEntityHeader johnEmployeeCreated = hrDeptCreationResponse.getUpdatedEntityByTypeNameAndAttribute(TestUtilsV2.EMPLOYEE_TYPE, NAME, "John");
+        final AtlasEntityHeader janeEmployeeCreated = hrDeptCreationResponse.getCreatedEntityByTypeNameAndAttribute(TestUtilsV2.MANAGER_TYPE, NAME, "Jane");
+        final AtlasEntityHeader juliusEmployeeCreated = hrDeptCreationResponse.getUpdatedEntityByTypeNameAndAttribute(TestUtilsV2.MANAGER_TYPE, NAME, "Julius");
+
+//        ITypedReferenceableInstance hrDeptInstance = metadataService.getEntityDefinition(hrDeptCreationResponse.getFirstCreatedEntityByTypeName(DEPARTMENT_TYPE).getGuid());
+//        Map<String, String> nameGuidMap = getEmployeeNameGuidMap(hrDeptInstance);
+
+        ITypedReferenceableInstance max = metadataService.getEntityDefinition(maxEmployeeCreated.getGuid());
+        String maxGuid = max.getId()._getId();
+        AtlasVertex vertex = GraphHelper.getInstance().getVertexForGUID(maxGuid);
+        Long creationTimestamp = GraphHelper.getSingleValuedProperty(vertex, Constants.TIMESTAMP_PROPERTY_KEY, Long.class);
+        Assert.assertNotNull(creationTimestamp);
+
+        Long modificationTimestampPreUpdate = GraphHelper.getSingleValuedProperty(vertex, Constants.MODIFICATION_TIMESTAMP_PROPERTY_KEY, Long.class);
+        Assert.assertNotNull(modificationTimestampPreUpdate);
+
+        AtlasEntity maxEmployee = getEmployeeByName(hrDept, "Max");
+        maxEmployee.setAttribute("mentor", johnEmployeeCreated.getAtlasObjectId());
+        maxEmployee.setAttribute("department", deptCreated.getAtlasObjectId());
+        maxEmployee.setAttribute("manager", janeEmployeeCreated.getAtlasObjectId());
+
+        init();
+        EntityMutationResponse entityResult = entityStore.createOrUpdate(new AtlasEntityStream(maxEmployee));
+
+        assertEquals(entityResult.getUpdatedEntities().size(), 1);
+        assertTrue(extractGuids(entityResult.getUpdatedEntities()).contains(maxGuid));
+
+        // Verify the update was applied correctly - john should now be max's mentor.
+        max = metadataService.getEntityDefinition(maxGuid);
+        ITypedReferenceableInstance refTarget = (ITypedReferenceableInstance) max.get("mentor");
+        Assert.assertEquals(refTarget.getId()._getId(), johnEmployeeCreated.getGuid());
+
+        // Verify modification timestamp was updated.
+        vertex = GraphHelper.getInstance().getVertexForGUID(maxGuid);
+        Long modificationTimestampPostUpdate = GraphHelper.getSingleValuedProperty(vertex, Constants.MODIFICATION_TIMESTAMP_PROPERTY_KEY, Long.class);
+        Assert.assertNotNull(modificationTimestampPostUpdate);
+        Assert.assertTrue(creationTimestamp < modificationTimestampPostUpdate);
+
+        // Update max's mentor reference to jane.
+        maxEmployee.setAttribute("mentor", janeEmployeeCreated.getAtlasObjectId());
+        init();
+        entityResult = entityStore.createOrUpdate(new AtlasEntityStream(maxEmployee));
+        assertEquals(entityResult.getUpdatedEntities().size(), 1);
+        assertTrue(extractGuids(entityResult.getUpdatedEntities()).contains(maxGuid));
+
+        // Verify the update was applied correctly - jane should now be max's mentor.
+        max = metadataService.getEntityDefinition(maxGuid);
+        refTarget = (ITypedReferenceableInstance) max.get("mentor");
+        Assert.assertEquals(refTarget.getId()._getId(), janeEmployeeCreated.getGuid());
+
+        // Verify modification timestamp was updated.
+        vertex = GraphHelper.getInstance().getVertexForGUID(maxGuid);
+        Long modificationTimestampPost2ndUpdate = GraphHelper.getSingleValuedProperty(vertex, Constants.MODIFICATION_TIMESTAMP_PROPERTY_KEY, Long.class);
+        Assert.assertNotNull(modificationTimestampPost2ndUpdate);
+        Assert.assertTrue(modificationTimestampPostUpdate < modificationTimestampPost2ndUpdate);
+
+        ITypedReferenceableInstance julius = metadataService.getEntityDefinition(juliusEmployeeCreated.getGuid());
+        Id juliusGuid = julius.getId();
+
+        init();
+        maxEmployee.setAttribute("manager", juliusEmployeeCreated.getAtlasObjectId());
+        entityResult = entityStore.createOrUpdate(new AtlasEntityStream(maxEmployee));
+        //TODO ATLAS-499 should have updated julius' subordinates
+        assertEquals(entityResult.getUpdatedEntities().size(), 2);
+        assertTrue(extractGuids(entityResult.getUpdatedEntities()).contains(maxGuid));
+        assertTrue(extractGuids(entityResult.getUpdatedEntities()).contains(janeEmployeeCreated.getGuid()));
+
+        // Verify the update was applied correctly - julius should now be max's manager.
+        max = metadataService.getEntityDefinition(maxGuid);
+        refTarget = (ITypedReferenceableInstance) max.get("manager");
+        Assert.assertEquals(refTarget.getId()._getId(), juliusGuid._getId());
+
+        assertTestUpdateEntity_MultiplicityOneNonCompositeReference(janeEmployeeCreated.getGuid());
+    }
+
+    private Map<String, String> getEmployeeNameGuidMap(final ITypedReferenceableInstance hrDept) throws AtlasException {
+        Object refValue = hrDept.get("employees");
+        Assert.assertTrue(refValue instanceof List);
+        List<Object> employees = (List<Object>)refValue;
+        Assert.assertEquals(employees.size(), 4);
+        Map<String, String> nameGuidMap = new HashMap<String, String>() {{
+            put("hr", hrDept.getId()._getId());
+        }};
+
+        for (Object listValue : employees) {
+            Assert.assertTrue(listValue instanceof ITypedReferenceableInstance);
+            ITypedReferenceableInstance employee = (ITypedReferenceableInstance) listValue;
+            nameGuidMap.put((String)employee.get("name"), employee.getId()._getId());
+        }
+        return nameGuidMap;
+    }
+
+
+    private AtlasEntity getEmployeeByName(AtlasEntity.AtlasEntitiesWithExtInfo hrDept, String name) {
+        for (AtlasEntity entity : hrDept.getEntities()) {
+            if ( name.equals(entity.getAttribute(NAME))) {
+                return entity;
+            }
+        }
+        return null;
+    }
+//
+    protected abstract void assertTestUpdateEntity_MultiplicityOneNonCompositeReference(String janeGuid) throws Exception;
+
+    /**
+     * Verify deleting an entity which is contained by another
+     * entity through a bi-directional composite reference.
+     *
+     * @throws Exception
+     */
+    @Test
+    public void testDisconnectBidirectionalReferences() throws Exception {
+        AtlasEntity.AtlasEntitiesWithExtInfo hrDept = TestUtilsV2.createDeptEg2();
+        init();
+        final EntityMutationResponse hrDeptCreationResponse = entityStore.createOrUpdate(new AtlasEntityStream(hrDept));
+
+        final AtlasEntityHeader deptCreated = hrDeptCreationResponse.getFirstCreatedEntityByTypeName(DEPARTMENT_TYPE);
+        final AtlasEntityHeader maxEmployee = hrDeptCreationResponse.getCreatedEntityByTypeNameAndAttribute(TestUtilsV2.EMPLOYEE_TYPE, NAME, "Max");
+        final AtlasEntityHeader johnEmployee = hrDeptCreationResponse.getCreatedEntityByTypeNameAndAttribute(TestUtilsV2.EMPLOYEE_TYPE, NAME, "John");
+        final AtlasEntityHeader janeEmployee = hrDeptCreationResponse.getCreatedEntityByTypeNameAndAttribute(TestUtilsV2.MANAGER_TYPE, NAME, "Jane");
+        final AtlasEntityHeader juliusEmployee = hrDeptCreationResponse.getCreatedEntityByTypeNameAndAttribute(TestUtilsV2.MANAGER_TYPE, NAME, "Julius");
+
+        ITypedReferenceableInstance hrDeptInstance = metadataService.getEntityDefinition(deptCreated.getGuid());
+        Map<String, String> nameGuidMap = getEmployeeNameGuidMap(hrDeptInstance);
+
+        // Verify that Max is one of Jane's subordinates.
+        ITypedReferenceableInstance jane = metadataService.getEntityDefinition(janeEmployee.getGuid());
+        Object refValue = jane.get("subordinates");
+        Assert.assertTrue(refValue instanceof List);
+        List<Object> subordinates = (List<Object>)refValue;
+        Assert.assertEquals(subordinates.size(), 2);
+        List<String> subordinateIds = new ArrayList<>(2);
+        for (Object listValue : subordinates) {
+            Assert.assertTrue(listValue instanceof ITypedReferenceableInstance);
+            ITypedReferenceableInstance employee = (ITypedReferenceableInstance) listValue;
+            subordinateIds.add(employee.getId()._getId());
+        }
+        Assert.assertTrue(subordinateIds.contains(maxEmployee.getGuid()));
+
+        init();
+        EntityMutationResponse entityResult = entityStore.deleteById(maxEmployee.getGuid());
+        ITypedReferenceableInstance john = metadataService.getEntityDefinitionReference(TestUtilsV2.EMPLOYEE_TYPE, NAME, "John");
+
+        assertEquals(entityResult.getDeletedEntities().size(), 1);
+        assertEquals(entityResult.getDeletedEntities().get(0).getGuid(), maxEmployee.getGuid());
+        assertEquals(entityResult.getUpdatedEntities().size(), 3);
+
+        assertEquals(extractGuids(entityResult.getUpdatedEntities()), Arrays.asList(janeEmployee.getGuid(), deptCreated.getGuid(), johnEmployee.getGuid()));
+        assertEntityDeleted(maxEmployee.getGuid());
+
+        assertMaxForTestDisconnectBidirectionalReferences(nameGuidMap);
+
+        // Now delete jane - this should disconnect the manager reference from her
+        // subordinate.
+        init();
+        entityResult = entityStore.deleteById(janeEmployee.getGuid());
+        assertEquals(entityResult.getDeletedEntities().size(), 1);
+        assertEquals(entityResult.getDeletedEntities().get(0).getGuid(), janeEmployee.getGuid());
+        assertEquals(entityResult.getUpdatedEntities().size(), 2);
+        assertEquals(extractGuids(entityResult.getUpdatedEntities()), Arrays.asList(deptCreated.getGuid(), johnEmployee.getGuid()));
+
+        assertEntityDeleted(janeEmployee.getGuid());
+
+        john = metadataService.getEntityDefinitionReference(TestUtilsV2.EMPLOYEE_TYPE, NAME, "John");
+        assertJohnForTestDisconnectBidirectionalReferences(john, janeEmployee.getGuid());
+    }
+
+    protected List<String> extractGuids(final List<AtlasEntityHeader> updatedEntities) {
+        List<String> guids = new ArrayList<>();
+        for (AtlasEntityHeader header : updatedEntities ) {
+            guids.add(header.getGuid());
+        }
+        return guids;
+    }
+
+    protected abstract void assertJohnForTestDisconnectBidirectionalReferences(ITypedReferenceableInstance john,
+        String janeGuid) throws Exception;
+
+    protected abstract void assertMaxForTestDisconnectBidirectionalReferences(Map<String, String> nameGuidMap)
+        throws Exception;
+
+    protected abstract void assertTestDisconnectUnidirectionalArrayReferenceFromClassType(
+        List<ITypedReferenceableInstance> columns, String columnGuid);
+
+    /**
+     * Verify deleting entities that are the target of a unidirectional class array reference
+     * from a struct or trait instance.
+     */
+    @Test
+    public void testDisconnectUnidirectionalArrayReferenceFromStructAndTraitTypes() throws Exception {
+        // Define class types.
+        AtlasStructDef.AtlasAttributeDef[] structTargetAttributes = new AtlasStructDef.AtlasAttributeDef[]{
+            new AtlasStructDef.AtlasAttributeDef("attr1", "string",
+                true,
+                AtlasStructDef.AtlasAttributeDef.Cardinality.SINGLE, 0, 1,
+                false, false,
+                Collections.<AtlasStructDef.AtlasConstraintDef>emptyList())};
+
+        AtlasEntityDef structTargetDef =
+            new AtlasEntityDef("StructTarget", "StructTarget_description", "1.0",
+                Arrays.asList(structTargetAttributes), Collections.<String>emptySet());
+
+
+        AtlasStructDef.AtlasAttributeDef[] traitTargetAttributes = new AtlasStructDef.AtlasAttributeDef[]{
+            new AtlasStructDef.AtlasAttributeDef("attr1", "string",
+                true,
+                AtlasStructDef.AtlasAttributeDef.Cardinality.SINGLE, 0, 1,
+                false, false,
+                Collections.<AtlasStructDef.AtlasConstraintDef>emptyList())};
+
+        AtlasEntityDef traitTargetDef =
+            new AtlasEntityDef("TraitTarget", "TraitTarget_description", "1.0",
+                Arrays.asList(traitTargetAttributes), Collections.<String>emptySet());
+
+        AtlasStructDef.AtlasAttributeDef[] structContainerAttributes = new AtlasStructDef.AtlasAttributeDef[]{
+            new AtlasStructDef.AtlasAttributeDef("struct", "TestStruct",
+                true,
+                AtlasStructDef.AtlasAttributeDef.Cardinality.SINGLE, 0, 1,
+                false, false,
+                Collections.<AtlasStructDef.AtlasConstraintDef>emptyList())};
+
+        AtlasEntityDef structContainerDef =
+            new AtlasEntityDef("StructContainer", "StructContainer_description", "1.0",
+                Arrays.asList(structContainerAttributes), Collections.<String>emptySet());
+
+        // Define struct and trait types which have a unidirectional array reference
+        // to a class type.
+        AtlasStructDef.AtlasAttributeDef[] structDefAttributes = new AtlasStructDef.AtlasAttributeDef[] {
+            new AtlasStructDef.AtlasAttributeDef("target", "array<StructTarget>",
+            true,
+            AtlasStructDef.AtlasAttributeDef.Cardinality.SINGLE, 0, 1,
+            false, false,
+            Collections.<AtlasStructDef.AtlasConstraintDef>emptyList()),
+
+            new AtlasStructDef.AtlasAttributeDef("nestedStructs", "array<NestedStruct>",
+            true,
+            AtlasStructDef.AtlasAttributeDef.Cardinality.SINGLE, 0, 1,
+            false, false,
+            Collections.<AtlasStructDef.AtlasConstraintDef>emptyList()) };
+
+        AtlasStructDef structDef = new AtlasStructDef("TestStruct", "TestStruct_desc", "1.0", Arrays.asList(structDefAttributes));
+
+
+        // Define struct and trait types which have a unidirectional array reference
+        // to a class type.
+        AtlasStructDef.AtlasAttributeDef[] nestedStructDefAttributes = new AtlasStructDef.AtlasAttributeDef[] {
+            new AtlasStructDef.AtlasAttributeDef("attr1", "string",
+                true,
+                AtlasStructDef.AtlasAttributeDef.Cardinality.SINGLE, 0, 1,
+                false, false,
+                Collections.<AtlasStructDef.AtlasConstraintDef>emptyList()),
+
+            new AtlasStructDef.AtlasAttributeDef("target", "array<TraitTarget>",
+                true,
+                AtlasStructDef.AtlasAttributeDef.Cardinality.SINGLE, 0, 1,
+                false, false,
+                Collections.<AtlasStructDef.AtlasConstraintDef>emptyList()) };
+
+        AtlasStructDef nestedStructDef = new AtlasStructDef("NestedStruct", "NestedStruct_desc", "1.0", Arrays.asList(nestedStructDefAttributes));
+
+        AtlasStructDef.AtlasAttributeDef[] traitDefAttributes = new AtlasStructDef.AtlasAttributeDef[] {
+            new AtlasStructDef.AtlasAttributeDef("target", "array<TraitTarget>",
+                true,
+                AtlasStructDef.AtlasAttributeDef.Cardinality.SINGLE, 0, 1,
+                false, false,
+                Collections.<AtlasStructDef.AtlasConstraintDef>emptyList())
+        };
+
+        AtlasClassificationDef traitDef = new AtlasClassificationDef("TestTrait", "TestTrait_desc", "1.0", Arrays.asList(traitDefAttributes));
+
+        AtlasTypesDef typesDef = AtlasTypeUtil.getTypesDef(ImmutableList.<AtlasEnumDef>of(),
+            ImmutableList.<AtlasStructDef>of(structDef, nestedStructDef),
+            ImmutableList.<AtlasClassificationDef>of(traitDef),
+            ImmutableList.<AtlasEntityDef>of(structTargetDef, traitTargetDef, structContainerDef));
+
+        typeDefStore.createTypesDef(typesDef);
+
+        // Create instances of class, struct, and trait types.
+        final AtlasEntity structTargetEntity = new AtlasEntity("StructTarget");
+        final AtlasEntity traitTargetEntity = new AtlasEntity("TraitTarget");
+        final AtlasEntity structContainerEntity = new AtlasEntity("StructContainer");
+        AtlasStruct structInstance = new AtlasStruct("TestStruct");
+        AtlasStruct nestedStructInstance = new AtlasStruct("NestedStruct");
+        Struct traitInstance = new Struct("TestTrait");
+        structContainerEntity.setAttribute("struct", structInstance);
+        structInstance.setAttribute("target", ImmutableList.of(structTargetEntity.getAtlasObjectId()));
+        structInstance.setAttribute("nestedStructs", ImmutableList.of(nestedStructInstance));
+
+        AtlasEntity.AtlasEntitiesWithExtInfo structCreationObj = new AtlasEntity.AtlasEntitiesWithExtInfo();
+        structCreationObj.addEntity(structContainerEntity);
+        structCreationObj.addEntity(traitTargetEntity);
+        structCreationObj.addReferredEntity(structTargetEntity);
+
+        init();
+
+        AtlasEntityStream entityStream = new AtlasEntityStream(structCreationObj);
+
+        EntityMutationResponse response = entityStore.createOrUpdate(entityStream);
+        Assert.assertEquals(response.getCreatedEntities().size(), 3);
+
+        final List<String> structTarget = metadataService.getEntityList("StructTarget");
+        Assert.assertEquals(structTarget.size(), 1);
+        final String structTargetGuid = structTarget.get(0);
+
+        final List<String> traitTarget = metadataService.getEntityList("TraitTarget");
+        Assert.assertEquals(traitTarget.size(), 1);
+        final String traitTargetGuid = traitTarget.get(0);
+
+        final List<String> structContainerTarget = metadataService.getEntityList("StructContainer");
+        Assert.assertEquals(structContainerTarget.size(), 1);
+        String structContainerGuid = structContainerTarget.get(0);
+
+        // Add TestTrait to StructContainer instance
+        traitInstance.set("target", ImmutableList.of(new Id(traitTargetGuid, 0, "TraitTarget")));
+        TraitType traitType = typeSystem.getDataType(TraitType.class, "TestTrait");
+        ITypedStruct convertedTrait = traitType.convert(traitInstance, Multiplicity.REQUIRED);
+        metadataService.addTrait(structContainerGuid, convertedTrait);
+
+        // Verify that the unidirectional references from the struct and trait instances
+        // are pointing at the target entities.
+        final ITypedReferenceableInstance structContainerConvertedEntity = metadataService.getEntityDefinition(structContainerGuid);
+        Object object = structContainerConvertedEntity.get("struct");
+        Assert.assertNotNull(object);
+        Assert.assertTrue(object instanceof ITypedStruct);
+        ITypedStruct struct = (ITypedStruct) object;
+        object = struct.get("target");
+        Assert.assertNotNull(object);
+        Assert.assertTrue(object instanceof List);
+        List<ITypedReferenceableInstance> refList = (List<ITypedReferenceableInstance>)object;
+        Assert.assertEquals(refList.size(), 1);
+        Assert.assertEquals(refList.get(0).getId()._getId(), structTargetGuid);
+
+        IStruct trait = structContainerConvertedEntity.getTrait("TestTrait");
+        Assert.assertNotNull(trait);
+        object = trait.get("target");
+        Assert.assertNotNull(object);
+        Assert.assertTrue(object instanceof List);
+        refList = (List<ITypedReferenceableInstance>)object;
+        Assert.assertEquals(refList.size(), 1);
+        Assert.assertEquals(refList.get(0).getId()._getId(), traitTargetGuid);
+
+        init();
+        // Delete the entities that are targets of the struct and trait instances.
+        EntityMutationResponse entityResult = entityStore.deleteByIds(new ArrayList<String>() {{
+            add(structTargetGuid);
+            add(traitTargetGuid);
+        }});
+        Assert.assertEquals(entityResult.getDeletedEntities().size(), 2);
+        Assert.assertTrue(extractGuids(entityResult.getDeletedEntities()).containsAll(Arrays.asList(structTargetGuid, traitTargetGuid)));
+        assertEntityDeleted(structTargetGuid);
+        assertEntityDeleted(traitTargetGuid);
+
+        assertTestDisconnectUnidirectionalArrayReferenceFromStructAndTraitTypes(structContainerGuid);
+
+        init();
+        // Delete the entity which contains nested structs and has the TestTrait trait.
+        entityResult = entityStore.deleteById(structContainerGuid);
+        Assert.assertEquals(entityResult.getDeletedEntities().size(), 1);
+        Assert.assertTrue(extractGuids(entityResult.getDeletedEntities()).contains(structContainerGuid));
+        assertEntityDeleted(structContainerGuid);
+
+        // Verify all TestStruct struct vertices were removed.
+        assertVerticesDeleted(getVertices(Constants.ENTITY_TYPE_PROPERTY_KEY, "TestStruct"));
+
+        // Verify all NestedStruct struct vertices were removed.
+        assertVerticesDeleted(getVertices(Constants.ENTITY_TYPE_PROPERTY_KEY, "NestedStruct"));
+
+        // Verify all TestTrait trait vertices were removed.
+        assertVerticesDeleted(getVertices(Constants.ENTITY_TYPE_PROPERTY_KEY, "TestTrait"));
+    }
+
+    @Test
+    public void testDeleteByUniqueAttribute() throws Exception {
+        // Create a table entity, with 3 composite column entities
+        init();
+        final AtlasEntity dbEntity = TestUtilsV2.createDBEntity();
+        EntityMutationResponse dbCreationResponse = entityStore.createOrUpdate(new AtlasEntityStream(dbEntity));
+
+        final AtlasEntity tableEntity = TestUtilsV2.createTableEntity(dbEntity);
+        AtlasEntity.AtlasEntitiesWithExtInfo entitiesInfo = new AtlasEntity.AtlasEntitiesWithExtInfo(tableEntity);
+
+        final AtlasEntity columnEntity1 = TestUtilsV2.createColumnEntity(tableEntity);
+        entitiesInfo.addReferredEntity(columnEntity1);
+        final AtlasEntity columnEntity2 = TestUtilsV2.createColumnEntity(tableEntity);
+        entitiesInfo.addReferredEntity(columnEntity2);
+        final AtlasEntity columnEntity3 = TestUtilsV2.createColumnEntity(tableEntity);
+        entitiesInfo.addReferredEntity(columnEntity3);
+
+        tableEntity.setAttribute(COLUMNS_ATTR_NAME, Arrays.asList(columnEntity1.getAtlasObjectId(), columnEntity2.getAtlasObjectId(), columnEntity3.getAtlasObjectId()));
+
+        init();
+
+        final EntityMutationResponse tblCreationResponse = entityStore.createOrUpdate(new AtlasEntityStream(entitiesInfo));
+
+        final AtlasEntityHeader column1Created = tblCreationResponse.getCreatedEntityByTypeNameAndAttribute(COLUMN_TYPE, NAME, (String) columnEntity1.getAttribute(NAME));
+        final AtlasEntityHeader column2Created = tblCreationResponse.getCreatedEntityByTypeNameAndAttribute(COLUMN_TYPE, NAME, (String) columnEntity2.getAttribute(NAME));
+        final AtlasEntityHeader column3Created = tblCreationResponse.getCreatedEntityByTypeNameAndAttribute(COLUMN_TYPE, NAME, (String) columnEntity3.getAttribute(NAME));
+
+        // Retrieve the table entities from the Repository, to get their guids and the composite column guids.
+        ITypedReferenceableInstance tableInstance = metadataService.getEntityDefinitionReference(TestUtils.TABLE_TYPE, NAME, (String) tableEntity.getAttribute(NAME));
+        List<IReferenceableInstance> columns = (List<IReferenceableInstance>) tableInstance.get(COLUMNS_ATTR_NAME);
+
+        //Delete column
+        String colId = columns.get(0).getId()._getId();
+        String tableId = tableInstance.getId()._getId();
+
+        init();
+
+        Map<String, Object> uniqueAttrs = new HashMap<>();
+        uniqueAttrs.put(NAME, column1Created.getAttribute(NAME));
+
+        AtlasEntityType columnType = typeRegistry.getEntityTypeByName(COLUMN_TYPE);
+        EntityMutationResponse deletionResponse = entityStore.deleteByUniqueAttributes(columnType, uniqueAttrs);
+        assertEquals(deletionResponse.getDeletedEntities().size(), 1);
+        assertEquals(deletionResponse.getDeletedEntities().get(0).getGuid(), colId);
+        assertEquals(deletionResponse.getUpdatedEntities().size(), 1);
+        assertEquals(deletionResponse.getUpdatedEntities().get(0).getGuid(), tableId);
+        assertEntityDeleted(colId);
+
+        tableInstance = metadataService.getEntityDefinitionReference(TestUtils.TABLE_TYPE, NAME, (String) tableEntity.getAttribute(NAME));
+        assertDeletedColumn(tableInstance);
+    }
+
+    protected abstract void assertTestDisconnectUnidirectionalArrayReferenceFromStructAndTraitTypes(
+        String structContainerGuid) throws Exception;
+
+    protected abstract void assertVerticesDeleted(List<AtlasVertex> vertices);
+
+    protected List<AtlasVertex> getVertices(String propertyName, Object value) {
+        AtlasGraph graph = TestUtils.getGraph();
+        Iterable<AtlasVertex> vertices = graph.getVertices(propertyName, value);
+        List<AtlasVertex> list = new ArrayList<>();
+        for (AtlasVertex vertex : vertices) {
+            list.add(vertex);
+        }
+        return list;
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-atlas/blob/aa67f8ae/repository/src/test/java/org/apache/atlas/repository/store/graph/v1/AtlasEntityStoreV1Test.java
----------------------------------------------------------------------
diff --git a/repository/src/test/java/org/apache/atlas/repository/store/graph/v1/AtlasEntityStoreV1Test.java b/repository/src/test/java/org/apache/atlas/repository/store/graph/v1/AtlasEntityStoreV1Test.java
index bb7de4a..e812ca6 100644
--- a/repository/src/test/java/org/apache/atlas/repository/store/graph/v1/AtlasEntityStoreV1Test.java
+++ b/repository/src/test/java/org/apache/atlas/repository/store/graph/v1/AtlasEntityStoreV1Test.java
@@ -119,13 +119,11 @@ public class AtlasEntityStoreV1Test {
     @AfterClass
     public void clear() {
         AtlasGraphProvider.cleanup();
-        TestUtils.resetRequestContext();
     }
 
     @BeforeTest
     public void init() throws Exception {
         entityStore = new AtlasEntityStoreV1(deleteHandler, typeRegistry);
-
         RequestContextV1.clear();
     }
 
@@ -138,7 +136,7 @@ public class AtlasEntityStoreV1Test {
         AtlasEntityHeader dept1 = response.getFirstCreatedEntityByTypeName(TestUtilsV2.DEPARTMENT_TYPE);
         validateEntity(deptEntity, getEntityFromStore(dept1), deptEntity.getEntities().get(0));
 
-        final Map<EntityOperation, List<AtlasEntityHeader>> entitiesMutated = response.getEntitiesMutated();
+        final Map<EntityOperation, List<AtlasEntityHeader>> entitiesMutated = response.getMutatedEntities();
         List<AtlasEntityHeader> entitiesCreated = entitiesMutated.get(EntityOperation.CREATE);
 
         Assert.assertTrue(entitiesCreated.size() >= deptEntity.getEntities().size());

http://git-wip-us.apache.org/repos/asf/incubator-atlas/blob/aa67f8ae/repository/src/test/java/org/apache/atlas/repository/store/graph/v1/SoftDeleteHandlerV1Test.java
----------------------------------------------------------------------
diff --git a/repository/src/test/java/org/apache/atlas/repository/store/graph/v1/SoftDeleteHandlerV1Test.java b/repository/src/test/java/org/apache/atlas/repository/store/graph/v1/SoftDeleteHandlerV1Test.java
new file mode 100644
index 0000000..987951e
--- /dev/null
+++ b/repository/src/test/java/org/apache/atlas/repository/store/graph/v1/SoftDeleteHandlerV1Test.java
@@ -0,0 +1,198 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ * <p/>
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * <p/>
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.atlas.repository.store.graph.v1;
+
+
+import org.apache.atlas.AtlasClient;
+import org.apache.atlas.AtlasException;
+import org.apache.atlas.model.instance.AtlasEntity;
+import org.apache.atlas.model.instance.AtlasEntityHeader;
+import org.apache.atlas.model.instance.AtlasObjectId;
+import org.apache.atlas.repository.Constants;
+import org.apache.atlas.repository.graph.GraphHelper;
+import org.apache.atlas.repository.graphdb.AtlasVertex;
+import org.apache.atlas.services.MetadataService;
+import org.apache.atlas.type.AtlasTypeRegistry;
+import org.apache.atlas.typesystem.IStruct;
+import org.apache.atlas.typesystem.ITypedReferenceableInstance;
+import org.apache.atlas.typesystem.ITypedStruct;
+import org.apache.atlas.typesystem.persistence.Id;
+import org.testng.Assert;
+
+import javax.inject.Inject;
+import java.util.List;
+import java.util.Map;
+
+import static org.apache.atlas.TestUtils.COLUMNS_ATTR_NAME;
+import static org.apache.atlas.TestUtils.NAME;
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertNotNull;
+
+public class SoftDeleteHandlerV1Test extends AtlasDeleteHandlerV1Test {
+
+    @Inject
+    MetadataService metadataService;
+
+    @Override
+    DeleteHandlerV1 getDeleteHandler(final AtlasTypeRegistry typeRegistry) {
+        return new SoftDeleteHandlerV1(typeRegistry);
+    }
+
+    @Override
+    protected void assertDeletedColumn(final ITypedReferenceableInstance tableInstance) throws AtlasException {
+
+    }
+
+    @Override
+    protected void assertTestDeleteEntities(final ITypedReferenceableInstance tableInstance) throws Exception {
+
+    }
+
+    @Override
+    protected void assertTableForTestDeleteReference(final String tableId) throws Exception {
+
+        //TODO - Fix after GET is ready
+        ITypedReferenceableInstance table = metadataService.getEntityDefinition(tableId);
+        assertNotNull(table.get(NAME));
+        assertNotNull(table.get("description"));
+        assertNotNull(table.get("type"));
+        assertNotNull(table.get("tableType"));
+        assertNotNull(table.get("created"));
+
+        Id dbId = (Id) table.get("database");
+        assertNotNull(dbId);
+
+        ITypedReferenceableInstance db = metadataService.getEntityDefinition(dbId.getId()._getId());
+        assertNotNull(db);
+        assertEquals(db.getId().getState(), Id.EntityState.ACTIVE);
+
+    }
+
+    @Override
+    protected void assertColumnForTestDeleteReference(final AtlasEntity tableInstance) throws AtlasException {
+
+        List<AtlasObjectId> columns = (List<AtlasObjectId>) tableInstance.getAttribute(COLUMNS_ATTR_NAME);
+        assertEquals(columns.size(), 1);
+
+        //TODO - Enable after GET is ready
+        ITypedReferenceableInstance colInst = metadataService.getEntityDefinition(columns.get(0).getGuid());
+        assertEquals(colInst.getId().getState(), Id.EntityState.DELETED);
+    }
+
+    @Override
+    protected void assertProcessForTestDeleteReference(final AtlasEntityHeader processInstance) throws Exception {
+        //
+        ITypedReferenceableInstance process = metadataService.getEntityDefinition(processInstance.getGuid());
+        List<ITypedReferenceableInstance> outputs =
+            (List<ITypedReferenceableInstance>) process.get(AtlasClient.PROCESS_ATTRIBUTE_OUTPUTS);
+        List<ITypedReferenceableInstance> expectedOutputs =
+            (List<ITypedReferenceableInstance>) process.get(AtlasClient.PROCESS_ATTRIBUTE_OUTPUTS);
+        assertEquals(outputs.size(), expectedOutputs.size());
+
+    }
+
+    @Override
+    protected void assertEntityDeleted(final String id) throws Exception {
+//        ITypedReferenceableInstance entity = metadataService.getEntityDefinition(id);
+//        assertEquals(entity.getId().getState(), Id.EntityState.DELETED);
+        final AtlasEntity.AtlasEntityWithExtInfo byId = entityStore.getById(id);
+        assertEquals(byId.getEntity().getStatus(), AtlasEntity.Status.DELETED);
+    }
+
+    @Override
+    protected void assertTestUpdateEntity_MultiplicityOneNonCompositeReference(final String janeGuid) throws Exception {
+        // Verify Jane's subordinates reference cardinality is still 2.
+        ITypedReferenceableInstance jane = metadataService.getEntityDefinition(janeGuid);
+        List<ITypedReferenceableInstance> subordinates = (List<ITypedReferenceableInstance>) jane.get("subordinates");
+        Assert.assertEquals(subordinates.size(), 2);
+    }
+
+    @Override
+    protected void assertJohnForTestDisconnectBidirectionalReferences(final ITypedReferenceableInstance john, final String janeGuid) throws Exception {
+        Id mgr = (Id) john.get("manager");
+        assertNotNull(mgr);
+        assertEquals(mgr._getId(), janeGuid);
+        assertEquals(mgr.getState(), Id.EntityState.DELETED);
+    }
+
+    @Override
+    protected void assertMaxForTestDisconnectBidirectionalReferences(final Map<String, String> nameGuidMap) throws Exception {
+
+        // Verify that the Department.employees reference to the deleted employee
+        // was disconnected.
+        ITypedReferenceableInstance hrDept = metadataService.getEntityDefinition(nameGuidMap.get("hr"));
+        List<ITypedReferenceableInstance> employees = (List<ITypedReferenceableInstance>) hrDept.get("employees");
+        Assert.assertEquals(employees.size(), 4);
+        String maxGuid = nameGuidMap.get("Max");
+        for (ITypedReferenceableInstance employee : employees) {
+            if (employee.getId()._getId().equals(maxGuid)) {
+                assertEquals(employee.getId().getState(), Id.EntityState.DELETED);
+            }
+        }
+
+        // Verify that the Manager.subordinates still references deleted employee
+        ITypedReferenceableInstance jane = metadataService.getEntityDefinition(nameGuidMap.get("Jane"));
+        List<ITypedReferenceableInstance> subordinates = (List<ITypedReferenceableInstance>) jane.get("subordinates");
+        assertEquals(subordinates.size(), 2);
+        for (ITypedReferenceableInstance subordinate : subordinates) {
+            if (subordinate.getId()._getId().equals(maxGuid)) {
+                assertEquals(subordinate.getId().getState(), Id.EntityState.DELETED);
+            }
+        }
+
+        // Verify that max's Person.mentor unidirectional reference to john was disconnected.
+        ITypedReferenceableInstance john = metadataService.getEntityDefinition(nameGuidMap.get("John"));
+        Id mentor = (Id) john.get("mentor");
+        assertEquals(mentor._getId(), maxGuid);
+        assertEquals(mentor.getState(), Id.EntityState.DELETED);
+
+    }
+
+    @Override
+    protected void assertTestDisconnectUnidirectionalArrayReferenceFromClassType(final List<ITypedReferenceableInstance> columns, final String columnGuid) {
+        Assert.assertEquals(columns.size(), 3);
+        for (ITypedReferenceableInstance column : columns) {
+            if (column.getId()._getId().equals(columnGuid)) {
+                assertEquals(column.getId().getState(), Id.EntityState.DELETED);
+            } else {
+                assertEquals(column.getId().getState(), Id.EntityState.ACTIVE);
+            }
+        }
+    }
+
+    @Override
+    protected void assertTestDisconnectUnidirectionalArrayReferenceFromStructAndTraitTypes(final String structContainerGuid) throws Exception {
+        // Verify that the unidirectional references from the struct and trait instances
+        // to the deleted entities were not disconnected.
+        ITypedReferenceableInstance structContainerConvertedEntity =
+            metadataService.getEntityDefinition(structContainerGuid);
+        ITypedStruct struct = (ITypedStruct) structContainerConvertedEntity.get("struct");
+        assertNotNull(struct.get("target"));
+        IStruct trait = structContainerConvertedEntity.getTrait("TestTrait");
+        assertNotNull(trait);
+        assertNotNull(trait.get("target"));
+
+    }
+
+    @Override
+    protected void assertVerticesDeleted(List<AtlasVertex> vertices) {
+        for (AtlasVertex vertex : vertices) {
+            assertEquals(GraphHelper.getSingleValuedProperty(vertex, Constants.STATE_PROPERTY_KEY, String.class), Id.EntityState.DELETED.name());
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-atlas/blob/aa67f8ae/server-api/src/main/java/org/apache/atlas/RequestContextV1.java
----------------------------------------------------------------------
diff --git a/server-api/src/main/java/org/apache/atlas/RequestContextV1.java b/server-api/src/main/java/org/apache/atlas/RequestContextV1.java
index 23eb4ce..bf73174 100644
--- a/server-api/src/main/java/org/apache/atlas/RequestContextV1.java
+++ b/server-api/src/main/java/org/apache/atlas/RequestContextV1.java
@@ -115,8 +115,8 @@ public class RequestContextV1 {
         return requestTime;
     }
     
-    public boolean isDeletedEntity(String entityGuid) {
-        return deletedEntityIds.contains(entityGuid);
+    public boolean isDeletedEntity(AtlasObjectId entityId) {
+        return deletedEntityIds.contains(entityId);
     }
 
     public static Metrics getMetrics() {


Mime
View raw message