private void ensureParentsByMerge(
      final LogicalDatastoreType store,
      final YangInstanceIdentifier normalizedPath,
      final DOMDataReadWriteTransaction rwTx,
      final SchemaContext schemaContext) {
    final List<PathArgument> normalizedPathWithoutChildArgs = new ArrayList<>();
    YangInstanceIdentifier rootNormalizedPath = null;

    final Iterator<PathArgument> it = normalizedPath.getPathArguments().iterator();

    while (it.hasNext()) {
      final PathArgument pathArgument = it.next();
      if (rootNormalizedPath == null) {
        rootNormalizedPath = YangInstanceIdentifier.create(pathArgument);
      }

      // Skip last element, its not a parent
      if (it.hasNext()) {
        normalizedPathWithoutChildArgs.add(pathArgument);
      }
    }

    // No parent structure involved, no need to ensure parents
    if (normalizedPathWithoutChildArgs.isEmpty()) {
      return;
    }

    Preconditions.checkArgument(rootNormalizedPath != null, "Empty path received");

    final NormalizedNode<?, ?> parentStructure =
        ImmutableNodes.fromInstanceId(
            schemaContext, YangInstanceIdentifier.create(normalizedPathWithoutChildArgs));
    rwTx.merge(store, rootNormalizedPath, parentStructure);
  }
  @Test
  public void basicTest() throws Exception {
    final Map<YangInstanceIdentifier, List<DOMRpcImplementation>> emptyImpls = new HashMap<>();
    final List<YangInstanceIdentifier> addList1 = new ArrayList<>();
    final List<YangInstanceIdentifier> addList2 = new ArrayList<>();
    final DOMRpcImplementation testClass = getTestRpcImplementation();
    final UnknownDOMRpcRoutingTableEntry test =
        new UnknownDOMRpcRoutingTableEntry(SchemaPath.ROOT, emptyImpls);

    TEST_LIST.add(testClass);
    emptyImpls.put(YangInstanceIdentifier.EMPTY, TEST_LIST);

    assertNotNull(test);
    assertNotNull(test.newInstance(emptyImpls));
    assertNotNull(test.invokeRpc(TEST_CONTAINER));
    assertNotNull(test.getImplementations());
    assertEquals(test.getImplementations(YangInstanceIdentifier.EMPTY), TEST_LIST);
    assertTrue(test.containsContext(YangInstanceIdentifier.EMPTY));
    assertTrue(test.registeredIdentifiers().contains(YangInstanceIdentifier.EMPTY));

    addList1.add(YangInstanceIdentifier.EMPTY);
    addList1.add(YangInstanceIdentifier.of(TestModel.TEST_QNAME));
    addList2.add(YangInstanceIdentifier.of(TestModel.TEST2_QNAME));

    final AbstractDOMRpcRoutingTableEntry tst = test.add(testClass, addList1);
    final AbstractDOMRpcRoutingTableEntry tst1 = tst.add(testClass, addList2);
    final AbstractDOMRpcRoutingTableEntry tst2 = tst1.remove(testClass, addList1);

    assertEquals(1, test.getImplementations().size());
    assertEquals(2, tst.getImplementations().size());
    assertEquals(3, tst1.getImplementations().size());
    assertNotNull(tst2.getImplementations());
    assertEquals(2, tst2.getImplementations().size());
  }
 private void postDataWithinTransaction(
     final DOMDataReadWriteTransaction rWTransaction,
     final LogicalDatastoreType datastore,
     final YangInstanceIdentifier path,
     final NormalizedNode<?, ?> payload,
     final SchemaContext schemaContext) {
   // FIXME: This is doing correct post for container and list children
   //        not sure if this will work for choice case
   if (payload instanceof MapNode) {
     LOG.trace(
         "POST {} within Restconf PATCH: {} with payload {}", datastore.name(), path, payload);
     final NormalizedNode<?, ?> emptySubtree = ImmutableNodes.fromInstanceId(schemaContext, path);
     rWTransaction.merge(
         datastore, YangInstanceIdentifier.create(emptySubtree.getIdentifier()), emptySubtree);
     ensureParentsByMerge(datastore, path, rWTransaction, schemaContext);
     for (final MapEntryNode child : ((MapNode) payload).getValue()) {
       final YangInstanceIdentifier childPath = path.node(child.getIdentifier());
       checkItemDoesNotExists(rWTransaction, datastore, childPath);
       rWTransaction.put(datastore, childPath, child);
     }
   } else {
     checkItemDoesNotExists(rWTransaction, datastore, path);
     ensureParentsByMerge(datastore, path, rWTransaction, schemaContext);
     rWTransaction.put(datastore, path, payload);
   }
 }
 private void verifyFilterIdentifier(String resource, YangInstanceIdentifier identifier)
     throws Exception {
   TestingGetConfig getConfig =
       new TestingGetConfig(sessionIdForReporting, currentSchemaContext, transactionProvider);
   Document request = XmlFileLoader.xmlFileToDocument(resource);
   YangInstanceIdentifier iid = getConfig.getInstanceIdentifierFromDocument(request);
   assertTrue(iid.equals(identifier));
 }
 private static YangInstanceIdentifier.InstanceIdentifierBuilder createTopologyIdentifier(
     String underlayTopologyId) {
   InstanceIdentifierBuilder identifier =
       YangInstanceIdentifier.builder(InstanceIdentifiers.TOPOLOGY_IDENTIFIER)
           .nodeWithKey(Topology.QNAME, TopologyQNames.TOPOLOGY_ID_QNAME, underlayTopologyId);
   return identifier;
 }
  /**
   * Test case: one SupportingNode translation<br>
   * - includes TopologyRef and NodeRef
   */
  @Test
  public void testSupportingNode() {
    String logicalName = "node:1";
    String physicalName = "node:11";

    UnderlayItem physicalNode1 =
        new UnderlayItem(
            mockNormalizedNode, null, TOPOLOGY_NAME, physicalName, CorrelationItemEnum.Node);
    OverlayItem logicalNode =
        new OverlayItem(Collections.singletonList(physicalNode1), CorrelationItemEnum.Node);
    OverlayItemWrapper wrapper = new OverlayItemWrapper(logicalName, logicalNode);
    NormalizedNode<?, ?> normalizedNode = translator.translate(wrapper);
    Map<QName, Object> keyValues = new HashMap<>();
    keyValues.put(TopologyQNames.TOPOLOGY_REF, TOPOLOGY_NAME);
    keyValues.put(TopologyQNames.NODE_REF, physicalName);

    // topologyRef
    YangInstanceIdentifier yiidTopoRef =
        YangInstanceIdentifier.builder()
            .node(SupportingNode.QNAME)
            .nodeWithKey(SupportingNode.QNAME, keyValues)
            .node(TopologyQNames.TOPOLOGY_REF)
            .build();
    Optional<NormalizedNode<?, ?>> topologyRef =
        NormalizedNodes.findNode(normalizedNode, yiidTopoRef);
    Assert.assertTrue("TopologyRef should be provided", topologyRef.isPresent());
    Assert.assertEquals(
        "TopologyRef from SupportingNodes should be the same as the PhysicalNode's Topology",
        TOPOLOGY_NAME,
        topologyRef.get().getValue());

    // nodeRef
    YangInstanceIdentifier yiidNodeRef =
        YangInstanceIdentifier.builder()
            .node(SupportingNode.QNAME)
            .nodeWithKey(SupportingNode.QNAME, keyValues)
            .node(TopologyQNames.NODE_REF)
            .build();
    Optional<NormalizedNode<?, ?>> nodeRef = NormalizedNodes.findNode(normalizedNode, yiidNodeRef);
    Assert.assertTrue("NodeRef should be provided", nodeRef.isPresent());
    Assert.assertEquals(
        "NodeRef from SupportingNodes should be the same as the PhysicalNode's Id",
        physicalName,
        nodeRef.get().getValue());
  }
  /**
   * This method stores the pushUpdate Notification data to MD-SAL
   *
   * @param sub_id
   * @param timeofeventupdate
   * @param domSource
   * @param data
   */
  private void storeToMdSal(
      String sub_id, String timeofeventupdate, DOMSource domSource, String data) {
    NodeIdentifier subscriptionid =
        NodeIdentifier.create(QName.create(PushUpdates.QNAME, "subscription-id"));
    NodeIdentifier timeofupdate =
        NodeIdentifier.create(QName.create(PushUpdates.QNAME, "time-of-update"));
    NodeIdentifier datanode = NodeIdentifier.create(QName.create(PushUpdates.QNAME, "data"));
    YangInstanceIdentifier pid =
        YangInstanceIdentifier.builder()
            .node(PushUpdates.QNAME)
            .node(
                org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.yangpush.rev150105
                    .push.updates.PushUpdate.QNAME)
            .build();

    NodeIdentifierWithPredicates p =
        new NodeIdentifierWithPredicates(
            QName.create(PushUpdates.QNAME, "push-update"),
            QName.create(PushUpdates.QNAME, "subscription-id"),
            sub_id);

    MapEntryNode men =
        ImmutableNodes.mapEntryBuilder()
            .withNodeIdentifier(p)
            .withChild(ImmutableNodes.leafNode(subscriptionid, sub_id))
            .withChild(ImmutableNodes.leafNode(timeofupdate, timeofeventupdate))
            .withChild(ImmutableNodes.leafNode(datanode, data))
            .build();

    DOMDataWriteTransaction tx = this.globalDomDataBroker.newWriteOnlyTransaction();
    YangInstanceIdentifier yid =
        pid.node(
            new NodeIdentifierWithPredicates(
                org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.yangpush.rev150105
                    .push.updates.PushUpdate.QNAME,
                men.getIdentifier().getKeyValues()));
    tx.merge(LogicalDatastoreType.CONFIGURATION, yid, men);
    LOG.info("--DATA PATh: {}\n--DATA\n{}", yid, men);
    try {
      tx.submit().checkedGet();
    } catch (TransactionCommitFailedException e) {
      e.printStackTrace();
    }
  }
  /**
   * This method creates a YANG II for the subscription-id used for this subscription to track. The
   * may be multiple subscription each will be identified by by the subscription-id.
   *
   * @param sub_id
   * @return
   */
  private YangInstanceIdentifier buildIID(String sub_id) {

    QName pushupdate =
        QName.create(YangpushRpcImpl.YANGPUSH_NS, YangpushRpcImpl.YANGPUSH_NS_DATE, "push-update");
    org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.InstanceIdentifierBuilder
        builder = org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.builder();
    builder
        .node(PushUpdates.QNAME)
        .node(pushupdate)
        .nodeWithKey(pushupdate, QName.create(pushupdate, "subscription-id"), sub_id);

    return builder.build();
  }
  /** Test case: NodeId translation */
  @Test
  public void testNodeId() {
    String logicalName = "node:1";
    UnderlayItem physicalNode =
        new UnderlayItem(
            mockNormalizedNode, null, TOPOLOGY_NAME, "node:1", CorrelationItemEnum.Node);
    OverlayItem logicalNode =
        new OverlayItem(Collections.singletonList(physicalNode), CorrelationItemEnum.Node);
    OverlayItemWrapper wrapper = new OverlayItemWrapper(logicalName, logicalNode);
    NormalizedNode<?, ?> normalizedNode = translator.translate(wrapper);

    NormalizedNode<?, ?> nodeId =
        NormalizedNodes.findNode(
                normalizedNode, YangInstanceIdentifier.of(TopologyQNames.NETWORK_NODE_ID_QNAME))
            .get();
    Assert.assertEquals(
        "NormalizedNode ID should be the same as the LogicalNodeWrapper ID",
        logicalName,
        nodeId.getValue());
  }
 public static final YangInstanceIdentifier path(final String topName) {
   return TOP_LEVEL
       .node(TopLevelList.QNAME)
       .node(new NodeIdentifierWithPredicates(TopLevelList.QNAME, NAME_QNAME, topName));
 }
