http://git-wip-us.apache.org/repos/asf/atlas/blob/3d5b4880/repository/src/test/java/org/apache/atlas/repository/store/graph/v2/AtlasComplexAttributesTest.java
----------------------------------------------------------------------
diff --git 
a/repository/src/test/java/org/apache/atlas/repository/store/graph/v2/AtlasComplexAttributesTest.java
 
b/repository/src/test/java/org/apache/atlas/repository/store/graph/v2/AtlasComplexAttributesTest.java
new file mode 100644
index 0000000..ebd5f0f
--- /dev/null
+++ 
b/repository/src/test/java/org/apache/atlas/repository/store/graph/v2/AtlasComplexAttributesTest.java
@@ -0,0 +1,512 @@
+/**
+ * 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.v2;
+
+import org.apache.atlas.TestModules;
+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.AtlasStruct;
+import org.apache.atlas.model.instance.EntityMutationResponse;
+import org.apache.atlas.model.typedef.AtlasTypesDef;
+import org.apache.atlas.repository.graphdb.AtlasEdge;
+import org.apache.atlas.repository.graphdb.AtlasEdgeDirection;
+import org.apache.atlas.repository.graphdb.AtlasVertex;
+import org.apache.commons.lang.time.DateUtils;
+import org.testng.annotations.BeforeClass;
+import org.testng.annotations.Guice;
+import org.testng.annotations.Test;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+
+import static org.apache.atlas.TestUtilsV2.ENTITY_TYPE;
+import static org.apache.atlas.TestUtilsV2.ENTITY_TYPE_MAP;
+import static 
org.apache.atlas.TestUtilsV2.ENTITY_TYPE_WITH_COMPLEX_COLLECTION_ATTR;
+import static 
org.apache.atlas.TestUtilsV2.ENTITY_TYPE_WITH_COMPLEX_COLLECTION_ATTR_DELETE;
+import static org.apache.atlas.TestUtilsV2.NAME;
+import static org.apache.atlas.repository.graph.GraphHelper.getStatus;
+import static org.apache.atlas.type.AtlasTypeUtil.getAtlasObjectId;
+import static org.testng.Assert.assertNull;
+import static org.testng.AssertJUnit.assertEquals;
+
+@Guice(modules = TestModules.TestOnlyModule.class)
+public class AtlasComplexAttributesTest extends AtlasEntityTestBase {
+    private AtlasEntityWithExtInfo complexCollectionAttrEntity;
+    private AtlasEntityWithExtInfo complexCollectionAttrEntityForDelete;
+    private AtlasEntityWithExtInfo mapAttributesEntity;
+
+    @BeforeClass
+    public void setUp() throws Exception {
+        super.setUp();
+
+        // create typeDefs
+        AtlasTypesDef[] testTypesDefs = new AtlasTypesDef[] { 
TestUtilsV2.defineTypeWithComplexCollectionAttributes(),
+                                                              
TestUtilsV2.defineTypeWithMapAttributes() };
+        createTypesDef(testTypesDefs);
+
+        // create entity
+        complexCollectionAttrEntity          = 
TestUtilsV2.createComplexCollectionAttrEntity();
+        complexCollectionAttrEntityForDelete = 
TestUtilsV2.createComplexCollectionAttrEntity();
+        mapAttributesEntity                  = 
TestUtilsV2.createMapAttrEntity();
+    }
+
+    @Test
+    public void testCreateComplexAttributeEntity() throws Exception {
+        init();
+
+        EntityMutationResponse response      = entityStore.createOrUpdate(new 
AtlasEntityStream(complexCollectionAttrEntity), false);
+        AtlasEntityHeader      entityCreated = 
response.getFirstCreatedEntityByTypeName(ENTITY_TYPE_WITH_COMPLEX_COLLECTION_ATTR);
+
+        validateEntity(complexCollectionAttrEntity, 
getEntityFromStore(entityCreated));
+    }
+
+    @Test
+    public void testPrimitiveMapAttributes() throws Exception {
+        init();
+
+        EntityMutationResponse response        = 
entityStore.createOrUpdate(new AtlasEntityStream(mapAttributesEntity), false);
+        AtlasEntityHeader      entityCreated   = 
response.getFirstCreatedEntityByTypeName(ENTITY_TYPE_MAP);
+        AtlasEntity            entityFromStore = 
getEntityFromStore(entityCreated);
+        validateEntity(mapAttributesEntity, entityFromStore);
+
+        // Modify map of primitives
+        AtlasEntity attrEntity = 
getEntityFromStore(mapAttributesEntity.getEntity().getGuid());
+
+        Map<String, String> map1 = new HashMap<String, String>() {{ 
put("map1Key11", "value11");
+                                                                    
put("map1Key22", "value22");
+                                                                    
put("map1Key33", "value33"); }};
+
+        Map<String, Integer> map2 = new HashMap<String, Integer>() {{ 
put("map2Key11", 1100);
+                                                                      
put("map2Key22", 2200);
+                                                                      
put("map2Key33", 3300); }};
+
+        Map<String, Boolean> map3 = new HashMap<String, Boolean>() {{ 
put("map3Key11", true);
+                                                                      
put("map3Key22", false);
+                                                                      
put("map3Key33", true); }};
+
+        Map<String, Float> map4 = new HashMap<String, Float>() {{ 
put("map4Key11", 11.0f);
+                                                                  
put("map4Key22", 22.0f);
+                                                                  
put("map4Key33", 33.0f); }};
+
+        Map<String, Date> map5 = new HashMap<String, Date>() {{ 
put("map5Key11", DateUtils.addHours(new Date(), 1));
+                                                                
put("map5Key22", DateUtils.addHours(new Date(), 2));
+                                                                
put("map5Key33", DateUtils.addHours(new Date(), 3)); }};
+
+        updateEntityMapAttributes(attrEntity, map1, map2, map3, map4, map5);
+
+        AtlasEntitiesWithExtInfo attrEntitiesInfo = new 
AtlasEntitiesWithExtInfo(attrEntity);
+        response = entityStore.createOrUpdate(new 
AtlasEntityStream(attrEntitiesInfo), false);
+        AtlasEntityHeader updatedAttrEntity = 
response.getFirstUpdatedEntityByTypeName(ENTITY_TYPE_MAP);
+        AtlasEntity       updatedFromStore  = 
getEntityFromStore(updatedAttrEntity);
+        validateEntity(attrEntitiesInfo, updatedFromStore);
+
+        // Add new entry to map of primitives
+        map1.put("map1Key44", "value44");
+        map2.put("map2Key44", 4400);
+        map3.put("map3Key44", false);
+        map4.put("map4Key44", 44.0f);
+        map5.put("map5Key44", DateUtils.addHours(new Date(), 4));
+
+        updateEntityMapAttributes(attrEntity, map1, map2, map3, map4, map5);
+
+        attrEntitiesInfo  = new AtlasEntitiesWithExtInfo(attrEntity);
+        response          = entityStore.createOrUpdate(new 
AtlasEntityStream(attrEntitiesInfo), false);
+        updatedAttrEntity = 
response.getFirstUpdatedEntityByTypeName(ENTITY_TYPE_MAP);
+        updatedFromStore  = getEntityFromStore(updatedAttrEntity);
+        validateEntity(attrEntitiesInfo, updatedFromStore);
+
+        // Remove an entry from map of primitives
+        map1.remove("map1Key11");
+        map2.remove("map2Key11");
+        map3.remove("map3Key11");
+        map4.remove("map4Key11");
+        map5.remove("map5Key11");
+
+        updateEntityMapAttributes(attrEntity, map1, map2, map3, map4, map5);
+
+        attrEntitiesInfo  = new AtlasEntitiesWithExtInfo(attrEntity);
+        response          = entityStore.createOrUpdate(new 
AtlasEntityStream(attrEntitiesInfo), false);
+        updatedAttrEntity = 
response.getFirstUpdatedEntityByTypeName(ENTITY_TYPE_MAP);
+        updatedFromStore  = getEntityFromStore(updatedAttrEntity);
+        validateEntity(attrEntitiesInfo, updatedFromStore);
+
+        // Edit existing entry to map of primitives
+        map1.put("map1Key44", "value44-edit");
+        map2.put("map2Key44", 5555);
+        map3.put("map3Key44", true);
+        map4.put("map4Key44", 55.5f);
+        map5.put("map5Key44", DateUtils.addHours(new Date(), 5));
+
+        updateEntityMapAttributes(attrEntity, map1, map2, map3, map4, map5);
+
+        attrEntitiesInfo  = new AtlasEntitiesWithExtInfo(attrEntity);
+        response          = entityStore.createOrUpdate(new 
AtlasEntityStream(attrEntitiesInfo), false);
+        updatedAttrEntity = 
response.getFirstUpdatedEntityByTypeName(ENTITY_TYPE_MAP);
+        updatedFromStore  = getEntityFromStore(updatedAttrEntity);
+        validateEntity(attrEntitiesInfo, updatedFromStore);
+
+        // clear primitive map entries
+        map1.clear();
+        map2.clear();
+        map3.clear();
+        map4.clear();
+        map5.clear();
+
+        updateEntityMapAttributes(attrEntity, map1, map2, map3, map4, map5);
+
+        attrEntitiesInfo  = new AtlasEntitiesWithExtInfo(attrEntity);
+        response          = entityStore.createOrUpdate(new 
AtlasEntityStream(attrEntitiesInfo), false);
+        updatedAttrEntity = 
response.getFirstUpdatedEntityByTypeName(ENTITY_TYPE_MAP);
+        updatedFromStore  = getEntityFromStore(updatedAttrEntity);
+        validateEntity(attrEntitiesInfo, updatedFromStore);
+    }
+
+    private void updateEntityMapAttributes(AtlasEntity attrEntity, Map<String, 
String> map1, Map<String, Integer> map2,
+                                           Map<String, Boolean> map3, 
Map<String, Float> map4, Map<String, Date> map5) {
+        attrEntity.setAttribute("mapAttr1", map1);
+        attrEntity.setAttribute("mapAttr2", map2);
+        attrEntity.setAttribute("mapAttr3", map3);
+        attrEntity.setAttribute("mapAttr4", map4);
+        attrEntity.setAttribute("mapAttr5", map5);
+    }
+
+    @Test(dependsOnMethods = "testCreateComplexAttributeEntity")
+    public void testStructArray() throws Exception {
+        init();
+        AtlasEntity              complexEntity       = 
getEntityFromStore(complexCollectionAttrEntity.getEntity().getGuid());
+        AtlasEntitiesWithExtInfo complexEntitiesInfo = new 
AtlasEntitiesWithExtInfo(complexEntity);
+
+        // Modify array of structs
+        List<AtlasStruct> structList = new ArrayList<>(Arrays.asList(new 
AtlasStruct("struct_type", "name", "structArray00"),
+                                                                     new 
AtlasStruct("struct_type", "name", "structArray11"),
+                                                                     new 
AtlasStruct("struct_type", "name", "structArray22")));
+        complexEntity.setAttribute("listOfStructs", structList);
+
+        EntityMutationResponse response             = 
entityStore.createOrUpdate(new AtlasEntityStream(complexEntitiesInfo), false);
+        AtlasEntityHeader      updatedComplexEntity = 
response.getFirstUpdatedEntityByTypeName(ENTITY_TYPE_WITH_COMPLEX_COLLECTION_ATTR);
+        validateEntity(complexEntitiesInfo, 
getEntityFromStore(updatedComplexEntity));
+
+        // add a new element to array of struct
+        init();
+        structList.add(new AtlasStruct("struct_type", "name", 
"structArray33"));
+        complexEntity.setAttribute("listOfStructs", structList);
+        response = entityStore.createOrUpdate(new 
AtlasEntityStream(complexEntitiesInfo), false);
+        updatedComplexEntity = 
response.getFirstUpdatedEntityByTypeName(ENTITY_TYPE_WITH_COMPLEX_COLLECTION_ATTR);
+        validateEntity(complexEntitiesInfo, 
getEntityFromStore(updatedComplexEntity));
+
+        // remove one of the struct values - structArray00
+        init();
+        structList.remove(0);
+        complexEntity.setAttribute("listOfStructs", structList);
+        response = entityStore.createOrUpdate(new 
AtlasEntityStream(complexEntitiesInfo), false);
+        updatedComplexEntity = 
response.getFirstUpdatedEntityByTypeName(ENTITY_TYPE_WITH_COMPLEX_COLLECTION_ATTR);
+        validateEntity(complexEntitiesInfo, 
getEntityFromStore(updatedComplexEntity));
+
+        // Update struct value within array of struct
+        init();
+        structList.get(0).setAttribute(NAME, "structArray11-edit");
+        complexEntity.setAttribute("listOfStructs", structList);
+        response = entityStore.createOrUpdate(new 
AtlasEntityStream(complexEntitiesInfo), false);
+        updatedComplexEntity = 
response.getFirstUpdatedEntityByTypeName(ENTITY_TYPE_WITH_COMPLEX_COLLECTION_ATTR);
+        validateEntity(complexEntitiesInfo, 
getEntityFromStore(updatedComplexEntity));
+
+        // add a repeated element to array of struct
+        init();
+        structList.add(new AtlasStruct("struct_type", "name", 
"structArray33"));
+        complexEntity.setAttribute("listOfStructs", structList);
+        response = entityStore.createOrUpdate(new 
AtlasEntityStream(complexEntitiesInfo), false);
+        updatedComplexEntity = 
response.getFirstUpdatedEntityByTypeName(ENTITY_TYPE_WITH_COMPLEX_COLLECTION_ATTR);
+        validateEntity(complexEntitiesInfo, 
getEntityFromStore(updatedComplexEntity));
+
+        // Remove all elements. Should set array attribute to null
+        init();
+        structList.clear();
+        complexEntity.setAttribute("listOfStructs", structList);
+        response = entityStore.createOrUpdate(new 
AtlasEntityStream(complexEntitiesInfo), false);
+        updatedComplexEntity = 
response.getFirstUpdatedEntityByTypeName(ENTITY_TYPE_WITH_COMPLEX_COLLECTION_ATTR);
+        validateEntity(complexEntitiesInfo, 
getEntityFromStore(updatedComplexEntity));
+    }
+
+    @Test(dependsOnMethods = "testStructArray")
+    public void testEntityArray() throws Exception {
+        init();
+        AtlasEntity              complexEntity       = 
getEntityFromStore(complexCollectionAttrEntity.getEntity().getGuid());
+        AtlasEntitiesWithExtInfo complexEntitiesInfo = new 
AtlasEntitiesWithExtInfo(complexEntity);
+
+        // Modify array of entities
+        AtlasEntity e0Array = new AtlasEntity(ENTITY_TYPE, new HashMap<String, 
Object>() {{ put(NAME, "entityArray00"); put("isReplicated", true); }});
+        AtlasEntity e1Array = new AtlasEntity(ENTITY_TYPE, new HashMap<String, 
Object>() {{ put(NAME, "entityArray11"); put("isReplicated", false); }});
+        AtlasEntity e2Array = new AtlasEntity(ENTITY_TYPE, new HashMap<String, 
Object>() {{ put(NAME, "entityArray22"); put("isReplicated", true); }});
+
+        List<AtlasObjectId> entityList = new 
ArrayList<>(Arrays.asList(getAtlasObjectId(e0Array), getAtlasObjectId(e1Array), 
getAtlasObjectId(e2Array)));
+
+        complexEntity.setAttribute("listOfEntities", entityList);
+        complexEntitiesInfo.addReferredEntity(e0Array);
+        complexEntitiesInfo.addReferredEntity(e1Array);
+        complexEntitiesInfo.addReferredEntity(e2Array);
+
+        init();
+        EntityMutationResponse response             = 
entityStore.createOrUpdate(new AtlasEntityStream(complexEntitiesInfo), false);
+        AtlasEntityHeader      updatedComplexEntity = 
response.getFirstUpdatedEntityByTypeName(ENTITY_TYPE_WITH_COMPLEX_COLLECTION_ATTR);
+        validateEntity(complexEntitiesInfo, 
getEntityFromStore(updatedComplexEntity));
+
+        // add a new element to array of entities
+        init();
+        AtlasEntity e3Array = new AtlasEntity(ENTITY_TYPE, new HashMap<String, 
Object>() {{ put(NAME, "entityArray33"); put("isReplicated", true); }});
+        entityList.add(getAtlasObjectId(e3Array));
+        complexEntity.setAttribute("listOfEntities", entityList);
+        complexEntitiesInfo.addReferredEntity(e3Array);
+
+        response = entityStore.createOrUpdate(new 
AtlasEntityStream(complexEntitiesInfo), false);
+        updatedComplexEntity = 
response.getFirstUpdatedEntityByTypeName(ENTITY_TYPE_WITH_COMPLEX_COLLECTION_ATTR);
+        validateEntity(complexEntitiesInfo, 
getEntityFromStore(updatedComplexEntity));
+
+        // remove one of the entity values - entityArray00
+        init();
+        entityList.remove(0);
+        complexEntity.setAttribute("listOfEntities", entityList);
+
+        response = entityStore.createOrUpdate(new 
AtlasEntityStream(complexEntitiesInfo), false);
+        updatedComplexEntity = 
response.getFirstUpdatedEntityByTypeName(ENTITY_TYPE_WITH_COMPLEX_COLLECTION_ATTR);
+        validateEntity(complexEntitiesInfo, 
getEntityFromStore(updatedComplexEntity));
+
+        // Update entity value within array of struct
+        init();
+        e1Array.setAttribute(NAME, "entityArray11-edit");
+        complexEntity.setAttribute("listOfEntities", entityList);
+
+        response = entityStore.createOrUpdate(new 
AtlasEntityStream(complexEntitiesInfo), false);
+        updatedComplexEntity = 
response.getFirstUpdatedEntityByTypeName(ENTITY_TYPE_WITH_COMPLEX_COLLECTION_ATTR);
+        validateEntity(complexEntitiesInfo, 
getEntityFromStore(updatedComplexEntity));
+
+        // add a repeated element to array of struct
+        init();
+        AtlasEntity e3Array_duplicate = new AtlasEntity(ENTITY_TYPE, new 
HashMap<String, Object>() {{ put(NAME, "entityArray33"); put("isReplicated", 
true); }});
+        entityList.add(getAtlasObjectId(e3Array_duplicate));
+        complexEntity.setAttribute("listOfEntities", entityList);
+        complexEntitiesInfo.addReferredEntity(e3Array_duplicate);
+
+        response = entityStore.createOrUpdate(new 
AtlasEntityStream(complexEntitiesInfo), false);
+        updatedComplexEntity = 
response.getFirstUpdatedEntityByTypeName(ENTITY_TYPE_WITH_COMPLEX_COLLECTION_ATTR);
+        validateEntity(complexEntitiesInfo, 
getEntityFromStore(updatedComplexEntity));
+
+        // Remove all elements. Should set array attribute to null
+        init();
+        entityList.clear();
+        complexEntity.setAttribute("listOfEntities", entityList);
+
+        response = entityStore.createOrUpdate(new 
AtlasEntityStream(complexEntitiesInfo), false);
+        updatedComplexEntity = 
response.getFirstUpdatedEntityByTypeName(ENTITY_TYPE_WITH_COMPLEX_COLLECTION_ATTR);
+        validateEntity(complexEntitiesInfo, 
getEntityFromStore(updatedComplexEntity));
+    }
+
+    @Test(dependsOnMethods = "testEntityArray")
+    public void testStructMap() throws Exception {
+        init();
+        AtlasEntity              complexEntity       = 
getEntityFromStore(complexCollectionAttrEntity.getEntity().getGuid());
+        AtlasEntitiesWithExtInfo complexEntitiesInfo = new 
AtlasEntitiesWithExtInfo(complexEntity);
+
+        // Modify map of structs
+        HashMap<String, AtlasStruct> structMap = new HashMap<String, 
AtlasStruct>() {{
+                                                        put("key00", new 
AtlasStruct("struct_type", "name", "structMap00"));
+                                                        put("key11", new 
AtlasStruct("struct_type", "name", "structMap11"));
+                                                        put("key22", new 
AtlasStruct("struct_type", "name", "structMap22")); }};
+
+        complexEntity.setAttribute("mapOfStructs", structMap);
+
+        EntityMutationResponse response             = 
entityStore.createOrUpdate(new AtlasEntityStream(complexEntitiesInfo), false);
+        AtlasEntityHeader      updatedComplexEntity = 
response.getFirstUpdatedEntityByTypeName(ENTITY_TYPE_WITH_COMPLEX_COLLECTION_ATTR);
+        validateEntity(complexEntitiesInfo, 
getEntityFromStore(updatedComplexEntity));
+
+        // add a new element to map of struct - structMap6
+        init();
+        structMap.put("key33", new AtlasStruct("struct_type", "name", 
"structMap33"));
+        complexEntity.setAttribute("mapOfStructs", structMap);
+
+        response             = entityStore.createOrUpdate(new 
AtlasEntityStream(complexEntitiesInfo), false);
+        updatedComplexEntity = 
response.getFirstUpdatedEntityByTypeName(ENTITY_TYPE_WITH_COMPLEX_COLLECTION_ATTR);
+        validateEntity(complexEntitiesInfo, 
getEntityFromStore(updatedComplexEntity));
+
+        // remove one of the entity values - structMap
+        init();
+        structMap.remove("key00");
+        complexEntity.setAttribute("mapOfStructs", structMap);
+
+        response             = entityStore.createOrUpdate(new 
AtlasEntityStream(complexEntitiesInfo), false);
+        updatedComplexEntity = 
response.getFirstUpdatedEntityByTypeName(ENTITY_TYPE_WITH_COMPLEX_COLLECTION_ATTR);
+        validateEntity(complexEntitiesInfo, 
getEntityFromStore(updatedComplexEntity));
+
+        // Update struct value within map of struct
+        init();
+        structMap.get("key11").setAttribute("name", "structMap11-edit");
+        complexEntity.setAttribute("mapOfStructs", structMap);
+
+        response = entityStore.createOrUpdate(new 
AtlasEntityStream(complexEntitiesInfo), false);
+        updatedComplexEntity = 
response.getFirstUpdatedEntityByTypeName(ENTITY_TYPE_WITH_COMPLEX_COLLECTION_ATTR);
+        validateEntity(complexEntitiesInfo, 
getEntityFromStore(updatedComplexEntity));
+
+        // add a repeated element to array of struct
+        init();
+        structMap.put("key33", new AtlasStruct("struct_type", "name", 
"structMap33"));
+        complexEntity.setAttribute("mapOfStructs", structMap);
+        response = entityStore.createOrUpdate(new 
AtlasEntityStream(complexEntitiesInfo), false);
+        updatedComplexEntity = 
response.getFirstUpdatedEntityByTypeName(ENTITY_TYPE_WITH_COMPLEX_COLLECTION_ATTR);
+        // no update since duplicate entry
+        assertNull(updatedComplexEntity);
+
+        // Remove all elements. Should set array attribute to null
+        init();
+        structMap.clear();
+        complexEntity.setAttribute("mapOfStructs", structMap);
+        response = entityStore.createOrUpdate(new 
AtlasEntityStream(complexEntitiesInfo), false);
+        updatedComplexEntity = 
response.getFirstUpdatedEntityByTypeName(ENTITY_TYPE_WITH_COMPLEX_COLLECTION_ATTR);
+        validateEntity(complexEntitiesInfo, 
getEntityFromStore(updatedComplexEntity));
+    }
+
+    @Test(dependsOnMethods = "testStructMap")
+    public void testEntityMap() throws Exception {
+        init();
+        AtlasEntity              complexEntity       = 
getEntityFromStore(complexCollectionAttrEntity.getEntity().getGuid());
+        AtlasEntitiesWithExtInfo complexEntitiesInfo = new 
AtlasEntitiesWithExtInfo(complexEntity);
+
+        // Modify map of entities
+        AtlasEntity e0MapValue = new AtlasEntity(ENTITY_TYPE, new 
HashMap<String, Object>() {{ put(NAME, "entityMapValue00"); put("isReplicated", 
false); }});
+        AtlasEntity e1MapValue = new AtlasEntity(ENTITY_TYPE, new 
HashMap<String, Object>() {{ put(NAME, "entityMapValue11"); put("isReplicated", 
true); }});
+        AtlasEntity e2MapValue = new AtlasEntity(ENTITY_TYPE, new 
HashMap<String, Object>() {{ put(NAME, "entityMapValue22"); put("isReplicated", 
false); }});
+
+        HashMap<String, Object> entityMap = new HashMap<String, Object>() {{ 
put("key00", getAtlasObjectId(e0MapValue));
+                                                                             
put("key11", getAtlasObjectId(e1MapValue));
+                                                                             
put("key22", getAtlasObjectId(e2MapValue)); }};
+        complexEntity.setAttribute("mapOfEntities", entityMap);
+        complexEntitiesInfo.addReferredEntity(e0MapValue);
+        complexEntitiesInfo.addReferredEntity(e1MapValue);
+        complexEntitiesInfo.addReferredEntity(e2MapValue);
+
+        init();
+        EntityMutationResponse response             = 
entityStore.createOrUpdate(new AtlasEntityStream(complexEntitiesInfo), false);
+        AtlasEntityHeader      updatedComplexEntity = 
response.getFirstUpdatedEntityByTypeName(ENTITY_TYPE_WITH_COMPLEX_COLLECTION_ATTR);
+        validateEntity(complexEntitiesInfo, 
getEntityFromStore(updatedComplexEntity));
+
+        // add a new element to map of entities
+        init();
+        AtlasEntity e3MapValue = new AtlasEntity(ENTITY_TYPE, new 
HashMap<String, Object>() {{ put(NAME, "entityMapValue33"); put("isReplicated", 
false); }});
+        entityMap.put("key33", getAtlasObjectId(e3MapValue));
+        complexEntity.setAttribute("mapOfEntities", entityMap);
+        complexEntitiesInfo.addReferredEntity(e3MapValue);
+
+        response = entityStore.createOrUpdate(new 
AtlasEntityStream(complexEntitiesInfo), false);
+        updatedComplexEntity = 
response.getFirstUpdatedEntityByTypeName(ENTITY_TYPE_WITH_COMPLEX_COLLECTION_ATTR);
+        validateEntity(complexEntitiesInfo, 
getEntityFromStore(updatedComplexEntity));
+
+        // remove one of the entity values - [key00 : entityMapValue00]
+        init();
+        entityMap.remove("key00");
+        complexEntity.setAttribute("mapOfEntities", entityMap);
+        complexEntitiesInfo.addReferredEntity(e3MapValue);
+
+        response = entityStore.createOrUpdate(new 
AtlasEntityStream(complexEntitiesInfo), false);
+        updatedComplexEntity = 
response.getFirstUpdatedEntityByTypeName(ENTITY_TYPE_WITH_COMPLEX_COLLECTION_ATTR);
+        validateEntity(complexEntitiesInfo, 
getEntityFromStore(updatedComplexEntity));
+
+        // Update entity value within map of entities
+        init();
+
+        AtlasEntity e1MapValueEdit = new AtlasEntity(ENTITY_TYPE, new 
HashMap<String, Object>() {{ put(NAME, "entityMapValue11-edit"); 
put("isReplicated", false); }});
+        entityMap.clear();
+        entityMap.put("key11", getAtlasObjectId(e1MapValueEdit));
+        entityMap.put("key22", getAtlasObjectId(e2MapValue));
+        entityMap.put("key33", getAtlasObjectId(e3MapValue));
+        complexEntity.setAttribute("mapOfEntities", entityMap);
+        complexEntitiesInfo.addReferredEntity(e1MapValueEdit);
+
+        response = entityStore.createOrUpdate(new 
AtlasEntityStream(complexEntitiesInfo), false);
+        updatedComplexEntity = 
response.getFirstUpdatedEntityByTypeName(ENTITY_TYPE_WITH_COMPLEX_COLLECTION_ATTR);
+        validateEntity(complexEntitiesInfo, 
getEntityFromStore(updatedComplexEntity));
+
+        // add a repeated element to map of entities
+        init();
+        e3MapValue = new AtlasEntity(ENTITY_TYPE, new HashMap<String, 
Object>() {{ put(NAME, "entityMapValue33"); put("isReplicated", false); }});
+        entityMap.put("key33", getAtlasObjectId(e3MapValue));
+        complexEntity.setAttribute("mapOfEntities", entityMap);
+        complexEntitiesInfo.addReferredEntity(e3MapValue);
+
+        response = entityStore.createOrUpdate(new 
AtlasEntityStream(complexEntitiesInfo), false);
+        updatedComplexEntity = 
response.getFirstUpdatedEntityByTypeName(ENTITY_TYPE_WITH_COMPLEX_COLLECTION_ATTR);
+        validateEntity(complexEntitiesInfo, 
getEntityFromStore(updatedComplexEntity));
+
+        // Remove all elements. Should set map attribute to null
+        init();
+        entityMap.clear();
+        complexEntity.setAttribute("mapOfEntities", entityMap);
+        complexEntitiesInfo.addReferredEntity(e3MapValue);
+
+        response = entityStore.createOrUpdate(new 
AtlasEntityStream(complexEntitiesInfo), false);
+        updatedComplexEntity = 
response.getFirstUpdatedEntityByTypeName(ENTITY_TYPE_WITH_COMPLEX_COLLECTION_ATTR);
+        validateEntity(complexEntitiesInfo, 
getEntityFromStore(updatedComplexEntity));
+    }
+
+    @Test(dependsOnMethods = "testEntityMap")
+    public void testDeleteEntityRemoveReferences() throws Exception {
+        init();
+
+        complexCollectionAttrEntityForDelete.getEntity().setAttribute(NAME, 
ENTITY_TYPE_WITH_COMPLEX_COLLECTION_ATTR_DELETE);
+
+        EntityMutationResponse response      = entityStore.createOrUpdate(new 
AtlasEntityStream(complexCollectionAttrEntityForDelete), false);
+        AtlasEntityHeader      entityCreated = 
response.getFirstCreatedEntityByTypeName(ENTITY_TYPE_WITH_COMPLEX_COLLECTION_ATTR);
+
+        validateEntity(complexCollectionAttrEntityForDelete, 
getEntityFromStore(entityCreated));
+
+        // delete entity and check if referenced complex attribute edges are 
deleted
+        response = entityStore.deleteById(entityCreated.getGuid());
+
+        AtlasEntityHeader entityDeleted = 
response.getFirstDeletedEntityByTypeName(ENTITY_TYPE_WITH_COMPLEX_COLLECTION_ATTR);
+
+        AtlasEntityWithExtInfo deletedEntityWithExtInfo = 
entityStore.getById(entityDeleted.getGuid());
+        AtlasVertex            deletedEntityVertex      = 
AtlasGraphUtilsV2.findByGuid(entityDeleted.getGuid());
+        Iterator<AtlasEdge>    edges                    = 
deletedEntityVertex.getEdges(AtlasEdgeDirection.OUT).iterator();
+
+        // validate all attribute edges are deleted
+        while (edges != null && edges.hasNext()) {
+            assertEquals(getStatus(edges.next()), AtlasEntity.Status.DELETED);
+        }
+
+        AtlasEntity                deletedEntity  = 
deletedEntityWithExtInfo.getEntity();
+        List<AtlasObjectId>        listOfEntities = (List<AtlasObjectId>) 
deletedEntity.getAttribute("listOfEntities");
+        Map<String, AtlasObjectId> mapOfEntities  = (Map<String, 
AtlasObjectId>) deletedEntity.getAttribute("mapOfEntities");
+
+        // validate entity attributes are deleted
+        for (AtlasObjectId o  : listOfEntities) {
+            AtlasEntity entity = 
deletedEntityWithExtInfo.getEntity(o.getGuid());
+            assertEquals(entity.getStatus(), AtlasEntity.Status.DELETED);
+        }
+
+        for (AtlasObjectId o  : mapOfEntities.values()) {
+            AtlasEntity entity = 
deletedEntityWithExtInfo.getEntity(o.getGuid());
+            assertEquals(entity.getStatus(), AtlasEntity.Status.DELETED);
+        }
+    }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/atlas/blob/3d5b4880/repository/src/test/java/org/apache/atlas/repository/store/graph/v2/AtlasEntityDefStoreV2Test.java
----------------------------------------------------------------------
diff --git 
a/repository/src/test/java/org/apache/atlas/repository/store/graph/v2/AtlasEntityDefStoreV2Test.java
 
b/repository/src/test/java/org/apache/atlas/repository/store/graph/v2/AtlasEntityDefStoreV2Test.java
new file mode 100644
index 0000000..5876248
--- /dev/null
+++ 
b/repository/src/test/java/org/apache/atlas/repository/store/graph/v2/AtlasEntityDefStoreV2Test.java
@@ -0,0 +1,80 @@
+/**
+ * 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.v2;
+
+import com.google.inject.Inject;
+import org.apache.atlas.ApplicationProperties;
+import org.apache.atlas.AtlasErrorCode;
+import org.apache.atlas.AtlasException;
+import org.apache.atlas.TestModules;
+import org.apache.atlas.exception.AtlasBaseException;
+import org.apache.atlas.model.typedef.AtlasEntityDef;
+import org.apache.atlas.repository.graph.AtlasGraphProvider;
+import org.apache.atlas.runner.LocalSolrRunner;
+import org.apache.atlas.type.AtlasTypeUtil;
+import org.testng.Assert;
+import org.testng.annotations.AfterClass;
+import org.testng.annotations.DataProvider;
+import org.testng.annotations.Guice;
+import org.testng.annotations.Test;
+
+import java.util.Collections;
+
+import static org.apache.atlas.graph.GraphSandboxUtil.useLocalSolr;
+
+/**
+ * Tests for AtlasEntityStoreV1
+ */
+@Guice(modules = TestModules.TestOnlyModule.class)
+public class AtlasEntityDefStoreV2Test {
+
+    @Inject
+    private
+    AtlasEntityDefStoreV2 entityDefStore;
+
+    @DataProvider
+    public Object[][] invalidAttributeNameWithReservedKeywords(){
+        AtlasEntityDef invalidAttrNameType =
+            AtlasTypeUtil.createClassTypeDef("Invalid_Attribute_Type", 
"description", Collections.emptySet(),
+                AtlasTypeUtil.createRequiredAttrDef("order", "string"),
+                AtlasTypeUtil.createRequiredAttrDef("limit", "string"));
+
+        return new Object[][] {{
+            invalidAttrNameType
+        }};
+    }
+
+    @Test(dataProvider = "invalidAttributeNameWithReservedKeywords")
+    public void testCreateTypeWithReservedKeywords(AtlasEntityDef 
atlasEntityDef) throws AtlasException {
+        try {
+            
ApplicationProperties.get().setProperty(AtlasAbstractDefStoreV2.ALLOW_RESERVED_KEYWORDS,
 false);
+            entityDefStore.create(atlasEntityDef, null);
+        } catch (AtlasBaseException e) {
+            Assert.assertEquals(e.getAtlasErrorCode(), 
AtlasErrorCode.ATTRIBUTE_NAME_INVALID);
+        }
+    }
+
+    @AfterClass
+    public void clear() throws Exception {
+        AtlasGraphProvider.cleanup();
+
+        if (useLocalSolr()) {
+            LocalSolrRunner.stop();
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/atlas/blob/3d5b4880/repository/src/test/java/org/apache/atlas/repository/store/graph/v2/AtlasEntityStoreV2BulkImportPercentTest.java
----------------------------------------------------------------------
diff --git 
a/repository/src/test/java/org/apache/atlas/repository/store/graph/v2/AtlasEntityStoreV2BulkImportPercentTest.java
 
b/repository/src/test/java/org/apache/atlas/repository/store/graph/v2/AtlasEntityStoreV2BulkImportPercentTest.java
new file mode 100644
index 0000000..b4824a8
--- /dev/null
+++ 
b/repository/src/test/java/org/apache/atlas/repository/store/graph/v2/AtlasEntityStoreV2BulkImportPercentTest.java
@@ -0,0 +1,167 @@
+/**
+ * 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.v2;
+
+import org.mockito.invocation.InvocationOnMock;
+import org.mockito.stubbing.Answer;
+import org.slf4j.Logger;
+import org.testng.annotations.BeforeClass;
+import org.testng.annotations.Test;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import static org.mockito.Matchers.*;
+import static org.mockito.Mockito.doAnswer;
+import static org.mockito.Mockito.mock;
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertTrue;
+
+public class AtlasEntityStoreV2BulkImportPercentTest {
+
+    private final int MAX_PERCENT = 100;
+    private List<Integer> percentHolder;
+    private Logger log;
+
+    public void setupPercentHolder(int max) {
+        percentHolder = new ArrayList<>();
+    }
+
+    @BeforeClass
+    void mockLog() {
+        log = mock(Logger.class);
+
+        doAnswer(new Answer() {
+            @Override
+            public Object answer(InvocationOnMock invocationOnMock) throws 
Throwable {
+                Object[] args = invocationOnMock.getArguments();
+                Integer d = (Integer) args[1];
+                percentHolder.add(d.intValue());
+                return null;
+            }
+        }).when(log).info(anyString(), anyFloat(), anyInt(), anyString());
+    }
+
+    @Test
+    public void percentTest_Equal4() throws Exception {
+        runWithSize(4);
+        assertEqualsForPercentHolder(25.0, 50.0, 75.0, 100.0);
+    }
+
+    @Test
+    public void percentTest_Equal10() throws Exception {
+        runWithSize(10);
+
+        assertEqualsForPercentHolder(10.0, 20.0, 30.0, 40.0, 50, 60, 70, 80, 
90, 100);
+    }
+
+    private void assertEqualsForPercentHolder(double... expected) {
+        assertEquals(percentHolder.size(), expected.length);
+        Object actual[] = percentHolder.toArray();
+        for (int i = 0; i < expected.length; i++) {
+            assertTrue((int) Double.compare((int) actual[i], expected[i]) == 
0);
+        }
+    }
+
+    @Test
+    public void bulkImportPercentageTestLessThan100() throws Exception {
+        int streamSize = 20;
+
+        runWithSize(streamSize);
+        assertEqualsForPercentHolder(5, 10, 15, 20, 25, 30, 35, 40, 45, 50, 
55, 60, 65, 70, 75, 80, 85, 90, 95, 100);
+    }
+
+    @Test
+    public void percentTest_Equal101() throws Exception {
+        int streamSize = 101;
+
+        double[] expected = fillPercentHolderWith100();
+
+        runWithSize(streamSize);
+        assertEqualsForPercentHolder(expected);
+    }
+
+    @Test
+    public void percentTest_Equal200() throws Exception {
+        int streamSize = 200;
+
+        double[] expected = fillPercentHolderWith100();
+
+        runWithSize(streamSize);
+        assertEqualsForPercentHolder(expected);
+    }
+
+    @Test
+    public void percentTest_Equal202() throws Exception {
+        int streamSize = 202;
+
+        double[] expected = fillPercentHolderWith100();
+
+        runWithSize(streamSize);
+        assertEqualsForPercentHolder(expected);
+    }
+
+    @Test
+    public void percentTest_Equal1001() throws Exception {
+        int streamSize = 1001;
+        double[] expected = fillPercentHolderWith100();
+
+        runWithSize(streamSize);
+        assertEqualsForPercentHolder(expected);
+    }
+
+    @Test
+    public void percentTest_Equal4323() throws Exception {
+        int streamSize = 4323;
+
+        double[] expected = fillPercentHolderWith100();
+        runWithSize(streamSize);
+        assertEqualsForPercentHolder(expected);
+    }
+
+    @Test
+    public void percentTest_Equal269() throws Exception {
+        int streamSize = 269;
+
+        double[] expected = fillPercentHolderWith100();
+        runWithSize(streamSize);
+        assertEqualsForPercentHolder(expected);
+    }
+
+    private void runWithSize(int streamSize) throws Exception {
+        float currentPercent = 0;
+        setupPercentHolder(streamSize);
+        for (int currentIndex = 0; currentIndex < streamSize; currentIndex++) {
+            currentPercent = invokeBulkImportProgress(currentIndex + 1, 
streamSize, currentPercent);
+        }
+    }
+
+    private float invokeBulkImportProgress(int currentIndex, int streamSize, 
float currentPercent) throws Exception {
+        return BulkImporterImpl.updateImportProgress(log, currentIndex, 
streamSize, currentPercent, "additional info");
+    }
+
+    private double[] fillPercentHolderWith100() {
+        double start = 1;
+        double expected[] = new double[MAX_PERCENT];
+        for (int i = 0; i < expected.length; i++) {
+            expected[i] = start;
+            start ++;
+        }
+        return expected;
+    }
+}

Reply via email to