You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@atlas.apache.org by ma...@apache.org on 2017/11/10 05:48:18 UTC

[2/5] atlas git commit: ATLAS-2251: restored bunch of deleted tests

http://git-wip-us.apache.org/repos/asf/atlas/blob/042fc557/repository/src/test/java/org/apache/atlas/repository/store/graph/v1/AtlasRelationshipStoreV1Test.java
----------------------------------------------------------------------
diff --git a/repository/src/test/java/org/apache/atlas/repository/store/graph/v1/AtlasRelationshipStoreV1Test.java b/repository/src/test/java/org/apache/atlas/repository/store/graph/v1/AtlasRelationshipStoreV1Test.java
new file mode 100644
index 0000000..d207a69
--- /dev/null
+++ b/repository/src/test/java/org/apache/atlas/repository/store/graph/v1/AtlasRelationshipStoreV1Test.java
@@ -0,0 +1,623 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.atlas.repository.store.graph.v1;
+
+import com.google.common.collect.ImmutableList;
+import org.apache.atlas.RequestContextV1;
+import org.apache.atlas.TestModules;
+import org.apache.atlas.TestUtilsV2;
+import org.apache.atlas.exception.AtlasBaseException;
+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.AtlasEntityHeader;
+import org.apache.atlas.model.instance.AtlasObjectId;
+import org.apache.atlas.model.instance.AtlasRelatedObjectId;
+import org.apache.atlas.model.instance.EntityMutationResponse;
+import org.apache.atlas.model.typedef.AtlasTypesDef;
+import org.apache.atlas.repository.graph.AtlasGraphProvider;
+import org.apache.atlas.repository.graph.GraphBackedSearchIndexer;
+import org.apache.atlas.repository.store.bootstrap.AtlasTypeDefStoreInitializer;
+import org.apache.atlas.repository.store.graph.AtlasEntityStore;
+import org.apache.atlas.repository.store.graph.AtlasRelationshipStore;
+import org.apache.atlas.store.AtlasTypeDefStore;
+import org.apache.atlas.type.AtlasEntityType;
+import org.apache.atlas.type.AtlasTypeRegistry;
+import org.apache.commons.collections.CollectionUtils;
+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.util.ArrayList;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import static org.apache.atlas.TestRelationshipUtilsV2.EMPLOYEE_TYPE;
+import static org.apache.atlas.TestRelationshipUtilsV2.getDepartmentEmployeeInstances;
+import static org.apache.atlas.TestRelationshipUtilsV2.getDepartmentEmployeeTypes;
+import static org.apache.atlas.TestRelationshipUtilsV2.getInverseReferenceTestTypes;
+import static org.apache.atlas.TestUtilsV2.NAME;
+import static org.apache.atlas.type.AtlasTypeUtil.getAtlasObjectId;
+import static org.mockito.Mockito.mock;
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertNotNull;
+import static org.testng.Assert.assertNull;
+import static org.testng.Assert.assertTrue;
+
+@Guice(modules = TestModules.TestOnlyModule.class)
+public abstract class AtlasRelationshipStoreV1Test {
+
+    @Inject
+    AtlasTypeRegistry typeRegistry;
+
+    @Inject
+    AtlasTypeDefStore typeDefStore;
+
+    @Inject
+    DeleteHandlerV1   deleteHandler;
+
+    @Inject
+    EntityGraphMapper graphMapper;
+
+    AtlasEntityStore          entityStore;
+    AtlasRelationshipStore    relationshipStore;
+    AtlasEntityChangeNotifier mockChangeNotifier = mock(AtlasEntityChangeNotifier.class);
+
+    protected Map<String, AtlasObjectId> employeeNameIdMap = new HashMap<>();
+
+    @BeforeClass
+    public void setUp() throws Exception {
+        new GraphBackedSearchIndexer(typeRegistry);
+
+        // create employee relationship types
+        AtlasTypesDef employeeTypes = getDepartmentEmployeeTypes();
+        typeDefStore.createTypesDef(employeeTypes);
+
+        AtlasEntitiesWithExtInfo employeeInstances = getDepartmentEmployeeInstances();
+        EntityMutationResponse response = entityStore.createOrUpdate(new AtlasEntityStream(employeeInstances), false);
+
+        for (AtlasEntityHeader entityHeader : response.getCreatedEntities()) {
+            employeeNameIdMap.put((String) entityHeader.getAttribute(NAME), getAtlasObjectId(entityHeader));
+        }
+
+        init();
+        AtlasTypesDef typesDef = getInverseReferenceTestTypes();
+
+        AtlasTypesDef typesToCreate = AtlasTypeDefStoreInitializer.getTypesToCreate(typesDef, typeRegistry);
+
+        if (!typesToCreate.isEmpty()) {
+            typeDefStore.createTypesDef(typesToCreate);
+        }
+    }
+
+    @BeforeTest
+    public void init() throws Exception {
+        entityStore       = new AtlasEntityStoreV1(deleteHandler, typeRegistry, mockChangeNotifier, graphMapper);
+        relationshipStore = new AtlasRelationshipStoreV1(typeRegistry);
+
+        RequestContextV1.clear();
+        RequestContextV1.get().setUser(TestUtilsV2.TEST_USER);
+    }
+
+    @AfterClass
+    public void clear() {
+        AtlasGraphProvider.cleanup();
+    }
+
+    @Test
+    public void testDepartmentEmployeeEntitiesUsingRelationship() throws Exception  {
+        AtlasObjectId hrId     = employeeNameIdMap.get("hr");
+        AtlasObjectId maxId    = employeeNameIdMap.get("Max");
+        AtlasObjectId johnId   = employeeNameIdMap.get("John");
+        AtlasObjectId juliusId = employeeNameIdMap.get("Julius");
+        AtlasObjectId janeId   = employeeNameIdMap.get("Jane");
+        AtlasObjectId mikeId   = employeeNameIdMap.get("Mike");
+
+        AtlasEntity hrDept = getEntityFromStore(hrId.getGuid());
+        AtlasEntity max    = getEntityFromStore(maxId.getGuid());
+        AtlasEntity john   = getEntityFromStore(johnId.getGuid());
+        AtlasEntity julius = getEntityFromStore(juliusId.getGuid());
+        AtlasEntity jane   = getEntityFromStore(janeId.getGuid());
+        AtlasEntity mike   = getEntityFromStore(mikeId.getGuid());
+
+        // Department relationship attributes
+        List<AtlasObjectId> deptEmployees = toAtlasObjectIds(hrDept.getRelationshipAttribute("employees"));
+        assertNotNull(deptEmployees);
+        assertEquals(deptEmployees.size(), 5);
+        assertObjectIdsContains(deptEmployees, maxId);
+        assertObjectIdsContains(deptEmployees, johnId);
+        assertObjectIdsContains(deptEmployees, juliusId);
+        assertObjectIdsContains(deptEmployees, janeId);
+        assertObjectIdsContains(deptEmployees, mikeId);
+
+        // Max employee validation
+        AtlasObjectId maxDepartmentId = toAtlasObjectId(max.getRelationshipAttribute("department"));
+        assertNotNull(maxDepartmentId);
+        assertObjectIdEquals(maxDepartmentId, hrId);
+
+        AtlasObjectId maxManagerId = toAtlasObjectId(max.getRelationshipAttribute("manager"));
+        assertNotNull(maxManagerId);
+        assertObjectIdEquals(maxManagerId, janeId);
+
+        List<AtlasObjectId> maxMentorsId = toAtlasObjectIds(max.getRelationshipAttribute("mentors"));
+        assertNotNull(maxMentorsId);
+        assertEquals(maxMentorsId.size(), 1);
+        assertObjectIdEquals(maxMentorsId.get(0), juliusId);
+
+        List<AtlasObjectId> maxMenteesId = toAtlasObjectIds(max.getRelationshipAttribute("mentees"));
+        assertNotNull(maxMenteesId);
+        assertEquals(maxMenteesId.size(), 1);
+        assertObjectIdEquals(maxMenteesId.get(0), johnId);
+
+        List<AtlasObjectId> maxFriendsIds = toAtlasObjectIds(max.getRelationshipAttribute("friends"));
+        assertNotNull(maxFriendsIds);
+        assertEquals(maxFriendsIds.size(), 2);
+        assertObjectIdsContains(maxFriendsIds, mikeId);
+        assertObjectIdsContains(maxFriendsIds, johnId);
+
+        // John Employee validation
+        AtlasObjectId johnDepartmentId = toAtlasObjectId(john.getRelationshipAttribute("department"));
+        assertNotNull(johnDepartmentId);
+        assertObjectIdEquals(johnDepartmentId, hrId);
+
+        AtlasObjectId johnManagerId = toAtlasObjectId(john.getRelationshipAttribute("manager"));
+        assertNotNull(johnManagerId);
+        assertObjectIdEquals(johnManagerId, janeId);
+
+        List<AtlasObjectId> johnMentorIds = toAtlasObjectIds(john.getRelationshipAttribute("mentors"));
+        assertNotNull(johnMentorIds);
+        assertEquals(johnMentorIds.size(), 2);
+        assertObjectIdsContains(johnMentorIds, maxId);
+        assertObjectIdsContains(johnMentorIds, juliusId);
+
+        List<AtlasObjectId> johnMenteesId = toAtlasObjectIds(john.getRelationshipAttribute("mentees"));
+        assertEmpty(johnMenteesId);
+
+        List<AtlasObjectId> johnFriendsIds = toAtlasObjectIds(john.getRelationshipAttribute("friends"));
+        assertNotNull(johnFriendsIds);
+        assertEquals(johnFriendsIds.size(), 2);
+        assertObjectIdsContains(johnFriendsIds, mikeId);
+        assertObjectIdsContains(johnFriendsIds, maxId);
+
+        // Mike Employee validation
+        AtlasObjectId mikeDepartmentId = toAtlasObjectId(mike.getRelationshipAttribute("department"));
+        assertNotNull(mikeDepartmentId);
+        assertObjectIdEquals(mikeDepartmentId, hrId);
+
+        AtlasObjectId mikeManagerId = toAtlasObjectId(mike.getRelationshipAttribute("manager"));
+        assertNotNull(mikeManagerId);
+        assertObjectIdEquals(mikeManagerId, juliusId);
+
+        List<AtlasObjectId> mikeMentorIds = toAtlasObjectIds(mike.getRelationshipAttribute("mentors"));
+        assertEmpty(mikeMentorIds);
+
+        List<AtlasObjectId> mikeMenteesId = toAtlasObjectIds(mike.getRelationshipAttribute("mentees"));
+        assertEmpty(mikeMenteesId);
+
+        List<AtlasObjectId> mikeFriendsIds = toAtlasObjectIds(mike.getRelationshipAttribute("friends"));
+        assertNotNull(mikeFriendsIds);
+        assertEquals(mikeFriendsIds.size(), 2);
+        assertObjectIdsContains(mikeFriendsIds, maxId);
+        assertObjectIdsContains(mikeFriendsIds, johnId);
+
+        // Jane Manager validation
+        AtlasObjectId janeDepartmentId = toAtlasObjectId(jane.getRelationshipAttribute("department"));
+        assertNotNull(janeDepartmentId);
+        assertObjectIdEquals(janeDepartmentId, hrId);
+
+        AtlasObjectId janeManagerId = toAtlasObjectId(jane.getRelationshipAttribute("manager"));
+        assertNull(janeManagerId);
+
+        List<AtlasObjectId> janeMentorIds = toAtlasObjectIds(jane.getRelationshipAttribute("mentors"));
+        assertEmpty(janeMentorIds);
+
+        List<AtlasObjectId> janeMenteesId = toAtlasObjectIds(jane.getRelationshipAttribute("mentees"));
+        assertEmpty(janeMenteesId);
+
+        List<AtlasObjectId> janeSubordinateIds = toAtlasObjectIds(jane.getRelationshipAttribute("subordinates"));
+        assertNotNull(janeSubordinateIds);
+        assertEquals(janeSubordinateIds.size(), 2);
+        assertObjectIdsContains(janeSubordinateIds, maxId);
+        assertObjectIdsContains(janeSubordinateIds, johnId);
+
+        List<AtlasObjectId> janeFriendsIds = toAtlasObjectIds(jane.getRelationshipAttribute("friends"));
+        assertEmpty(janeFriendsIds);
+
+        AtlasObjectId janeSiblingId = toAtlasObjectId(jane.getRelationshipAttribute("sibling"));
+        assertNotNull(janeSiblingId);
+        assertObjectIdEquals(janeSiblingId, juliusId);
+
+        // Julius Manager validation
+        AtlasObjectId juliusDepartmentId = toAtlasObjectId(julius.getRelationshipAttribute("department"));
+        assertNotNull(juliusDepartmentId);
+        assertObjectIdEquals(juliusDepartmentId, hrId);
+
+        AtlasObjectId juliusManagerId = toAtlasObjectId(julius.getRelationshipAttribute("manager"));
+        assertNull(juliusManagerId);
+
+        List<AtlasObjectId> juliusMentorIds = toAtlasObjectIds(julius.getRelationshipAttribute("mentors"));
+        assertEmpty(juliusMentorIds);
+
+        List<AtlasObjectId> juliusMenteesId = toAtlasObjectIds(julius.getRelationshipAttribute("mentees"));
+        assertNotNull(juliusMenteesId);
+        assertEquals(juliusMenteesId.size(), 2);
+        assertObjectIdsContains(juliusMenteesId, maxId);
+        assertObjectIdsContains(juliusMenteesId, johnId);
+
+        List<AtlasObjectId> juliusSubordinateIds = toAtlasObjectIds(julius.getRelationshipAttribute("subordinates"));
+        assertNotNull(juliusSubordinateIds);
+        assertEquals(juliusSubordinateIds.size(), 1);
+        assertObjectIdsContains(juliusSubordinateIds, mikeId);
+
+        List<AtlasObjectId> juliusFriendsIds = toAtlasObjectIds(julius.getRelationshipAttribute("friends"));
+        assertEmpty(juliusFriendsIds);
+
+        AtlasObjectId juliusSiblingId = toAtlasObjectId(julius.getRelationshipAttribute("sibling"));
+        assertNotNull(juliusSiblingId);
+        assertObjectIdEquals(juliusSiblingId, janeId);
+    }
+
+    // Seeing intermittent failures with janus profile, disabling it until its fixed.
+    @Test(enabled = false)
+    public void testRelationshipAttributeUpdate_NonComposite_OneToMany() throws Exception {
+        AtlasObjectId maxId    = employeeNameIdMap.get("Max");
+        AtlasObjectId juliusId = employeeNameIdMap.get("Julius");
+        AtlasObjectId janeId   = employeeNameIdMap.get("Jane");
+        AtlasObjectId mikeId   = employeeNameIdMap.get("Mike");
+        AtlasObjectId johnId   = employeeNameIdMap.get("John");
+
+        // Change Max's Employee.manager reference to Julius and apply the change as a partial update.
+        // This should also update Julius to add Max to the inverse Manager.subordinates reference.
+        AtlasEntity maxEntityForUpdate = new AtlasEntity(EMPLOYEE_TYPE);
+        maxEntityForUpdate.setRelationshipAttribute("manager", juliusId);
+
+        AtlasEntityType        employeeType   = typeRegistry.getEntityTypeByName(EMPLOYEE_TYPE);
+        Map<String, Object>    uniqAttributes = Collections.<String, Object>singletonMap("name", "Max");
+        EntityMutationResponse updateResponse = entityStore.updateByUniqueAttributes(employeeType, uniqAttributes , new AtlasEntityWithExtInfo(maxEntityForUpdate));
+
+        List<AtlasEntityHeader> partialUpdatedEntities = updateResponse.getPartialUpdatedEntities();
+        assertEquals(partialUpdatedEntities.size(), 3);
+        // 3 entities should have been updated:
+        // * Max to change the Employee.manager reference
+        // * Julius to add Max to Manager.subordinates
+        // * Jane to remove Max from Manager.subordinates
+
+        AtlasEntitiesWithExtInfo updatedEntities = entityStore.getByIds(ImmutableList.of(maxId.getGuid(), juliusId.getGuid(), janeId.getGuid()));
+
+        // Max's manager updated as Julius
+        AtlasEntity maxEntity = updatedEntities.getEntity(maxId.getGuid());
+        verifyRelationshipAttributeValue(maxEntity, "manager", juliusId.getGuid());
+
+        // Max added to the subordinate list of Julius, existing subordinate is Mike
+        AtlasEntity juliusEntity = updatedEntities.getEntity(juliusId.getGuid());
+        verifyRelationshipAttributeList(juliusEntity, "subordinates", ImmutableList.of(maxId, mikeId));
+
+        // Max removed from the subordinate list of Julius
+        AtlasEntity janeEntity = updatedEntities.getEntity(janeId.getGuid());
+
+        // Jane's subordinates list includes John and Max for soft delete
+        // Jane's subordinates list includes only John for hard delete
+        verifyRelationshipAttributeUpdate_NonComposite_OneToMany(janeEntity);
+
+        // Remove Mike from Max's friends list
+        // Max's current friends: [Mike, John]
+        // Max's updated friends: [Julius, John]
+        maxEntityForUpdate = new AtlasEntity(EMPLOYEE_TYPE);
+        maxEntityForUpdate.setRelationshipAttribute("friends", ImmutableList.of(johnId, juliusId));
+
+        init();
+        updateResponse = entityStore.updateByUniqueAttributes(employeeType, uniqAttributes , new AtlasEntityWithExtInfo(maxEntityForUpdate));
+
+        partialUpdatedEntities = updateResponse.getPartialUpdatedEntities();
+        assertEquals(partialUpdatedEntities.size(), 3);
+        // 3 entities should have been updated:
+        // * Max added Julius and removed Mike from Employee.friends
+        // * Mike removed Max from Employee.friends
+        // * Julius added Max in Employee.friends
+
+        updatedEntities = entityStore.getByIds(ImmutableList.of(maxId.getGuid(), mikeId.getGuid(), johnId.getGuid(), juliusId.getGuid()));
+
+        maxEntity    = updatedEntities.getEntity(maxId.getGuid());
+        juliusEntity = updatedEntities.getEntity(juliusId.getGuid());
+        AtlasEntity mikeEntity = updatedEntities.getEntity(mikeId.getGuid());
+        AtlasEntity johnEntity = updatedEntities.getEntity(johnId.getGuid());
+
+        verifyRelationshipAttributeUpdate_ManyToMany_Friends(maxEntity, juliusEntity, mikeEntity, johnEntity);
+
+        // Remove Julius from Jane's sibling and add Mike as new sibling
+        AtlasEntity juliusEntityForUpdate = new AtlasEntity(EMPLOYEE_TYPE);
+        juliusEntityForUpdate.setRelationshipAttribute("sibling", mikeId);
+
+        init();
+        updateResponse = entityStore.updateByUniqueAttributes(employeeType, Collections.<String, Object>singletonMap("name", "Julius") , new AtlasEntityWithExtInfo(juliusEntityForUpdate));
+        partialUpdatedEntities = updateResponse.getPartialUpdatedEntities();
+        assertEquals(partialUpdatedEntities.size(), 3);
+
+        updatedEntities = entityStore.getByIds(ImmutableList.of(juliusId.getGuid(), janeId.getGuid(), mikeId.getGuid()));
+
+        juliusEntity = updatedEntities.getEntity(juliusId.getGuid());
+        janeEntity   = updatedEntities.getEntity(janeId.getGuid());
+        mikeEntity   = updatedEntities.getEntity(mikeId.getGuid());
+
+        verifyRelationshipAttributeUpdate_OneToOne_Sibling(juliusEntity, janeEntity, mikeEntity);
+    }
+
+    @Test
+    public void testRelationshipAttributeUpdate_NonComposite_ManyToOne() throws Exception {
+        AtlasEntity a1 = new AtlasEntity("A");
+        a1.setAttribute(NAME, "a1_name");
+
+        AtlasEntity a2 = new AtlasEntity("A");
+        a2.setAttribute(NAME, "a2_name");
+
+        AtlasEntity a3 = new AtlasEntity("A");
+        a3.setAttribute(NAME, "a3_name");
+
+        AtlasEntity b = new AtlasEntity("B");
+        b.setAttribute(NAME, "b_name");
+
+        AtlasEntitiesWithExtInfo entitiesWithExtInfo = new AtlasEntitiesWithExtInfo();
+        entitiesWithExtInfo.addEntity(a1);
+        entitiesWithExtInfo.addEntity(a2);
+        entitiesWithExtInfo.addEntity(a3);
+        entitiesWithExtInfo.addEntity(b);
+        entityStore.createOrUpdate(new AtlasEntityStream(entitiesWithExtInfo) , false);
+
+        AtlasEntity bPartialUpdate = new AtlasEntity("B");
+        bPartialUpdate.setRelationshipAttribute("manyA", ImmutableList.of(getAtlasObjectId(a1), getAtlasObjectId(a2)));
+
+        init();
+        EntityMutationResponse response = entityStore.updateByUniqueAttributes(typeRegistry.getEntityTypeByName("B"),
+                                                                               Collections.singletonMap(NAME, b.getAttribute(NAME)),
+                                                                               new AtlasEntityWithExtInfo(bPartialUpdate));
+        // Verify 3 entities were updated:
+        // * set b.manyA reference to a1 and a2
+        // * set inverse a1.oneB reference to b
+        // * set inverse a2.oneB reference to b
+        assertEquals(response.getPartialUpdatedEntities().size(), 3);
+        AtlasEntitiesWithExtInfo updatedEntities = entityStore.getByIds(ImmutableList.of(a1.getGuid(), a2.getGuid(), b.getGuid()));
+
+        AtlasEntity a1Entity = updatedEntities.getEntity(a1.getGuid());
+        verifyRelationshipAttributeValue(a1Entity, "oneB", b.getGuid());
+
+        AtlasEntity a2Entity = updatedEntities.getEntity(a2.getGuid());
+        verifyRelationshipAttributeValue(a2Entity, "oneB", b.getGuid());
+
+        AtlasEntity bEntity = updatedEntities.getEntity(b.getGuid());
+        verifyRelationshipAttributeList(bEntity, "manyA", ImmutableList.of(getAtlasObjectId(a1), getAtlasObjectId(a2)));
+
+
+        bPartialUpdate.setRelationshipAttribute("manyA", ImmutableList.of(getAtlasObjectId(a3)));
+        init();
+        response = entityStore.updateByUniqueAttributes(typeRegistry.getEntityTypeByName("B"),
+                                                        Collections.singletonMap(NAME, b.getAttribute(NAME)),
+                                                        new AtlasEntityWithExtInfo(bPartialUpdate));
+        // Verify 4 entities were updated:
+        // * set b.manyA reference to a3
+        // * set inverse a3.oneB reference to b
+        // * disconnect inverse a1.oneB reference to b
+        // * disconnect inverse a2.oneB reference to b
+        assertEquals(response.getPartialUpdatedEntities().size(), 4);
+        init();
+
+        updatedEntities = entityStore.getByIds(ImmutableList.of(a1.getGuid(), a2.getGuid(), a3.getGuid(), b.getGuid()));
+        a1Entity        = updatedEntities.getEntity(a1.getGuid());
+        a2Entity        = updatedEntities.getEntity(a2.getGuid());
+        bEntity         = updatedEntities.getEntity(b.getGuid());
+
+        AtlasEntity a3Entity = updatedEntities.getEntity(a3.getGuid());
+        verifyRelationshipAttributeValue(a3Entity, "oneB", b.getGuid());
+
+        verifyRelationshipAttributeUpdate_NonComposite_ManyToOne(a1Entity, a2Entity, a3Entity, bEntity);
+    }
+
+    @Test
+    public void testRelationshipAttributeUpdate_NonComposite_OneToOne() throws Exception {
+        AtlasEntity a1 = new AtlasEntity("A");
+        a1.setAttribute(NAME, "a1_name");
+
+        AtlasEntity a2 = new AtlasEntity("A");
+        a2.setAttribute(NAME, "a2_name");
+
+        AtlasEntity b = new AtlasEntity("B");
+        b.setAttribute(NAME, "b_name");
+
+        AtlasEntitiesWithExtInfo entitiesWithExtInfo = new AtlasEntitiesWithExtInfo();
+        entitiesWithExtInfo.addEntity(a1);
+        entitiesWithExtInfo.addEntity(a2);
+        entitiesWithExtInfo.addEntity(b);
+
+        EntityMutationResponse response = entityStore.createOrUpdate(new AtlasEntityStream(entitiesWithExtInfo) , false);
+
+        AtlasEntity partialUpdateB = new AtlasEntity("B");
+        partialUpdateB.setRelationshipAttribute("a", getAtlasObjectId(a1));
+
+        init();
+        AtlasEntityType bType = typeRegistry.getEntityTypeByName("B");
+
+        response = entityStore.updateByUniqueAttributes(bType, Collections.singletonMap(NAME, b.getAttribute(NAME)), new AtlasEntityWithExtInfo(partialUpdateB));
+        List<AtlasEntityHeader> partialUpdatedEntitiesHeader = response.getPartialUpdatedEntities();
+        // Verify 2 entities were updated:
+        // * set b.a reference to a1
+        // * set inverse a1.b reference to b
+        assertEquals(partialUpdatedEntitiesHeader.size(), 2);
+        AtlasEntitiesWithExtInfo partialUpdatedEntities = entityStore.getByIds(ImmutableList.of(a1.getGuid(), b.getGuid()));
+
+        AtlasEntity a1Entity = partialUpdatedEntities.getEntity(a1.getGuid());
+        verifyRelationshipAttributeValue(a1Entity, "b", b.getGuid());
+
+        AtlasEntity bEntity = partialUpdatedEntities.getEntity(b.getGuid());
+        verifyRelationshipAttributeValue(bEntity, "a", a1.getGuid());
+
+        init();
+
+        // Update b.a to reference a2.
+        partialUpdateB.setRelationshipAttribute("a", getAtlasObjectId(a2));
+        response = entityStore.updateByUniqueAttributes(bType, Collections.<String, Object>singletonMap(NAME, b.getAttribute(NAME)), new AtlasEntityWithExtInfo(partialUpdateB));
+        partialUpdatedEntitiesHeader = response.getPartialUpdatedEntities();
+        // Verify 3 entities were updated:
+        // * set b.a reference to a2
+        // * set a2.b reference to b
+        // * disconnect a1.b reference
+        assertEquals(partialUpdatedEntitiesHeader.size(), 3);
+        partialUpdatedEntities = entityStore.getByIds(ImmutableList.of(a1.getGuid(), a2.getGuid(), b.getGuid()));
+
+        bEntity = partialUpdatedEntities.getEntity(b.getGuid());
+        verifyRelationshipAttributeValue(bEntity, "a", a2.getGuid());
+
+        AtlasEntity a2Entity = partialUpdatedEntities.getEntity(a2.getGuid());
+        verifyRelationshipAttributeValue(a2Entity, "b", b.getGuid());
+
+        a1Entity = partialUpdatedEntities.getEntity(a1.getGuid());
+        verifyRelationshipAttributeUpdate_NonComposite_OneToOne(a1Entity, bEntity);
+    }
+
+    @Test
+    public void testRelationshipAttributeUpdate_NonComposite_ManyToMany() throws Exception {
+        AtlasEntity a1 = new AtlasEntity("A");
+        a1.setAttribute(NAME, "a1_name");
+
+        AtlasEntity a2 = new AtlasEntity("A");
+        a2.setAttribute(NAME, "a2_name");
+
+        AtlasEntity a3 = new AtlasEntity("A");
+        a3.setAttribute(NAME, "a3_name");
+
+        AtlasEntity b1 = new AtlasEntity("B");
+        b1.setAttribute(NAME, "b1_name");
+
+        AtlasEntity b2 = new AtlasEntity("B");
+        b2.setAttribute(NAME, "b2_name");
+
+        AtlasEntitiesWithExtInfo entitiesWithExtInfo = new AtlasEntitiesWithExtInfo();
+        entitiesWithExtInfo.addEntity(a1);
+        entitiesWithExtInfo.addEntity(a2);
+        entitiesWithExtInfo.addEntity(a3);
+        entitiesWithExtInfo.addEntity(b1);
+        entitiesWithExtInfo.addEntity(b2);
+        entityStore.createOrUpdate(new AtlasEntityStream(entitiesWithExtInfo) , false);
+
+        AtlasEntity b1PartialUpdate = new AtlasEntity("B");
+        b1PartialUpdate.setRelationshipAttribute("manyToManyA", ImmutableList.of(getAtlasObjectId(a1), getAtlasObjectId(a2)));
+
+        init();
+        EntityMutationResponse response = entityStore.updateByUniqueAttributes(typeRegistry.getEntityTypeByName("B"),
+                                                                               Collections.singletonMap(NAME, b1.getAttribute(NAME)),
+                                                                               new AtlasEntityWithExtInfo(b1PartialUpdate));
+
+        List<AtlasEntityHeader> updatedEntityHeaders = response.getPartialUpdatedEntities();
+        assertEquals(updatedEntityHeaders.size(), 3);
+
+        AtlasEntitiesWithExtInfo updatedEntities = entityStore.getByIds(ImmutableList.of(a1.getGuid(), a2.getGuid(), b1.getGuid()));
+
+        AtlasEntity b1Entity = updatedEntities.getEntity(b1.getGuid());
+        verifyRelationshipAttributeList(b1Entity, "manyToManyA", ImmutableList.of(getAtlasObjectId(a1), getAtlasObjectId(a2)));
+
+        AtlasEntity a1Entity = updatedEntities.getEntity(a1.getGuid());
+        verifyRelationshipAttributeList(a1Entity, "manyB", ImmutableList.of(getAtlasObjectId(b1)));
+
+        AtlasEntity a2Entity = updatedEntities.getEntity(a2.getGuid());
+        verifyRelationshipAttributeList(a2Entity, "manyB", ImmutableList.of(getAtlasObjectId(b1)));
+    }
+
+    protected abstract void verifyRelationshipAttributeUpdate_NonComposite_OneToOne(AtlasEntity a1, AtlasEntity b);
+
+    protected abstract void verifyRelationshipAttributeUpdate_NonComposite_OneToMany(AtlasEntity entity) throws Exception;
+
+    protected abstract void verifyRelationshipAttributeUpdate_NonComposite_ManyToOne(AtlasEntity a1, AtlasEntity a2, AtlasEntity a3, AtlasEntity b);
+
+    protected abstract void verifyRelationshipAttributeUpdate_ManyToMany_Friends(AtlasEntity e1, AtlasEntity e2, AtlasEntity e3, AtlasEntity e4) throws Exception;
+
+    protected abstract void verifyRelationshipAttributeUpdate_OneToOne_Sibling(AtlasEntity e1, AtlasEntity e2, AtlasEntity e3) throws Exception;
+
+    protected static void assertObjectIdsContains(List<AtlasObjectId> objectIds, AtlasObjectId objectId) {
+        assertTrue(CollectionUtils.isNotEmpty(objectIds));
+        assertTrue(objectIds.contains(objectId));
+    }
+
+    protected static void assertObjectIdEquals(AtlasObjectId objId1, AtlasObjectId objId2) {
+        assertTrue(objId1.equals(objId2));
+    }
+
+    private static void assertEmpty(List collection) {
+        assertTrue(collection != null && collection.isEmpty());
+    }
+
+    protected static List<AtlasObjectId> toAtlasObjectIds(Object object) {
+        List<AtlasObjectId> ret = new ArrayList<>();
+
+        if (object instanceof List) {
+            List<?> objectIds = (List) object;
+
+            if (CollectionUtils.isNotEmpty(objectIds)) {
+                for (Object obj : objectIds) {
+                    if (obj instanceof AtlasRelatedObjectId) {
+                        AtlasRelatedObjectId relatedObjectId = (AtlasRelatedObjectId) obj;
+                        ret.add(new AtlasObjectId(relatedObjectId.getGuid(), relatedObjectId.getTypeName(), relatedObjectId.getUniqueAttributes()));
+                    }
+                }
+            }
+        }
+
+        return ret;
+    }
+
+    protected static AtlasObjectId toAtlasObjectId(Object object) {
+        if (object instanceof AtlasRelatedObjectId) {
+            AtlasRelatedObjectId relatedObjectId = (AtlasRelatedObjectId) object;
+            return new AtlasObjectId(relatedObjectId.getGuid(), relatedObjectId.getTypeName(), relatedObjectId.getUniqueAttributes());
+        }
+
+        return null;
+    }
+
+    private AtlasEntity getEntityFromStore(String guid) throws AtlasBaseException {
+        AtlasEntityWithExtInfo entity = guid != null ? entityStore.getById(guid) : null;
+
+        return entity != null ? entity.getEntity() : null;
+    }
+
+    protected static void verifyRelationshipAttributeList(AtlasEntity entity, String relationshipAttrName, List<AtlasObjectId> expectedValues) {
+        Object refValue = entity.getRelationshipAttribute(relationshipAttrName);
+        assertTrue(refValue instanceof List);
+
+        List<AtlasObjectId> refList = toAtlasObjectIds(refValue);
+        assertEquals(refList.size(), expectedValues.size());
+
+        if (expectedValues.size() > 0) {
+            assertTrue(refList.containsAll(expectedValues));
+        }
+    }
+
+    protected static void verifyRelationshipAttributeValue(AtlasEntity entity, String relationshipAttrName, String expectedGuid) {
+        Object refValue = entity.getRelationshipAttribute(relationshipAttrName);
+        if (expectedGuid == null) {
+            assertNull(refValue);
+        }
+        else {
+            assertTrue(refValue instanceof AtlasObjectId);
+            AtlasObjectId referencedObjectId = (AtlasObjectId) refValue;
+            assertEquals(referencedObjectId.getGuid(), expectedGuid);
+        }
+    }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/atlas/blob/042fc557/repository/src/test/java/org/apache/atlas/repository/store/graph/v1/InverseReferenceUpdateHardDeleteV1Test.java
----------------------------------------------------------------------
diff --git a/repository/src/test/java/org/apache/atlas/repository/store/graph/v1/InverseReferenceUpdateHardDeleteV1Test.java b/repository/src/test/java/org/apache/atlas/repository/store/graph/v1/InverseReferenceUpdateHardDeleteV1Test.java
new file mode 100644
index 0000000..d54adeb
--- /dev/null
+++ b/repository/src/test/java/org/apache/atlas/repository/store/graph/v1/InverseReferenceUpdateHardDeleteV1Test.java
@@ -0,0 +1,75 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.atlas.repository.store.graph.v1;
+
+import com.google.common.collect.ImmutableList;
+import org.apache.atlas.TestModules;
+import org.apache.atlas.model.instance.AtlasEntity;
+import org.apache.atlas.model.instance.AtlasObjectId;
+import org.apache.atlas.type.AtlasTypeUtil;
+import org.testng.annotations.Guice;
+
+import java.util.Map;
+
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertTrue;
+
+/**
+ * Inverse reference update test with {@link HardDeleteHandlerV1}
+ */
+@Guice(modules = TestModules.HardDeleteModule.class)
+public class InverseReferenceUpdateHardDeleteV1Test extends InverseReferenceUpdateV1Test {
+
+    @Override
+    protected void verify_testInverseReferenceAutoUpdate_NonComposite_OneToMany(AtlasEntity jane) throws Exception {
+
+        // Max should have been removed from the subordinates list, leaving only John.
+        verifyReferenceList(jane, "subordinates", ImmutableList.of(nameIdMap.get("John")));
+    }
+
+    @Override
+    protected void verify_testInverseReferenceAutoUpdate_NonCompositeManyToOne(AtlasEntity a1, AtlasEntity a2, AtlasEntity a3, AtlasEntity b) {
+
+        verifyReferenceValue(a1, "oneB", null);
+
+        verifyReferenceValue(a2, "oneB", null);
+
+        verifyReferenceList(b, "manyA", ImmutableList.of(AtlasTypeUtil.getAtlasObjectId(a3)));
+    }
+
+    @Override
+    protected void verify_testInverseReferenceAutoUpdate_NonComposite_OneToOne(AtlasEntity a1, AtlasEntity b) {
+
+        verifyReferenceValue(a1, "b", null);
+    }
+
+    @Override
+    protected void verify_testInverseReferenceAutoUpdate_Map(AtlasEntity a1, AtlasEntity b1,
+        AtlasEntity b2, AtlasEntity b3) {
+
+        Object value = a1.getAttribute("mapToB");
+        assertTrue(value instanceof Map);
+        Map<String, AtlasObjectId> refMap = (Map<String, AtlasObjectId>) value;
+        assertEquals(refMap.size(), 1);
+        AtlasObjectId referencedEntityId = refMap.get("b3");
+        assertEquals(referencedEntityId, AtlasTypeUtil.getAtlasObjectId(b3));
+        verifyReferenceValue(b1, "mappedFromA", null);
+        verifyReferenceValue(b2, "mappedFromA", null);
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/atlas/blob/042fc557/repository/src/test/java/org/apache/atlas/repository/store/graph/v1/InverseReferenceUpdateSoftDeleteV1Test.java
----------------------------------------------------------------------
diff --git a/repository/src/test/java/org/apache/atlas/repository/store/graph/v1/InverseReferenceUpdateSoftDeleteV1Test.java b/repository/src/test/java/org/apache/atlas/repository/store/graph/v1/InverseReferenceUpdateSoftDeleteV1Test.java
new file mode 100644
index 0000000..884ab54
--- /dev/null
+++ b/repository/src/test/java/org/apache/atlas/repository/store/graph/v1/InverseReferenceUpdateSoftDeleteV1Test.java
@@ -0,0 +1,78 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.atlas.repository.store.graph.v1;
+
+import com.google.common.collect.ImmutableList;
+import org.apache.atlas.TestModules;
+import org.apache.atlas.model.instance.AtlasEntity;
+import org.apache.atlas.model.instance.AtlasObjectId;
+import org.apache.atlas.type.AtlasTypeUtil;
+import org.testng.annotations.Guice;
+
+import java.util.Map;
+
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertTrue;
+
+
+/**
+ * Inverse reference update test with {@link SoftDeleteHandlerV1}
+ */
+@Guice(modules = TestModules.SoftDeleteModule.class)
+public class InverseReferenceUpdateSoftDeleteV1Test extends InverseReferenceUpdateV1Test {
+
+    @Override
+    protected void verify_testInverseReferenceAutoUpdate_NonComposite_OneToMany(AtlasEntity jane)
+        throws Exception {
+
+        // Max is still in the subordinates list, as the edge still exists with state DELETED
+        verifyReferenceList(jane, "subordinates", ImmutableList.of(nameIdMap.get("John"), nameIdMap.get("Max")));
+    }
+
+    @Override
+    protected void verify_testInverseReferenceAutoUpdate_NonCompositeManyToOne(AtlasEntity a1,
+        AtlasEntity a2, AtlasEntity a3, AtlasEntity b) {
+
+        verifyReferenceValue(a1, "oneB", b.getGuid());
+
+        verifyReferenceValue(a2, "oneB", b.getGuid());
+
+        verifyReferenceList(b, "manyA", ImmutableList.of(AtlasTypeUtil.getAtlasObjectId(a1), AtlasTypeUtil.getAtlasObjectId(a2), AtlasTypeUtil.getAtlasObjectId(a3)));
+    }
+
+    @Override
+    protected void verify_testInverseReferenceAutoUpdate_NonComposite_OneToOne(AtlasEntity a1, AtlasEntity b) {
+
+        verifyReferenceValue(a1, "b", b.getGuid());
+    }
+
+    @Override
+    protected void verify_testInverseReferenceAutoUpdate_Map(AtlasEntity a1, AtlasEntity b1,
+        AtlasEntity b2, AtlasEntity b3) {
+
+        Object value = a1.getAttribute("mapToB");
+        assertTrue(value instanceof Map);
+        Map<String, AtlasObjectId> refMap = (Map<String, AtlasObjectId>) value;
+        assertEquals(refMap.size(), 3);
+        AtlasObjectId referencedEntityId = refMap.get("b3");
+        assertEquals(referencedEntityId, AtlasTypeUtil.getAtlasObjectId(b3));
+        verifyReferenceValue(b1, "mappedFromA", a1.getGuid());
+        verifyReferenceValue(b2, "mappedFromA", a1.getGuid());
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/atlas/blob/042fc557/repository/src/test/java/org/apache/atlas/repository/store/graph/v1/InverseReferenceUpdateV1Test.java
----------------------------------------------------------------------
diff --git a/repository/src/test/java/org/apache/atlas/repository/store/graph/v1/InverseReferenceUpdateV1Test.java b/repository/src/test/java/org/apache/atlas/repository/store/graph/v1/InverseReferenceUpdateV1Test.java
new file mode 100644
index 0000000..2c21638
--- /dev/null
+++ b/repository/src/test/java/org/apache/atlas/repository/store/graph/v1/InverseReferenceUpdateV1Test.java
@@ -0,0 +1,374 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.atlas.repository.store.graph.v1;
+
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableMap;
+import org.apache.atlas.RequestContextV1;
+import org.apache.atlas.TestUtilsV2;
+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.AtlasEntityHeader;
+import org.apache.atlas.model.instance.AtlasObjectId;
+import org.apache.atlas.model.instance.EntityMutationResponse;
+import org.apache.atlas.model.typedef.AtlasTypesDef;
+import org.apache.atlas.repository.graph.AtlasGraphProvider;
+import org.apache.atlas.repository.store.bootstrap.AtlasTypeDefStoreInitializer;
+import org.apache.atlas.repository.store.graph.AtlasEntityStore;
+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.testng.annotations.AfterClass;
+import org.testng.annotations.BeforeClass;
+import org.testng.annotations.BeforeMethod;
+import org.testng.annotations.Test;
+
+import javax.inject.Inject;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertNull;
+import static org.testng.Assert.assertTrue;
+
+import static org.apache.atlas.TestUtilsV2.NAME;
+
+/**
+ * Test automatic inverse reference updating in V1 (V2?) code path.
+ *
+ */
+public abstract class InverseReferenceUpdateV1Test {
+    @Inject
+    AtlasTypeRegistry typeRegistry;
+
+    @Inject
+    AtlasTypeDefStore typeDefStore;
+
+    @Inject
+    AtlasEntityStore entityStore;
+
+    private AtlasEntitiesWithExtInfo deptEntity;
+
+    protected Map<String, AtlasObjectId> nameIdMap = new HashMap<>();
+
+    @BeforeClass
+    public void setUp() throws Exception {
+        RequestContextV1.clear();
+        RequestContextV1.get().setUser(TestUtilsV2.TEST_USER);
+
+        AtlasTypesDef[] testTypesDefs = new AtlasTypesDef[] { TestUtilsV2.defineDeptEmployeeTypes(),
+                                                              TestUtilsV2.defineInverseReferenceTestTypes()
+                                                            };
+
+        for (AtlasTypesDef typesDef : testTypesDefs) {
+            AtlasTypesDef typesToCreate = AtlasTypeDefStoreInitializer.getTypesToCreate(typesDef, typeRegistry);
+
+            if (!typesToCreate.isEmpty()) {
+                typeDefStore.createTypesDef(typesToCreate);
+            }
+        }
+
+        deptEntity = TestUtilsV2.createDeptEg2();
+        init();
+        EntityMutationResponse response = entityStore.createOrUpdate(new AtlasEntityStream(deptEntity), false);
+        for (AtlasEntityHeader entityHeader : response.getCreatedEntities()) {
+            nameIdMap.put((String)entityHeader.getAttribute(NAME), AtlasTypeUtil.getAtlasObjectId(entityHeader));
+        }
+    }
+
+    @AfterClass
+    public void clear() {
+        AtlasGraphProvider.cleanup();
+    }
+
+    @BeforeMethod
+    public void init() throws Exception {
+        RequestContextV1.clear();
+        RequestContextV1.get().setUser(TestUtilsV2.TEST_USER);
+    }
+
+    @Test
+    public void testInverseReferenceAutoUpdate_NonComposite_OneToMany() throws Exception {
+        AtlasObjectId juliusId = nameIdMap.get("Julius");
+
+        // Change Max's Employee.manager reference to Julius and apply the change as a partial update.
+        // This should also update Julius to add Max to the inverse Manager.subordinates reference.
+        AtlasEntity maxEntityForUpdate = new AtlasEntity(TestUtilsV2.EMPLOYEE_TYPE);
+        maxEntityForUpdate.setAttribute("manager", juliusId);
+        AtlasEntityType employeeType = typeRegistry.getEntityTypeByName(TestUtilsV2.EMPLOYEE_TYPE);
+        Map<String, Object> uniqAttributes = Collections.<String, Object>singletonMap("name", "Max");
+        EntityMutationResponse updateResponse = entityStore.updateByUniqueAttributes(employeeType, uniqAttributes , new AtlasEntityWithExtInfo(maxEntityForUpdate));
+        List<AtlasEntityHeader> partialUpdatedEntities = updateResponse.getPartialUpdatedEntities();
+        // 3 entities should have been updated:
+        // * Max to change the Employee.manager reference
+        // * Julius to add Max to Manager.subordinates
+        // * Jane to remove Max from Manager.subordinates
+        assertEquals(partialUpdatedEntities.size(), 3);
+
+        AtlasObjectId maxId = nameIdMap.get("Max");
+        String janeGuid = nameIdMap.get("Jane").getGuid();
+        AtlasEntitiesWithExtInfo storedEntities = entityStore.getByIds(ImmutableList.of(maxId.getGuid(), juliusId.getGuid(), janeGuid));
+        AtlasEntity storedEntity = storedEntities.getEntity(maxId.getGuid());
+        verifyReferenceValue(storedEntity, "manager", juliusId.getGuid());
+        storedEntity = storedEntities.getEntity(juliusId.getGuid());
+        verifyReferenceList(storedEntity, "subordinates", ImmutableList.of(maxId));
+        storedEntity = storedEntities.getEntity(janeGuid);
+        verify_testInverseReferenceAutoUpdate_NonComposite_OneToMany(storedEntity);
+    }
+
+    protected abstract void verify_testInverseReferenceAutoUpdate_NonComposite_OneToMany(AtlasEntity jane) throws Exception;
+
+    @Test
+    public void testInverseReferenceAutoUpdate_NonCompositeManyToOne() throws Exception {
+        AtlasEntityType bType = typeRegistry.getEntityTypeByName("B");
+        AtlasEntity a1 = new AtlasEntity("A");
+        a1.setAttribute(NAME, TestUtilsV2.randomString());
+        AtlasEntity a2 = new AtlasEntity("A");
+        a2.setAttribute(NAME, TestUtilsV2.randomString());
+        AtlasEntity a3 = new AtlasEntity("A");
+        a3.setAttribute(NAME, TestUtilsV2.randomString());
+        AtlasEntity b = new AtlasEntity("B");
+
+        b.setAttribute(NAME, TestUtilsV2.randomString());
+        AtlasEntitiesWithExtInfo atlasEntitiesWithExtInfo = new AtlasEntitiesWithExtInfo();
+        atlasEntitiesWithExtInfo.addEntity(a1);
+        atlasEntitiesWithExtInfo.addEntity(a2);
+        atlasEntitiesWithExtInfo.addEntity(a3);
+        atlasEntitiesWithExtInfo.addEntity(b);
+        AtlasEntityStream entityStream = new AtlasEntityStream(atlasEntitiesWithExtInfo);
+        EntityMutationResponse response = entityStore.createOrUpdate(entityStream , false);
+
+        AtlasEntity bForPartialUpdate = new AtlasEntity("B");
+        bForPartialUpdate.setAttribute("manyA", ImmutableList.of(AtlasTypeUtil.getAtlasObjectId(a1), AtlasTypeUtil.getAtlasObjectId(a2)));
+        init();
+        response = entityStore.updateByUniqueAttributes(bType, Collections.<String, Object>singletonMap(NAME, b.getAttribute(NAME)), new AtlasEntityWithExtInfo(bForPartialUpdate));
+        List<AtlasEntityHeader> partialUpdatedEntities = response.getPartialUpdatedEntities();
+        // Verify 3 entities were updated:
+        // * set b.manyA reference to a1 and a2
+        // * set inverse a1.oneB reference to b
+        // * set inverse a2.oneB reference to b
+        assertEquals(partialUpdatedEntities.size(), 3);
+        AtlasEntitiesWithExtInfo storedEntities = entityStore.getByIds(ImmutableList.of(a1.getGuid(), a2.getGuid(), b.getGuid()));
+        AtlasEntity storedEntity = storedEntities.getEntity(a1.getGuid());
+        verifyReferenceValue(storedEntity, "oneB", b.getGuid());
+
+        storedEntity = storedEntities.getEntity(a2.getGuid());
+        verifyReferenceValue(storedEntity, "oneB", b.getGuid());
+
+        storedEntity = storedEntities.getEntity(b.getGuid());
+        verifyReferenceList(storedEntity, "manyA", ImmutableList.of(AtlasTypeUtil.getAtlasObjectId(a1), AtlasTypeUtil.getAtlasObjectId(a2)));
+
+        bForPartialUpdate.setAttribute("manyA", ImmutableList.of(AtlasTypeUtil.getAtlasObjectId(a3)));
+        init();
+        response = entityStore.updateByUniqueAttributes(bType, Collections.<String, Object>singletonMap(NAME, b.getAttribute(NAME)), new AtlasEntityWithExtInfo(bForPartialUpdate));
+        partialUpdatedEntities = response.getPartialUpdatedEntities();
+        // Verify 4 entities were updated:
+        // * set b.manyA reference to a3
+        // * set inverse a3.oneB reference to b
+        // * disconnect inverse a1.oneB reference to b
+        // * disconnect inverse a2.oneB reference to b
+        assertEquals(partialUpdatedEntities.size(), 4);
+
+        init();
+        storedEntities = entityStore.getByIds(ImmutableList.of(a1.getGuid(), a2.getGuid(), a3.getGuid(), b.getGuid()));
+        verifyReferenceValue(storedEntities.getEntity(a3.getGuid()), "oneB", b.getGuid());
+
+        verify_testInverseReferenceAutoUpdate_NonCompositeManyToOne(storedEntities.getEntity(a1.getGuid()), storedEntities.getEntity(a2.getGuid()),
+            storedEntities.getEntity(a3.getGuid()), storedEntities.getEntity(b.getGuid()));
+    }
+
+    protected abstract void verify_testInverseReferenceAutoUpdate_NonCompositeManyToOne(AtlasEntity a1, AtlasEntity a2, AtlasEntity a3, AtlasEntity b);
+
+    @Test
+    public void testInverseReferenceAutoUpdate_NonComposite_OneToOne() throws Exception {
+        AtlasEntityType bType = typeRegistry.getEntityTypeByName("B");
+        AtlasEntity a1 = new AtlasEntity("A");
+        a1.setAttribute(NAME, TestUtilsV2.randomString());
+        AtlasEntity a2 = new AtlasEntity("A");
+        a2.setAttribute(NAME, TestUtilsV2.randomString());
+        AtlasEntity b = new AtlasEntity("B");
+        b.setAttribute(NAME, TestUtilsV2.randomString());
+        AtlasEntitiesWithExtInfo atlasEntitiesWithExtInfo = new AtlasEntitiesWithExtInfo();
+        atlasEntitiesWithExtInfo.addEntity(a1);
+        atlasEntitiesWithExtInfo.addEntity(a2);
+        atlasEntitiesWithExtInfo.addEntity(b);
+        AtlasEntityStream entityStream = new AtlasEntityStream(atlasEntitiesWithExtInfo);
+        EntityMutationResponse response = entityStore.createOrUpdate(entityStream , false);
+
+        AtlasEntity bForPartialUpdate = new AtlasEntity("B");
+        bForPartialUpdate.setAttribute("a", AtlasTypeUtil.getAtlasObjectId(a1));
+        init();
+        response = entityStore.updateByUniqueAttributes(bType, Collections.<String, Object>singletonMap(NAME, b.getAttribute(NAME)), new AtlasEntityWithExtInfo(bForPartialUpdate));
+        List<AtlasEntityHeader> partialUpdatedEntities = response.getPartialUpdatedEntities();
+        // Verify 2 entities were updated:
+        // * set b.a reference to a1
+        // * set inverse a1.b reference to b
+        assertEquals(partialUpdatedEntities.size(), 2);
+        AtlasEntitiesWithExtInfo storedEntities = entityStore.getByIds(ImmutableList.of(a1.getGuid(), b.getGuid()));
+        AtlasEntity storedEntity = storedEntities.getEntity(a1.getGuid());
+        verifyReferenceValue(storedEntity, "b", b.getGuid());
+        storedEntity = storedEntities.getEntity(b.getGuid());
+        verifyReferenceValue(storedEntity, "a", a1.getGuid());
+
+        // Update b.a to reference a2.
+        bForPartialUpdate.setAttribute("a", AtlasTypeUtil.getAtlasObjectId(a2));
+        init();
+        response = entityStore.updateByUniqueAttributes(bType, Collections.<String, Object>singletonMap(NAME, b.getAttribute(NAME)), new AtlasEntityWithExtInfo(bForPartialUpdate));
+        partialUpdatedEntities = response.getPartialUpdatedEntities();
+        // Verify 3 entities were updated:
+        // * set b.a reference to a2
+        // * set a2.b reference to b
+        // * disconnect a1.b reference
+        assertEquals(partialUpdatedEntities.size(), 3);
+        storedEntities = entityStore.getByIds(ImmutableList.of(a1.getGuid(), a2.getGuid(), b.getGuid()));
+        storedEntity = storedEntities.getEntity(a2.getGuid());
+        verifyReferenceValue(storedEntity, "b", b.getGuid());
+        storedEntity = storedEntities.getEntity(b.getGuid());
+        verifyReferenceValue(storedEntity, "a", a2.getGuid());
+        storedEntity = storedEntities.getEntity(a1.getGuid());
+        Object refValue = storedEntity.getAttribute("b");
+        verify_testInverseReferenceAutoUpdate_NonComposite_OneToOne(storedEntities.getEntity(a1.getGuid()), storedEntities.getEntity(b.getGuid()));
+    }
+
+    protected abstract void verify_testInverseReferenceAutoUpdate_NonComposite_OneToOne(AtlasEntity a1, AtlasEntity b);
+
+    @Test
+    public void testInverseReferenceAutoUpdate_NonComposite_ManyToMany() throws Exception {
+        AtlasEntityType bType = typeRegistry.getEntityTypeByName("B");
+        AtlasEntity a1 = new AtlasEntity("A");
+        a1.setAttribute(NAME, TestUtilsV2.randomString());
+        AtlasEntity a2 = new AtlasEntity("A");
+        a2.setAttribute(NAME, TestUtilsV2.randomString());
+        AtlasEntity a3 = new AtlasEntity("A");
+        a3.setAttribute(NAME, TestUtilsV2.randomString());
+        AtlasEntity b1 = new AtlasEntity("B");
+        b1.setAttribute(NAME, TestUtilsV2.randomString());
+        AtlasEntity b2 = new AtlasEntity("B");
+        b2.setAttribute(NAME, TestUtilsV2.randomString());
+        AtlasEntitiesWithExtInfo atlasEntitiesWithExtInfo = new AtlasEntitiesWithExtInfo();
+        atlasEntitiesWithExtInfo.addEntity(a1);
+        atlasEntitiesWithExtInfo.addEntity(a2);
+        atlasEntitiesWithExtInfo.addEntity(a3);
+        atlasEntitiesWithExtInfo.addEntity(b1);
+        atlasEntitiesWithExtInfo.addEntity(b2);
+        AtlasEntityStream entityStream = new AtlasEntityStream(atlasEntitiesWithExtInfo);
+        EntityMutationResponse response = entityStore.createOrUpdate(entityStream , false);
+
+        AtlasEntity b1ForPartialUpdate = new AtlasEntity("B");
+        b1ForPartialUpdate.setAttribute("manyToManyA", ImmutableList.of(AtlasTypeUtil.getAtlasObjectId(a1), AtlasTypeUtil.getAtlasObjectId(a2)));
+        init();
+        response = entityStore.updateByUniqueAttributes(bType, Collections.<String, Object>singletonMap(NAME, b1.getAttribute(NAME)), new AtlasEntityWithExtInfo(b1ForPartialUpdate));
+        List<AtlasEntityHeader> partialUpdatedEntities = response.getPartialUpdatedEntities();
+        assertEquals(partialUpdatedEntities.size(), 3);
+        AtlasEntitiesWithExtInfo storedEntities = entityStore.getByIds(ImmutableList.of(a1.getGuid(), a2.getGuid(), b1.getGuid()));
+        AtlasEntity storedEntity = storedEntities.getEntity(b1.getGuid());
+        verifyReferenceList(storedEntity, "manyToManyA", ImmutableList.of(AtlasTypeUtil.getAtlasObjectId(a1), AtlasTypeUtil.getAtlasObjectId(a2)));
+        storedEntity = storedEntities.getEntity(a1.getGuid());
+        verifyReferenceList(storedEntity, "manyB", ImmutableList.of(AtlasTypeUtil.getAtlasObjectId(b1)));
+        storedEntity = storedEntities.getEntity(a2.getGuid());
+        verifyReferenceList(storedEntity, "manyB", ImmutableList.of(AtlasTypeUtil.getAtlasObjectId(b1)));
+    }
+
+    @Test
+    public void testInverseReferenceAutoUpdate_Map() throws Exception {
+        AtlasEntity a1 = new AtlasEntity("A");
+        a1.setAttribute(NAME, TestUtilsV2.randomString());
+        AtlasEntity b1 = new AtlasEntity("B");
+        b1.setAttribute(NAME, TestUtilsV2.randomString());
+        AtlasEntity b2 = new AtlasEntity("B");
+        b2.setAttribute(NAME, TestUtilsV2.randomString());
+        AtlasEntity b3 = new AtlasEntity("B");
+        b3.setAttribute(NAME, TestUtilsV2.randomString());
+        AtlasEntitiesWithExtInfo atlasEntitiesWithExtInfo = new AtlasEntitiesWithExtInfo();
+        atlasEntitiesWithExtInfo.addEntity(a1);
+        atlasEntitiesWithExtInfo.addEntity(b1);
+        atlasEntitiesWithExtInfo.addEntity(b2);
+        atlasEntitiesWithExtInfo.addEntity(b3);
+        AtlasEntityStream entityStream = new AtlasEntityStream(atlasEntitiesWithExtInfo);
+        EntityMutationResponse response = entityStore.createOrUpdate(entityStream , false);
+
+        AtlasEntityType aType = typeRegistry.getEntityTypeByName("A");
+        AtlasEntity aForPartialUpdate = new AtlasEntity("A");
+        aForPartialUpdate.setAttribute("mapToB", ImmutableMap.<String, AtlasObjectId>of("b1", AtlasTypeUtil.getAtlasObjectId(b1), "b2", AtlasTypeUtil.getAtlasObjectId(b2)));
+        init();
+        response = entityStore.updateByUniqueAttributes(aType, Collections.<String, Object>singletonMap(NAME, a1.getAttribute(NAME)), new AtlasEntityWithExtInfo(aForPartialUpdate));
+        List<AtlasEntityHeader> partialUpdatedEntities = response.getPartialUpdatedEntities();
+        // Verify 3 entities were updated:
+        // * set a1.mapToB to "b1"->b1, "b2"->b2
+        // * set b1.mappedFromA to a1
+        // * set b2.mappedFromA to a1
+        assertEquals(partialUpdatedEntities.size(), 3);
+        AtlasEntitiesWithExtInfo storedEntities = entityStore.getByIds(ImmutableList.of(a1.getGuid(), b2.getGuid(), b1.getGuid()));
+        AtlasEntity storedEntity = storedEntities.getEntity(a1.getGuid());
+        Object value = storedEntity.getAttribute("mapToB");
+        assertTrue(value instanceof Map);
+        Map<String, AtlasObjectId> refMap = (Map<String, AtlasObjectId>) value;
+        assertEquals(refMap.size(), 2);
+        AtlasObjectId referencedEntityId = refMap.get("b1");
+        assertEquals(referencedEntityId, AtlasTypeUtil.getAtlasObjectId(b1));
+        referencedEntityId = refMap.get("b2");
+        assertEquals(referencedEntityId, AtlasTypeUtil.getAtlasObjectId(b2));
+        storedEntity = storedEntities.getEntity(b1.getGuid());
+        verifyReferenceValue(storedEntity, "mappedFromA", a1.getGuid());
+        storedEntity = storedEntities.getEntity(b2.getGuid());
+        verifyReferenceValue(storedEntity, "mappedFromA", a1.getGuid());
+
+        aForPartialUpdate.setAttribute("mapToB", ImmutableMap.<String, AtlasObjectId>of("b3", AtlasTypeUtil.getAtlasObjectId(b3)));
+        init();
+        response = entityStore.updateByUniqueAttributes(aType, Collections.<String, Object>singletonMap(NAME, a1.getAttribute(NAME)), new AtlasEntityWithExtInfo(aForPartialUpdate));
+        partialUpdatedEntities = response.getPartialUpdatedEntities();
+        // Verify 4 entities were updated:
+        // * set a1.mapToB to "b3"->b3
+        // * set b3.mappedFromA to a1
+        // * disconnect b1.mappedFromA
+        // * disconnect b2.mappedFromA
+        assertEquals(partialUpdatedEntities.size(), 4);
+        storedEntities = entityStore.getByIds(ImmutableList.of(a1.getGuid(), b2.getGuid(), b1.getGuid(), b3.getGuid()));
+        AtlasEntity storedB3 = storedEntities.getEntity(b3.getGuid());
+        verifyReferenceValue(storedB3, "mappedFromA", a1.getGuid());
+        verify_testInverseReferenceAutoUpdate_Map(storedEntities.getEntity(a1.getGuid()), storedEntities.getEntity(b1.getGuid()), storedEntities.getEntity(b2.getGuid()), storedB3);
+    }
+
+    protected abstract void verify_testInverseReferenceAutoUpdate_Map(AtlasEntity a1, AtlasEntity b1, AtlasEntity b2, AtlasEntity b3);
+
+    protected void verifyReferenceValue(AtlasEntity entity, String refName, String expectedGuid) {
+        Object refValue = entity.getAttribute(refName);
+        if (expectedGuid == null) {
+            assertNull(refValue);
+        }
+        else {
+            assertTrue(refValue instanceof AtlasObjectId);
+            AtlasObjectId referencedObjectId = (AtlasObjectId) refValue;
+            assertEquals(referencedObjectId.getGuid(), expectedGuid);
+        }
+    }
+
+    protected void verifyReferenceList(AtlasEntity entity, String refName, List<AtlasObjectId> expectedValues) {
+        Object refValue = entity.getAttribute(refName);
+        assertTrue(refValue instanceof List);
+        List<AtlasObjectId> refList = (List<AtlasObjectId>) refValue;
+        assertEquals(refList.size(), expectedValues.size());
+        if (expectedValues.size() > 0) {
+            assertTrue(refList.containsAll(expectedValues));
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/atlas/blob/042fc557/repository/src/test/java/org/apache/atlas/repository/userprofile/UserProfileServiceTest.java
----------------------------------------------------------------------
diff --git a/repository/src/test/java/org/apache/atlas/repository/userprofile/UserProfileServiceTest.java b/repository/src/test/java/org/apache/atlas/repository/userprofile/UserProfileServiceTest.java
new file mode 100644
index 0000000..0532f16
--- /dev/null
+++ b/repository/src/test/java/org/apache/atlas/repository/userprofile/UserProfileServiceTest.java
@@ -0,0 +1,280 @@
+/**
+ * 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.userprofile;
+
+import org.apache.atlas.AtlasErrorCode;
+import org.apache.atlas.TestModules;
+import org.apache.atlas.exception.AtlasBaseException;
+import org.apache.atlas.model.SearchFilter;
+import org.apache.atlas.model.discovery.SearchParameters;
+import org.apache.atlas.model.profile.AtlasUserProfile;
+import org.apache.atlas.model.profile.AtlasUserSavedSearch;
+import org.apache.atlas.model.typedef.AtlasTypesDef;
+import org.apache.atlas.repository.util.FilterUtil;
+import org.apache.atlas.store.AtlasTypeDefStore;
+import org.apache.atlas.type.AtlasType;
+import org.apache.atlas.type.AtlasTypeRegistry;
+import org.testng.annotations.Guice;
+import org.testng.annotations.Test;
+
+import javax.inject.Inject;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.List;
+
+import static org.apache.atlas.model.profile.AtlasUserSavedSearch.SavedSearchType.BASIC;
+import static org.apache.atlas.repository.impexp.ZipFileResourceTestUtils.loadModelFromJson;
+import static org.testng.Assert.*;
+
+@Guice(modules = TestModules.TestOnlyModule.class)
+public class UserProfileServiceTest {
+    private UserProfileService userProfileService;
+    private AtlasTypeDefStore  typeDefStore;
+    private int                max_searches = 4;
+
+    @Inject
+    public void UserProfileServiceTest(AtlasTypeRegistry  typeRegistry,
+                                       AtlasTypeDefStore  typeDefStore,
+                                       UserProfileService userProfileService) throws IOException, AtlasBaseException {
+        this.typeDefStore       = typeDefStore;
+        this.userProfileService = userProfileService;
+
+        loadModelFromJson("0010-base_model.json", typeDefStore, typeRegistry);
+    }
+
+    @Test
+    public void filterInternalType() throws AtlasBaseException {
+        SearchFilter searchFilter = new SearchFilter();
+        AtlasTypesDef filteredTypeDefs = typeDefStore.searchTypesDef(searchFilter);
+        int maxTypeDefs = filteredTypeDefs.getEntityDefs().size();
+
+        FilterUtil.addParamsToHideInternalType(searchFilter);
+        filteredTypeDefs = typeDefStore.searchTypesDef(searchFilter);
+
+        assertNotNull(filteredTypeDefs);
+        assertEquals(filteredTypeDefs.getEntityDefs().size(), maxTypeDefs - 3);
+    }
+
+    @Test
+    public void createsNewProfile() throws AtlasBaseException {
+        int i = 0;
+        assertSaveLoadUserProfile(i++);
+        assertSaveLoadUserProfile(i);
+    }
+
+    @Test(dependsOnMethods = { "createsNewProfile", "savesQueryForAnNonExistentUser" }, expectedExceptions = AtlasBaseException.class)
+    public void atteptsToAddAlreadyExistingQueryForAnExistingUser() throws AtlasBaseException {
+        SearchParameters expectedSearchParameter = getActualSearchParameters();
+
+        for (int i = 0; i < 2; i++) {
+            String userName = getIndexBasedUserName(i);
+
+            for (int j = 0; j < max_searches; j++) {
+                String queryName = getIndexBasedQueryName(j);
+                AtlasUserSavedSearch expected = getDefaultSavedSearch(userName, queryName, expectedSearchParameter);
+                AtlasUserSavedSearch actual = userProfileService.addSavedSearch(expected);
+
+                assertNotNull(actual);
+                assertNotNull(actual.getGuid());
+                assertEquals(actual.getOwnerName(), expected.getOwnerName());
+                assertEquals(actual.getName(), expected.getName());
+                assertEquals(actual.getSearchType(), expected.getSearchType());
+                assertEquals(actual.getSearchParameters(), expected.getSearchParameters());
+            }
+        }
+    }
+
+    @Test(dependsOnMethods = { "createsNewProfile", "savesQueryForAnNonExistentUser", "atteptsToAddAlreadyExistingQueryForAnExistingUser" })
+    public void savesExistingQueryForAnExistingUser() throws AtlasBaseException {
+        SearchParameters expectedSearchParameter = getActualSearchParameters();
+
+        for (int i = 0; i < 2; i++) {
+            String userName = getIndexBasedUserName(i);
+
+            for (int j = 4; j < max_searches + 6; j++) {
+                String queryName = getIndexBasedQueryName(j);
+                AtlasUserSavedSearch actual = userProfileService.addSavedSearch(getDefaultSavedSearch(userName, queryName, expectedSearchParameter));
+                assertNotNull(actual);
+
+                AtlasUserSavedSearch savedSearch = userProfileService.getSavedSearch(userName, queryName);
+                assertNotNull(savedSearch);
+                assertEquals(savedSearch.getSearchParameters(), expectedSearchParameter);
+            }
+        }
+    }
+
+    private SearchParameters getActualSearchParameters() {
+        SearchParameters sp = new SearchParameters();
+        sp.setClassification("test-classification");
+        sp.setQuery("g.v().has('__guid').__guid.toList()");
+        sp.setLimit(10);
+        sp.setTypeName("some-type");
+
+        return sp;
+    }
+
+    @Test(dependsOnMethods = "createsNewProfile")
+    public void savesQueryForAnNonExistentUser() throws AtlasBaseException {
+        String expectedUserName = getIndexBasedUserName(0);
+        String expectedQueryName = "testQuery";
+        SearchParameters expectedSearchParam = getActualSearchParameters();
+        AtlasUserSavedSearch expectedSavedSearch = getDefaultSavedSearch(expectedUserName, expectedQueryName, expectedSearchParam);
+
+        AtlasUserSavedSearch actual = userProfileService.addSavedSearch(expectedSavedSearch);
+        assertEquals(actual.getOwnerName(), expectedUserName);
+        assertEquals(actual.getName(), expectedQueryName);
+    }
+
+    private AtlasUserSavedSearch getDefaultSavedSearch(String userName, String queryName, SearchParameters expectedSearchParam) {
+        return new AtlasUserSavedSearch(userName, queryName,
+                BASIC, expectedSearchParam);
+    }
+
+    @Test(dependsOnMethods = "createsNewProfile")
+    public void savesMultipleQueriesForUser() throws AtlasBaseException {
+        final String userName = getIndexBasedUserName(0);
+        createUserWithSavedQueries(userName);
+    }
+
+    private void createUserWithSavedQueries(String userName) throws AtlasBaseException {
+        SearchParameters actualSearchParameter = getActualSearchParameters();
+
+        saveQueries(userName, actualSearchParameter);
+        for (int i = 0; i < max_searches; i++) {
+            AtlasUserSavedSearch savedSearch = userProfileService.getSavedSearch(userName, getIndexBasedQueryName(i));
+            assertEquals(savedSearch.getName(), getIndexBasedQueryName(i));
+            assertEquals(savedSearch.getSearchParameters(), actualSearchParameter);
+        }
+    }
+
+    private void saveQueries(String userName, SearchParameters sp) throws AtlasBaseException {
+        for (int i = 0; i < max_searches; i++) {
+            userProfileService.addSavedSearch(getDefaultSavedSearch(userName, getIndexBasedQueryName(i), sp));
+        }
+    }
+
+    @Test(dependsOnMethods = {"createsNewProfile", "savesMultipleQueriesForUser"})
+    public void verifyQueryNameListForUser() throws AtlasBaseException {
+        final String userName = getIndexBasedUserName(0);
+
+        List<AtlasUserSavedSearch> list = userProfileService.getSavedSearches(userName);
+        List<String> names = getIndexBasedQueryNamesList();
+        for (int i = 0; i < names.size(); i++) {
+            assertTrue(names.contains(list.get(i).getName()), list.get(i).getName() + " failed!");
+        }
+    }
+
+    @Test(dependsOnMethods = {"createsNewProfile", "savesMultipleQueriesForUser"}, enabled = false)
+    public void verifyQueryConversionFromJSON() throws AtlasBaseException {
+        List<AtlasUserSavedSearch> list = userProfileService.getSavedSearches("first-0");
+
+        for (int i = 0; i < max_searches; i++) {
+            SearchParameters sp = list.get(i).getSearchParameters();
+            String json = AtlasType.toJson(sp);
+            assertEquals(AtlasType.toJson(getActualSearchParameters()).replace("\n", "").replace(" ", ""), json);
+        }
+    }
+
+    @Test(dependsOnMethods = {"createsNewProfile", "savesMultipleQueriesForUser"})
+    public void updateSearch() throws AtlasBaseException {
+        final String queryName = getIndexBasedQueryName(0);
+        String userName = getIndexBasedUserName(0);
+        AtlasUserSavedSearch expected = userProfileService.getSavedSearch(userName, queryName);
+        assertNotNull(expected);
+
+        SearchParameters sp = expected.getSearchParameters();
+        sp.setClassification("new-classification");
+
+        AtlasUserSavedSearch actual = userProfileService.updateSavedSearch(expected);
+
+        assertNotNull(actual);
+        assertNotNull(actual.getSearchParameters());
+        assertEquals(actual.getSearchParameters().getClassification(), expected.getSearchParameters().getClassification());
+    }
+
+    @Test(dependsOnMethods = {"createsNewProfile", "savesMultipleQueriesForUser", "verifyQueryNameListForUser"}, expectedExceptions = AtlasBaseException.class)
+    public void deleteUsingGuid() throws AtlasBaseException {
+        final String queryName = getIndexBasedQueryName(1);
+        String userName = getIndexBasedUserName(0);
+
+        AtlasUserSavedSearch expected = userProfileService.getSavedSearch(userName, queryName);
+        assertNotNull(expected);
+
+        userProfileService.deleteSavedSearch(expected.getGuid());
+        userProfileService.getSavedSearch(userName, queryName);
+    }
+
+    @Test(dependsOnMethods = {"createsNewProfile", "savesMultipleQueriesForUser", "verifyQueryNameListForUser"})
+    public void deleteSavedQuery() throws AtlasBaseException {
+        final String userName = getIndexBasedUserName(0);
+        AtlasUserProfile expected = userProfileService.getUserProfile(userName);
+        assertNotNull(expected);
+
+        int new_max_searches = expected.getSavedSearches().size();
+        String queryNameToBeDeleted = getIndexBasedQueryName(max_searches - 2);
+        userProfileService.deleteSearchBySearchName(userName, queryNameToBeDeleted);
+
+        List<AtlasUserSavedSearch> savedSearchList = userProfileService.getSavedSearches(userName);
+        assertEquals(savedSearchList.size(), new_max_searches - 1);
+    }
+
+    @Test(dependsOnMethods = {"createsNewProfile", "savesMultipleQueriesForUser", "verifyQueryNameListForUser"})
+    void deleteUser() throws AtlasBaseException {
+        String userName = getIndexBasedUserName(1);
+
+        userProfileService.deleteUserProfile(userName);
+        try {
+            userProfileService.getUserProfile(userName);
+        }
+        catch(AtlasBaseException ex) {
+            assertEquals(ex.getAtlasErrorCode().name(), AtlasErrorCode.INSTANCE_BY_UNIQUE_ATTRIBUTE_NOT_FOUND.name());
+        }
+    }
+
+    private void assertSaveLoadUserProfile(int i) throws AtlasBaseException {
+        String s = String.valueOf(i);
+        AtlasUserProfile expected = getAtlasUserProfile(i);
+
+        AtlasUserProfile actual = userProfileService.saveUserProfile(expected);
+        assertNotNull(actual);
+        assertEquals(expected.getName(), actual.getName());
+        assertEquals(expected.getFullName(), actual.getFullName());
+        assertNotNull(actual.getGuid());
+    }
+
+    public static AtlasUserProfile getAtlasUserProfile(Integer s) {
+        return new AtlasUserProfile(getIndexBasedUserName(s), String.format("first-%s last-%s", s, s));
+    }
+
+    private static String getIndexBasedUserName(Integer i) {
+        return String.format("first-%s", i.toString());
+    }
+
+    private static String getIndexBasedQueryName(Integer i) {
+        return String.format("testQuery-%s", i.toString());
+    }
+
+    public List<String> getIndexBasedQueryNamesList() {
+        List<String> list = new ArrayList<>();
+        for (int i = 0; i < max_searches; i++) {
+            list.add(getIndexBasedQueryName(i));
+        }
+
+        return list;
+    }
+}

http://git-wip-us.apache.org/repos/asf/atlas/blob/042fc557/repository/src/test/java/org/apache/atlas/services/MetricsServiceTest.java
----------------------------------------------------------------------
diff --git a/repository/src/test/java/org/apache/atlas/services/MetricsServiceTest.java b/repository/src/test/java/org/apache/atlas/services/MetricsServiceTest.java
new file mode 100644
index 0000000..5165bcb
--- /dev/null
+++ b/repository/src/test/java/org/apache/atlas/services/MetricsServiceTest.java
@@ -0,0 +1,123 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.atlas.services;
+
+import org.apache.atlas.exception.AtlasBaseException;
+import org.apache.atlas.model.metrics.AtlasMetrics;
+import org.apache.atlas.repository.graphdb.AtlasGraph;
+import org.apache.atlas.type.AtlasTypeRegistry;
+import org.apache.commons.configuration.Configuration;
+import org.mockito.invocation.InvocationOnMock;
+import org.mockito.stubbing.Answer;
+import org.testng.annotations.BeforeClass;
+import org.testng.annotations.Test;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import static org.mockito.Matchers.anyString;
+import static org.mockito.Matchers.eq;
+import static org.mockito.Mockito.*;
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertNotNull;
+
+public class MetricsServiceTest {
+    private Configuration mockConfig = mock(Configuration.class);
+    private AtlasTypeRegistry mockTypeRegistry = mock(AtlasTypeRegistry.class);
+    private AtlasGraph mockGraph = mock(AtlasGraph.class);
+    private MetricsService metricsService;
+
+    private List<Map> mockMapList = new ArrayList<>();
+    private Number mockCount = 10;
+
+    @BeforeClass
+    public void init() throws AtlasBaseException {
+        Map<String, Object> mockMap = new HashMap<>();
+        mockMap.put("a", 1);
+        mockMap.put("b", 2);
+        mockMap.put("c", 3);
+        mockMapList.add(mockMap);
+
+        when(mockConfig.getInt(anyString(), anyInt())).thenReturn(5);
+        assertEquals(mockConfig.getInt("test", 1), 5);
+        when(mockConfig.getString(anyString(), anyString()))
+                .thenReturn("count()", "count()", "count()", "count()", "count()", "toList()", "count()", "toList()");
+        when(mockTypeRegistry.getAllEntityDefNames()).thenReturn(Arrays.asList("a", "b", "c"));
+        setupMockGraph();
+
+        metricsService = new MetricsService(mockConfig, mockGraph);
+    }
+
+    private void setupMockGraph() throws AtlasBaseException {
+        if (mockGraph == null) mockGraph = mock(AtlasGraph.class);
+        when(mockGraph.executeGremlinScript(anyString(), eq(false))).thenAnswer(new Answer<Object>() {
+            @Override
+            public Object answer(InvocationOnMock invocationOnMock) throws Throwable {
+                if (((String)invocationOnMock.getArguments()[0]).contains("count()")) {
+                    return mockCount;
+                } else {
+                    return mockMapList;
+                }
+            }
+        });
+    }
+
+    @Test
+    public void testGetMetrics() throws InterruptedException, AtlasBaseException {
+        assertNotNull(metricsService);
+        AtlasMetrics metrics = metricsService.getMetrics(false);
+        assertNotNull(metrics);
+        Number aCount = metrics.getMetric("entity", "a");
+        assertNotNull(aCount);
+        assertEquals(aCount, 1);
+
+        Number bCount = metrics.getMetric("entity", "b");
+        assertNotNull(bCount);
+        assertEquals(bCount, 2);
+
+        Number cCount = metrics.getMetric("entity", "c");
+        assertNotNull(cCount);
+        assertEquals(cCount, 3);
+
+        Number aTags = metrics.getMetric("tag", "a");
+        assertNotNull(aTags);
+        assertEquals(aTags, 1);
+
+        Number bTags = metrics.getMetric("tag", "b");
+        assertNotNull(bTags);
+        assertEquals(bTags, 2);
+
+        Number cTags = metrics.getMetric("tag", "c");
+        assertNotNull(cTags);
+        assertEquals(cTags, 3);
+
+        verify(mockGraph, atLeastOnce()).executeGremlinScript(anyString(), anyBoolean());
+
+        // Subsequent call within the cache timeout window
+        metricsService.getMetrics(false);
+        verifyZeroInteractions(mockGraph);
+
+        // Now test the cache refresh
+        Thread.sleep(6000);
+        metricsService.getMetrics(true);
+        verify(mockGraph, atLeastOnce()).executeGremlinScript(anyString(), anyBoolean());
+    }
+}

http://git-wip-us.apache.org/repos/asf/atlas/blob/042fc557/repository/src/test/java/org/apache/atlas/utils/ObjectUpdateSynchronizerTest.java
----------------------------------------------------------------------
diff --git a/repository/src/test/java/org/apache/atlas/utils/ObjectUpdateSynchronizerTest.java b/repository/src/test/java/org/apache/atlas/utils/ObjectUpdateSynchronizerTest.java
new file mode 100644
index 0000000..03ebae4
--- /dev/null
+++ b/repository/src/test/java/org/apache/atlas/utils/ObjectUpdateSynchronizerTest.java
@@ -0,0 +1,218 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.atlas.utils;
+
+import org.apache.atlas.GraphTransactionInterceptor;
+import org.apache.commons.lang.ArrayUtils;
+import org.apache.commons.lang.RandomStringUtils;
+import org.springframework.util.CollectionUtils;
+import org.testng.annotations.BeforeMethod;
+import org.testng.annotations.Test;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertFalse;
+
+public class ObjectUpdateSynchronizerTest {
+    private static final GraphTransactionInterceptor.ObjectUpdateSynchronizer objectUpdateSynchronizer = new GraphTransactionInterceptor.ObjectUpdateSynchronizer();
+
+    private final List<Integer> outputList = new ArrayList<>();
+    private final int MAX_COUNT = 10;
+
+    class CounterThread extends Thread {
+        String ids[];
+        public CounterThread(String id) {
+            this.ids = new String[1];
+            this.ids[0] = id;
+        }
+
+        public void setIds(String... ids) {
+            this.ids = ids;
+        }
+
+        public void run() {
+            objectUpdateSynchronizer.lockObject(CollectionUtils.arrayToList(ids));
+            for (int i = 0; i < MAX_COUNT; i++) {
+                outputList.add(i);
+                RandomStringUtils.randomAlphabetic(20);
+            }
+
+            objectUpdateSynchronizer.releaseLockedObjects();
+        }
+    }
+
+    @BeforeMethod
+    public void clearOutputList() {
+        outputList.clear();
+    }
+
+    @Test
+    public void singleThreadRun() throws InterruptedException {
+        verifyMultipleThreadRun(1);
+    }
+
+    @Test
+    public void twoThreadsAccessingDifferntGuids_DoNotSerialize() throws InterruptedException {
+        CounterThread th[] = getCounterThreads(false, 2);
+
+        startCounterThreads(th);
+        waitForThreadsToEnd(th);
+        assertArrayNotEquals(populateExpectedArrayOutput(2));
+    }
+
+    @Test
+    public void twoThreadsAccessingSameGuid_Serialize() throws InterruptedException {
+        verifyMultipleThreadRun(2);
+    }
+
+    @Test
+    public void severalThreadsAccessingSameGuid_Serialize() throws InterruptedException {
+        verifyMultipleThreadRun(10);
+    }
+
+    @Test
+    public void severalThreadsSequentialAccessingListOfGuids() throws InterruptedException {
+        CounterThread th[] = getCounterThreads(false, 10);
+        int i = 0;
+        th[i++].setIds("1", "2", "3", "4", "5");
+        th[i++].setIds("1", "2", "3", "4");
+        th[i++].setIds("1", "2", "3");
+        th[i++].setIds("1", "2");
+        th[i++].setIds("1");
+        th[i++].setIds("1", "2");
+        th[i++].setIds("1", "2", "3");
+        th[i++].setIds("1", "2", "3", "4");
+        th[i++].setIds("1", "2", "3", "4", "5");
+        th[i++].setIds("1");
+
+        startCounterThreads(th);
+        waitForThreadsToEnd(th);
+        assertArrayEquals(populateExpectedArrayOutput(th.length));
+    }
+
+    @Test
+    public void severalThreadsNonSequentialAccessingListOfGuids() throws InterruptedException {
+        CounterThread th[] = getCounterThreads(false, 5);
+        int i = 0;
+        th[i++].setIds("2", "1", "3", "4", "5");
+        th[i++].setIds("3", "2", "4", "1");
+        th[i++].setIds("2", "3", "1");
+        th[i++].setIds("1", "2");
+        th[i++].setIds("1");
+
+        startCounterThreads(th);
+        waitForThreadsToEnd(th);
+        assertArrayEquals(populateExpectedArrayOutput(th.length));
+    }
+
+    @Test
+    public void severalThreadsAccessingOverlappingListOfGuids() throws InterruptedException {
+        CounterThread th[] = getCounterThreads(false, 5);
+        int i = 0;
+        th[i++].setIds("1", "2", "3", "4", "5");
+        th[i++].setIds("3", "4", "5", "6");
+        th[i++].setIds("5", "6", "7");
+        th[i++].setIds("7", "8");
+        th[i++].setIds("8");
+
+        startCounterThreads(th);
+        waitForThreadsToEnd(th);
+        assertArrayNotEquals(populateExpectedArrayOutput(th.length));
+    }
+
+
+    @Test
+    public void severalThreadsAccessingOverlappingListOfGuids2() throws InterruptedException {
+        CounterThread th[] = getCounterThreads(false, 3);
+        int i = 0;
+        th[i++].setIds("1", "2", "3", "4", "5");
+        th[i++].setIds("6", "7", "8", "9");
+        th[i++].setIds("4", "5", "6");
+
+        startCounterThreads(th);
+        waitForThreadsToEnd(th);
+        assertArrayNotEquals(populateExpectedArrayOutput(th.length));
+    }
+
+    @Test
+    public void severalThreadsAccessingOverlappingListOfGuidsEnsuringSerialOutput() throws InterruptedException {
+        CounterThread th[] = getCounterThreads(false, 5);
+        int i = 0;
+        th[i++].setIds("1", "2", "3", "4", "7");
+        th[i++].setIds("3", "4", "5", "7");
+        th[i++].setIds("5", "6", "7");
+        th[i++].setIds("7", "8");
+        th[i++].setIds("7");
+
+        startCounterThreads(th);
+        waitForThreadsToEnd(th);
+        assertArrayEquals(populateExpectedArrayOutput(th.length));
+    }
+
+    private void verifyMultipleThreadRun(int limit) throws InterruptedException {
+        CounterThread[] th = getCounterThreads(limit);
+        startCounterThreads(th);
+        waitForThreadsToEnd(th);
+        assertArrayEquals(populateExpectedArrayOutput(limit));
+    }
+
+    private void startCounterThreads(CounterThread[] th) {
+        for (int i = 0; i < th.length; i++) {
+            th[i].start();
+        }
+    }
+    private CounterThread[] getCounterThreads(int limit) {
+        return getCounterThreads(true, limit);
+    }
+
+    private CounterThread[] getCounterThreads(boolean sameId, int limit) {
+        CounterThread th[] = new CounterThread[limit];
+        for (Integer i = 0; i < limit; i++) {
+            th[i] = new CounterThread(sameId ? "1" : i.toString());
+        }
+        return th;
+    }
+
+
+    private void assertArrayEquals(List<Integer> expected) {
+        assertEquals(outputList.toArray(), expected.toArray());
+    }
+
+    private void assertArrayNotEquals(List<Integer> expected) {
+        assertFalse(ArrayUtils.isEquals(outputList.toArray(), expected));
+    }
+
+    private void waitForThreadsToEnd(CounterThread... threads) throws InterruptedException {
+        for (Thread t : threads) {
+            t.join();
+        }
+    }
+
+    private List<Integer> populateExpectedArrayOutput(int limit) {
+        List<Integer> list = new ArrayList<>();
+        for (int i = 0; i < limit*MAX_COUNT; i+=MAX_COUNT) {
+            for (int j = 0; j < MAX_COUNT; j++) {
+                list.add(j);
+            }
+        }
+
+        return list;
+    }
+}