public abstract class AbstractDataChangeListenerTest {

  protected static final YangInstanceIdentifier TOP_LEVEL = YangInstanceIdentifier.of(Top.QNAME);
  private static final QName NAME_QNAME = QName.create(Top.QNAME, "name");
  protected static final String FOO = "foo";
  protected static final String BAR = "bar";
  protected static final String BAZ = "baz";

  private InMemoryDOMDataStore datastore;
  private SchemaContext schemaContext;
  private TestDCLExecutorService dclExecutorService;

  @Before
  public final void setup() throws Exception {
    YangModuleInfo moduleInfo = BindingReflections.getModuleInfo(TwoLevelList.class);
    ModuleInfoBackedContext context = ModuleInfoBackedContext.create();
    context.registerModuleInfo(moduleInfo);
    schemaContext = context.tryToCreateSchemaContext().get();

    dclExecutorService =
        new TestDCLExecutorService(SpecialExecutors.newBlockingBoundedFastThreadPool(1, 10, "DCL"));

    datastore = new InMemoryDOMDataStore("TEST", dclExecutorService);
    datastore.onGlobalContextUpdated(schemaContext);
  }

  @After
  public void tearDown() {
    if (dclExecutorService != null) {
      dclExecutorService.shutdownNow();
    }
  }

  /**
   * Create a new test task. The task will operate on the backed database, and will use the proper
   * background executor service.
   *
   * @return Test task initialized to clean up {@value #TOP_LEVEL} and its children.
   */
  public final DatastoreTestTask newTestTask() {
    return new DatastoreTestTask(datastore, dclExecutorService)
        .cleanup(DatastoreTestTask.simpleDelete(TOP_LEVEL));
  }

  public static final YangInstanceIdentifier path(final String topName, final String nestedName) {
    return path(topName)
        .node(NestedList.QNAME)
        .node(new NodeIdentifierWithPredicates(NestedList.QNAME, NAME_QNAME, nestedName));
  }

  public static final YangInstanceIdentifier path(final String topName) {
    return TOP_LEVEL
        .node(TopLevelList.QNAME)
        .node(new NodeIdentifierWithPredicates(TopLevelList.QNAME, NAME_QNAME, topName));
  }

  protected static DataContainerNodeAttrBuilder<NodeIdentifier, ContainerNode> top() {
    return Builders.containerBuilder().withNodeIdentifier(new NodeIdentifier(Top.QNAME));
  }

