NETCONF-536: support for <candidate> validation 17/70917/4
authorMarek Gradzki <mgradzki@cisco.com>
Wed, 28 Mar 2018 19:52:41 +0000 (21:52 +0200)
committerMarek Gradzki <mgradzki@cisco.com>
Thu, 3 May 2018 08:59:59 +0000 (10:59 +0200)
Provides support <validate> RPC, as defined in:
https://tools.ietf.org/html/rfc4741#section-8.6.

Only <candidate> datastore is supported.

Support for test-option and capability advertisement
are not included in this patch.

The actual implementation of validation process is delegated to
DOMDataTransactionValidator - an DOMDataBrokerExtension.

Change-Id: I4bbaba18d2e630787d127a51c26918d05fd7e648
Signed-off-by: Marek Gradzki <mgradzki@cisco.com>
netconf/mdsal-netconf-connector/src/main/java/org/opendaylight/netconf/mdsal/connector/DOMDataTransactionValidator.java [new file with mode: 0644]
netconf/mdsal-netconf-connector/src/main/java/org/opendaylight/netconf/mdsal/connector/OperationProvider.java
netconf/mdsal-netconf-connector/src/main/java/org/opendaylight/netconf/mdsal/connector/TransactionProvider.java
netconf/mdsal-netconf-connector/src/main/java/org/opendaylight/netconf/mdsal/connector/ops/AbstractConfigOperation.java [new file with mode: 0644]
netconf/mdsal-netconf-connector/src/main/java/org/opendaylight/netconf/mdsal/connector/ops/AbstractEdit.java
netconf/mdsal-netconf-connector/src/main/java/org/opendaylight/netconf/mdsal/connector/ops/Validate.java [new file with mode: 0644]
netconf/mdsal-netconf-connector/src/test/java/org/opendaylight/netconf/mdsal/connector/ops/ValidateTest.java [new file with mode: 0644]
netconf/mdsal-netconf-connector/src/test/resources/messages/mapping/validate/validate.xml [new file with mode: 0644]
netconf/mdsal-netconf-connector/src/test/resources/messages/mapping/validate/validate_no_source.xml [new file with mode: 0644]
netconf/mdsal-netconf-connector/src/test/resources/messages/mapping/validate/validate_running.xml [new file with mode: 0644]

