From fb41618f6e78d5f1a20bbf37c45282c5fc15387d Mon Sep 17 00:00:00 2001
From: Maros Marsalek <mmarsale@cisco.com>
Date: Wed, 29 Jun 2016 09:14:51 +0200
Subject: HONEYCOMB-94 Reimplement writer registry with better ordering options

Now the registry is flat and allows for full control of writer execution order

Change-Id: I864e1d676588ffe59b596145e0829e81b1a1ed2f
Signed-off-by: Maros Marsalek <mmarsale@cisco.com>
---
 .../data/impl/ModifiableDataTreeDelegatorTest.java | 367 ++++++++-------------
 .../v3po/data/impl/ModificationDiffTest.java       | 215 +++++++-----
 2 files changed, 272 insertions(+), 310 deletions(-)

(limited to 'v3po/data-impl/src/test/java')

diff --git a/v3po/data-impl/src/test/java/io/fd/honeycomb/v3po/data/impl/ModifiableDataTreeDelegatorTest.java b/v3po/data-impl/src/test/java/io/fd/honeycomb/v3po/data/impl/ModifiableDataTreeDelegatorTest.java
index 086636de6..c2653661a 100644
--- a/v3po/data-impl/src/test/java/io/fd/honeycomb/v3po/data/impl/ModifiableDataTreeDelegatorTest.java
+++ b/v3po/data-impl/src/test/java/io/fd/honeycomb/v3po/data/impl/ModifiableDataTreeDelegatorTest.java
@@ -16,27 +16,34 @@
 
 package io.fd.honeycomb.v3po.data.impl;
 
+import static org.hamcrest.CoreMatchers.hasItem;
+import static org.hamcrest.CoreMatchers.hasItems;
+import static org.hamcrest.CoreMatchers.is;
 import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertThat;
 import static org.junit.Assert.assertTrue;
 import static org.junit.Assert.fail;
 import static org.mockito.Matchers.any;
-import static org.mockito.Matchers.anyMap;
 import static org.mockito.Matchers.eq;
 import static org.mockito.Mockito.doReturn;
 import static org.mockito.Mockito.doThrow;
 import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.times;
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
 import static org.mockito.MockitoAnnotations.initMocks;
 
 import com.google.common.base.Optional;
+import com.google.common.collect.HashMultimap;
+import com.google.common.collect.ImmutableMultimap;
+import com.google.common.collect.Multimap;
 import com.google.common.util.concurrent.CheckedFuture;
 import com.google.common.util.concurrent.Futures;
 import io.fd.honeycomb.v3po.data.DataModification;
 import io.fd.honeycomb.v3po.translate.TranslationException;
+import io.fd.honeycomb.v3po.translate.write.DataObjectUpdate;
 import io.fd.honeycomb.v3po.translate.write.WriteContext;
 import io.fd.honeycomb.v3po.translate.write.WriterRegistry;
+import java.util.AbstractMap;
 import java.util.Collections;
 import java.util.HashMap;
 import java.util.Map;
@@ -46,18 +53,14 @@ import org.mockito.Mock;
 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
 import org.opendaylight.controller.md.sal.common.api.data.ReadFailedException;
 import org.opendaylight.mdsal.binding.dom.codec.api.BindingNormalizedNodeSerializer;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.v3po.rev150105.interfaces._interface.Ethernet;
 import org.opendaylight.yangtools.yang.binding.DataObject;
 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
 import org.opendaylight.yangtools.yang.common.QName;
 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
 import org.opendaylight.yangtools.yang.data.api.schema.ContainerNode;