  protected static void assertEmpty(final Collection<?> set) {
    Assert.assertTrue(set.isEmpty());
  }

  protected static void assertEmpty(final Map<?, ?> set) {
    Assert.assertTrue(set.isEmpty());
  }

  protected static <K> void assertContains(final Collection<K> set, final K... values) {
    for (K key : values) {
      Assert.assertTrue(set.contains(key));
    }
  }

  protected static <K> void assertNotContains(final Collection<K> set, final K... values) {
    for (K key : values) {
      Assert.assertFalse(set.contains(key));
    }
  }

  protected static <K> void assertContains(final Map<K, ?> map, final K... values) {
    for (K key : values) {
      Assert.assertTrue(map.containsKey(key));
    }
  }

  protected static <K> void assertNotContains(final Map<K, ?> map, final K... values) {
    for (K key : values) {
      Assert.assertFalse(map.containsKey(key));
    }
  }

  protected static CollectionNodeBuilder<MapEntryNode, MapNode> topLevelMap() {
    return ImmutableNodes.mapNodeBuilder(TopLevelList.QNAME);
  }

  protected static CollectionNodeBuilder<MapEntryNode, OrderedMapNode> nestedMap() {
    return Builders.orderedMapBuilder().withNodeIdentifier(new NodeIdentifier(NestedList.QNAME));
  }

  public static DataContainerNodeBuilder<NodeIdentifierWithPredicates, MapEntryNode> topLevelList(
      final String key) {
    return ImmutableNodes.mapEntryBuilder(TopLevelList.QNAME, NAME_QNAME, key);
  }

  public static DataContainerNodeBuilder<NodeIdentifierWithPredicates, MapEntryNode> nestedList(
      final String key) {
    return ImmutableNodes.mapEntryBuilder(NestedList.QNAME, NAME_QNAME, key);
  }

  public static final WriteTransactionCustomizer writeOneTopMultipleNested(
      final String topName, final String... nestedName) {
    CollectionNodeBuilder<MapEntryNode, OrderedMapNode> nestedMapBuilder = nestedMap();
    for (String nestedItem : nestedName) {
      nestedMapBuilder.addChild(nestedList(nestedItem).build());
    }

    final ContainerNode data =
        top()
            .addChild(
                topLevelMap()
                    .addChild(topLevelList(topName).addChild(nestedMapBuilder.build()).build())
                    .build())
            .build();

    return DatastoreTestTask.simpleWrite(TOP_LEVEL, data);
  }

  public static final WriteTransactionCustomizer deleteNested(
      final String topName, final String nestedName) {
    return DatastoreTestTask.simpleDelete(path(topName, nestedName));
  }
}
public class NetconfMDSalMappingTest {

  private static final Logger LOG = LoggerFactory.getLogger(NetconfMDSalMappingTest.class);

  private static final String RPC_REPLY_ELEMENT = "rpc-reply";
  private static final String DATA_ELEMENT = "data";
  private static final String FILTER_NODE = "filter";
  private static final String GET_CONFIG = "get-config";
  private static final QName TOP =
      QName.create("urn:opendaylight:mdsal:mapping:test", "2015-02-26", "top");
  private static final QName USERS =
      QName.create("urn:opendaylight:mdsal:mapping:test", "2015-02-26", "users");
  private static final QName USER =
      QName.create("urn:opendaylight:mdsal:mapping:test", "2015-02-26", "user");
  private static final QName MODULES =
      QName.create("urn:opendaylight:mdsal:mapping:test", "2015-02-26", "modules");
  private static final QName AUGMENTED_CONTAINER =
      QName.create("urn:opendaylight:mdsal:mapping:test", "2015-02-26", "augmented-container");
  private static final QName AUGMENTED_STRING_IN_CONT =
      QName.create("urn:opendaylight:mdsal:mapping:test", "2015-02-26", "identifier");
  private static final QName CHOICE_NODE =
      QName.create("urn:opendaylight:mdsal:mapping:test", "2015-02-26", "choice-node");
  private static final QName AUGMENTED_CASE =
      QName.create("urn:opendaylight:mdsal:mapping:test", "2015-02-26", "augmented-case");
  private static final QName CHOICE_WRAPPER =
      QName.create("urn:opendaylight:mdsal:mapping:test", "2015-02-26", "choice-wrapper");
  private static final QName INNER_CHOICE =
      QName.create("urn:opendaylight:mdsal:mapping:test", "2015-02-26", "inner-choice");
  private static final QName INNER_CHOICE_TEXT =
      QName.create("urn:opendaylight:mdsal:mapping:test", "2015-02-26", "text");

  private static final YangInstanceIdentifier AUGMENTED_CONTAINER_IN_MODULES =
      YangInstanceIdentifier.builder()
          .node(TOP)
          .node(MODULES)
          .build()
          .node(new AugmentationIdentifier(Collections.singleton(AUGMENTED_CONTAINER)));

  private static Document RPC_REPLY_OK = null;

  static {
    try {
      RPC_REPLY_OK = XmlFileLoader.xmlFileToDocument("messages/mapping/rpc-reply_ok.xml");
    } catch (Exception e) {
      LOG.debug("unable to load rpc reply ok.", e);
      RPC_REPLY_OK = XmlUtil.newDocument();
    }
  }

  private CurrentSchemaContext currentSchemaContext = null;
  private SchemaContext schemaContext = null;
  private String sessionIdForReporting = "netconf-test-session1";

  private TransactionProvider transactionProvider = null;

  @Mock private SchemaSourceProvider<YangTextSchemaSource> sourceProvider;

  @Before
  public void setUp() throws Exception {
    MockitoAnnotations.initMocks(this);

    XMLUnit.setIgnoreWhitespace(true);
    XMLUnit.setIgnoreAttributeOrder(true);

    this.schemaContext = parseSchemas(getYangSchemas());
    schemaContext.getModules();
    final SchemaService schemaService = createSchemaService();

    final DOMStore operStore = InMemoryDOMDataStoreFactory.create("DOM-OPER", schemaService);
    final DOMStore configStore = InMemoryDOMDataStoreFactory.create("DOM-CFG", schemaService);

    final EnumMap<LogicalDatastoreType, DOMStore> datastores =
        new EnumMap<>(LogicalDatastoreType.class);
    datastores.put(LogicalDatastoreType.CONFIGURATION, configStore);
    datastores.put(LogicalDatastoreType.OPERATIONAL, operStore);

    ExecutorService listenableFutureExecutor =
        SpecialExecutors.newBlockingBoundedCachedThreadPool(16, 16, "CommitFutures");

    final ConcurrentDOMDataBroker cdb =
        new ConcurrentDOMDataBroker(datastores, listenableFutureExecutor);
    this.transactionProvider = new TransactionProvider(cdb, sessionIdForReporting);

    doAnswer(
            new Answer() {
              @Override
              public Object answer(final InvocationOnMock invocationOnMock) throws Throwable {
                final SourceIdentifier sId = (SourceIdentifier) invocationOnMock.getArguments()[0];
                final YangTextSchemaSource yangTextSchemaSource =
                    YangTextSchemaSource.delegateForByteSource(
                        sId, ByteSource.wrap("module test".getBytes()));
                return Futures.immediateCheckedFuture(yangTextSchemaSource);
              }
            })
        .when(sourceProvider)
        .getSource(any(SourceIdentifier.class));

    this.currentSchemaContext = new CurrentSchemaContext(schemaService, sourceProvider);
  }

