/* * Copyright (c) 2016 Cisco Systems, Inc. and others. All rights reserved. * * This program and the accompanying materials are made available under the * terms of the Eclipse Public License v1.0 which accompanies this distribution, * and is available at http://www.eclipse.org/legal/epl-v10.html */ package org.opendaylight.yangtools.yang.data.impl.schema.tree; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; import com.google.common.base.Optional; import com.google.common.collect.ImmutableMap; import java.io.File; import java.net.URI; import org.junit.Before; import org.junit.Test; import org.opendaylight.yangtools.yang.common.QName; import org.opendaylight.yangtools.yang.common.QNameModule; import org.opendaylight.yangtools.yang.common.SimpleDateFormatUtil; import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier; import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifierWithPredicates; import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifier; import org.opendaylight.yangtools.yang.data.api.schema.ContainerNode; import org.opendaylight.yangtools.yang.data.api.schema.MapEntryNode; import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode; import org.opendaylight.yangtools.yang.data.api.schema.OrderedMapNode; import org.opendaylight.yangtools.yang.data.api.schema.tree.ConflictingModificationAppliedException; import org.opendaylight.yangtools.yang.data.api.schema.tree.DataTreeModification; import org.opendaylight.yangtools.yang.data.api.schema.tree.DataTreeSnapshot; import org.opendaylight.yangtools.yang.data.api.schema.tree.DataValidationFailedException; import org.opendaylight.yangtools.yang.data.api.schema.tree.TipProducingDataTree; import org.opendaylight.yangtools.yang.data.api.schema.tree.TreeType; import org.opendaylight.yangtools.yang.data.impl.schema.Builders; import org.opendaylight.yangtools.yang.model.api.SchemaContext; import org.opendaylight.yangtools.yang.test.util.YangParserTestUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; public class OrderedListTest { private Logger LOG = LoggerFactory.getLogger(OrderedListTest.class); private TipProducingDataTree inMemoryDataTree; private SchemaContext context; private QNameModule testModule; private QName parentContainer; private QName childContainer; private QName parentOrderedList; private QName childOrderedList; private QName parentKeyLeaf; private QName parentOrdinaryLeaf; private QName childKeyLeaf; private QName childOrdinaryLeaf; @Before public void setup() throws Exception { final File resourceFile = new File(Bug4295Test.class.getResource("/ordered-list-modification-test.yang") .toURI()); context = YangParserTestUtils.parseYangSources(resourceFile); testModule = QNameModule.create(new URI("ordered-list-modification-test"), SimpleDateFormatUtil.getRevisionFormat().parse("1970-01-01")); parentContainer = QName.create(testModule, "parent-container"); childContainer = QName.create(testModule, "child-container"); parentOrderedList = QName.create(testModule, "parent-ordered-list"); childOrderedList = QName.create(testModule, "child-ordered-list"); parentKeyLeaf = QName.create(testModule, "parent-key-leaf"); childKeyLeaf = QName.create(testModule, "child-key-leaf"); parentOrdinaryLeaf = QName.create(testModule, "parent-ordinary-leaf"); childOrdinaryLeaf = QName.create(testModule, "child-ordinary-leaf"); inMemoryDataTree = InMemoryDataTreeFactory.getInstance().create(TreeType.OPERATIONAL); inMemoryDataTree.setSchemaContext(context); } @Test public void testsequentialModifications() throws DataValidationFailedException { modification1(); modification2(); delete1(); delete2(); modification3(); modification4(); } public void modification1() throws DataValidationFailedException { OrderedMapNode parentOrderedListNode = Builders.orderedMapBuilder().withNodeIdentifier( new NodeIdentifier(parentOrderedList)) .withChild(createParentOrderedListEntry("pkval1", "plfval1")) .withChild(createParentOrderedListEntry("pkval2", "plfval2")) .withChild(createParentOrderedListEntry("pkval3", "plfval3")).build(); ContainerNode parentContainerNode = Builders.containerBuilder().withNodeIdentifier( new NodeIdentifier(parentContainer)).withChild(Builders.containerBuilder() .withNodeIdentifier(new NodeIdentifier(childContainer)).withChild(parentOrderedListNode).build()) .build(); YangInstanceIdentifier path1 = YangInstanceIdentifier.of(parentContainer); DataTreeModification treeModification = inMemoryDataTree.takeSnapshot().newModification(); treeModification.write(path1, parentContainerNode); OrderedMapNode childOrderedListNode = Builders.orderedMapBuilder().withNodeIdentifier( new NodeIdentifier(childOrderedList)) .withChild(createChildOrderedListEntry("chkval1", "chlfval1")) .withChild(createChildOrderedListEntry("chkval2", "chlfval2")).build(); YangInstanceIdentifier path2 = YangInstanceIdentifier.of(parentContainer).node(childContainer) .node(parentOrderedList).node(createParentOrderedListEntryPath("pkval2")).node(childOrderedList); treeModification.write(path2, childOrderedListNode); treeModification.ready(); inMemoryDataTree.validate(treeModification); inMemoryDataTree.commit(inMemoryDataTree.prepare(treeModification)); DataTreeSnapshot snapshotAfterCommits = inMemoryDataTree.takeSnapshot(); Optional<NormalizedNode<?, ?>> readNode = snapshotAfterCommits.readNode(path1); assertTrue(readNode.isPresent()); readNode = snapshotAfterCommits.readNode(path2); assertTrue(readNode.isPresent()); } public void modification2() throws DataValidationFailedException { OrderedMapNode parentOrderedListNode = Builders.orderedMapBuilder().withNodeIdentifier( new NodeIdentifier(parentOrderedList)) .withChild(createParentOrderedListEntry("pkval3", "plfval3updated")) .withChild(createParentOrderedListEntry("pkval4", "plfval4")) .withChild(createParentOrderedListEntry("pkval5", "plfval5")).build(); ContainerNode parentContainerNode = Builders.containerBuilder().withNodeIdentifier( new NodeIdentifier(parentContainer)).withChild(Builders.containerBuilder() .withNodeIdentifier(new NodeIdentifier(childContainer)).withChild(parentOrderedListNode).build()) .build(); DataTreeModification treeModification = inMemoryDataTree.takeSnapshot().newModification(); YangInstanceIdentifier path1 = YangInstanceIdentifier.of(parentContainer); treeModification.merge(path1, parentContainerNode); OrderedMapNode childOrderedListNode = Builders.orderedMapBuilder().withNodeIdentifier( new NodeIdentifier(childOrderedList)) .withChild(createChildOrderedListEntry("chkval1", "chlfval1updated")) .withChild(createChildOrderedListEntry("chkval2", "chlfval2updated")) .withChild(createChildOrderedListEntry("chkval3", "chlfval3")).build(); YangInstanceIdentifier path2 = YangInstanceIdentifier.of(parentContainer).node(childContainer).node (parentOrderedList).node(createParentOrderedListEntryPath("pkval2")).node(childOrderedList); treeModification.merge(path2, childOrderedListNode); treeModification.ready(); inMemoryDataTree.validate(treeModification); inMemoryDataTree.commit(inMemoryDataTree.prepare(treeModification)); DataTreeSnapshot snapshotAfterCommits = inMemoryDataTree.takeSnapshot(); Optional<NormalizedNode<?, ?>> readNode = snapshotAfterCommits.readNode(path1); assertTrue(readNode.isPresent()); readNode = snapshotAfterCommits.readNode(path2); assertTrue(readNode.isPresent()); } public void modification3() throws DataValidationFailedException { OrderedMapNode parentOrderedListNode = Builders.orderedMapBuilder().withNodeIdentifier( new NodeIdentifier(parentOrderedList)) .withChild(createParentOrderedListEntry("pkval1", "plfval1")).build(); ContainerNode parentContainerNode = Builders.containerBuilder().withNodeIdentifier( new NodeIdentifier(parentContainer)).withChild(Builders.containerBuilder() .withNodeIdentifier(new NodeIdentifier(childContainer)).withChild(parentOrderedListNode).build()) .build(); YangInstanceIdentifier path1 = YangInstanceIdentifier.of(parentContainer); DataTreeModification treeModification = inMemoryDataTree.takeSnapshot().newModification(); treeModification.write(path1, parentContainerNode); OrderedMapNode childOrderedListNode = Builders.orderedMapBuilder().withNodeIdentifier( new NodeIdentifier(childOrderedList)) .withChild(createChildOrderedListEntry("chkval1", "chlfval1new")).build(); YangInstanceIdentifier path2 = YangInstanceIdentifier.of(parentContainer).node(childContainer).node (parentOrderedList) .node(createParentOrderedListEntryPath("pkval4")).node(childOrderedList); treeModification.merge(path2, childOrderedListNode); try { treeModification.ready(); fail("Exception should have been thrown."); inMemoryDataTree.validate(treeModification); inMemoryDataTree.commit(inMemoryDataTree.prepare(treeModification)); } catch (final IllegalArgumentException ex) { LOG.debug("IllegalArgumentException was thrown as expected: {}", ex); assertTrue(ex.getMessage().contains("Metadata not available for modification NodeModification")); } DataTreeSnapshot snapshotAfterCommits = inMemoryDataTree.takeSnapshot(); Optional<NormalizedNode<?, ?>> readNode = snapshotAfterCommits.readNode(path1); assertTrue(readNode.isPresent()); readNode = snapshotAfterCommits.readNode(path2); assertFalse(readNode.isPresent()); } public void modification4() throws DataValidationFailedException { DataTreeModification treeModification1 = inMemoryDataTree.takeSnapshot().newModification(); DataTreeModification treeModification2 = inMemoryDataTree.takeSnapshot().newModification(); OrderedMapNode parentOrderedListNode = Builders.orderedMapBuilder().withNodeIdentifier(new NodeIdentifier(parentOrderedList)).withChild(createParentOrderedListEntry("pkval1", "plfval1")).build(); OrderedMapNode parentOrderedListNode2 = Builders.orderedMapBuilder().withNodeIdentifier(new NodeIdentifier(parentOrderedList)).withChild(createParentOrderedListEntry("pkval2", "plfval2")).build(); ContainerNode parentContainerNode = Builders.containerBuilder().withNodeIdentifier( new NodeIdentifier(parentContainer)).withChild(Builders.containerBuilder() .withNodeIdentifier(new NodeIdentifier(childContainer)).withChild(parentOrderedListNode).build()).build(); ContainerNode parentContainerNode2 = Builders.containerBuilder().withNodeIdentifier( new NodeIdentifier(parentContainer)).withChild(Builders.containerBuilder() .withNodeIdentifier(new NodeIdentifier(childContainer)).withChild(parentOrderedListNode2).build()) .build(); YangInstanceIdentifier path = YangInstanceIdentifier.of(parentContainer); treeModification1.write(path, parentContainerNode); treeModification2.write(path, parentContainerNode2); treeModification1.ready(); treeModification2.ready(); inMemoryDataTree.validate(treeModification1); inMemoryDataTree.commit(inMemoryDataTree.prepare(treeModification1)); try { inMemoryDataTree.validate(treeModification2); fail("Exception should have been thrown."); inMemoryDataTree.commit(inMemoryDataTree.prepare(treeModification2)); } catch (ConflictingModificationAppliedException ex) { LOG.debug("ConflictingModificationAppliedException was thrown as expected: {}", ex); assertTrue(ex.getMessage().contains("Node was replaced by other transaction")); } DataTreeSnapshot snapshotAfterCommits = inMemoryDataTree.takeSnapshot(); Optional<NormalizedNode<?, ?>> readNode = snapshotAfterCommits.readNode(path); assertTrue(readNode.isPresent()); } public void delete1() throws DataValidationFailedException { YangInstanceIdentifier path = YangInstanceIdentifier.of(parentContainer).node(childContainer) .node(parentOrderedList).node(createParentOrderedListEntryPath("pkval2")).node(childOrderedList) .node(createChildOrderedListEntryPath("chkval1")); DataTreeModification treeModification = inMemoryDataTree.takeSnapshot().newModification(); treeModification.delete(path); treeModification.ready(); inMemoryDataTree.validate(treeModification); inMemoryDataTree.commit(inMemoryDataTree.prepare(treeModification)); DataTreeSnapshot snapshotAfterCommits = inMemoryDataTree.takeSnapshot(); Optional<NormalizedNode<?, ?>> readNode = snapshotAfterCommits.readNode(path); assertFalse(readNode.isPresent()); } public void delete2() throws DataValidationFailedException { YangInstanceIdentifier path = YangInstanceIdentifier.of(parentContainer).node(childContainer) .node(parentOrderedList).node(createParentOrderedListEntryPath("pkval2")); DataTreeModification treeModification = inMemoryDataTree.takeSnapshot().newModification(); treeModification.delete(path); treeModification.ready(); inMemoryDataTree.validate(treeModification); inMemoryDataTree.commit(inMemoryDataTree.prepare(treeModification)); DataTreeSnapshot snapshotAfterCommits = inMemoryDataTree.takeSnapshot(); Optional<NormalizedNode<?, ?>> readNode = snapshotAfterCommits.readNode(path); assertFalse(readNode.isPresent()); } private MapEntryNode createParentOrderedListEntry(String keyValue, String leafValue) { return Builders.mapEntryBuilder().withNodeIdentifier(new NodeIdentifierWithPredicates(parentOrderedList, parentKeyLeaf, keyValue)) .withChild(Builders.leafBuilder().withNodeIdentifier(NodeIdentifier.create(parentOrdinaryLeaf)).withValue (leafValue).build()).build(); } private MapEntryNode createChildOrderedListEntry(String keyValue, String leafValue) { return Builders.mapEntryBuilder().withNodeIdentifier(new NodeIdentifierWithPredicates(childOrderedList, childKeyLeaf, keyValue)) .withChild(Builders.leafBuilder().withNodeIdentifier(NodeIdentifier.create(childOrdinaryLeaf)).withValue (leafValue).build()).build(); } private NodeIdentifierWithPredicates createParentOrderedListEntryPath(String keyValue) { ImmutableMap.Builder<QName, Object> builder = ImmutableMap.builder(); ImmutableMap<QName, Object> keys = builder.put(parentKeyLeaf, keyValue).build(); return new NodeIdentifierWithPredicates(parentOrderedList, keys); } private NodeIdentifierWithPredicates createChildOrderedListEntryPath(String keyValue) { ImmutableMap.Builder<QName, Object> builder = ImmutableMap.builder(); ImmutableMap<QName, Object> keys = builder.put(childKeyLeaf, keyValue).build(); return new NodeIdentifierWithPredicates(childOrderedList, keys); } }