content: package alien4cloud.component.dao.model.indexed;
  
  import static org.junit.Assert.assertEquals;
  import static org.junit.Assert.assertNotEquals;
  import static org.junit.Assert.assertNotNull;
  import static org.junit.Assert.assertNull;
  import static org.junit.Assert.assertSame;
  import static org.junit.Assert.assertTrue;
  
  import java.util.Arrays;
  import java.util.List;
  import java.util.Map;
  
  import com.google.common.collect.Maps;
  import alien4cloud.rest.utils.JsonUtil;
  import com.fasterxml.jackson.core.JsonProcessingException;
  
  import org.junit.Test;
  
  import alien4cloud.model.common.Tag;
  import org.alien4cloud.tosca.model.definitions.AttributeDefinition;
  import org.alien4cloud.tosca.model.definitions.IValue;
  import org.alien4cloud.tosca.model.types.AbstractInheritableToscaType;
  import alien4cloud.model.components.IndexedModelUtils;
  import org.alien4cloud.tosca.model.types.NodeType;
  import org.alien4cloud.tosca.model.definitions.Interface;
  import org.alien4cloud.tosca.model.definitions.Operation;
  import org.alien4cloud.tosca.model.definitions.PropertyDefinition;
  import org.alien4cloud.tosca.model.definitions.ScalarPropertyValue;
  import alien4cloud.utils.MapUtil;
  
  import com.google.common.collect.Lists;
  
  public class IndexedModelTest {
  
      // root -- child1 -- grandChild1, granChild2
      // |
      // |
      // |------ child2
      // |
      // orphan
      // The sort should give me [root,orphan],[child1,child2],[grandChild1,grandChild2]
      static Map<String, AbstractInheritableToscaType> elementsByIdMap = Maps.newHashMap();
  
      static AbstractInheritableToscaType root, child1, child2, grandChild1, grandChild2;
      static List<Tag> rootTags, childTags;
  
      static NodeType parent, sonWith3Tags, sonWithoutTags;
  
      static {
  
          rootTags = Lists.newArrayList();
          rootTags.add(new Tag("alienicon", "/usr/local/root-icon.png"));
          rootTags.add(new Tag("prod", "deployment details from team A the 21th JAN 2014"));
          rootTags.add(new Tag("misc-details", "<pathed the 22th...>"));
  
          childTags = Lists.newArrayList();
          childTags.add(new Tag("alienicon", "/usr/child-icon.png"));
          childTags.add(new Tag("prodChild", "Bad deployment"));
          childTags.add(new Tag("another-tag", "<pathed the 22th...>"));
  
          parent = new NodeType();
          parent.setElementId("1");
          parent.setArchiveName("tosca.nodes.Root");
          parent.setArchiveVersion("1.0");
          parent.setDerivedFrom(null);
          parent.setDescription("Root description...");
          parent.setTags(rootTags);
  
          sonWith3Tags = new NodeType();
          sonWith3Tags.setElementId("2");
          sonWith3Tags.setArchiveName("tosca.nodes.Compute");
          sonWith3Tags.setArchiveVersion("1.0");
          sonWith3Tags.setDerivedFrom(Arrays.asList("tosca.nodes.Root"));
          sonWith3Tags.setDescription("Child description...");
          sonWith3Tags.setTags(childTags);
  
          sonWithoutTags = new NodeType();
          sonWithoutTags.setElementId("3");
          sonWithoutTags.setArchiveName("tosca.nodes.Network");
          sonWithoutTags.setArchiveVersion("1.2");
          sonWithoutTags.setDerivedFrom(Arrays.asList("tosca.nodes.Root"));
          sonWithoutTags.setDescription("Child 2 description...");
          sonWithoutTags.setTags(null);
  
          root = fabricElement(elementsByIdMap, "root", null, rootTags);
          child1 = fabricElement(elementsByIdMap, "child1", "root", childTags);
          child2 = fabricElement(elementsByIdMap, "child2", "root", null);
          grandChild1 = fabricElement(elementsByIdMap, "grandChild1", "child1", null);
          grandChild2 = fabricElement(elementsByIdMap, "grandChild2", "child1", null);
  
          fabricElement(elementsByIdMap, "orphan1", null, null);
          fabricElement(elementsByIdMap, "orphan2", "toto", null);
          fabricElement(elementsByIdMap, "orphan3", "tata", null);
          fabricElement(elementsByIdMap, "orphan4", "titi", null);
  
      }
  
      @Test
      public void testOrderInheritableElements() {
          List<AbstractInheritableToscaType> sorted = IndexedModelUtils.orderByDerivedFromHierarchy(elementsByIdMap);
  
          for (AbstractInheritableToscaType el : sorted) {
              System.out.println(el.getElementId() + " " + el.getDerivedFrom());
          }
  
          assertTrue(sorted.indexOf(root) < sorted.indexOf(child1));
          assertTrue(sorted.indexOf(root) < sorted.indexOf(child2));
          assertTrue(sorted.indexOf(child1) < sorted.indexOf(grandChild1));
          assertTrue(sorted.indexOf(child1) < sorted.indexOf(grandChild2));
      }
  
      @Test
      public void mergeInheritableIndexWithTags() {
          IndexedModelUtils.mergeInheritableIndex(parent, sonWith3Tags);
  
          // son should have 5 tags : 3 from himself 2 from his parent
          assertEquals(sonWith3Tags.getTags().size(), 5);
  
          // son should'nt have parent icon
          ;
          for (Tag tag : sonWith3Tags.getTags()) {
              if (tag.getName().equals("alienicon")) {
                  assertNotEquals(tag.getValue(), "/usr/local/root-icon.png");
                  assertEquals(tag.getValue(), "/usr/child-icon.png");
              }
          }
  
          // son has all parent's tags
          assertTrue(sonWith3Tags.getTags().containsAll(parent.getTags()));
  
          // Parent witht 3 tags merged with son without tags => son with 3 tags
          IndexedModelUtils.mergeInheritableIndex(parent, sonWithoutTags);
  
          assertEquals(sonWithoutTags.getTags().size(), parent.getTags().size());
          assertEquals(sonWithoutTags.getTags(), parent.getTags());
      }
  
      @Test
      public void mergeInheritableIndexMaps() {
          NodeType son = new NodeType();
          son.setElementId("son");
          son.setArchiveVersion("1");
  
          PropertyDefinition propDef = new PropertyDefinition();
          AttributeDefinition attrDef = new AttributeDefinition();
  
          propDef.setType("string");
          propDef.setDefault(new ScalarPropertyValue("default_parent"));
          attrDef.setType("string");
          parent.setProperties(MapUtil.newHashMap(new String[] { "prop1" }, new PropertyDefinition[] { propDef }));
          parent.setAttributes(Maps.<String, IValue> newHashMap());
          parent.getAttributes().put("attr1", attrDef);
  
          propDef = new PropertyDefinition();
          propDef.setDefault(new ScalarPropertyValue("default_parent2"));
          propDef.setType("string");
          attrDef = new AttributeDefinition();
          attrDef.setType("version");
          parent.getProperties().put("prop2", propDef);
          parent.setAttributes(Maps.<String, IValue> newHashMap());
          parent.getAttributes().put("attr2", attrDef);
  
          propDef = new PropertyDefinition();
          propDef.setDefault(new ScalarPropertyValue("default_son"));
          propDef.setType("string");
          attrDef = new AttributeDefinition();
          attrDef.setType("integer");
          son.setProperties(MapUtil.newHashMap(new String[] { "prop1" }, new PropertyDefinition[] { propDef }));
          // son.setAttributes(MapUtil.newHashMap(new String[] { "attr1" }, new AttributeDefinition[] { attrDef }));
          son.setAttributes(Maps.<String, IValue> newHashMap());
          son.getAttributes().put("attr1", attrDef);
  
          propDef = new PropertyDefinition();
          propDef.setDefault(new ScalarPropertyValue("default_son2"));
          propDef.setType("integer");
          attrDef = new AttributeDefinition();
          attrDef.setType("boolean");
          son.getProperties().put("prop3", propDef);
          son.getAttributes().put("attr3", attrDef);
  
          IndexedModelUtils.mergeInheritableIndex(parent, son);
  
          // son should have 3 : 1 from himself, 1 from his parent, and one that he overrides from the parent
          assertEquals(3, son.getProperties().size());
          assertEquals(3, son.getAttributes().size());
  
          // son should'nt have parent's one when both defined the same
          PropertyDefinition propDefSon = son.getProperties().get("prop1");
          assertNotNull(propDefSon);
          assertEquals(new ScalarPropertyValue("default_son"), propDefSon.getDefault());
          AttributeDefinition attrDefSon = (AttributeDefinition) son.getAttributes().get("attr1");
          assertEquals("integer", attrDefSon.getType());
  
          // son has all parent's
          for (String key : parent.getProperties().keySet()) {
              assertTrue(son.getProperties().containsKey(key));
          }
          for (String key : parent.getAttributes().keySet()) {
              assertTrue(son.getAttributes().containsKey(key));
          }
  
      }
  
      private static AbstractInheritableToscaType fabricElement(Map<String, AbstractInheritableToscaType> map, String elementId, String derivedFrom,
                                                                List<Tag> tags) {
          AbstractInheritableToscaType element = new AbstractInheritableToscaType();
          element.setElementId(elementId);
          element.setArchiveVersion("1.0");
          element.setDerivedFrom(Arrays.asList(derivedFrom));
          map.put(element.getElementId(), element);
          return element;
      }
  
      @Test
      public void testMergeInterfacesNull() {
          assertNull(IndexedModelUtils.mergeInterfaces(null, null));
          Map<String, Interface> from = Maps.newHashMap();
          Map<String, Interface> merged = IndexedModelUtils.mergeInterfaces(from, null);
          assertNotNull(merged);
          assertSame(from, merged);
          Map<String, Interface> to = from;
          merged = IndexedModelUtils.mergeInterfaces(null, to);
          assertNotNull(merged);
          assertSame(to, merged);
      }
  
      @Test
      public void testMergeInterfacesBasic() {
          Map<String, Interface> from = Maps.newHashMap();
          Interface i1 = new Interface();
          from.put("i1", i1);
          Map<String, Interface> to = Maps.newHashMap();
          Interface i2 = new Interface();
          to.put("i2", i2);
          Map<String, Interface> merged = IndexedModelUtils.mergeInterfaces(from, to);
          assertEquals(2, merged.size());
          assertSame(merged.get("i1"), i1);
          assertSame(merged.get("i2"), i2);
      }
  
      @Test
      public void testMergeInterfaceOperationsKeepTo() {
          // TO keeps it's own operation
          Map<String, Interface> from = Maps.newHashMap();
          Interface i1 = new Interface();
          Map<String, Operation> ios1 = Maps.newHashMap();
          Operation o1 = new Operation();
          ios1.put("o1", o1);
          i1.setOperations(ios1);
          from.put("i1", i1);
          Map<String, Interface> to = Maps.newHashMap();
          Interface i2 = new Interface();
          Map<String, Operation> ios2 = Maps.newHashMap();
          Operation o2 = new Operation();
          ios2.put("o1", o2);
          i2.setOperations(ios2);
          to.put("i1", i2);
          Map<String, Interface> merged = IndexedModelUtils.mergeInterfaces(from, to);
          assertEquals(1, merged.size());
          assertSame(merged.get("i1").getOperations().get("o1"), o2);
      }
  
      @Test
      public void testMergeInterfaceOperationsToNull() throws JsonProcessingException {
          // TO's operation is null
          Map<String, Interface> from = Maps.newHashMap();
          Interface i1 = new Interface();
          Map<String, Operation> ios1 = Maps.newHashMap();
          Operation o1 = new Operation();
          o1.setDescription("My Operation");
          ios1.put("o1", o1);
          i1.setOperations(ios1);
          from.put("i1", i1);
          Map<String, Interface> to = Maps.newHashMap();
          Interface i2 = new Interface();
          to.put("i1", i2);
          Map<String, Interface> merged = IndexedModelUtils.mergeInterfaces(from, to);
  
          assertEquals(1, merged.size());
  
          String mergedOpString = JsonUtil.toString(merged.get("i1").getOperations().get("o1"));
          String fromOpString = JsonUtil.toString(o1);
          assertEquals(mergedOpString, fromOpString);
      }
  
      @Test
      public void testMergeInterfaceOperationsFromNull() {
          // FROM's operation is null
          Map<String, Interface> from = Maps.newHashMap();
          Interface i1 = new Interface();
          from.put("i1", i1);
          Map<String, Interface> to = Maps.newHashMap();
          Interface i2 = new Interface();
          Map<String, Operation> ios2 = Maps.newHashMap();
          Operation o2 = new Operation();
          ios2.put("o1", o2);
          i2.setOperations(ios2);
          to.put("i1", i2);
          Map<String, Interface> merged = IndexedModelUtils.mergeInterfaces(from, to);
          assertEquals(1, merged.size());
          assertSame(merged.get("i1").getOperations().get("o1"), o2);
      }
  
      @Test
      public void testMergeInterfaceOperationsMerge() throws JsonProcessingException {
          // both are merged
          Map<String, Interface> from = Maps.newHashMap();
          Interface i1 = new Interface();
          Map<String, Operation> ios1 = Maps.newHashMap();
          Operation o1 = new Operation();
          o1.setDescription("Operation o1");
          ios1.put("o1", o1);
          i1.setOperations(ios1);
          from.put("i1", i1);
          Map<String, Interface> to = Maps.newHashMap();
          Interface i2 = new Interface();
          Map<String, Operation> ios2 = Maps.newHashMap();
          Operation o2 = new Operation();
          o2.setDescription("Operation o2");
          ios2.put("o2", o2);
          i2.setOperations(ios2);
          to.put("i1", i2);
          Map<String, Interface> merged = IndexedModelUtils.mergeInterfaces(from, to);
          assertEquals(1, merged.size());
          assertEquals(2, merged.get("i1").getOperations().size());
          assertEquals(JsonUtil.toString(merged.get("i1").getOperations().get("o1")), JsonUtil.toString(o1));
          assertEquals(JsonUtil.toString(merged.get("i1").getOperations().get("o2")), JsonUtil.toString(o2));
      }
  
  }