  @Test
  public void testEmptyDatastore() throws Exception {
    assertEmptyDatastore(get());
    assertEmptyDatastore(getConfigCandidate());
    assertEmptyDatastore(getConfigRunning());
  }

  @Test
  public void testIncorrectGet() throws Exception {

    try {
      executeOperation(
          new GetConfig(sessionIdForReporting, currentSchemaContext, transactionProvider),
          "messages/mapping/bad_getConfig.xml");
      fail("Should have failed, this is an incorrect request");
    } catch (DocumentedException e) {
      assertTrue(e.getErrorSeverity() == ErrorSeverity.error);
      assertTrue(e.getErrorTag() == ErrorTag.operation_failed);
      assertTrue(e.getErrorType() == ErrorType.application);
    }

    try {
      executeOperation(
          new GetConfig(sessionIdForReporting, currentSchemaContext, transactionProvider),
          "messages/mapping/bad_namespace_getConfig.xml");
      fail("Should have failed, this is an incorrect request");
    } catch (DocumentedException e) {
      assertTrue(e.getErrorSeverity() == ErrorSeverity.error);
      assertTrue(e.getErrorTag() == ErrorTag.operation_failed);
      assertTrue(e.getErrorType() == ErrorType.application);
    }
  }

  @Test
  public void testEditRunning() throws Exception {

    try {
      edit("messages/mapping/editConfigs/editConfig_running.xml");
      fail("Should have failed - edit config on running datastore is not supported");
    } catch (DocumentedException e) {
      assertTrue(e.getErrorSeverity() == ErrorSeverity.error);
      assertTrue(e.getErrorTag() == ErrorTag.operation_not_supported);
      assertTrue(e.getErrorType() == ErrorType.protocol);
    }
  }

  @Test
  public void testCommitWithoutOpenTransaction() throws Exception {
    verifyResponse(commit(), RPC_REPLY_OK);
    assertEmptyDatastore(getConfigCandidate());
  }

  @Test
  public void testCandidateTransaction() throws Exception {

    verifyResponse(edit("messages/mapping/editConfigs/editConfig_merge_n1.xml"), RPC_REPLY_OK);
    verifyResponse(
        getConfigCandidate(),
        XmlFileLoader.xmlFileToDocument(
            "messages/mapping/editConfigs/editConfig_merge_n1_control.xml"));
    assertEmptyDatastore(getConfigRunning());

    verifyResponse(discardChanges(), RPC_REPLY_OK);
    assertEmptyDatastore(getConfigCandidate());
  }

  @Test
  public void testEditWithCommit() throws Exception {

    verifyResponse(edit("messages/mapping/editConfigs/editConfig_merge_n1.xml"), RPC_REPLY_OK);
    verifyResponse(
        getConfigCandidate(),
        XmlFileLoader.xmlFileToDocument(
            "messages/mapping/editConfigs/editConfig_merge_n1_control.xml"));

    verifyResponse(commit(), RPC_REPLY_OK);
    verifyResponse(
        getConfigRunning(),
        XmlFileLoader.xmlFileToDocument(
            "messages/mapping/editConfigs/editConfig_merge_n1_control.xml"));

    deleteDatastore();
  }

  @Test
  public void testKeyOrder() throws Exception {
    verifyResponse(
        edit("messages/mapping/editConfigs/editConfig_merge_multiple_keys_1.xml"), RPC_REPLY_OK);
    verifyResponse(commit(), RPC_REPLY_OK);
    final Document configRunning = getConfigRunning();
    final String responseAsString = XmlUtil.toString(configRunning);
    verifyResponse(
        configRunning,
        XmlFileLoader.xmlFileToDocument(
            "messages/mapping/editConfigs/editConfig_merge_multiple_keys_1_control.xml"));

    final int key3 = responseAsString.indexOf("key3");
    final int key1 = responseAsString.indexOf("key1");
    final int key2 = responseAsString.indexOf("key2");

    assertTrue(
        String.format(
            "Key ordering invalid, should be key3(%d) < key1(%d) < key2(%d)", key3, key1, key2),
        key3 < key1 && key1 < key2);

    deleteDatastore();
  }

  @Test
  public void testMultipleEditsWithMerge() throws Exception {

    verifyResponse(
        edit("messages/mapping/editConfigs/editConfig_merge_multiple_1.xml"), RPC_REPLY_OK);
    verifyResponse(
        getConfigCandidate(),
        XmlFileLoader.xmlFileToDocument(
            "messages/mapping/editConfigs/editConfig_merge_multiple_control_1.xml"));
    verifyResponse(
        edit("messages/mapping/editConfigs/editConfig_merge_single_1.xml"), RPC_REPLY_OK);
    verifyResponse(
        getConfigCandidate(),
        XmlFileLoader.xmlFileToDocument(
            "messages/mapping/editConfigs/editConfig_merge_multiple_control_2.xml"));
    assertEmptyDatastore(getConfigRunning());

    verifyResponse(commit(), RPC_REPLY_OK);
    verifyResponse(
        getConfigRunning(),
        XmlFileLoader.xmlFileToDocument(
            "messages/mapping/editConfigs/editConfig_merge_multiple_control_2.xml"));

    deleteDatastore();
  }

  @Test
  public void testMoreComplexEditConfigs() throws Exception {

    verifyResponse(
        edit("messages/mapping/editConfigs/editConfig_merge_multiple_1.xml"), RPC_REPLY_OK);
    verifyResponse(
        edit("messages/mapping/editConfigs/editConfig_merge_single_1.xml"), RPC_REPLY_OK);

    verifyResponse(
        edit("messages/mapping/editConfigs/editConfig_merge_multiple_2.xml"), RPC_REPLY_OK);
    verifyResponse(
        getConfigCandidate(),
        XmlFileLoader.xmlFileToDocument(
            "messages/mapping/editConfigs/editConfig_merge_multiple_after_more_complex_merge.xml"));

    verifyResponse(
        edit("messages/mapping/editConfigs/editConfig_merge_multiple_3.xml"), RPC_REPLY_OK);
    verifyResponse(
        getConfigCandidate(),
        XmlFileLoader.xmlFileToDocument(
            "messages/mapping/editConfigs/editConfig_merge_multiple_after_more_complex_merge_2.xml"));

    verifyResponse(
        edit("messages/mapping/editConfigs/editConfig_merge_multiple_4_replace.xml"), RPC_REPLY_OK);
    verifyResponse(
        getConfigCandidate(),
        XmlFileLoader.xmlFileToDocument(
            "messages/mapping/editConfigs/editConfig_merge_multiple_after_replace.xml"));
    verifyResponse(commit(), RPC_REPLY_OK);

    verifyResponse(
        getConfigRunning(),
        XmlFileLoader.xmlFileToDocument(
            "messages/mapping/editConfigs/editConfig_merge_multiple_after_replace.xml"));

    verifyResponse(
        edit("messages/mapping/editConfigs/editConfig_replace_default.xml"), RPC_REPLY_OK);
    verifyResponse(
        getConfigCandidate(),
        XmlFileLoader.xmlFileToDocument(
            "messages/mapping/editConfigs/editConfig_replace_default_control.xml"));
    verifyResponse(commit(), RPC_REPLY_OK);

    verifyResponse(
        getConfigRunning(),
        XmlFileLoader.xmlFileToDocument(
            "messages/mapping/editConfigs/editConfig_replace_default_control.xml"));

    deleteDatastore();
  }

