summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--infra/data-impl/pom.xml16
-rw-r--r--infra/data-impl/src/main/java/io/fd/honeycomb/data/impl/DataBroker.java6
-rw-r--r--infra/data-impl/src/main/java/io/fd/honeycomb/data/impl/ReadWriteTransaction.java12
-rw-r--r--infra/data-impl/src/main/java/io/fd/honeycomb/data/impl/ValidableTransaction.java45
-rw-r--r--infra/data-impl/src/main/java/io/fd/honeycomb/data/impl/WriteTransaction.java35
-rw-r--r--infra/data-impl/src/test/java/io/fd/honeycomb/data/impl/DataBrokerTest.java6
-rw-r--r--infra/data-impl/src/test/java/io/fd/honeycomb/data/impl/ReadWriteTransactionTest.java3
-rw-r--r--infra/data-impl/src/test/java/io/fd/honeycomb/data/impl/ValidateTest.java217
-rw-r--r--infra/data-impl/src/test/java/io/fd/honeycomb/data/impl/WriteTransactionTest.java1
-rw-r--r--infra/data-impl/src/test/resources/messages/rpc-reply_ok.xml19
-rw-r--r--infra/data-impl/src/test/resources/messages/validate/commit.xml19
-rw-r--r--infra/data-impl/src/test/resources/messages/validate/edit-config-create-top-container.xml28
-rw-r--r--infra/data-impl/src/test/resources/messages/validate/edit-config-missing-mandatory-node.xml35
-rw-r--r--infra/data-impl/src/test/resources/messages/validate/validate.xml23
-rw-r--r--infra/data-impl/src/test/resources/test-validate.yang27
15 files changed, 470 insertions, 22 deletions
diff --git a/infra/data-impl/pom.xml b/infra/data-impl/pom.xml
index 6abc1892d..fa6e11704 100644
--- a/infra/data-impl/pom.xml
+++ b/infra/data-impl/pom.xml
@@ -62,6 +62,10 @@
<groupId>org.opendaylight.controller</groupId>
<artifactId>sal-core-spi</artifactId>
</dependency>
+ <dependency>
+ <groupId>org.opendaylight.netconf</groupId>
+ <artifactId>mdsal-netconf-connector</artifactId>
+ </dependency>
<dependency>
<groupId>junit</groupId>
@@ -83,6 +87,18 @@
<artifactId>yang-test-util</artifactId>
<scope>test</scope>
</dependency>
+ <dependency>
+ <groupId>xmlunit</groupId>
+ <artifactId>xmlunit</artifactId>
+ <version>1.6</version>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.opendaylight.netconf</groupId>
+ <artifactId>netconf-util</artifactId>
+ <type>test-jar</type>
+ <scope>test</scope>
+ </dependency>
</dependencies>
<build>
diff --git a/infra/data-impl/src/main/java/io/fd/honeycomb/data/impl/DataBroker.java b/infra/data-impl/src/main/java/io/fd/honeycomb/data/impl/DataBroker.java
index a60bf3415..1952f8778 100644
--- a/infra/data-impl/src/main/java/io/fd/honeycomb/data/impl/DataBroker.java
+++ b/infra/data-impl/src/main/java/io/fd/honeycomb/data/impl/DataBroker.java
@@ -33,6 +33,7 @@ import org.opendaylight.controller.md.sal.dom.api.DOMDataReadOnlyTransaction;
import org.opendaylight.controller.md.sal.dom.api.DOMDataReadWriteTransaction;
import org.opendaylight.controller.md.sal.dom.api.DOMDataWriteTransaction;
import org.opendaylight.controller.md.sal.dom.api.DOMTransactionChain;
+import org.opendaylight.netconf.mdsal.connector.DOMDataTransactionValidator;
import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -81,7 +82,10 @@ public class DataBroker implements DOMDataBroker, Closeable {
@Nonnull
@Override
public Map<Class<? extends DOMDataBrokerExtension>, DOMDataBrokerExtension> getSupportedExtensions() {
- return Collections.emptyMap();
+ return Collections.singletonMap(
+ DOMDataTransactionValidator.class,
+ (DOMDataTransactionValidator) tx -> ((ValidableTransaction)tx).validate()
+ );
}
/**
diff --git a/infra/data-impl/src/main/java/io/fd/honeycomb/data/impl/ReadWriteTransaction.java b/infra/data-impl/src/main/java/io/fd/honeycomb/data/impl/ReadWriteTransaction.java
index f26810e15..c7d54f0ec 100644
--- a/infra/data-impl/src/main/java/io/fd/honeycomb/data/impl/ReadWriteTransaction.java
+++ b/infra/data-impl/src/main/java/io/fd/honeycomb/data/impl/ReadWriteTransaction.java
@@ -31,6 +31,7 @@ import org.opendaylight.controller.md.sal.dom.api.DOMDataReadTransaction;
import org.opendaylight.controller.md.sal.dom.api.DOMDataReadWriteTransaction;
import org.opendaylight.controller.md.sal.dom.api.DOMDataWriteTransaction;
import org.opendaylight.mdsal.common.api.CommitInfo;
+import org.opendaylight.netconf.mdsal.connector.DOMDataTransactionValidator;
import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
import org.slf4j.Logger;
@@ -40,15 +41,15 @@ import org.slf4j.LoggerFactory;
* Composite DOM transaction that delegates reads to a {@link DOMDataReadTransaction} delegate and writes to a {@link
* DOMDataWriteTransaction} delegate.
*/
-final class ReadWriteTransaction implements DOMDataReadWriteTransaction {
+final class ReadWriteTransaction implements DOMDataReadWriteTransaction, ValidableTransaction {
private static final Logger LOG = LoggerFactory.getLogger(ReadWriteTransaction.class);
private final DOMDataReadOnlyTransaction delegateReadTx;
- private final DOMDataWriteTransaction delegateWriteTx;
+ private final ValidableTransaction delegateWriteTx;
ReadWriteTransaction(@Nonnull final DOMDataReadOnlyTransaction delegateReadTx,
- @Nonnull final DOMDataWriteTransaction delegateWriteTx) {
+ @Nonnull final ValidableTransaction delegateWriteTx) {
this.delegateReadTx = Preconditions.checkNotNull(delegateReadTx, "delegateReadTx should not be null");
this.delegateWriteTx = Preconditions.checkNotNull(delegateWriteTx, "delegateWriteTx should not be null");
}
@@ -111,5 +112,10 @@ final class ReadWriteTransaction implements DOMDataReadWriteTransaction {
public Object getIdentifier() {
return this;
}
+
+ @Override
+ public CheckedFuture<Void, DOMDataTransactionValidator.ValidationFailedException> validate() {
+ return delegateWriteTx.validate();
+ }
}
diff --git a/infra/data-impl/src/main/java/io/fd/honeycomb/data/impl/ValidableTransaction.java b/infra/data-impl/src/main/java/io/fd/honeycomb/data/impl/ValidableTransaction.java
new file mode 100644
index 000000000..0c67f863f
--- /dev/null
+++ b/infra/data-impl/src/main/java/io/fd/honeycomb/data/impl/ValidableTransaction.java
@@ -0,0 +1,45 @@
+/*
+ * Copyright (c) 2018 Cisco and/or its affiliates.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package io.fd.honeycomb.data.impl;
+
+import com.google.common.annotations.Beta;
+import com.google.common.util.concurrent.CheckedFuture;
+import org.opendaylight.controller.md.sal.dom.api.DOMDataWriteTransaction;
+import org.opendaylight.netconf.mdsal.connector.DOMDataTransactionValidator;
+import org.opendaylight.netconf.mdsal.connector.DOMDataTransactionValidator.ValidationFailedException;
+
+/**
+ * An {@link DOMDataWriteTransaction} than can be validated.
+ * @see DOMDataTransactionValidator
+ */
+@Beta
+interface ValidableTransaction extends DOMDataWriteTransaction {
+ /**
+ * 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.
+ *
+ * @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();
+}
diff --git a/infra/data-impl/src/main/java/io/fd/honeycomb/data/impl/WriteTransaction.java b/infra/data-impl/src/main/java/io/fd/honeycomb/data/impl/WriteTransaction.java
index b2ed5265f..91b48cc10 100644
--- a/infra/data-impl/src/main/java/io/fd/honeycomb/data/impl/WriteTransaction.java
+++ b/infra/data-impl/src/main/java/io/fd/honeycomb/data/impl/WriteTransaction.java
@@ -32,7 +32,7 @@ import javax.annotation.concurrent.NotThreadSafe;
import org.eclipse.jdt.annotation.NonNull;
import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
import org.opendaylight.controller.md.sal.common.api.data.TransactionCommitFailedException;
-import org.opendaylight.controller.md.sal.dom.api.DOMDataWriteTransaction;
+import org.opendaylight.netconf.mdsal.connector.DOMDataTransactionValidator;
import org.opendaylight.mdsal.common.api.CommitInfo;
import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
@@ -40,7 +40,7 @@ import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@NotThreadSafe
-final class WriteTransaction implements DOMDataWriteTransaction {
+final class WriteTransaction implements ValidableTransaction {
private static final Logger LOG = LoggerFactory.getLogger(WriteTransaction.class);
@@ -120,7 +120,7 @@ final class WriteTransaction implements DOMDataWriteTransaction {
checkIsNew();
try {
- validateAndCommit();
+ doCommit();
} catch (Exception e) {
status = TransactionStatus.FAILED;
LOG.error("Submit failed", e);
@@ -130,16 +130,8 @@ final class WriteTransaction implements DOMDataWriteTransaction {
return Futures.immediateCheckedFuture(null);
}
- private void validateAndCommit() throws TranslationException {
+ private void doCommit() throws TranslationException {
status = TransactionStatus.SUBMITED;
- // Validate first to catch any issues before attempting commit
- if (configModification != null) {
- configModification.validate();
- }
- if (operationalModification != null) {
- operationalModification.validate();
- }
-
if (configModification != null) {
configModification.commit();
}
@@ -155,7 +147,7 @@ final class WriteTransaction implements DOMDataWriteTransaction {
LOG.trace("WriteTransaction.commit()");
checkIsNew();
try {
- validateAndCommit();
+ doCommit();
} catch (Exception e) {
status = TransactionStatus.FAILED;
LOG.error("Submit failed", e);
@@ -171,6 +163,21 @@ final class WriteTransaction implements DOMDataWriteTransaction {
return this;
}
+ @Override
+ public CheckedFuture<Void, DOMDataTransactionValidator.ValidationFailedException> validate() {
+ try {
+ if (configModification != null) {
+ configModification.validate();
+ }
+ if (operationalModification != null) {
+ operationalModification.validate();
+ }
+ } catch (Exception e) {
+ return Futures.immediateFailedCheckedFuture(new DOMDataTransactionValidator.ValidationFailedException(e.getMessage(), e.getCause()));
+ }
+ return Futures.immediateCheckedFuture(null);
+ }
+
@Nonnull
static WriteTransaction createOperationalOnly(@Nonnull final DataModification operationalData) {
@@ -188,7 +195,7 @@ final class WriteTransaction implements DOMDataWriteTransaction {
return new WriteTransaction(requireNonNull(configData), requireNonNull(operationalData));
}
- // TODO consider removing because original class was deprecated and removed, this is just temporary fix.
+ // TODO consider refactor based on implemented contract.
enum TransactionStatus {
/**
* The transaction has been freshly allocated. The user is still accessing
diff --git a/infra/data-impl/src/test/java/io/fd/honeycomb/data/impl/DataBrokerTest.java b/infra/data-impl/src/test/java/io/fd/honeycomb/data/impl/DataBrokerTest.java
index 14d32784f..124179c79 100644
--- a/infra/data-impl/src/test/java/io/fd/honeycomb/data/impl/DataBrokerTest.java
+++ b/infra/data-impl/src/test/java/io/fd/honeycomb/data/impl/DataBrokerTest.java
@@ -16,6 +16,8 @@
package io.fd.honeycomb.data.impl;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;
@@ -34,6 +36,7 @@ import org.opendaylight.controller.md.sal.common.api.data.TransactionChainListen
import org.opendaylight.controller.md.sal.dom.api.DOMDataBrokerExtension;
import org.opendaylight.controller.md.sal.dom.api.DOMDataReadOnlyTransaction;
import org.opendaylight.controller.md.sal.dom.api.DOMDataReadWriteTransaction;
+import org.opendaylight.netconf.mdsal.connector.DOMDataTransactionValidator;
import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
public class DataBrokerTest {
@@ -93,7 +96,8 @@ public class DataBrokerTest {
public void testGetSupportedExtensions() {
final Map<Class<? extends DOMDataBrokerExtension>, DOMDataBrokerExtension> supportedExtensions =
broker.getSupportedExtensions();
- assertTrue(supportedExtensions.isEmpty());
+ assertEquals(1, supportedExtensions.size());
+ assertNotNull(supportedExtensions.get(DOMDataTransactionValidator.class));
}
public static class DataBrokerForContextTest {
diff --git a/infra/data-impl/src/test/java/io/fd/honeycomb/data/impl/ReadWriteTransactionTest.java b/infra/data-impl/src/test/java/io/fd/honeycomb/data/impl/ReadWriteTransactionTest.java
index 820d499be..bbe384289 100644
--- a/infra/data-impl/src/test/java/io/fd/honeycomb/data/impl/ReadWriteTransactionTest.java
+++ b/infra/data-impl/src/test/java/io/fd/honeycomb/data/impl/ReadWriteTransactionTest.java
@@ -25,7 +25,6 @@ import org.junit.Test;
import org.mockito.Mock;
import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
import org.opendaylight.controller.md.sal.dom.api.DOMDataReadOnlyTransaction;
-import org.opendaylight.controller.md.sal.dom.api.DOMDataWriteTransaction;
import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
@@ -35,7 +34,7 @@ public class ReadWriteTransactionTest {
private DOMDataReadOnlyTransaction readTx;
@Mock
- private DOMDataWriteTransaction writeTx;
+ private ValidableTransaction writeTx;
private LogicalDatastoreType store;
diff --git a/infra/data-impl/src/test/java/io/fd/honeycomb/data/impl/ValidateTest.java b/infra/data-impl/src/test/java/io/fd/honeycomb/data/impl/ValidateTest.java
new file mode 100644
index 000000000..b2a3aa64d
--- /dev/null
+++ b/infra/data-impl/src/test/java/io/fd/honeycomb/data/impl/ValidateTest.java
@@ -0,0 +1,217 @@
+/*
+ * Copyright (c) 2018 Cisco and/or its affiliates.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package io.fd.honeycomb.data.impl;
+
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.Mockito.when;
+import static org.mockito.MockitoAnnotations.initMocks;
+import static org.opendaylight.yangtools.yang.data.api.schema.tree.DataTreeConfiguration.DEFAULT_CONFIGURATION;
+
+import com.google.common.io.ByteSource;
+import com.google.common.util.concurrent.Futures;
+import io.fd.honeycomb.data.ModifiableDataManager;
+import io.fd.honeycomb.data.ReadableDataManager;
+import java.io.StringWriter;
+import javax.xml.transform.OutputKeys;
+import javax.xml.transform.Transformer;
+import javax.xml.transform.TransformerFactory;
+import javax.xml.transform.dom.DOMSource;
+import javax.xml.transform.stream.StreamResult;
+import org.custommonkey.xmlunit.DetailedDiff;
+import org.custommonkey.xmlunit.Diff;
+import org.custommonkey.xmlunit.XMLUnit;
+import org.junit.Before;
+import org.junit.Test;
+import org.mockito.Mock;
+import org.opendaylight.mdsal.dom.api.DOMSchemaService;
+import org.opendaylight.netconf.api.DocumentedException;
+import org.opendaylight.netconf.api.xml.XmlUtil;
+import org.opendaylight.netconf.mapping.api.NetconfOperation;
+import org.opendaylight.netconf.mapping.api.NetconfOperationChainedExecution;
+import org.opendaylight.netconf.mdsal.connector.CurrentSchemaContext;
+import org.opendaylight.netconf.mdsal.connector.TransactionProvider;
+import org.opendaylight.netconf.mdsal.connector.ops.Commit;
+import org.opendaylight.netconf.mdsal.connector.ops.EditConfig;
+import org.opendaylight.netconf.mdsal.connector.ops.Validate;
+import org.opendaylight.netconf.util.test.NetconfXmlUnitRecursiveQualifier;
+import org.opendaylight.netconf.util.test.XmlFileLoader;
+import org.opendaylight.yangtools.concepts.ListenerRegistration;
+import org.opendaylight.yangtools.yang.data.api.schema.tree.DataTree;
+import org.opendaylight.yangtools.yang.data.impl.schema.tree.InMemoryDataTreeFactory;
+import org.opendaylight.yangtools.yang.model.api.SchemaContext;
+import org.opendaylight.yangtools.yang.model.api.SchemaContextListener;
+import org.opendaylight.yangtools.yang.model.repo.api.YangTextSchemaSource;
+import org.opendaylight.yangtools.yang.test.util.YangParserTestUtils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.w3c.dom.Document;
+
+public class ValidateTest {
+ private static final Logger LOG = LoggerFactory.getLogger(ValidateTest.class);
+ private static final String SESSION_ID_FOR_REPORTING = "netconf-test-session";
+ private static final Document RPC_REPLY_OK = getReplyOk();
+
+ @Mock
+ private DOMSchemaService schemaService;
+ @Mock
+ private ReadableDataManager operationalData;
+
+ private ModifiableDataManager configData;
+ private CurrentSchemaContext currentSchemaContext;
+ private DataBroker dataBroker;
+
+ @Before
+ public void setUp() throws Exception {
+ initMocks(this);
+ final DataTree dataTree = new InMemoryDataTreeFactory().create(DEFAULT_CONFIGURATION);
+ final SchemaContext schemaContext = YangParserTestUtils.parseYangResources(ValidateTest.class,
+ "/test-validate.yang");
+ when(schemaService.registerSchemaContextListener(any())).thenAnswer(invocation -> {
+ SchemaContextListener listener = invocation.getArgument(0);
+ listener.onGlobalContextUpdated(schemaContext);
+ return new ListenerRegistration<SchemaContextListener>() {
+ @Override
+ public void close() {
+ }
+
+ @Override
+ public SchemaContextListener getInstance() {
+ return listener;
+ }
+ };
+ });
+ currentSchemaContext = new CurrentSchemaContext(schemaService, sourceIdentifier -> {
+ final YangTextSchemaSource yangTextSchemaSource =
+ YangTextSchemaSource.delegateForByteSource(sourceIdentifier, ByteSource.wrap("module test".getBytes()));
+ return Futures.immediateCheckedFuture(yangTextSchemaSource);
+ });
+ dataTree.setSchemaContext(schemaContext);
+ configData = new ModifiableDataTreeManager(dataTree);
+ dataBroker = DataBroker.create(configData, operationalData);
+ XMLUnit.setIgnoreWhitespace(true);
+ XMLUnit.setIgnoreAttributeOrder(true);
+ }
+
+ @Test
+ public void testValidate() throws Exception {
+ verifyResponse(validate("messages/validate/validate.xml"));
+ }
+
+ @Test
+ public void testValidateMissingMandatoryNode() throws Exception {
+ final TransactionProvider transactionProvider = new TransactionProvider(dataBroker, SESSION_ID_FOR_REPORTING);
+ verifyResponse(edit("messages/validate/edit-config-missing-mandatory-node.xml", transactionProvider));
+ try {
+ verifyResponse(commit(transactionProvider));
+ fail("Should have failed due to missing mandatory node");
+ } catch (DocumentedException e) {
+ assertTrue(e.getMessage().contains("missing mandatory descendant"));
+ }
+ }
+
+ @Test
+ public void testValidateAndCommit() throws Exception {
+ final TransactionProvider transactionProvider = new TransactionProvider(dataBroker, SESSION_ID_FOR_REPORTING);
+ verifyResponse(edit("messages/validate/edit-config-create-top-container.xml", transactionProvider));
+ verifyResponse(validate("messages/validate/validate.xml", transactionProvider));
+ verifyResponse(commit(transactionProvider));
+ }
+
+ @Test
+ public void testValidateTwice() throws Exception {
+ final TransactionProvider transactionProvider = initCandidateTransaction();
+ verifyResponse(validate("messages/validate/validate.xml", transactionProvider));
+ verifyResponse(validate("messages/validate/validate.xml", transactionProvider));
+ }
+
+ @SuppressWarnings("illegalCatch")
+ private static Document getReplyOk() {
+ Document doc;
+ try {
+ doc = XmlFileLoader.xmlFileToDocument("messages/rpc-reply_ok.xml");
+ } catch (final Exception e) {
+ LOG.debug("unable to load rpc reply ok.", e);
+ doc = XmlUtil.newDocument();
+ }
+ return doc;
+ }
+
+ private static void verifyResponse(final Document actual) throws Exception {
+ final DetailedDiff dd = new DetailedDiff(new Diff(RPC_REPLY_OK, actual));
+ dd.overrideElementQualifier(new NetconfXmlUnitRecursiveQualifier());
+ if (!dd.similar()) {
+ LOG.warn("Actual response:");
+ printDocument(actual);
+ LOG.warn("Expected response:");
+ printDocument(RPC_REPLY_OK);
+ fail("Differences found: " + dd.toString());
+ }
+ }
+
+ private static void printDocument(final Document doc) throws Exception {
+ final TransformerFactory tf = TransformerFactory.newInstance();
+ final 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");
+
+ final StringWriter writer = new StringWriter();
+ transformer.transform(new DOMSource(doc),
+ new StreamResult(writer));
+ LOG.warn(writer.getBuffer().toString());
+ }
+
+ private Document validate(final String resource) throws Exception {
+ final TransactionProvider transactionProvider = initCandidateTransaction();
+ return validate(resource, 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 edit(final String resource, final TransactionProvider transactionProvider) throws Exception {
+ final EditConfig editConfig = new EditConfig(SESSION_ID_FOR_REPORTING, currentSchemaContext,
+ transactionProvider);
+ return executeOperation(editConfig, resource);
+ }
+
+ private Document commit(final TransactionProvider transactionProvider) throws Exception {
+ final Commit commit = new Commit(SESSION_ID_FOR_REPORTING, transactionProvider);
+ return executeOperation(commit, "messages/validate/commit.xml");
+ }
+
+ private TransactionProvider initCandidateTransaction() {
+ final TransactionProvider transactionProvider = new TransactionProvider(dataBroker, SESSION_ID_FOR_REPORTING);
+ // Emulate non empty <candidate> DS to make sure validate is not skipped:
+ transactionProvider.getOrCreateTransaction();
+ return transactionProvider;
+ }
+
+ private static Document executeOperation(final NetconfOperation op, final String filename) throws Exception {
+ final Document request = XmlFileLoader.xmlFileToDocument(filename);
+ final Document response = op.handle(request, NetconfOperationChainedExecution.EXECUTION_TERMINATION_POINT);
+
+ LOG.debug("Got response {}", response);
+ return response;
+ }
+}
diff --git a/infra/data-impl/src/test/java/io/fd/honeycomb/data/impl/WriteTransactionTest.java b/infra/data-impl/src/test/java/io/fd/honeycomb/data/impl/WriteTransactionTest.java
index d0cbb3235..74313a1ba 100644
--- a/infra/data-impl/src/test/java/io/fd/honeycomb/data/impl/WriteTransactionTest.java
+++ b/infra/data-impl/src/test/java/io/fd/honeycomb/data/impl/WriteTransactionTest.java
@@ -119,7 +119,6 @@ public class WriteTransactionTest {
@Test
public void testCommit() throws TranslationException {
writeTx.commit();
- verify(configSnapshot).validate();
verify(configSnapshot).commit();
}
diff --git a/infra/data-impl/src/test/resources/messages/rpc-reply_ok.xml b/infra/data-impl/src/test/resources/messages/rpc-reply_ok.xml
new file mode 100644
index 000000000..df205b60b
--- /dev/null
+++ b/infra/data-impl/src/test/resources/messages/rpc-reply_ok.xml
@@ -0,0 +1,19 @@
+<!--
+ ~ Copyright (c) 2018 Cisco and/or its affiliates.
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at:
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+
+<rpc-reply xmlns="urn:ietf:params:xml:ns:netconf:base:1.0" message-id="a">
+ <ok/>
+</rpc-reply> \ No newline at end of file
diff --git a/infra/data-impl/src/test/resources/messages/validate/commit.xml b/infra/data-impl/src/test/resources/messages/validate/commit.xml
new file mode 100644
index 000000000..a4a98f4ca
--- /dev/null
+++ b/infra/data-impl/src/test/resources/messages/validate/commit.xml
@@ -0,0 +1,19 @@
+<!--
+ ~ Copyright (c) 2018 Cisco and/or its affiliates.
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at:
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+
+<rpc message-id="a" xmlns="urn:ietf:params:xml:ns:netconf:base:1.0">
+ <commit/>
+</rpc>
diff --git a/infra/data-impl/src/test/resources/messages/validate/edit-config-create-top-container.xml b/infra/data-impl/src/test/resources/messages/validate/edit-config-create-top-container.xml
new file mode 100644
index 000000000..b75a4504a
--- /dev/null
+++ b/infra/data-impl/src/test/resources/messages/validate/edit-config-create-top-container.xml
@@ -0,0 +1,28 @@
+<!--
+ ~ Copyright (c) 2018 Cisco and/or its affiliates.
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at:
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+
+<rpc message-id="a" xmlns="urn:ietf:params:xml:ns:netconf:base:1.0">
+ <edit-config>
+ <target>
+ <candidate/>
+ </target>
+ <config>
+ <top-container xmlns="urn:honeycomb:params:xml:ns:yang:test:validate" xmlns:a="urn:ietf:params:xml:ns:netconf:base:1.0" a:operation="create">
+ <name>top-container-name</name>
+ </top-container>
+ </config>
+ </edit-config>
+</rpc> \ No newline at end of file
diff --git a/infra/data-impl/src/test/resources/messages/validate/edit-config-missing-mandatory-node.xml b/infra/data-impl/src/test/resources/messages/validate/edit-config-missing-mandatory-node.xml
new file mode 100644
index 000000000..829ef567a
--- /dev/null
+++ b/infra/data-impl/src/test/resources/messages/validate/edit-config-missing-mandatory-node.xml
@@ -0,0 +1,35 @@
+<!--
+ ~ Copyright (c) 2018 Cisco and/or its affiliates.
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at:
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+
+<rpc message-id="a" xmlns="urn:ietf:params:xml:ns:netconf:base:1.0">
+ <edit-config>
+ <target>
+ <candidate/>
+ </target>
+ <default-operation>none</default-operation>
+ <config>
+ <top-container xmlns="urn:honeycomb:params:xml:ns:yang:test:validate" xmlns:a="urn:ietf:params:xml:ns:netconf:base:1.0" a:operation="create">
+ <list-in-container>
+ <name>item1</name>>
+ </list-in-container>
+ <list-in-container>
+ <name>item2</name>
+ <description>description2</description>
+ </list-in-container>
+ </top-container>
+ </config>
+ </edit-config>
+</rpc> \ No newline at end of file
diff --git a/infra/data-impl/src/test/resources/messages/validate/validate.xml b/infra/data-impl/src/test/resources/messages/validate/validate.xml
new file mode 100644
index 000000000..3c1ba8c65
--- /dev/null
+++ b/infra/data-impl/src/test/resources/messages/validate/validate.xml
@@ -0,0 +1,23 @@
+<!--
+ ~ Copyright (c) 2018 Cisco and/or its affiliates.
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at:
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+
+<rpc message-id="a" 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/infra/data-impl/src/test/resources/test-validate.yang b/infra/data-impl/src/test/resources/test-validate.yang
new file mode 100644
index 000000000..144045661
--- /dev/null
+++ b/infra/data-impl/src/test/resources/test-validate.yang
@@ -0,0 +1,27 @@
+module test-validate {
+ yang-version 1;
+ namespace "urn:honeycomb:params:xml:ns:yang:test:validate";
+ prefix "td";
+
+ revision "2018-06-08" {
+ description "Initial revision";
+ }
+
+ container top-container {
+ leaf name {
+ type string;
+ }
+ list list-in-container {
+ key "name";
+
+ leaf name {
+ type string;
+ }
+
+ leaf description {
+ type string;
+ mandatory true;
+ }
+ }
+ }
+}