Merge branch 'master' of ../controller
authorAnil Belur <abelur@linuxfoundation.org>
Fri, 1 Nov 2019 06:59:39 +0000 (12:29 +0530)
committerAnil Belur <abelur@linuxfoundation.org>
Fri, 1 Nov 2019 06:59:39 +0000 (12:29 +0530)
- Pull in classes for src/test

./node
./node/utils
./node/utils/QNameFactoryTest.java
./node/utils/transformer
./node/utils/transformer/NormalizedNodePrunerTest.java
./node/utils/stream
./node/utils/stream/NormalizedNodeStreamReaderWriterTest.java
./node/utils/stream/SerializationUtilsTest.java
./node/utils/stream/LithiumWriteObjectMappingTest.java
./node/utils/stream/SampleNormalizedNodeSerializable.java

Change-Id: I896ea34d6cad7167669f5d9f1be7cb1307a9b9e0

node/utils/QNameFactoryTest.java [new file with mode: 0644]
node/utils/stream/LithiumWriteObjectMappingTest.java [new file with mode: 0644]
node/utils/stream/NormalizedNodeStreamReaderWriterTest.java [new file with mode: 0644]
node/utils/stream/SampleNormalizedNodeSerializable.java [new file with mode: 0644]
node/utils/stream/SerializationUtilsTest.java [new file with mode: 0644]
node/utils/transformer/NormalizedNodePrunerTest.java [new file with mode: 0644]
util/TestModel.java [new file with mode: 0644]