diff --git a/netconf/mdsal-netconf-connector/src/main/java/org/opendaylight/netconf/mdsal/connector/DOMDataTransactionValidator.java b/netconf/mdsal-netconf-connector/src/main/java/org/opendaylight/netconf/mdsal/connector/DOMDataTransactionValidator.java
new file mode 100644 (file)
index 0000000..9d4aa7d
--- /dev/null
@@ -0,0 +1,62 @@
+/*
+ * Copyright (c) 2018 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+
+package org.opendaylight.netconf.mdsal.connector;
+
+import com.google.common.annotations.Beta;
+import com.google.common.util.concurrent.CheckedFuture;
+import org.opendaylight.controller.md.sal.dom.api.DOMDataBroker;
+import org.opendaylight.controller.md.sal.dom.api.DOMDataBrokerExtension;
+import org.opendaylight.controller.md.sal.dom.api.DOMDataWriteTransaction;
+import org.opendaylight.controller.md.sal.dom.api.DOMServiceExtension;
+import org.opendaylight.yangtools.yang.common.OperationFailedException;
+import org.opendaylight.yangtools.yang.common.RpcError;
+import org.opendaylight.yangtools.yang.common.RpcResultBuilder;
+
+/**
+ * A {@link DOMServiceExtension} which allows users to provide Validate capability for {@link DOMDataBroker}.
+ *
+ * <p> See <a href="https://tools.ietf.org/html/rfc4741#section-8.6">RFC4741 section 8.6</a> for details.
+ */
+@Beta
+public interface DOMDataTransactionValidator extends DOMDataBrokerExtension {
+    /**
+     * Validates state of the data tree associated with the provided {@link DOMDataWriteTransaction}.
+     *
+     * <p>The operation should not have any side-effects on the transaction state.
+     *
+     * <p>It can be executed many times, providing the same results if the state of the transaction has not been
+     * changed.
+     *
+     * @param transaction
+     *     transaction to be validated
+     * @return
+     *     a CheckedFuture containing the result of the validate operation. The future blocks until the validation
+     *     operation is complete. A successful validate returns nothing. On failure, the Future will fail
+     *     with a {@link ValidationFailedException} or an exception derived from ValidationFailedException.
+     */
+    CheckedFuture<Void, ValidationFailedException> validate(DOMDataWriteTransaction transaction);
+
+    /**
+     * Failed validation of asynchronous transaction. This exception is raised and returned when transaction validation
+     * failed.
+     */
+    class ValidationFailedException extends OperationFailedException {
+        private static final long serialVersionUID = 1L;
+
+        public ValidationFailedException(final String message, final Throwable cause) {
+            super(message, cause, RpcResultBuilder.newError(RpcError.ErrorType.APPLICATION, "invalid-value", message,
+                null, null, cause));
+        }
+
+        public ValidationFailedException(final String message) {
+            this(message, null);
+        }
+    }
+}
+
index 59ccc29f084472546ec3c8adfaf7e54161e28077..ddf713f6a4fb883a8cc0a363055279f53bbebb4d 100644 (file)
@@ -20,6 +20,7 @@ import org.opendaylight.netconf.mdsal.connector.ops.EditConfig;
 import org.opendaylight.netconf.mdsal.connector.ops.Lock;
 import org.opendaylight.netconf.mdsal.connector.ops.RuntimeRpc;
 import org.opendaylight.netconf.mdsal.connector.ops.Unlock;
+import org.opendaylight.netconf.mdsal.connector.ops.Validate;
 import org.opendaylight.netconf.mdsal.connector.ops.get.Get;
 import org.opendaylight.netconf.mdsal.connector.ops.get.GetConfig;
 