-import org.opendaylight.yangtools.yang.data.api.schema.DataContainerChild;
+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.tree.DataTree;
-import org.opendaylight.yangtools.yang.data.api.schema.tree.DataTreeCandidate;
-import org.opendaylight.yangtools.yang.data.api.schema.tree.DataTreeCandidateNode;
-import org.opendaylight.yangtools.yang.data.api.schema.tree.ModificationType;
 
 public class ModifiableDataTreeDelegatorTest {
 
@@ -65,112 +68,66 @@ public class ModifiableDataTreeDelegatorTest {
     private WriterRegistry writer;
     @Mock
     private BindingNormalizedNodeSerializer serializer;
-    @Mock
     private DataTree dataTree;
     @Mock
     private org.opendaylight.yangtools.yang.data.api.schema.tree.DataTreeModification modification;
     @Mock
     private DataBroker contextBroker;
+    @Mock
+    private org.opendaylight.controller.md.sal.binding.api.ReadWriteTransaction tx;
 
     private ModifiableDataTreeManager configDataTree;
 
+    static final InstanceIdentifier<?> DEFAULT_ID = InstanceIdentifier.create(DataObject.class);
+    static DataObject DEFAULT_DATA_OBJECT = mockDataObject("serialized", DataObject.class);
+
     @Before
-    public void setUp() {
+    public void setUp() throws Exception {
         initMocks(this);
-        configDataTree = new ModifiableDataTreeDelegator(serializer, dataTree, writer, contextBroker);
-    }
-
-    @Test
-    public void testRead() throws Exception {
-        final org.opendaylight.yangtools.yang.data.api.schema.tree.DataTreeSnapshot
-                snapshot = mock(org.opendaylight.yangtools.yang.data.api.schema.tree.DataTreeSnapshot.class);
-        when(dataTree.takeSnapshot()).thenReturn(snapshot);
-        when(snapshot.newModification()).thenReturn(modification);
+        dataTree = ModificationDiffTest.getDataTree();
+        when(contextBroker.newReadWriteTransaction()).thenReturn(tx);
+        when(tx.submit()).thenReturn(Futures.immediateCheckedFuture(null));
 
-        final YangInstanceIdentifier path = mock(YangInstanceIdentifier.class);
-        final Optional node = mock(Optional.class);
-        doReturn(node).when(modification).readNode(path);
+        when(serializer.fromYangInstanceIdentifier(any(YangInstanceIdentifier.class))).thenReturn(((InstanceIdentifier) DEFAULT_ID));
+        final Map.Entry<InstanceIdentifier<?>, DataObject> parsed = new AbstractMap.SimpleEntry<>(DEFAULT_ID, DEFAULT_DATA_OBJECT);
+        when(serializer.fromNormalizedNode(any(YangInstanceIdentifier.class), any(NormalizedNode.class))).thenReturn(parsed);
 
-        final DataModification dataTreeSnapshot = configDataTree.newModification();
-        final CheckedFuture<Optional<NormalizedNode<?, ?>>, ReadFailedException> future =
-                dataTreeSnapshot.read(path);
-
-        verify(dataTree, times(2)).takeSnapshot();
-        verify(modification).readNode(path);
-
-        assertTrue(future.isDone());
-        assertEquals(node, future.get());
+        configDataTree = new ModifiableDataTreeDelegator(serializer, dataTree, writer, contextBroker);
     }
 
     @Test
-    public void testNewModification() throws Exception {
-        final org.opendaylight.yangtools.yang.data.api.schema.tree.DataTreeSnapshot
-                snapshot = mock(org.opendaylight.yangtools.yang.data.api.schema.tree.DataTreeSnapshot.class);
-        when(dataTree.takeSnapshot()).thenReturn(snapshot);
-        when(snapshot.newModification()).thenReturn(modification);
-
-        configDataTree.newModification();
-        // Snapshot captured twice, so that original data could be provided to translation layer without any possible
-        // modification
-        verify(dataTree, times(2)).takeSnapshot();
-        verify(snapshot, times(2)).newModification();
+    public void testRead() throws Exception {
+        final ContainerNode topContainer = ModificationDiffTest.getTopContainer("topContainer");
+        ModificationDiffTest.addNodeToTree(dataTree, topContainer, ModificationDiffTest.TOP_CONTAINER_ID);
+        final CheckedFuture<Optional<NormalizedNode<?, ?>>, ReadFailedException> read =
+                configDataTree.read(ModificationDiffTest.TOP_CONTAINER_ID);
+        final CheckedFuture<Optional<NormalizedNode<?, ?>>, ReadFailedException> read2 =
+                configDataTree.newModification().read(ModificationDiffTest.TOP_CONTAINER_ID);
+        final Optional<NormalizedNode<?, ?>> normalizedNodeOptional = read.get();
+        final Optional<NormalizedNode<?, ?>> normalizedNodeOptional2 = read2.get();
+
+        assertEquals(normalizedNodeOptional, normalizedNodeOptional2);
+        assertTrue(normalizedNodeOptional.isPresent());
+        assertEquals(topContainer, normalizedNodeOptional.get());
+        assertEquals(dataTree.takeSnapshot().readNode(ModificationDiffTest.TOP_CONTAINER_ID), normalizedNodeOptional);
     }
 
     @Test
     public void testCommitSuccessful() throws Exception {
-        final org.opendaylight.yangtools.yang.data.api.schema.tree.DataTreeSnapshot
-            snapshot = mock(org.opendaylight.yangtools.yang.data.api.schema.tree.DataTreeSnapshot.class);
-        when(dataTree.takeSnapshot()).thenReturn(snapshot);
-        when(snapshot.newModification()).thenReturn(modification);
-        final DataTreeCandidate prepare = mock(DataTreeCandidate.class);
-        doReturn(prepare).when(dataTree).prepare(modification);
-
-        final org.opendaylight.controller.md.sal.binding.api.ReadWriteTransaction ctxTransaction = mock(
-            org.opendaylight.controller.md.sal.binding.api.ReadWriteTransaction.class);
-        doReturn(ctxTransaction).when(contextBroker).newReadWriteTransaction();
-        doReturn(Futures.immediateCheckedFuture(null)).when(ctxTransaction).submit();
-
-        final DataObject dataBefore = mockDataObject("before", Ethernet.class);
-        final DataObject dataAfter = mockDataObject("after", Ethernet.class);
-
-        // Prepare modification:
-        final DataTreeCandidateNode rootNode = mockRootNode();
-        doReturn(ModificationType.SUBTREE_MODIFIED).when(rootNode).getModificationType();
-        doReturn(mock(YangInstanceIdentifier.PathArgument.class)).when(rootNode).getIdentifier();
-        final DataTreeCandidateNode childNode = mock(DataTreeCandidateNode.class);
-        doReturn(mock(YangInstanceIdentifier.PathArgument.class)).when(childNode).getIdentifier();
-        doReturn(Collections.singleton(childNode)).when(rootNode).getChildNodes();
-        doReturn(ModificationType.WRITE).when(childNode).getModificationType();
-
-        // data before:
-        final ContainerNode nodeBefore = mockContainerNode(dataBefore);
-        when(childNode.getDataBefore()).thenReturn(Optional.fromNullable(nodeBefore));
-        // data after:
-        final ContainerNode nodeAfter = mockContainerNode(dataAfter);
-        when(childNode.getDataAfter()).thenReturn(Optional.fromNullable(nodeAfter));
-
-        // Run the test
-        doReturn(rootNode).when(prepare).getRootNode();
+        final MapNode nestedList = ModificationDiffTest.getNestedList("listEntry", "listValue");
+
         final DataModification dataModification = configDataTree.newModification();
+        dataModification.write(ModificationDiffTest.NESTED_LIST_ID, nestedList);
+        dataModification.validate();
         dataModification.commit();
 
-        // Verify all changes were processed:
-        verify(writer).update(
-                mapOf(dataBefore, Ethernet.class),
-                mapOf(dataAfter, Ethernet.class),
-                any(WriteContext.class));
-
-        // Verify modification was validated
-        verify(dataTree).validate(modification);
-        // Verify context transaction was finished
-        verify(ctxTransaction).submit();
-    }
-
-    private Map<InstanceIdentifier<?>, DataObject> mapOf(final DataObject dataBefore, final Class<Ethernet> type) {
-        return eq(Collections.singletonMap(InstanceIdentifier.create(type),dataBefore));
+        final Multimap<InstanceIdentifier<?>, DataObjectUpdate> map = HashMultimap.create();
+        map.put(DEFAULT_ID, DataObjectUpdate.create(DEFAULT_ID, DEFAULT_DATA_OBJECT, DEFAULT_DATA_OBJECT));
+        verify(writer).update(eq(new WriterRegistry.DataObjectUpdates(map, ImmutableMultimap.of())), any(WriteContext.class));
+        assertEquals(nestedList, dataTree.takeSnapshot().readNode(ModificationDiffTest.NESTED_LIST_ID).get());
     }
 
-    private DataObject mockDataObject(final String name, final Class<? extends DataObject> classToMock) {
+    private static DataObject mockDataObject(final String name, final Class<? extends DataObject> classToMock) {
         final DataObject dataBefore = mock(classToMock, name);
         doReturn(classToMock).when(dataBefore).getImplementedInterface();
         return dataBefore;
@@ -178,171 +135,135 @@ public class ModifiableDataTreeDelegatorTest {
 
     @Test
     public void testCommitUndoSuccessful() throws Exception {
-        final org.opendaylight.yangtools.yang.data.api.schema.tree.DataTreeSnapshot
-            snapshot = mock(org.opendaylight.yangtools.yang.data.api.schema.tree.DataTreeSnapshot.class);
-        when(dataTree.takeSnapshot()).thenReturn(snapshot);
-        when(snapshot.newModification()).thenReturn(modification);
-        final DataTreeCandidate prepare = mock(DataTreeCandidate.class);
-        doReturn(prepare).when(dataTree).prepare(modification);
-
-        // Prepare data changes:
-        final DataObject dataBefore = mockDataObject("before", Ethernet.class);
-        final DataObject dataAfter = mockDataObject("after", Ethernet.class);
-
-        final io.fd.honeycomb.v3po.translate.write.WriterRegistry.Reverter reverter = mock(
-            io.fd.honeycomb.v3po.translate.write.WriterRegistry.Reverter.class);
+        final MapNode nestedList = ModificationDiffTest.getNestedList("listEntry", "listValue");
 
         // Fail on update:
+        final WriterRegistry.Reverter reverter = mock(WriterRegistry.Reverter.class);
         final TranslationException failedOnUpdateException = new TranslationException("update failed");
-        doThrow(new io.fd.honeycomb.v3po.translate.write.WriterRegistry.BulkUpdateException(InstanceIdentifier.create(Ethernet.class), reverter,
-                failedOnUpdateException)).when(writer).update(anyMap(), anyMap(), any(WriteContext.class));
-
-        // Prepare modification:
-        final DataTreeCandidateNode rootNode = mockRootNode();
-        doReturn(ModificationType.SUBTREE_MODIFIED).when(rootNode).getModificationType();
-        doReturn(mock(YangInstanceIdentifier.PathArgument.class)).when(rootNode).getIdentifier();
-        final DataTreeCandidateNode childNode = mock(DataTreeCandidateNode.class);
-        doReturn(mock(YangInstanceIdentifier.PathArgument.class)).when(childNode).getIdentifier();
-        doReturn(Collections.singleton(childNode)).when(rootNode).getChildNodes();
-        doReturn(ModificationType.WRITE).when(childNode).getModificationType();
-
-        // data before:
-        final ContainerNode nodeBefore = mockContainerNode(dataBefore);
-        when(childNode.getDataBefore()).thenReturn(Optional.fromNullable(nodeBefore));
-        // data after:
-        final ContainerNode nodeAfter = mockContainerNode(dataAfter);
-        when(childNode.getDataAfter()).thenReturn(Optional.fromNullable(nodeAfter));
-
-        // Run the test
+        doThrow(new WriterRegistry.BulkUpdateException(Collections.singleton(DEFAULT_ID), reverter, failedOnUpdateException))
+                .when(writer).update(any(WriterRegistry.DataObjectUpdates.class), any(WriteContext.class));
+
         try {
-            doReturn(rootNode).when(prepare).getRootNode();
+            // Run the test
             final DataModification dataModification = configDataTree.newModification();
+            dataModification.write(ModificationDiffTest.NESTED_LIST_ID, nestedList);
+            dataModification.validate();
             dataModification.commit();
-        } catch (io.fd.honeycomb.v3po.translate.write.WriterRegistry.BulkUpdateException e) {
-            verify(writer).update(anyMap(), anyMap(), any(WriteContext.class));
+            fail("WriterRegistry.BulkUpdateException was expected");
+        } catch (WriterRegistry.BulkUpdateException e) {
+            verify(writer).update(any(WriterRegistry.DataObjectUpdates.class), any(WriteContext.class));
+            assertThat(e.getFailedIds(), hasItem(DEFAULT_ID));
             verify(reverter).revert();
             assertEquals(failedOnUpdateException, e.getCause());
-            return;
         }
-
-        fail("WriterRegistry.BulkUpdateException was expected");
     }
 
     @Test
     public void testCommitUndoFailed() throws Exception {
-        final org.opendaylight.yangtools.yang.data.api.schema.tree.DataTreeSnapshot
-            snapshot = mock(org.opendaylight.yangtools.yang.data.api.schema.tree.DataTreeSnapshot.class);
-        when(dataTree.takeSnapshot()).thenReturn(snapshot);
-        when(snapshot.newModification()).thenReturn(modification);
-        final DataTreeCandidate prepare = mock(DataTreeCandidate.class);
-        doReturn(prepare).when(dataTree).prepare(modification);
-
-        // Prepare data changes:
-        final DataObject dataBefore = mockDataObject("before", Ethernet.class);
-        final DataObject dataAfter = mockDataObject("after", Ethernet.class);
-
-        final io.fd.honeycomb.v3po.translate.write.WriterRegistry.Reverter reverter = mock(
-            io.fd.honeycomb.v3po.translate.write.WriterRegistry.Reverter.class);
+        final MapNode nestedList = ModificationDiffTest.getNestedList("listEntry", "listValue");
 
         // Fail on update:
-        doThrow(new io.fd.honeycomb.v3po.translate.write.WriterRegistry.BulkUpdateException(InstanceIdentifier.create(Ethernet.class), reverter,
-                new TranslationException("update failed"))).when(writer).update(anyMap(), anyMap(), any(WriteContext.class));
+        final WriterRegistry.Reverter reverter = mock(WriterRegistry.Reverter.class);
+        final TranslationException failedOnUpdateException = new TranslationException("update failed");
+        doThrow(new WriterRegistry.BulkUpdateException(Collections.singleton(DEFAULT_ID), reverter, failedOnUpdateException))
+                .when(writer).update(any(WriterRegistry.DataObjectUpdates.class), any(WriteContext.class));
 
         // Fail on revert:
-        final TranslationException failedOnRevertException = new TranslationException("update failed");
-        final io.fd.honeycomb.v3po.translate.write.WriterRegistry.Reverter.RevertFailedException revertFailedException =
-                new io.fd.honeycomb.v3po.translate.write.WriterRegistry.Reverter.RevertFailedException(Collections.<InstanceIdentifier<?>>emptyList(),
-                        failedOnRevertException);
-        doThrow(revertFailedException).when(reverter).revert();
-
-        // Prepare modification:
-        final DataTreeCandidateNode rootNode = mockRootNode();
-        doReturn(ModificationType.SUBTREE_MODIFIED).when(rootNode).getModificationType();
-        doReturn(mock(YangInstanceIdentifier.PathArgument.class)).when(rootNode).getIdentifier();
-        final DataTreeCandidateNode childNode = mock(DataTreeCandidateNode.class);
-        doReturn(mock(YangInstanceIdentifier.PathArgument.class)).when(childNode).getIdentifier();
-        doReturn(Collections.singleton(childNode)).when(rootNode).getChildNodes();
-        doReturn(ModificationType.WRITE).when(childNode).getModificationType();
-
-        // data before:
-        final ContainerNode nodeBefore = mockContainerNode(dataBefore);
-        when(childNode.getDataBefore()).thenReturn(Optional.fromNullable(nodeBefore));
-        // data after:
-        final ContainerNode nodeAfter = mockContainerNode(dataAfter);
-        when(childNode.getDataAfter()).thenReturn(Optional.fromNullable(nodeAfter));
-
-        // Run the test
+        final TranslationException failedOnRevertException = new TranslationException("revert failed");
+        doThrow(new WriterRegistry.Reverter.RevertFailedException(Collections.emptySet(), failedOnRevertException))
+                .when(reverter).revert();
+
         try {
-            doReturn(rootNode).when(prepare).getRootNode();
+            // Run the test
             final DataModification dataModification = configDataTree.newModification();
+            dataModification.write(ModificationDiffTest.NESTED_LIST_ID, nestedList);
+            dataModification.validate();
             dataModification.commit();
-        } catch (io.fd.honeycomb.v3po.translate.write.WriterRegistry.Reverter.RevertFailedException e) {
-            verify(writer).update(anyMap(), anyMap(), any(WriteContext.class));
+            fail("WriterRegistry.Reverter.RevertFailedException was expected");
+        } catch (WriterRegistry.Reverter.RevertFailedException e) {
+            verify(writer).update(any(WriterRegistry.DataObjectUpdates.class), any(WriteContext.class));
             verify(reverter).revert();
             assertEquals(failedOnRevertException, e.getCause());
-            return;
         }
-
-        fail("RevertFailedException was expected");
     }
 
+    private abstract static class DataObject1 implements DataObject {}
+    private abstract static class DataObject2 implements DataObject {}
+    private abstract static class DataObject3 implements DataObject {}
+
     @Test
-    public void testChildrenFromNormalized() throws Exception {
-        final BindingNormalizedNodeSerializer serializer = mock(BindingNormalizedNodeSerializer.class);
-
-        final Map<YangInstanceIdentifier, NormalizedNode<?, ?>> map = new HashMap<>();
-
-        // init child1 (will not be serialized)
-        final DataContainerChild child1 = mock(DataContainerChild.class);
-        when(child1.getIdentifier()).thenReturn(mock(YangInstanceIdentifier.PathArgument.class));
-        when(serializer.fromNormalizedNode(any(YangInstanceIdentifier.class), eq(child1))).thenReturn(null);
-        map.put(mock(YangInstanceIdentifier.class), child1);
-
-        // init child 2 (will be serialized)
-        final DataContainerChild child2 = mock(DataContainerChild.class);
-        when(child2.getIdentifier()).thenReturn(mock(YangInstanceIdentifier.PathArgument.class));
-
-        final Map.Entry entry = mock(Map.Entry.class);
-        final InstanceIdentifier<?> id = mock(InstanceIdentifier.class);
-        doReturn(id).when(entry).getKey();
-        final DataObject data = mock(DataObject.class);
-        doReturn(data).when(entry).getValue();
-        when(serializer.fromNormalizedNode(any(YangInstanceIdentifier.class), eq(child2))).thenReturn(entry);
-        map.put(mock(YangInstanceIdentifier.class), child2);
-
-        // run tested method
-        final Map<InstanceIdentifier<?>, DataObject> baMap =
-                ModifiableDataTreeDelegator.toBindingAware(map, serializer);
-        assertEquals(1, baMap.size());
-        assertEquals(data, baMap.get(id));
+    public void testToBindingAware() throws Exception {
+        when(serializer.fromNormalizedNode(any(YangInstanceIdentifier.class), eq(null))).thenReturn(null);
+
+        final Map<YangInstanceIdentifier, ModificationDiff.NormalizedNodeUpdate> biNodes = new HashMap<>();
+        // delete
+        final QName nn1 = QName.create("namespace", "nn1");
+        final YangInstanceIdentifier yid1 = mockYid(nn1);
+        final InstanceIdentifier iid1 = mockIid(yid1, DataObject1.class);
+        final NormalizedNode nn1B = mockNormalizedNode(nn1);
+        final DataObject1 do1B = mockDataObject(yid1, iid1, nn1B, DataObject1.class);
+        biNodes.put(yid1, ModificationDiff.NormalizedNodeUpdate.create(yid1, nn1B, null));
+
+        // create
+        final QName nn2 = QName.create("namespace", "nn1");
+        final YangInstanceIdentifier yid2 = mockYid(nn2);
+        final InstanceIdentifier iid2 = mockIid(yid2, DataObject2.class);;
+        final NormalizedNode nn2A = mockNormalizedNode(nn2);
+        final DataObject2 do2A = mockDataObject(yid2, iid2, nn2A, DataObject2.class);
+        biNodes.put(yid2, ModificationDiff.NormalizedNodeUpdate.create(yid2, null, nn2A));
+
+        // update
+        final QName nn3 = QName.create("namespace", "nn1");
+        final YangInstanceIdentifier yid3 = mockYid(nn3);
+        final InstanceIdentifier iid3 = mockIid(yid3, DataObject3.class);
+        final NormalizedNode nn3B = mockNormalizedNode(nn3);
+        final DataObject3 do3B = mockDataObject(yid3, iid3, nn3B, DataObject3.class);
+        final NormalizedNode nn3A = mockNormalizedNode(nn3);
+        final DataObject3 do3A = mockDataObject(yid3, iid3, nn3A, DataObject3.class);;
+        biNodes.put(yid3, ModificationDiff.NormalizedNodeUpdate.create(yid3, nn3B, nn3A));
+
+        final WriterRegistry.DataObjectUpdates dataObjectUpdates =
+                ModifiableDataTreeDelegator.toBindingAware(biNodes, serializer);
+
+        assertThat(dataObjectUpdates.getDeletes().size(), is(1));
+        assertThat(dataObjectUpdates.getDeletes().keySet(), hasItem(((InstanceIdentifier<?>) iid1)));
+        assertThat(dataObjectUpdates.getDeletes().values(), hasItem(
+                ((DataObjectUpdate.DataObjectDelete) DataObjectUpdate.create(iid1, do1B, null))));
+
+        assertThat(dataObjectUpdates.getUpdates().size(), is(2));
+        assertThat(dataObjectUpdates.getUpdates().keySet(), hasItems((InstanceIdentifier<?>) iid2, (InstanceIdentifier<?>) iid3));
+        assertThat(dataObjectUpdates.getUpdates().values(), hasItems(
+                DataObjectUpdate.create(iid2, null, do2A),
+                DataObjectUpdate.create(iid3, do3B, do3A)));
+
+        assertThat(dataObjectUpdates.getTypeIntersection().size(), is(3));
     }
 
-    private DataTreeCandidateNode mockRootNode() {
-        final DataTreeCandidate candidate = mock(DataTreeCandidate.class);
-        when(dataTree.prepare(modification)).thenReturn(candidate);
-
-        final DataTreeCandidateNode rootNode = mock(DataTreeCandidateNode.class);
-        when(candidate.getRootNode()).thenReturn(rootNode);
-
-        return rootNode;
+    private <D extends DataObject> D mockDataObject(final YangInstanceIdentifier yid1,
+                                       final InstanceIdentifier iid1,
+                                       final NormalizedNode nn1B,
+                                       final Class<D> type) {
+        final D do1B = mock(type);
+        when(serializer.fromNormalizedNode(yid1, nn1B)).thenReturn(new AbstractMap.SimpleEntry<>(iid1, do1B));
+        return do1B;
     }
 
-    private ContainerNode mockContainerNode(DataObject modification) {
-        final YangInstanceIdentifier.NodeIdentifier identifier =
-                YangInstanceIdentifier.NodeIdentifier.create(QName.create("/"));
-
-        final ContainerNode node = mock(ContainerNode.class);
-        when(node.getIdentifier()).thenReturn(identifier);
-
-        final Map.Entry entry = mock(Map.Entry.class);
-        final Class<? extends DataObject> implementedInterface =
-                (Class<? extends DataObject>) modification.getImplementedInterface();
-        final InstanceIdentifier<?> id = InstanceIdentifier.create(implementedInterface);
+    private NormalizedNode mockNormalizedNode(final QName nn1) {
+        final NormalizedNode nn1B = mock(NormalizedNode.class);
+        when(nn1B.getNodeType()).thenReturn(nn1);
+        return nn1B;
+    }
 
-        doReturn(id).when(entry).getKey();
-        doReturn(modification).when(entry).getValue();
-        doReturn(entry).when(serializer).fromNormalizedNode(any(YangInstanceIdentifier.class), eq(node));
+    private InstanceIdentifier mockIid(final YangInstanceIdentifier yid1,
+                                       final Class<? extends DataObject> type) {
+        final InstanceIdentifier iid1 = InstanceIdentifier.create(type);
+        when(serializer.fromYangInstanceIdentifier(yid1)).thenReturn(iid1);
+        return iid1;
+    }
 
-        return node;
+    private YangInstanceIdentifier mockYid(final QName nn1) {
+        final YangInstanceIdentifier yid1 = mock(YangInstanceIdentifier.class);
+        when(yid1.getLastPathArgument()).thenReturn(new YangInstanceIdentifier.NodeIdentifier(nn1));
+        return yid1;
     }
 }
diff --git a/v3po/data-impl/src/test/java/io/fd/honeycomb/v3po/data/impl/ModificationDiffTest.java b/v3po/data-impl/src/test/java/io/fd/honeycomb/v3po/data/impl/ModificationDiffTest.java
index 3475973d6..bc7582e93 100644
--- a/v3po/data-impl/src/test/java/io/fd/honeycomb/v3po/data/impl/ModificationDiffTest.java
+++ b/v3po/data-impl/src/test/java/io/fd/honeycomb/v3po/data/impl/ModificationDiffTest.java
@@ -1,7 +1,8 @@
 package io.fd.honeycomb.v3po.data.impl;
 
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertTrue;
+import static org.hamcrest.CoreMatchers.hasItems;
+import static org.hamcrest.CoreMatchers.is;
+import static org.junit.Assert.assertThat;
 
 import java.util.Map;
 import org.junit.Test;
@@ -11,6 +12,8 @@ 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.MapNode;
 import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
+import org.opendaylight.yangtools.yang.data.api.schema.tree.DataTree;
+import org.opendaylight.yangtools.yang.data.api.schema.tree.DataTreeCandidate;
 import org.opendaylight.yangtools.yang.data.api.schema.tree.DataTreeCandidateTip;
 import org.opendaylight.yangtools.yang.data.api.schema.tree.DataTreeModification;
 import org.opendaylight.yangtools.yang.data.api.schema.tree.DataTreeSnapshot;
@@ -28,15 +31,23 @@ import org.opendaylight.yangtools.yang.parser.stmt.rfc6020.YangStatementSourceIm
 
 public class ModificationDiffTest {
 
-    private static final QName TOP_CONTAINER_QNAME =
+    static final QName TOP_CONTAINER_QNAME =
             QName.create("urn:opendaylight:params:xml:ns:yang:test:diff", "2015-01-05", "top-container");
-    private static final QName STRING_LEAF_QNAME = QName.create(TOP_CONTAINER_QNAME, "string");
-    private static final QName NAME_LEAF_QNAME = QName.create(TOP_CONTAINER_QNAME, "name");
-    private static final QName TEXT_LEAF_QNAME = QName.create(TOP_CONTAINER_QNAME, "text");
-    private static final QName NESTED_LIST_QNAME = QName.create(TOP_CONTAINER_QNAME, "nested-list");
-    private static final QName DEEP_LIST_QNAME = QName.create(TOP_CONTAINER_QNAME, "deep-list");
+    static final QName STRING_LEAF_QNAME = QName.create(TOP_CONTAINER_QNAME, "string");
+    static final QName NAME_LEAF_QNAME = QName.create(TOP_CONTAINER_QNAME, "name");
+    static final QName TEXT_LEAF_QNAME = QName.create(TOP_CONTAINER_QNAME, "text");
+    static final QName NESTED_LIST_QNAME = QName.create(TOP_CONTAINER_QNAME, "nested-list");
+    static final QName DEEP_LIST_QNAME = QName.create(TOP_CONTAINER_QNAME, "deep-list");
+
+    static final QName WITH_CHOICE_CONTAINER_QNAME =
+            QName.create("urn:opendaylight:params:xml:ns:yang:test:diff", "2015-01-05", "with-choice");
+    static final QName CHOICE_QNAME = QName.create(WITH_CHOICE_CONTAINER_QNAME, "choice");
+    static final QName IN_CASE1_LEAF_QNAME = QName.create(WITH_CHOICE_CONTAINER_QNAME, "in-case1");
+    static final QName IN_CASE2_LEAF_QNAME = QName.create(WITH_CHOICE_CONTAINER_QNAME, "in-case2");
+
+    static final YangInstanceIdentifier TOP_CONTAINER_ID = YangInstanceIdentifier.of(TOP_CONTAINER_QNAME);
+    static final YangInstanceIdentifier NESTED_LIST_ID = TOP_CONTAINER_ID.node(new YangInstanceIdentifier.NodeIdentifier(NESTED_LIST_QNAME));
 
-    private static final YangInstanceIdentifier TOP_CONTAINER_ID = YangInstanceIdentifier.of(TOP_CONTAINER_QNAME);
 
     @Test
     public void testInitialWrite() throws Exception {
@@ -47,10 +58,33 @@ public class ModificationDiffTest {
         dataTreeModification.write(TOP_CONTAINER_ID, topContainer);
         final DataTreeCandidateTip prepare = prepareModification(dataTree, dataTreeModification);
 
-        final ModifiableDataTreeDelegator.ModificationDiff modificationDiff = getModificationDiff(prepare);
+        final ModificationDiff modificationDiff = getModificationDiff(prepare);
 
-        assertTrue(modificationDiff.getModificationsBefore().isEmpty());
-        assertAfter(topContainer, TOP_CONTAINER_ID, modificationDiff);
+        assertThat(modificationDiff.getUpdates().size(), is(1));
+        assertThat(modificationDiff.getUpdates().values().size(), is(1));
+        assertUpdate(modificationDiff.getUpdates().values().iterator().next(), TOP_CONTAINER_ID, null, topContainer);
+    }
+
+    @Test
+    public void testInitialWriteForContainerWithChoice() throws Exception {
+        final TipProducingDataTree dataTree = getDataTree();
+        final DataTreeModification dataTreeModification = getModification(dataTree);
+        final ContainerNode containerWithChoice = Builders.containerBuilder()
+                .withNodeIdentifier(new YangInstanceIdentifier.NodeIdentifier(WITH_CHOICE_CONTAINER_QNAME))
+                .withChild(Builders.choiceBuilder()
+                        .withNodeIdentifier(new YangInstanceIdentifier.NodeIdentifier(CHOICE_QNAME))
+                        .withChild(ImmutableNodes.leafNode(IN_CASE1_LEAF_QNAME, "withinCase1"))
+                        .build())
+                .build();
+        final YangInstanceIdentifier WITH_CHOICE_CONTAINER_ID = YangInstanceIdentifier.of(WITH_CHOICE_CONTAINER_QNAME);
+        dataTreeModification.write(WITH_CHOICE_CONTAINER_ID, containerWithChoice);
+        final DataTreeCandidateTip prepare = prepareModification(dataTree, dataTreeModification);
+
+        final Map<YangInstanceIdentifier, ModificationDiff.NormalizedNodeUpdate> updates = getModificationDiff(prepare).getUpdates();
+
+        assertThat(updates.size(), is(1));
+        assertUpdate(getNormalizedNodeUpdateForAfterType(updates, ContainerNode.class),
+                WITH_CHOICE_CONTAINER_ID, null, containerWithChoice);
     }
 
     private DataTreeModification getModification(final TipProducingDataTree dataTree) {
@@ -66,10 +100,9 @@ public class ModificationDiffTest {
         dataTreeModification.write(TOP_CONTAINER_ID, topContainer);
         final DataTreeCandidateTip prepare = prepareModification(dataTree, dataTreeModification);
 
-        final ModifiableDataTreeDelegator.ModificationDiff modificationDiff = getModificationDiff(prepare);
+        final ModificationDiff modificationDiff = getModificationDiff(prepare);
 
-        assertTrue(modificationDiff.getModificationsBefore().isEmpty());
-        assertTrue(modificationDiff.getModificationsAfter().isEmpty());
+        assertThat(modificationDiff.getUpdates().size(), is(0));
     }
 
     private DataTreeCandidateTip prepareModification(final TipProducingDataTree dataTree,
@@ -83,60 +116,61 @@ public class ModificationDiffTest {
     @Test
     public void testUpdateWrite() throws Exception {
         final TipProducingDataTree dataTree = getDataTree();
-        final NormalizedNode<?, ?> topContainerBefore = addTopContainer(dataTree);
+        final ContainerNode topContainer = getTopContainer("string1");
+        addNodeToTree(dataTree, topContainer, TOP_CONTAINER_ID);
 
         final DataTreeModification dataTreeModification = getModification(dataTree);
         final NormalizedNode<?, ?> topContainerAfter = getTopContainer("string2");
         dataTreeModification.write(TOP_CONTAINER_ID, topContainerAfter);
         final DataTreeCandidateTip prepare = prepareModification(dataTree, dataTreeModification);
 
-        final ModifiableDataTreeDelegator.ModificationDiff modificationDiff = getModificationDiff(prepare);
+        final Map<YangInstanceIdentifier, ModificationDiff.NormalizedNodeUpdate> updates = getModificationDiff(prepare).getUpdates();
 
-        assertBefore(topContainerBefore, TOP_CONTAINER_ID, modificationDiff);
-        assertAfter(topContainerAfter, TOP_CONTAINER_ID, modificationDiff);
+        assertThat(updates.size(), is(1));
+        assertThat(updates.values().size(), is(1));
+        assertUpdate(updates.values().iterator().next(), TOP_CONTAINER_ID, topContainer, topContainerAfter);
     }
 
-    private ModifiableDataTreeDelegator.ModificationDiff getModificationDiff(final DataTreeCandidateTip prepare) {
-        return ModifiableDataTreeDelegator.ModificationDiff
-                .recursivelyFromCandidate(YangInstanceIdentifier.EMPTY, prepare.getRootNode());
+    private ModificationDiff getModificationDiff(final DataTreeCandidateTip prepare) {
+        return ModificationDiff.recursivelyFromCandidate(YangInstanceIdentifier.EMPTY, prepare.getRootNode());
     }
 
     @Test
     public void testUpdateMerge() throws Exception {
         final TipProducingDataTree dataTree = getDataTree();
-        final NormalizedNode<?, ?> topContainerBefore = addTopContainer(dataTree);
+        final ContainerNode topContainer = getTopContainer("string1");
+        addNodeToTree(dataTree, topContainer, TOP_CONTAINER_ID);
 
         final DataTreeModification dataTreeModification = getModification(dataTree);
         final NormalizedNode<?, ?> topContainerAfter = getTopContainer("string2");
         dataTreeModification.merge(TOP_CONTAINER_ID, topContainerAfter);
         final DataTreeCandidateTip prepare = prepareModification(dataTree, dataTreeModification);
 
-        final ModifiableDataTreeDelegator.ModificationDiff modificationDiff =
-                getModificationDiff(prepare);
-
-        assertBefore(topContainerBefore, TOP_CONTAINER_ID, modificationDiff);
-        assertAfter(topContainerAfter, TOP_CONTAINER_ID, modificationDiff);
+        final Map<YangInstanceIdentifier, ModificationDiff.NormalizedNodeUpdate> updates = getModificationDiff(prepare).getUpdates();
+        assertThat(updates.size(), is(1));
+        assertThat(updates.values().size(), is(1));
+        assertUpdate(updates.values().iterator().next(), TOP_CONTAINER_ID, topContainer, topContainerAfter);
     }
 
     @Test
     public void testUpdateDelete() throws Exception {
         final TipProducingDataTree dataTree = getDataTree();
-        final NormalizedNode<?, ?> topContainerBefore = addTopContainer(dataTree);
+        final ContainerNode topContainer = getTopContainer("string1");
+        addNodeToTree(dataTree, topContainer, TOP_CONTAINER_ID);
 
         final DataTreeModification dataTreeModification = getModification(dataTree);
         dataTreeModification.delete(TOP_CONTAINER_ID);
         final DataTreeCandidateTip prepare = prepareModification(dataTree, dataTreeModification);
 
-        final ModifiableDataTreeDelegator.ModificationDiff modificationDiff = getModificationDiff(prepare);
-
-        assertBefore(topContainerBefore, TOP_CONTAINER_ID, modificationDiff);
-        assertTrue(modificationDiff.getModificationsAfter().isEmpty());
+        final Map<YangInstanceIdentifier, ModificationDiff.NormalizedNodeUpdate> updates = getModificationDiff(prepare).getUpdates();
+        assertThat(updates.size(), is(1));
+        assertThat(updates.values().size(), is(1));
+        assertUpdate(updates.values().iterator().next(), TOP_CONTAINER_ID, topContainer, null);
     }
 
     @Test
     public void testWriteAndUpdateInnerList() throws Exception {
         final TipProducingDataTree dataTree = getDataTree();
-        addTopContainer(dataTree);
 
         DataTreeSnapshot dataTreeSnapshot = dataTree.takeSnapshot();
         DataTreeModification dataTreeModification = dataTreeSnapshot.newModification();
@@ -146,15 +180,17 @@ public class ModificationDiffTest {
                         new YangInstanceIdentifier.NodeIdentifier(NESTED_LIST_QNAME));
 
         final MapNode mapNode = getNestedList("name1", "text");
+        final YangInstanceIdentifier listEntryId = listId.node(mapNode.getValue().iterator().next().getIdentifier());
         dataTreeModification.write(listId, mapNode);
         dataTreeModification.ready();
         dataTree.validate(dataTreeModification);
         DataTreeCandidateTip prepare = dataTree.prepare(dataTreeModification);
 
-        ModifiableDataTreeDelegator.ModificationDiff modificationDiff = getModificationDiff(prepare);
+        Map<YangInstanceIdentifier, ModificationDiff.NormalizedNodeUpdate> updates = getModificationDiff(prepare).getUpdates();
 
-        assertTrue(modificationDiff.getModificationsBefore().isEmpty());
-        assertAfter(mapNode, listId, modificationDiff);
+        assertThat(updates.size(), is(1));
+        assertUpdate(getNormalizedNodeUpdateForAfterType(updates, MapEntryNode.class),
+                listEntryId, null, mapNode.getValue().iterator().next());
 
         // Commit so that update can be tested next
         dataTree.commit(prepare);
@@ -171,9 +207,17 @@ public class ModificationDiffTest {
         dataTree.validate(dataTreeModification);
         prepare = dataTree.prepare(dataTreeModification);
 
-        modificationDiff = getModificationDiff(prepare);
-        assertBefore(mapNode.getValue().iterator().next(), listItemId, modificationDiff);
-        assertAfter(mapEntryNode, listItemId, modificationDiff);
+        updates = getModificationDiff(prepare).getUpdates();
+        assertThat(updates.size(), is(1 /*Actual list entry*/));
+    }
+//
+    private void assertUpdate(final ModificationDiff.NormalizedNodeUpdate update,
+                              final YangInstanceIdentifier idExpected,
+                              final NormalizedNode<?, ?> beforeExpected,
+                              final NormalizedNode<?, ?> afterExpected) {
+        assertThat(update.getId(), is(idExpected));
+        assertThat(update.getDataBefore(), is(beforeExpected));
+        assertThat(update.getDataAfter(), is(afterExpected));
     }
 
     @Test
@@ -192,25 +236,44 @@ public class ModificationDiffTest {
                         new YangInstanceIdentifier.NodeIdentifier(NESTED_LIST_QNAME));
 
         final MapNode mapNode = getNestedList("name1", "text");
+        final YangInstanceIdentifier listEntryId = listId.node(mapNode.getValue().iterator().next().getIdentifier());
+
         dataTreeModification.write(listId, mapNode);
 
         final DataTreeCandidateTip prepare = prepareModification(dataTree, dataTreeModification);
 
-        final ModifiableDataTreeDelegator.ModificationDiff modificationDiff = getModificationDiff(prepare);
+        final Map<YangInstanceIdentifier, ModificationDiff.NormalizedNodeUpdate> updates = getModificationDiff(prepare).getUpdates();
+
+        assertThat(updates.size(), is(2));
+        assertThat(updates.values().size(), is(2));
+        assertUpdate(getNormalizedNodeUpdateForAfterType(updates, ContainerNode.class), TOP_CONTAINER_ID, null,
+                Builders.containerBuilder(topContainer).withChild(mapNode).build());
+        assertUpdate(getNormalizedNodeUpdateForAfterType(updates, MapEntryNode.class), listEntryId, null, mapNode.getValue().iterator().next());
+        // Assert that keys of the updates map are not wildcarded YID
+        assertThat(updates.keySet(), hasItems(
+                TOP_CONTAINER_ID,
+                listEntryId));
+    }
 
-        assertTrue(modificationDiff.getModificationsBefore().isEmpty());
+    private ModificationDiff.NormalizedNodeUpdate getNormalizedNodeUpdateForAfterType(
+            final Map<YangInstanceIdentifier, ModificationDiff.NormalizedNodeUpdate> updates,
+            final Class<? extends NormalizedNode<?, ?>> containerNodeClass) {
+        return updates.values().stream()
+                    .filter(update -> containerNodeClass.isAssignableFrom(update.getDataAfter().getClass()))
+                    .findFirst().get();
+    }
 
-        // TODO HONEYCOMB-94 2 after modifications should appear, for top-container and nested-list entry
-        assertAfter(Builders.containerBuilder(topContainer)
-                        .withChild(mapNode)
-                        .build(),
-                TOP_CONTAINER_ID, modificationDiff);
+    private ModificationDiff.NormalizedNodeUpdate getNormalizedNodeUpdateForBeforeType(
+            final Map<YangInstanceIdentifier, ModificationDiff.NormalizedNodeUpdate> updates,
+            final Class<? extends NormalizedNode<?, ?>> containerNodeClass) {
+        return updates.values().stream()
+                    .filter(update -> containerNodeClass.isAssignableFrom(update.getDataBefore().getClass()))
+                    .findFirst().get();
     }
 
     @Test
     public void testWriteDeepList() throws Exception {
         final TipProducingDataTree dataTree = getDataTree();
-        addTopContainer(dataTree);
 
         DataTreeSnapshot dataTreeSnapshot = dataTree.takeSnapshot();
         DataTreeModification dataTreeModification = dataTreeSnapshot.newModification();
@@ -250,7 +313,8 @@ public class ModificationDiffTest {
                         .withChild(ImmutableNodes.leafNode(NAME_LEAF_QNAME, "name1")).build());
         dataTreeModification.merge(
                 deepListId,
-                Builders.mapBuilder().withNodeIdentifier(new YangInstanceIdentifier.NodeIdentifier(DEEP_LIST_QNAME))
+                Builders.mapBuilder()
+                        .withNodeIdentifier(new YangInstanceIdentifier.NodeIdentifier(DEEP_LIST_QNAME))
                         .build());
         dataTreeModification.merge(
                 deepListEntryId,
@@ -261,16 +325,14 @@ public class ModificationDiffTest {
         prepare = dataTree.prepare(dataTreeModification);
         dataTree.commit(prepare);
 
-        final ModifiableDataTreeDelegator.ModificationDiff modificationDiff = getModificationDiff(prepare);
-
-        assertTrue(modificationDiff.getModificationsBefore().isEmpty());
-        assertAfter(getDeepList("name1"), deepListId, modificationDiff);
+        final Map<YangInstanceIdentifier, ModificationDiff.NormalizedNodeUpdate> updates = getModificationDiff(prepare).getUpdates();
+        assertThat(updates.size(), is(1));
+        assertUpdate(getNormalizedNodeUpdateForAfterType(updates, MapEntryNode.class), deepListEntryId, null, deepListEntry);
     }
 
     @Test
     public void testDeleteInnerListItem() throws Exception {
         final TipProducingDataTree dataTree = getDataTree();
-        addTopContainer(dataTree);
 
         DataTreeSnapshot dataTreeSnapshot = dataTree.takeSnapshot();
         DataTreeModification dataTreeModification = dataTreeSnapshot.newModification();
@@ -298,58 +360,37 @@ public class ModificationDiffTest {
         dataTree.validate(dataTreeModification);
         prepare = dataTree.prepare(dataTreeModification);
 
-        final ModifiableDataTreeDelegator.ModificationDiff modificationDiff = getModificationDiff(prepare);
-
-        assertBefore(mapNode.getValue().iterator().next(), listItemId, modificationDiff);
-        assertTrue(modificationDiff.getModificationsAfter().isEmpty());
+        final Map<YangInstanceIdentifier, ModificationDiff.NormalizedNodeUpdate> updates = getModificationDiff(prepare).getUpdates();
+        assertThat(updates.size(), is(1));
+        assertUpdate(getNormalizedNodeUpdateForBeforeType(updates, MapEntryNode.class), listItemId, mapNode.getValue().iterator().next(), null);
     }
 
-    private NormalizedNode<?, ?> addTopContainer(final TipProducingDataTree dataTree)
+    static void addNodeToTree(final DataTree dataTree, final NormalizedNode<?, ?> node,
+                                              final YangInstanceIdentifier id)
             throws DataValidationFailedException {
         DataTreeSnapshot dataTreeSnapshot = dataTree.takeSnapshot();
         DataTreeModification dataTreeModification = dataTreeSnapshot.newModification();
-        final NormalizedNode<?, ?> topContainerBefore = getTopContainer("string1");
-        dataTreeModification.write(TOP_CONTAINER_ID, topContainerBefore);
+        dataTreeModification.write(id, node);
         dataTreeModification.ready();
         dataTree.validate(dataTreeModification);
-        DataTreeCandidateTip prepare = dataTree.prepare(dataTreeModification);
+        DataTreeCandidate prepare = dataTree.prepare(dataTreeModification);
         dataTree.commit(prepare);
-        return topContainerBefore;
-    }
-
-    private void assertAfter(final NormalizedNode<?, ?> topContainer, final YangInstanceIdentifier TOP_CONTAINER_ID,
-                             final ModifiableDataTreeDelegator.ModificationDiff modificationDiff) {
-        assertModification(topContainer, TOP_CONTAINER_ID, modificationDiff.getModificationsAfter());
-    }
-
-    private void assertModification(final NormalizedNode<?, ?> topContainer,
-                                    final YangInstanceIdentifier TOP_CONTAINER_ID,
-                                    final Map<YangInstanceIdentifier, NormalizedNode<?, ?>> modificationMap) {
-        assertEquals(1, modificationMap.keySet().size());
-        assertEquals(TOP_CONTAINER_ID, modificationMap.keySet().iterator().next());
-        assertEquals(topContainer, modificationMap.values().iterator().next());
-    }
-
-    private void assertBefore(final NormalizedNode<?, ?> topContainerBefore,
-                              final YangInstanceIdentifier TOP_CONTAINER_ID,
-                              final ModifiableDataTreeDelegator.ModificationDiff modificationDiff) {
-        assertModification(topContainerBefore, TOP_CONTAINER_ID, modificationDiff.getModificationsBefore());
     }
 
-    private TipProducingDataTree getDataTree() throws ReactorException {
+    static TipProducingDataTree getDataTree() throws ReactorException {
         final TipProducingDataTree dataTree = InMemoryDataTreeFactory.getInstance().create(TreeType.CONFIGURATION);
         dataTree.setSchemaContext(getSchemaCtx());
         return dataTree;
     }
 
-    private ContainerNode getTopContainer(final String stringValue) {
+    static ContainerNode getTopContainer(final String stringValue) {
         return Builders.containerBuilder()
                 .withNodeIdentifier(new YangInstanceIdentifier.NodeIdentifier(TOP_CONTAINER_QNAME))
                 .withChild(ImmutableNodes.leafNode(STRING_LEAF_QNAME, stringValue))
                 .build();
     }
 
-    private MapNode getNestedList(final String listItemName, final String text) {
+    static MapNode getNestedList(final String listItemName, final String text) {
         return Builders.mapBuilder()
                 .withNodeIdentifier(new YangInstanceIdentifier.NodeIdentifier(NESTED_LIST_QNAME))
                 .withChild(
@@ -378,9 +419,9 @@ public class ModificationDiffTest {
                 .build();
     }
 
-    private SchemaContext getSchemaCtx() throws ReactorException {
+    private static SchemaContext getSchemaCtx() throws ReactorException {
         final CrossSourceStatementReactor.BuildAction buildAction = YangInferencePipeline.RFC6020_REACTOR.newBuild();
-        buildAction.addSource(new YangStatementSourceImpl(getClass().getResourceAsStream("/test-diff.yang")));
+        buildAction.addSource(new YangStatementSourceImpl(ModificationDiffTest.class.getResourceAsStream("/test-diff.yang")));
         return buildAction.buildEffective();
     }
 }
\ No newline at end of file
-- 
cgit