diff --git a/node/utils/QNameFactoryTest.java b/node/utils/QNameFactoryTest.java
new file mode 100644 (file)
index 0000000..557675e
--- /dev/null
@@ -0,0 +1,48 @@
+/*
+ * Copyright (c) 2014, 2015 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.controller.cluster.datastore.node.utils;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotSame;
+import static org.junit.Assert.assertSame;
+
+import org.junit.Test;
+import org.opendaylight.controller.cluster.datastore.util.TestModel;
+import org.opendaylight.yangtools.yang.common.QName;
+import org.opendaylight.yangtools.yang.common.Revision;
+
+public class QNameFactoryTest {
+
+    @Test
+    @Deprecated
+    public void testBasicString() {
+        QName expected = TestModel.AUG_NAME_QNAME;
+        QName created = QNameFactory.create(expected.toString());
+        assertNotSame(expected, created);
+        assertEquals(expected, created);
+
+        QName cached = QNameFactory.create(expected.toString());
+        assertSame(created, cached);
+    }
+
+    @Test
+    public void testBasic() {
+        QName expected = TestModel.AUG_NAME_QNAME;
+        QName created = lookup(expected);
+        assertNotSame(expected, created);
+        assertEquals(expected, created);
+
+        QName cached = lookup(expected);
+        assertSame(created, cached);
+    }
+
+    private static QName lookup(final QName qname) {
+        return QNameFactory.create(qname.getLocalName(), qname.getNamespace().toString(),
+            qname.getRevision().map(Revision::toString).orElse(null));
+    }
+}
diff --git a/node/utils/stream/LithiumWriteObjectMappingTest.java b/node/utils/stream/LithiumWriteObjectMappingTest.java
new file mode 100644 (file)
index 0000000..dc38471
--- /dev/null
@@ -0,0 +1,30 @@
+/*
+ * Copyright (c) 2015 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.controller.cluster.datastore.node.utils.stream;
+
+import static org.junit.Assert.assertEquals;
+
+import org.junit.Test;
+
+public class LithiumWriteObjectMappingTest {
+    @Test
+    public void testStringType() {
+        assertEquals(LithiumValue.STRING_TYPE, AbstractLithiumDataOutput.getSerializableType("foobar"));
+        final String largeString = largeString(LithiumValue.STRING_BYTES_LENGTH_THRESHOLD);
+        assertEquals(LithiumValue.STRING_BYTES_TYPE, AbstractLithiumDataOutput.getSerializableType(largeString));
+    }
+
+    private static String largeString(final int minSize) {
+        final int pow = (int) (Math.log(minSize * 2) / Math.log(2));
+        StringBuilder sb = new StringBuilder("X");
+        for (int i = 0; i < pow; i++) {
+            sb.append(sb);
+        }
+        return sb.toString();
+    }
+}
diff --git a/node/utils/stream/NormalizedNodeStreamReaderWriterTest.java b/node/utils/stream/NormalizedNodeStreamReaderWriterTest.java
new file mode 100644 (file)
index 0000000..951170c
--- /dev/null
@@ -0,0 +1,334 @@
+/*
+ * Copyright (c) 2014, 2015 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.controller.cluster.datastore.node.utils.stream;
+
+import static org.junit.Assert.assertEquals;
+
+import com.google.common.collect.ImmutableSet;
+import com.google.common.io.ByteStreams;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.StringReader;
+import java.io.StringWriter;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Optional;
+import javax.xml.parsers.DocumentBuilderFactory;
+import javax.xml.transform.OutputKeys;
+import javax.xml.transform.Transformer;
+import javax.xml.transform.TransformerFactory;
+import javax.xml.transform.dom.DOMSource;
+import javax.xml.transform.stream.StreamResult;
+import org.apache.commons.lang.SerializationUtils;
+import org.junit.Assert;
+import org.junit.Test;
+import org.opendaylight.controller.cluster.datastore.util.TestModel;
+import org.opendaylight.yangtools.yang.common.Empty;
+import org.opendaylight.yangtools.yang.common.QName;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.AugmentationIdentifier;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifier;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifierWithPredicates;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeWithValue;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.PathArgument;
+import org.opendaylight.yangtools.yang.data.api.schema.ContainerNode;
+import org.opendaylight.yangtools.yang.data.api.schema.DOMSourceAnyxmlNode;
+import org.opendaylight.yangtools.yang.data.api.schema.DataContainerChild;
+import org.opendaylight.yangtools.yang.data.api.schema.LeafSetEntryNode;
+import org.opendaylight.yangtools.yang.data.api.schema.MapEntryNode;
+import org.opendaylight.yangtools.yang.data.api.schema.MapNode;
+import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
+import org.opendaylight.yangtools.yang.data.impl.schema.Builders;
+import org.opendaylight.yangtools.yang.data.impl.schema.ImmutableNodes;
+import org.opendaylight.yangtools.yang.data.impl.schema.builder.api.CollectionNodeBuilder;
+import org.opendaylight.yangtools.yang.data.impl.schema.builder.api.DataContainerNodeBuilder;
+import org.opendaylight.yangtools.yang.data.impl.schema.builder.impl.ImmutableContainerNodeBuilder;
+import org.opendaylight.yangtools.yang.data.impl.schema.builder.impl.ImmutableLeafSetEntryNodeBuilder;
+import org.opendaylight.yangtools.yang.data.impl.schema.builder.impl.ImmutableLeafSetNodeBuilder;
+import org.opendaylight.yangtools.yang.model.api.SchemaContext;
+import org.opendaylight.yangtools.yang.model.api.SchemaPath;
+import org.w3c.dom.Node;
+import org.xml.sax.InputSource;
+
+public class NormalizedNodeStreamReaderWriterTest {
+
+    @Test
+    public void testNormalizedNodeStreaming() throws IOException {
+
+        ByteArrayOutputStream bos = new ByteArrayOutputStream();
+        NormalizedNodeDataOutput nnout = NormalizedNodeInputOutput.newDataOutput(ByteStreams.newDataOutput(bos));
+
+        NormalizedNode<?, ?> testContainer = createTestContainer();
+        nnout.writeNormalizedNode(testContainer);
+
+        QName toaster = QName.create("http://netconfcentral.org/ns/toaster","2009-11-20","toaster");
+        QName darknessFactor = QName.create("http://netconfcentral.org/ns/toaster","2009-11-20","darknessFactor");
+        QName description = QName.create("http://netconfcentral.org/ns/toaster","2009-11-20","description");
+        ContainerNode toasterNode = Builders.containerBuilder().withNodeIdentifier(new NodeIdentifier(toaster))
+                .withChild(ImmutableNodes.leafNode(darknessFactor, "1000"))
+                .withChild(ImmutableNodes.leafNode(description, largeString(20))).build();
+
+        ContainerNode toasterContainer = Builders.containerBuilder()
+                .withNodeIdentifier(new NodeIdentifier(SchemaContext.NAME)).withChild(toasterNode).build();
+        nnout.writeNormalizedNode(toasterContainer);
+
+        final byte[] bytes = bos.toByteArray();
+        assertEquals(1049619, bytes.length);
+
+        NormalizedNodeDataInput nnin = NormalizedNodeInputOutput.newDataInput(ByteStreams.newDataInput(bytes));
+
+        NormalizedNode<?, ?> node = nnin.readNormalizedNode();
+        Assert.assertEquals(testContainer, node);
+
+        node = nnin.readNormalizedNode();
+        Assert.assertEquals(toasterContainer, node);
+    }
+
+    private static NormalizedNode<?, ?> createTestContainer() {
+        byte[] bytes1 = {1, 2, 3};
+        LeafSetEntryNode<Object> entry1 = ImmutableLeafSetEntryNodeBuilder.create().withNodeIdentifier(
+                new NodeWithValue<>(TestModel.BINARY_LEAF_LIST_QNAME, bytes1)).withValue(bytes1).build();
+
+        byte[] bytes2 = {};
+        LeafSetEntryNode<Object> entry2 = ImmutableLeafSetEntryNodeBuilder.create().withNodeIdentifier(
+                new NodeWithValue<>(TestModel.BINARY_LEAF_LIST_QNAME, bytes2)).withValue(bytes2).build();
+
+        return TestModel.createBaseTestContainerBuilder()
+                .withChild(ImmutableLeafSetNodeBuilder.create().withNodeIdentifier(
+                        new NodeIdentifier(TestModel.BINARY_LEAF_LIST_QNAME))
+                        .withChild(entry1).withChild(entry2).build())
+                .withChild(ImmutableNodes.leafNode(TestModel.SOME_BINARY_DATA_QNAME, new byte[]{1, 2, 3, 4}))
+                .withChild(ImmutableNodes.leafNode(TestModel.EMPTY_QNAME, Empty.getInstance()))
+                .withChild(Builders.orderedMapBuilder()
+                      .withNodeIdentifier(new NodeIdentifier(TestModel.ORDERED_LIST_QNAME))
+                      .withChild(ImmutableNodes.mapEntry(TestModel.ORDERED_LIST_ENTRY_QNAME,
+                              TestModel.ID_QNAME, 11)).build()).build();
+    }
+
+    @Test
+    public void testYangInstanceIdentifierStreaming() throws IOException  {
+        YangInstanceIdentifier path = YangInstanceIdentifier.builder(TestModel.TEST_PATH)
+                .node(TestModel.OUTER_LIST_QNAME).nodeWithKey(
+                        TestModel.INNER_LIST_QNAME, TestModel.ID_QNAME, 10).build();
+
+        ByteArrayOutputStream bos = new ByteArrayOutputStream();
+        NormalizedNodeDataOutput nnout = NormalizedNodeInputOutput.newDataOutput(ByteStreams.newDataOutput(bos));
+
+        nnout.writeYangInstanceIdentifier(path);
+
+        final byte[] bytes = bos.toByteArray();
+        assertEquals(139, bytes.length);
+
+        NormalizedNodeDataInput nnin = NormalizedNodeInputOutput.newDataInput(ByteStreams.newDataInput(bytes));
+
+        YangInstanceIdentifier newPath = nnin.readYangInstanceIdentifier();
+        Assert.assertEquals(path, newPath);
+    }
+
+    @Test
+    public void testNormalizedNodeAndYangInstanceIdentifierStreaming() throws IOException {
+
+        ByteArrayOutputStream bos = new ByteArrayOutputStream();
+        NormalizedNodeDataOutput writer = NormalizedNodeInputOutput.newDataOutput(
+            ByteStreams.newDataOutput(bos));
+
+        NormalizedNode<?, ?> testContainer = TestModel.createBaseTestContainerBuilder().build();
+        writer.writeNormalizedNode(testContainer);
+
+        YangInstanceIdentifier path = YangInstanceIdentifier.builder(TestModel.TEST_PATH)
+                .node(TestModel.OUTER_LIST_QNAME).nodeWithKey(
+                        TestModel.INNER_LIST_QNAME, TestModel.ID_QNAME, 10).build();
+
+        writer.writeYangInstanceIdentifier(path);
+
+        final byte[] bytes = bos.toByteArray();
+        assertEquals(826, bytes.length);
+
+        NormalizedNodeDataInput reader = NormalizedNodeInputOutput.newDataInput(ByteStreams.newDataInput(bytes));
+
+        NormalizedNode<?,?> node = reader.readNormalizedNode();
+        Assert.assertEquals(testContainer, node);
+
+        YangInstanceIdentifier newPath = reader.readYangInstanceIdentifier();
+        Assert.assertEquals(path, newPath);
+
+        writer.close();
+    }
+
+    @Test(expected = InvalidNormalizedNodeStreamException.class, timeout = 10000)
+    public void testInvalidNormalizedNodeStream() throws IOException {
+        byte[] invalidBytes = {1, 2, 3};
+        NormalizedNodeDataInput reader = NormalizedNodeInputOutput.newDataInput(
+                ByteStreams.newDataInput(invalidBytes));
+
+        reader.readNormalizedNode();
+    }
+
+    @Test(expected = InvalidNormalizedNodeStreamException.class, timeout = 10000)
+    public void testInvalidYangInstanceIdentifierStream() throws IOException {
+        byte[] invalidBytes = {1,2,3};
+        NormalizedNodeDataInput reader = NormalizedNodeInputOutput.newDataInput(
+            ByteStreams.newDataInput(invalidBytes));
+
+        reader.readYangInstanceIdentifier();
+    }
+
+    @Test
+    public void testWithSerializable() {
+        NormalizedNode<?, ?> input = TestModel.createTestContainer();
+        SampleNormalizedNodeSerializable serializable = new SampleNormalizedNodeSerializable(input);
+        SampleNormalizedNodeSerializable clone =
+                (SampleNormalizedNodeSerializable)SerializationUtils.clone(serializable);
+
+        Assert.assertEquals(input, clone.getInput());
+    }
+
+    @Test
+    public void testAnyXmlStreaming() throws Exception {
+        String xml = "<foo xmlns=\"http://www.w3.org/TR/html4/\" x=\"123\"><bar>one</bar><bar>two</bar></foo>";
+        final DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
+        factory.setNamespaceAware(true);
+
+        Node xmlNode = factory.newDocumentBuilder().parse(
+                new InputSource(new StringReader(xml))).getDocumentElement();
+
+        assertEquals("http://www.w3.org/TR/html4/", xmlNode.getNamespaceURI());
+
+        NormalizedNode<?, ?> anyXmlContainer = ImmutableContainerNodeBuilder.create().withNodeIdentifier(
+                new YangInstanceIdentifier.NodeIdentifier(TestModel.TEST_QNAME)).withChild(
+                        Builders.anyXmlBuilder().withNodeIdentifier(new NodeIdentifier(TestModel.ANY_XML_QNAME))
+                            .withValue(new DOMSource(xmlNode)).build()).build();
+
+        ByteArrayOutputStream bos = new ByteArrayOutputStream();
+        NormalizedNodeDataOutput nnout = NormalizedNodeInputOutput.newDataOutput(ByteStreams.newDataOutput(bos));
+
+        nnout.writeNormalizedNode(anyXmlContainer);
+
+        final byte[] bytes = bos.toByteArray();
+        assertEquals(229, bytes.length);
+
+        NormalizedNodeDataInput nnin = NormalizedNodeInputOutput.newDataInput(ByteStreams.newDataInput(bytes));
+
+        ContainerNode deserialized = (ContainerNode)nnin.readNormalizedNode();
+
+        Optional<DataContainerChild<? extends PathArgument, ?>> child =
+                deserialized.getChild(new NodeIdentifier(TestModel.ANY_XML_QNAME));
+        assertEquals("AnyXml child present", true, child.isPresent());
+
+        StreamResult xmlOutput = new StreamResult(new StringWriter());
+        Transformer transformer = TransformerFactory.newInstance().newTransformer();
+        transformer.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, "yes");
+        transformer.transform(((DOMSourceAnyxmlNode)child.get()).getValue(), xmlOutput);
+
+        assertEquals("XML", xml, xmlOutput.getWriter().toString());
+        assertEquals("http://www.w3.org/TR/html4/",
+            ((DOMSourceAnyxmlNode)child.get()).getValue().getNode().getNamespaceURI());
+    }
+
+    @Test
+    public void testSchemaPathSerialization() throws IOException {
+        final SchemaPath expected = SchemaPath.create(true, TestModel.ANY_XML_QNAME);
+
+        ByteArrayOutputStream bos = new ByteArrayOutputStream();
+        try (NormalizedNodeDataOutput nnout = NormalizedNodeInputOutput.newDataOutput(ByteStreams.newDataOutput(bos))) {
+            nnout.writeSchemaPath(expected);
+        }
+
+        final byte[] bytes = bos.toByteArray();
+        assertEquals(99, bytes.length);
+
+        NormalizedNodeDataInput nnin = NormalizedNodeInputOutput.newDataInput(ByteStreams.newDataInput(bytes));
+        assertEquals(expected, nnin.readSchemaPath());
+    }
+
+    @Test
+    public void testWritePathArgument() throws IOException {
+        final NodeIdentifier expected = new NodeIdentifier(TestModel.BOOLEAN_LEAF_QNAME);
+
+        ByteArrayOutputStream bos = new ByteArrayOutputStream();
+
+        try (NormalizedNodeDataOutput nnout = NormalizedNodeInputOutput.newDataOutput(ByteStreams.newDataOutput(bos))) {
+            nnout.writePathArgument(expected);
+        }
+
+        final byte[] bytes = bos.toByteArray();
+        assertEquals(103, bytes.length);
+
+        NormalizedNodeDataInput nnin = NormalizedNodeInputOutput.newDataInput(ByteStreams.newDataInput(bytes));
+        assertEquals(expected, nnin.readPathArgument());
+    }
+
+    /*
+     * This tests the encoding of a MapNode with a lot of entries, each of them having the key leaf (a string)
+     * and an integer.
+     */
+    @Test
+    public void testHugeEntries() throws IOException {
+        final CollectionNodeBuilder<MapEntryNode, MapNode> mapBuilder = Builders.mapBuilder()
+                .withNodeIdentifier(new NodeIdentifier(TestModel.TEST_QNAME));
+        final DataContainerNodeBuilder<NodeIdentifierWithPredicates, MapEntryNode> entryBuilder =
+                Builders.mapEntryBuilder().withChild(ImmutableNodes.leafNode(TestModel.DESC_QNAME, (byte) 42));
+
+        for (int i = 0; i < 100_000; ++i) {
+            final String key = "xyzzy" + i;
+            mapBuilder.addChild(entryBuilder
+                .withNodeIdentifier(NodeIdentifierWithPredicates.of(TestModel.TEST_QNAME,
+                    TestModel.CHILD_NAME_QNAME, key))
+                .withChild(ImmutableNodes.leafNode(TestModel.CHILD_NAME_QNAME, key))
+                .build());
+        }
+
+        final MapNode expected = mapBuilder.build();
+        final ByteArrayOutputStream bos = new ByteArrayOutputStream();
+
+        try (NormalizedNodeDataOutput nnout = NormalizedNodeInputOutput.newDataOutput(ByteStreams.newDataOutput(bos))) {
+            nnout.writeNormalizedNode(expected);
+        }
+
+        final byte[] bytes = bos.toByteArray();
+        assertEquals(2_289_103, bytes.length);
+
+        NormalizedNodeDataInput nnin = NormalizedNodeInputOutput.newDataInput(ByteStreams.newDataInput(bytes));
+        assertEquals(expected, nnin.readNormalizedNode());
+    }
+
+    @Test
+    public void testAugmentationIdentifier() throws IOException {
+        final List<QName> qnames = new ArrayList<>();
+        for (int i = 0; i < 257; ++i) {
+            qnames.add(QName.create(TestModel.TEST_QNAME, "a" + i));
+        }
+
+        for (int i = 0; i < qnames.size(); ++i) {
+            final AugmentationIdentifier expected = AugmentationIdentifier.create(
+                ImmutableSet.copyOf(qnames.subList(0, i)));
+
+            ByteArrayOutputStream bos = new ByteArrayOutputStream();
+
+            try (NormalizedNodeDataOutput nnout =
+                    NormalizedNodeInputOutput.newDataOutput(ByteStreams.newDataOutput(bos),
+                        NormalizedNodeStreamVersion.SODIUM_SR1)) {
+                nnout.writePathArgument(expected);
+            }
+
+            final byte[] bytes = bos.toByteArray();
+
+            NormalizedNodeDataInput nnin = NormalizedNodeInputOutput.newDataInput(ByteStreams.newDataInput(bytes));
+            PathArgument arg = nnin.readPathArgument();
+            assertEquals(expected, arg);
+        }
+    }
+
+    private static String largeString(final int pow) {
+        StringBuilder sb = new StringBuilder("X");
+        for (int i = 0; i < pow; i++) {
+            sb.append(sb);
+        }
+        return sb.toString();
+    }
+}
diff --git a/node/utils/stream/SampleNormalizedNodeSerializable.java b/node/utils/stream/SampleNormalizedNodeSerializable.java
new file mode 100644 (file)
index 0000000..0ce7331
--- /dev/null
@@ -0,0 +1,38 @@
+/*
+ * Copyright (c) 2014 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.controller.cluster.datastore.node.utils.stream;
+
+import java.io.IOException;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+import java.io.Serializable;
+import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
+
+public class SampleNormalizedNodeSerializable implements Serializable {
+    private static final long serialVersionUID = 1L;
+
+    private NormalizedNode<?, ?> input;
+
+    public SampleNormalizedNodeSerializable(final NormalizedNode<?, ?> input) {
+        this.input = input;
+    }
+
+    public NormalizedNode<?, ?> getInput() {
+        return input;
+    }
+
+    private void readObject(final ObjectInputStream stream) throws IOException {
+        this.input = NormalizedNodeInputOutput.newDataInput(stream).readNormalizedNode();
+    }
+
+    private void writeObject(final ObjectOutputStream stream) throws IOException {
+        NormalizedNodeInputOutput.newDataOutput(stream).writeNormalizedNode(input);
+    }
+
+}
diff --git a/node/utils/stream/SerializationUtilsTest.java b/node/utils/stream/SerializationUtilsTest.java
new file mode 100644 (file)
index 0000000..04da2a6
--- /dev/null
@@ -0,0 +1,272 @@
+/*
+ * Copyright (c) 2017 Pantheon Technologies s.r.o. 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.controller.cluster.datastore.node.utils.stream;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+
+import com.google.common.collect.ImmutableSet;
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.DataInputStream;
+import java.io.DataOutput;
+import java.io.DataOutputStream;
+import java.io.IOException;
+import java.nio.charset.Charset;
+import java.util.Arrays;
+import java.util.Set;
+import java.util.concurrent.atomic.AtomicBoolean;
+import java.util.stream.Collectors;
+import javax.xml.transform.dom.DOMSource;
+import org.custommonkey.xmlunit.Diff;
+import org.custommonkey.xmlunit.XMLUnit;
+import org.junit.Test;
+import org.opendaylight.yangtools.util.xml.UntrustedXML;
+import org.opendaylight.yangtools.yang.common.QName;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.AugmentationIdentifier;
+import org.opendaylight.yangtools.yang.data.api.schema.AugmentationNode;
+import org.opendaylight.yangtools.yang.data.api.schema.ChoiceNode;
+import org.opendaylight.yangtools.yang.data.api.schema.DOMSourceAnyxmlNode;
+import org.opendaylight.yangtools.yang.data.api.schema.LeafNode;
+import org.opendaylight.yangtools.yang.data.api.schema.LeafSetEntryNode;
+import org.opendaylight.yangtools.yang.data.api.schema.LeafSetNode;
+import org.opendaylight.yangtools.yang.data.api.schema.MapEntryNode;
+import org.opendaylight.yangtools.yang.data.api.schema.MapNode;
+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.UnkeyedListEntryNode;
+import org.opendaylight.yangtools.yang.data.api.schema.UnkeyedListNode;
+import org.opendaylight.yangtools.yang.data.impl.schema.Builders;
+import org.opendaylight.yangtools.yang.data.impl.schema.ImmutableNodes;
+import org.w3c.dom.Document;
+
+public class SerializationUtilsTest {
+
+    private static final QName CONTAINER_Q_NAME = QName.create("ns-1", "2017-03-17", "container1");
+
+    @Test
+    public void testSerializeDeserializeNodes() throws IOException {
+        final NormalizedNode<?, ?> normalizedNode = createNormalizedNode();
+        final byte[] bytes = serializeNormalizedNode(normalizedNode);
+        assertEquals(10564, bytes.length);
+        assertEquals(normalizedNode, deserializeNormalizedNode(bytes));
+    }
+
+    @Test
+    public void testSerializeDeserializeAnyXmlNode() throws Exception {
+        final ByteArrayInputStream is =
+                new ByteArrayInputStream("<xml><data/></xml>".getBytes(Charset.defaultCharset()));
+        final Document parse = UntrustedXML.newDocumentBuilder().parse(is);
+        final DOMSourceAnyxmlNode anyXmlNode = Builders.anyXmlBuilder()
+                .withNodeIdentifier(id("anyXmlNode"))
+                .withValue(new DOMSource(parse))
+                .build();
+        final byte[] bytes = serializeNormalizedNode(anyXmlNode);
+        assertEquals(113, bytes.length);
+        final NormalizedNode<?, ?> deserialized = deserializeNormalizedNode(bytes);
+        final DOMSource value = (DOMSource) deserialized.getValue();
+        final Diff diff = XMLUnit.compareXML((Document) anyXmlNode.getValue().getNode(),
+                value.getNode().getOwnerDocument());
+        assertTrue(diff.toString(), diff.similar());
+    }
+
+    @Test
+    public void testSerializeDeserializePath() throws IOException {
+        final ByteArrayOutputStream bos = new ByteArrayOutputStream();
+        final DataOutput out = new DataOutputStream(bos);
+        final YangInstanceIdentifier path = YangInstanceIdentifier.builder()
+                .node(id("container1"))
+                .node(autmentationId("list1", "list2"))
+                .node(listId("list1", "keyName1", "keyValue1"))
+                .node(leafSetId("leafSer1", "leafSetValue1"))
+                .build();
+        SerializationUtils.writePath(out, path);
+
+        final byte[] bytes = bos.toByteArray();
+        assertEquals(119, bytes.length);
+
+        final YangInstanceIdentifier deserialized =
+                SerializationUtils.readPath(new DataInputStream(new ByteArrayInputStream(bytes)));
+        assertEquals(path, deserialized);
+    }
+
+    @Test
+    public void testSerializeDeserializePathAndNode() throws IOException {
+        final ByteArrayOutputStream bos = new ByteArrayOutputStream();
+        final DataOutput out = new DataOutputStream(bos);
+        final NormalizedNode<?, ?> node = createNormalizedNode();
+        final YangInstanceIdentifier path = YangInstanceIdentifier.create(id("container1"));
+        SerializationUtils.writeNodeAndPath(out, path, node);
+
+        final byte[] bytes = bos.toByteArray();
+        assertEquals(10566, bytes.length);
+
+        final DataInputStream in = new DataInputStream(new ByteArrayInputStream(bytes));
+        final AtomicBoolean applierCalled = new AtomicBoolean(false);
+        SerializationUtils.readNodeAndPath(in, applierCalled, (instance, deserializedPath, deserializedNode) -> {
+            assertEquals(path, deserializedPath);
+            assertEquals(node, deserializedNode);
+            applierCalled.set(true);
+        });
+        assertTrue(applierCalled.get());
+    }
+
+    @Test
+    public void testSerializeDeserializeAugmentNoref() throws IOException {
+        final YangInstanceIdentifier expected = YangInstanceIdentifier.create(
+            AugmentationIdentifier.create(ImmutableSet.of(
+                QName.create("foo", "leaf1"),
+                QName.create("bar", "leaf2"))));
+
+        final ByteArrayOutputStream bos = new ByteArrayOutputStream();
+        final DataOutput out = new DataOutputStream(bos);
+        SerializationUtils.writePath(out, expected);
+
+        final byte[] bytes = bos.toByteArray();
+        assertEquals(37, bytes.length);
+
+        final DataInputStream in = new DataInputStream(new ByteArrayInputStream(bytes));
+        final YangInstanceIdentifier read = SerializationUtils.readPath(in);
+        assertEquals(expected, read);
+    }
+
+    private static NormalizedNode<?, ?> deserializeNormalizedNode(final byte[] bytes) throws IOException {
+        return SerializationUtils.readNormalizedNode(new DataInputStream(new ByteArrayInputStream(bytes))).get();
+    }
+
+    private static byte[] serializeNormalizedNode(final NormalizedNode<?, ?> node) throws IOException {
+        ByteArrayOutputStream bos = new ByteArrayOutputStream();
+        SerializationUtils.writeNormalizedNode(new DataOutputStream(bos), node);
+        return bos.toByteArray();
+    }
+
+    private static NormalizedNode<?, ?> createNormalizedNode() {
+        final LeafSetNode<Object> leafSetNode = Builders.leafSetBuilder()
+                .withNodeIdentifier(id("leafSetNode"))
+                .withChild(createLeafSetEntry("leafSetNode", "leafSetValue1"))
+                .withChild(createLeafSetEntry("leafSetNode", "leafSetValue2"))
+                .build();
+        final LeafSetNode<Object> orderedLeafSetNode = Builders.orderedLeafSetBuilder()
+                .withNodeIdentifier(id("orderedLeafSetNode"))
+                .withChild(createLeafSetEntry("orderedLeafSetNode", "value1"))
+                .withChild(createLeafSetEntry("orderedLeafSetNode", "value2"))
+                .build();
+        final LeafNode<Boolean> booleanLeaf = createLeaf("booleanLeaf", true);
+        final LeafNode<Byte> byteLeaf = createLeaf("byteLeaf", (byte) 0);
+        final LeafNode<Short> shortLeaf = createLeaf("shortLeaf", (short) 55);
+        final LeafNode<Integer> intLeaf = createLeaf("intLeaf", 11);
+        final LeafNode<Long> longLeaf = createLeaf("longLeaf", 151515L);
+        final LeafNode<String> stringLeaf = createLeaf("stringLeaf", "stringValue");
+        final LeafNode<String> longStringLeaf = createLeaf("longStringLeaf", getLongString());
+        final LeafNode<QName> qNameLeaf = createLeaf("stringLeaf", QName.create("base", "qName"));
+        final LeafNode<YangInstanceIdentifier> idLeaf = createLeaf("stringLeaf", YangInstanceIdentifier.empty());
+        final MapEntryNode entry1 = Builders.mapEntryBuilder()
+                .withNodeIdentifier(listId("mapNode", "key", "key1"))
+                .withChild(stringLeaf)
+                .build();
+        final MapEntryNode entry2 = Builders.mapEntryBuilder()
+                .withNodeIdentifier(listId("mapNode", "key", "key2"))
+                .withChild(stringLeaf)
+                .build();
+        final MapNode mapNode = Builders.mapBuilder()
+                .withNodeIdentifier(id("mapNode"))
+                .withChild(entry1)
+                .withChild(entry2)
+                .build();
+        final OrderedMapNode orderedMapNode = Builders.orderedMapBuilder()
+                .withNodeIdentifier(id("orderedMapNode"))
+                .withChild(entry2)
+                .withChild(entry1)
+                .build();
+        final UnkeyedListEntryNode unkeyedListEntry1 = Builders.unkeyedListEntryBuilder()
+                .withNodeIdentifier(id("unkeyedList"))
+                .withChild(stringLeaf)
+                .build();
+        final UnkeyedListEntryNode unkeyedListEntry2 = Builders.unkeyedListEntryBuilder()
+                .withNodeIdentifier(id("unkeyedList"))
+                .withChild(stringLeaf)
+                .build();
+        final UnkeyedListNode unkeyedListNode = Builders.unkeyedListBuilder()
+                .withNodeIdentifier(id("unkeyedList"))
+                .withChild(unkeyedListEntry1)
+                .withChild(unkeyedListEntry2)
+                .build();
+        final ImmutableSet<QName> childNames =
+                ImmutableSet.of(QName.create(CONTAINER_Q_NAME, "aug1"), QName.create(CONTAINER_Q_NAME, "aug1"));
+        final AugmentationNode augmentationNode = Builders.augmentationBuilder()
+                .withNodeIdentifier(new YangInstanceIdentifier.AugmentationIdentifier(childNames))
+                .withChild(createLeaf("aug1", "aug1Value"))
+                .withChild(createLeaf("aug2", "aug2Value"))
+                .build();
+        final ChoiceNode choiceNode = Builders.choiceBuilder()
+                .withNodeIdentifier(id("choiceNode"))
+                .withChild(createLeaf("choiceLeaf", 12))
+                .build();
+        return Builders.containerBuilder()
+                .withNodeIdentifier(new YangInstanceIdentifier.NodeIdentifier(CONTAINER_Q_NAME))
+                .withChild(booleanLeaf)
+                .withChild(byteLeaf)
+                .withChild(shortLeaf)
+                .withChild(intLeaf)
+                .withChild(longLeaf)
+                .withChild(stringLeaf)
+                .withChild(longStringLeaf)
+                .withChild(qNameLeaf)
+                .withChild(idLeaf)
+                .withChild(mapNode)
+                .withChild(orderedMapNode)
+                .withChild(unkeyedListNode)
+                .withChild(leafSetNode)
+                .withChild(orderedLeafSetNode)
+                .withChild(augmentationNode)
+                .withChild(choiceNode)
+                .build();
+    }
+
+    private static <T> LeafNode<T> createLeaf(final String name, final T value) {
+        return ImmutableNodes.leafNode(id(name), value);
+    }
+
+    private static LeafSetEntryNode<Object> createLeafSetEntry(final String leafSet, final String value) {
+        return Builders.leafSetEntryBuilder()
+                .withNodeIdentifier(leafSetId(leafSet, value))
+                .withValue(value)
+                .build();
+    }
+
+    private static YangInstanceIdentifier.NodeIdentifier id(final String name) {
+        return new YangInstanceIdentifier.NodeIdentifier(QName.create(CONTAINER_Q_NAME, name));
+    }
+
+    private static YangInstanceIdentifier.NodeIdentifierWithPredicates listId(final String listName,
+                                                                              final String keyName,
+                                                                              final Object keyValue) {
+        return YangInstanceIdentifier.NodeIdentifierWithPredicates.of(QName.create(CONTAINER_Q_NAME, listName),
+                QName.create(CONTAINER_Q_NAME, keyName), keyValue);
+    }
+
+    private static <T> YangInstanceIdentifier.NodeWithValue<T> leafSetId(final String node, final T value) {
+        return new YangInstanceIdentifier.NodeWithValue<>(QName.create(CONTAINER_Q_NAME, node), value);
+    }
+
+    private static YangInstanceIdentifier.AugmentationIdentifier autmentationId(final String... nodes) {
+        final Set<QName> qNames = Arrays.stream(nodes)
+                .map(node -> QName.create(CONTAINER_Q_NAME, node))
+                .collect(Collectors.toSet());
+        return new YangInstanceIdentifier.AugmentationIdentifier(qNames);
+    }
+
+    private static String getLongString() {
+        final StringBuilder builder = new StringBuilder(10000);
+        for (int i = 0; i < 1000; i++) {
+            builder.append("0123456789");
+        }
+        return builder.toString();
+    }
+}
diff --git a/node/utils/transformer/NormalizedNodePrunerTest.java b/node/utils/transformer/NormalizedNodePrunerTest.java
new file mode 100644 (file)
index 0000000..50ade78
--- /dev/null
@@ -0,0 +1,399 @@
+/*
+ * Copyright (c) 2015 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.controller.cluster.datastore.node.utils.transformer;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+import static org.mockito.Mockito.mock;
+import static org.opendaylight.yangtools.yang.data.impl.schema.ImmutableNodes.mapEntry;
+import static org.opendaylight.yangtools.yang.data.impl.schema.ImmutableNodes.mapEntryBuilder;
+import static org.opendaylight.yangtools.yang.data.impl.schema.ImmutableNodes.mapNodeBuilder;
+
+import com.google.common.collect.Sets;
+import java.io.IOException;
+import java.util.concurrent.atomic.AtomicInteger;
+import javax.xml.transform.dom.DOMSource;
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Test;
+import org.mockito.MockitoAnnotations;
+import org.opendaylight.controller.cluster.datastore.node.utils.NormalizedNodeNavigator;
+import org.opendaylight.controller.cluster.datastore.util.TestModel;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.AugmentationIdentifier;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifier;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeWithValue;
+import org.opendaylight.yangtools.yang.data.api.schema.DOMSourceAnyxmlNode;
+import org.opendaylight.yangtools.yang.data.api.schema.LeafNode;
+import org.opendaylight.yangtools.yang.data.api.schema.LeafSetEntryNode;
+import org.opendaylight.yangtools.yang.data.api.schema.MapNode;
+import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
+import org.opendaylight.yangtools.yang.data.api.schema.stream.NormalizedNodeWriter;
+import org.opendaylight.yangtools.yang.data.impl.schema.Builders;
+import org.opendaylight.yangtools.yang.data.impl.schema.ImmutableNodes;
+import org.opendaylight.yangtools.yang.data.impl.schema.builder.impl.ImmutableLeafSetEntryNodeBuilder;
+import org.opendaylight.yangtools.yang.data.impl.schema.builder.impl.ImmutableLeafSetNodeBuilder;
+import org.opendaylight.yangtools.yang.model.api.SchemaContext;
+
+public class NormalizedNodePrunerTest {
+    private static final SchemaContext NO_TEST_SCHEMA = TestModel.createTestContextWithoutTestSchema();
+    private static final SchemaContext NO_AUG_SCHEMA = TestModel.createTestContextWithoutAugmentationSchema();
+    private static final SchemaContext FULL_SCHEMA = TestModel.createTestContext();
+
+    @Before
+    public void setUp() {
+        MockitoAnnotations.initMocks(this);
+    }
+
+    private static NormalizedNodePruner prunerFullSchema(final YangInstanceIdentifier path) {
+        return new NormalizedNodePruner(path, FULL_SCHEMA);
+    }
+
+    private static NormalizedNodePruner prunerNoAugSchema(final YangInstanceIdentifier path) {
+        return new NormalizedNodePruner(path, NO_AUG_SCHEMA);
+    }
+
+    private static NormalizedNodePruner prunerNoTestSchema(final YangInstanceIdentifier path) {
+        return new NormalizedNodePruner(path, NO_TEST_SCHEMA);
+    }
+
+    @Test
+    public void testNodesNotPrunedWhenSchemaPresent() throws IOException {
+        NormalizedNodePruner pruner = prunerFullSchema(TestModel.TEST_PATH);
+
+        NormalizedNodeWriter normalizedNodeWriter = NormalizedNodeWriter.forStreamWriter(pruner);
+
+        NormalizedNode<?, ?> expected = createTestContainer();
+
+        normalizedNodeWriter.write(expected);
+
+        NormalizedNode<?, ?> actual = pruner.normalizedNode();
+
+        assertEquals(expected, actual);
+
+    }
+
+    @Test(expected = IllegalStateException.class)
+    public void testReusePruner() throws IOException {
+        NormalizedNodePruner pruner = prunerFullSchema(TestModel.TEST_PATH);
+
+        NormalizedNodeWriter normalizedNodeWriter = NormalizedNodeWriter.forStreamWriter(pruner);
+
+        NormalizedNode<?, ?> expected = createTestContainer();
+
+        normalizedNodeWriter.write(expected);
+
+        NormalizedNode<?, ?> actual = pruner.normalizedNode();
+
+        assertEquals(expected, actual);
+
+        NormalizedNodeWriter.forStreamWriter(pruner).write(expected);
+
+    }
+
+
+    @Test
+    public void testNodesPrunedWhenAugmentationSchemaMissing() throws IOException {
+        NormalizedNodePruner pruner = prunerNoAugSchema(TestModel.TEST_PATH);
+
+        NormalizedNodeWriter normalizedNodeWriter = NormalizedNodeWriter.forStreamWriter(pruner);
+
+        NormalizedNode<?, ?> expected = createTestContainer();
+
+        normalizedNodeWriter.write(expected);
+
+        NormalizedNode<?, ?> actual = pruner.normalizedNode();
+
+        Assert.assertNotEquals(expected, actual);
+
+        // Asserting true here instead of checking actual value because I don't want this assertion to be fragile
+        assertTrue(countNodes(expected, "store:aug") > 0);
+
+        // All nodes from the augmentation module are gone from the resulting node
+        assertEquals(0, countNodes(actual, "store:aug"));
+    }
+
+    @Test
+    public void testNodesPrunedWhenTestSchemaMissing() throws IOException {
+        NormalizedNodePruner pruner = prunerNoTestSchema(TestModel.TEST_PATH);
+
+        NormalizedNodeWriter normalizedNodeWriter = NormalizedNodeWriter.forStreamWriter(pruner);
+
+        NormalizedNode<?, ?> expected = createTestContainer();
+
+        normalizedNodeWriter.write(expected);
+
+        NormalizedNode<?, ?> actual = pruner.normalizedNode();
+
+        // Since top level schema is missing null is returned
+        assertNull(actual);
+
+        // Asserting true here instead of checking actual value because I don't want this assertion to be fragile
+        assertTrue(countNodes(expected, "urn:opendaylight:params:xml:ns:yang:controller:md:sal:dom:store:test") > 0);
+
+    }
+
+    private static int countNodes(final NormalizedNode<?,?> normalizedNode, final String namespaceFilter) {
+        if (normalizedNode == null) {
+            return 0;
+        }
+        final AtomicInteger count = new AtomicInteger();
+        new NormalizedNodeNavigator((level, parentPath, normalizedNode1) -> {
+            if (!(normalizedNode1.getIdentifier() instanceof AugmentationIdentifier)) {
+                if (normalizedNode1.getIdentifier().getNodeType().getNamespace().toString().contains(namespaceFilter)) {
+                    count.incrementAndGet();
+                }
+            }
+        }).navigate(YangInstanceIdentifier.empty().toString(), normalizedNode);
+
+        return count.get();
+    }
+
+    @Test
+    public void testLeafNodeNotPrunedWhenHasNoParent() throws IOException {
+        NormalizedNodePruner pruner = prunerFullSchema(TestModel.TEST_PATH.node(TestModel.DESC_QNAME));
+        NormalizedNode<?, ?> input = Builders.leafBuilder().withNodeIdentifier(
+                new NodeIdentifier(TestModel.DESC_QNAME)).withValue("test").build();
+        NormalizedNodeWriter.forStreamWriter(pruner).write(input);
+
+        NormalizedNode<?, ?> actual = pruner.normalizedNode();
+        assertEquals("normalizedNode", input, actual);
+    }
+
+    @Test
+    public void testLeafNodePrunedWhenHasAugmentationParentAndSchemaMissing() throws IOException {
+        AugmentationIdentifier augId = new AugmentationIdentifier(Sets.newHashSet(TestModel.AUG_CONT_QNAME));
+        NormalizedNodePruner pruner = prunerFullSchema(YangInstanceIdentifier.builder()
+                .node(TestModel.TEST_QNAME).node(TestModel.AUGMENTED_LIST_QNAME)
+                        .node(TestModel.AUGMENTED_LIST_QNAME).node(augId).build());
+        LeafNode<Object> child = Builders.leafBuilder().withNodeIdentifier(
+                new NodeIdentifier(TestModel.INVALID_QNAME)).withValue("test").build();
+        NormalizedNode<?, ?> input = Builders.augmentationBuilder().withNodeIdentifier(augId).withChild(child).build();
+        NormalizedNodeWriter.forStreamWriter(pruner).write(input);
+
+        NormalizedNode<?, ?> actual = pruner.normalizedNode();
+        assertEquals("normalizedNode", Builders.augmentationBuilder().withNodeIdentifier(augId).build(), actual);
+    }
+
+    @Test
+    public void testLeafNodePrunedWhenHasNoParentAndSchemaMissing() throws IOException {
+        NormalizedNodePruner pruner = prunerFullSchema(TestModel.TEST_PATH.node(TestModel.INVALID_QNAME));
+        NormalizedNode<?, ?> input = Builders.leafBuilder().withNodeIdentifier(
+                new NodeIdentifier(TestModel.INVALID_QNAME)).withValue("test").build();
+        NormalizedNodeWriter.forStreamWriter(pruner).write(input);
+
+        NormalizedNode<?, ?> actual = pruner.normalizedNode();
+        assertNull(actual);
+    }
+
+
+    @Test
+    public void testLeafSetEntryNodeNotPrunedWhenHasNoParent() throws IOException {
+        NormalizedNodePruner pruner = prunerFullSchema(TestModel.TEST_PATH.node(TestModel.SHOE_QNAME));
+        NormalizedNode<?, ?> input = Builders.leafSetEntryBuilder().withValue("puma").withNodeIdentifier(
+                new NodeWithValue<>(TestModel.SHOE_QNAME, "puma")).build();
+        NormalizedNodeWriter.forStreamWriter(pruner).write(input);
+
+        NormalizedNode<?, ?> actual = pruner.normalizedNode();
+        assertEquals("normalizedNode", input, actual);
+    }
+
+    @Test
+    public void testLeafSetEntryNodeNotPrunedWhenHasParent() throws IOException {
+        NormalizedNodePruner pruner = prunerFullSchema(TestModel.TEST_PATH.node(TestModel.SHOE_QNAME));
+        LeafSetEntryNode<Object> child = Builders.leafSetEntryBuilder().withValue("puma").withNodeIdentifier(
+                new NodeWithValue<>(TestModel.SHOE_QNAME, "puma")).build();
+        NormalizedNode<?, ?> input = Builders.leafSetBuilder().withNodeIdentifier(
+                new NodeIdentifier(TestModel.SHOE_QNAME)).withChild(child).build();
+        NormalizedNodeWriter.forStreamWriter(pruner).write(input);
+
+        NormalizedNode<?, ?> actual = pruner.normalizedNode();
+        assertEquals("normalizedNode", input, actual);
+    }
+
+    @Test
+    public void testLeafSetEntryNodePrunedWhenHasNoParentAndSchemaMissing() throws IOException {
+        NormalizedNodePruner pruner = prunerFullSchema(TestModel.TEST_PATH.node(TestModel.INVALID_QNAME));
+        NormalizedNode<?, ?> input = Builders.leafSetEntryBuilder().withValue("test").withNodeIdentifier(
+                new NodeWithValue<>(TestModel.INVALID_QNAME, "test")).build();
+        NormalizedNodeWriter.forStreamWriter(pruner).write(input);
+
+        NormalizedNode<?, ?> actual = pruner.normalizedNode();
+        assertNull(actual);
+    }
+
+    @Test
+    public void testLeafSetEntryNodePrunedWhenHasParentAndSchemaMissing() throws IOException {
+        NormalizedNodePruner pruner = prunerFullSchema(TestModel.TEST_PATH.node(TestModel.INVALID_QNAME));
+        LeafSetEntryNode<Object> child = Builders.leafSetEntryBuilder().withValue("test").withNodeIdentifier(
+                new NodeWithValue<>(TestModel.INVALID_QNAME, "test")).build();
+        NormalizedNode<?, ?> input = Builders.leafSetBuilder().withNodeIdentifier(
+                new NodeIdentifier(TestModel.INVALID_QNAME)).withChild(child).build();
+        NormalizedNodeWriter.forStreamWriter(pruner).write(input);
+
+        NormalizedNode<?, ?> actual = pruner.normalizedNode();
+        assertNull(actual);
+    }
+
+    @Test
+    public void testAnyXMLNodeNotPrunedWhenHasNoParent() throws IOException {
+        NormalizedNodePruner pruner = prunerFullSchema(TestModel.TEST_PATH.node(TestModel.ANY_XML_QNAME));
+        NormalizedNode<?, ?> input = Builders.anyXmlBuilder().withNodeIdentifier(
+                new NodeIdentifier(TestModel.ANY_XML_QNAME)).withValue(mock(DOMSource.class)).build();
+        NormalizedNodeWriter.forStreamWriter(pruner).write(input);
+
+        NormalizedNode<?, ?> actual = pruner.normalizedNode();
+        assertEquals("normalizedNode", input, actual);
+    }
+
+
+    @Test
+    public void testAnyXMLNodeNotPrunedWhenHasParent() throws IOException {
+        NormalizedNodePruner pruner = prunerFullSchema(TestModel.TEST_PATH);
+        DOMSourceAnyxmlNode child = Builders.anyXmlBuilder().withNodeIdentifier(
+                new NodeIdentifier(TestModel.ANY_XML_QNAME)).withValue(mock(DOMSource.class)).build();
+        NormalizedNode<?, ?> input = Builders.containerBuilder().withNodeIdentifier(
+                new NodeIdentifier(TestModel.TEST_QNAME)).withChild(child).build();
+        NormalizedNodeWriter.forStreamWriter(pruner).write(input);
+
+        NormalizedNode<?, ?> actual = pruner.normalizedNode();
+        assertEquals("normalizedNode", input, actual);
+    }
+
+    @Test
+    public void testAnyXmlNodePrunedWhenHasNoParentAndSchemaMissing() throws IOException {
+        NormalizedNodePruner pruner = prunerNoTestSchema(TestModel.TEST_PATH.node(TestModel.ANY_XML_QNAME));
+        NormalizedNode<?, ?> input = Builders.anyXmlBuilder().withNodeIdentifier(
+                new NodeIdentifier(TestModel.ANY_XML_QNAME)).withValue(mock(DOMSource.class)).build();
+        NormalizedNodeWriter.forStreamWriter(pruner).write(input);
+
+        NormalizedNode<?, ?> actual = pruner.normalizedNode();
+        assertNull(actual);
+    }
+
+    @Test
+    public void testInnerContainerNodeWithFullPathPathNotPruned() throws IOException {
+        YangInstanceIdentifier path = YangInstanceIdentifier.builder().node(TestModel.TEST_QNAME)
+                .node(TestModel.OUTER_LIST_QNAME).nodeWithKey(TestModel.OUTER_LIST_QNAME, TestModel.ID_QNAME, 1)
+                .node(TestModel.INNER_LIST_QNAME).nodeWithKey(TestModel.INNER_LIST_QNAME, TestModel.NAME_QNAME, "one")
+                .node(TestModel.INNER_CONTAINER_QNAME).build();
+        NormalizedNodePruner pruner = prunerFullSchema(path);
+
+        NormalizedNode<?, ?> input = ImmutableNodes.containerNode(TestModel.INNER_CONTAINER_QNAME);
+        NormalizedNodeWriter.forStreamWriter(pruner).write(input);
+
+        NormalizedNode<?, ?> actual = pruner.normalizedNode();
+        assertEquals("normalizedNode", input, actual);
+    }
+
+    @Test
+    public void testInnerContainerNodeWithFullPathPrunedWhenSchemaMissing() throws IOException {
+        YangInstanceIdentifier path = YangInstanceIdentifier.builder().node(TestModel.TEST_QNAME)
+                .node(TestModel.OUTER_LIST_QNAME).nodeWithKey(TestModel.OUTER_LIST_QNAME, TestModel.ID_QNAME, 1)
+                .node(TestModel.INNER_LIST_QNAME).nodeWithKey(TestModel.INNER_LIST_QNAME, TestModel.NAME_QNAME, "one")
+                .node(TestModel.INVALID_QNAME).build();
+        NormalizedNodePruner pruner = prunerFullSchema(path);
+
+        NormalizedNode<?, ?> input = ImmutableNodes.containerNode(TestModel.INVALID_QNAME);
+        NormalizedNodeWriter.forStreamWriter(pruner).write(input);
+
+        NormalizedNode<?, ?> actual = pruner.normalizedNode();
+        assertNull(actual);
+    }
+
+    @Test
+    public void testInnerContainerNodeWithParentPathPrunedWhenSchemaMissing() throws IOException {
+        YangInstanceIdentifier path = YangInstanceIdentifier.builder().node(TestModel.TEST_QNAME)
+                .node(TestModel.OUTER_LIST_QNAME).nodeWithKey(TestModel.OUTER_LIST_QNAME, TestModel.ID_QNAME, 1)
+                .build();
+        NormalizedNodePruner pruner = prunerFullSchema(path);
+
+        MapNode innerList = mapNodeBuilder(TestModel.INNER_LIST_QNAME).withChild(mapEntryBuilder(
+                TestModel.INNER_LIST_QNAME, TestModel.NAME_QNAME, "one").withChild(
+                        ImmutableNodes.containerNode(TestModel.INVALID_QNAME)).build()).build();
+        NormalizedNode<?, ?> input = mapEntryBuilder(TestModel.OUTER_LIST_QNAME, TestModel.ID_QNAME, 1)
+                .withChild(innerList).build();
+        NormalizedNodeWriter.forStreamWriter(pruner).write(input);
+
+        NormalizedNode<?, ?> expected = mapEntryBuilder(TestModel.OUTER_LIST_QNAME, TestModel.ID_QNAME, 1)
+                .withChild(mapNodeBuilder(TestModel.INNER_LIST_QNAME).withChild(mapEntryBuilder(
+                    TestModel.INNER_LIST_QNAME, TestModel.NAME_QNAME, "one").build()).build()).build();
+        NormalizedNode<?, ?> actual = pruner.normalizedNode();
+        assertEquals("normalizedNode", expected, actual);
+    }
+
+    @Test
+    public void testInnerListNodeWithFullPathNotPruned() throws IOException {
+        YangInstanceIdentifier path = YangInstanceIdentifier.builder().node(TestModel.TEST_QNAME)
+                .node(TestModel.OUTER_LIST_QNAME).nodeWithKey(TestModel.OUTER_LIST_QNAME, TestModel.ID_QNAME, 1)
+                .node(TestModel.INNER_LIST_QNAME).build();
+        NormalizedNodePruner pruner = prunerFullSchema(path);
+
+        MapNode input = mapNodeBuilder(TestModel.INNER_LIST_QNAME).withChild(mapEntryBuilder(
+                TestModel.INNER_LIST_QNAME, TestModel.NAME_QNAME, "one").withChild(
+                        ImmutableNodes.containerNode(TestModel.INNER_CONTAINER_QNAME)).build()).build();
+        NormalizedNodeWriter.forStreamWriter(pruner).write(input);
+
+        NormalizedNode<?, ?> actual = pruner.normalizedNode();
+        assertEquals("normalizedNode", input, actual);
+    }
+
+    @Test
+    public void testInnerListNodeWithFullPathPrunedWhenSchemaMissing() throws IOException {
+        YangInstanceIdentifier path = YangInstanceIdentifier.builder().node(TestModel.TEST_QNAME)
+                .node(TestModel.OUTER_LIST_QNAME).nodeWithKey(TestModel.OUTER_LIST_QNAME, TestModel.ID_QNAME, 1)
+                .node(TestModel.INVALID_QNAME).build();
+        NormalizedNodePruner pruner = prunerFullSchema(path);
+
+        MapNode input = mapNodeBuilder(TestModel.INVALID_QNAME).withChild(mapEntryBuilder(
+                TestModel.INVALID_QNAME, TestModel.NAME_QNAME, "one").withChild(
+                        ImmutableNodes.containerNode(TestModel.INNER_CONTAINER_QNAME)).build()).build();
+        NormalizedNodeWriter.forStreamWriter(pruner).write(input);
+
+        NormalizedNode<?, ?> actual = pruner.normalizedNode();
+        assertNull(actual);
+    }
+
+    @Test
+    public void testInnerListNodeWithParentPathPrunedWhenSchemaMissing() throws IOException {
+        YangInstanceIdentifier path = YangInstanceIdentifier.builder().node(TestModel.TEST_QNAME)
+                .node(TestModel.OUTER_LIST_QNAME).nodeWithKey(TestModel.OUTER_LIST_QNAME, TestModel.ID_QNAME, 1)
+                .build();
+        NormalizedNodePruner pruner = prunerFullSchema(path);
+
+        MapNode innerList = mapNodeBuilder(TestModel.INVALID_QNAME).withChild(mapEntryBuilder(
+                TestModel.INVALID_QNAME, TestModel.NAME_QNAME, "one").withChild(
+                        ImmutableNodes.containerNode(TestModel.INNER_CONTAINER_QNAME)).build()).build();
+        NormalizedNode<?, ?> input = mapEntryBuilder(TestModel.OUTER_LIST_QNAME, TestModel.ID_QNAME, 1)
+                .withChild(innerList).build();
+        NormalizedNodeWriter.forStreamWriter(pruner).write(input);
+
+        NormalizedNode<?, ?> expected = mapEntry(TestModel.OUTER_LIST_QNAME, TestModel.ID_QNAME, 1);
+        NormalizedNode<?, ?> actual = pruner.normalizedNode();
+        assertEquals("normalizedNode", expected, actual);
+    }
+
+    private static NormalizedNode<?, ?> createTestContainer() {
+        byte[] bytes1 = {1, 2, 3};
+        LeafSetEntryNode<Object> entry1 = ImmutableLeafSetEntryNodeBuilder.create().withNodeIdentifier(
+                new NodeWithValue<>(TestModel.BINARY_LEAF_LIST_QNAME, bytes1)).withValue(bytes1).build();
+
+        byte[] bytes2 = {};
+        LeafSetEntryNode<Object> entry2 = ImmutableLeafSetEntryNodeBuilder.create().withNodeIdentifier(
+                new NodeWithValue<>(TestModel.BINARY_LEAF_LIST_QNAME, bytes2)).withValue(bytes2).build();
+
+        return TestModel.createBaseTestContainerBuilder()
+                .withChild(ImmutableLeafSetNodeBuilder.create().withNodeIdentifier(
+                        new NodeIdentifier(TestModel.BINARY_LEAF_LIST_QNAME))
+                        .withChild(entry1).withChild(entry2).build())
+                .withChild(ImmutableNodes.leafNode(TestModel.SOME_BINARY_DATA_QNAME, new byte[]{1, 2, 3, 4}))
+                .build();
+    }
+}
diff --git a/util/TestModel.java b/util/TestModel.java
new file mode 100644 (file)
index 0000000..ebef712
--- /dev/null
@@ -0,0 +1,424 @@
+/*
+ * Copyright (c) 2014, 2015 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.controller.cluster.datastore.util;
+
+import static org.opendaylight.yangtools.yang.data.impl.schema.ImmutableNodes.mapEntry;
+import static org.opendaylight.yangtools.yang.data.impl.schema.ImmutableNodes.mapEntryBuilder;
+import static org.opendaylight.yangtools.yang.data.impl.schema.ImmutableNodes.mapNodeBuilder;
+
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableSet;
+import java.io.InputStream;
+import java.math.BigDecimal;
+import java.math.BigInteger;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
+import org.opendaylight.yangtools.yang.common.QName;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.AugmentationIdentifier;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifier;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifierWithPredicates;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeWithValue;
+import org.opendaylight.yangtools.yang.data.api.schema.AugmentationNode;
+import org.opendaylight.yangtools.yang.data.api.schema.ContainerNode;
+import org.opendaylight.yangtools.yang.data.api.schema.LeafNode;
+import org.opendaylight.yangtools.yang.data.api.schema.LeafSetEntryNode;
+import org.opendaylight.yangtools.yang.data.api.schema.LeafSetNode;
+import org.opendaylight.yangtools.yang.data.api.schema.MapEntryNode;
+import org.opendaylight.yangtools.yang.data.api.schema.MapNode;
+import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
+import org.opendaylight.yangtools.yang.data.api.schema.UnkeyedListEntryNode;
+import org.opendaylight.yangtools.yang.data.impl.schema.Builders;
+import org.opendaylight.yangtools.yang.data.impl.schema.ImmutableNodes;
+import org.opendaylight.yangtools.yang.data.impl.schema.builder.api.CollectionNodeBuilder;
+import org.opendaylight.yangtools.yang.data.impl.schema.builder.api.DataContainerNodeBuilder;
+import org.opendaylight.yangtools.yang.data.impl.schema.builder.api.NormalizedNodeBuilder;
+import org.opendaylight.yangtools.yang.data.impl.schema.builder.impl.ImmutableContainerNodeBuilder;
+import org.opendaylight.yangtools.yang.data.impl.schema.builder.impl.ImmutableLeafSetEntryNodeBuilder;
+import org.opendaylight.yangtools.yang.data.impl.schema.builder.impl.ImmutableLeafSetNodeBuilder;
+import org.opendaylight.yangtools.yang.data.impl.schema.builder.impl.ImmutableMapEntryNodeBuilder;
+import org.opendaylight.yangtools.yang.model.api.SchemaContext;
+import org.opendaylight.yangtools.yang.test.util.YangParserTestUtils;
+
+public final class TestModel {
+
+    public static final QName TEST_QNAME = QName.create(
+            "urn:opendaylight:params:xml:ns:yang:controller:md:sal:dom:store:test",
+            "2014-03-13", "test");
+
+    public static final QName AUG_NAME_QNAME = QName.create(
+            "urn:opendaylight:params:xml:ns:yang:controller:md:sal:dom:store:aug",
+            "2014-03-13", "name");
+
+    public static final QName AUG_CONT_QNAME = QName.create(
+            "urn:opendaylight:params:xml:ns:yang:controller:md:sal:dom:store:aug",
+            "2014-03-13", "cont");
+
+
+    public static final QName DESC_QNAME = QName.create(TEST_QNAME, "desc");
+    public static final QName POINTER_QNAME = QName.create(TEST_QNAME, "pointer");
+    public static final QName SOME_BINARY_DATA_QNAME = QName.create(TEST_QNAME, "some-binary-data");
+    public static final QName BINARY_LEAF_LIST_QNAME = QName.create(TEST_QNAME, "binary_leaf_list");
+    public static final QName SOME_REF_QNAME = QName.create(TEST_QNAME, "some-ref");
+    public static final QName MYIDENTITY_QNAME = QName.create(TEST_QNAME, "myidentity");
+    public static final QName SWITCH_FEATURES_QNAME = QName.create(TEST_QNAME, "switch-features");
+
+    public static final QName AUGMENTED_LIST_QNAME = QName.create(TEST_QNAME, "augmented-list");
+    public static final QName AUGMENTED_LIST_ENTRY_QNAME = QName.create(TEST_QNAME, "augmented-list-entry");
+
+    public static final QName OUTER_LIST_QNAME = QName.create(TEST_QNAME, "outer-list");
+    public static final QName INNER_LIST_QNAME = QName.create(TEST_QNAME, "inner-list");
+    public static final QName INNER_CONTAINER_QNAME = QName.create(TEST_QNAME, "inner-container");
+    public static final QName OUTER_CHOICE_QNAME = QName.create(TEST_QNAME, "outer-choice");
+    public static final QName ID_QNAME = QName.create(TEST_QNAME, "id");
+    public static final QName NAME_QNAME = QName.create(TEST_QNAME, "name");
+    public static final QName VALUE_QNAME = QName.create(TEST_QNAME, "value");
+    public static final QName BOOLEAN_LEAF_QNAME = QName.create(TEST_QNAME, "boolean-leaf");
+    public static final QName SHORT_LEAF_QNAME = QName.create(TEST_QNAME, "short-leaf");
+    public static final QName BYTE_LEAF_QNAME = QName.create(TEST_QNAME, "byte-leaf");
+    public static final QName BIGINTEGER_LEAF_QNAME = QName.create(TEST_QNAME, "biginteger-leaf");
+    public static final QName BIGDECIMAL_LEAF_QNAME = QName.create(TEST_QNAME, "bigdecimal-leaf");
+    public static final QName ORDERED_LIST_QNAME = QName.create(TEST_QNAME, "ordered-list");
+    public static final QName ORDERED_LIST_ENTRY_QNAME = QName.create(TEST_QNAME, "ordered-list-leaf");
+    public static final QName UNKEYED_LIST_QNAME = QName.create(TEST_QNAME, "unkeyed-list");
+    public static final QName UNKEYED_LIST_ENTRY_QNAME = QName.create(TEST_QNAME, "unkeyed-list-entry");
+    public static final QName CHOICE_QNAME = QName.create(TEST_QNAME, "choice");
+    public static final QName SHOE_QNAME = QName.create(TEST_QNAME, "shoe");
+    public static final QName ANY_XML_QNAME = QName.create(TEST_QNAME, "any");
+    public static final QName EMPTY_QNAME = QName.create(TEST_QNAME, "empty-leaf");
+    public static final QName INVALID_QNAME = QName.create(TEST_QNAME, "invalid");
+    private static final String DATASTORE_TEST_YANG = "/odl-datastore-test.yang";
+    private static final String DATASTORE_AUG_YANG = "/odl-datastore-augmentation.yang";
+    private static final String DATASTORE_TEST_NOTIFICATION_YANG = "/odl-datastore-test-notification.yang";
+
+    public static final YangInstanceIdentifier TEST_PATH = YangInstanceIdentifier.of(TEST_QNAME);
+    public static final YangInstanceIdentifier DESC_PATH = YangInstanceIdentifier
+            .builder(TEST_PATH).node(DESC_QNAME).build();
+    public static final YangInstanceIdentifier OUTER_LIST_PATH =
+            YangInstanceIdentifier.builder(TEST_PATH).node(OUTER_LIST_QNAME).build();
+    public static final QName TWO_THREE_QNAME = QName.create(TEST_QNAME, "two");
+    public static final QName TWO_QNAME = QName.create(TEST_QNAME, "two");
+    public static final QName THREE_QNAME = QName.create(TEST_QNAME, "three");
+
+    private static final Integer ONE_ID = 1;
+    private static final Integer TWO_ID = 2;
+    private static final String TWO_ONE_NAME = "one";
+    private static final String TWO_TWO_NAME = "two";
+    private static final String DESC = "Hello there";
+    private static final Boolean ENABLED = true;
+    private static final Short SHORT_ID = 1;
+    private static final Byte BYTE_ID = 1;
+    // Family specific constants
+    public static final QName FAMILY_QNAME = QName.create(
+        "urn:opendaylight:params:xml:ns:yang:controller:md:sal:dom:store:notification-test", "2014-04-17", "family");
+    public static final QName CHILDREN_QNAME = QName.create(FAMILY_QNAME, "children");
+    public static final QName GRAND_CHILDREN_QNAME = QName.create(FAMILY_QNAME, "grand-children");
+    public static final QName CHILD_NUMBER_QNAME = QName.create(FAMILY_QNAME, "child-number");
+    public static final QName CHILD_NAME_QNAME = QName.create(FAMILY_QNAME, "child-name");
+    public static final QName GRAND_CHILD_NUMBER_QNAME = QName.create(FAMILY_QNAME, "grand-child-number");
+    public static final QName GRAND_CHILD_NAME_QNAME = QName.create(FAMILY_QNAME,"grand-child-name");
+
+    public static final YangInstanceIdentifier FAMILY_PATH = YangInstanceIdentifier.of(FAMILY_QNAME);
+    public static final YangInstanceIdentifier FAMILY_DESC_PATH =
+            YangInstanceIdentifier.builder(FAMILY_PATH).node(DESC_QNAME).build();
+    public static final YangInstanceIdentifier CHILDREN_PATH =
+            YangInstanceIdentifier.builder(FAMILY_PATH).node(CHILDREN_QNAME).build();
+
+    private static final Integer FIRST_CHILD_ID = 1;
+    private static final Integer SECOND_CHILD_ID = 2;
+
+    private static final String FIRST_CHILD_NAME = "first child";
+    private static final String SECOND_CHILD_NAME = "second child";
+
+    private static final Integer FIRST_GRAND_CHILD_ID = 1;
+    private static final Integer SECOND_GRAND_CHILD_ID = 2;
+
+    private static final String FIRST_GRAND_CHILD_NAME = "first grand child";
+    private static final String SECOND_GRAND_CHILD_NAME = "second grand child";
+
+    private static final MapEntryNode BAR_NODE = mapEntryBuilder(
+            OUTER_LIST_QNAME, ID_QNAME, TWO_ID) //
+            .withChild(mapNodeBuilder(INNER_LIST_QNAME) //
+                    .withChild(mapEntry(INNER_LIST_QNAME, NAME_QNAME, TWO_ONE_NAME)) //
+                    .withChild(mapEntry(INNER_LIST_QNAME, NAME_QNAME, TWO_TWO_NAME)) //
+                    .build()) //
+            .build();
+
+    private TestModel() {
+        throw new UnsupportedOperationException();
+    }
+
+    public static InputStream getDatastoreTestInputStream() {
+        return getInputStream(DATASTORE_TEST_YANG);
+    }
+
+    public static InputStream getDatastoreAugInputStream() {
+        return getInputStream(DATASTORE_AUG_YANG);
+    }
+
+    public static InputStream getDatastoreTestNotificationInputStream() {
+        return getInputStream(DATASTORE_TEST_NOTIFICATION_YANG);
+    }
+
+    private static InputStream getInputStream(final String resourceName) {
+        return TestModel.class.getResourceAsStream(resourceName);
+    }
+
+    public static SchemaContext createTestContext() {
+        return YangParserTestUtils.parseYangResources(TestModel.class, DATASTORE_TEST_YANG, DATASTORE_AUG_YANG,
+            DATASTORE_TEST_NOTIFICATION_YANG);
+    }
+
+    public static SchemaContext createTestContextWithoutTestSchema() {
+        return YangParserTestUtils.parseYangResource(DATASTORE_TEST_NOTIFICATION_YANG);
+    }
+
+    public static SchemaContext createTestContextWithoutAugmentationSchema() {
+        return YangParserTestUtils.parseYangResources(TestModel.class, DATASTORE_TEST_YANG,
+            DATASTORE_TEST_NOTIFICATION_YANG);
+    }
+
+    /**
+     * Returns a test document.
+     * <p/>
+     * <p/>
+     * <pre>
+     * test
+     *     outer-list
+     *          id 1
+     *     outer-list
+     *          id 2
+     *          inner-list
+     *                  name "one"
+     *          inner-list
+     *                  name "two"
+     *
+     * </pre>
+     */
+    public static NormalizedNode<?, ?> createDocumentOne(final SchemaContext schemaContext) {
+        return ImmutableContainerNodeBuilder
+                .create()
+                .withNodeIdentifier(
+                        new NodeIdentifier(schemaContext.getQName()))
+                .withChild(createTestContainer()).build();
+
+    }
+
+    public static DataContainerNodeBuilder<NodeIdentifier, ContainerNode> createBaseTestContainerBuilder() {
+        // Create a list of shoes
+        // This is to test leaf list entry
+        final LeafSetEntryNode<Object> nike = ImmutableLeafSetEntryNodeBuilder.create().withNodeIdentifier(
+                new NodeWithValue<>(SHOE_QNAME, "nike")).withValue("nike").build();
+
+        final LeafSetEntryNode<Object> puma = ImmutableLeafSetEntryNodeBuilder.create().withNodeIdentifier(
+                new NodeWithValue<>(SHOE_QNAME, "puma")).withValue("puma").build();
+
+        final LeafSetNode<Object> shoes = ImmutableLeafSetNodeBuilder.create().withNodeIdentifier(
+                new NodeIdentifier(SHOE_QNAME)).withChild(nike).withChild(puma).build();
+
+        // Test a leaf-list where each entry contains an identity
+        final LeafSetEntryNode<Object> cap1 =
+                ImmutableLeafSetEntryNodeBuilder
+                        .create()
+                        .withNodeIdentifier(
+                                new NodeWithValue<>(QName.create(
+                                        TEST_QNAME, "capability"), DESC_QNAME))
+                        .withValue(DESC_QNAME).build();
+
+        final LeafSetNode<Object> capabilities =
+                ImmutableLeafSetNodeBuilder
+                        .create()
+                        .withNodeIdentifier(
+                                new NodeIdentifier(QName.create(
+                                        TEST_QNAME, "capability"))).withChild(cap1).build();
+
+        ContainerNode switchFeatures =
+                ImmutableContainerNodeBuilder
+                        .create()
+                        .withNodeIdentifier(
+                                new NodeIdentifier(SWITCH_FEATURES_QNAME))
+                        .withChild(capabilities).build();
+
+        // Create a leaf list with numbers
+        final LeafSetEntryNode<Object> five =
+                ImmutableLeafSetEntryNodeBuilder
+                        .create()
+                        .withNodeIdentifier(
+                                new NodeWithValue<>(QName.create(
+                                        TEST_QNAME, "number"), 5)).withValue(5).build();
+        final LeafSetEntryNode<Object> fifteen =
+                ImmutableLeafSetEntryNodeBuilder
+                        .create()
+                        .withNodeIdentifier(
+                                new NodeWithValue<>(QName.create(
+                                        TEST_QNAME, "number"), 15)).withValue(15).build();
+        final LeafSetNode<Object> numbers =
+                ImmutableLeafSetNodeBuilder
+                        .create()
+                        .withNodeIdentifier(
+                                new NodeIdentifier(QName.create(
+                                        TEST_QNAME, "number"))).withChild(five).withChild(fifteen)
+                        .build();
+
+
+        // Create augmentations
+        MapEntryNode augMapEntry = createAugmentedListEntry(1, "First Test");
+
+        // Create a bits leaf
+        NormalizedNodeBuilder<NodeIdentifier, Object, LeafNode<Object>>
+                myBits = Builders.leafBuilder()
+                .withNodeIdentifier(new NodeIdentifier(QName.create(TEST_QNAME, "my-bits")))
+                .withValue(ImmutableSet.of("foo", "bar"));
+
+        // Create unkeyed list entry
+        UnkeyedListEntryNode unkeyedListEntry =
+                Builders.unkeyedListEntryBuilder().withNodeIdentifier(new YangInstanceIdentifier.NodeIdentifier(
+                    UNKEYED_LIST_QNAME)).withChild(ImmutableNodes.leafNode(NAME_QNAME, "unkeyed-entry-name")).build();
+
+        // Create YangInstanceIdentifier with all path arg types.
+        YangInstanceIdentifier instanceID = YangInstanceIdentifier.create(
+                new NodeIdentifier(QName.create(TEST_QNAME, "qname")),
+                NodeIdentifierWithPredicates.of(QName.create(TEST_QNAME, "list-entry"),
+                        QName.create(TEST_QNAME, "key"), 10),
+                new AugmentationIdentifier(ImmutableSet.of(
+                        QName.create(TEST_QNAME, "aug1"), QName.create(TEST_QNAME, "aug2"))),
+                new NodeWithValue<>(QName.create(TEST_QNAME, "leaf-list-entry"), "foo"));
+
+        Map<QName, Object> keyValues = new HashMap<>();
+        keyValues.put(CHILDREN_QNAME, FIRST_CHILD_NAME);
+
+
+        // Create the document
+        return ImmutableContainerNodeBuilder
+                .create()
+                .withNodeIdentifier(new YangInstanceIdentifier.NodeIdentifier(TEST_QNAME))
+                .withChild(myBits.build())
+                .withChild(ImmutableNodes.leafNode(DESC_QNAME, DESC))
+                .withChild(ImmutableNodes.leafNode(BOOLEAN_LEAF_QNAME, ENABLED))
+                .withChild(ImmutableNodes.leafNode(SHORT_LEAF_QNAME, SHORT_ID))
+                .withChild(ImmutableNodes.leafNode(BYTE_LEAF_QNAME, BYTE_ID))
+                .withChild(ImmutableNodes.leafNode(TestModel.BIGINTEGER_LEAF_QNAME, BigInteger.valueOf(100)))
+                .withChild(ImmutableNodes.leafNode(TestModel.BIGDECIMAL_LEAF_QNAME, BigDecimal.valueOf(1.2)))
+                .withChild(ImmutableNodes.leafNode(SOME_REF_QNAME, instanceID))
+                .withChild(ImmutableNodes.leafNode(MYIDENTITY_QNAME, DESC_QNAME))
+                .withChild(Builders.unkeyedListBuilder()
+                        .withNodeIdentifier(new YangInstanceIdentifier.NodeIdentifier(UNKEYED_LIST_QNAME))
+                        .withChild(unkeyedListEntry).build())
+                .withChild(Builders.choiceBuilder()
+                        .withNodeIdentifier(new YangInstanceIdentifier.NodeIdentifier(TWO_THREE_QNAME))
+                        .withChild(ImmutableNodes.leafNode(TWO_QNAME, "two")).build())
+                .withChild(Builders.orderedMapBuilder()
+                        .withNodeIdentifier(new YangInstanceIdentifier.NodeIdentifier(ORDERED_LIST_QNAME))
+                        .withValue(ImmutableList.<MapEntryNode>builder().add(
+                                mapEntryBuilder(ORDERED_LIST_QNAME, ORDERED_LIST_ENTRY_QNAME, "1").build(),
+                                mapEntryBuilder(ORDERED_LIST_QNAME, ORDERED_LIST_ENTRY_QNAME, "2").build()).build())
+                        .build())
+                .withChild(shoes)
+                .withChild(numbers)
+                .withChild(switchFeatures)
+                .withChild(mapNodeBuilder(AUGMENTED_LIST_QNAME).withChild(augMapEntry).build())
+                .withChild(mapNodeBuilder(OUTER_LIST_QNAME)
+                                .withChild(mapEntry(OUTER_LIST_QNAME, ID_QNAME, ONE_ID))
+                                .withChild(BAR_NODE).build()
+                );
+    }
+
+    public static ContainerNode createTestContainer() {
+        return createBaseTestContainerBuilder().build();
+    }
+
+    public static MapEntryNode createAugmentedListEntry(final int id, final String name) {
+
+        Set<QName> childAugmentations = new HashSet<>();
+        childAugmentations.add(AUG_CONT_QNAME);
+
+        ContainerNode augCont =
+                ImmutableContainerNodeBuilder
+                        .create()
+                        .withNodeIdentifier(
+                                new YangInstanceIdentifier.NodeIdentifier(AUG_CONT_QNAME))
+                        .withChild(ImmutableNodes.leafNode(AUG_NAME_QNAME, name)).build();
+
+
+        final YangInstanceIdentifier.AugmentationIdentifier augmentationIdentifier =
+                new YangInstanceIdentifier.AugmentationIdentifier(childAugmentations);
+
+        final AugmentationNode augmentationNode =
+                Builders.augmentationBuilder()
+                        .withNodeIdentifier(augmentationIdentifier).withChild(augCont)
+                        .build();
+
+        return ImmutableMapEntryNodeBuilder
+                .create()
+                .withNodeIdentifier(
+                        YangInstanceIdentifier.NodeIdentifierWithPredicates.of(
+                                AUGMENTED_LIST_QNAME, ID_QNAME, id))
+                .withChild(ImmutableNodes.leafNode(ID_QNAME, id))
+                .withChild(augmentationNode).build();
+    }
+
+
+    public static ContainerNode createFamily() {
+        final DataContainerNodeBuilder<YangInstanceIdentifier.NodeIdentifier, ContainerNode>
+            familyContainerBuilder = ImmutableContainerNodeBuilder.create().withNodeIdentifier(
+                        new YangInstanceIdentifier.NodeIdentifier(FAMILY_QNAME));
+
+        final CollectionNodeBuilder<MapEntryNode, MapNode> childrenBuilder =
+                mapNodeBuilder(CHILDREN_QNAME);
+
+        final DataContainerNodeBuilder<YangInstanceIdentifier.NodeIdentifierWithPredicates, MapEntryNode>
+            firstChildBuilder = mapEntryBuilder(CHILDREN_QNAME, CHILD_NUMBER_QNAME, FIRST_CHILD_ID);
+        final DataContainerNodeBuilder<YangInstanceIdentifier.NodeIdentifierWithPredicates, MapEntryNode>
+            secondChildBuilder = mapEntryBuilder(CHILDREN_QNAME, CHILD_NUMBER_QNAME, SECOND_CHILD_ID);
+
+        final DataContainerNodeBuilder<YangInstanceIdentifier.NodeIdentifierWithPredicates, MapEntryNode>
+            firstGrandChildBuilder = mapEntryBuilder(GRAND_CHILDREN_QNAME, GRAND_CHILD_NUMBER_QNAME,
+                    FIRST_GRAND_CHILD_ID);
+        final DataContainerNodeBuilder<YangInstanceIdentifier.NodeIdentifierWithPredicates, MapEntryNode>
+            secondGrandChildBuilder = mapEntryBuilder(GRAND_CHILDREN_QNAME, GRAND_CHILD_NUMBER_QNAME,
+                    SECOND_GRAND_CHILD_ID);
+
+        firstGrandChildBuilder
+                .withChild(
+                        ImmutableNodes.leafNode(GRAND_CHILD_NUMBER_QNAME,
+                                FIRST_GRAND_CHILD_ID)).withChild(
+                ImmutableNodes.leafNode(GRAND_CHILD_NAME_QNAME,
+                        FIRST_GRAND_CHILD_NAME));
+
+        secondGrandChildBuilder.withChild(
+                ImmutableNodes
+                        .leafNode(GRAND_CHILD_NUMBER_QNAME, SECOND_GRAND_CHILD_ID))
+                .withChild(
+                        ImmutableNodes.leafNode(GRAND_CHILD_NAME_QNAME,
+                                SECOND_GRAND_CHILD_NAME));
+
+        firstChildBuilder
+                .withChild(ImmutableNodes.leafNode(CHILD_NUMBER_QNAME, FIRST_CHILD_ID))
+                .withChild(ImmutableNodes.leafNode(CHILD_NAME_QNAME, FIRST_CHILD_NAME))
+                .withChild(
+                        mapNodeBuilder(GRAND_CHILDREN_QNAME).withChild(
+                                firstGrandChildBuilder.build()).build());
+
+
+        secondChildBuilder
+                .withChild(ImmutableNodes.leafNode(CHILD_NUMBER_QNAME, SECOND_CHILD_ID))
+                .withChild(ImmutableNodes.leafNode(CHILD_NAME_QNAME, SECOND_CHILD_NAME))
+                .withChild(
+                        mapNodeBuilder(GRAND_CHILDREN_QNAME).withChild(
+                                firstGrandChildBuilder.build()).build());
+
+        childrenBuilder.withChild(firstChildBuilder.build());
+        childrenBuilder.withChild(secondChildBuilder.build());
+
+        return familyContainerBuilder.withChild(childrenBuilder.build()).build();
+    }
+
+}