  @Test
  public void testLock() throws Exception {

    verifyResponse(lockCandidate(), RPC_REPLY_OK);

    try {
      lock();
      fail("Should have failed - locking of running datastore is not supported");
    } catch (DocumentedException e) {
      assertTrue(e.getErrorSeverity() == ErrorSeverity.error);
      assertTrue(e.getErrorTag() == ErrorTag.operation_not_supported);
      assertTrue(e.getErrorType() == ErrorType.application);
    }

    try {
      lockWithoutTarget();
      fail("Should have failed, target is missing");
    } catch (DocumentedException e) {
      assertTrue(e.getErrorSeverity() == ErrorSeverity.error);
      assertTrue(e.getErrorTag() == ErrorTag.invalid_value);
      assertTrue(e.getErrorType() == ErrorType.application);
    }
  }

  @Test
  public void testUnlock() throws Exception {

    verifyResponse(unlockCandidate(), RPC_REPLY_OK);

    try {
      unlock();
      fail("Should have failed - unlocking of running datastore is not supported");
    } catch (DocumentedException e) {
      assertTrue(e.getErrorSeverity() == ErrorSeverity.error);
      assertTrue(e.getErrorTag() == ErrorTag.operation_not_supported);
      assertTrue(e.getErrorType() == ErrorType.application);
    }

    try {
      unlockWithoutTarget();
      fail("Should have failed, target is missing");
    } catch (DocumentedException e) {
      assertTrue(e.getErrorSeverity() == ErrorSeverity.error);
      assertTrue(e.getErrorTag() == ErrorTag.invalid_value);
      assertTrue(e.getErrorType() == ErrorType.application);
    }
  }

  @Test
  public void testEditWithCreate() throws Exception {

    verifyResponse(edit("messages/mapping/editConfigs/editConfig_create.xml"), RPC_REPLY_OK);
    verifyResponse(
        getConfigCandidate(),
        XmlFileLoader.xmlFileToDocument("messages/mapping/editConfig_create_n1_control.xml"));

    try {
      edit("messages/mapping/editConfigs/editConfig_create.xml");
      fail("Create should have failed - data already exists");
    } catch (DocumentedException e) {
      assertTrue(e.getErrorSeverity() == ErrorSeverity.error);
      assertTrue(e.getErrorTag() == ErrorTag.data_exists);
      assertTrue(e.getErrorType() == ErrorType.protocol);
    }

    verifyResponse(discardChanges(), RPC_REPLY_OK);
  }

  @Test
  public void testDeleteNonExisting() throws Exception {

    assertEmptyDatastore(getConfigCandidate());
    assertEmptyDatastore(getConfigRunning());

    try {
      edit("messages/mapping/editConfigs/editConfig_delete-top.xml");
      fail("Delete should have failed - data is missing");
    } catch (DocumentedException e) {
      assertTrue(e.getErrorSeverity() == ErrorSeverity.error);
      assertTrue(e.getErrorTag() == ErrorTag.data_missing);
      assertTrue(e.getErrorType() == ErrorType.protocol);
    }
  }

  @Test
  public void testEditMissingDefaultOperation() throws Exception {

    verifyResponse(
        edit("messages/mapping/editConfigs/editConfig_merge_missing_default-operation_1.xml"),
        RPC_REPLY_OK);
    verifyResponse(
        edit("messages/mapping/editConfigs/editConfig_merge_missing_default-operation_2.xml"),
        RPC_REPLY_OK);
    verifyResponse(
        getConfigCandidate(),
        XmlFileLoader.xmlFileToDocument(
            "messages/mapping/editConfigs/editConfig_merge_missing_default-operation_control.xml"));

    verifyResponse(commit(), RPC_REPLY_OK);
    verifyResponse(
        getConfigRunning(),
        XmlFileLoader.xmlFileToDocument(
            "messages/mapping/editConfigs/editConfig_merge_missing_default-operation_control.xml"));

    deleteDatastore();
  }

  public static void printDocument(Document doc) throws IOException, TransformerException {
    TransformerFactory tf = TransformerFactory.newInstance();
    Transformer transformer = tf.newTransformer();
    transformer.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, "no");
    transformer.setOutputProperty(OutputKeys.METHOD, "xml");
    transformer.setOutputProperty(OutputKeys.INDENT, "yes");
    transformer.setOutputProperty(OutputKeys.ENCODING, "UTF-8");
    transformer.setOutputProperty("{http://xml.apache.org/xslt}indent-amount", "4");