@@ -41,7 +42,8 @@ final class OperationProvider {
             new GetConfig(netconfSessionIdForReporting, schemaContext, transactionProvider),
             new Lock(netconfSessionIdForReporting),
             new Unlock(netconfSessionIdForReporting),
-            new RuntimeRpc(netconfSessionIdForReporting, schemaContext, rpcService));
+            new RuntimeRpc(netconfSessionIdForReporting, schemaContext, rpcService),
+            new Validate(netconfSessionIdForReporting, transactionProvider));
     }
 
     Set<NetconfOperation> getOperations() {
index b906b741e14c4d81dbd1c8f32702ab806e49d973..768c7f2c2372b75f5e569cda775848680cbc55c4 100644 (file)
@@ -8,6 +8,8 @@
 
 package org.opendaylight.netconf.mdsal.connector;
 
+import static org.opendaylight.netconf.mdsal.connector.DOMDataTransactionValidator.ValidationFailedException;
+
 import com.google.common.base.Optional;
 import com.google.common.base.Preconditions;
 import com.google.common.util.concurrent.CheckedFuture;
@@ -32,6 +34,7 @@ public class TransactionProvider implements AutoCloseable {
     private DOMDataReadWriteTransaction candidateTransaction = null;
     private DOMDataReadWriteTransaction runningTransaction = null;
     private final List<DOMDataReadWriteTransaction> allOpenReadWriteTransactions = new ArrayList<>();
+    private final DOMDataTransactionValidator transactionValidator;
 
     private final String netconfSessionIdForReporting;
 
@@ -40,6 +43,8 @@ public class TransactionProvider implements AutoCloseable {
     public TransactionProvider(final DOMDataBroker dataBroker, final String netconfSessionIdForReporting) {
         this.dataBroker = dataBroker;
         this.netconfSessionIdForReporting = netconfSessionIdForReporting;
+        this.transactionValidator = (DOMDataTransactionValidator)dataBroker.getSupportedExtensions()
+            .get(DOMDataTransactionValidator.class);
     }
 
     @Override
@@ -69,6 +74,32 @@ public class TransactionProvider implements AutoCloseable {
         return candidateTransaction;
     }
 
+    public synchronized void validateTransaction() throws DocumentedException {
+        if (transactionValidator == null) {
+            LOG.error("Validate capability is not supported");
+            throw new DocumentedException("Validate capability is not supported",
+                ErrorType.PROTOCOL, ErrorTag.OPERATION_NOT_SUPPORTED, ErrorSeverity.ERROR);
+        }
+
+        if (!getCandidateTransaction().isPresent()) {
+            // Validating empty transaction, just return true
+            LOG.debug("Validating empty candidate transaction for session {}", netconfSessionIdForReporting);
+            return;
+        }
+
+        try {
+            transactionValidator.validate(candidateTransaction).checkedGet();
+        } catch (final ValidationFailedException e) {
+            LOG.debug("Candidate transaction validation {} failed on session {}", candidateTransaction,
+                netconfSessionIdForReporting, e);
+            final String cause = e.getCause() != null ? (" Cause: " + e.getCause().getMessage()) : "";
+            throw new DocumentedException(
+                "Candidate transaction validate failed on " + e.getMessage() + " " + netconfSessionIdForReporting
+                    +  cause, e, ErrorType.APPLICATION, ErrorTag.OPERATION_FAILED, ErrorSeverity.ERROR);
+        }
+        return;
+    }
+
     public synchronized boolean commitTransaction() throws DocumentedException {
         if (!getCandidateTransaction().isPresent()) {
             //making empty commit without prior opened transaction, just return true
diff --git a/netconf/mdsal-netconf-connector/src/main/java/org/opendaylight/netconf/mdsal/connector/ops/AbstractConfigOperation.java b/netconf/mdsal-netconf-connector/src/main/java/org/opendaylight/netconf/mdsal/connector/ops/AbstractConfigOperation.java
new file mode 100644 (file)
index 0000000..cfeddcd
--- /dev/null
@@ -0,0 +1,37 @@
+/*
+ * Copyright (c) 2018 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+
+package org.opendaylight.netconf.mdsal.connector.ops;
+
+import com.google.common.base.Strings;
+import org.opendaylight.netconf.api.DocumentedException;
+import org.opendaylight.netconf.api.xml.XmlElement;
+import org.opendaylight.netconf.util.mapping.AbstractSingletonNetconfOperation;
+import org.w3c.dom.Element;
+import org.w3c.dom.NodeList;
+
+abstract class AbstractConfigOperation extends AbstractSingletonNetconfOperation {
+
+    protected AbstractConfigOperation(final String netconfSessionIdForReporting) {
+        super(netconfSessionIdForReporting);
+    }
+
+    protected static NodeList getElementsByTagName(final XmlElement parent, final String key) throws
+        DocumentedException {
+        final Element domParent = parent.getDomElement();
+        final NodeList elementsByTagName;
+
+        if (Strings.isNullOrEmpty(domParent.getPrefix())) {
+            elementsByTagName = domParent.getElementsByTagName(key);
+        } else {
+            elementsByTagName = domParent.getElementsByTagNameNS(parent.getNamespace(), key);
+        }
+
+        return elementsByTagName;
+    }
+}
index 0efeab08ad45a1c63f2b70ae76c19b1c45e3b1b3..b68e17aacfcd052ee3e66d8e4e4a7db962754d85 100644 (file)
@@ -9,7 +9,6 @@
 package org.opendaylight.netconf.mdsal.connector.ops;
 
 import com.google.common.base.Optional;
-import com.google.common.base.Strings;
 import com.google.common.collect.ImmutableMap;
 import java.net.URI;
 import java.net.URISyntaxException;
@@ -23,7 +22,6 @@ import org.opendaylight.netconf.api.DocumentedException.ErrorType;
 import org.opendaylight.netconf.api.NetconfDocumentedException;
 import org.opendaylight.netconf.api.xml.XmlElement;
 import org.opendaylight.netconf.mdsal.connector.CurrentSchemaContext;
-import org.opendaylight.netconf.util.mapping.AbstractSingletonNetconfOperation;
 import org.opendaylight.yangtools.yang.common.QName;
 import org.opendaylight.yangtools.yang.data.api.schema.stream.NormalizedNodeStreamWriter;
 import org.opendaylight.yangtools.yang.data.codec.xml.XmlParserStream;
@@ -36,7 +34,7 @@ import org.slf4j.LoggerFactory;
 import org.w3c.dom.Element;
 import org.w3c.dom.NodeList;
 
-abstract class AbstractEdit extends AbstractSingletonNetconfOperation {
+abstract class AbstractEdit extends AbstractConfigOperation {
     private static final Logger LOG = LoggerFactory.getLogger(AbstractEdit.class);
     private static final String TARGET_KEY = "target";
 
@@ -129,18 +127,4 @@ abstract class AbstractEdit extends AbstractSingletonNetconfOperation {
 
         return childNode.get();
     }
-
-    protected static NodeList getElementsByTagName(final XmlElement parent, final String key) throws
-        DocumentedException {
-        final Element domParent = parent.getDomElement();
-        final NodeList elementsByTagName;
-
-        if (Strings.isNullOrEmpty(domParent.getPrefix())) {
-            elementsByTagName = domParent.getElementsByTagName(key);
-        } else {
-            elementsByTagName = domParent.getElementsByTagNameNS(parent.getNamespace(), key);
-        }
-
-        return elementsByTagName;
-    }
 }
diff --git a/netconf/mdsal-netconf-connector/src/main/java/org/opendaylight/netconf/mdsal/connector/ops/Validate.java b/netconf/mdsal-netconf-connector/src/main/java/org/opendaylight/netconf/mdsal/connector/ops/Validate.java
new file mode 100644 (file)
index 0000000..4792dd7
--- /dev/null
@@ -0,0 +1,79 @@
+/*
+ * Copyright (c) 2018 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+
+package org.opendaylight.netconf.mdsal.connector.ops;
+
+import com.google.common.base.Optional;
+import com.google.common.collect.ImmutableMap;
+import java.util.Map;
+import org.opendaylight.netconf.api.DocumentedException;
+import org.opendaylight.netconf.api.DocumentedException.ErrorSeverity;
+import org.opendaylight.netconf.api.DocumentedException.ErrorTag;
+import org.opendaylight.netconf.api.DocumentedException.ErrorType;
+import org.opendaylight.netconf.api.xml.XmlElement;
+import org.opendaylight.netconf.api.xml.XmlNetconfConstants;
+import org.opendaylight.netconf.api.xml.XmlUtil;
+import org.opendaylight.netconf.mdsal.connector.TransactionProvider;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
+import org.w3c.dom.NodeList;
+
+public final class Validate extends AbstractConfigOperation {
+    private static final Logger LOG = LoggerFactory.getLogger(Validate.class);
+    private static final String OPERATION_NAME = "validate";
+    private static final String SOURCE_KEY = "source";
+
+    private final TransactionProvider transactionProvider;
+
+    public Validate(final String netconfSessionIdForReporting, final TransactionProvider transactionProvider) {
+        super(netconfSessionIdForReporting);
+        this.transactionProvider = transactionProvider;
+    }
+
+    @Override
+    protected Element handleWithNoSubsequentOperations(final Document document, final XmlElement operationElement)
+        throws DocumentedException {
+        final Datastore targetDatastore = extractSourceParameter(operationElement, OPERATION_NAME);
+        if (targetDatastore != Datastore.candidate) {
+            throw new DocumentedException("<validate> is only supported on candidate datastore",
+                DocumentedException.ErrorType.PROTOCOL,
+                ErrorTag.OPERATION_NOT_SUPPORTED,
+                ErrorSeverity.ERROR);
+        }
+
+        transactionProvider.validateTransaction();
+        LOG.trace("<validate> request completed successfully on session {}", getNetconfSessionIdForReporting());
+        return XmlUtil.createElement(document, XmlNetconfConstants.OK, Optional.absent());
+    }
+
+    protected static Datastore extractSourceParameter(final XmlElement operationElement, final String operationName)
+        throws DocumentedException {
+        final NodeList elementsByTagName = getElementsByTagName(operationElement, SOURCE_KEY);
+        // Direct lookup instead of using XmlElement class due to performance
+        if (elementsByTagName.getLength() == 0) {
+            final Map<String, String> errorInfo = ImmutableMap.of("bad-attribute", SOURCE_KEY, "bad-element",
+                operationName);
+            throw new DocumentedException("Missing source element", ErrorType.PROTOCOL, ErrorTag.MISSING_ELEMENT,
+                ErrorSeverity.ERROR, errorInfo);
+        } else if (elementsByTagName.getLength() > 1) {
+            throw new DocumentedException("Multiple source elements", ErrorType.RPC, ErrorTag.UNKNOWN_ATTRIBUTE,
+                ErrorSeverity.ERROR);
+        } else {
+            final XmlElement sourceChildNode =
+                XmlElement.fromDomElement((Element) elementsByTagName.item(0)).getOnlyChildElement();
+            return Datastore.valueOf(sourceChildNode.getName());
+        }
+    }
+
+    @Override
+    protected String getOperationName() {
+        return OPERATION_NAME;
+    }
+}
diff --git a/netconf/mdsal-netconf-connector/src/test/java/org/opendaylight/netconf/mdsal/connector/ops/ValidateTest.java b/netconf/mdsal-netconf-connector/src/test/java/org/opendaylight/netconf/mdsal/connector/ops/ValidateTest.java
new file mode 100644 (file)
index 0000000..a035c82
--- /dev/null
@@ -0,0 +1,149 @@
+/*
+ * Copyright (c) 2018 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+
+package org.opendaylight.netconf.mdsal.connector.ops;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.fail;
+import static org.mockito.Matchers.any;
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.verifyZeroInteractions;
+import static org.mockito.MockitoAnnotations.initMocks;
+import static org.opendaylight.netconf.mdsal.connector.ops.AbstractNetconfOperationTest.RPC_REPLY_OK;
+import static org.opendaylight.netconf.mdsal.connector.ops.AbstractNetconfOperationTest.SESSION_ID_FOR_REPORTING;
+import static org.opendaylight.netconf.mdsal.connector.ops.AbstractNetconfOperationTest.executeOperation;
+import static org.opendaylight.netconf.mdsal.connector.ops.AbstractNetconfOperationTest.verifyResponse;
+
+import com.google.common.util.concurrent.Futures;
+import java.util.Collections;
+import org.custommonkey.xmlunit.XMLUnit;
+import org.junit.Before;
+import org.junit.Test;
+import org.mockito.Mock;
+import org.opendaylight.controller.md.sal.dom.api.DOMDataBroker;
+import org.opendaylight.controller.md.sal.dom.api.DOMDataReadWriteTransaction;
+import org.opendaylight.netconf.api.DocumentedException;
+import org.opendaylight.netconf.mdsal.connector.DOMDataTransactionValidator;
+import org.opendaylight.netconf.mdsal.connector.DOMDataTransactionValidator.ValidationFailedException;
+import org.opendaylight.netconf.mdsal.connector.TransactionProvider;
+import org.w3c.dom.Document;
+
+public class ValidateTest {
+    @Mock
+    private DOMDataTransactionValidator noopValidator;
+    @Mock
+    private DOMDataTransactionValidator failingValidator;
+    @Mock
+    private DOMDataReadWriteTransaction readWriteTx;
+    @Mock
+    private DOMDataBroker dataBroker;
+
+    @Before
+    public void setUp() throws Exception {
+        initMocks(this);
+        doReturn(Futures.immediateCheckedFuture(null)).when(noopValidator).validate(any());
+        doReturn(Futures.immediateFailedCheckedFuture(new ValidationFailedException("invalid data")))
+            .when(failingValidator).validate(any());
+        doReturn(readWriteTx).when(dataBroker).newReadWriteTransaction();
+        XMLUnit.setIgnoreWhitespace(true);
+    }
+
+    @Test
+    public void testValidateUnsupported() throws Exception {
+        whenValidatorIsNotDefined();
+        try {
+            validate("messages/mapping/validate/validate.xml");
+            fail("Should have failed - <validate> not supported");
+        } catch (final DocumentedException e) {
+            assertEquals(DocumentedException.ErrorSeverity.ERROR, e.getErrorSeverity());
+            assertEquals(DocumentedException.ErrorTag.OPERATION_NOT_SUPPORTED, e.getErrorTag());
+            assertEquals(DocumentedException.ErrorType.PROTOCOL, e.getErrorType());
+        }
+    }
+
+    @Test
+    public void testSourceMissing() throws Exception {
+        whenUsingValidator(noopValidator);
+        try {
+            validate("messages/mapping/validate/validate_no_source.xml");
+            fail("Should have failed - <source> element is missing");
+        } catch (final DocumentedException e) {
+            assertEquals(DocumentedException.ErrorSeverity.ERROR, e.getErrorSeverity());
+            assertEquals(DocumentedException.ErrorTag.MISSING_ELEMENT, e.getErrorTag());
+            assertEquals(DocumentedException.ErrorType.PROTOCOL, e.getErrorType());
+        }
+    }
+
+    @Test
+    public void testSourceRunning() throws Exception {
+        whenUsingValidator(noopValidator);
+        try {
+            validate("messages/mapping/validate/validate_running.xml");
+            fail("Should have failed - <running/> is not supported");
+        } catch (final DocumentedException e) {
+            assertEquals(DocumentedException.ErrorSeverity.ERROR, e.getErrorSeverity());
+            assertEquals(DocumentedException.ErrorTag.OPERATION_NOT_SUPPORTED, e.getErrorTag());
+            assertEquals(DocumentedException.ErrorType.PROTOCOL, e.getErrorType());
+        }
+    }
+
+    @Test
+    public void testValidateEmptyTx() throws Exception {
+        whenUsingValidator(noopValidator);
+        verifyResponse(validate("messages/mapping/validate/validate.xml"), RPC_REPLY_OK);
+        verifyZeroInteractions(noopValidator);
+    }
+
+    @Test
+    public void testValidate() throws Exception {
+        whenUsingValidator(noopValidator);
+        final TransactionProvider transactionProvider = initCandidateTransaction();
+        verifyResponse(validate("messages/mapping/validate/validate.xml", transactionProvider), RPC_REPLY_OK);
+        verify(noopValidator).validate(readWriteTx);
+    }
+
+    @Test
+    public void testValidateFailed() throws Exception {
+        whenUsingValidator(failingValidator);
+        final TransactionProvider transactionProvider = initCandidateTransaction();
+        try {
+            validate("messages/mapping/validate/validate.xml", transactionProvider);
+            fail("Should have failed - operation failed");
+        } catch (final DocumentedException e) {
+            assertEquals(DocumentedException.ErrorSeverity.ERROR, e.getErrorSeverity());
+            assertEquals(DocumentedException.ErrorTag.OPERATION_FAILED, e.getErrorTag());
+            assertEquals(DocumentedException.ErrorType.APPLICATION, e.getErrorType());
+        }
+    }
+
+    private void whenValidatorIsNotDefined() {
+        doReturn(Collections.emptyMap()).when(dataBroker).getSupportedExtensions();
+    }
+
+    private void whenUsingValidator(final DOMDataTransactionValidator validator) {
+        doReturn(Collections.singletonMap(DOMDataTransactionValidator.class, validator))
+            .when(dataBroker).getSupportedExtensions();
+    }
+
+    private TransactionProvider initCandidateTransaction() {
+        final TransactionProvider transactionProvider = new TransactionProvider(dataBroker, SESSION_ID_FOR_REPORTING);
+        transactionProvider.getOrCreateTransaction();
+        return transactionProvider;
+    }
+
+    private Document validate(final String resource,
+                              final TransactionProvider transactionProvider) throws Exception {
+        final Validate validate = new Validate(SESSION_ID_FOR_REPORTING, transactionProvider);
+        return executeOperation(validate, resource);
+    }
+
+    private Document validate(final String resource) throws Exception {
+        return validate(resource, new TransactionProvider(dataBroker, SESSION_ID_FOR_REPORTING));
+    }
+}
\ No newline at end of file
diff --git a/netconf/mdsal-netconf-connector/src/test/resources/messages/mapping/validate/validate.xml b/netconf/mdsal-netconf-connector/src/test/resources/messages/mapping/validate/validate.xml
new file mode 100644 (file)
index 0000000..99f3ec3
--- /dev/null
@@ -0,0 +1,15 @@
+<!--
+  ~ Copyright (c) 2018 Cisco Systems, Inc. and others.  All rights reserved.
+  ~
+  ~ This program and the accompanying materials are made available under the
+  ~ terms of the Eclipse Public License v1.0 which accompanies this distribution,
+  ~ and is available at http://www.eclipse.org/legal/epl-v10.html
+  -->
+
+<rpc message-id="a" a="64" xmlns="urn:ietf:params:xml:ns:netconf:base:1.0">
+    <validate>
+        <source>
+            <candidate/>
+        </source>
+    </validate>
+</rpc>
\ No newline at end of file
diff --git a/netconf/mdsal-netconf-connector/src/test/resources/messages/mapping/validate/validate_no_source.xml b/netconf/mdsal-netconf-connector/src/test/resources/messages/mapping/validate/validate_no_source.xml
new file mode 100644 (file)
index 0000000..819ace8
--- /dev/null
@@ -0,0 +1,11 @@
+<!--
+  ~ Copyright (c) 2018 Cisco Systems, Inc. and others.  All rights reserved.
+  ~
+  ~ This program and the accompanying materials are made available under the
+  ~ terms of the Eclipse Public License v1.0 which accompanies this distribution,
+  ~ and is available at http://www.eclipse.org/legal/epl-v10.html
+  -->
+
+<rpc message-id="a" a="64" xmlns="urn:ietf:params:xml:ns:netconf:base:1.0">
+    <validate/>
+</rpc>
\ No newline at end of file
diff --git a/netconf/mdsal-netconf-connector/src/test/resources/messages/mapping/validate/validate_running.xml b/netconf/mdsal-netconf-connector/src/test/resources/messages/mapping/validate/validate_running.xml
new file mode 100644 (file)
index 0000000..5f2af34
--- /dev/null
@@ -0,0 +1,15 @@
+<!--
+  ~ Copyright (c) 2018 Cisco Systems, Inc. and others.  All rights reserved.
+  ~
+  ~ This program and the accompanying materials are made available under the
+  ~ terms of the Eclipse Public License v1.0 which accompanies this distribution,
+  ~ and is available at http://www.eclipse.org/legal/epl-v10.html
+  -->
+
+<rpc message-id="a" a="64" xmlns="urn:ietf:params:xml:ns:netconf:base:1.0">
+    <validate>
+        <source>
+            <running/>
+        </source>
+    </validate>
+</rpc>
\ No newline at end of file