    StringWriter writer = new StringWriter();
    transformer.transform(new DOMSource(doc), new StreamResult(writer));
    LOG.warn(writer.getBuffer().toString());
  }

  @Test
  public void testEditConfigWithMultipleOperations() throws Exception {
    deleteDatastore();

    verifyResponse(
        edit("messages/mapping/editConfigs/editConfig_merge_multiple_operations_setup.xml"),
        RPC_REPLY_OK);
    verifyResponse(
        edit("messages/mapping/editConfigs/editConfig_merge_multiple_operations_1.xml"),
        RPC_REPLY_OK);

    verifyResponse(
        edit("messages/mapping/editConfigs/editConfig_merge_multiple_operations_2.xml"),
        RPC_REPLY_OK);
    verifyResponse(
        getConfigCandidate(),
        XmlFileLoader.xmlFileToDocument(
            "messages/mapping/editConfigs/editConfig_merge_multiple_operations_2_control.xml"));

    verifyResponse(
        edit(
            "messages/mapping/editConfigs/editConfig_merge_multiple_operations_3_leaf_operations.xml"),
        RPC_REPLY_OK);
    verifyResponse(
        getConfigCandidate(),
        XmlFileLoader.xmlFileToDocument(
            "messages/mapping/editConfigs/editConfig_merge_multiple_operations_3_control.xml"));

    deleteDatastore();

    verifyResponse(
        edit("messages/mapping/editConfigs/editConfig_merge_multiple_operations_4_setup.xml"),
        RPC_REPLY_OK);
    verifyResponse(
        edit(
            "messages/mapping/editConfigs/editConfig_merge_multiple_operations_4_default-replace.xml"),
        RPC_REPLY_OK);

    try {
      edit(
          "messages/mapping/editConfigs/editConfig_merge_multiple_operations_4_create_existing.xml");
      fail();
    } catch (DocumentedException e) {
      assertTrue(e.getErrorSeverity() == ErrorSeverity.error);
      assertTrue(e.getErrorTag() == ErrorTag.data_exists);
      assertTrue(e.getErrorType() == ErrorType.protocol);
    }

    verifyResponse(
        edit(
            "messages/mapping/editConfigs/editConfig_merge_multiple_operations_4_delete_children_operations.xml"),
        RPC_REPLY_OK);
    verifyResponse(
        getConfigCandidate(),
        XmlFileLoader.xmlFileToDocument(
            "messages/mapping/editConfigs/editConfig_merge_multiple_operations_4_delete_children_operations_control.xml"));
    verifyResponse(
        edit(
            "messages/mapping/editConfigs/editConfig_merge_multiple_operations_4_remove-non-existing.xml"),
        RPC_REPLY_OK);

    try {
      edit(
          "messages/mapping/editConfigs/editConfig_merge_multiple_operations_4_delete-non-existing.xml");
      fail();
    } catch (DocumentedException e) {
      assertTrue(e.getErrorSeverity() == ErrorSeverity.error);
      assertTrue(e.getErrorTag() == ErrorTag.data_missing);
      assertTrue(e.getErrorType() == ErrorType.protocol);
    }

    verifyResponse(
        edit(
            "messages/mapping/editConfigs/editConfig_merge_multiple_operations_5_choice_setup.xml"),
        RPC_REPLY_OK);
    verifyResponse(
        getConfigCandidate(),
        XmlFileLoader.xmlFileToDocument(
            "messages/mapping/editConfigs/editConfig_merge_multiple_operations_5_choice_setup-control.xml"));

    // Test files have been modified. RFC6020 requires that at most once case inside a choice is
    // present at any time
    verifyResponse(
        edit(
            "messages/mapping/editConfigs/editConfig_merge_multiple_operations_5_choice_setup2.xml"),
        RPC_REPLY_OK);
    verifyResponse(
        getConfigCandidate(),
        XmlFileLoader.xmlFileToDocument(
            "messages/mapping/editConfigs/editConfig_merge_multiple_operations_5_choice_setup2-control.xml"));

    verifyResponse(
        edit(
            "messages/mapping/editConfigs/editConfig_merge_multiple_operations_5_choice_delete.xml"),
        RPC_REPLY_OK);
    verifyResponse(
        getConfigCandidate(),
        XmlFileLoader.xmlFileToDocument(
            "messages/mapping/editConfigs/editConfig_merge_multiple_operations_4_delete_children_operations_control.xml"));

    deleteDatastore();
  }

  @Test
  public void testFiltering() throws Exception {

    assertEmptyDatastore(getConfigCandidate());
    assertEmptyDatastore(getConfigRunning());

    verifyResponse(
        getConfigWithFilter("messages/mapping/filters/get-config-empty-filter.xml"),
        XmlFileLoader.xmlFileToDocument("messages/mapping/get-empty-response.xml"));
    verifyResponse(
        getWithFilter("messages/mapping/filters/get-empty-filter.xml"),
        XmlFileLoader.xmlFileToDocument("messages/mapping/get-empty-response.xml"));

    verifyResponse(
        getConfigCandidate(),
        XmlFileLoader.xmlFileToDocument("messages/mapping/get-empty-response.xml"));
    verifyResponse(
        getConfigRunning(),
        XmlFileLoader.xmlFileToDocument("messages/mapping/get-empty-response.xml"));
    verifyResponse(
        getConfigWithFilter("messages/mapping/filters/get-filter-users.xml"),
        XmlFileLoader.xmlFileToDocument("messages/mapping/get-empty-response.xml"));

    verifyResponse(
        edit("messages/mapping/editConfigs/editConfig-filtering-setup.xml"), RPC_REPLY_OK);
    verifyResponse(commit(), RPC_REPLY_OK);

    // TODO uncomment these tests once we can parse KeyedListNode as a selection node, currently you
    // cannot use a KeyedList as a selection node in filter
    //        verifyFilterIdentifier("messages/mapping/filters/get-filter-alluser.xml",
    //                YangInstanceIdentifier.builder().node(TOP).node(USERS).node(USER).build());
    verifyFilterIdentifier(
        "messages/mapping/filters/get-filter-company-info.xml",
        YangInstanceIdentifier.builder().node(TOP).node(USERS).node(USER).build());
    verifyFilterIdentifier(
        "messages/mapping/filters/get-filter-modules-and-admin.xml",
        YangInstanceIdentifier.builder().node(TOP).build());
    verifyFilterIdentifier(
        "messages/mapping/filters/get-filter-only-names-types.xml",
        YangInstanceIdentifier.builder().node(TOP).node(USERS).node(USER).build());
    //
    // verifyFilterIdentifier("messages/mapping/filters/get-filter-specific-module-type-and-user.xml",
    //                YangInstanceIdentifier.builder().node(TOP).build());
    //        verifyFilterIdentifier("messages/mapping/filters/get-filter-superuser.xml",
    //                YangInstanceIdentifier.builder().node(TOP).node(USERS).node(USER).build());
    verifyFilterIdentifier(
        "messages/mapping/filters/get-filter-users.xml",
        YangInstanceIdentifier.builder().node(TOP).node(USERS).build());

    YangInstanceIdentifier ident =
        YangInstanceIdentifier.builder(AUGMENTED_CONTAINER_IN_MODULES)
            .node(AUGMENTED_CONTAINER)
            .node(AUGMENTED_STRING_IN_CONT)
            .build();

    verifyFilterIdentifier("messages/mapping/filters/get-filter-augmented-string.xml", ident);
    verifyFilterIdentifier(
        "messages/mapping/filters/get-filter-augmented-case.xml",
        YangInstanceIdentifier.builder().node(TOP).node(CHOICE_NODE).node(AUGMENTED_CASE).build());

    verifyResponse(
        getConfigWithFilter("messages/mapping/filters/get-filter-augmented-case.xml"),
        XmlFileLoader.xmlFileToDocument("messages/mapping/filters/response-augmented-case.xml"));

    /*
     *  RFC6020 requires that at most once case inside a choice is present at any time.
     *  Therefore
     *  <augmented-case>augmented case</augmented-case>
     *  from
     *  messages/mapping/editConfigs/editConfig-filtering-setup.xml
     *  cannot exists together with
     *  <text>augmented nested choice text1</text>
     *  from
     *  messages/mapping/editConfigs/editConfig-filtering-setup2.xml
     */
    // verifyResponse(edit("messages/mapping/editConfigs/editConfig-filtering-setup2.xml"),
    // RPC_REPLY_OK);
    // verifyResponse(commit(), RPC_REPLY_OK);

    //
    // verifyFilterIdentifier("messages/mapping/filters/get-filter-augmented-case-inner-choice.xml",
    //
    // YangInstanceIdentifier.builder().node(TOP).node(CHOICE_NODE).node(CHOICE_WRAPPER).build());
    //
    // verifyFilterIdentifier("messages/mapping/filters/get-filter-augmented-case-inner-case.xml",
    //
    // YangInstanceIdentifier.builder().node(TOP).node(CHOICE_NODE).node(CHOICE_WRAPPER).node(INNER_CHOICE).node(INNER_CHOICE_TEXT).build());

    //
    // verifyResponse(getConfigWithFilter("messages/mapping/filters/get-filter-augmented-string.xml"),
    //
    // XmlFileLoader.xmlFileToDocument("messages/mapping/filters/response-augmented-string.xml"));
    //
    // verifyResponse(getConfigWithFilter("messages/mapping/filters/get-filter-augmented-case-inner-choice.xml"),
    //
    // XmlFileLoader.xmlFileToDocument("messages/mapping/filters/response-augmented-case-inner-choice.xml"));
    //
    // verifyResponse(getConfigWithFilter("messages/mapping/filters/get-filter-augmented-case-inner-case.xml"),
    //
    // XmlFileLoader.xmlFileToDocument("messages/mapping/filters/response-augmented-case-inner-choice.xml"));

    verifyResponse(edit("messages/mapping/editConfigs/editConfig_delete-top.xml"), RPC_REPLY_OK);
    verifyResponse(commit(), RPC_REPLY_OK);
  }

  private void verifyFilterIdentifier(String resource, YangInstanceIdentifier identifier)
      throws Exception {
    TestingGetConfig getConfig =
        new TestingGetConfig(sessionIdForReporting, currentSchemaContext, transactionProvider);
    Document request = XmlFileLoader.xmlFileToDocument(resource);
    YangInstanceIdentifier iid = getConfig.getInstanceIdentifierFromDocument(request);
    assertTrue(iid.equals(identifier));
  }

  private class TestingGetConfig extends GetConfig {
    public TestingGetConfig(
        String sessionId,
        CurrentSchemaContext schemaContext,
        TransactionProvider transactionProvider) {
      super(sessionId, schemaContext, transactionProvider);
    }

    public YangInstanceIdentifier getInstanceIdentifierFromDocument(Document request)
        throws DocumentedException {
      XmlElement filterElement =
          XmlElement.fromDomDocument(request)
              .getOnlyChildElement(GET_CONFIG)
              .getOnlyChildElement(FILTER_NODE);
      return getInstanceIdentifierFromFilter(filterElement);
    }
  }

  private void deleteDatastore() throws Exception {
    verifyResponse(edit("messages/mapping/editConfigs/editConfig_delete-root.xml"), RPC_REPLY_OK);
    assertEmptyDatastore(getConfigCandidate());

    verifyResponse(commit(), RPC_REPLY_OK);
    assertEmptyDatastore(getConfigRunning());
  }

  private void verifyResponse(Document response, Document template)
      throws IOException, TransformerException {
    DetailedDiff dd = new DetailedDiff(new Diff(response, template));
    dd.overrideElementQualifier(new NetconfXmlUnitRecursiveQualifier());

    printDocument(response);
    printDocument(template);

    assertTrue(dd.toString(), dd.similar());
  }

  private void assertEmptyDatastore(Document response) {

    NodeList nodes = response.getChildNodes();
    assertTrue(nodes.getLength() == 1);

    assertEquals(nodes.item(0).getLocalName(), RPC_REPLY_ELEMENT);

    NodeList replyNodes = nodes.item(0).getChildNodes();
    assertTrue(replyNodes.getLength() == 1);

    Node dataNode = replyNodes.item(0);
    assertEquals(dataNode.getLocalName(), DATA_ELEMENT);
    assertFalse(dataNode.hasChildNodes());
  }

  private Document commit()
      throws DocumentedException, ParserConfigurationException, SAXException, IOException {
    Commit commit = new Commit(sessionIdForReporting, transactionProvider);
    return executeOperation(commit, "messages/mapping/commit.xml");
  }

  private Document discardChanges()
      throws DocumentedException, ParserConfigurationException, SAXException, IOException {
    DiscardChanges discardOp = new DiscardChanges(sessionIdForReporting, transactionProvider);
    return executeOperation(discardOp, "messages/mapping/discardChanges.xml");
  }

  private Document edit(String resource)
      throws DocumentedException, ParserConfigurationException, SAXException, IOException {
    EditConfig editConfig =
        new EditConfig(sessionIdForReporting, currentSchemaContext, transactionProvider);
    return executeOperation(editConfig, resource);
  }

  private Document get()
      throws DocumentedException, ParserConfigurationException, SAXException, IOException {
    Get get = new Get(sessionIdForReporting, currentSchemaContext, transactionProvider);
    return executeOperation(get, "messages/mapping/get.xml");
  }

  private Document getWithFilter(String resource)
      throws DocumentedException, ParserConfigurationException, SAXException, IOException {
    Get get = new Get(sessionIdForReporting, currentSchemaContext, transactionProvider);
    return executeOperation(get, resource);
  }

  private Document getConfigRunning()
      throws DocumentedException, ParserConfigurationException, SAXException, IOException {
    GetConfig getConfig =
        new GetConfig(sessionIdForReporting, currentSchemaContext, transactionProvider);
    return executeOperation(getConfig, "messages/mapping/getConfig.xml");
  }

  private Document getConfigCandidate()
      throws DocumentedException, ParserConfigurationException, SAXException, IOException {
    GetConfig getConfig =
        new GetConfig(sessionIdForReporting, currentSchemaContext, transactionProvider);
    return executeOperation(getConfig, "messages/mapping/getConfig_candidate.xml");
  }

  private Document getConfigWithFilter(String resource)
      throws DocumentedException, ParserConfigurationException, SAXException, IOException {
    GetConfig getConfig =
        new GetConfig(sessionIdForReporting, currentSchemaContext, transactionProvider);
    return executeOperation(getConfig, resource);
  }

  private Document lock()
      throws DocumentedException, ParserConfigurationException, SAXException, IOException {
    Lock lock = new Lock(sessionIdForReporting);
    return executeOperation(lock, "messages/mapping/lock.xml");
  }

  private Document unlock()
      throws DocumentedException, ParserConfigurationException, SAXException, IOException {
    Unlock unlock = new Unlock(sessionIdForReporting);
    return executeOperation(unlock, "messages/mapping/unlock.xml");
  }

  private Document lockWithoutTarget()
      throws DocumentedException, ParserConfigurationException, SAXException, IOException {
    Lock lock = new Lock(sessionIdForReporting);
    return executeOperation(lock, "messages/mapping/lock_notarget.xml");
  }

  private Document unlockWithoutTarget()
      throws DocumentedException, ParserConfigurationException, SAXException, IOException {
    Unlock unlock = new Unlock(sessionIdForReporting);
    return executeOperation(unlock, "messages/mapping/unlock_notarget.xml");
  }

  private Document lockCandidate()
      throws DocumentedException, ParserConfigurationException, SAXException, IOException {
    Lock lock = new Lock(sessionIdForReporting);
    return executeOperation(lock, "messages/mapping/lock_candidate.xml");
  }

  private Document unlockCandidate()
      throws DocumentedException, ParserConfigurationException, SAXException, IOException {
    Unlock unlock = new Unlock(sessionIdForReporting);
    return executeOperation(unlock, "messages/mapping/unlock_candidate.xml");
  }

  private Document executeOperation(NetconfOperation op, String filename)
      throws ParserConfigurationException, SAXException, IOException, DocumentedException {
    final Document request = XmlFileLoader.xmlFileToDocument(filename);
    final Document response =
        op.handle(request, NetconfOperationChainedExecution.EXECUTION_TERMINATION_POINT);

    LOG.debug("Got response {}", response);
    return response;
  }

  private Collection<InputStream> getYangSchemas() {
    final List<String> schemaPaths =
        Arrays.asList("/META-INF/yang/config.yang", "/yang/mdsal-netconf-mapping-test.yang");
    final List<InputStream> schemas = new ArrayList<>();

    for (String schemaPath : schemaPaths) {
      InputStream resourceAsStream = getClass().getResourceAsStream(schemaPath);
      schemas.add(resourceAsStream);
    }

    return schemas;
  }

  private SchemaContext parseSchemas(Collection<InputStream> schemas)
      throws IOException, YangSyntaxErrorException {
    final YangParserImpl parser = new YangParserImpl();
    Collection<ByteSource> sources = BuilderUtils.streamsToByteSources(schemas);
    return parser.parseSources(sources);
  }

  private SchemaService createSchemaService() {
    return new SchemaService() {

      @Override
      public void addModule(Module module) {}

      @Override
      public void removeModule(Module module) {}

      @Override
      public SchemaContext getSessionContext() {
        return schemaContext;
      }

      @Override
      public SchemaContext getGlobalContext() {
        return schemaContext;
      }

      @Override
      public ListenerRegistration<SchemaContextListener> registerSchemaContextListener(
          final SchemaContextListener listener) {
        listener.onGlobalContextUpdated(getGlobalContext());
        return new ListenerRegistration<SchemaContextListener>() {
          @Override
          public void close() {}

          @Override
          public SchemaContextListener getInstance() {
            return listener;
          }
        };
      }
    };
  }
}
  @Test
  public void testFiltering() throws Exception {

    assertEmptyDatastore(getConfigCandidate());
    assertEmptyDatastore(getConfigRunning());

    verifyResponse(
        getConfigWithFilter("messages/mapping/filters/get-config-empty-filter.xml"),
        XmlFileLoader.xmlFileToDocument("messages/mapping/get-empty-response.xml"));
    verifyResponse(
        getWithFilter("messages/mapping/filters/get-empty-filter.xml"),
        XmlFileLoader.xmlFileToDocument("messages/mapping/get-empty-response.xml"));

    verifyResponse(
        getConfigCandidate(),
        XmlFileLoader.xmlFileToDocument("messages/mapping/get-empty-response.xml"));
    verifyResponse(
        getConfigRunning(),
        XmlFileLoader.xmlFileToDocument("messages/mapping/get-empty-response.xml"));
    verifyResponse(
        getConfigWithFilter("messages/mapping/filters/get-filter-users.xml"),
        XmlFileLoader.xmlFileToDocument("messages/mapping/get-empty-response.xml"));

    verifyResponse(
        edit("messages/mapping/editConfigs/editConfig-filtering-setup.xml"), RPC_REPLY_OK);
    verifyResponse(commit(), RPC_REPLY_OK);

    // TODO uncomment these tests once we can parse KeyedListNode as a selection node, currently you
    // cannot use a KeyedList as a selection node in filter
    //        verifyFilterIdentifier("messages/mapping/filters/get-filter-alluser.xml",
    //                YangInstanceIdentifier.builder().node(TOP).node(USERS).node(USER).build());
    verifyFilterIdentifier(
        "messages/mapping/filters/get-filter-company-info.xml",
        YangInstanceIdentifier.builder().node(TOP).node(USERS).node(USER).build());
    verifyFilterIdentifier(
        "messages/mapping/filters/get-filter-modules-and-admin.xml",
        YangInstanceIdentifier.builder().node(TOP).build());
    verifyFilterIdentifier(
        "messages/mapping/filters/get-filter-only-names-types.xml",
        YangInstanceIdentifier.builder().node(TOP).node(USERS).node(USER).build());
    //
    // verifyFilterIdentifier("messages/mapping/filters/get-filter-specific-module-type-and-user.xml",
    //                YangInstanceIdentifier.builder().node(TOP).build());
    //        verifyFilterIdentifier("messages/mapping/filters/get-filter-superuser.xml",
    //                YangInstanceIdentifier.builder().node(TOP).node(USERS).node(USER).build());
    verifyFilterIdentifier(
        "messages/mapping/filters/get-filter-users.xml",
        YangInstanceIdentifier.builder().node(TOP).node(USERS).build());

    YangInstanceIdentifier ident =
        YangInstanceIdentifier.builder(AUGMENTED_CONTAINER_IN_MODULES)
            .node(AUGMENTED_CONTAINER)
            .node(AUGMENTED_STRING_IN_CONT)
            .build();

    verifyFilterIdentifier("messages/mapping/filters/get-filter-augmented-string.xml", ident);
    verifyFilterIdentifier(
        "messages/mapping/filters/get-filter-augmented-case.xml",
        YangInstanceIdentifier.builder().node(TOP).node(CHOICE_NODE).node(AUGMENTED_CASE).build());

    verifyResponse(
        getConfigWithFilter("messages/mapping/filters/get-filter-augmented-case.xml"),
        XmlFileLoader.xmlFileToDocument("messages/mapping/filters/response-augmented-case.xml"));

    /*
     *  RFC6020 requires that at most once case inside a choice is present at any time.
     *  Therefore
     *  <augmented-case>augmented case</augmented-case>
     *  from
     *  messages/mapping/editConfigs/editConfig-filtering-setup.xml
     *  cannot exists together with
     *  <text>augmented nested choice text1</text>
     *  from
     *  messages/mapping/editConfigs/editConfig-filtering-setup2.xml
     */
    // verifyResponse(edit("messages/mapping/editConfigs/editConfig-filtering-setup2.xml"),
    // RPC_REPLY_OK);
    // verifyResponse(commit(), RPC_REPLY_OK);

    //
    // verifyFilterIdentifier("messages/mapping/filters/get-filter-augmented-case-inner-choice.xml",
    //
    // YangInstanceIdentifier.builder().node(TOP).node(CHOICE_NODE).node(CHOICE_WRAPPER).build());
    //
    // verifyFilterIdentifier("messages/mapping/filters/get-filter-augmented-case-inner-case.xml",
    //
    // YangInstanceIdentifier.builder().node(TOP).node(CHOICE_NODE).node(CHOICE_WRAPPER).node(INNER_CHOICE).node(INNER_CHOICE_TEXT).build());

    //
    // verifyResponse(getConfigWithFilter("messages/mapping/filters/get-filter-augmented-string.xml"),
    //
    // XmlFileLoader.xmlFileToDocument("messages/mapping/filters/response-augmented-string.xml"));
    //
    // verifyResponse(getConfigWithFilter("messages/mapping/filters/get-filter-augmented-case-inner-choice.xml"),
    //
    // XmlFileLoader.xmlFileToDocument("messages/mapping/filters/response-augmented-case-inner-choice.xml"));
    //
    // verifyResponse(getConfigWithFilter("messages/mapping/filters/get-filter-augmented-case-inner-case.xml"),
    //
    // XmlFileLoader.xmlFileToDocument("messages/mapping/filters/response-augmented-case-inner-choice.xml"));

    verifyResponse(edit("messages/mapping/editConfigs/editConfig_delete-top.xml"), RPC_REPLY_OK);
    verifyResponse(commit(), RPC_REPLY_OK);
  }