summaryrefslogtreecommitdiffstats
path: root/netconf/restconf/restconf-nb-bierman02/src/test/java/org/opendaylight
diff options
context:
space:
mode:
Diffstat (limited to 'netconf/restconf/restconf-nb-bierman02/src/test/java/org/opendaylight')
-rw-r--r--netconf/restconf/restconf-nb-bierman02/src/test/java/org/opendaylight/controller/md/sal/rest/common/TestRestconfUtils.java189
-rw-r--r--netconf/restconf/restconf-nb-bierman02/src/test/java/org/opendaylight/controller/sal/rest/impl/InstanceIdentifierTypeLeafTest.java55
-rw-r--r--netconf/restconf/restconf-nb-bierman02/src/test/java/org/opendaylight/controller/sal/rest/impl/test/providers/AbstractBodyReaderTest.java127
-rw-r--r--netconf/restconf/restconf-nb-bierman02/src/test/java/org/opendaylight/controller/sal/rest/impl/test/providers/TestJsonBodyReader.java186
-rw-r--r--netconf/restconf/restconf-nb-bierman02/src/test/java/org/opendaylight/controller/sal/rest/impl/test/providers/TestJsonBodyReaderMountPoint.java151
-rw-r--r--netconf/restconf/restconf-nb-bierman02/src/test/java/org/opendaylight/controller/sal/rest/impl/test/providers/TestJsonBodyWriter.java65
-rw-r--r--netconf/restconf/restconf-nb-bierman02/src/test/java/org/opendaylight/controller/sal/rest/impl/test/providers/TestJsonPatchBodyReader.java165
-rw-r--r--netconf/restconf/restconf-nb-bierman02/src/test/java/org/opendaylight/controller/sal/rest/impl/test/providers/TestJsonPatchBodyReaderMountPoint.java172
-rw-r--r--netconf/restconf/restconf-nb-bierman02/src/test/java/org/opendaylight/controller/sal/rest/impl/test/providers/TestXmlBodyReader.java287
-rw-r--r--netconf/restconf/restconf-nb-bierman02/src/test/java/org/opendaylight/controller/sal/rest/impl/test/providers/TestXmlBodyReaderMountPoint.java220
-rw-r--r--netconf/restconf/restconf-nb-bierman02/src/test/java/org/opendaylight/controller/sal/rest/impl/test/providers/TestXmlBodyWriter.java58
-rw-r--r--netconf/restconf/restconf-nb-bierman02/src/test/java/org/opendaylight/controller/sal/rest/impl/test/providers/TestXmlPatchBodyReader.java137
-rw-r--r--netconf/restconf/restconf-nb-bierman02/src/test/java/org/opendaylight/controller/sal/rest/impl/test/providers/TestXmlPatchBodyReaderMountPoint.java133
-rw-r--r--netconf/restconf/restconf-nb-bierman02/src/test/java/org/opendaylight/controller/sal/restconf/impl/cnsn/to/json/test/CnSnToJsonBasicDataTypesTest.java281
-rw-r--r--netconf/restconf/restconf-nb-bierman02/src/test/java/org/opendaylight/controller/sal/restconf/impl/cnsn/to/json/test/CnSnToJsonIdentityrefTest.java22
-rw-r--r--netconf/restconf/restconf-nb-bierman02/src/test/java/org/opendaylight/controller/sal/restconf/impl/cnsn/to/json/test/CnSnToJsonWithDataFromSeveralModulesTest.java21
-rw-r--r--netconf/restconf/restconf-nb-bierman02/src/test/java/org/opendaylight/controller/sal/restconf/impl/input/to/cnsn/test/RestPutListDataTest.java228
-rw-r--r--netconf/restconf/restconf-nb-bierman02/src/test/java/org/opendaylight/controller/sal/restconf/impl/json/to/nn/test/JsonIdentityrefToNnTest.java68
-rw-r--r--netconf/restconf/restconf-nb-bierman02/src/test/java/org/opendaylight/controller/sal/restconf/impl/json/to/nn/test/JsonLeafrefToNnTest.java58
-rw-r--r--netconf/restconf/restconf-nb-bierman02/src/test/java/org/opendaylight/controller/sal/restconf/impl/json/to/nn/test/JsonToNnTest.java334
-rw-r--r--netconf/restconf/restconf-nb-bierman02/src/test/java/org/opendaylight/controller/sal/restconf/impl/nn/to/json/test/NnJsonChoiceCaseTest.java181
-rw-r--r--netconf/restconf/restconf-nb-bierman02/src/test/java/org/opendaylight/controller/sal/restconf/impl/nn/to/json/test/NnToJsonLeafrefType.java107
-rw-r--r--netconf/restconf/restconf-nb-bierman02/src/test/java/org/opendaylight/controller/sal/restconf/impl/nn/to/json/test/NnToJsonWithAugmentTest.java70
-rw-r--r--netconf/restconf/restconf-nb-bierman02/src/test/java/org/opendaylight/controller/sal/restconf/impl/nn/to/xml/test/NnInstanceIdentifierToXmlTest.java250
-rw-r--r--netconf/restconf/restconf-nb-bierman02/src/test/java/org/opendaylight/controller/sal/restconf/impl/nn/to/xml/test/NnToXmlTest.java407
-rw-r--r--netconf/restconf/restconf-nb-bierman02/src/test/java/org/opendaylight/controller/sal/restconf/impl/nn/to/xml/test/NnToXmlWithChoiceTest.java108
-rw-r--r--netconf/restconf/restconf-nb-bierman02/src/test/java/org/opendaylight/controller/sal/restconf/impl/nn/to/xml/test/NnToXmlWithDataFromSeveralModulesTest.java144
-rw-r--r--netconf/restconf/restconf-nb-bierman02/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/Bierman02RestConfWiringTest.java54
-rw-r--r--netconf/restconf/restconf-nb-bierman02/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/BrokerFacadeTest.java432
-rw-r--r--netconf/restconf/restconf-nb-bierman02/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/Bug3595Test.java53
-rw-r--r--netconf/restconf/restconf-nb-bierman02/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/Bug8072Test.java71
-rw-r--r--netconf/restconf/restconf-nb-bierman02/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/CnSnToXmlAndJsonInstanceIdentifierTest.java150
-rw-r--r--netconf/restconf/restconf-nb-bierman02/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/CodecsExceptionsCatchingTest.java68
-rw-r--r--netconf/restconf/restconf-nb-bierman02/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/CutDataToCorrectDepthTest.java388
-rw-r--r--netconf/restconf/restconf-nb-bierman02/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/DummyFuture.java94
-rw-r--r--netconf/restconf/restconf-nb-bierman02/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/DummyRpcResult.java71
-rw-r--r--netconf/restconf/restconf-nb-bierman02/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/DummyType.java62
-rw-r--r--netconf/restconf/restconf-nb-bierman02/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/ExpressionParserTest.java171
-rw-r--r--netconf/restconf/restconf-nb-bierman02/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/InvokeRpcMethodTest.java344
-rw-r--r--netconf/restconf/restconf-nb-bierman02/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/JSONRestconfServiceImplTest.java532
-rw-r--r--netconf/restconf/restconf-nb-bierman02/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/MediaTypesTest.java260
-rw-r--r--netconf/restconf/restconf-nb-bierman02/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/NormalizeNodeTest.java21
-rw-r--r--netconf/restconf/restconf-nb-bierman02/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/RestCodecExceptionsTest.java38
-rw-r--r--netconf/restconf/restconf-nb-bierman02/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/RestDeleteOperationTest.java96
-rw-r--r--netconf/restconf/restconf-nb-bierman02/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/RestGetAugmentedElementWhenEqualNamesTest.java52
-rw-r--r--netconf/restconf/restconf-nb-bierman02/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/RestGetOperationTest.java742
-rw-r--r--netconf/restconf/restconf-nb-bierman02/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/RestOperationUtils.java17
-rw-r--r--netconf/restconf/restconf-nb-bierman02/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/RestPostOperationTest.java182
-rw-r--r--netconf/restconf/restconf-nb-bierman02/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/RestPutConfigTest.java135
-rw-r--r--netconf/restconf/restconf-nb-bierman02/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/RestPutOperationTest.java220
-rw-r--r--netconf/restconf/restconf-nb-bierman02/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/RestconfDocumentedExceptionMapperTest.java831
-rw-r--r--netconf/restconf/restconf-nb-bierman02/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/RestconfErrorTest.java147
-rw-r--r--netconf/restconf/restconf-nb-bierman02/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/RestconfImplNotificationSubscribingTest.java168
-rw-r--r--netconf/restconf/restconf-nb-bierman02/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/RestconfImplTest.java306
-rw-r--r--netconf/restconf/restconf-nb-bierman02/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/TestUtils.java258
-rw-r--r--netconf/restconf/restconf-nb-bierman02/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/URIParametersParsing.java172
-rw-r--r--netconf/restconf/restconf-nb-bierman02/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/URITest.java163
-rw-r--r--netconf/restconf/restconf-nb-bierman02/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/XmlAndJsonToCnSnInstanceIdentifierTest.java21
-rw-r--r--netconf/restconf/restconf-nb-bierman02/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/XmlAndJsonToCnSnLeafRefTest.java30
-rw-r--r--netconf/restconf/restconf-nb-bierman02/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/YangAndXmlAndDataSchemaLoader.java42
-rw-r--r--netconf/restconf/restconf-nb-bierman02/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/incubate/InMemoryMdsalModule.java127
-rw-r--r--netconf/restconf/restconf-nb-bierman02/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/incubate/InMemoryMdsalModuleTest.java35
-rw-r--r--netconf/restconf/restconf-nb-bierman02/src/test/java/org/opendaylight/controller/sal/restconf/impl/websockets/client/IClientMessageCallback.java17
-rw-r--r--netconf/restconf/restconf-nb-bierman02/src/test/java/org/opendaylight/controller/sal/restconf/impl/websockets/client/WebSocketClient.java130
-rw-r--r--netconf/restconf/restconf-nb-bierman02/src/test/java/org/opendaylight/controller/sal/restconf/impl/websockets/client/WebSocketClientHandler.java92
-rw-r--r--netconf/restconf/restconf-nb-bierman02/src/test/java/org/opendaylight/controller/sal/restconf/impl/websockets/test/RestStreamTest.java132
-rw-r--r--netconf/restconf/restconf-nb-bierman02/src/test/java/org/opendaylight/controller/sal/restconf/impl/xml/to/cnsn/test/XmlAugmentedElementToCnSnTest.java13
-rw-r--r--netconf/restconf/restconf-nb-bierman02/src/test/java/org/opendaylight/controller/sal/restconf/impl/xml/to/cnsn/test/XmlToCnSnTest.java22
-rw-r--r--netconf/restconf/restconf-nb-bierman02/src/test/java/org/opendaylight/netconf/sal/rest/impl/DepthAwareNormalizedNodeWriterTest.java343
-rw-r--r--netconf/restconf/restconf-nb-bierman02/src/test/java/org/opendaylight/netconf/sal/restconf/impl/InstanceIdentifierCodecImplTest.java99
-rw-r--r--netconf/restconf/restconf-nb-bierman02/src/test/java/org/opendaylight/netconf/sal/streams/listeners/ListenerAdapterTest.java220
-rw-r--r--netconf/restconf/restconf-nb-bierman02/src/test/java/org/opendaylight/netconf/sal/streams/listeners/NotificationListenerTest.java206
-rw-r--r--netconf/restconf/restconf-nb-bierman02/src/test/java/org/opendaylight/yang/gen/v1/urn/ietf/params/xml/ns/yang/ietf/restconf/rev131019/DatastoreIdentifierBuilderTest.java23
-rw-r--r--netconf/restconf/restconf-nb-bierman02/src/test/java/org/opendaylight/yang/gen/v1/urn/ietf/params/xml/ns/yang/ietf/restconf/rev131019/restconf/restconf/modules/ModuleBuilderTest.java70
-rw-r--r--netconf/restconf/restconf-nb-bierman02/src/test/java/org/opendaylight/yang/gen/v1/urn/ietf/params/xml/ns/yang/ietf/restconf/rev131019/restconf/restconf/modules/ModuleRevisionBuilderTest.java28
-rw-r--r--netconf/restconf/restconf-nb-bierman02/src/test/java/org/opendaylight/yang/gen/v1/urn/ietf/params/xml/ns/yang/ietf/restconf/rev131019/restconf/restconf/modules/RevisionBuilderTest.java49
76 files changed, 12221 insertions, 0 deletions
diff --git a/netconf/restconf/restconf-nb-bierman02/src/test/java/org/opendaylight/controller/md/sal/rest/common/TestRestconfUtils.java b/netconf/restconf/restconf-nb-bierman02/src/test/java/org/opendaylight/controller/md/sal/rest/common/TestRestconfUtils.java
new file mode 100644
index 0000000..d883797
--- /dev/null
+++ b/netconf/restconf/restconf-nb-bierman02/src/test/java/org/opendaylight/controller/md/sal/rest/common/TestRestconfUtils.java
@@ -0,0 +1,189 @@
+/*
+ * Copyright (c) 2015 Cisco Systems, Inc. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.controller.md.sal.rest.common;
+
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.mock;
+
+import com.google.common.base.Preconditions;
+import com.google.common.collect.ImmutableClassToInstanceMap;
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.URISyntaxException;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+import java.util.Optional;
+import javax.xml.stream.XMLStreamException;
+import javax.xml.transform.dom.DOMSource;
+import org.opendaylight.controller.sal.rest.impl.test.providers.TestJsonBodyWriter;
+import org.opendaylight.mdsal.dom.api.DOMMountPoint;
+import org.opendaylight.mdsal.dom.api.DOMMountPointService;
+import org.opendaylight.mdsal.dom.api.DOMSchemaService;
+import org.opendaylight.mdsal.dom.spi.FixedDOMSchemaService;
+import org.opendaylight.netconf.sal.rest.impl.NormalizedNodeContext;
+import org.opendaylight.netconf.sal.restconf.impl.ControllerContext;
+import org.opendaylight.restconf.common.context.InstanceIdentifierContext;
+import org.opendaylight.yangtools.util.xml.UntrustedXML;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
+import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
+import org.opendaylight.yangtools.yang.data.api.schema.stream.NormalizedNodeStreamWriter;
+import org.opendaylight.yangtools.yang.data.codec.xml.XmlParserStream;
+import org.opendaylight.yangtools.yang.data.impl.schema.ImmutableNormalizedNodeStreamWriter;
+import org.opendaylight.yangtools.yang.data.impl.schema.NormalizedNodeResult;
+import org.opendaylight.yangtools.yang.model.api.ContainerLike;
+import org.opendaylight.yangtools.yang.model.api.DataNodeContainer;
+import org.opendaylight.yangtools.yang.model.api.DataSchemaNode;
+import org.opendaylight.yangtools.yang.model.api.EffectiveModelContext;
+import org.opendaylight.yangtools.yang.model.api.ListSchemaNode;
+import org.opendaylight.yangtools.yang.model.api.RpcDefinition;
+import org.opendaylight.yangtools.yang.model.api.SchemaNode;
+import org.opendaylight.yangtools.yang.model.util.SchemaInferenceStack;
+import org.opendaylight.yangtools.yang.test.util.YangParserTestUtils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.w3c.dom.Document;
+import org.xml.sax.SAXException;
+
+public final class TestRestconfUtils {
+
+ private static final Logger LOG = LoggerFactory.getLogger(TestRestconfUtils.class);
+
+ private TestRestconfUtils() {
+ throw new UnsupportedOperationException("Test utility class");
+ }
+
+ public static ControllerContext newControllerContext(final EffectiveModelContext schemaContext) {
+ return newControllerContext(schemaContext, null);
+ }
+
+ public static ControllerContext newControllerContext(final EffectiveModelContext schemaContext,
+ final DOMMountPoint mountInstance) {
+ final DOMMountPointService mockMountService = mock(DOMMountPointService.class);
+
+ if (mountInstance != null) {
+ doReturn(Optional.of(FixedDOMSchemaService.of(() -> schemaContext))).when(mountInstance)
+ .getService(eq(DOMSchemaService.class));
+ doReturn(Optional.ofNullable(mountInstance)).when(mockMountService).getMountPoint(
+ any(YangInstanceIdentifier.class));
+ }
+
+ DOMSchemaService mockSchemaService = mock(DOMSchemaService.class);
+ doReturn(schemaContext).when(mockSchemaService).getGlobalContext();
+
+ DOMSchemaService mockDomSchemaService = mock(DOMSchemaService.class);
+ doReturn(ImmutableClassToInstanceMap.of()).when(mockDomSchemaService).getExtensions();
+
+ return ControllerContext.newInstance(mockSchemaService, mockMountService, mockDomSchemaService);
+ }
+
+ @SuppressWarnings("checkstyle:IllegalCatch")
+ public static EffectiveModelContext loadSchemaContext(final String yangPath,
+ final EffectiveModelContext schemaContext) {
+ try {
+ Preconditions.checkArgument(yangPath != null, "Path can not be null.");
+ Preconditions.checkArgument(!yangPath.isEmpty(), "Path can not be empty.");
+ if (schemaContext == null) {
+ return YangParserTestUtils.parseYangFiles(TestRestconfUtils.loadFiles(yangPath));
+ } else {
+ throw new UnsupportedOperationException("Unable to add new yang sources to existing schema context.");
+ }
+ } catch (final Exception e) {
+ LOG.error("Yang files at path: " + yangPath + " weren't loaded.", e);
+ }
+ return schemaContext;
+ }
+
+ public static NormalizedNodeContext loadNormalizedContextFromJsonFile() {
+ throw new AbstractMethodError("Not implemented yet");
+ }
+
+ @SuppressWarnings("checkstyle:IllegalCatch")
+ public static NormalizedNodeContext loadNormalizedContextFromXmlFile(final String pathToInputFile,
+ final String uri, final ControllerContext controllerContext) {
+ final InstanceIdentifierContext iiContext = controllerContext.toInstanceIdentifier(uri);
+ final InputStream inputStream = TestJsonBodyWriter.class.getResourceAsStream(pathToInputFile);
+ try {
+ final Document doc = UntrustedXML.newDocumentBuilder().parse(inputStream);
+ final NormalizedNode nn = parse(iiContext, doc);
+ return new NormalizedNodeContext(iiContext, nn);
+ } catch (final Exception e) {
+ LOG.error("Load xml file " + pathToInputFile + " fail.", e);
+ }
+ return null;
+ }
+
+ private static NormalizedNode parse(final InstanceIdentifierContext iiContext, final Document doc)
+ throws XMLStreamException, IOException, SAXException, URISyntaxException {
+ final SchemaNode schemaNodeContext = iiContext.getSchemaNode();
+ final SchemaInferenceStack stack;
+ DataSchemaNode schemaNode = null;
+ if (schemaNodeContext instanceof RpcDefinition) {
+ final var rpc = (RpcDefinition) schemaNodeContext;
+ stack = SchemaInferenceStack.of(iiContext.getSchemaContext());
+ stack.enterSchemaTree(rpc.getQName());
+ if ("input".equalsIgnoreCase(doc.getDocumentElement().getLocalName())) {
+ schemaNode = rpc.getInput();
+ } else if ("output".equalsIgnoreCase(doc.getDocumentElement().getLocalName())) {
+ schemaNode = rpc.getOutput();
+ } else {
+ throw new IllegalStateException("Unknown Rpc input node");
+ }
+ stack.enterSchemaTree(schemaNode.getQName());
+ } else if (schemaNodeContext instanceof DataSchemaNode) {
+ schemaNode = (DataSchemaNode) schemaNodeContext;
+ stack = iiContext.inference().toSchemaInferenceStack();
+ } else {
+ throw new IllegalStateException("Unknow SchemaNode");
+ }
+
+ final String docRootElm = doc.getDocumentElement().getLocalName();
+ final String schemaNodeName = iiContext.getSchemaNode().getQName().getLocalName();
+
+ if (!schemaNodeName.equalsIgnoreCase(docRootElm)) {
+ for (final DataSchemaNode child : ((DataNodeContainer) schemaNode).getChildNodes()) {
+ if (child.getQName().getLocalName().equalsIgnoreCase(docRootElm)) {
+ schemaNode = child;
+ stack.enterSchemaTree(child.getQName());
+ break;
+ }
+ }
+ }
+
+ final NormalizedNodeResult resultHolder = new NormalizedNodeResult();
+ final NormalizedNodeStreamWriter writer = ImmutableNormalizedNodeStreamWriter.from(resultHolder);
+ final XmlParserStream xmlParser = XmlParserStream.create(writer, stack.toInference());
+
+ if (schemaNode instanceof ContainerLike || schemaNode instanceof ListSchemaNode) {
+ xmlParser.traverse(new DOMSource(doc.getDocumentElement()));
+ return resultHolder.getResult();
+ }
+ // FIXME : add another DataSchemaNode extensions e.g. LeafSchemaNode
+ return null;
+ }
+
+ public static Collection<File> loadFiles(final String resourceDirectory) throws FileNotFoundException {
+ final String path = TestRestconfUtils.class.getResource(resourceDirectory).getPath();
+ final File testDir = new File(path);
+ final String[] fileList = testDir.list();
+ final List<File> testFiles = new ArrayList<>();
+ if (fileList == null) {
+ throw new FileNotFoundException(resourceDirectory);
+ }
+ for (final String fileName : fileList) {
+ if (new File(testDir, fileName).isDirectory() == false) {
+ testFiles.add(new File(testDir, fileName));
+ }
+ }
+ return testFiles;
+ }
+}
diff --git a/netconf/restconf/restconf-nb-bierman02/src/test/java/org/opendaylight/controller/sal/rest/impl/InstanceIdentifierTypeLeafTest.java b/netconf/restconf/restconf-nb-bierman02/src/test/java/org/opendaylight/controller/sal/rest/impl/InstanceIdentifierTypeLeafTest.java
new file mode 100644
index 0000000..3c46201
--- /dev/null
+++ b/netconf/restconf/restconf-nb-bierman02/src/test/java/org/opendaylight/controller/sal/rest/impl/InstanceIdentifierTypeLeafTest.java
@@ -0,0 +1,55 @@
+/*
+ * Copyright (c) 2016 Cisco Systems, Inc. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.controller.sal.rest.impl;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+
+import org.junit.Test;
+import org.opendaylight.controller.md.sal.rest.common.TestRestconfUtils;
+import org.opendaylight.netconf.sal.restconf.impl.ControllerContext;
+import org.opendaylight.restconf.common.context.InstanceIdentifierContext;
+import org.opendaylight.yangtools.yang.common.QName;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifierWithPredicates;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.PathArgument;
+import org.opendaylight.yangtools.yang.model.api.EffectiveModelContext;
+import org.opendaylight.yangtools.yang.test.util.YangParserTestUtils;
+
+public class InstanceIdentifierTypeLeafTest {
+
+ @Test
+ public void stringToInstanceIdentifierTest() throws Exception {
+ final EffectiveModelContext schemaContext =
+ YangParserTestUtils.parseYangFiles(TestRestconfUtils.loadFiles("/instanceidentifier"));
+ ControllerContext controllerContext = TestRestconfUtils.newControllerContext(schemaContext);
+ final InstanceIdentifierContext instanceIdentifier =
+ controllerContext.toInstanceIdentifier(
+ "/iid-value-module:cont-iid/iid-list/%2Fiid-value-module%3Acont-iid%2Fiid-value-module%3A"
+ + "values-iid%5Biid-value-module:value-iid='value'%5D");
+ final YangInstanceIdentifier yiD = instanceIdentifier.getInstanceIdentifier();
+ assertNotNull(yiD);
+ final PathArgument lastPathArgument = yiD.getLastPathArgument();
+ assertTrue(lastPathArgument.getNodeType().getNamespace().toString().equals("iid:value:module"));
+ assertTrue(lastPathArgument.getNodeType().getLocalName().equals("iid-list"));
+
+ final NodeIdentifierWithPredicates list = (NodeIdentifierWithPredicates) lastPathArgument;
+ final YangInstanceIdentifier value = (YangInstanceIdentifier) list.getValue(
+ QName.create(lastPathArgument.getNodeType(), "iid-leaf"));
+ final PathArgument lastPathArgumentOfValue = value.getLastPathArgument();
+ assertTrue(lastPathArgumentOfValue.getNodeType().getNamespace().toString().equals("iid:value:module"));
+ assertTrue(lastPathArgumentOfValue.getNodeType().getLocalName().equals("values-iid"));
+
+ final NodeIdentifierWithPredicates valueList = (NodeIdentifierWithPredicates) lastPathArgumentOfValue;
+ final String valueIid = (String) valueList.getValue(
+ QName.create(lastPathArgumentOfValue.getNodeType(), "value-iid"));
+ assertEquals("value", valueIid);
+ }
+
+}
diff --git a/netconf/restconf/restconf-nb-bierman02/src/test/java/org/opendaylight/controller/sal/rest/impl/test/providers/AbstractBodyReaderTest.java b/netconf/restconf/restconf-nb-bierman02/src/test/java/org/opendaylight/controller/sal/rest/impl/test/providers/AbstractBodyReaderTest.java
new file mode 100644
index 0000000..5bbd161
--- /dev/null
+++ b/netconf/restconf/restconf-nb-bierman02/src/test/java/org/opendaylight/controller/sal/rest/impl/test/providers/AbstractBodyReaderTest.java
@@ -0,0 +1,127 @@
+/*
+ * Copyright (c) 2015 Cisco Systems, Inc. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.controller.sal.rest.impl.test.providers;
+
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+import java.lang.reflect.Field;
+import java.net.URI;
+import java.util.List;
+import java.util.Optional;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.MultivaluedHashMap;
+import javax.ws.rs.core.MultivaluedMap;
+import javax.ws.rs.core.Request;
+import javax.ws.rs.core.UriInfo;
+import org.opendaylight.controller.md.sal.rest.common.TestRestconfUtils;
+import org.opendaylight.mdsal.dom.api.DOMMountPoint;
+import org.opendaylight.mdsal.dom.api.DOMSchemaService;
+import org.opendaylight.netconf.sal.rest.api.RestconfConstants;
+import org.opendaylight.netconf.sal.rest.impl.AbstractIdentifierAwareJaxRsProvider;
+import org.opendaylight.netconf.sal.rest.impl.NormalizedNodeContext;
+import org.opendaylight.netconf.sal.restconf.impl.ControllerContext;
+import org.opendaylight.restconf.common.patch.PatchContext;
+import org.opendaylight.yangtools.yang.model.api.EffectiveModelContext;
+
+public abstract class AbstractBodyReaderTest {
+ private static Field uriField;
+ private static Field requestField;
+
+ static {
+ try {
+ uriField = AbstractIdentifierAwareJaxRsProvider.class.getDeclaredField("uriInfo");
+ uriField.setAccessible(true);
+ requestField = AbstractIdentifierAwareJaxRsProvider.class.getDeclaredField("request");
+ requestField.setAccessible(true);
+ } catch (NoSuchFieldException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ protected final ControllerContext controllerContext;
+ protected final MediaType mediaType;
+
+ protected AbstractBodyReaderTest(final EffectiveModelContext schemaContext, final DOMMountPoint mountInstance) {
+ mediaType = getMediaType();
+
+ controllerContext = TestRestconfUtils.newControllerContext(schemaContext, mountInstance);
+ }
+
+ protected abstract MediaType getMediaType();
+
+ protected static EffectiveModelContext schemaContextLoader(final String yangPath,
+ final EffectiveModelContext schemaContext) {
+ return TestRestconfUtils.loadSchemaContext(yangPath, schemaContext);
+ }
+
+ protected static <T extends AbstractIdentifierAwareJaxRsProvider> void mockBodyReader(
+ final String identifier, final T normalizedNodeProvider, final boolean isPost) throws Exception {
+ final UriInfo uriInfoMock = mock(UriInfo.class);
+ final MultivaluedMap<String, String> pathParm = new MultivaluedHashMap<>(1);
+
+ if (!identifier.isEmpty()) {
+ pathParm.put(RestconfConstants.IDENTIFIER, List.of(identifier));
+ }
+
+ when(uriInfoMock.getPathParameters()).thenReturn(pathParm);
+ when(uriInfoMock.getPathParameters(false)).thenReturn(pathParm);
+ when(uriInfoMock.getPathParameters(true)).thenReturn(pathParm);
+ when(uriInfoMock.getAbsolutePath()).thenReturn(URI.create("restconf"));
+ uriField.set(normalizedNodeProvider, uriInfoMock);
+
+ final Request request = mock(Request.class);
+ if (isPost) {
+ when(request.getMethod()).thenReturn("POST");
+ } else {
+ when(request.getMethod()).thenReturn("PUT");
+ }
+
+ requestField.set(normalizedNodeProvider, request);
+ }
+
+ protected static void checkMountPointNormalizedNodeContext(final NormalizedNodeContext nnContext) {
+ checkNormalizedNodeContext(nnContext);
+ assertNotNull(nnContext.getInstanceIdentifierContext().getMountPoint());
+ }
+
+ protected static void checkNormalizedNodeContext(final NormalizedNodeContext nnContext) {
+ assertNotNull(nnContext.getData());
+ assertNotNull(nnContext.getInstanceIdentifierContext().getInstanceIdentifier());
+ assertNotNull(nnContext.getInstanceIdentifierContext().getSchemaContext());
+ assertNotNull(nnContext.getInstanceIdentifierContext().getSchemaNode());
+ }
+
+ protected static void checkNormalizedNodeContextRpc(final NormalizedNodeContext nnContext) {
+ assertNotNull(nnContext.getData());
+ assertNull(nnContext.getInstanceIdentifierContext().getInstanceIdentifier());
+ assertNotNull(nnContext.getInstanceIdentifierContext().getSchemaContext());
+ assertNotNull(nnContext.getInstanceIdentifierContext().getSchemaNode());
+ }
+
+ protected static void checkPatchContext(final PatchContext patchContext) {
+ assertNotNull(patchContext.getData());
+ assertNotNull(patchContext.getInstanceIdentifierContext().getInstanceIdentifier());
+ assertNotNull(patchContext.getInstanceIdentifierContext().getSchemaContext());
+ assertNotNull(patchContext.getInstanceIdentifierContext().getSchemaNode());
+ }
+
+ protected static void checkPatchContextMountPoint(final PatchContext patchContext) {
+ checkPatchContext(patchContext);
+ assertNotNull(patchContext.getInstanceIdentifierContext().getMountPoint());
+ }
+
+ protected static EffectiveModelContext modelContext(final DOMMountPoint mountPoint) {
+ return mountPoint.getService(DOMSchemaService.class)
+ .flatMap(svc -> Optional.ofNullable(svc.getGlobalContext()))
+ .orElse(null);
+ }
+
+}
diff --git a/netconf/restconf/restconf-nb-bierman02/src/test/java/org/opendaylight/controller/sal/rest/impl/test/providers/TestJsonBodyReader.java b/netconf/restconf/restconf-nb-bierman02/src/test/java/org/opendaylight/controller/sal/rest/impl/test/providers/TestJsonBodyReader.java
new file mode 100644
index 0000000..fe50c68
--- /dev/null
+++ b/netconf/restconf/restconf-nb-bierman02/src/test/java/org/opendaylight/controller/sal/rest/impl/test/providers/TestJsonBodyReader.java
@@ -0,0 +1,186 @@
+/*
+ * Copyright (c) 2015 Cisco Systems, Inc. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+
+package org.opendaylight.controller.sal.rest.impl.test.providers;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+
+import java.io.File;
+import java.io.InputStream;
+import java.util.Collection;
+import java.util.Optional;
+import java.util.Set;
+import javax.ws.rs.core.MediaType;
+import org.junit.BeforeClass;
+import org.junit.Test;
+import org.opendaylight.controller.md.sal.rest.common.TestRestconfUtils;
+import org.opendaylight.netconf.sal.rest.impl.JsonNormalizedNodeBodyReader;
+import org.opendaylight.netconf.sal.rest.impl.NormalizedNodeContext;
+import org.opendaylight.yangtools.yang.common.QName;
+import org.opendaylight.yangtools.yang.common.QNameModule;
+import org.opendaylight.yangtools.yang.common.Revision;
+import org.opendaylight.yangtools.yang.common.XMLNamespace;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.AugmentationIdentifier;
+import org.opendaylight.yangtools.yang.data.api.schema.ContainerNode;
+import org.opendaylight.yangtools.yang.data.api.schema.DataContainerChild;
+import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNodes;
+import org.opendaylight.yangtools.yang.model.api.DataNodeContainer;
+import org.opendaylight.yangtools.yang.model.api.DataSchemaNode;
+import org.opendaylight.yangtools.yang.model.api.EffectiveModelContext;
+import org.opendaylight.yangtools.yang.model.api.Module;
+import org.opendaylight.yangtools.yang.test.util.YangParserTestUtils;
+
+public class TestJsonBodyReader extends AbstractBodyReaderTest {
+
+ private final JsonNormalizedNodeBodyReader jsonBodyReader;
+ private static EffectiveModelContext schemaContext;
+
+ private static final QNameModule INSTANCE_IDENTIFIER_MODULE_QNAME = QNameModule.create(
+ XMLNamespace.of("instance:identifier:module"), Revision.of("2014-01-17"));
+
+ public TestJsonBodyReader() {
+ super(schemaContext, null);
+ jsonBodyReader = new JsonNormalizedNodeBodyReader(controllerContext);
+ }
+
+ @Override
+ protected MediaType getMediaType() {
+ return new MediaType(MediaType.APPLICATION_XML, null);
+ }
+
+ @BeforeClass
+ public static void initialization()
+ throws Exception {
+ final Collection<File> testFiles = TestRestconfUtils.loadFiles("/instanceidentifier/yang");
+ testFiles.addAll(TestRestconfUtils.loadFiles("/invoke-rpc"));
+ schemaContext = YangParserTestUtils.parseYangFiles(testFiles);
+ }
+
+ @Test
+ public void moduleDataTest() throws Exception {
+ final DataSchemaNode dataSchemaNode =
+ schemaContext.getDataChildByName(QName.create(INSTANCE_IDENTIFIER_MODULE_QNAME, "cont"));
+ final YangInstanceIdentifier dataII = YangInstanceIdentifier.of(dataSchemaNode.getQName());
+ final String uri = "instance-identifier-module:cont";
+ mockBodyReader(uri, jsonBodyReader, false);
+ final InputStream inputStream = TestJsonBodyReader.class
+ .getResourceAsStream("/instanceidentifier/json/jsondata.json");
+ final NormalizedNodeContext returnValue = jsonBodyReader
+ .readFrom(null, null, null, mediaType, null, inputStream);
+ checkNormalizedNodeContext(returnValue);
+ checkExpectValueNormalizeNodeContext(dataSchemaNode, returnValue, dataII);
+ }
+
+ @Test
+ public void moduleSubContainerDataPutTest() throws Exception {
+ final DataSchemaNode dataSchemaNode =
+ schemaContext.getDataChildByName(QName.create(INSTANCE_IDENTIFIER_MODULE_QNAME, "cont"));
+ final QName cont1QName = QName.create(dataSchemaNode.getQName(), "cont1");
+ final YangInstanceIdentifier dataII = YangInstanceIdentifier.of(dataSchemaNode.getQName()).node(cont1QName);
+ final DataSchemaNode dataSchemaNodeOnPath = ((DataNodeContainer) dataSchemaNode).getDataChildByName(cont1QName);
+ final String uri = "instance-identifier-module:cont/cont1";
+ mockBodyReader(uri, jsonBodyReader, false);
+ final InputStream inputStream = TestJsonBodyReader.class
+ .getResourceAsStream("/instanceidentifier/json/json_sub_container.json");
+ final NormalizedNodeContext returnValue = jsonBodyReader
+ .readFrom(null, null, null, mediaType, null, inputStream);
+ checkNormalizedNodeContext(returnValue);
+ checkExpectValueNormalizeNodeContext(dataSchemaNodeOnPath, returnValue, dataII);
+ }
+
+ @Test
+ public void moduleSubContainerDataPostTest() throws Exception {
+ final DataSchemaNode dataSchemaNode =
+ schemaContext.getDataChildByName(QName.create(INSTANCE_IDENTIFIER_MODULE_QNAME, "cont"));
+ final QName cont1QName = QName.create(dataSchemaNode.getQName(), "cont1");
+ final YangInstanceIdentifier dataII = YangInstanceIdentifier.of(dataSchemaNode.getQName()).node(cont1QName);
+ final String uri = "instance-identifier-module:cont";
+ mockBodyReader(uri, jsonBodyReader, true);
+ final InputStream inputStream = TestJsonBodyReader.class
+ .getResourceAsStream("/instanceidentifier/json/json_sub_container.json");
+ final NormalizedNodeContext returnValue = jsonBodyReader
+ .readFrom(null, null, null, mediaType, null, inputStream);
+ checkNormalizedNodeContext(returnValue);
+ checkExpectValueNormalizeNodeContext(dataSchemaNode, returnValue, dataII);
+ }
+
+ @Test
+ public void moduleSubContainerAugmentDataPostTest() throws Exception {
+ final DataSchemaNode dataSchemaNode =
+ schemaContext.getDataChildByName(QName.create(INSTANCE_IDENTIFIER_MODULE_QNAME, "cont"));
+ final Module augmentModule = schemaContext.findModules(XMLNamespace.of("augment:module")).iterator().next();
+ final QName contAugmentQName = QName.create(augmentModule.getQNameModule(), "cont-augment");
+ final AugmentationIdentifier augII = new AugmentationIdentifier(Set.of(contAugmentQName));
+ final YangInstanceIdentifier dataII = YangInstanceIdentifier.of(dataSchemaNode.getQName())
+ .node(augII).node(contAugmentQName);
+ final String uri = "instance-identifier-module:cont";
+ mockBodyReader(uri, jsonBodyReader, true);
+ final InputStream inputStream = TestXmlBodyReader.class
+ .getResourceAsStream("/instanceidentifier/json/json_augment_container.json");
+ final NormalizedNodeContext returnValue = jsonBodyReader
+ .readFrom(null, null, null, mediaType, null, inputStream);
+ checkNormalizedNodeContext(returnValue);
+ checkExpectValueNormalizeNodeContext(dataSchemaNode, returnValue, dataII);
+ }
+
+ //FIXME: Uncomment this when JsonParserStream works correctly with case augmentation with choice
+ //@Test
+ public void moduleSubContainerChoiceAugmentDataPostTest() throws Exception {
+ final DataSchemaNode dataSchemaNode =
+ schemaContext.getDataChildByName(QName.create(INSTANCE_IDENTIFIER_MODULE_QNAME, "cont"));
+ final Module augmentModule = schemaContext.findModules(XMLNamespace.of("augment:module")).iterator().next();
+ final QName augmentChoice1QName = QName.create(augmentModule.getQNameModule(), "augment-choice1");
+ final QName augmentChoice2QName = QName.create(augmentChoice1QName, "augment-choice2");
+ final QName containerQName = QName.create(augmentChoice1QName, "case-choice-case-container1");
+ final AugmentationIdentifier augChoice1II = new AugmentationIdentifier(Set.of(augmentChoice1QName));
+ final AugmentationIdentifier augChoice2II = new AugmentationIdentifier(Set.of(augmentChoice2QName));
+ final YangInstanceIdentifier dataII = YangInstanceIdentifier.of(dataSchemaNode.getQName())
+ .node(augChoice1II).node(augmentChoice1QName).node(augChoice2II).node(augmentChoice2QName)
+ .node(containerQName);
+ final String uri = "instance-identifier-module:cont";
+ mockBodyReader(uri, jsonBodyReader, true);
+ final InputStream inputStream = TestXmlBodyReader.class
+ .getResourceAsStream("/instanceidentifier/json/json_augment_choice_container.json");
+ final NormalizedNodeContext returnValue = jsonBodyReader
+ .readFrom(null, null, null, mediaType, null, inputStream);
+ checkNormalizedNodeContext(returnValue);
+ checkExpectValueNormalizeNodeContext(dataSchemaNode, returnValue, dataII);
+ }
+
+ @Test
+ public void rpcModuleInputTest() throws Exception {
+ final String uri = "invoke-rpc-module:rpc-test";
+ mockBodyReader(uri, jsonBodyReader, true);
+ final InputStream inputStream = TestJsonBodyReader.class.getResourceAsStream("/invoke-rpc/json/rpc-input.json");
+ final NormalizedNodeContext returnValue = jsonBodyReader.readFrom(null, null, null, mediaType, null,
+ inputStream);
+ checkNormalizedNodeContextRpc(returnValue);
+ final ContainerNode inputNode = (ContainerNode) returnValue.getData();
+ final YangInstanceIdentifier yangCont = YangInstanceIdentifier.of(
+ QName.create(inputNode.getIdentifier().getNodeType(), "cont"));
+ final Optional<DataContainerChild> contDataNode = inputNode.findChildByArg(yangCont.getLastPathArgument());
+ assertTrue(contDataNode.isPresent());
+ assertTrue(contDataNode.get() instanceof ContainerNode);
+ final YangInstanceIdentifier yangleaf = YangInstanceIdentifier.of(
+ QName.create(inputNode.getIdentifier().getNodeType(), "lf"));
+ final Optional<DataContainerChild> leafDataNode = ((ContainerNode) contDataNode.get())
+ .findChildByArg(yangleaf.getLastPathArgument());
+ assertTrue(leafDataNode.isPresent());
+ assertTrue("lf-test".equalsIgnoreCase(leafDataNode.get().body().toString()));
+ }
+
+ private static void checkExpectValueNormalizeNodeContext(final DataSchemaNode dataSchemaNode,
+ final NormalizedNodeContext nnContext, final YangInstanceIdentifier dataNodeIdent) {
+ assertEquals(dataSchemaNode, nnContext.getInstanceIdentifierContext().getSchemaNode());
+ assertEquals(dataNodeIdent, nnContext.getInstanceIdentifierContext().getInstanceIdentifier());
+ assertNotNull(NormalizedNodes.findNode(nnContext.getData(), dataNodeIdent));
+ }
+}
diff --git a/netconf/restconf/restconf-nb-bierman02/src/test/java/org/opendaylight/controller/sal/rest/impl/test/providers/TestJsonBodyReaderMountPoint.java b/netconf/restconf/restconf-nb-bierman02/src/test/java/org/opendaylight/controller/sal/rest/impl/test/providers/TestJsonBodyReaderMountPoint.java
new file mode 100644
index 0000000..e8776c8
--- /dev/null
+++ b/netconf/restconf/restconf-nb-bierman02/src/test/java/org/opendaylight/controller/sal/rest/impl/test/providers/TestJsonBodyReaderMountPoint.java
@@ -0,0 +1,151 @@
+/*
+ * Copyright (c) 2015 Cisco Systems, Inc. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.controller.sal.rest.impl.test.providers;
+
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+import static org.mockito.Mockito.mock;
+
+import java.io.File;
+import java.io.InputStream;
+import java.util.Collection;
+import java.util.Optional;
+import javax.ws.rs.core.MediaType;
+import org.junit.BeforeClass;
+import org.junit.Test;
+import org.opendaylight.controller.md.sal.rest.common.TestRestconfUtils;
+import org.opendaylight.mdsal.dom.api.DOMMountPoint;
+import org.opendaylight.netconf.sal.rest.impl.JsonNormalizedNodeBodyReader;
+import org.opendaylight.netconf.sal.rest.impl.NormalizedNodeContext;
+import org.opendaylight.yangtools.yang.common.QName;
+import org.opendaylight.yangtools.yang.common.QNameModule;
+import org.opendaylight.yangtools.yang.common.Revision;
+import org.opendaylight.yangtools.yang.common.XMLNamespace;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
+import org.opendaylight.yangtools.yang.data.api.schema.ContainerNode;
+import org.opendaylight.yangtools.yang.data.api.schema.DataContainerChild;
+import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNodes;
+import org.opendaylight.yangtools.yang.model.api.DataNodeContainer;
+import org.opendaylight.yangtools.yang.model.api.DataSchemaNode;
+import org.opendaylight.yangtools.yang.model.api.EffectiveModelContext;
+import org.opendaylight.yangtools.yang.test.util.YangParserTestUtils;
+
+public class TestJsonBodyReaderMountPoint extends AbstractBodyReaderTest {
+
+ private final JsonNormalizedNodeBodyReader jsonBodyReader;
+ private static EffectiveModelContext schemaContext;
+
+ private static final QNameModule INSTANCE_IDENTIFIER_MODULE_QNAME = QNameModule.create(
+ XMLNamespace.of("instance:identifier:module"), Revision.of("2014-01-17"));
+
+ public TestJsonBodyReaderMountPoint() throws NoSuchFieldException, SecurityException {
+ super(schemaContext, mock(DOMMountPoint.class));
+ jsonBodyReader = new JsonNormalizedNodeBodyReader(controllerContext);
+ }
+
+ @Override
+ protected MediaType getMediaType() {
+ return new MediaType(MediaType.APPLICATION_XML, null);
+ }
+
+ @BeforeClass
+ public static void initialization() throws Exception {
+ final Collection<File> testFiles = TestRestconfUtils.loadFiles("/instanceidentifier/yang");
+ testFiles.addAll(TestRestconfUtils.loadFiles("/invoke-rpc"));
+ schemaContext = YangParserTestUtils.parseYangFiles(testFiles);
+ }
+
+ @Test
+ public void moduleDataTest() throws Exception {
+ final DataSchemaNode dataSchemaNode = schemaContext
+ .getDataChildByName(QName.create(INSTANCE_IDENTIFIER_MODULE_QNAME, "cont"));
+ final String uri = "instance-identifier-module:cont/yang-ext:mount/instance-identifier-module:cont";
+ mockBodyReader(uri, jsonBodyReader, false);
+ final InputStream inputStream = TestJsonBodyReaderMountPoint.class
+ .getResourceAsStream("/instanceidentifier/json/jsondata.json");
+ final NormalizedNodeContext returnValue = jsonBodyReader.readFrom(null,
+ null, null, mediaType, null, inputStream);
+ checkMountPointNormalizedNodeContext(returnValue);
+ checkExpectValueNormalizeNodeContext(dataSchemaNode, returnValue);
+ }
+
+ @Test
+ public void moduleSubContainerDataPutTest() throws Exception {
+ final DataSchemaNode dataSchemaNode = schemaContext
+ .getDataChildByName(QName.create(INSTANCE_IDENTIFIER_MODULE_QNAME, "cont"));
+ final String uri = "instance-identifier-module:cont/yang-ext:mount/instance-identifier-module:cont/cont1";
+ mockBodyReader(uri, jsonBodyReader, false);
+ final InputStream inputStream = TestJsonBodyReaderMountPoint.class
+ .getResourceAsStream("/instanceidentifier/json/json_sub_container.json");
+ final NormalizedNodeContext returnValue = jsonBodyReader.readFrom(null,
+ null, null, mediaType, null, inputStream);
+ checkMountPointNormalizedNodeContext(returnValue);
+ checkExpectValueNormalizeNodeContext(dataSchemaNode, returnValue,
+ QName.create(dataSchemaNode.getQName(), "cont1"));
+ }
+
+ @Test
+ public void moduleSubContainerDataPostTest() throws Exception {
+ final DataSchemaNode dataSchemaNode = schemaContext
+ .getDataChildByName(QName.create(INSTANCE_IDENTIFIER_MODULE_QNAME, "cont"));
+ final String uri = "instance-identifier-module:cont/yang-ext:mount/instance-identifier-module:cont";
+ mockBodyReader(uri, jsonBodyReader, true);
+ final InputStream inputStream = TestJsonBodyReaderMountPoint.class
+ .getResourceAsStream("/instanceidentifier/json/json_sub_container.json");
+ final NormalizedNodeContext returnValue = jsonBodyReader.readFrom(null,
+ null, null, mediaType, null, inputStream);
+ checkMountPointNormalizedNodeContext(returnValue);
+ checkExpectValueNormalizeNodeContext(dataSchemaNode, returnValue);
+ }
+
+ @Test
+ public void rpcModuleInputTest() throws Exception {
+ final String uri = "instance-identifier-module:cont/yang-ext:mount/invoke-rpc-module:rpc-test";
+ mockBodyReader(uri, jsonBodyReader, true);
+ final InputStream inputStream = TestJsonBodyReaderMountPoint.class.getResourceAsStream(
+ "/invoke-rpc/json/rpc-input.json");
+ final NormalizedNodeContext returnValue = jsonBodyReader.readFrom(null, null, null, mediaType, null,
+ inputStream);
+ checkNormalizedNodeContextRpc(returnValue);
+ final ContainerNode inputNode = (ContainerNode) returnValue.getData();
+ final YangInstanceIdentifier yangCont = YangInstanceIdentifier.of(
+ QName.create(inputNode.getIdentifier().getNodeType(), "cont"));
+ final Optional<DataContainerChild> contDataNode = inputNode.findChildByArg(yangCont.getLastPathArgument());
+ assertTrue(contDataNode.isPresent());
+ assertTrue(contDataNode.get() instanceof ContainerNode);
+ final YangInstanceIdentifier yangleaf = YangInstanceIdentifier.of(
+ QName.create(inputNode.getIdentifier().getNodeType(), "lf"));
+ final Optional<DataContainerChild> leafDataNode =
+ ((ContainerNode) contDataNode.get()).findChildByArg(yangleaf.getLastPathArgument());
+ assertTrue(leafDataNode.isPresent());
+ assertTrue("lf-test".equalsIgnoreCase(leafDataNode.get().body().toString()));
+ }
+
+ private void checkExpectValueNormalizeNodeContext(final DataSchemaNode dataSchemaNode,
+ final NormalizedNodeContext nnContext) {
+ checkExpectValueNormalizeNodeContext(dataSchemaNode, nnContext, null);
+ }
+
+ protected void checkExpectValueNormalizeNodeContext(final DataSchemaNode dataSchemaNode,
+ final NormalizedNodeContext nnContext, final QName qualifiedName) {
+ YangInstanceIdentifier dataNodeIdent = YangInstanceIdentifier.of(dataSchemaNode.getQName());
+ final DOMMountPoint mountPoint = nnContext.getInstanceIdentifierContext().getMountPoint();
+ final DataSchemaNode mountDataSchemaNode = modelContext(mountPoint).getDataChildByName(
+ dataSchemaNode.getQName());
+ assertNotNull(mountDataSchemaNode);
+ if (qualifiedName != null && dataSchemaNode instanceof DataNodeContainer) {
+ final DataSchemaNode child = ((DataNodeContainer) dataSchemaNode).getDataChildByName(qualifiedName);
+ dataNodeIdent = YangInstanceIdentifier.builder(dataNodeIdent).node(child.getQName()).build();
+ assertTrue(nnContext.getInstanceIdentifierContext().getSchemaNode().equals(child));
+ } else {
+ assertTrue(mountDataSchemaNode.equals(dataSchemaNode));
+ }
+ assertNotNull(NormalizedNodes.findNode(nnContext.getData(),
+ dataNodeIdent));
+ }
+}
diff --git a/netconf/restconf/restconf-nb-bierman02/src/test/java/org/opendaylight/controller/sal/rest/impl/test/providers/TestJsonBodyWriter.java b/netconf/restconf/restconf-nb-bierman02/src/test/java/org/opendaylight/controller/sal/rest/impl/test/providers/TestJsonBodyWriter.java
new file mode 100644
index 0000000..121a7d6
--- /dev/null
+++ b/netconf/restconf/restconf-nb-bierman02/src/test/java/org/opendaylight/controller/sal/rest/impl/test/providers/TestJsonBodyWriter.java
@@ -0,0 +1,65 @@
+/*
+ * Copyright (c) 2015 Cisco Systems, Inc. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+
+package org.opendaylight.controller.sal.rest.impl.test.providers;
+
+import static org.junit.Assert.assertTrue;
+
+import java.io.ByteArrayOutputStream;
+import java.io.File;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.util.Collection;
+import javax.ws.rs.core.MediaType;
+import org.junit.BeforeClass;
+import org.junit.Test;
+import org.opendaylight.controller.md.sal.rest.common.TestRestconfUtils;
+import org.opendaylight.netconf.sal.rest.impl.JsonNormalizedNodeBodyReader;
+import org.opendaylight.netconf.sal.rest.impl.NormalizedNodeContext;
+import org.opendaylight.netconf.sal.rest.impl.NormalizedNodeJsonBodyWriter;
+import org.opendaylight.yangtools.yang.model.api.EffectiveModelContext;
+import org.opendaylight.yangtools.yang.test.util.YangParserTestUtils;
+
+public class TestJsonBodyWriter extends AbstractBodyReaderTest {
+
+ private final JsonNormalizedNodeBodyReader jsonBodyReader;
+ private final NormalizedNodeJsonBodyWriter jsonBodyWriter;
+ private static EffectiveModelContext schemaContext;
+
+ public TestJsonBodyWriter() {
+ super(schemaContext, null);
+ this.jsonBodyWriter = new NormalizedNodeJsonBodyWriter();
+ this.jsonBodyReader = new JsonNormalizedNodeBodyReader(controllerContext);
+ }
+
+ @Override
+ protected MediaType getMediaType() {
+ return new MediaType(MediaType.APPLICATION_XML, null);
+ }
+
+ @BeforeClass
+ public static void initialization() throws Exception {
+ final Collection<File> testFiles = TestRestconfUtils.loadFiles("/instanceidentifier/yang");
+ testFiles.addAll(TestRestconfUtils.loadFiles("/invoke-rpc"));
+ schemaContext = YangParserTestUtils.parseYangFiles(testFiles);
+ }
+
+ @Test
+ public void rpcModuleInputTest() throws Exception {
+ final String uri = "invoke-rpc-module:rpc-test";
+ mockBodyReader(uri, this.jsonBodyReader, true);
+ final InputStream inputStream = TestJsonBodyWriter.class
+ .getResourceAsStream("/invoke-rpc/json/rpc-output.json");
+ final NormalizedNodeContext returnValue = this.jsonBodyReader.readFrom(null,
+ null, null, this.mediaType, null, inputStream);
+ final OutputStream output = new ByteArrayOutputStream();
+ this.jsonBodyWriter.writeTo(returnValue, null, null, null, this.mediaType, null,
+ output);
+ assertTrue(output.toString().contains("lf-test"));
+ }
+}
diff --git a/netconf/restconf/restconf-nb-bierman02/src/test/java/org/opendaylight/controller/sal/rest/impl/test/providers/TestJsonPatchBodyReader.java b/netconf/restconf/restconf-nb-bierman02/src/test/java/org/opendaylight/controller/sal/rest/impl/test/providers/TestJsonPatchBodyReader.java
new file mode 100644
index 0000000..f2a6c41
--- /dev/null
+++ b/netconf/restconf/restconf-nb-bierman02/src/test/java/org/opendaylight/controller/sal/rest/impl/test/providers/TestJsonPatchBodyReader.java
@@ -0,0 +1,165 @@
+/*
+ * Copyright (c) 2015 Cisco Systems, Inc. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.controller.sal.rest.impl.test.providers;
+
+import static javax.ws.rs.core.MediaType.APPLICATION_JSON;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertThrows;
+
+import java.io.InputStream;
+import javax.ws.rs.core.MediaType;
+import org.junit.BeforeClass;
+import org.junit.Test;
+import org.opendaylight.netconf.sal.rest.impl.JsonToPatchBodyReader;
+import org.opendaylight.restconf.common.errors.RestconfDocumentedException;
+import org.opendaylight.restconf.common.patch.PatchContext;
+import org.opendaylight.yangtools.yang.common.ErrorTag;
+import org.opendaylight.yangtools.yang.model.api.EffectiveModelContext;
+
+public class TestJsonPatchBodyReader extends AbstractBodyReaderTest {
+ private static EffectiveModelContext schemaContext;
+
+ private final JsonToPatchBodyReader jsonToPatchBodyReader;
+
+ public TestJsonPatchBodyReader() {
+ super(schemaContext, null);
+ jsonToPatchBodyReader = new JsonToPatchBodyReader(controllerContext);
+ }
+
+ @BeforeClass
+ public static void initialization() {
+ schemaContext = schemaContextLoader("/instanceidentifier/yang", schemaContext);
+ }
+
+ @Override
+ protected MediaType getMediaType() {
+ return new MediaType(APPLICATION_JSON, null);
+ }
+
+ @Test
+ public void modulePatchDataTest() throws Exception {
+ final String uri = "instance-identifier-patch-module:patch-cont/my-list1/leaf1";
+ mockBodyReader(uri, jsonToPatchBodyReader, false);
+
+ final InputStream inputStream = TestJsonBodyReader.class.getResourceAsStream(
+ "/instanceidentifier/json/jsonPATCHdata.json");
+
+ final PatchContext returnValue = jsonToPatchBodyReader.readFrom(null, null, null, mediaType, null, inputStream);
+ checkPatchContext(returnValue);
+ }
+
+ /**
+ * Test of successful Patch consisting of create and delete Patch operations.
+ */
+ @Test
+ public void modulePatchCreateAndDeleteTest() throws Exception {
+ final String uri = "instance-identifier-patch-module:patch-cont/my-list1/leaf1";
+ mockBodyReader(uri, jsonToPatchBodyReader, false);
+
+ final InputStream inputStream = TestJsonBodyReader.class.getResourceAsStream(
+ "/instanceidentifier/json/jsonPATCHdataCreateAndDelete.json");
+
+ final PatchContext returnValue = jsonToPatchBodyReader.readFrom(null, null, null, mediaType, null, inputStream);
+ checkPatchContext(returnValue);
+ }
+
+ /**
+ * Test trying to use Patch create operation which requires value without value. Test should fail with
+ * {@link RestconfDocumentedException} with error code 400.
+ */
+ @Test
+ public void modulePatchValueMissingNegativeTest() throws Exception {
+ final String uri = "instance-identifier-patch-module:patch-cont/my-list1/leaf1";
+ mockBodyReader(uri, jsonToPatchBodyReader, false);
+
+ final InputStream inputStream = TestJsonBodyReader.class.getResourceAsStream(
+ "/instanceidentifier/json/jsonPATCHdataValueMissing.json");
+
+ final RestconfDocumentedException ex = assertThrows(RestconfDocumentedException.class,
+ () -> jsonToPatchBodyReader.readFrom(null, null, null, mediaType, null, inputStream));
+ assertEquals(ErrorTag.MALFORMED_MESSAGE, ex.getErrors().get(0).getErrorTag());
+ }
+
+ /**
+ * Test trying to use value with Patch delete operation which does not support value. Test should fail with
+ * {@link RestconfDocumentedException} with error code 400.
+ */
+ @Test
+ public void modulePatchValueNotSupportedNegativeTest() throws Exception {
+ final String uri = "instance-identifier-patch-module:patch-cont/my-list1/leaf1";
+ mockBodyReader(uri, jsonToPatchBodyReader, false);
+
+ final InputStream inputStream = TestJsonBodyReader.class.getResourceAsStream(
+ "/instanceidentifier/json/jsonPATCHdataValueNotSupported.json");
+
+ final RestconfDocumentedException ex = assertThrows(RestconfDocumentedException.class,
+ () -> jsonToPatchBodyReader.readFrom(null, null, null, mediaType, null, inputStream));
+ assertEquals(ErrorTag.MALFORMED_MESSAGE, ex.getErrors().get(0).getErrorTag());
+ }
+
+ /**
+ * Test using Patch when target is completely specified in request URI and thus target leaf contains only '/' sign.
+ */
+ @Test
+ public void modulePatchCompleteTargetInURITest() throws Exception {
+ final String uri = "instance-identifier-patch-module:patch-cont";
+ mockBodyReader(uri, jsonToPatchBodyReader, false);
+
+ final InputStream inputStream = TestJsonBodyReader.class.getResourceAsStream(
+ "/instanceidentifier/json/jsonPATCHdataCompleteTargetInURI.json");
+
+ final PatchContext returnValue = jsonToPatchBodyReader.readFrom(null, null, null, mediaType, null, inputStream);
+ checkPatchContext(returnValue);
+ }
+
+ /**
+ * Test of Yang Patch merge operation on list. Test consists of two edit operations - replace and merge.
+ */
+ @Test
+ public void modulePatchMergeOperationOnListTest() throws Exception {
+ final String uri = "instance-identifier-patch-module:patch-cont/my-list1/leaf1";
+ mockBodyReader(uri, jsonToPatchBodyReader, false);
+
+ final InputStream inputStream = TestJsonBodyReader.class
+ .getResourceAsStream("/instanceidentifier/json/jsonPATCHMergeOperationOnList.json");
+
+ final PatchContext returnValue = jsonToPatchBodyReader.readFrom(null, null, null, mediaType, null, inputStream);
+ checkPatchContext(returnValue);
+ }
+
+ /**
+ * Test of Yang Patch merge operation on container. Test consists of two edit operations - create and merge.
+ */
+ @Test
+ public void modulePatchMergeOperationOnContainerTest() throws Exception {
+ final String uri = "instance-identifier-patch-module:patch-cont";
+ mockBodyReader(uri, jsonToPatchBodyReader, false);
+
+ final InputStream inputStream = TestJsonBodyReader.class.getResourceAsStream(
+ "/instanceidentifier/json/jsonPATCHMergeOperationOnContainer.json");
+
+ final PatchContext returnValue = jsonToPatchBodyReader.readFrom(null, null, null, mediaType, null, inputStream);
+ checkPatchContext(returnValue);
+ }
+
+ /**
+ * Test reading simple leaf value.
+ */
+ @Test
+ public void modulePatchSimpleLeafValueTest() throws Exception {
+ final String uri = "instance-identifier-patch-module:patch-cont/my-list1/leaf1";
+ mockBodyReader(uri, jsonToPatchBodyReader, false);
+
+ final InputStream inputStream = TestJsonBodyReader.class
+ .getResourceAsStream("/instanceidentifier/json/jsonPATCHSimpleLeafValue.json");
+
+ final PatchContext returnValue = jsonToPatchBodyReader
+ .readFrom(null, null, null, mediaType, null, inputStream);
+ checkPatchContext(returnValue);
+ }
+}
diff --git a/netconf/restconf/restconf-nb-bierman02/src/test/java/org/opendaylight/controller/sal/rest/impl/test/providers/TestJsonPatchBodyReaderMountPoint.java b/netconf/restconf/restconf-nb-bierman02/src/test/java/org/opendaylight/controller/sal/rest/impl/test/providers/TestJsonPatchBodyReaderMountPoint.java
new file mode 100644
index 0000000..4ad1a65
--- /dev/null
+++ b/netconf/restconf/restconf-nb-bierman02/src/test/java/org/opendaylight/controller/sal/rest/impl/test/providers/TestJsonPatchBodyReaderMountPoint.java
@@ -0,0 +1,172 @@
+/*
+ * Copyright (c) 2016 Cisco Systems, Inc. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.controller.sal.rest.impl.test.providers;
+
+import static javax.ws.rs.core.MediaType.APPLICATION_JSON;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertThrows;
+import static org.mockito.Mockito.mock;
+
+import java.io.InputStream;
+import javax.ws.rs.core.MediaType;
+import org.junit.BeforeClass;
+import org.junit.Test;
+import org.opendaylight.mdsal.dom.api.DOMMountPoint;
+import org.opendaylight.netconf.sal.rest.impl.JsonToPatchBodyReader;
+import org.opendaylight.restconf.common.errors.RestconfDocumentedException;
+import org.opendaylight.restconf.common.patch.PatchContext;
+import org.opendaylight.yangtools.yang.common.ErrorTag;
+import org.opendaylight.yangtools.yang.model.api.EffectiveModelContext;
+
+public class TestJsonPatchBodyReaderMountPoint extends AbstractBodyReaderTest {
+ private final JsonToPatchBodyReader jsonToPatchBodyReader;
+ private static EffectiveModelContext schemaContext;
+ private static final String MOUNT_POINT = "instance-identifier-module:cont/yang-ext:mount";
+
+ public TestJsonPatchBodyReaderMountPoint() {
+ super(schemaContext, mock(DOMMountPoint.class));
+ jsonToPatchBodyReader = new JsonToPatchBodyReader(controllerContext);
+ }
+
+ @Override
+ protected MediaType getMediaType() {
+ return new MediaType(APPLICATION_JSON, null);
+ }
+
+ @BeforeClass
+ public static void initialization() {
+ schemaContext = schemaContextLoader("/instanceidentifier/yang", schemaContext);
+ }
+
+ @Test
+ public void modulePatchDataTest() throws Exception {
+ final String uri = MOUNT_POINT + "/instance-identifier-patch-module:patch-cont/my-list1/leaf1";
+ mockBodyReader(uri, jsonToPatchBodyReader, false);
+
+ final InputStream inputStream = TestJsonBodyReader.class
+ .getResourceAsStream("/instanceidentifier/json/jsonPATCHdata.json");
+
+ final PatchContext returnValue = jsonToPatchBodyReader
+ .readFrom(null, null, null, mediaType, null, inputStream);
+ checkPatchContextMountPoint(returnValue);
+ }
+
+ /**
+ * Test of successful Patch consisting of create and delete Patch operations.
+ */
+ @Test
+ public void modulePatchCreateAndDeleteTest() throws Exception {
+ final String uri = MOUNT_POINT + "/instance-identifier-patch-module:patch-cont/my-list1/leaf1";
+ mockBodyReader(uri, jsonToPatchBodyReader, false);
+
+ final InputStream inputStream = TestJsonBodyReader.class
+ .getResourceAsStream("/instanceidentifier/json/jsonPATCHdataCreateAndDelete.json");
+
+ final PatchContext returnValue = jsonToPatchBodyReader
+ .readFrom(null, null, null, mediaType, null, inputStream);
+ checkPatchContextMountPoint(returnValue);
+ }
+
+ /**
+ * Test trying to use Patch create operation which requires value without value. Test should fail with
+ * {@link RestconfDocumentedException} with error code 400.
+ */
+ @Test
+ public void modulePatchValueMissingNegativeTest() throws Exception {
+ final String uri = MOUNT_POINT + "/instance-identifier-patch-module:patch-cont/my-list1/leaf1";
+ mockBodyReader(uri, jsonToPatchBodyReader, false);
+
+ final InputStream inputStream = TestJsonBodyReader.class.getResourceAsStream(
+ "/instanceidentifier/json/jsonPATCHdataValueMissing.json");
+
+ final RestconfDocumentedException ex = assertThrows(RestconfDocumentedException.class,
+ () -> jsonToPatchBodyReader.readFrom(null, null, null, mediaType, null, inputStream));
+ assertEquals(ErrorTag.MALFORMED_MESSAGE, ex.getErrors().get(0).getErrorTag());
+ }
+
+ /**
+ * Test trying to use value with Patch delete operation which does not support value. Test should fail with
+ * {@link RestconfDocumentedException} with error code 400.
+ */
+ @Test
+ public void modulePatchValueNotSupportedNegativeTest() throws Exception {
+ final String uri = MOUNT_POINT + "/instance-identifier-patch-module:patch-cont/my-list1/leaf1";
+ mockBodyReader(uri, jsonToPatchBodyReader, false);
+
+ final InputStream inputStream = TestJsonBodyReader.class
+ .getResourceAsStream("/instanceidentifier/json/jsonPATCHdataValueNotSupported.json");
+
+ final RestconfDocumentedException ex = assertThrows(RestconfDocumentedException.class,
+ () -> jsonToPatchBodyReader.readFrom(null, null, null, mediaType, null, inputStream));
+ assertEquals(ErrorTag.MALFORMED_MESSAGE, ex.getErrors().get(0).getErrorTag());
+ }
+
+ /**
+ * Test using Patch when target is completely specified in request URI and thus target leaf contains only '/' sign.
+ */
+ @Test
+ public void modulePatchCompleteTargetInURITest() throws Exception {
+ final String uri = MOUNT_POINT + "/instance-identifier-patch-module:patch-cont";
+ mockBodyReader(uri, jsonToPatchBodyReader, false);
+
+ final InputStream inputStream = TestJsonBodyReader.class
+ .getResourceAsStream("/instanceidentifier/json/jsonPATCHdataCompleteTargetInURI.json");
+
+ final PatchContext returnValue = jsonToPatchBodyReader
+ .readFrom(null, null, null, mediaType, null, inputStream);
+ checkPatchContextMountPoint(returnValue);
+ }
+
+ /**
+ * Test of Yang Patch merge operation on list. Test consists of two edit operations - replace and merge.
+ */
+ @Test
+ public void modulePatchMergeOperationOnListTest() throws Exception {
+ final String uri = MOUNT_POINT + "/instance-identifier-patch-module:patch-cont/my-list1/leaf1";
+ mockBodyReader(uri, jsonToPatchBodyReader, false);
+
+ final InputStream inputStream = TestJsonBodyReader.class
+ .getResourceAsStream("/instanceidentifier/json/jsonPATCHMergeOperationOnList.json");
+
+ final PatchContext returnValue = jsonToPatchBodyReader
+ .readFrom(null, null, null, mediaType, null, inputStream);
+ checkPatchContextMountPoint(returnValue);
+ }
+
+ /**
+ * Test of Yang Patch merge operation on container. Test consists of two edit operations - create and merge.
+ */
+ @Test
+ public void modulePatchMergeOperationOnContainerTest() throws Exception {
+ final String uri = MOUNT_POINT + "/instance-identifier-patch-module:patch-cont";
+ mockBodyReader(uri, jsonToPatchBodyReader, false);
+
+ final InputStream inputStream = TestJsonBodyReader.class
+ .getResourceAsStream("/instanceidentifier/json/jsonPATCHMergeOperationOnContainer.json");
+
+ final PatchContext returnValue = jsonToPatchBodyReader
+ .readFrom(null, null, null, mediaType, null, inputStream);
+ checkPatchContextMountPoint(returnValue);
+ }
+
+ /**
+ * Test reading simple leaf value.
+ */
+ @Test
+ public void modulePatchSimpleLeafValueTest() throws Exception {
+ final String uri = MOUNT_POINT + "/instance-identifier-patch-module:patch-cont/my-list1/leaf1";
+ mockBodyReader(uri, jsonToPatchBodyReader, false);
+
+ final InputStream inputStream = TestJsonBodyReader.class
+ .getResourceAsStream("/instanceidentifier/json/jsonPATCHSimpleLeafValue.json");
+
+ final PatchContext returnValue = jsonToPatchBodyReader
+ .readFrom(null, null, null, mediaType, null, inputStream);
+ checkPatchContext(returnValue);
+ }
+}
diff --git a/netconf/restconf/restconf-nb-bierman02/src/test/java/org/opendaylight/controller/sal/rest/impl/test/providers/TestXmlBodyReader.java b/netconf/restconf/restconf-nb-bierman02/src/test/java/org/opendaylight/controller/sal/rest/impl/test/providers/TestXmlBodyReader.java
new file mode 100644
index 0000000..7ff353e
--- /dev/null
+++ b/netconf/restconf/restconf-nb-bierman02/src/test/java/org/opendaylight/controller/sal/rest/impl/test/providers/TestXmlBodyReader.java
@@ -0,0 +1,287 @@
+/*
+ * Copyright (c) 2015 Cisco Systems, Inc. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.controller.sal.rest.impl.test.providers;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+
+import java.io.File;
+import java.io.InputStream;
+import java.util.Collection;
+import java.util.Optional;
+import java.util.Set;
+import javax.ws.rs.core.MediaType;
+import org.junit.Assert;
+import org.junit.BeforeClass;
+import org.junit.Test;
+import org.opendaylight.controller.md.sal.rest.common.TestRestconfUtils;
+import org.opendaylight.netconf.sal.rest.impl.NormalizedNodeContext;
+import org.opendaylight.netconf.sal.rest.impl.XmlNormalizedNodeBodyReader;
+import org.opendaylight.restconf.common.errors.RestconfDocumentedException;
+import org.opendaylight.restconf.common.errors.RestconfError;
+import org.opendaylight.yangtools.yang.common.ErrorTag;
+import org.opendaylight.yangtools.yang.common.ErrorType;
+import org.opendaylight.yangtools.yang.common.QName;
+import org.opendaylight.yangtools.yang.common.QNameModule;
+import org.opendaylight.yangtools.yang.common.Revision;
+import org.opendaylight.yangtools.yang.common.XMLNamespace;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.AugmentationIdentifier;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifier;
+import org.opendaylight.yangtools.yang.data.api.schema.ContainerNode;
+import org.opendaylight.yangtools.yang.data.api.schema.DataContainerChild;
+import org.opendaylight.yangtools.yang.data.api.schema.MapEntryNode;
+import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNodes;
+import org.opendaylight.yangtools.yang.model.api.DataNodeContainer;
+import org.opendaylight.yangtools.yang.model.api.DataSchemaNode;
+import org.opendaylight.yangtools.yang.model.api.EffectiveModelContext;
+import org.opendaylight.yangtools.yang.model.api.Module;
+import org.opendaylight.yangtools.yang.test.util.YangParserTestUtils;
+
+public class TestXmlBodyReader extends AbstractBodyReaderTest {
+
+ private final XmlNormalizedNodeBodyReader xmlBodyReader;
+ private static EffectiveModelContext schemaContext;
+ private static final QNameModule INSTANCE_IDENTIFIER_MODULE_QNAME = QNameModule.create(
+ XMLNamespace.of("instance:identifier:module"), Revision.of("2014-01-17"));
+
+ public TestXmlBodyReader() {
+ super(schemaContext, null);
+ xmlBodyReader = new XmlNormalizedNodeBodyReader(controllerContext);
+ }
+
+ @Override
+ protected MediaType getMediaType() {
+ return new MediaType(MediaType.APPLICATION_XML, null);
+ }
+
+ @BeforeClass
+ public static void initialization() throws Exception {
+ final Collection<File> testFiles = TestRestconfUtils.loadFiles("/instanceidentifier/yang");
+ testFiles.addAll(TestRestconfUtils.loadFiles("/invoke-rpc"));
+ testFiles.addAll(TestRestconfUtils.loadFiles("/foo-xml-test/yang"));
+ schemaContext = YangParserTestUtils.parseYangFiles(testFiles);
+ }
+
+ @Test
+ public void putXmlTest() throws Exception {
+ runXmlTest(false, "foo:top-level-list/key-value");
+ }
+
+ @Test
+ public void postXmlTest() throws Exception {
+ runXmlTest(true, "");
+ }
+
+ private void runXmlTest(final boolean isPost, final String path) throws Exception {
+ mockBodyReader(path, xmlBodyReader, isPost);
+ final InputStream inputStream = TestXmlBodyReader.class.getResourceAsStream("/foo-xml-test/foo.xml");
+ final NormalizedNodeContext nnc = xmlBodyReader.readFrom(null, null, null, mediaType, null, inputStream);
+ assertNotNull(nnc);
+
+ assertTrue(nnc.getData() instanceof MapEntryNode);
+ final MapEntryNode data = (MapEntryNode) nnc.getData();
+ assertEquals(2, data.size());
+ for (final DataContainerChild child : data.body()) {
+ switch (child.getIdentifier().getNodeType().getLocalName()) {
+ case "key-leaf":
+ assertEquals("key-value", child.body());
+ break;
+
+ case "ordinary-leaf":
+ assertEquals("leaf-value", child.body());
+ break;
+ default:
+ fail();
+ }
+ }
+ }
+
+ @Test
+ public void moduleDataTest() throws Exception {
+ final DataSchemaNode dataSchemaNode =
+ schemaContext.getDataChildByName(QName.create(INSTANCE_IDENTIFIER_MODULE_QNAME, "cont"));
+ final YangInstanceIdentifier dataII = YangInstanceIdentifier.of(dataSchemaNode.getQName());
+ final String uri = "instance-identifier-module:cont";
+ mockBodyReader(uri, xmlBodyReader, false);
+ final InputStream inputStream = TestXmlBodyReader.class
+ .getResourceAsStream("/instanceidentifier/xml/xmldata.xml");
+ final NormalizedNodeContext returnValue = xmlBodyReader
+ .readFrom(null, null, null, mediaType, null, inputStream);
+ checkNormalizedNodeContext(returnValue);
+ checkExpectValueNormalizeNodeContext(dataSchemaNode, returnValue, dataII);
+ }
+
+ @Test
+ public void moduleSubContainerDataPutTest() throws Exception {
+ final DataSchemaNode dataSchemaNode =
+ schemaContext.getDataChildByName(QName.create(INSTANCE_IDENTIFIER_MODULE_QNAME, "cont"));
+ final QName cont1QName = QName.create(dataSchemaNode.getQName(), "cont1");
+ final YangInstanceIdentifier dataII = YangInstanceIdentifier.of(dataSchemaNode.getQName()).node(cont1QName);
+ final DataSchemaNode dataSchemaNodeOnPath = ((DataNodeContainer) dataSchemaNode).getDataChildByName(cont1QName);
+ final String uri = "instance-identifier-module:cont/cont1";
+ mockBodyReader(uri, xmlBodyReader, false);
+ final InputStream inputStream = TestXmlBodyReader.class
+ .getResourceAsStream("/instanceidentifier/xml/xml_sub_container.xml");
+ final NormalizedNodeContext returnValue = xmlBodyReader
+ .readFrom(null, null, null, mediaType, null, inputStream);
+ checkNormalizedNodeContext(returnValue);
+ checkExpectValueNormalizeNodeContext(dataSchemaNodeOnPath, returnValue, dataII);
+ }
+
+ @Test
+ public void moduleSubContainerDataPostTest() throws Exception {
+ final DataSchemaNode dataSchemaNode =
+ schemaContext.getDataChildByName(QName.create(INSTANCE_IDENTIFIER_MODULE_QNAME, "cont"));
+ final QName cont1QName = QName.create(dataSchemaNode.getQName(), "cont1");
+ final YangInstanceIdentifier dataII = YangInstanceIdentifier.of(dataSchemaNode.getQName()).node(cont1QName);
+ final String uri = "instance-identifier-module:cont";
+ mockBodyReader(uri, xmlBodyReader, true);
+ final InputStream inputStream = TestXmlBodyReader.class
+ .getResourceAsStream("/instanceidentifier/xml/xml_sub_container.xml");
+ final NormalizedNodeContext returnValue = xmlBodyReader
+ .readFrom(null, null, null, mediaType, null, inputStream);
+ checkNormalizedNodeContext(returnValue);
+ checkExpectValueNormalizeNodeContext(dataSchemaNode, returnValue, dataII);
+ }
+
+ @Test
+ public void moduleSubContainerAugmentDataPostTest() throws Exception {
+ final DataSchemaNode dataSchemaNode =
+ schemaContext.getDataChildByName(QName.create(INSTANCE_IDENTIFIER_MODULE_QNAME, "cont"));
+ final Module augmentModule = schemaContext.findModules(XMLNamespace.of("augment:module")).iterator().next();
+ final QName contAugmentQName = QName.create(augmentModule.getQNameModule(), "cont-augment");
+ final AugmentationIdentifier augII = new AugmentationIdentifier(Set.of(contAugmentQName));
+ final YangInstanceIdentifier dataII = YangInstanceIdentifier.of(dataSchemaNode.getQName())
+ .node(augII).node(contAugmentQName);
+ final String uri = "instance-identifier-module:cont";
+ mockBodyReader(uri, xmlBodyReader, true);
+ final InputStream inputStream = TestXmlBodyReader.class
+ .getResourceAsStream("/instanceidentifier/xml/xml_augment_container.xml");
+ final NormalizedNodeContext returnValue = xmlBodyReader
+ .readFrom(null, null, null, mediaType, null, inputStream);
+ checkNormalizedNodeContext(returnValue);
+ checkExpectValueNormalizeNodeContext(dataSchemaNode, returnValue, dataII);
+ }
+
+ @Test
+ public void moduleSubContainerChoiceAugmentDataPostTest() throws Exception {
+ final DataSchemaNode dataSchemaNode =
+ schemaContext.getDataChildByName(QName.create(INSTANCE_IDENTIFIER_MODULE_QNAME, "cont"));
+ final Module augmentModule = schemaContext.findModules(XMLNamespace.of("augment:module")).iterator().next();
+ final QName augmentChoice1QName = QName.create(augmentModule.getQNameModule(), "augment-choice1");
+ final QName augmentChoice2QName = QName.create(augmentChoice1QName, "augment-choice2");
+ final YangInstanceIdentifier dataII = YangInstanceIdentifier.of(dataSchemaNode.getQName())
+ .node(new AugmentationIdentifier(Set.of(augmentChoice1QName)))
+ .node(augmentChoice1QName)
+ // FIXME: DataSchemaTreeNode intepretation seems to have a bug
+ //.node(new AugmentationIdentifier(Set.of(augmentChoice2QName)))
+ .node(augmentChoice2QName)
+ .node(QName.create(augmentChoice1QName, "case-choice-case-container1"));
+ final String uri = "instance-identifier-module:cont";
+ mockBodyReader(uri, xmlBodyReader, true);
+ final InputStream inputStream = TestXmlBodyReader.class
+ .getResourceAsStream("/instanceidentifier/xml/xml_augment_choice_container.xml");
+ final NormalizedNodeContext returnValue = xmlBodyReader
+ .readFrom(null, null, null, mediaType, null, inputStream);
+ checkNormalizedNodeContext(returnValue);
+ checkExpectValueNormalizeNodeContext(dataSchemaNode, returnValue, dataII);
+ }
+
+ @Test
+ public void rpcModuleInputTest() throws Exception {
+ final String uri = "invoke-rpc-module:rpc-test";
+ mockBodyReader(uri, xmlBodyReader, true);
+ final InputStream inputStream = TestXmlBodyReader.class.getResourceAsStream("/invoke-rpc/xml/rpc-input.xml");
+ final NormalizedNodeContext returnValue = xmlBodyReader.readFrom(null, null, null, mediaType, null,
+ inputStream);
+ checkNormalizedNodeContextRpc(returnValue);
+ final ContainerNode contNode = (ContainerNode) returnValue.getData();
+ final Optional<DataContainerChild> contDataNodePotential = contNode.findChildByArg(new NodeIdentifier(
+ QName.create(contNode.getIdentifier().getNodeType(), "cont")));
+ assertTrue(contDataNodePotential.isPresent());
+ final ContainerNode contDataNode = (ContainerNode) contDataNodePotential.get();
+ final Optional<DataContainerChild> leafDataNode = contDataNode.findChildByArg(new NodeIdentifier(
+ QName.create(contDataNode.getIdentifier().getNodeType(), "lf")));
+ assertTrue(leafDataNode.isPresent());
+ assertTrue("lf-test".equalsIgnoreCase(leafDataNode.get().body().toString()));
+ }
+
+ private static void checkExpectValueNormalizeNodeContext(final DataSchemaNode dataSchemaNode,
+ final NormalizedNodeContext nnContext, final YangInstanceIdentifier dataNodeIdent) {
+ assertEquals(dataSchemaNode, nnContext.getInstanceIdentifierContext().getSchemaNode());
+ assertEquals(dataNodeIdent, nnContext.getInstanceIdentifierContext().getInstanceIdentifier());
+ assertNotNull(NormalizedNodes.findNode(nnContext.getData(), dataNodeIdent));
+ }
+
+ /**
+ * Test when container with the same name is placed in two modules (foo-module and bar-module). Namespace must be
+ * used to distinguish between them to find correct one. Check if container was found not only according to its name
+ * but also by correct namespace used in payload.
+ */
+ @Test
+ public void findFooContainerUsingNamespaceTest() throws Exception {
+ mockBodyReader("", xmlBodyReader, true);
+ final InputStream inputStream = TestXmlBodyReader.class
+ .getResourceAsStream("/instanceidentifier/xml/xmlDataFindFooContainer.xml");
+ final NormalizedNodeContext returnValue = xmlBodyReader
+ .readFrom(null, null, null, mediaType, null, inputStream);
+
+ // check return value
+ checkNormalizedNodeContext(returnValue);
+ // check if container was found both according to its name and namespace
+ assertEquals("Not correct container found, name was ignored",
+ "foo-bar-container", returnValue.getData().getIdentifier().getNodeType().getLocalName());
+ assertEquals("Not correct container found, namespace was ignored",
+ "foo:module", returnValue.getData().getIdentifier().getNodeType().getNamespace().toString());
+ }
+
+ /**
+ * Test when container with the same name is placed in two modules (foo-module and bar-module). Namespace must be
+ * used to distinguish between them to find correct one. Check if container was found not only according to its name
+ * but also by correct namespace used in payload.
+ */
+ @Test
+ public void findBarContainerUsingNamespaceTest() throws Exception {
+ mockBodyReader("", xmlBodyReader, true);
+ final InputStream inputStream = TestXmlBodyReader.class
+ .getResourceAsStream("/instanceidentifier/xml/xmlDataFindBarContainer.xml");
+ final NormalizedNodeContext returnValue = xmlBodyReader
+ .readFrom(null, null, null, mediaType, null, inputStream);
+
+ // check return value
+ checkNormalizedNodeContext(returnValue);
+ // check if container was found both according to its name and namespace
+ assertEquals("Not correct container found, name was ignored",
+ "foo-bar-container", returnValue.getData().getIdentifier().getNodeType().getLocalName());
+ assertEquals("Not correct container found, namespace was ignored",
+ "bar:module", returnValue.getData().getIdentifier().getNodeType().getNamespace().toString());
+ }
+
+ /**
+ * Test PUT operation when message root element is not the same as the last element in request URI.
+ * PUT operation message should always start with schema node from URI otherwise exception should be
+ * thrown.
+ */
+ @Test
+ public void wrongRootElementTest() throws Exception {
+ mockBodyReader("instance-identifier-module:cont", xmlBodyReader, false);
+ final InputStream inputStream = TestXmlBodyReader.class.getResourceAsStream(
+ "/instanceidentifier/xml/bug7933.xml");
+ try {
+ xmlBodyReader.readFrom(null, null, null, mediaType, null, inputStream);
+ Assert.fail("Test should fail due to malformed PUT operation message");
+ } catch (final RestconfDocumentedException exception) {
+ final RestconfError restconfError = exception.getErrors().get(0);
+ assertEquals(ErrorType.PROTOCOL, restconfError.getErrorType());
+ assertEquals(ErrorTag.MALFORMED_MESSAGE, restconfError.getErrorTag());
+ }
+ }
+}
diff --git a/netconf/restconf/restconf-nb-bierman02/src/test/java/org/opendaylight/controller/sal/rest/impl/test/providers/TestXmlBodyReaderMountPoint.java b/netconf/restconf/restconf-nb-bierman02/src/test/java/org/opendaylight/controller/sal/rest/impl/test/providers/TestXmlBodyReaderMountPoint.java
new file mode 100644
index 0000000..fe257db
--- /dev/null
+++ b/netconf/restconf/restconf-nb-bierman02/src/test/java/org/opendaylight/controller/sal/rest/impl/test/providers/TestXmlBodyReaderMountPoint.java
@@ -0,0 +1,220 @@
+/*
+ * Copyright (c) 2015 Cisco Systems, Inc. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.controller.sal.rest.impl.test.providers;
+
+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 java.io.File;
+import java.io.InputStream;
+import java.util.Collection;
+import java.util.Optional;
+import javax.ws.rs.core.MediaType;
+import org.junit.Assert;
+import org.junit.BeforeClass;
+import org.junit.Test;
+import org.opendaylight.controller.md.sal.rest.common.TestRestconfUtils;
+import org.opendaylight.mdsal.dom.api.DOMMountPoint;
+import org.opendaylight.netconf.sal.rest.impl.NormalizedNodeContext;
+import org.opendaylight.netconf.sal.rest.impl.XmlNormalizedNodeBodyReader;
+import org.opendaylight.restconf.common.errors.RestconfDocumentedException;
+import org.opendaylight.restconf.common.errors.RestconfError;
+import org.opendaylight.yangtools.yang.common.ErrorTag;
+import org.opendaylight.yangtools.yang.common.ErrorType;
+import org.opendaylight.yangtools.yang.common.QName;
+import org.opendaylight.yangtools.yang.common.QNameModule;
+import org.opendaylight.yangtools.yang.common.Revision;
+import org.opendaylight.yangtools.yang.common.XMLNamespace;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
+import org.opendaylight.yangtools.yang.data.api.schema.ContainerNode;
+import org.opendaylight.yangtools.yang.data.api.schema.DataContainerChild;
+import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNodes;
+import org.opendaylight.yangtools.yang.model.api.DataNodeContainer;
+import org.opendaylight.yangtools.yang.model.api.DataSchemaNode;
+import org.opendaylight.yangtools.yang.model.api.EffectiveModelContext;
+import org.opendaylight.yangtools.yang.test.util.YangParserTestUtils;
+
+public class TestXmlBodyReaderMountPoint extends AbstractBodyReaderTest {
+ private final XmlNormalizedNodeBodyReader xmlBodyReader;
+ private static EffectiveModelContext schemaContext;
+
+ private static final QNameModule INSTANCE_IDENTIFIER_MODULE_QNAME = QNameModule.create(
+ XMLNamespace.of("instance:identifier:module"), Revision.of("2014-01-17"));
+
+ public TestXmlBodyReaderMountPoint() {
+ super(schemaContext, mock(DOMMountPoint.class));
+ xmlBodyReader = new XmlNormalizedNodeBodyReader(controllerContext);
+ }
+
+ @Override
+ protected MediaType getMediaType() {
+ return new MediaType(MediaType.APPLICATION_XML, null);
+ }
+
+ @BeforeClass
+ public static void initialization() throws Exception {
+ final Collection<File> testFiles = TestRestconfUtils.loadFiles("/instanceidentifier/yang");
+ testFiles.addAll(TestRestconfUtils.loadFiles("/invoke-rpc"));
+ schemaContext = YangParserTestUtils.parseYangFiles(testFiles);
+ }
+
+ @Test
+ public void moduleDataTest() throws Exception {
+ final DataSchemaNode dataSchemaNode = schemaContext
+ .getDataChildByName(QName.create(INSTANCE_IDENTIFIER_MODULE_QNAME, "cont"));
+ final String uri = "instance-identifier-module:cont/yang-ext:mount/instance-identifier-module:cont";
+ mockBodyReader(uri, xmlBodyReader, false);
+ final InputStream inputStream = TestXmlBodyReaderMountPoint.class
+ .getResourceAsStream("/instanceidentifier/xml/xmldata.xml");
+ final NormalizedNodeContext returnValue = xmlBodyReader.readFrom(null,
+ null, null, mediaType, null, inputStream);
+ checkMountPointNormalizedNodeContext(returnValue);
+ checkExpectValueNormalizeNodeContext(dataSchemaNode, returnValue);
+ }
+
+ @Test
+ public void moduleSubContainerDataPutTest() throws Exception {
+ final DataSchemaNode dataSchemaNode = schemaContext
+ .getDataChildByName(QName.create(INSTANCE_IDENTIFIER_MODULE_QNAME, "cont"));
+ final String uri = "instance-identifier-module:cont/yang-ext:mount/instance-identifier-module:cont/cont1";
+ mockBodyReader(uri, xmlBodyReader, false);
+ final InputStream inputStream = TestXmlBodyReaderMountPoint.class
+ .getResourceAsStream("/instanceidentifier/xml/xml_sub_container.xml");
+ final NormalizedNodeContext returnValue = xmlBodyReader.readFrom(null,
+ null, null, mediaType, null, inputStream);
+ checkMountPointNormalizedNodeContext(returnValue);
+ checkExpectValueNormalizeNodeContext(dataSchemaNode, returnValue,
+ QName.create(dataSchemaNode.getQName(), "cont1"));
+ }
+
+ @Test
+ public void moduleSubContainerDataPostTest() throws Exception {
+ final DataSchemaNode dataSchemaNode = schemaContext
+ .getDataChildByName(QName.create(INSTANCE_IDENTIFIER_MODULE_QNAME, "cont"));
+ final String uri = "instance-identifier-module:cont/yang-ext:mount/instance-identifier-module:cont";
+ mockBodyReader(uri, xmlBodyReader, true);
+ final InputStream inputStream = TestXmlBodyReaderMountPoint.class
+ .getResourceAsStream("/instanceidentifier/xml/xml_sub_container.xml");
+ final NormalizedNodeContext returnValue = xmlBodyReader.readFrom(null,
+ null, null, mediaType, null, inputStream);
+ checkMountPointNormalizedNodeContext(returnValue);
+ checkExpectValueNormalizeNodeContext(dataSchemaNode, returnValue);
+ }
+
+ @Test
+ public void rpcModuleInputTest() throws Exception {
+ final String uri = "instance-identifier-module:cont/yang-ext:mount/invoke-rpc-module:rpc-test";
+ mockBodyReader(uri, xmlBodyReader, true);
+ final InputStream inputStream = TestXmlBodyReaderMountPoint.class
+ .getResourceAsStream("/invoke-rpc/xml/rpc-input.xml");
+ final NormalizedNodeContext returnValue = xmlBodyReader.readFrom(null,
+ null, null, mediaType, null, inputStream);
+ checkNormalizedNodeContextRpc(returnValue);
+ final ContainerNode contNode = (ContainerNode) returnValue.getData();
+ final YangInstanceIdentifier yangCont = YangInstanceIdentifier.of(
+ QName.create(contNode.getIdentifier().getNodeType(), "cont"));
+ final Optional<DataContainerChild> contDataNodePotential =
+ contNode.findChildByArg(yangCont.getLastPathArgument());
+ assertTrue(contDataNodePotential.isPresent());
+ final ContainerNode contDataNode = (ContainerNode) contDataNodePotential.get();
+ final YangInstanceIdentifier yangLeaf = YangInstanceIdentifier.of(
+ QName.create(contDataNode.getIdentifier().getNodeType(), "lf"));
+ final Optional<DataContainerChild> leafDataNode = contDataNode.findChildByArg(yangLeaf.getLastPathArgument());
+ assertTrue(leafDataNode.isPresent());
+ assertTrue("lf-test".equalsIgnoreCase(leafDataNode.get().body().toString()));
+ }
+
+ private void checkExpectValueNormalizeNodeContext(
+ final DataSchemaNode dataSchemaNode,
+ final NormalizedNodeContext nnContext) {
+ checkExpectValueNormalizeNodeContext(dataSchemaNode, nnContext, null);
+ }
+
+ protected void checkExpectValueNormalizeNodeContext(
+ final DataSchemaNode dataSchemaNode, final NormalizedNodeContext nnContext, final QName qualifiedName) {
+ YangInstanceIdentifier dataNodeIdent = YangInstanceIdentifier.of(dataSchemaNode.getQName());
+ final DOMMountPoint mountPoint = nnContext.getInstanceIdentifierContext().getMountPoint();
+ final DataSchemaNode mountDataSchemaNode =
+ modelContext(mountPoint).getDataChildByName(dataSchemaNode.getQName());
+ assertNotNull(mountDataSchemaNode);
+ if (qualifiedName != null && dataSchemaNode instanceof DataNodeContainer) {
+ final DataSchemaNode child = ((DataNodeContainer) dataSchemaNode).getDataChildByName(qualifiedName);
+ dataNodeIdent = YangInstanceIdentifier.builder(dataNodeIdent).node(child.getQName()).build();
+ assertTrue(nnContext.getInstanceIdentifierContext().getSchemaNode().equals(child));
+ } else {
+ assertTrue(mountDataSchemaNode.equals(dataSchemaNode));
+ }
+ assertNotNull(NormalizedNodes.findNode(nnContext.getData(), dataNodeIdent));
+ }
+
+ /**
+ * Test when container with the same name is placed in two modules (foo-module and bar-module). Namespace must be
+ * used to distinguish between them to find correct one. Check if container was found not only according to its name
+ * but also by correct namespace used in payload.
+ */
+ @Test
+ public void findFooContainerUsingNamespaceTest() throws Exception {
+ mockBodyReader("instance-identifier-module:cont/yang-ext:mount", xmlBodyReader, true);
+ final InputStream inputStream = TestXmlBodyReader.class
+ .getResourceAsStream("/instanceidentifier/xml/xmlDataFindFooContainer.xml");
+ final NormalizedNodeContext returnValue = xmlBodyReader
+ .readFrom(null, null, null, mediaType, null, inputStream);
+
+ // check return value
+ checkMountPointNormalizedNodeContext(returnValue);
+ // check if container was found both according to its name and namespace
+ assertEquals("Not correct container found, name was ignored",
+ "foo-bar-container", returnValue.getData().getIdentifier().getNodeType().getLocalName());
+ assertEquals("Not correct container found, namespace was ignored",
+ "foo:module", returnValue.getData().getIdentifier().getNodeType().getNamespace().toString());
+ }
+
+ /**
+ * Test when container with the same name is placed in two modules (foo-module and bar-module). Namespace must be
+ * used to distinguish between them to find correct one. Check if container was found not only according to its name
+ * but also by correct namespace used in payload.
+ */
+ @Test
+ public void findBarContainerUsingNamespaceTest() throws Exception {
+ mockBodyReader("instance-identifier-module:cont/yang-ext:mount", xmlBodyReader, true);
+ final InputStream inputStream = TestXmlBodyReader.class
+ .getResourceAsStream("/instanceidentifier/xml/xmlDataFindBarContainer.xml");
+ final NormalizedNodeContext returnValue = xmlBodyReader
+ .readFrom(null, null, null, mediaType, null, inputStream);
+
+ // check return value
+ checkMountPointNormalizedNodeContext(returnValue);
+ // check if container was found both according to its name and namespace
+ assertEquals("Not correct container found, name was ignored",
+ "foo-bar-container", returnValue.getData().getIdentifier().getNodeType().getLocalName());
+ assertEquals("Not correct container found, namespace was ignored",
+ "bar:module", returnValue.getData().getIdentifier().getNodeType().getNamespace().toString());
+ }
+
+ /**
+ * Test PUT operation when message root element is not the same as the last element in request URI.
+ * PUT operation message should always start with schema node from URI otherwise exception should be
+ * thrown.
+ */
+ @Test
+ public void wrongRootElementTest() throws Exception {
+ mockBodyReader("instance-identifier-module:cont/yang-ext:mount", xmlBodyReader, false);
+ final InputStream inputStream = TestXmlBodyReader.class.getResourceAsStream(
+ "/instanceidentifier/xml/bug7933.xml");
+ try {
+ xmlBodyReader.readFrom(null, null, null, mediaType, null, inputStream);
+ Assert.fail("Test should fail due to malformed PUT operation message");
+ } catch (final RestconfDocumentedException exception) {
+ final RestconfError restconfError = exception.getErrors().get(0);
+ assertEquals(ErrorType.PROTOCOL, restconfError.getErrorType());
+ assertEquals(ErrorTag.MALFORMED_MESSAGE, restconfError.getErrorTag());
+ }
+ }
+}
diff --git a/netconf/restconf/restconf-nb-bierman02/src/test/java/org/opendaylight/controller/sal/rest/impl/test/providers/TestXmlBodyWriter.java b/netconf/restconf/restconf-nb-bierman02/src/test/java/org/opendaylight/controller/sal/rest/impl/test/providers/TestXmlBodyWriter.java
new file mode 100644
index 0000000..169d806
--- /dev/null
+++ b/netconf/restconf/restconf-nb-bierman02/src/test/java/org/opendaylight/controller/sal/rest/impl/test/providers/TestXmlBodyWriter.java
@@ -0,0 +1,58 @@
+/*
+ * Copyright (c) 2015 Cisco Systems, Inc. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+
+package org.opendaylight.controller.sal.rest.impl.test.providers;
+
+import static org.junit.Assert.assertTrue;
+
+import java.io.ByteArrayOutputStream;
+import java.io.File;
+import java.io.OutputStream;
+import java.util.Collection;
+import javax.ws.rs.core.MediaType;
+import org.junit.BeforeClass;
+import org.junit.Test;
+import org.opendaylight.controller.md.sal.rest.common.TestRestconfUtils;
+import org.opendaylight.netconf.sal.rest.impl.NormalizedNodeContext;
+import org.opendaylight.netconf.sal.rest.impl.NormalizedNodeXmlBodyWriter;
+import org.opendaylight.yangtools.yang.model.api.EffectiveModelContext;
+import org.opendaylight.yangtools.yang.test.util.YangParserTestUtils;
+
+public class TestXmlBodyWriter extends AbstractBodyReaderTest {
+
+ private final NormalizedNodeXmlBodyWriter xmlBodyWriter;
+ private static EffectiveModelContext schemaContext;
+
+ public TestXmlBodyWriter() {
+ super(schemaContext, null);
+ this.xmlBodyWriter = new NormalizedNodeXmlBodyWriter();
+ }
+
+ @Override
+ protected MediaType getMediaType() {
+ return new MediaType(MediaType.APPLICATION_XML, null);
+ }
+
+ @BeforeClass
+ public static void initialization() throws Exception {
+ final Collection<File> testFiles = TestRestconfUtils.loadFiles("/instanceidentifier/yang");
+ testFiles.addAll(TestRestconfUtils.loadFiles("/invoke-rpc"));
+ schemaContext = YangParserTestUtils.parseYangFiles(testFiles);
+ }
+
+ @Test
+ public void rpcModuleInputTest() throws Exception {
+ final String uri = "invoke-rpc-module:rpc-test";
+ final String pathToInputFile = "/invoke-rpc/xml/rpc-output.xml";
+ final NormalizedNodeContext nnContext = TestRestconfUtils
+ .loadNormalizedContextFromXmlFile(pathToInputFile, uri, controllerContext);
+ final OutputStream output = new ByteArrayOutputStream();
+ this.xmlBodyWriter.writeTo(nnContext, null, null, null, this.mediaType, null, output);
+ assertTrue(output.toString().contains("lf-test"));
+ }
+}
diff --git a/netconf/restconf/restconf-nb-bierman02/src/test/java/org/opendaylight/controller/sal/rest/impl/test/providers/TestXmlPatchBodyReader.java b/netconf/restconf/restconf-nb-bierman02/src/test/java/org/opendaylight/controller/sal/rest/impl/test/providers/TestXmlPatchBodyReader.java
new file mode 100644
index 0000000..8b37ba4
--- /dev/null
+++ b/netconf/restconf/restconf-nb-bierman02/src/test/java/org/opendaylight/controller/sal/rest/impl/test/providers/TestXmlPatchBodyReader.java
@@ -0,0 +1,137 @@
+/*
+ * Copyright (c) 2015 Cisco Systems, Inc. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.controller.sal.rest.impl.test.providers;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertThrows;
+
+import java.io.InputStream;
+import javax.ws.rs.core.MediaType;
+import org.junit.BeforeClass;
+import org.junit.Test;
+import org.opendaylight.netconf.sal.rest.impl.XmlToPatchBodyReader;
+import org.opendaylight.restconf.common.errors.RestconfDocumentedException;
+import org.opendaylight.restconf.common.patch.PatchContext;
+import org.opendaylight.yangtools.yang.common.ErrorTag;
+import org.opendaylight.yangtools.yang.model.api.EffectiveModelContext;
+
+public class TestXmlPatchBodyReader extends AbstractBodyReaderTest {
+
+ private final XmlToPatchBodyReader xmlToPatchBodyReader;
+ private static EffectiveModelContext schemaContext;
+
+ public TestXmlPatchBodyReader() {
+ super(schemaContext, null);
+ xmlToPatchBodyReader = new XmlToPatchBodyReader(controllerContext);
+ }
+
+ @Override
+ protected MediaType getMediaType() {
+ return new MediaType(MediaType.APPLICATION_XML, null);
+ }
+
+ @BeforeClass
+ public static void initialization() throws NoSuchFieldException, SecurityException {
+ schemaContext = schemaContextLoader("/instanceidentifier/yang", schemaContext);
+ }
+
+ @Test
+ public void moduleDataTest() throws Exception {
+ final String uri = "instance-identifier-patch-module:patch-cont/my-list1/leaf1";
+ mockBodyReader(uri, xmlToPatchBodyReader, false);
+ final InputStream inputStream = TestXmlBodyReader.class.getResourceAsStream(
+ "/instanceidentifier/xml/xmlPATCHdata.xml");
+ final PatchContext returnValue = xmlToPatchBodyReader.readFrom(null, null, null, mediaType, null, inputStream);
+ checkPatchContext(returnValue);
+ }
+
+ /**
+ * Test trying to use Patch create operation which requires value without value. Error code 400 should be returned.
+ */
+ @Test
+ public void moduleDataValueMissingNegativeTest() throws Exception {
+ final String uri = "instance-identifier-patch-module:patch-cont/my-list1/leaf1";
+ mockBodyReader(uri, xmlToPatchBodyReader, false);
+ final InputStream inputStream = TestXmlBodyReader.class.getResourceAsStream(
+ "/instanceidentifier/xml/xmlPATCHdataValueMissing.xml");
+ final RestconfDocumentedException ex = assertThrows(RestconfDocumentedException.class,
+ () -> xmlToPatchBodyReader.readFrom(null, null, null, mediaType, null, inputStream));
+ assertEquals(1, ex.getErrors().size());
+ assertEquals(ErrorTag.MALFORMED_MESSAGE, ex.getErrors().get(0).getErrorTag());
+ }
+
+ /**
+ * Test trying to use value with Patch delete operation which does not support value. Error code 400 should be
+ * returned.
+ */
+ @Test
+ public void moduleDataNotValueNotSupportedNegativeTest() throws Exception {
+ final String uri = "instance-identifier-patch-module:patch-cont/my-list1/leaf1";
+ mockBodyReader(uri, xmlToPatchBodyReader, false);
+ final InputStream inputStream = TestXmlBodyReader.class.getResourceAsStream(
+ "/instanceidentifier/xml/xmlPATCHdataValueNotSupported.xml");
+
+ final RestconfDocumentedException ex = assertThrows(RestconfDocumentedException.class,
+ () -> xmlToPatchBodyReader.readFrom(null, null, null, mediaType, null, inputStream));
+ assertEquals(1, ex.getErrors().size());
+ assertEquals(ErrorTag.MALFORMED_MESSAGE, ex.getErrors().get(0).getErrorTag());
+ }
+
+ /**
+ * Test of Yang Patch with absolute target path.
+ */
+ @Test
+ public void moduleDataAbsoluteTargetPathTest() throws Exception {
+ final String uri = "";
+ mockBodyReader(uri, xmlToPatchBodyReader, false);
+ final InputStream inputStream = TestXmlBodyReader.class
+ .getResourceAsStream("/instanceidentifier/xml/xmlPATCHdataAbsoluteTargetPath.xml");
+ final PatchContext returnValue = xmlToPatchBodyReader.readFrom(null, null, null, mediaType, null, inputStream);
+ checkPatchContext(returnValue);
+ }
+
+ /**
+ * Test using Patch when target is completely specified in request URI and thus target leaf contains only '/' sign.
+ */
+ @Test
+ public void modulePatchCompleteTargetInURITest() throws Exception {
+ final String uri = "instance-identifier-patch-module:patch-cont";
+ mockBodyReader(uri, xmlToPatchBodyReader, false);
+ final InputStream inputStream = TestXmlBodyReader.class
+ .getResourceAsStream("/instanceidentifier/xml/xmlPATCHdataCompleteTargetInURI.xml");
+ final PatchContext returnValue = xmlToPatchBodyReader
+ .readFrom(null, null, null, mediaType, null, inputStream);
+ checkPatchContext(returnValue);
+ }
+
+ /**
+ * Test of Yang Patch merge operation on list. Test consists of two edit operations - replace and merge.
+ */
+ @Test
+ public void moduleDataMergeOperationOnListTest() throws Exception {
+ final String uri = "instance-identifier-patch-module:patch-cont/my-list1/leaf1";
+ mockBodyReader(uri, xmlToPatchBodyReader, false);
+ final InputStream inputStream = TestXmlBodyReader.class
+ .getResourceAsStream("/instanceidentifier/xml/xmlPATCHdataMergeOperationOnList.xml");
+ final PatchContext returnValue = xmlToPatchBodyReader.readFrom(null, null, null, mediaType, null, inputStream);
+ checkPatchContext(returnValue);
+ }
+
+ /**
+ * Test of Yang Patch merge operation on container. Test consists of two edit operations - create and merge.
+ */
+ @Test
+ public void moduleDataMergeOperationOnContainerTest() throws Exception {
+ final String uri = "instance-identifier-patch-module:patch-cont";
+ mockBodyReader(uri, xmlToPatchBodyReader, false);
+ final InputStream inputStream = TestXmlBodyReader.class
+ .getResourceAsStream("/instanceidentifier/xml/xmlPATCHdataMergeOperationOnContainer.xml");
+ final PatchContext returnValue = xmlToPatchBodyReader.readFrom(null, null, null, mediaType, null, inputStream);
+ checkPatchContext(returnValue);
+ }
+}
diff --git a/netconf/restconf/restconf-nb-bierman02/src/test/java/org/opendaylight/controller/sal/rest/impl/test/providers/TestXmlPatchBodyReaderMountPoint.java b/netconf/restconf/restconf-nb-bierman02/src/test/java/org/opendaylight/controller/sal/rest/impl/test/providers/TestXmlPatchBodyReaderMountPoint.java
new file mode 100644
index 0000000..614f36e
--- /dev/null
+++ b/netconf/restconf/restconf-nb-bierman02/src/test/java/org/opendaylight/controller/sal/rest/impl/test/providers/TestXmlPatchBodyReaderMountPoint.java
@@ -0,0 +1,133 @@
+/*
+ * Copyright (c) 2016 Cisco Systems, Inc. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.controller.sal.rest.impl.test.providers;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertThrows;
+import static org.mockito.Mockito.mock;
+
+import java.io.InputStream;
+import javax.ws.rs.core.MediaType;
+import org.junit.BeforeClass;
+import org.junit.Test;
+import org.opendaylight.mdsal.dom.api.DOMMountPoint;
+import org.opendaylight.netconf.sal.rest.impl.XmlToPatchBodyReader;
+import org.opendaylight.restconf.common.errors.RestconfDocumentedException;
+import org.opendaylight.restconf.common.patch.PatchContext;
+import org.opendaylight.yangtools.yang.common.ErrorTag;
+import org.opendaylight.yangtools.yang.model.api.EffectiveModelContext;
+
+public class TestXmlPatchBodyReaderMountPoint extends AbstractBodyReaderTest {
+
+ private final XmlToPatchBodyReader xmlToPatchBodyReader;
+ private static EffectiveModelContext schemaContext;
+ private static final String MOUNT_POINT = "instance-identifier-module:cont/yang-ext:mount";
+
+ public TestXmlPatchBodyReaderMountPoint() {
+ super(schemaContext, mock(DOMMountPoint.class));
+ xmlToPatchBodyReader = new XmlToPatchBodyReader(controllerContext);
+ }
+
+ @BeforeClass
+ public static void initialization() throws NoSuchFieldException, SecurityException {
+ schemaContext = schemaContextLoader("/instanceidentifier/yang", schemaContext);
+ }
+
+ @Override
+ protected MediaType getMediaType() {
+ return new MediaType(MediaType.APPLICATION_XML, null);
+ }
+
+ @Test
+ public void moduleDataTest() throws Exception {
+ final String uri = MOUNT_POINT + "/instance-identifier-patch-module:patch-cont/my-list1/leaf1";
+ mockBodyReader(uri, xmlToPatchBodyReader, false);
+ final InputStream inputStream = TestXmlBodyReader.class.getResourceAsStream(
+ "/instanceidentifier/xml/xmlPATCHdata.xml");
+ checkPatchContextMountPoint(xmlToPatchBodyReader.readFrom(null, null, null, mediaType, null, inputStream));
+ }
+
+ /**
+ * Test trying to use Patch create operation which requires value without value. Error code 400 should be returned.
+ */
+ @Test
+ public void moduleDataValueMissingNegativeTest() throws Exception {
+ final String uri = MOUNT_POINT + "/instance-identifier-patch-module:patch-cont/my-list1/leaf1";
+ mockBodyReader(uri, xmlToPatchBodyReader, false);
+ final InputStream inputStream = TestXmlBodyReader.class.getResourceAsStream(
+ "/instanceidentifier/xml/xmlPATCHdataValueMissing.xml");
+ final RestconfDocumentedException ex = assertThrows(RestconfDocumentedException.class,
+ () -> xmlToPatchBodyReader.readFrom(null, null, null, mediaType, null, inputStream));
+ assertEquals(ErrorTag.MALFORMED_MESSAGE, ex.getErrors().get(0).getErrorTag());
+ }
+
+ /**
+ * Test trying to use value with Patch delete operation which does not support value. Error code 400 should be
+ * returned.
+ */
+ @Test
+ public void moduleDataNotValueNotSupportedNegativeTest() throws Exception {
+ final String uri = MOUNT_POINT + "/instance-identifier-patch-module:patch-cont/my-list1/leaf1";
+ mockBodyReader(uri, xmlToPatchBodyReader, false);
+ final InputStream inputStream = TestXmlBodyReader.class
+ .getResourceAsStream("/instanceidentifier/xml/xmlPATCHdataValueNotSupported.xml");
+ final RestconfDocumentedException ex = assertThrows(RestconfDocumentedException.class,
+ () -> xmlToPatchBodyReader.readFrom(null, null, null, mediaType, null, inputStream));
+ assertEquals(ErrorTag.MALFORMED_MESSAGE, ex.getErrors().get(0).getErrorTag());
+ }
+
+ /**
+ * Test of Yang Patch with absolute target path.
+ */
+ @Test
+ public void moduleDataAbsoluteTargetPathTest() throws Exception {
+ final String uri = MOUNT_POINT;
+ mockBodyReader(uri, xmlToPatchBodyReader, false);
+ final InputStream inputStream = TestXmlBodyReader.class.getResourceAsStream(
+ "/instanceidentifier/xml/xmlPATCHdataAbsoluteTargetPath.xml");
+ final PatchContext returnValue = xmlToPatchBodyReader.readFrom(null, null, null, mediaType, null, inputStream);
+ checkPatchContextMountPoint(returnValue);
+ }
+
+ /**
+ * Test using Patch when target is completely specified in request URI and thus target leaf contains only '/' sign.
+ */
+ @Test
+ public void modulePatchCompleteTargetInURITest() throws Exception {
+ final String uri = MOUNT_POINT + "/instance-identifier-patch-module:patch-cont";
+ mockBodyReader(uri, xmlToPatchBodyReader, false);
+ final InputStream inputStream = TestXmlBodyReader.class.getResourceAsStream(
+ "/instanceidentifier/xml/xmlPATCHdataCompleteTargetInURI.xml");
+ final PatchContext returnValue = xmlToPatchBodyReader.readFrom(null, null, null, mediaType, null, inputStream);
+ checkPatchContextMountPoint(returnValue);
+ }
+
+ /**
+ * Test of Yang Patch merge operation on list. Test consists of two edit operations - replace and merge.
+ */
+ @Test
+ public void moduleDataMergeOperationOnListTest() throws Exception {
+ final String uri = MOUNT_POINT + "/instance-identifier-patch-module:patch-cont/my-list1/leaf1";
+ mockBodyReader(uri, xmlToPatchBodyReader, false);
+ final InputStream inputStream = TestXmlBodyReader.class.getResourceAsStream(
+ "/instanceidentifier/xml/xmlPATCHdataMergeOperationOnList.xml");
+ checkPatchContextMountPoint(xmlToPatchBodyReader.readFrom(null, null, null, mediaType, null, inputStream));
+ }
+
+ /**
+ * Test of Yang Patch merge operation on container. Test consists of two edit operations - create and merge.
+ */
+ @Test
+ public void moduleDataMergeOperationOnContainerTest() throws Exception {
+ final String uri = MOUNT_POINT + "/instance-identifier-patch-module:patch-cont";
+ mockBodyReader(uri, xmlToPatchBodyReader, false);
+ final InputStream inputStream = TestXmlBodyReader.class.getResourceAsStream(
+ "/instanceidentifier/xml/xmlPATCHdataMergeOperationOnContainer.xml");
+ checkPatchContextMountPoint(xmlToPatchBodyReader.readFrom(null, null, null, mediaType, null, inputStream));
+ }
+}
diff --git a/netconf/restconf/restconf-nb-bierman02/src/test/java/org/opendaylight/controller/sal/restconf/impl/cnsn/to/json/test/CnSnToJsonBasicDataTypesTest.java b/netconf/restconf/restconf-nb-bierman02/src/test/java/org/opendaylight/controller/sal/restconf/impl/cnsn/to/json/test/CnSnToJsonBasicDataTypesTest.java
new file mode 100644
index 0000000..e263873
--- /dev/null
+++ b/netconf/restconf/restconf-nb-bierman02/src/test/java/org/opendaylight/controller/sal/restconf/impl/cnsn/to/json/test/CnSnToJsonBasicDataTypesTest.java
@@ -0,0 +1,281 @@
+/*
+ * Copyright (c) 2014 Cisco Systems, Inc. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.controller.sal.restconf.impl.cnsn.to.json.test;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.fail;
+
+import com.google.gson.stream.JsonReader;
+import com.google.gson.stream.JsonToken;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.io.StringReader;
+import java.util.HashMap;
+import java.util.Map;
+import org.junit.BeforeClass;
+import org.opendaylight.controller.sal.restconf.impl.test.YangAndXmlAndDataSchemaLoader;
+
+public class CnSnToJsonBasicDataTypesTest extends YangAndXmlAndDataSchemaLoader {
+
+ abstract static class LeafVerifier {
+
+ Object expectedValue;
+ JsonToken expectedToken;
+
+ LeafVerifier(final Object expectedValue, final JsonToken expectedToken) {
+ this.expectedValue = expectedValue;
+ this.expectedToken = expectedToken;
+ }
+
+ abstract Object getActualValue(JsonReader reader) throws IOException;
+
+ void verify(final JsonReader reader, final String keyName) throws IOException {
+ assertEquals("Json value for key " + keyName, this.expectedValue, getActualValue(reader));
+ }
+
+ JsonToken expectedTokenType() {
+ return this.expectedToken;
+ }
+ }
+
+ static class BooleanVerifier extends LeafVerifier {
+
+ BooleanVerifier(final boolean expected) {
+ super(expected, JsonToken.BOOLEAN);
+ }
+
+ @Override
+ Object getActualValue(final JsonReader reader) throws IOException {
+ return reader.nextBoolean();
+ }
+ }
+
+ static class NumberVerifier extends LeafVerifier {
+
+ NumberVerifier(final Number expected) {
+ super(expected, JsonToken.NUMBER);
+ }
+
+ @Override
+ Object getActualValue(final JsonReader reader) throws IOException {
+ if (this.expectedValue instanceof Double) {
+ return reader.nextDouble();
+ } else if (this.expectedValue instanceof Long) {
+ return reader.nextLong();
+ } else if (this.expectedValue instanceof Integer) {
+ return reader.nextInt();
+ }
+
+ return null;
+ }
+ }
+
+ static class StringVerifier extends LeafVerifier {
+
+ StringVerifier(final String expected) {
+ super(expected, JsonToken.STRING);
+ }
+
+ @Override
+ Object getActualValue(final JsonReader reader) throws IOException {
+ return reader.nextString();
+ }
+ }
+
+ static class EmptyVerifier extends LeafVerifier {
+
+ EmptyVerifier() {
+ super(null, null);
+ }
+
+ @Override
+ Object getActualValue(final JsonReader reader) throws IOException {
+ reader.beginArray();
+ reader.nextNull();
+ reader.endArray();
+ return null;
+ }
+
+ }
+
+ static class ComplexAnyXmlVerifier extends LeafVerifier {
+
+ ComplexAnyXmlVerifier() {
+ super(null, JsonToken.BEGIN_OBJECT);
+ }
+
+ @Override
+ void verify(final JsonReader reader, final String keyName) throws IOException {
+
+ reader.beginObject();
+ final String innerKey = reader.nextName();
+ assertEquals("Json reader child key for " + keyName, "data", innerKey);
+ assertEquals("Json token type for key " + innerKey, JsonToken.BEGIN_OBJECT, reader.peek());
+
+ reader.beginObject();
+ verifyLeaf(reader, innerKey, "leaf1", "leaf1-value");
+ verifyLeaf(reader, innerKey, "leaf2", "leaf2-value");
+
+ String nextName = reader.nextName();
+ assertEquals("Json reader child key for " + innerKey, "leaf-list", nextName);
+ reader.beginArray();
+ assertEquals("Json value for key " + nextName, "leaf-list-value1", reader.nextString());
+ assertEquals("Json value for key " + nextName, "leaf-list-value2", reader.nextString());
+ reader.endArray();
+
+ nextName = reader.nextName();
+ assertEquals("Json reader child key for " + innerKey, "list", nextName);
+ reader.beginArray();
+ verifyNestedLists(reader, 1);
+ verifyNestedLists(reader, 3);
+ reader.endArray();
+
+ reader.endObject();
+ reader.endObject();
+ }
+
+ void verifyNestedLists(final JsonReader reader, int leafNum) throws IOException {
+ reader.beginObject();
+
+ final String nextName = reader.nextName();
+ assertEquals("Json reader next name", "nested-list", nextName);
+
+ reader.beginArray();
+
+ reader.beginObject();
+ verifyLeaf(reader, "nested-list", "nested-leaf", "nested-value" + leafNum++);
+ reader.endObject();
+
+ reader.beginObject();
+ verifyLeaf(reader, "nested-list", "nested-leaf", "nested-value" + leafNum);
+ reader.endObject();
+
+ reader.endArray();
+ reader.endObject();
+ }
+
+ void verifyLeaf(final JsonReader reader, final String parent, final String name,
+ final String value) throws IOException {
+ final String nextName = reader.nextName();
+ assertEquals("Json reader child key for " + parent, name, nextName);
+ assertEquals("Json token type for key " + parent, JsonToken.STRING, reader.peek());
+ assertEquals("Json value for key " + nextName, value, reader.nextString());
+ }
+
+ @Override
+ Object getActualValue(final JsonReader reader) throws IOException {
+ return null;
+ }
+ }
+
+ @BeforeClass
+ public static void initialize() throws FileNotFoundException {
+ dataLoad("/cnsn-to-json/simple-data-types");
+ }
+
+ private static void verifyJsonOutput(final String jsonOutput) {
+ final StringReader strReader = new StringReader(jsonOutput);
+ final JsonReader jReader = new JsonReader(strReader);
+
+ String exception = null;
+ try {
+ jsonReadCont(jReader);
+ } catch (final IOException e) {
+ exception = e.getMessage();
+ }
+
+ assertNull("Error during reading Json output: " + exception, exception);
+ }
+
+ private static void jsonReadCont(final JsonReader jsonReader) throws IOException {
+ jsonReader.beginObject();
+ assertNotNull("cont1 is missing.", jsonReader.hasNext());
+
+ // Cont dataFromJson = new Cont(jReader.nextName());
+ jsonReader.nextName();
+ jsonReadContElements(jsonReader);
+
+ assertFalse("cont shouldn't have other element.", jsonReader.hasNext());
+ jsonReader.endObject();
+ // return dataFromJson;
+ }
+
+ private static void jsonReadContElements(final JsonReader jsonReader) throws IOException {
+ jsonReader.beginObject();
+
+ final Map<String, LeafVerifier> expectedMap = new HashMap<>();
+ expectedMap.put("lfnint8Min", new NumberVerifier(-128));
+ expectedMap.put("lfnint8Max", new NumberVerifier(127));
+ expectedMap.put("lfnint16Min", new NumberVerifier(-32768));
+ expectedMap.put("lfnint16Max", new NumberVerifier(32767));
+ expectedMap.put("lfnint32Min", new NumberVerifier(-2147483648));
+ expectedMap.put("lfnint32Max", new NumberVerifier(2147483647L));
+ expectedMap.put("lfnint64Min", new NumberVerifier(-9223372036854775808L));
+ expectedMap.put("lfnint64Max", new NumberVerifier(9223372036854775807L));
+ expectedMap.put("lfnuint8Max", new NumberVerifier(255));
+ expectedMap.put("lfnuint16Max", new NumberVerifier(65535));
+ expectedMap.put("lfnuint32Max", new NumberVerifier(4294967295L));
+ expectedMap.put("lfstr", new StringVerifier("lfstr"));
+ expectedMap.put("lfstr1", new StringVerifier(""));
+ expectedMap.put("lfbool1", new BooleanVerifier(true));
+ expectedMap.put("lfbool2", new BooleanVerifier(false));
+ expectedMap.put("lfbool3", new BooleanVerifier(false));
+ expectedMap.put("lfdecimal1", new NumberVerifier(43.32));
+ expectedMap.put("lfdecimal2", new NumberVerifier(-0.43));
+ expectedMap.put("lfdecimal3", new NumberVerifier(43d));
+ expectedMap.put("lfdecimal4", new NumberVerifier(43E3));
+ expectedMap.put("lfdecimal6", new NumberVerifier(33.12345));
+ expectedMap.put("lfenum", new StringVerifier("enum3"));
+ expectedMap.put("lfbits", new StringVerifier("bit3 bit2"));
+ expectedMap.put("lfbinary", new StringVerifier("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"));
+ expectedMap.put("lfunion1", new StringVerifier("324"));
+ expectedMap.put("lfunion2", new StringVerifier("33.3"));
+ expectedMap.put("lfunion3", new StringVerifier("55"));
+ expectedMap.put("lfunion4", new StringVerifier("true"));
+ expectedMap.put("lfunion5", new StringVerifier("true"));
+ expectedMap.put("lfunion6", new StringVerifier("10"));
+ expectedMap.put("lfunion7", new StringVerifier(""));
+ expectedMap.put("lfunion8", new StringVerifier(""));
+ expectedMap.put("lfunion9", new StringVerifier(""));
+ expectedMap.put("lfunion10", new StringVerifier("bt1"));
+ expectedMap.put("lfunion11", new StringVerifier("33"));
+ expectedMap.put("lfunion12", new StringVerifier("false"));
+ expectedMap.put("lfunion13", new StringVerifier("b1"));
+ expectedMap.put("lfunion14", new StringVerifier("zero"));
+ expectedMap.put("lfempty", new EmptyVerifier());
+ expectedMap.put("identityref1", new StringVerifier("simple-data-types:iden"));
+ expectedMap.put("complex-any", new ComplexAnyXmlVerifier());
+ expectedMap.put("simple-any", new StringVerifier("simple"));
+ expectedMap.put("empty-any", new StringVerifier(""));
+
+ while (jsonReader.hasNext()) {
+ final String keyName = jsonReader.nextName();
+ final JsonToken peek = jsonReader.peek();
+
+ final LeafVerifier verifier = expectedMap.remove(keyName);
+ assertNotNull("Found unexpected leaf: " + keyName, verifier);
+
+ final JsonToken expToken = verifier.expectedTokenType();
+ if (expToken != null) {
+ assertEquals("Json token type for key " + keyName, expToken, peek);
+ }
+
+ verifier.verify(jsonReader, keyName);
+ }
+
+ if (!expectedMap.isEmpty()) {
+ fail("Missing leaf nodes in Json output: " + expectedMap.keySet());
+ }
+
+ jsonReader.endObject();
+ }
+
+}
diff --git a/netconf/restconf/restconf-nb-bierman02/src/test/java/org/opendaylight/controller/sal/restconf/impl/cnsn/to/json/test/CnSnToJsonIdentityrefTest.java b/netconf/restconf/restconf-nb-bierman02/src/test/java/org/opendaylight/controller/sal/restconf/impl/cnsn/to/json/test/CnSnToJsonIdentityrefTest.java
new file mode 100644
index 0000000..bf262d7
--- /dev/null
+++ b/netconf/restconf/restconf-nb-bierman02/src/test/java/org/opendaylight/controller/sal/restconf/impl/cnsn/to/json/test/CnSnToJsonIdentityrefTest.java
@@ -0,0 +1,22 @@
+/*
+ * Copyright (c) 2014 Cisco Systems, Inc. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.controller.sal.restconf.impl.cnsn.to.json.test;
+
+import java.io.FileNotFoundException;
+import org.junit.BeforeClass;
+import org.opendaylight.controller.sal.restconf.impl.test.YangAndXmlAndDataSchemaLoader;
+import org.opendaylight.yangtools.yang.parser.spi.meta.ReactorException;
+
+public class CnSnToJsonIdentityrefTest extends YangAndXmlAndDataSchemaLoader {
+
+ @BeforeClass
+ public static void initialization() throws FileNotFoundException, ReactorException {
+ dataLoad("/cnsn-to-json/identityref", 2, "identityref-module", "cont");
+ }
+
+}
diff --git a/netconf/restconf/restconf-nb-bierman02/src/test/java/org/opendaylight/controller/sal/restconf/impl/cnsn/to/json/test/CnSnToJsonWithDataFromSeveralModulesTest.java b/netconf/restconf/restconf-nb-bierman02/src/test/java/org/opendaylight/controller/sal/restconf/impl/cnsn/to/json/test/CnSnToJsonWithDataFromSeveralModulesTest.java
new file mode 100644
index 0000000..1b44d75
--- /dev/null
+++ b/netconf/restconf/restconf-nb-bierman02/src/test/java/org/opendaylight/controller/sal/restconf/impl/cnsn/to/json/test/CnSnToJsonWithDataFromSeveralModulesTest.java
@@ -0,0 +1,21 @@
+/*
+ * Copyright (c) 2014 Cisco Systems, Inc. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.controller.sal.restconf.impl.cnsn.to.json.test;
+
+import java.io.FileNotFoundException;
+import org.junit.BeforeClass;
+import org.opendaylight.controller.sal.restconf.impl.test.YangAndXmlAndDataSchemaLoader;
+import org.opendaylight.yangtools.yang.parser.spi.meta.ReactorException;
+
+public class CnSnToJsonWithDataFromSeveralModulesTest extends YangAndXmlAndDataSchemaLoader {
+
+ @BeforeClass
+ public static void initialize() throws FileNotFoundException, ReactorException {
+ dataLoad("/xml-to-cnsn/data-of-several-modules/yang", 2, "module1", "cont_m1");
+ }
+}
diff --git a/netconf/restconf/restconf-nb-bierman02/src/test/java/org/opendaylight/controller/sal/restconf/impl/input/to/cnsn/test/RestPutListDataTest.java b/netconf/restconf/restconf-nb-bierman02/src/test/java/org/opendaylight/controller/sal/restconf/impl/input/to/cnsn/test/RestPutListDataTest.java
new file mode 100644
index 0000000..71406ca
--- /dev/null
+++ b/netconf/restconf/restconf-nb-bierman02/src/test/java/org/opendaylight/controller/sal/restconf/impl/input/to/cnsn/test/RestPutListDataTest.java
@@ -0,0 +1,228 @@
+/*
+ * Copyright (c) 2014 Cisco Systems, Inc. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.controller.sal.restconf.impl.input.to.cnsn.test;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+import com.google.common.util.concurrent.FluentFuture;
+import java.io.FileNotFoundException;
+import java.util.List;
+import javax.ws.rs.core.Response.Status;
+import javax.ws.rs.core.UriInfo;
+import org.junit.Before;
+import org.junit.BeforeClass;
+import org.junit.Ignore;
+import org.junit.Test;
+import org.mockito.Mockito;
+import org.opendaylight.controller.md.sal.rest.common.TestRestconfUtils;
+import org.opendaylight.controller.sal.restconf.impl.test.TestUtils;
+import org.opendaylight.netconf.sal.rest.impl.NormalizedNodeContext;
+import org.opendaylight.netconf.sal.restconf.impl.BrokerFacade;
+import org.opendaylight.netconf.sal.restconf.impl.ControllerContext;
+import org.opendaylight.netconf.sal.restconf.impl.PutResult;
+import org.opendaylight.netconf.sal.restconf.impl.RestconfImpl;
+import org.opendaylight.restconf.common.context.InstanceIdentifierContext;
+import org.opendaylight.restconf.common.errors.RestconfDocumentedException;
+import org.opendaylight.restconf.common.errors.RestconfError;
+import org.opendaylight.yangtools.yang.common.ErrorTag;
+import org.opendaylight.yangtools.yang.common.ErrorType;
+import org.opendaylight.yangtools.yang.common.QName;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifier;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifierWithPredicates;
+import org.opendaylight.yangtools.yang.data.api.schema.LeafNode;
+import org.opendaylight.yangtools.yang.data.api.schema.MapEntryNode;
+import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
+import org.opendaylight.yangtools.yang.data.api.schema.builder.DataContainerNodeBuilder;
+import org.opendaylight.yangtools.yang.data.api.schema.builder.NormalizedNodeBuilder;
+import org.opendaylight.yangtools.yang.data.impl.schema.SchemaAwareBuilders;
+import org.opendaylight.yangtools.yang.data.impl.schema.builder.impl.valid.DataValidationException;
+import org.opendaylight.yangtools.yang.model.api.DataSchemaNode;
+import org.opendaylight.yangtools.yang.model.api.EffectiveModelContext;
+import org.opendaylight.yangtools.yang.model.api.LeafSchemaNode;
+import org.opendaylight.yangtools.yang.model.api.ListSchemaNode;
+import org.opendaylight.yangtools.yang.model.util.SchemaInferenceStack;
+
+public class RestPutListDataTest {
+ private static EffectiveModelContext schemaContextTestModule;
+
+ private static BrokerFacade brokerFacade;
+ private static RestconfImpl restconfImpl;
+
+ private static final String TEST_MODULE_NS_STRING = "test:module";
+ private static final String TEST_MODULE_REVISION = "2014-01-09";
+
+ @BeforeClass
+ public static void staticSetup() throws FileNotFoundException {
+ schemaContextTestModule = TestUtils.loadSchemaContext("/full-versions/test-module");
+ }
+
+ @Before
+ public void initialize() throws FileNotFoundException {
+ final ControllerContext controllerContext = TestRestconfUtils.newControllerContext(schemaContextTestModule);
+ brokerFacade = mock(BrokerFacade.class);
+ restconfImpl = RestconfImpl.newInstance(brokerFacade, controllerContext);
+ final PutResult result = mock(PutResult.class);
+ when(brokerFacade.commitConfigurationDataPut(any(EffectiveModelContext.class),
+ any(YangInstanceIdentifier.class), any(NormalizedNode.class), Mockito.anyString(), Mockito.anyString()))
+ .thenReturn(result);
+ when(result.getFutureOfPutData()).thenReturn(mock(FluentFuture.class));
+ when(result.getStatus()).thenReturn(Status.OK);
+ }
+
+ /**
+ * Tests whether no exception is raised if number and values of keys in URI
+ * and payload are equal.
+ */
+ @Test
+ @Ignore
+ public void testValidKeys() {
+ putListDataTest("key1value", "15", "key1value", (short) 15);
+ }
+
+ /**
+ * Tests whether an exception is raised if key values in URI and payload are
+ * different.
+ *
+ * <p>
+ * The exception should be raised from validation method
+ * {@code RestconfImpl#validateListEqualityOfListInDataAndUri}
+ */
+ @Test
+ @Ignore // RestconfDocumentedExceptionMapper needs update
+ public void testUriAndPayloadKeysDifferent() {
+ try {
+ putListDataTest("key1value", "15", "key1value", (short) 16);
+ fail("RestconfDocumentedException expected");
+ } catch (final RestconfDocumentedException e) {
+ verifyException(e, ErrorType.PROTOCOL, ErrorTag.INVALID_VALUE);
+ }
+
+ try {
+ putListDataTest("key1value", "15", "key1value1", (short) 16);
+ fail("RestconfDocumentedException expected");
+ } catch (final RestconfDocumentedException e) {
+ verifyException(e, ErrorType.PROTOCOL, ErrorTag.INVALID_VALUE);
+ }
+ }
+
+ /**
+ * Tests whether an exception is raised if URI contains less key values then
+ * payload.
+ *
+ * <p>
+ * The exception is raised during {@code InstanceIdentifier} instance is
+ * built from URI
+ */
+ @Test
+ @Ignore
+ public void testMissingKeysInUri() {
+ try {
+ putListDataTest("key1value", null, "key1value", (short) 15);
+ fail("RestconfDocumentedException expected");
+ } catch (final RestconfDocumentedException e) {
+ verifyException(e, ErrorType.PROTOCOL, ErrorTag.DATA_MISSING);
+ }
+ }
+
+ /**
+ * Tests whether an exception is raised if URI contains more key values then
+ * payload.
+ *
+ * <p>
+ * The exception should be raised from validation method
+ * {@code RestconfImpl#validateListEqualityOfListInDataAndUri}
+ */
+ @Test
+ public void testMissingKeysInPayload() {
+ try {
+ putListDataTest("key1value", "15", "key1value", null);
+ fail("RestconfDocumentedException expected");
+ } catch (final DataValidationException e) {
+ // FIXME: thing about different approach for testing the Exception states
+ // RestconfDocumentedException is not rise in new API because you get
+ // DataValidationException from putListDataTest before you call the real rest service
+// verifyException(e, ErrorType.PROTOCOL, ErrorTag.DATA_MISSING);
+ }
+ }
+
+ private static void verifyException(final RestconfDocumentedException restDocumentedException,
+ final ErrorType errorType, final ErrorTag errorTag) {
+ final List<RestconfError> errors = restDocumentedException.getErrors();
+ assertEquals("getErrors() size", 1, errors.size());
+ assertEquals("RestconfError getErrorType()", errorType, errors.get(0).getErrorType());
+ assertEquals("RestconfError getErrorTag()", errorTag, errors.get(0).getErrorTag());
+ }
+
+ public void putListDataTest(final String uriKey1, final String uriKey2, final String payloadKey1,
+ final Short payloadKey2) {
+ final QName lstWithCompositeKey =
+ QName.create(TEST_MODULE_NS_STRING, TEST_MODULE_REVISION, "lst-with-composite-key");
+ final QName key1 = QName.create(TEST_MODULE_NS_STRING, TEST_MODULE_REVISION, "key1");
+ final QName key2 = QName.create(TEST_MODULE_NS_STRING, TEST_MODULE_REVISION, "key2");
+
+ final DataSchemaNode testNodeSchemaNode = schemaContextTestModule.getDataChildByName(lstWithCompositeKey);
+ assertTrue(testNodeSchemaNode != null);
+ assertTrue(testNodeSchemaNode instanceof ListSchemaNode);
+ final DataContainerNodeBuilder<NodeIdentifierWithPredicates, MapEntryNode> testNodeContainer =
+ SchemaAwareBuilders.mapEntryBuilder((ListSchemaNode) testNodeSchemaNode);
+
+ var testChildren = ControllerContext.findInstanceDataChildrenByName(
+ (ListSchemaNode) testNodeSchemaNode, key1.getLocalName());
+ assertTrue(testChildren != null);
+ final DataSchemaNode testLeafKey1SchemaNode = testChildren.get(0).child;
+ assertTrue(testLeafKey1SchemaNode != null);
+ assertTrue(testLeafKey1SchemaNode instanceof LeafSchemaNode);
+ final NormalizedNodeBuilder<NodeIdentifier, Object, LeafNode<Object>> leafKey1 =
+ SchemaAwareBuilders.leafBuilder((LeafSchemaNode) testLeafKey1SchemaNode);
+ leafKey1.withValue(payloadKey1);
+ testNodeContainer.withChild(leafKey1.build());
+
+ if (payloadKey2 != null) {
+ testChildren = ControllerContext.findInstanceDataChildrenByName(
+ (ListSchemaNode) testNodeSchemaNode, key2.getLocalName());
+ assertTrue(testChildren != null);
+ final DataSchemaNode testLeafKey2SchemaNode = testChildren.get(0).child;
+ assertNotNull(testLeafKey2SchemaNode);
+ assertTrue(testLeafKey2SchemaNode instanceof LeafSchemaNode);
+ final NormalizedNodeBuilder<NodeIdentifier, Object, LeafNode<Object>> leafKey2 =
+ SchemaAwareBuilders.leafBuilder((LeafSchemaNode) testLeafKey2SchemaNode);
+ leafKey2.withValue(payloadKey2);
+ testNodeContainer.withChild(leafKey2.build());
+ }
+
+ final NormalizedNodeContext testCompositeContext = new NormalizedNodeContext(
+ InstanceIdentifierContext.ofStack(
+ SchemaInferenceStack.ofDataTreePath(schemaContextTestModule, lstWithCompositeKey)),
+ testNodeContainer.build());
+
+ final UriInfo uriInfo = Mockito.mock(UriInfo.class);
+ restconfImpl.updateConfigurationData(toUri(uriKey1, uriKey2), testCompositeContext, uriInfo);
+ }
+
+ public void putListDataWithWrapperTest(final String uriKey1, final String uriKey2, final String payloadKey1,
+ final Short payloadKey2) {
+ putListDataTest(uriKey1, uriKey2, payloadKey1, payloadKey2);
+ }
+
+ private static String toUri(final String uriKey1, final String uriKey2) {
+ final StringBuilder uriBuilder = new StringBuilder("/test-module:lst-with-composite-key/");
+ uriBuilder.append(uriKey1);
+ if (uriKey2 != null) {
+ uriBuilder.append("/");
+ uriBuilder.append(uriKey2);
+ }
+ return uriBuilder.toString();
+ }
+}
diff --git a/netconf/restconf/restconf-nb-bierman02/src/test/java/org/opendaylight/controller/sal/restconf/impl/json/to/nn/test/JsonIdentityrefToNnTest.java b/netconf/restconf/restconf-nb-bierman02/src/test/java/org/opendaylight/controller/sal/restconf/impl/json/to/nn/test/JsonIdentityrefToNnTest.java
new file mode 100644
index 0000000..f331c47
--- /dev/null
+++ b/netconf/restconf/restconf-nb-bierman02/src/test/java/org/opendaylight/controller/sal/restconf/impl/json/to/nn/test/JsonIdentityrefToNnTest.java
@@ -0,0 +1,68 @@
+/*
+ * Copyright (c) 2014 Cisco Systems, Inc. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.controller.sal.restconf.impl.json.to.nn.test;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+
+import java.io.InputStream;
+import javax.ws.rs.core.MediaType;
+import org.junit.BeforeClass;
+import org.junit.Test;
+import org.opendaylight.controller.sal.rest.impl.test.providers.AbstractBodyReaderTest;
+import org.opendaylight.netconf.sal.rest.impl.JsonNormalizedNodeBodyReader;
+import org.opendaylight.netconf.sal.rest.impl.NormalizedNodeContext;
+import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNodes;
+import org.opendaylight.yangtools.yang.model.api.EffectiveModelContext;
+
+public class JsonIdentityrefToNnTest extends AbstractBodyReaderTest {
+
+ private final JsonNormalizedNodeBodyReader jsonBodyReader;
+ private static EffectiveModelContext schemaContext;
+
+ public JsonIdentityrefToNnTest() {
+ super(schemaContext, null);
+ this.jsonBodyReader = new JsonNormalizedNodeBodyReader(controllerContext);
+ }
+
+ @BeforeClass
+ public static void initialize() {
+ schemaContext = schemaContextLoader("/json-to-nn/identityref", schemaContext);
+ }
+
+ @Test
+ public void jsonIdentityrefToNn() throws Exception {
+
+ final String uri = "identityref-module:cont";
+ mockBodyReader(uri, this.jsonBodyReader, false);
+ final InputStream inputStream = this.getClass().getResourceAsStream(
+ "/json-to-nn/identityref/json/data.json");
+
+ final NormalizedNodeContext normalizedNodeContext = this.jsonBodyReader.readFrom(
+ null, null, null, this.mediaType, null, inputStream);
+
+ assertEquals("cont", normalizedNodeContext.getData().getIdentifier().getNodeType().getLocalName());
+
+ final String dataTree = NormalizedNodes.toStringTree(normalizedNodeContext.getData());
+
+ assertTrue(dataTree.contains("cont1"));
+ assertTrue(dataTree
+ .contains("lf11 (identity:module?revision=2013-12-02)iden"));
+ assertTrue(dataTree
+ .contains("lf12 (identityref:module?revision=2013-12-02)iden_local"));
+ assertTrue(dataTree
+ .contains("lf13 (identityref:module?revision=2013-12-02)iden_local"));
+ assertTrue(dataTree
+ .contains("lf14 (identity:module?revision=2013-12-02)iden"));
+ }
+
+ @Override
+ protected MediaType getMediaType() {
+ return null;
+ }
+}
diff --git a/netconf/restconf/restconf-nb-bierman02/src/test/java/org/opendaylight/controller/sal/restconf/impl/json/to/nn/test/JsonLeafrefToNnTest.java b/netconf/restconf/restconf-nb-bierman02/src/test/java/org/opendaylight/controller/sal/restconf/impl/json/to/nn/test/JsonLeafrefToNnTest.java
new file mode 100644
index 0000000..19bba7b
--- /dev/null
+++ b/netconf/restconf/restconf-nb-bierman02/src/test/java/org/opendaylight/controller/sal/restconf/impl/json/to/nn/test/JsonLeafrefToNnTest.java
@@ -0,0 +1,58 @@
+/*
+ * Copyright (c) 2014 Cisco Systems, Inc. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.controller.sal.restconf.impl.json.to.nn.test;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+
+import java.io.InputStream;
+import javax.ws.rs.core.MediaType;
+import org.junit.BeforeClass;
+import org.junit.Test;
+import org.opendaylight.controller.sal.rest.impl.test.providers.AbstractBodyReaderTest;
+import org.opendaylight.netconf.sal.rest.impl.JsonNormalizedNodeBodyReader;
+import org.opendaylight.netconf.sal.rest.impl.NormalizedNodeContext;
+import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNodes;
+import org.opendaylight.yangtools.yang.model.api.EffectiveModelContext;
+
+public class JsonLeafrefToNnTest extends AbstractBodyReaderTest {
+
+ private final JsonNormalizedNodeBodyReader jsonBodyReader;
+ private static EffectiveModelContext schemaContext;
+
+ public JsonLeafrefToNnTest() {
+ super(schemaContext, null);
+ this.jsonBodyReader = new JsonNormalizedNodeBodyReader(controllerContext);
+ }
+
+ @BeforeClass
+ public static void initialize() {
+ schemaContext = schemaContextLoader("/json-to-nn/leafref", schemaContext);
+ }
+
+ @Test
+ public void jsonIdentityrefToNormalizeNode() throws Exception {
+
+ final String uri = "leafref-module:cont";
+ mockBodyReader(uri, this.jsonBodyReader, false);
+ final InputStream inputStream = this.getClass().getResourceAsStream(
+ "/json-to-nn/leafref/json/data.json");
+
+ final NormalizedNodeContext normalizedNodeContext = this.jsonBodyReader.readFrom(
+ null, null, null, this.mediaType, null, inputStream);
+
+ assertEquals("cont", normalizedNodeContext.getData().getIdentifier().getNodeType().getLocalName());
+ final String dataTree = NormalizedNodes.toStringTree(normalizedNodeContext.getData());
+ assertTrue(dataTree.contains("lf2 121"));
+ }
+
+ @Override
+ protected MediaType getMediaType() {
+ return null;
+ }
+}
diff --git a/netconf/restconf/restconf-nb-bierman02/src/test/java/org/opendaylight/controller/sal/restconf/impl/json/to/nn/test/JsonToNnTest.java b/netconf/restconf/restconf-nb-bierman02/src/test/java/org/opendaylight/controller/sal/restconf/impl/json/to/nn/test/JsonToNnTest.java
new file mode 100644
index 0000000..51d1e64
--- /dev/null
+++ b/netconf/restconf/restconf-nb-bierman02/src/test/java/org/opendaylight/controller/sal/restconf/impl/json/to/nn/test/JsonToNnTest.java
@@ -0,0 +1,334 @@
+/*
+ * Copyright (c) 2014 Cisco Systems, Inc. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.controller.sal.restconf.impl.json.to.nn.test;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.InputStream;
+import java.util.Collection;
+import javax.ws.rs.WebApplicationException;
+import javax.ws.rs.core.MediaType;
+import org.junit.BeforeClass;
+import org.junit.Test;
+import org.opendaylight.controller.md.sal.rest.common.TestRestconfUtils;
+import org.opendaylight.controller.sal.rest.impl.test.providers.AbstractBodyReaderTest;
+import org.opendaylight.netconf.sal.rest.impl.JsonNormalizedNodeBodyReader;
+import org.opendaylight.netconf.sal.rest.impl.NormalizedNodeContext;
+import org.opendaylight.restconf.common.errors.RestconfDocumentedException;
+import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNodes;
+import org.opendaylight.yangtools.yang.model.api.EffectiveModelContext;
+import org.opendaylight.yangtools.yang.test.util.YangParserTestUtils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class JsonToNnTest extends AbstractBodyReaderTest {
+
+ private static final Logger LOG = LoggerFactory.getLogger(AbstractBodyReaderTest.class);
+
+ private final JsonNormalizedNodeBodyReader jsonBodyReader;
+ private static EffectiveModelContext schemaContext;
+
+ public JsonToNnTest() {
+ super(schemaContext, null);
+ this.jsonBodyReader = new JsonNormalizedNodeBodyReader(controllerContext);
+ }
+
+ @BeforeClass
+ public static void initialize() throws FileNotFoundException {
+ final Collection<File> testFiles = TestRestconfUtils.loadFiles("/json-to-nn/simple-list-yang/1");
+ testFiles.addAll(TestRestconfUtils.loadFiles("/json-to-nn/simple-list-yang/3"));
+ testFiles.addAll(TestRestconfUtils.loadFiles("/json-to-nn/simple-list-yang/4"));
+ testFiles.addAll(TestRestconfUtils.loadFiles("/json-to-nn/simple-container-yang"));
+ testFiles.addAll(TestRestconfUtils.loadFiles("/common/augment/yang"));
+ schemaContext = YangParserTestUtils.parseYangFiles(testFiles);
+ }
+
+ @Test
+ public void simpleListTest() throws Exception {
+ simpleTest("/json-to-nn/simple-list.json",
+ "lst", "simple-list-yang1");
+ }
+
+ @Test
+ public void simpleContainerTest() throws Exception {
+ simpleTest("/json-to-nn/simple-container.json",
+ "cont", "simple-container-yang");
+ }
+
+ @Test
+ public void multipleItemsInLeafListTest() throws Exception {
+ final NormalizedNodeContext normalizedNodeContext = prepareNNC(
+ "/json-to-nn/multiple-leaflist-items.json",
+ "simple-list-yang1:lst");
+ assertNotNull(normalizedNodeContext);
+
+ final String dataTree = NormalizedNodes.toStringTree(normalizedNodeContext
+ .getData());
+ assertTrue(dataTree.contains("45"));
+ assertTrue(dataTree.contains("55"));
+ assertTrue(dataTree.contains("66"));
+ }
+
+ @Test
+ public void multipleItemsInListTest() throws Exception {
+ final NormalizedNodeContext normalizedNodeContext = prepareNNC(
+ "/json-to-nn/multiple-items-in-list.json",
+ "multiple-items-yang:lst");
+ assertNotNull(normalizedNodeContext);
+
+ assertEquals("lst", normalizedNodeContext.getData().getIdentifier().getNodeType().getLocalName());
+
+ verityMultipleItemsInList(normalizedNodeContext);
+ }
+
+ @Test
+ public void nullArrayToSimpleNodeWithNullValueTest() throws Exception {
+ final NormalizedNodeContext normalizedNodeContext = prepareNNC(
+ "/json-to-nn/array-with-null.json", "array-with-null-yang:cont");
+ assertNotNull(normalizedNodeContext);
+
+ assertEquals("cont", normalizedNodeContext.getData().getIdentifier().getNodeType().getLocalName());
+
+ final String dataTree = NormalizedNodes.toStringTree(normalizedNodeContext.getData());
+ assertTrue(dataTree.contains("lf"));
+ assertTrue(dataTree.contains("empty"));
+ }
+
+ @Test
+ public void incorrectTopLevelElementsTest() throws Exception {
+ mockBodyReader("simple-list-yang1:lst", this.jsonBodyReader, false);
+
+ InputStream inputStream = this.getClass().getResourceAsStream(
+ "/json-to-nn/wrong-top-level1.json");
+
+ int countExceptions = 0;
+ RestconfDocumentedException exception = null;
+
+ try {
+ this.jsonBodyReader.readFrom(null, null, null, this.mediaType, null,
+ inputStream);
+ } catch (final RestconfDocumentedException e) {
+ exception = e;
+ countExceptions++;
+ }
+ assertNotNull(exception);
+ assertEquals(
+ "Error parsing input: Schema node with name wrong was not found under "
+ + "(urn:ietf:params:xml:ns:netconf:base:1.0)data.",
+ exception.getErrors().get(0).getErrorMessage());
+
+ inputStream = this.getClass().getResourceAsStream(
+ "/json-to-nn/wrong-top-level2.json");
+ exception = null;
+ try {
+ this.jsonBodyReader.readFrom(null, null, null, this.mediaType, null,
+ inputStream);
+ } catch (final RestconfDocumentedException e) {
+ exception = e;
+ countExceptions++;
+ }
+ assertNotNull(exception);
+ assertEquals(
+ "Error parsing input: Schema node with name lst1 was not found under "
+ + "(urn:ietf:params:xml:ns:netconf:base:1.0)data.",
+ exception.getErrors().get(0).getErrorMessage());
+
+ inputStream = this.getClass().getResourceAsStream(
+ "/json-to-nn/wrong-top-level3.json");
+ exception = null;
+ try {
+ this.jsonBodyReader.readFrom(null, null, null, this.mediaType, null,
+ inputStream);
+ } catch (final RestconfDocumentedException e) {
+ exception = e;
+ countExceptions++;
+ }
+ assertNotNull(exception);
+ assertEquals(
+ "Error parsing input: Schema node with name lf was not found under "
+ + "(urn:ietf:params:xml:ns:netconf:base:1.0)data.",
+ exception.getErrors().get(0).getErrorMessage());
+ assertEquals(3, countExceptions);
+ }
+
+ @Test
+ public void emptyDataReadTest() throws Exception {
+ final NormalizedNodeContext normalizedNodeContext = prepareNNC(
+ "/json-to-nn/empty-data.json", "array-with-null-yang:cont");
+ assertNotNull(normalizedNodeContext);
+
+ assertEquals("cont", normalizedNodeContext.getData().getIdentifier().getNodeType().getLocalName());
+
+ final String dataTree = NormalizedNodes.toStringTree(normalizedNodeContext.getData());
+
+ assertTrue(dataTree.contains("lflst1"));
+
+ assertTrue(dataTree.contains("lflst2 45"));
+
+ RestconfDocumentedException exception = null;
+ mockBodyReader("array-with-null-yang:cont", this.jsonBodyReader, false);
+ final InputStream inputStream = this.getClass().getResourceAsStream("/json-to-nn/empty-data.json1");
+
+ try {
+ this.jsonBodyReader.readFrom(null, null, null, this.mediaType, null,inputStream);
+ } catch (final RestconfDocumentedException e) {
+ exception = e;
+ }
+ assertNotNull(exception);
+ assertEquals("Error parsing input: null", exception.getErrors().get(0).getErrorMessage());
+ }
+
+ @Test
+ public void testJsonBlankInput() throws Exception {
+ final NormalizedNodeContext normalizedNodeContext = prepareNNC("", "array-with-null-yang:cont");
+ assertNull(normalizedNodeContext);
+ }
+
+ @Test
+ public void notSupplyNamespaceIfAlreadySupplied()throws Exception {
+ final String uri = "simple-list-yang1" + ":" + "lst";
+
+ final NormalizedNodeContext normalizedNodeContext = prepareNNC("/json-to-nn/simple-list.json", uri);
+ assertNotNull(normalizedNodeContext);
+
+ verifyNormaluizedNodeContext(normalizedNodeContext, "lst");
+
+ mockBodyReader("simple-list-yang2:lst", this.jsonBodyReader, false);
+ final InputStream inputStream = this.getClass().getResourceAsStream("/json-to-nn/simple-list.json");
+
+ try {
+ this.jsonBodyReader.readFrom(null, null, null, this.mediaType, null, inputStream);
+ fail("NormalizedNodeContext should not be create because of different namespace");
+ } catch (final RestconfDocumentedException e) {
+ LOG.warn("Read from InputStream failed. Message: {}. Status: {}", e.getMessage(), e.getStatus());
+ }
+
+ verifyNormaluizedNodeContext(normalizedNodeContext, "lst");
+ }
+
+ @Test
+ public void dataAugmentedTest() throws Exception {
+ NormalizedNodeContext normalizedNodeContext = prepareNNC("/common/augment/json/dataa.json", "main:cont");
+
+ assertNotNull(normalizedNodeContext);
+ assertEquals("cont", normalizedNodeContext.getData().getIdentifier().getNodeType().getLocalName());
+
+ String dataTree = NormalizedNodes.toStringTree(normalizedNodeContext
+ .getData());
+ assertTrue(dataTree.contains("cont1"));
+ assertTrue(dataTree.contains("lf11 lf11 value from a"));
+
+ normalizedNodeContext = prepareNNC("/common/augment/json/datab.json", "main:cont");
+
+ assertNotNull(normalizedNodeContext);
+ assertEquals("cont", normalizedNodeContext.getData().getIdentifier().getNodeType().getLocalName());
+ dataTree = NormalizedNodes.toStringTree(normalizedNodeContext.getData());
+ assertTrue(dataTree.contains("cont1"));
+ assertTrue(dataTree.contains("lf11 lf11 value from b"));
+ }
+
+ private void simpleTest(final String jsonPath, final String topLevelElementName,
+ final String moduleName) throws Exception {
+ final String uri = moduleName + ":" + topLevelElementName;
+
+ final NormalizedNodeContext normalizedNodeContext = prepareNNC(jsonPath, uri);
+ assertNotNull(normalizedNodeContext);
+
+ verifyNormaluizedNodeContext(normalizedNodeContext, topLevelElementName);
+ }
+
+ private NormalizedNodeContext prepareNNC(final String jsonPath, final String uri) throws Exception {
+ try {
+ mockBodyReader(uri, this.jsonBodyReader, false);
+ } catch (NoSuchFieldException | SecurityException | IllegalArgumentException | IllegalAccessException e) {
+ LOG.warn("Operation failed due to: {}", e.getMessage());
+ }
+ final InputStream inputStream = this.getClass().getResourceAsStream(jsonPath);
+
+ NormalizedNodeContext normalizedNodeContext = null;
+
+ try {
+ normalizedNodeContext = this.jsonBodyReader.readFrom(null, null, null, this.mediaType, null, inputStream);
+ } catch (WebApplicationException e) {
+ // TODO Auto-generated catch block
+ }
+
+ return normalizedNodeContext;
+ }
+
+ private static void verifyNormaluizedNodeContext(final NormalizedNodeContext normalizedNodeContext,
+ final String topLevelElementName) {
+ assertEquals(topLevelElementName, normalizedNodeContext.getData().getIdentifier().getNodeType().getLocalName());
+
+ final String dataTree = NormalizedNodes.toStringTree(normalizedNodeContext.getData());
+ assertTrue(dataTree.contains("cont1"));
+ assertTrue(dataTree.contains("lst1"));
+ assertTrue(dataTree.contains("lflst1"));
+ assertTrue(dataTree.contains("lflst1_1"));
+ assertTrue(dataTree.contains("lflst1_2"));
+ assertTrue(dataTree.contains("lf1"));
+ }
+
+ private static void verityMultipleItemsInList(final NormalizedNodeContext normalizedNodeContext) {
+ final String dataTree = NormalizedNodes.toStringTree(normalizedNodeContext.getData());
+ assertTrue(dataTree.contains("lf11"));
+ assertTrue(dataTree.contains("lf11_1"));
+ assertTrue(dataTree.contains("lflst11"));
+ assertTrue(dataTree.contains("45"));
+ assertTrue(dataTree.contains("cont11"));
+ assertTrue(dataTree.contains("lst11"));
+ }
+
+ @Test
+ public void unsupportedDataFormatTest() throws Exception {
+ mockBodyReader("simple-list-yang1:lst", this.jsonBodyReader, false);
+
+ final InputStream inputStream = this.getClass().getResourceAsStream("/json-to-nn/unsupported-json-format.json");
+
+ RestconfDocumentedException exception = null;
+
+ try {
+ this.jsonBodyReader.readFrom(null, null, null, this.mediaType, null, inputStream);
+ } catch (final RestconfDocumentedException e) {
+ exception = e;
+ }
+ LOG.info(exception.getErrors().get(0).getErrorMessage());
+
+ assertTrue(exception.getErrors().get(0).getErrorMessage().contains("is not a simple type"));
+ }
+
+ @Test
+ public void invalidUriCharacterInValue() throws Exception {
+ mockBodyReader("array-with-null-yang:cont", this.jsonBodyReader, false);
+
+ final InputStream inputStream = this.getClass().getResourceAsStream(
+ "/json-to-nn/invalid-uri-character-in-value.json");
+
+ final NormalizedNodeContext normalizedNodeContext = this.jsonBodyReader.readFrom(
+ null, null, null, this.mediaType, null, inputStream);
+ assertNotNull(normalizedNodeContext);
+
+ assertEquals("cont", normalizedNodeContext.getData().getIdentifier().getNodeType().getLocalName());
+
+ final String dataTree = NormalizedNodes.toStringTree(normalizedNodeContext.getData());
+ assertTrue(dataTree.contains("lf1 module<Name:value lf1"));
+ assertTrue(dataTree.contains("lf2 module>Name:value lf2"));
+ }
+
+ @Override
+ protected MediaType getMediaType() {
+ return null;
+ }
+
+}
diff --git a/netconf/restconf/restconf-nb-bierman02/src/test/java/org/opendaylight/controller/sal/restconf/impl/nn/to/json/test/NnJsonChoiceCaseTest.java b/netconf/restconf/restconf-nb-bierman02/src/test/java/org/opendaylight/controller/sal/restconf/impl/nn/to/json/test/NnJsonChoiceCaseTest.java
new file mode 100644
index 0000000..8fd5db8
--- /dev/null
+++ b/netconf/restconf/restconf-nb-bierman02/src/test/java/org/opendaylight/controller/sal/restconf/impl/nn/to/json/test/NnJsonChoiceCaseTest.java
@@ -0,0 +1,181 @@
+/*
+ * Copyright (c) 2015 Cisco Systems, Inc. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.controller.sal.restconf.impl.nn.to.json.test;
+
+import static org.junit.Assert.assertTrue;
+
+import java.io.ByteArrayOutputStream;
+import java.io.OutputStream;
+import javax.ws.rs.core.MediaType;
+import org.junit.BeforeClass;
+import org.junit.Test;
+import org.opendaylight.controller.md.sal.rest.common.TestRestconfUtils;
+import org.opendaylight.controller.sal.rest.impl.test.providers.AbstractBodyReaderTest;
+import org.opendaylight.netconf.sal.rest.impl.NormalizedNodeContext;
+import org.opendaylight.netconf.sal.rest.impl.NormalizedNodeJsonBodyWriter;
+import org.opendaylight.yangtools.yang.model.api.EffectiveModelContext;
+
+public class NnJsonChoiceCaseTest extends AbstractBodyReaderTest {
+
+ private static EffectiveModelContext schemaContext;
+ private final NormalizedNodeJsonBodyWriter jsonBodyWriter;
+
+ public NnJsonChoiceCaseTest() {
+ super(schemaContext, null);
+ jsonBodyWriter = new NormalizedNodeJsonBodyWriter();
+ }
+
+ @BeforeClass
+ public static void initialization() {
+ schemaContext = schemaContextLoader("/nn-to-json/choice", schemaContext);
+ }
+
+ /**
+ * Test when some data are in one case node and other in another. This isn't
+ * correct. Next Json validator should return error because nodes has to be
+ * from one case below concrete choice.
+ */
+ @Test(expected = NullPointerException.class)
+ public void nodeSchemasOnVariousChoiceCasePathTest() throws Exception {
+ getJson("/nn-to-json/choice/xml/data_various_path_err.xml");
+ }
+
+ /**
+ * Test when some data are in one case node and other in another.
+ * Additionally data are loadef from various choices. This isn't correct.
+ * Next Json validator should return error because nodes has to be from one
+ * case below concrete choice.
+ */
+ @Test(expected = NullPointerException.class)
+ public void nodeSchemasOnVariousChoiceCasePathAndMultipleChoicesTest()
+ throws Exception {
+ getJson("/nn-to-json/choice/xml/data_more_choices_same_level_various_paths_err.xml");
+ }
+
+ /**
+ * Test when second level data are red first, then first and at the end
+ * third level. Level represents pass through couple choice-case
+ */
+
+ @Test
+ public void nodeSchemasWithRandomOrderAccordingLevel() throws Exception {
+ final String json = getJson("/nn-to-json/choice/xml/data_random_level.xml");
+
+ assertTrue(json.contains("cont"));
+ assertTrue(json.contains("\"lf1\":\"lf1 val\""));
+ assertTrue(json.contains("\"lf1aaa\":\"lf1aaa val\""));
+ assertTrue(json.contains("\"lf1aa\":\"lf1aa val\""));
+ assertTrue(json.contains("\"lf1a\":121"));
+ }
+
+ /**
+ * Test when element from no first case is used.
+ */
+ @Test
+ public void nodeSchemasNotInFirstCase() throws Exception {
+ final String json = getJson("/nn-to-json/choice/xml/data_no_first_case.xml");
+
+ assertTrue(json.contains("cont"));
+ assertTrue(json.contains("\"lf1\":\"lf1 val\""));
+ assertTrue(json.contains("\"lf1ab\":\"lf1ab val\""));
+ assertTrue(json.contains("\"lf1a\":121"));
+ }
+
+ /**
+ * Test when element in case is list.
+ */
+ @Test
+ public void nodeSchemaAsList() throws Exception {
+ final String json = getJson("/nn-to-json/choice/xml/data_list.xml");
+
+ assertTrue(json.contains("cont"));
+ assertTrue(json.contains("\"lst1b\":["));
+ assertTrue(json.contains("{\"lf11b\":\"lf11b_1 val\"}"));
+ assertTrue(json.contains("{\"lf11b\":\"lf11b_2 val\"}"));
+ }
+
+ /**
+ * Test when element in case is container.
+ */
+ @Test
+ public void nodeSchemaAsContainer() throws Exception {
+ final String json = getJson("/nn-to-json/choice/xml/data_container.xml");
+
+ assertTrue(json.contains("cont"));
+ assertTrue(json.contains("\"cont1c\":{"));
+ assertTrue(json.contains("\"lf11c\":\"lf11c val\""));
+ }
+
+ /**
+ * Test when element in case is leaflist.
+ */
+ @Test
+ public void nodeSchemaAsLeafList() throws Exception {
+ final String json = getJson("/nn-to-json/choice/xml/data_leaflist.xml");
+
+ assertTrue(json.contains("cont"));
+ assertTrue(json.contains("\"lflst1d\":["));
+ assertTrue(json.contains("\"lflst1d_1 val\""));
+ assertTrue(json.contains("\"lflst1d_2 val\""));
+ }
+
+ @Test
+ public void nodeSchemasInMultipleChoicesTest() throws Exception {
+ final String json = getJson("/nn-to-json/choice/xml/data_more_choices_same_level.xml");
+
+ assertTrue(json.contains("cont"));
+ assertTrue(json.contains("\"lf2b\":\"lf2b value\""));
+ assertTrue(json.contains("\"cont1c\":{"));
+ assertTrue(json.contains("\"lf11c\":\"lf11c val\""));
+ }
+
+ /**
+ * Test whether is possible to find data schema for node which is specified
+ * as dirrect subnode of choice (case without CASE key word).
+ */
+ @Test
+ public void nodeSchemasInCaseNotDefinedWithCaseKeyword() throws Exception {
+ final String json = getJson("/nn-to-json/choice/xml/data_case_defined_without_case.xml");
+
+ assertTrue(json.contains("cont"));
+ assertTrue(json.contains("\"lf2b\":\"lf2b val\""));
+ assertTrue(json.contains("\"e1\":45"));
+ }
+
+ /**
+ * Test of multiple use of choices.
+ */
+ @Test
+ public void nodeSchemasInThreeChoicesAtSameLevel() throws Exception {
+ final String json = getJson("/nn-to-json/choice/xml/data_three_choices_same_level.xml");
+
+ assertTrue(json.contains("cont"));
+ assertTrue(json.contains("lf2b\":\"lf2b value"));
+ assertTrue(json.contains("lst4a\":[{"));
+ assertTrue(json.contains("{\"lf4ab\":33}"));
+ assertTrue(json.contains("{\"lf4ab\":37}"));
+ assertTrue(json.contains("\"lf1aaa\":\"lf1aaa value\""));
+ }
+
+ private String getJson(final String xmlPath) throws Exception {
+ final String uri = "choice-case-test:cont";
+ final NormalizedNodeContext testNN = TestRestconfUtils
+ .loadNormalizedContextFromXmlFile(xmlPath, uri, controllerContext);
+
+ final OutputStream output = new ByteArrayOutputStream();
+ jsonBodyWriter.writeTo(testNN, null, null, null, mediaType, null,
+ output);
+
+ return output.toString();
+ }
+
+ @Override
+ protected MediaType getMediaType() {
+ return null;
+ }
+}
diff --git a/netconf/restconf/restconf-nb-bierman02/src/test/java/org/opendaylight/controller/sal/restconf/impl/nn/to/json/test/NnToJsonLeafrefType.java b/netconf/restconf/restconf-nb-bierman02/src/test/java/org/opendaylight/controller/sal/restconf/impl/nn/to/json/test/NnToJsonLeafrefType.java
new file mode 100644
index 0000000..4ea6130
--- /dev/null
+++ b/netconf/restconf/restconf-nb-bierman02/src/test/java/org/opendaylight/controller/sal/restconf/impl/nn/to/json/test/NnToJsonLeafrefType.java
@@ -0,0 +1,107 @@
+/*
+ * Copyright (c) 2014 Cisco Systems, Inc. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.controller.sal.restconf.impl.nn.to.json.test;
+
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+
+import java.io.ByteArrayOutputStream;
+import java.io.OutputStream;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+import javax.ws.rs.core.MediaType;
+import org.junit.BeforeClass;
+import org.junit.Test;
+import org.opendaylight.controller.md.sal.rest.common.TestRestconfUtils;
+import org.opendaylight.controller.sal.rest.impl.test.providers.AbstractBodyReaderTest;
+import org.opendaylight.netconf.sal.rest.impl.NormalizedNodeContext;
+import org.opendaylight.netconf.sal.rest.impl.NormalizedNodeJsonBodyWriter;
+import org.opendaylight.yangtools.yang.model.api.EffectiveModelContext;
+
+public class NnToJsonLeafrefType extends AbstractBodyReaderTest {
+
+ private static EffectiveModelContext schemaContext;
+ private final NormalizedNodeJsonBodyWriter jsonBodyWriter;
+
+ public NnToJsonLeafrefType() {
+ super(schemaContext, null);
+ jsonBodyWriter = new NormalizedNodeJsonBodyWriter();
+ }
+
+ @BeforeClass
+ public static void initialization() {
+ schemaContext = schemaContextLoader("/nn-to-json/leafref", schemaContext);
+ }
+
+ @Test
+ public void leafrefAbsolutePathToExistingLeafTest() throws Exception {
+ final String json = toJson("/nn-to-json/leafref/xml/data_absolut_ref_to_existing_leaf.xml");
+ validateJson(".*\"lf3\":\\p{Blank}*\"true\".*", json);
+ }
+
+ @Test
+ public void leafrefRelativePathToExistingLeafTest() throws Exception {
+ final String json = toJson("/nn-to-json/leafref/xml/data_relativ_ref_to_existing_leaf.xml");
+ validateJson(".*\"lf2\":\\p{Blank}*\"121\".*", json);
+ }
+
+ @Test(expected = NullPointerException.class)
+ public void leafrefToNonExistingLeafTest() throws Exception {
+ toJson("/nn-to-json/leafref/xml/data_ref_to_non_existing_leaf.xml");
+ }
+
+ @Test
+ public void leafrefToNotLeafTest() throws Exception {
+ final String json = toJson("/nn-to-json/leafref/xml/data_ref_to_not_leaf.xml");
+ validateJson(
+ ".*\"cont-augment-module\\p{Blank}*:\\p{Blank}*lf6\":\\p{Blank}*\"44\".*",
+ json);
+ }
+
+ @Test
+ public void leafrefFromLeafListToLeafTest() throws Exception {
+ final String json = toJson("/nn-to-json/leafref/xml/data_relativ_ref_from_leaflist_to_existing_leaf.xml");
+ validateJson(".*\"cont-augment-module\\p{Blank}*:\\p{Blank}*lflst1\":\\p{Blank}*.*\"34[5|6|7]\",*\"34[5|6|7]\","
+ + "*\"34[5|6|7]\".*", json);
+ }
+
+ @Test
+ public void leafrefFromLeafrefToLeafrefTest() throws Exception {
+ final String json = toJson("/nn-to-json/leafref/xml/data_from_leafref_to_leafref.xml");
+ validateJson(
+ ".*\"cont-augment-module\\p{Blank}*:\\p{Blank}*lf7\":\\p{Blank}*\"200\".*",
+ json);
+ }
+
+ private static void validateJson(final String regex, final String value) {
+ assertNotNull(value);
+ final Pattern ptrn = Pattern.compile(regex, Pattern.DOTALL);
+ final Matcher mtch = ptrn.matcher(value);
+ assertTrue(mtch.matches());
+ }
+
+ private String toJson(final String xmlDataPath) throws Exception {
+ final String uri = "main-module:cont";
+ final String pathToInputFile = xmlDataPath;
+
+ final NormalizedNodeContext testNN = TestRestconfUtils
+ .loadNormalizedContextFromXmlFile(pathToInputFile, uri, controllerContext);
+
+ final OutputStream output = new ByteArrayOutputStream();
+ jsonBodyWriter.writeTo(testNN, null, null, null, mediaType, null,
+ output);
+ final String jsonOutput = output.toString();
+
+ return jsonOutput;
+ }
+
+ @Override
+ protected MediaType getMediaType() {
+ return new MediaType(MediaType.APPLICATION_XML, null);
+ }
+}
diff --git a/netconf/restconf/restconf-nb-bierman02/src/test/java/org/opendaylight/controller/sal/restconf/impl/nn/to/json/test/NnToJsonWithAugmentTest.java b/netconf/restconf/restconf-nb-bierman02/src/test/java/org/opendaylight/controller/sal/restconf/impl/nn/to/json/test/NnToJsonWithAugmentTest.java
new file mode 100644
index 0000000..d97b246
--- /dev/null
+++ b/netconf/restconf/restconf-nb-bierman02/src/test/java/org/opendaylight/controller/sal/restconf/impl/nn/to/json/test/NnToJsonWithAugmentTest.java
@@ -0,0 +1,70 @@
+/*
+ * Copyright (c) 2014 Cisco Systems, Inc. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.controller.sal.restconf.impl.nn.to.json.test;
+
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.OutputStream;
+import javax.ws.rs.WebApplicationException;
+import javax.ws.rs.core.MediaType;
+import org.junit.BeforeClass;
+import org.junit.Test;
+import org.opendaylight.controller.md.sal.rest.common.TestRestconfUtils;
+import org.opendaylight.controller.sal.rest.impl.test.providers.AbstractBodyReaderTest;
+import org.opendaylight.netconf.sal.rest.impl.NormalizedNodeContext;
+import org.opendaylight.netconf.sal.rest.impl.NormalizedNodeJsonBodyWriter;
+import org.opendaylight.yangtools.yang.model.api.EffectiveModelContext;
+
+@Deprecated
+public class NnToJsonWithAugmentTest extends AbstractBodyReaderTest {
+
+ private static EffectiveModelContext schemaContext;
+ private final NormalizedNodeJsonBodyWriter xmlBodyWriter;
+
+ public NnToJsonWithAugmentTest() {
+ super(schemaContext, null);
+ xmlBodyWriter = new NormalizedNodeJsonBodyWriter();
+ }
+
+ @BeforeClass
+ public static void initialize() {
+ schemaContext = schemaContextLoader("/nn-to-json/augmentation", schemaContext);
+ }
+
+ @Test
+ public void augmentedElementsToJson() throws WebApplicationException,
+ IOException {
+ final String uri = "yang:cont";
+ final String pathToInputFile = "/nn-to-json/augmentation/xml/data.xml";
+
+ final NormalizedNodeContext testNN = TestRestconfUtils
+ .loadNormalizedContextFromXmlFile(pathToInputFile, uri, controllerContext);
+
+ final OutputStream output = new ByteArrayOutputStream();
+ xmlBodyWriter
+ .writeTo(testNN, null, null, null, mediaType, null, output);
+ final String jsonOutput = output.toString();
+
+ assertNotNull(jsonOutput);
+ assertTrue(jsonOutput.contains("\"cont1\"" + ":" + '{'));
+ assertTrue(jsonOutput.contains("\"lf11\"" + ":" + "\"lf11\""));
+ assertTrue(jsonOutput.contains("\"lst1\"" + ":" + '['));
+ assertTrue(jsonOutput.contains("\"lf11\"" + ":" + "\"lf1_1\""));
+ assertTrue(jsonOutput.contains("\"lf11\"" + ":" + "\"lf1_2\""));
+ assertTrue(jsonOutput.contains("\"lflst1\"" + ":" + "["));
+ assertTrue(jsonOutput.contains("\"lf2\"" + ":" + "\"lf2\""));
+ }
+
+ @Override
+ protected MediaType getMediaType() {
+ return new MediaType(MediaType.APPLICATION_XML, null);
+ }
+}
diff --git a/netconf/restconf/restconf-nb-bierman02/src/test/java/org/opendaylight/controller/sal/restconf/impl/nn/to/xml/test/NnInstanceIdentifierToXmlTest.java b/netconf/restconf/restconf-nb-bierman02/src/test/java/org/opendaylight/controller/sal/restconf/impl/nn/to/xml/test/NnInstanceIdentifierToXmlTest.java
new file mode 100644
index 0000000..2ab6476
--- /dev/null
+++ b/netconf/restconf/restconf-nb-bierman02/src/test/java/org/opendaylight/controller/sal/restconf/impl/nn/to/xml/test/NnInstanceIdentifierToXmlTest.java
@@ -0,0 +1,250 @@
+/*
+ * Copyright (c) 2014 Cisco Systems, Inc. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.controller.sal.restconf.impl.nn.to.xml.test;
+
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+
+import java.io.ByteArrayOutputStream;
+import java.io.OutputStream;
+import java.net.URISyntaxException;
+import javax.ws.rs.core.MediaType;
+import org.junit.BeforeClass;
+import org.junit.Test;
+import org.opendaylight.controller.sal.rest.impl.test.providers.AbstractBodyReaderTest;
+import org.opendaylight.netconf.sal.rest.impl.NormalizedNodeContext;
+import org.opendaylight.netconf.sal.rest.impl.NormalizedNodeXmlBodyWriter;
+import org.opendaylight.netconf.sal.restconf.impl.ControllerContext;
+import org.opendaylight.restconf.common.context.InstanceIdentifierContext;
+import org.opendaylight.yangtools.yang.common.QName;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifier;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifierWithPredicates;
+import org.opendaylight.yangtools.yang.data.api.schema.ContainerNode;
+import org.opendaylight.yangtools.yang.data.api.schema.DataContainerChild;
+import org.opendaylight.yangtools.yang.data.api.schema.MapEntryNode;
+import org.opendaylight.yangtools.yang.data.api.schema.SystemLeafSetNode;
+import org.opendaylight.yangtools.yang.data.api.schema.SystemMapNode;
+import org.opendaylight.yangtools.yang.data.api.schema.builder.CollectionNodeBuilder;
+import org.opendaylight.yangtools.yang.data.api.schema.builder.DataContainerNodeBuilder;
+import org.opendaylight.yangtools.yang.data.api.schema.builder.ListNodeBuilder;
+import org.opendaylight.yangtools.yang.data.impl.schema.SchemaAwareBuilders;
+import org.opendaylight.yangtools.yang.model.api.ContainerSchemaNode;
+import org.opendaylight.yangtools.yang.model.api.DataNodeContainer;
+import org.opendaylight.yangtools.yang.model.api.DataSchemaNode;
+import org.opendaylight.yangtools.yang.model.api.EffectiveModelContext;
+import org.opendaylight.yangtools.yang.model.api.LeafListSchemaNode;
+import org.opendaylight.yangtools.yang.model.api.LeafSchemaNode;
+import org.opendaylight.yangtools.yang.model.api.ListSchemaNode;
+import org.opendaylight.yangtools.yang.model.util.SchemaInferenceStack;
+
+public class NnInstanceIdentifierToXmlTest extends AbstractBodyReaderTest {
+ private static EffectiveModelContext schemaContext;
+
+ private final NormalizedNodeXmlBodyWriter xmlBodyWriter = new NormalizedNodeXmlBodyWriter();
+
+ public NnInstanceIdentifierToXmlTest() {
+ super(schemaContext, null);
+ }
+
+ @BeforeClass
+ public static void initialization() throws URISyntaxException {
+ schemaContext = schemaContextLoader("/instanceidentifier/yang", schemaContext);
+ }
+
+ @Test
+ public void nnAsYangInstanceIdentifierAugmentLeafList() throws Exception {
+ final NormalizedNodeContext normalizedNodeContext = prepareNNCLeafList();
+
+ final OutputStream output = new ByteArrayOutputStream();
+
+ xmlBodyWriter.writeTo(normalizedNodeContext, null, null, null, mediaType, null, output);
+
+ assertNotNull(output);
+
+ final String outputJson = output.toString();
+
+ assertTrue(outputJson.contains("<cont xmlns="));
+ assertTrue(outputJson.contains(
+ '"' + "instance:identifier:module" + '"'));
+ assertTrue(outputJson.contains(">"));
+
+ assertTrue(outputJson.contains("<cont1>"));
+
+ assertTrue(outputJson.contains("<lf11 xmlns="));
+ assertTrue(outputJson.contains(
+ '"' + "augment:module:leaf:list" + '"'));
+ assertTrue(outputJson.contains(">"));
+ assertTrue(outputJson.contains("/instanceidentifier/"));
+ assertTrue(outputJson.contains("</lf11>"));
+
+ assertTrue(outputJson.contains("<lflst11 xmlns="));
+ assertTrue(outputJson.contains(
+ '"' + "augment:module:leaf:list" + '"'));
+ assertTrue(outputJson.contains(">"));
+ assertTrue(outputJson.contains("lflst11 value"));
+ assertTrue(outputJson.contains("</lflst11>"));
+
+ assertTrue(outputJson.contains("</cont1>"));
+ assertTrue(outputJson.contains("</cont>"));
+ }
+
+ private static NormalizedNodeContext prepareNNCLeafList() throws URISyntaxException {
+ final QName cont = QName.create("instance:identifier:module", "2014-01-17",
+ "cont");
+ final QName cont1 = QName.create("instance:identifier:module", "2014-01-17",
+ "cont1");
+ final QName lflst11 = QName.create("augment:module:leaf:list", "2014-01-17",
+ "lflst11");
+ final QName lf11 = QName.create("augment:module:leaf:list", "2014-01-17",
+ "lf11");
+
+ final DataSchemaNode schemaCont = schemaContext.getDataChildByName(cont);
+
+ final DataContainerNodeBuilder<NodeIdentifier, ContainerNode> dataCont = SchemaAwareBuilders
+ .containerBuilder((ContainerSchemaNode) schemaCont);
+
+ final DataSchemaNode schemaCont1 = ((ContainerSchemaNode) schemaCont).getDataChildByName(cont1);
+
+ final DataContainerNodeBuilder<NodeIdentifier, ContainerNode> dataCont1 = SchemaAwareBuilders
+ .containerBuilder((ContainerSchemaNode) schemaCont1);
+
+ final var instanceLfLst11 = ControllerContext.findInstanceDataChildrenByName(
+ (DataNodeContainer) schemaCont1, lflst11.getLocalName());
+
+ final DataSchemaNode lfLst11Schema = instanceLfLst11.get(0).child;
+ final ListNodeBuilder<Object, SystemLeafSetNode<Object>> lfLst11Data = SchemaAwareBuilders
+ .leafSetBuilder((LeafListSchemaNode) lfLst11Schema);
+
+ lfLst11Data.withChild(SchemaAwareBuilders.leafSetEntryBuilder((LeafListSchemaNode) lfLst11Schema)
+ .withValue("lflst11 value").build());
+ dataCont1.withChild(lfLst11Data.build());
+
+ final var instanceLf11 = ControllerContext.findInstanceDataChildrenByName(
+ (DataNodeContainer) schemaCont1, lf11.getLocalName());
+ final DataSchemaNode lf11Schema = instanceLf11.get(0).child;
+
+ dataCont1.withChild(SchemaAwareBuilders.leafBuilder((LeafSchemaNode) lf11Schema)
+ .withValue("/instanceidentifier/").build());
+ dataCont.withChild(dataCont1.build());
+
+ return new NormalizedNodeContext(
+ InstanceIdentifierContext.ofStack(SchemaInferenceStack.ofDataTreePath(schemaContext, cont)),
+ dataCont.build());
+ }
+
+ @Test
+ public void nnAsYangInstanceIdentifierAugment() throws Exception {
+
+ final NormalizedNodeContext normalizedNodeContext = preparNNC();
+ final OutputStream output = new ByteArrayOutputStream();
+
+ xmlBodyWriter.writeTo(normalizedNodeContext, null, null, null,
+ mediaType, null, output);
+
+ assertNotNull(output);
+
+ final String outputJson = output.toString();
+
+ assertTrue(outputJson.contains("<cont xmlns="));
+ assertTrue(outputJson.contains(
+ '"' + "instance:identifier:module" + '"'));
+ assertTrue(outputJson.contains(">"));
+
+ assertTrue(outputJson.contains("<cont1>"));
+
+ assertTrue(outputJson.contains("<lst11 xmlns="));
+ assertTrue(outputJson.contains('"' + "augment:module" + '"'));
+ assertTrue(outputJson.contains(">"));
+
+ assertTrue(outputJson.contains(
+ "<keyvalue111>keyvalue111</keyvalue111>"));
+ assertTrue(outputJson.contains(
+ "<keyvalue112>keyvalue112</keyvalue112>"));
+
+ assertTrue(outputJson.contains("<lf111 xmlns="));
+ assertTrue(outputJson.contains(
+ '"' + "augment:augment:module" + '"'));
+ assertTrue(outputJson.contains(">/cont/cont1/lf12</lf111>"));
+
+ assertTrue(outputJson.contains("<lf112 xmlns="));
+ assertTrue(outputJson.contains(
+ '"' + "augment:augment:module" + '"'));
+ assertTrue(outputJson.contains(">lf12 value</lf112>"));
+
+ assertTrue(outputJson.contains("</lst11></cont1></cont>"));
+ }
+
+ private static NormalizedNodeContext preparNNC() {
+ final QName cont = QName.create("instance:identifier:module", "2014-01-17",
+ "cont");
+ final QName cont1 = QName.create("instance:identifier:module", "2014-01-17",
+ "cont1");
+ final QName lst11 = QName.create("augment:module", "2014-01-17", "lst11");
+ final QName lf11 = QName.create("augment:augment:module", "2014-01-17",
+ "lf111");
+ final QName lf12 = QName.create("augment:augment:module", "2014-01-17",
+ "lf112");
+ final QName keyvalue111 = QName.create("augment:module", "2014-01-17",
+ "keyvalue111");
+ final QName keyvalue112 = QName.create("augment:module", "2014-01-17",
+ "keyvalue112");
+
+ final DataSchemaNode schemaCont = schemaContext.getDataChildByName(cont);
+
+ final DataContainerNodeBuilder<NodeIdentifier, ContainerNode> dataCont = SchemaAwareBuilders
+ .containerBuilder((ContainerSchemaNode) schemaCont);
+
+ final DataSchemaNode schemaCont1 = ((ContainerSchemaNode) schemaCont)
+ .getDataChildByName(cont1);
+
+ final DataContainerNodeBuilder<NodeIdentifier, ContainerNode> dataCont1 = SchemaAwareBuilders
+ .containerBuilder((ContainerSchemaNode) schemaCont1);
+
+ final var instanceLst11 = ControllerContext.findInstanceDataChildrenByName(
+ (DataNodeContainer) schemaCont1, lst11.getLocalName());
+ final DataSchemaNode lst11Schema = instanceLst11.get(0).child;
+
+ final CollectionNodeBuilder<MapEntryNode, SystemMapNode> dataLst11 = SchemaAwareBuilders
+ .mapBuilder((ListSchemaNode) lst11Schema);
+
+ final DataContainerNodeBuilder<NodeIdentifierWithPredicates, MapEntryNode> dataLst11Vaule = SchemaAwareBuilders
+ .mapEntryBuilder((ListSchemaNode) lst11Schema);
+
+ dataLst11Vaule.withChild(buildLeaf(lst11Schema, keyvalue111, dataLst11, "keyvalue111"));
+
+ dataLst11Vaule.withChild(buildLeaf(lst11Schema, keyvalue112, dataLst11, "keyvalue112"));
+
+ dataLst11Vaule.withChild(buildLeaf(lst11Schema, lf11, dataLst11, "/cont/cont1/lf12"));
+
+ dataLst11Vaule.withChild(buildLeaf(lst11Schema, lf12, dataLst11, "lf12 value"));
+
+ dataLst11.withChild(dataLst11Vaule.build());
+
+ dataCont1.withChild(dataLst11.build());
+ dataCont.withChild(dataCont1.build());
+
+ return new NormalizedNodeContext(
+ InstanceIdentifierContext.ofStack(SchemaInferenceStack.ofDataTreePath(schemaContext, cont)),
+ dataCont.build());
+ }
+
+ private static DataContainerChild buildLeaf(final DataSchemaNode lst11Schema, final QName qname,
+ final CollectionNodeBuilder<MapEntryNode, SystemMapNode> dataLst11, final Object value) {
+
+ final var instanceLf = ControllerContext.findInstanceDataChildrenByName(
+ (DataNodeContainer) lst11Schema, qname.getLocalName());
+ final DataSchemaNode schemaLf = instanceLf.get(0).child;
+
+ return SchemaAwareBuilders.leafBuilder((LeafSchemaNode) schemaLf).withValue(value).build();
+ }
+
+ @Override
+ protected MediaType getMediaType() {
+ return null;
+ }
+}
diff --git a/netconf/restconf/restconf-nb-bierman02/src/test/java/org/opendaylight/controller/sal/restconf/impl/nn/to/xml/test/NnToXmlTest.java b/netconf/restconf/restconf-nb-bierman02/src/test/java/org/opendaylight/controller/sal/restconf/impl/nn/to/xml/test/NnToXmlTest.java
new file mode 100644
index 0000000..b1385d9
--- /dev/null
+++ b/netconf/restconf/restconf-nb-bierman02/src/test/java/org/opendaylight/controller/sal/restconf/impl/nn/to/xml/test/NnToXmlTest.java
@@ -0,0 +1,407 @@
+/*
+ * Copyright (c) 2014 Cisco Systems, Inc. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.controller.sal.restconf.impl.nn.to.xml.test;
+
+import static org.hamcrest.CoreMatchers.instanceOf;
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertThrows;
+import static org.junit.Assert.assertTrue;
+
+import com.google.common.base.Throwables;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.OutputStream;
+import javax.ws.rs.core.MediaType;
+import org.junit.BeforeClass;
+import org.junit.Test;
+import org.mockito.Mockito;
+import org.opendaylight.controller.sal.rest.impl.test.providers.AbstractBodyReaderTest;
+import org.opendaylight.netconf.sal.rest.impl.NormalizedNodeContext;
+import org.opendaylight.netconf.sal.rest.impl.NormalizedNodeXmlBodyWriter;
+import org.opendaylight.netconf.sal.restconf.impl.ControllerContext;
+import org.opendaylight.restconf.common.context.InstanceIdentifierContext;
+import org.opendaylight.yangtools.yang.common.QName;
+import org.opendaylight.yangtools.yang.common.Uint32;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifier;
+import org.opendaylight.yangtools.yang.data.api.schema.ContainerNode;
+import org.opendaylight.yangtools.yang.data.api.schema.builder.DataContainerNodeBuilder;
+import org.opendaylight.yangtools.yang.data.impl.codec.TypeDefinitionAwareCodec;
+import org.opendaylight.yangtools.yang.data.impl.schema.SchemaAwareBuilders;
+import org.opendaylight.yangtools.yang.model.api.ContainerSchemaNode;
+import org.opendaylight.yangtools.yang.model.api.DataNodeContainer;
+import org.opendaylight.yangtools.yang.model.api.DataSchemaNode;
+import org.opendaylight.yangtools.yang.model.api.EffectiveModelContext;
+import org.opendaylight.yangtools.yang.model.api.LeafSchemaNode;
+import org.opendaylight.yangtools.yang.model.api.type.BitsTypeDefinition;
+import org.opendaylight.yangtools.yang.model.api.type.EnumTypeDefinition;
+import org.opendaylight.yangtools.yang.model.ri.type.BaseTypes;
+import org.opendaylight.yangtools.yang.model.ri.type.BitsTypeBuilder;
+import org.opendaylight.yangtools.yang.model.ri.type.EnumerationTypeBuilder;
+import org.opendaylight.yangtools.yang.model.ri.type.UnionTypeBuilder;
+import org.opendaylight.yangtools.yang.model.util.SchemaInferenceStack;
+
+public class NnToXmlTest extends AbstractBodyReaderTest {
+ private static EffectiveModelContext schemaContext;
+
+ private final NormalizedNodeXmlBodyWriter xmlBodyWriter;
+
+ public NnToXmlTest() {
+ super(schemaContext, null);
+ xmlBodyWriter = new NormalizedNodeXmlBodyWriter();
+ }
+
+ @BeforeClass
+ public static void initialization() {
+ schemaContext = schemaContextLoader("/nn-to-xml/yang", schemaContext);
+ }
+
+ @Test
+ public void nnAsYangIdentityrefToXMLTest() throws Exception {
+ final NormalizedNodeContext normalizedNodeContext = prepareIdrefData(null, true);
+ nnToXml(normalizedNodeContext, "<lf11 xmlns:x=\"referenced:module\">x:iden</lf11>");
+ }
+
+ @Test
+ public void nnAsYangIdentityrefWithQNamePrefixToXMLTest() throws Exception {
+ final NormalizedNodeContext normalizedNodeContext = prepareIdrefData("prefix", true);
+ nnToXml(normalizedNodeContext, "<lf11 xmlns", "=\"referenced:module\">", ":iden</lf11>");
+ }
+
+ @Test
+ public void nnAsYangIdentityrefWithPrefixToXMLTest() throws Exception {
+ final NormalizedNodeContext normalizedNodeContext = prepareIdrefData("prefix", false);
+ nnToXml(normalizedNodeContext, "<lf11>no qname value</lf11>");
+ }
+
+ @Test
+ public void nnAsYangLeafrefWithPrefixToXMLTest() throws Exception {
+ nnToXml(prepareLeafrefData(), "<lfBoolean>true</lfBoolean>", "<lfLfref>true</lfLfref>");
+ }
+
+ /**
+ * Negative test when leaf of type leafref references to not-existing leaf.
+ * {@code VerifyException} is expected.
+ */
+ @Test
+ public void nnAsYangLeafrefWithPrefixToXMLNegativeTest() throws Exception {
+ final NormalizedNodeContext normalizedNodeContext = prepareLeafrefNegativeData();
+
+ final IOException ex = assertThrows(IOException.class, () -> nnToXml(normalizedNodeContext,
+ "<not-existing>value</not-existing>", "<lfLfrefNegative>value</lfLfrefnegative>"));
+ final Throwable rootCause = Throwables.getRootCause(ex);
+ assertThat(rootCause, instanceOf(IllegalArgumentException.class));
+ assertEquals("Data tree child (basic:module?revision=2013-12-02)not-existing not present in schema parent "
+ + "(basic:module?revision=2013-12-02)cont", rootCause.getMessage());
+ }
+
+ @Test
+ public void nnAsYangStringToXmlTest() throws Exception {
+ final NormalizedNodeContext normalizedNodeContext = prepareNNC(
+ TypeDefinitionAwareCodec.from(BaseTypes.stringType()).deserialize("lfStr value"), "lfStr");
+ nnToXml(normalizedNodeContext, "<lfStr>lfStr value</lfStr>");
+ }
+
+ @Test
+ public void nnAsYangInt8ToXmlTest() throws Exception {
+ final String elName = "lfInt8";
+
+ final NormalizedNodeContext normalizedNodeContext = prepareNNC(
+ TypeDefinitionAwareCodec.from(BaseTypes.int8Type()).deserialize("14"), elName);
+ nnToXml(normalizedNodeContext, "<" + elName + ">14</" + elName + ">");
+ }
+
+ @Test
+ public void nnAsYangInt16ToXmlTest() throws Exception {
+ final String elName = "lfInt16";
+
+ final NormalizedNodeContext normalizedNodeContext = prepareNNC(
+ TypeDefinitionAwareCodec.from(BaseTypes.int16Type()).deserialize("3000"), elName);
+ nnToXml(normalizedNodeContext, "<" + elName + ">3000</" + elName + ">");
+ }
+
+ @Test
+ public void nnAsYangInt32ToXmlTest() throws Exception {
+ final String elName = "lfInt32";
+
+ final NormalizedNodeContext normalizedNodeContext = prepareNNC(
+ TypeDefinitionAwareCodec.from(BaseTypes.int32Type()).deserialize("201234"), elName);
+ nnToXml(normalizedNodeContext, "<" + elName + ">201234</" + elName + ">");
+ }
+
+ @Test
+ public void nnAsYangInt64ToXmlTest() throws Exception {
+ final String elName = "lfInt64";
+
+ final NormalizedNodeContext normalizedNodeContext = prepareNNC(
+ TypeDefinitionAwareCodec.from(BaseTypes.int64Type()).deserialize("5123456789"), elName);
+ nnToXml(normalizedNodeContext, "<" + elName + ">5123456789</" + elName + ">");
+ }
+
+ @Test
+ public void nnAsYangUint8ToXmlTest() throws Exception {
+ final String elName = "lfUint8";
+
+ final NormalizedNodeContext normalizedNodeContext = prepareNNC(
+ TypeDefinitionAwareCodec.from(BaseTypes.uint8Type()).deserialize("200"), elName);
+ nnToXml(normalizedNodeContext, "<" + elName + ">200</" + elName + ">");
+ }
+
+ @Test
+ public void snAsYangUint16ToXmlTest() throws Exception {
+ final String elName = "lfUint16";
+
+ final NormalizedNodeContext normalizedNodeContext = prepareNNC(
+ TypeDefinitionAwareCodec.from(BaseTypes.uint16Type()).deserialize("4000"), elName);
+ nnToXml(normalizedNodeContext, "<" + elName + ">4000</" + elName + ">");
+ }
+
+ @Test
+ public void nnAsYangUint32ToXmlTest() throws Exception {
+ final String elName = "lfUint32";
+
+ final NormalizedNodeContext normalizedNodeContext = prepareNNC(
+ TypeDefinitionAwareCodec.from(BaseTypes.uint32Type()).deserialize("4123456789"), elName);
+ nnToXml(normalizedNodeContext, "<" + elName + ">4123456789</" + elName + ">");
+ }
+
+ @Test
+ public void snAsYangUint64ToXmlTest() throws Exception {
+ final String elName = "lfUint64";
+ final NormalizedNodeContext normalizedNodeContext = prepareNNC(
+ TypeDefinitionAwareCodec.from(BaseTypes.uint64Type()).deserialize("5123456789"), elName);
+ nnToXml(normalizedNodeContext, "<" + elName + ">5123456789</" + elName + ">");
+ }
+
+ @Test
+ public void nnAsYangBinaryToXmlTest() throws Exception {
+ final String elName = "lfBinary";
+ final NormalizedNodeContext normalizedNodeContext = prepareNNC(
+ TypeDefinitionAwareCodec.from(BaseTypes.binaryType())
+ .deserialize("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz01234567"),
+ elName);
+ nnToXml(normalizedNodeContext,
+ "<" + elName + ">ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz01234567</" + elName + ">");
+ }
+
+ @Test
+ public void nnAsYangBitsToXmlTest() throws Exception {
+ final BitsTypeDefinition.Bit mockBit1 = Mockito.mock(BitsTypeDefinition.Bit.class);
+ Mockito.when(mockBit1.getName()).thenReturn("one");
+ Mockito.when(mockBit1.getPosition()).thenReturn(Uint32.ONE);
+ final BitsTypeDefinition.Bit mockBit2 = Mockito.mock(BitsTypeDefinition.Bit.class);
+ Mockito.when(mockBit2.getName()).thenReturn("two");
+ Mockito.when(mockBit2.getPosition()).thenReturn(Uint32.TWO);
+ final BitsTypeBuilder bitsTypeBuilder = BaseTypes.bitsTypeBuilder(QName.create("foo", "foo"));
+ bitsTypeBuilder.addBit(mockBit1);
+ bitsTypeBuilder.addBit(mockBit2);
+
+ final String elName = "lfBits";
+ final NormalizedNodeContext normalizedNodeContext = prepareNNC(
+ TypeDefinitionAwareCodec.from(bitsTypeBuilder.build()).deserialize("one two"), elName);
+ nnToXml(normalizedNodeContext, "<" + elName + ">one two</" + elName + ">");
+ }
+
+ @Test
+ public void nnAsYangEnumerationToXmlTest() throws Exception {
+ final EnumTypeDefinition.EnumPair mockEnum = Mockito.mock(EnumTypeDefinition.EnumPair.class);
+ Mockito.when(mockEnum.getName()).thenReturn("enum2");
+
+ final EnumerationTypeBuilder enumerationTypeBuilder = BaseTypes
+ .enumerationTypeBuilder(QName.create("foo", "foo"));
+ enumerationTypeBuilder.addEnum(mockEnum);
+
+ final String elName = "lfEnumeration";
+ final NormalizedNodeContext normalizedNodeContext = prepareNNC(
+ TypeDefinitionAwareCodec.from(enumerationTypeBuilder.build()).deserialize("enum2"), elName);
+ nnToXml(normalizedNodeContext, "<" + elName + ">enum2</" + elName + ">");
+ }
+
+ @Test
+ public void nnAsYangEmptyToXmlTest() throws Exception {
+ final String elName = "lfEmpty";
+ final NormalizedNodeContext normalizedNodeContext = prepareNNC(
+ TypeDefinitionAwareCodec.from(BaseTypes.emptyType()).deserialize(""), elName);
+ nnToXml(normalizedNodeContext, "<" + elName + "/>");
+ }
+
+ @Test
+ public void nnAsYangBooleanToXmlTest() throws Exception {
+ final String elName = "lfBoolean";
+ NormalizedNodeContext normalizedNodeContext = prepareNNC(
+ TypeDefinitionAwareCodec.from(BaseTypes.booleanType()).deserialize("false"), elName);
+ nnToXml(normalizedNodeContext, "<" + elName + ">false</" + elName + ">");
+
+ normalizedNodeContext = prepareNNC(TypeDefinitionAwareCodec.from(BaseTypes.booleanType()).deserialize("true"),
+ elName);
+ nnToXml(normalizedNodeContext, "<" + elName + ">true</" + elName + ">");
+ }
+
+ @Test
+ public void nnAsYangUnionToXmlTest() throws Exception {
+ final BitsTypeDefinition.Bit mockBit1 = Mockito.mock(BitsTypeDefinition.Bit.class);
+ Mockito.when(mockBit1.getName()).thenReturn("first");
+ Mockito.when(mockBit1.getPosition()).thenReturn(Uint32.ONE);
+ final BitsTypeDefinition.Bit mockBit2 = Mockito.mock(BitsTypeDefinition.Bit.class);
+ Mockito.when(mockBit2.getName()).thenReturn("second");
+ Mockito.when(mockBit2.getPosition()).thenReturn(Uint32.TWO);
+
+ final BitsTypeBuilder bitsTypeBuilder = BaseTypes.bitsTypeBuilder(QName.create("foo", "foo"));
+ bitsTypeBuilder.addBit(mockBit1);
+ bitsTypeBuilder.addBit(mockBit2);
+
+ final UnionTypeBuilder unionTypeBuilder = BaseTypes.unionTypeBuilder(QName.create("foo", "foo"));
+ unionTypeBuilder.addType(BaseTypes.int8Type());
+ unionTypeBuilder.addType(bitsTypeBuilder.build());
+ unionTypeBuilder.addType(BaseTypes.booleanType());
+ unionTypeBuilder.addType(BaseTypes.stringType());
+
+ final String elName = "lfUnion";
+
+ // test int8
+ final String int8 = "15";
+ NormalizedNodeContext normalizedNodeContext = prepareNNC(
+ TypeDefinitionAwareCodec.from(unionTypeBuilder.build()).deserialize(int8), elName);
+ nnToXml(normalizedNodeContext, "<" + elName + ">15</" + elName + ">");
+
+ // test bits
+ final String bits = "first second";
+ normalizedNodeContext = prepareNNC(TypeDefinitionAwareCodec.from(unionTypeBuilder.build()).deserialize(bits),
+ elName);
+ nnToXml(normalizedNodeContext, "<" + elName + ">[first, second]</" + elName + ">");
+
+ // test boolean
+ final String bool = "true";
+ normalizedNodeContext = prepareNNC(TypeDefinitionAwareCodec.from(unionTypeBuilder.build()).deserialize(bool),
+ elName);
+ nnToXml(normalizedNodeContext, "<" + elName + ">true</" + elName + ">");
+
+ // test string
+ final String s = "Hi!";
+ normalizedNodeContext = prepareNNC(TypeDefinitionAwareCodec.from(unionTypeBuilder.build()).deserialize(s),
+ elName);
+ nnToXml(normalizedNodeContext, "<" + elName + ">Hi!</" + elName + ">");
+ }
+
+ private static NormalizedNodeContext prepareNNC(final Object object, final String name) {
+ final QName cont = QName.create("basic:module", "2013-12-02", "cont");
+ final QName lf = QName.create("basic:module", "2013-12-02", name);
+
+ final DataSchemaNode contSchema = schemaContext.getDataChildByName(cont);
+
+ final DataContainerNodeBuilder<NodeIdentifier, ContainerNode> contData = SchemaAwareBuilders
+ .containerBuilder((ContainerSchemaNode) contSchema);
+
+ final var instanceLf = ControllerContext
+ .findInstanceDataChildrenByName((DataNodeContainer) contSchema, lf.getLocalName());
+ final DataSchemaNode schemaLf = instanceLf.get(0).child;
+
+ contData.withChild(SchemaAwareBuilders.leafBuilder((LeafSchemaNode) schemaLf).withValue(object).build());
+
+ return new NormalizedNodeContext(
+ InstanceIdentifierContext.ofStack(SchemaInferenceStack.ofDataTreePath(schemaContext, cont)),
+ contData.build());
+ }
+
+ private void nnToXml(final NormalizedNodeContext normalizedNodeContext, final String... xmlRepresentation)
+ throws Exception {
+ final OutputStream output = new ByteArrayOutputStream();
+ xmlBodyWriter.writeTo(normalizedNodeContext, null, null, null, mediaType, null, output);
+
+ for (String element : xmlRepresentation) {
+ assertTrue(output.toString().contains(element));
+ }
+ }
+
+ private static NormalizedNodeContext prepareLeafrefData() {
+ final QName cont = QName.create("basic:module", "2013-12-02", "cont");
+ final QName lfBoolean = QName.create("basic:module", "2013-12-02", "lfBoolean");
+ final QName lfLfref = QName.create("basic:module", "2013-12-02", "lfLfref");
+
+ final DataSchemaNode contSchema = schemaContext.getDataChildByName(cont);
+
+ final DataContainerNodeBuilder<NodeIdentifier, ContainerNode> contData = SchemaAwareBuilders
+ .containerBuilder((ContainerSchemaNode) contSchema);
+
+ var instanceLf = ControllerContext
+ .findInstanceDataChildrenByName((DataNodeContainer) contSchema, lfBoolean.getLocalName());
+ DataSchemaNode schemaLf = instanceLf.get(0).child;
+
+ contData.withChild(SchemaAwareBuilders.leafBuilder((LeafSchemaNode) schemaLf).withValue(Boolean.TRUE).build());
+
+ instanceLf = ControllerContext.findInstanceDataChildrenByName((DataNodeContainer) contSchema,
+ lfLfref.getLocalName());
+ schemaLf = instanceLf.get(0).child;
+
+ contData.withChild(SchemaAwareBuilders.leafBuilder((LeafSchemaNode) schemaLf).withValue("true").build());
+
+ return new NormalizedNodeContext(
+ InstanceIdentifierContext.ofStack(SchemaInferenceStack.ofDataTreePath(schemaContext, cont)),
+ contData.build());
+ }
+
+ private static NormalizedNodeContext prepareLeafrefNegativeData() {
+ final QName cont = QName.create("basic:module", "2013-12-02", "cont");
+ final QName lfLfref = QName.create("basic:module", "2013-12-02", "lfLfrefNegative");
+
+ final DataSchemaNode contSchema = schemaContext.getDataChildByName(cont);
+ final DataContainerNodeBuilder<NodeIdentifier, ContainerNode> contData = SchemaAwareBuilders
+ .containerBuilder((ContainerSchemaNode) contSchema);
+
+ final var instanceLf = ControllerContext.findInstanceDataChildrenByName((DataNodeContainer)
+ contSchema, lfLfref.getLocalName());
+ final DataSchemaNode schemaLf = instanceLf.get(0).child;
+
+ contData.withChild(SchemaAwareBuilders.leafBuilder((LeafSchemaNode) schemaLf).withValue("value").build());
+
+ return new NormalizedNodeContext(
+ InstanceIdentifierContext.ofStack(SchemaInferenceStack.ofDataTreePath(schemaContext, cont)),
+ contData.build());
+ }
+
+ private static NormalizedNodeContext prepareIdrefData(final String prefix, final boolean valueAsQName) {
+ final QName cont = QName.create("basic:module", "2013-12-02", "cont");
+ final QName cont1 = QName.create("basic:module", "2013-12-02", "cont1");
+ final QName lf11 = QName.create("basic:module", "2013-12-02", "lf11");
+
+ final DataSchemaNode contSchema = schemaContext.getDataChildByName(cont);
+
+ final DataContainerNodeBuilder<NodeIdentifier, ContainerNode> contData = SchemaAwareBuilders
+ .containerBuilder((ContainerSchemaNode) contSchema);
+
+ final DataSchemaNode cont1Schema = ((ContainerSchemaNode) contSchema).getDataChildByName(cont1);
+
+ final DataContainerNodeBuilder<NodeIdentifier, ContainerNode> cont1Data = SchemaAwareBuilders
+ .containerBuilder((ContainerSchemaNode) cont1Schema);
+
+ Object value = null;
+ if (valueAsQName) {
+ value = QName.create("referenced:module", "2013-12-02", "iden");
+ } else {
+ value = "no qname value";
+ }
+
+ final var instanceLf = ControllerContext
+ .findInstanceDataChildrenByName((DataNodeContainer) cont1Schema, lf11.getLocalName());
+ final DataSchemaNode schemaLf = instanceLf.get(0).child;
+
+ cont1Data.withChild(SchemaAwareBuilders.leafBuilder((LeafSchemaNode) schemaLf).withValue(value).build());
+
+ contData.withChild(cont1Data.build());
+
+ final NormalizedNodeContext testNormalizedNodeContext = new NormalizedNodeContext(
+ InstanceIdentifierContext.ofStack(SchemaInferenceStack.ofDataTreePath(schemaContext, cont)),
+ contData.build());
+ return testNormalizedNodeContext;
+ }
+
+ @Override
+ protected MediaType getMediaType() {
+ return null;
+ }
+}
diff --git a/netconf/restconf/restconf-nb-bierman02/src/test/java/org/opendaylight/controller/sal/restconf/impl/nn/to/xml/test/NnToXmlWithChoiceTest.java b/netconf/restconf/restconf-nb-bierman02/src/test/java/org/opendaylight/controller/sal/restconf/impl/nn/to/xml/test/NnToXmlWithChoiceTest.java
new file mode 100644
index 0000000..9d2954d
--- /dev/null
+++ b/netconf/restconf/restconf-nb-bierman02/src/test/java/org/opendaylight/controller/sal/restconf/impl/nn/to/xml/test/NnToXmlWithChoiceTest.java
@@ -0,0 +1,108 @@
+/*
+ * Copyright (c) 2014 Cisco Systems, Inc. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.controller.sal.restconf.impl.nn.to.xml.test;
+
+import static org.junit.Assert.assertTrue;
+
+import java.io.ByteArrayOutputStream;
+import java.io.OutputStream;
+import javax.ws.rs.core.MediaType;
+import org.junit.BeforeClass;
+import org.junit.Test;
+import org.opendaylight.controller.sal.rest.impl.test.providers.AbstractBodyReaderTest;
+import org.opendaylight.netconf.sal.rest.impl.NormalizedNodeContext;
+import org.opendaylight.netconf.sal.rest.impl.NormalizedNodeXmlBodyWriter;
+import org.opendaylight.netconf.sal.restconf.impl.ControllerContext;
+import org.opendaylight.restconf.common.context.InstanceIdentifierContext;
+import org.opendaylight.yangtools.yang.common.QName;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifier;
+import org.opendaylight.yangtools.yang.data.api.schema.ChoiceNode;
+import org.opendaylight.yangtools.yang.data.api.schema.ContainerNode;
+import org.opendaylight.yangtools.yang.data.api.schema.builder.DataContainerNodeBuilder;
+import org.opendaylight.yangtools.yang.data.impl.schema.SchemaAwareBuilders;
+import org.opendaylight.yangtools.yang.model.api.ChoiceSchemaNode;
+import org.opendaylight.yangtools.yang.model.api.ContainerSchemaNode;
+import org.opendaylight.yangtools.yang.model.api.DataNodeContainer;
+import org.opendaylight.yangtools.yang.model.api.DataSchemaNode;
+import org.opendaylight.yangtools.yang.model.api.EffectiveModelContext;
+import org.opendaylight.yangtools.yang.model.api.LeafSchemaNode;
+import org.opendaylight.yangtools.yang.model.util.SchemaInferenceStack;
+
+public class NnToXmlWithChoiceTest extends AbstractBodyReaderTest {
+
+ private final NormalizedNodeXmlBodyWriter xmlBodyWriter;
+ private static EffectiveModelContext schemaContext;
+
+ public NnToXmlWithChoiceTest() {
+ super(schemaContext, null);
+ xmlBodyWriter = new NormalizedNodeXmlBodyWriter();
+ }
+
+ @BeforeClass
+ public static void initialization() {
+ schemaContext = schemaContextLoader("/nn-to-xml/choice", schemaContext);
+ }
+
+ @Test
+ public void cnSnToXmlWithYangChoice() throws Exception {
+ NormalizedNodeContext normalizedNodeContext = prepareNNC("lf1",
+ "String data1");
+ OutputStream output = new ByteArrayOutputStream();
+ xmlBodyWriter.writeTo(normalizedNodeContext, null, null, null,
+ mediaType, null, output);
+ assertTrue(output.toString().contains("<lf1>String data1</lf1>"));
+
+ normalizedNodeContext = prepareNNC("lf2", "String data2");
+ output = new ByteArrayOutputStream();
+
+ xmlBodyWriter.writeTo(normalizedNodeContext, null, null, null,
+ mediaType, null, output);
+ assertTrue(output.toString().contains("<lf2>String data2</lf2>"));
+ }
+
+ private static NormalizedNodeContext prepareNNC(final String name, final Object value) {
+
+ final QName contQname = QName.create("module:with:choice", "2013-12-18",
+ "cont");
+ final QName lf = QName.create("module:with:choice", "2013-12-18", name);
+ final QName choA = QName.create("module:with:choice", "2013-12-18", "choA");
+
+ final DataSchemaNode contSchemaNode = schemaContext
+ .getDataChildByName(contQname);
+ final DataContainerNodeBuilder<NodeIdentifier, ContainerNode> dataContainerNodeAttrBuilder = SchemaAwareBuilders
+ .containerBuilder((ContainerSchemaNode) contSchemaNode);
+
+ final DataSchemaNode choiceSchemaNode = ((ContainerSchemaNode) contSchemaNode)
+ .getDataChildByName(choA);
+ assertTrue(choiceSchemaNode instanceof ChoiceSchemaNode);
+
+ final DataContainerNodeBuilder<NodeIdentifier, ChoiceNode> dataChoice = SchemaAwareBuilders
+ .choiceBuilder((ChoiceSchemaNode) choiceSchemaNode);
+
+ final var instanceLf = ControllerContext
+ .findInstanceDataChildrenByName(
+ (DataNodeContainer) contSchemaNode, lf.getLocalName());
+ final DataSchemaNode schemaLf = instanceLf.get(0).child;
+
+ dataChoice.withChild(SchemaAwareBuilders.leafBuilder((LeafSchemaNode) schemaLf)
+ .withValue(value).build());
+
+ dataContainerNodeAttrBuilder.withChild(dataChoice.build());
+
+ final NormalizedNodeContext testNormalizedNodeContext = new NormalizedNodeContext(
+ InstanceIdentifierContext.ofStack(SchemaInferenceStack.ofDataTreePath(schemaContext, contQname)),
+ dataContainerNodeAttrBuilder.build());
+
+ return testNormalizedNodeContext;
+ }
+
+ @Override
+ protected MediaType getMediaType() {
+ return null;
+ }
+}
diff --git a/netconf/restconf/restconf-nb-bierman02/src/test/java/org/opendaylight/controller/sal/restconf/impl/nn/to/xml/test/NnToXmlWithDataFromSeveralModulesTest.java b/netconf/restconf/restconf-nb-bierman02/src/test/java/org/opendaylight/controller/sal/restconf/impl/nn/to/xml/test/NnToXmlWithDataFromSeveralModulesTest.java
new file mode 100644
index 0000000..a9cf7a6
--- /dev/null
+++ b/netconf/restconf/restconf-nb-bierman02/src/test/java/org/opendaylight/controller/sal/restconf/impl/nn/to/xml/test/NnToXmlWithDataFromSeveralModulesTest.java
@@ -0,0 +1,144 @@
+/*
+ * Copyright (c) 2014 Cisco Systems, Inc. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.controller.sal.restconf.impl.nn.to.xml.test;
+
+import static org.junit.Assert.assertTrue;
+
+import com.google.common.base.Preconditions;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.net.URISyntaxException;
+import javax.ws.rs.WebApplicationException;
+import javax.ws.rs.core.MediaType;
+import org.junit.BeforeClass;
+import org.junit.Test;
+import org.opendaylight.controller.sal.rest.impl.test.providers.AbstractBodyReaderTest;
+import org.opendaylight.netconf.sal.rest.impl.NormalizedNodeContext;
+import org.opendaylight.netconf.sal.rest.impl.NormalizedNodeXmlBodyWriter;
+import org.opendaylight.netconf.sal.restconf.impl.ControllerContext;
+import org.opendaylight.restconf.common.context.InstanceIdentifierContext;
+import org.opendaylight.yangtools.yang.common.QName;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifier;
+import org.opendaylight.yangtools.yang.data.api.schema.ContainerNode;
+import org.opendaylight.yangtools.yang.data.api.schema.builder.DataContainerNodeBuilder;
+import org.opendaylight.yangtools.yang.data.impl.schema.SchemaAwareBuilders;
+import org.opendaylight.yangtools.yang.model.api.ContainerSchemaNode;
+import org.opendaylight.yangtools.yang.model.api.DataNodeContainer;
+import org.opendaylight.yangtools.yang.model.api.DataSchemaNode;
+import org.opendaylight.yangtools.yang.model.api.EffectiveModelContext;
+import org.opendaylight.yangtools.yang.model.api.LeafSchemaNode;
+
+public class NnToXmlWithDataFromSeveralModulesTest extends
+ AbstractBodyReaderTest {
+
+ private final NormalizedNodeXmlBodyWriter xmlBodyWriter;
+ private static EffectiveModelContext schemaContext;
+
+ public NnToXmlWithDataFromSeveralModulesTest() {
+ super(schemaContext, null);
+ xmlBodyWriter = new NormalizedNodeXmlBodyWriter();
+ }
+
+ @BeforeClass
+ public static void initialize() {
+ schemaContext = schemaContextLoader("/nn-to-xml/data-of-several-modules/yang", schemaContext);
+ }
+
+ @Test
+ public void dataFromSeveralModulesToXmlTest()
+ throws WebApplicationException, IOException, URISyntaxException {
+ final NormalizedNodeContext normalizedNodeContext = prepareNormalizedNodeContext();
+ final OutputStream output = new ByteArrayOutputStream();
+ xmlBodyWriter.writeTo(normalizedNodeContext, null, null, null,
+ mediaType, null, output);
+
+ final String outputString = output.toString();
+ // data
+ assertTrue(outputString
+ .contains(
+ "<data xmlns=" + '"'
+ + "urn:ietf:params:xml:ns:netconf:base:1.0"
+ + '"' + '>'));
+ // cont m2
+ assertTrue(outputString.contains(
+ "<cont_m2 xmlns=" + '"' + "module:two" + '"' + '>'));
+ assertTrue(outputString.contains("<lf1_m2>lf1 m2 value</lf1_m2>"));
+ assertTrue(outputString.contains("<contB_m2/>"));
+ assertTrue(outputString.contains("</cont_m2>"));
+
+ // cont m1
+ assertTrue(outputString.contains(
+ "<cont_m1 xmlns=" + '"' + "module:one" + '"' + '>'));
+ assertTrue(outputString.contains("<contB_m1/>"));
+ assertTrue(outputString.contains("<lf1_m1>lf1 m1 value</lf1_m1>"));
+ assertTrue(outputString.contains("</cont_m1>"));
+
+ // end
+ assertTrue(output.toString().contains("</data>"));
+ }
+
+ @Override
+ protected MediaType getMediaType() {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ private static NormalizedNodeContext prepareNormalizedNodeContext() {
+ final String rev = "2014-01-17";
+
+ final DataContainerNodeBuilder<NodeIdentifier, ContainerNode> dataContSchemaContNode = SchemaAwareBuilders
+ .containerBuilder(schemaContext);
+
+ final DataContainerNodeBuilder<NodeIdentifier, ContainerNode> modul1 = buildContBuilderMod1(
+ "module:one", rev, "cont_m1", "contB_m1", "lf1_m1",
+ "lf1 m1 value");
+ dataContSchemaContNode.withChild(modul1.build());
+
+ final DataContainerNodeBuilder<NodeIdentifier, ContainerNode> modul2 = buildContBuilderMod1(
+ "module:two", rev, "cont_m2", "contB_m2", "lf1_m2",
+ "lf1 m2 value");
+ dataContSchemaContNode.withChild(modul2.build());
+
+ final NormalizedNodeContext testNormalizedNodeContext = new NormalizedNodeContext(
+ InstanceIdentifierContext.ofLocalRoot(schemaContext),
+ dataContSchemaContNode.build());
+
+ return testNormalizedNodeContext;
+ }
+
+ private static DataContainerNodeBuilder<NodeIdentifier, ContainerNode> buildContBuilderMod1(
+ final String uri, final String rev, final String cont, final String contB, final String lf1,
+ final String lf1Value) {
+ final QName contQname = QName.create(uri, rev, cont);
+ final QName contBQname = QName.create(uri, rev, contB);
+ final QName lf1Qname = QName.create(contQname, lf1);
+
+ final DataSchemaNode contSchemaNode = schemaContext
+ .getDataChildByName(contQname);
+ final DataContainerNodeBuilder<NodeIdentifier, ContainerNode> dataContainerNodeAttrBuilder = SchemaAwareBuilders
+ .containerBuilder((ContainerSchemaNode) contSchemaNode);
+
+ Preconditions.checkState(contSchemaNode instanceof ContainerSchemaNode);
+ final var instanceLf1_m1 = ControllerContext.findInstanceDataChildrenByName(
+ (DataNodeContainer) contSchemaNode, lf1Qname.getLocalName());
+ final DataSchemaNode schemaLf1_m1 = instanceLf1_m1.get(0).child;
+
+ dataContainerNodeAttrBuilder.withChild(SchemaAwareBuilders
+ .leafBuilder((LeafSchemaNode) schemaLf1_m1)
+ .withValue(lf1Value).build());
+
+ final DataSchemaNode contBSchemaNode = ((ContainerSchemaNode) contSchemaNode)
+ .getDataChildByName(contBQname);
+
+ final DataContainerNodeBuilder<NodeIdentifier, ContainerNode> dataContainerB = SchemaAwareBuilders
+ .containerBuilder((ContainerSchemaNode) contBSchemaNode);
+
+ return dataContainerNodeAttrBuilder.withChild(dataContainerB.build());
+ }
+}
diff --git a/netconf/restconf/restconf-nb-bierman02/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/Bierman02RestConfWiringTest.java b/netconf/restconf/restconf-nb-bierman02/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/Bierman02RestConfWiringTest.java
new file mode 100644
index 0000000..990453f
--- /dev/null
+++ b/netconf/restconf/restconf-nb-bierman02/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/Bierman02RestConfWiringTest.java
@@ -0,0 +1,54 @@
+/*
+ * Copyright (c) 2019 Red Hat, Inc. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.controller.sal.restconf.impl.test;
+
+import static org.junit.Assert.assertEquals;
+
+import com.google.inject.AbstractModule;
+import java.io.IOException;
+import java.net.URISyntaxException;
+import javax.inject.Inject;
+import org.junit.Rule;
+import org.junit.Test;
+import org.opendaylight.aaa.filterchain.configuration.CustomFilterAdapterConfiguration;
+import org.opendaylight.aaa.web.WebServer;
+import org.opendaylight.aaa.web.testutils.TestWebClient;
+import org.opendaylight.aaa.web.testutils.WebTestModule;
+import org.opendaylight.controller.sal.restconf.impl.test.incubate.InMemoryMdsalModule;
+import org.opendaylight.infrautils.inject.guice.testutils.AnnotationsModule;
+import org.opendaylight.infrautils.inject.guice.testutils.GuiceRule;
+import org.opendaylight.netconf.sal.restconf.api.RestConfConfig;
+import org.opendaylight.netconf.sal.restconf.impl.Bierman02RestConfWiring;
+
+/**
+ * Tests if the {@link Bierman02RestConfWiring} works.
+ *
+ * @author Michael Vorburger.ch
+ */
+public class Bierman02RestConfWiringTest {
+
+ public static class TestModule extends AbstractModule {
+ @Override
+ protected void configure() {
+ bind(Bierman02RestConfWiring.class).asEagerSingleton();
+ bind(RestConfConfig.class).toInstance(() -> 9090);
+ bind(CustomFilterAdapterConfiguration.class).toInstance(listener -> { });
+ }
+ }
+
+ public @Rule GuiceRule guice = new GuiceRule(TestModule.class,
+ InMemoryMdsalModule.class, WebTestModule.class, AnnotationsModule.class);
+
+ @Inject WebServer webServer;
+ @Inject TestWebClient webClient;
+
+ @Test
+ public void testWiring() throws IOException, InterruptedException, URISyntaxException {
+ assertEquals(200, webClient.request("GET", "/restconf/modules/").statusCode());
+ }
+}
diff --git a/netconf/restconf/restconf-nb-bierman02/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/BrokerFacadeTest.java b/netconf/restconf/restconf-nb-bierman02/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/BrokerFacadeTest.java
new file mode 100644
index 0000000..8443712
--- /dev/null
+++ b/netconf/restconf/restconf-nb-bierman02/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/BrokerFacadeTest.java
@@ -0,0 +1,432 @@
+/*
+ * Copyright (c) 2014, 2015 Brocade Communications Systems, Inc. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.controller.sal.restconf.impl.test;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertSame;
+import static org.junit.Assert.assertThrows;
+import static org.junit.Assert.assertTrue;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.inOrder;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.verifyNoMoreInteractions;
+import static org.mockito.Mockito.when;
+import static org.opendaylight.yangtools.util.concurrent.FluentFutures.immediateBooleanFluentFuture;
+import static org.opendaylight.yangtools.util.concurrent.FluentFutures.immediateFailedFluentFuture;
+import static org.opendaylight.yangtools.util.concurrent.FluentFutures.immediateFluentFuture;
+import static org.opendaylight.yangtools.util.concurrent.FluentFutures.immediateTrueFluentFuture;
+
+import com.google.common.collect.ImmutableClassToInstanceMap;
+import com.google.common.util.concurrent.FluentFuture;
+import com.google.common.util.concurrent.ListenableFuture;
+import java.util.List;
+import java.util.Optional;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.InOrder;
+import org.mockito.Mock;
+import org.mockito.Mockito;
+import org.mockito.junit.MockitoJUnitRunner;
+import org.opendaylight.controller.md.sal.rest.common.TestRestconfUtils;
+import org.opendaylight.mdsal.common.api.CommitInfo;
+import org.opendaylight.mdsal.common.api.LogicalDatastoreType;
+import org.opendaylight.mdsal.common.api.ReadFailedException;
+import org.opendaylight.mdsal.dom.api.DOMDataBroker;
+import org.opendaylight.mdsal.dom.api.DOMDataTreeChangeService;
+import org.opendaylight.mdsal.dom.api.DOMDataTreeIdentifier;
+import org.opendaylight.mdsal.dom.api.DOMDataTreeReadTransaction;
+import org.opendaylight.mdsal.dom.api.DOMDataTreeReadWriteTransaction;
+import org.opendaylight.mdsal.dom.api.DOMDataTreeWriteTransaction;
+import org.opendaylight.mdsal.dom.api.DOMMountPoint;
+import org.opendaylight.mdsal.dom.api.DOMNotificationService;
+import org.opendaylight.mdsal.dom.api.DOMRpcResult;
+import org.opendaylight.mdsal.dom.api.DOMRpcService;
+import org.opendaylight.mdsal.dom.api.DOMSchemaService;
+import org.opendaylight.mdsal.dom.api.DOMTransactionChain;
+import org.opendaylight.netconf.sal.restconf.impl.BrokerFacade;
+import org.opendaylight.netconf.sal.restconf.impl.ControllerContext;
+import org.opendaylight.netconf.sal.restconf.impl.PutResult;
+import org.opendaylight.netconf.sal.streams.listeners.ListenerAdapter;
+import org.opendaylight.netconf.sal.streams.listeners.NotificationListenerAdapter;
+import org.opendaylight.netconf.sal.streams.listeners.Notificator;
+import org.opendaylight.restconf.common.ErrorTags;
+import org.opendaylight.restconf.common.context.InstanceIdentifierContext;
+import org.opendaylight.restconf.common.errors.RestconfDocumentedException;
+import org.opendaylight.restconf.common.errors.RestconfError;
+import org.opendaylight.restconf.common.patch.PatchContext;
+import org.opendaylight.restconf.common.patch.PatchStatusContext;
+import org.opendaylight.yang.gen.v1.urn.sal.restconf.event.subscription.rev140708.CreateDataChangeEventSubscriptionInput1.Scope;
+import org.opendaylight.yang.gen.v1.urn.sal.restconf.event.subscription.rev140708.NotificationOutputTypeGrouping.NotificationOutputType;
+import org.opendaylight.yangtools.concepts.ListenerRegistration;
+import org.opendaylight.yangtools.yang.common.ErrorTag;
+import org.opendaylight.yangtools.yang.common.ErrorType;
+import org.opendaylight.yangtools.yang.common.QName;
+import org.opendaylight.yangtools.yang.common.RpcError;
+import org.opendaylight.yangtools.yang.common.RpcResultBuilder;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifier;
+import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
+import org.opendaylight.yangtools.yang.data.impl.schema.Builders;
+import org.opendaylight.yangtools.yang.model.api.DataSchemaNode;
+import org.opendaylight.yangtools.yang.model.api.EffectiveModelContext;
+import org.opendaylight.yangtools.yang.model.api.stmt.SchemaNodeIdentifier.Absolute;
+import org.opendaylight.yangtools.yang.model.util.SchemaInferenceStack;
+
+/**
+ * Unit tests for BrokerFacade.
+ *
+ * @author Thomas Pantelis
+ */
+@RunWith(MockitoJUnitRunner.StrictStubs.class)
+public class BrokerFacadeTest {
+
+ @Mock
+ private DOMDataBroker domDataBroker;
+ @Mock
+ private DOMNotificationService domNotification;
+ @Mock
+ private DOMRpcService mockRpcService;
+ @Mock
+ private DOMMountPoint mockMountInstance;
+ @Mock
+ private DOMDataTreeReadTransaction readTransaction;
+ @Mock
+ private DOMDataTreeWriteTransaction writeTransaction;
+ @Mock
+ private DOMDataTreeReadWriteTransaction rwTransaction;
+
+ private BrokerFacade brokerFacade;
+ private final NormalizedNode dummyNode = createDummyNode("test:module", "2014-01-09", "interfaces");
+ private final FluentFuture<Optional<NormalizedNode>> dummyNodeInFuture = wrapDummyNode(dummyNode);
+ private final QName qname = TestUtils.buildQName("interfaces","test:module", "2014-01-09");
+ private final YangInstanceIdentifier instanceID = YangInstanceIdentifier.builder().node(qname).build();
+ private ControllerContext controllerContext;
+
+ @Before
+ public void setUp() throws Exception {
+ controllerContext = TestRestconfUtils.newControllerContext(
+ TestUtils.loadSchemaContext("/full-versions/test-module", "/modules"));
+
+ brokerFacade = BrokerFacade.newInstance(mockRpcService, domDataBroker, domNotification, controllerContext);
+
+ when(domDataBroker.newReadOnlyTransaction()).thenReturn(readTransaction);
+ when(domDataBroker.newReadWriteTransaction()).thenReturn(rwTransaction);
+ when(domDataBroker.getExtensions()).thenReturn(ImmutableClassToInstanceMap.of(
+ DOMDataTreeChangeService.class, Mockito.mock(DOMDataTreeChangeService.class)));
+ }
+
+ private static FluentFuture<Optional<NormalizedNode>> wrapDummyNode(final NormalizedNode dummyNode) {
+ return immediateFluentFuture(Optional.of(dummyNode));
+ }
+
+ private static FluentFuture<Boolean> wrapExistence(final boolean exists) {
+ return immediateBooleanFluentFuture(exists);
+ }
+
+ /**
+ * Value of this node shouldn't be important for testing purposes.
+ */
+ private static NormalizedNode createDummyNode(final String namespace, final String date, final String localName) {
+ return Builders.containerBuilder()
+ .withNodeIdentifier(new NodeIdentifier(QName.create(namespace, date, localName)))
+ .build();
+ }
+
+ @Test
+ public void testReadConfigurationData() {
+ when(readTransaction.read(any(LogicalDatastoreType.class), any(YangInstanceIdentifier.class))).thenReturn(
+ dummyNodeInFuture);
+
+ final NormalizedNode actualNode = brokerFacade.readConfigurationData(instanceID);
+
+ assertSame("readConfigurationData", dummyNode, actualNode);
+ }
+
+ @Test
+ public void testReadOperationalData() {
+ when(readTransaction.read(any(LogicalDatastoreType.class), any(YangInstanceIdentifier.class))).thenReturn(
+ dummyNodeInFuture);
+
+ final NormalizedNode actualNode = brokerFacade.readOperationalData(instanceID);
+
+ assertSame("readOperationalData", dummyNode, actualNode);
+ }
+
+ @Test
+ public void test503() throws Exception {
+ final RpcError error = RpcResultBuilder.newError(ErrorType.TRANSPORT, ErrorTag.RESOURCE_DENIED,
+ "Master is down. Please try again.");
+ doReturn(immediateFailedFluentFuture(new ReadFailedException("Read from transaction failed", error)))
+ .when(readTransaction).read(any(LogicalDatastoreType.class), any(YangInstanceIdentifier.class));
+
+ final RestconfDocumentedException ex = assertThrows(RestconfDocumentedException.class,
+ () -> brokerFacade.readConfigurationData(instanceID, "explicit"));
+ final List<RestconfError> errors = ex.getErrors();
+ assertEquals(1, errors.size());
+ assertEquals("getErrorTag", ErrorTags.RESOURCE_DENIED_TRANSPORT, errors.get(0).getErrorTag());
+ assertEquals("getErrorType", ErrorType.TRANSPORT,errors.get(0).getErrorType());
+ assertEquals("getErrorMessage", "Master is down. Please try again.", errors.get(0).getErrorMessage());
+ }
+
+ @Test
+ public void testInvokeRpc() throws Exception {
+ final DOMRpcResult expResult = mock(DOMRpcResult.class);
+ doReturn(immediateFluentFuture(expResult)).when(mockRpcService).invokeRpc(qname, dummyNode);
+
+ final ListenableFuture<? extends DOMRpcResult> actualFuture = brokerFacade.invokeRpc(qname,
+ dummyNode);
+ assertNotNull("Future is null", actualFuture);
+ final DOMRpcResult actualResult = actualFuture.get();
+ assertSame("invokeRpc", expResult, actualResult);
+ }
+
+ @Test
+ public void testCommitConfigurationDataPut() throws Exception {
+ doReturn(CommitInfo.emptyFluentFuture()).when(rwTransaction).commit();
+
+ doReturn(immediateFluentFuture(Optional.of(mock(NormalizedNode.class)))).when(rwTransaction)
+ .read(LogicalDatastoreType.CONFIGURATION, instanceID);
+
+ final PutResult result = brokerFacade.commitConfigurationDataPut(mock(EffectiveModelContext.class),
+ instanceID, dummyNode, null, null);
+
+ assertSame("commitConfigurationDataPut", CommitInfo.emptyFluentFuture(), result.getFutureOfPutData());
+
+ final InOrder inOrder = inOrder(domDataBroker, rwTransaction);
+ inOrder.verify(domDataBroker).newReadWriteTransaction();
+ inOrder.verify(rwTransaction).put(LogicalDatastoreType.CONFIGURATION, instanceID, dummyNode);
+ inOrder.verify(rwTransaction).commit();
+ }
+
+ @Test
+ public void testCommitConfigurationDataPost() {
+ when(rwTransaction.exists(LogicalDatastoreType.CONFIGURATION, instanceID))
+ .thenReturn(wrapExistence(false));
+
+ doReturn(CommitInfo.emptyFluentFuture()).when(rwTransaction).commit();
+
+ final FluentFuture<? extends CommitInfo> actualFuture = brokerFacade
+ .commitConfigurationDataPost(mock(EffectiveModelContext.class), instanceID, dummyNode, null,
+ null);
+
+ assertSame("commitConfigurationDataPost", CommitInfo.emptyFluentFuture(), actualFuture);
+
+ final InOrder inOrder = inOrder(domDataBroker, rwTransaction);
+ inOrder.verify(domDataBroker).newReadWriteTransaction();
+ inOrder.verify(rwTransaction).exists(LogicalDatastoreType.CONFIGURATION, instanceID);
+ inOrder.verify(rwTransaction).put(LogicalDatastoreType.CONFIGURATION, instanceID, dummyNode);
+ inOrder.verify(rwTransaction).commit();
+ }
+
+ @Test(expected = RestconfDocumentedException.class)
+ public void testCommitConfigurationDataPostAlreadyExists() {
+ when(rwTransaction.exists(eq(LogicalDatastoreType.CONFIGURATION), any(YangInstanceIdentifier.class)))
+ .thenReturn(immediateTrueFluentFuture());
+ try {
+ // Schema context is only necessary for ensuring parent structure
+ brokerFacade.commitConfigurationDataPost((EffectiveModelContext) null, instanceID, dummyNode,
+ null, null);
+ } catch (final RestconfDocumentedException e) {
+ assertEquals("getErrorTag", ErrorTag.DATA_EXISTS, e.getErrors().get(0).getErrorTag());
+ throw e;
+ }
+ }
+
+ /**
+ * Positive test of delete operation when data to delete exits. Returned value and order of steps are validated.
+ */
+ @Test
+ public void testCommitConfigurationDataDelete() throws Exception {
+ // assume that data to delete exists
+ prepareDataForDelete(true);
+
+ // expected result
+ doReturn(CommitInfo.emptyFluentFuture()).when(rwTransaction).commit();
+
+ // test
+ final FluentFuture<? extends CommitInfo> actualFuture = brokerFacade
+ .commitConfigurationDataDelete(instanceID);
+
+ // verify result and interactions
+ assertSame("commitConfigurationDataDelete", CommitInfo.emptyFluentFuture(), actualFuture);
+
+ // check exists, delete, submit
+ final InOrder inOrder = inOrder(domDataBroker, rwTransaction);
+ inOrder.verify(rwTransaction).exists(LogicalDatastoreType.CONFIGURATION, instanceID);
+ inOrder.verify(rwTransaction).delete(LogicalDatastoreType.CONFIGURATION, instanceID);
+ inOrder.verify(rwTransaction).commit();
+ }
+
+ /**
+ * Negative test of delete operation when data to delete does not exist. Error DATA_MISSING should be returned.
+ */
+ @Test
+ public void testCommitConfigurationDataDeleteNoData() throws Exception {
+ // assume that data to delete does not exist
+ prepareDataForDelete(false);
+
+ // try to delete and expect DATA_MISSING error
+ final RestconfDocumentedException ex = assertThrows(RestconfDocumentedException.class,
+ () -> brokerFacade.commitConfigurationDataDelete(instanceID));
+ final List<RestconfError> errors = ex.getErrors();
+ assertEquals(1, errors.size());
+ assertEquals(ErrorType.PROTOCOL, errors.get(0).getErrorType());
+ assertEquals(ErrorTag.DATA_MISSING, errors.get(0).getErrorTag());
+ }
+
+ /**
+ * Prepare conditions to test delete operation. Data to delete exists or does not exist according to value of
+ * {@code assumeDataExists} parameter.
+ * @param assumeDataExists boolean to assume if data exists
+ */
+ private void prepareDataForDelete(final boolean assumeDataExists) {
+ when(rwTransaction.exists(LogicalDatastoreType.CONFIGURATION, instanceID))
+ .thenReturn(immediateBooleanFluentFuture(assumeDataExists));
+ }
+
+ @Test
+ public void testRegisterToListenDataChanges() {
+ final ListenerAdapter listener = Notificator.createListener(instanceID, "stream",
+ NotificationOutputType.XML, controllerContext);
+
+ @SuppressWarnings("unchecked")
+ final ListenerRegistration<ListenerAdapter> mockRegistration = mock(ListenerRegistration.class);
+
+ DOMDataTreeChangeService changeService = domDataBroker.getExtensions()
+ .getInstance(DOMDataTreeChangeService.class);
+ DOMDataTreeIdentifier loc = new DOMDataTreeIdentifier(LogicalDatastoreType.CONFIGURATION, instanceID);
+ when(changeService.registerDataTreeChangeListener(eq(loc), eq(listener))).thenReturn(mockRegistration);
+
+ brokerFacade.registerToListenDataChanges(LogicalDatastoreType.CONFIGURATION, Scope.BASE, listener);
+
+ verify(changeService).registerDataTreeChangeListener(loc, listener);
+
+ assertEquals("isListening", true, listener.isListening());
+
+ brokerFacade.registerToListenDataChanges(LogicalDatastoreType.CONFIGURATION, Scope.BASE, listener);
+ verifyNoMoreInteractions(changeService);
+ }
+
+ /**
+ * Create, register, close and remove notification listener.
+ */
+ @Test
+ public void testRegisterToListenNotificationChanges() throws Exception {
+ // create test notification listener
+ final String identifier = "create-notification-stream/toaster:toastDone";
+ Notificator.createNotificationListener(
+ List.of(Absolute.of(QName.create("http://netconfcentral.org/ns/toaster", "2009-11-20", "toastDone"))),
+ identifier, "XML", controllerContext);
+ final NotificationListenerAdapter listener = Notificator.getNotificationListenerFor(identifier).get(0);
+
+ // mock registration
+ final ListenerRegistration<NotificationListenerAdapter> registration = mock(ListenerRegistration.class);
+ when(domNotification.registerNotificationListener(listener, listener.getSchemaPath()))
+ .thenReturn(registration);
+
+ // test to register listener for the first time
+ brokerFacade.registerToListenNotification(listener);
+ assertEquals("Registration was not successful", true, listener.isListening());
+
+ // try to register for the second time
+ brokerFacade.registerToListenNotification(listener);
+ assertEquals("Registration was not successful", true, listener.isListening());
+
+ // registrations should be invoked only once
+ verify(domNotification, times(1)).registerNotificationListener(listener, listener.getSchemaPath());
+
+ final DOMTransactionChain transactionChain = mock(DOMTransactionChain.class);
+ final DOMDataTreeWriteTransaction wTx = mock(DOMDataTreeWriteTransaction.class);
+ // close and remove test notification listener
+ listener.close();
+ Notificator.removeListenerIfNoSubscriberExists(listener);
+ }
+
+ /**
+ * Test Patch method on the server with no data.
+ */
+ @Test
+ public void testPatchConfigurationDataWithinTransactionServer() throws Exception {
+ final PatchContext patchContext = mock(PatchContext.class);
+
+ when(patchContext.getData()).thenReturn(List.of());
+ // no mount point
+ doReturn(InstanceIdentifierContext.ofPath(SchemaInferenceStack.of(mock(EffectiveModelContext.class)),
+ mock(DataSchemaNode.class), YangInstanceIdentifier.empty(), null))
+ .when(patchContext).getInstanceIdentifierContext();
+
+ doReturn(CommitInfo.emptyFluentFuture()).when(rwTransaction).commit();
+
+ final PatchStatusContext status = brokerFacade.patchConfigurationDataWithinTransaction(patchContext);
+
+ // assert success
+ assertTrue("Patch operation should be successful on server", status.isOk());
+ }
+
+ /**
+ * Test Patch method on mounted device with no data.
+ */
+ @Test
+ public void testPatchConfigurationDataWithinTransactionMount() throws Exception {
+ final PatchContext patchContext = mock(PatchContext.class);
+ final DOMMountPoint mountPoint = mock(DOMMountPoint.class);
+ final DOMDataBroker mountDataBroker = mock(DOMDataBroker.class);
+ final DOMDataTreeReadWriteTransaction transaction = mock(DOMDataTreeReadWriteTransaction.class);
+
+ when(patchContext.getData()).thenReturn(List.of());
+ // return mount point with broker
+ doReturn(InstanceIdentifierContext.ofPath(SchemaInferenceStack.of(mock(EffectiveModelContext.class)),
+ mock(DataSchemaNode.class), YangInstanceIdentifier.empty(), mountPoint))
+ .when(patchContext).getInstanceIdentifierContext();
+
+ when(mountPoint.getService(DOMDataBroker.class)).thenReturn(Optional.of(mountDataBroker));
+ when(mountPoint.getService(DOMSchemaService.class)).thenReturn(Optional.empty());
+ when(mountDataBroker.newReadWriteTransaction()).thenReturn(transaction);
+ doReturn(CommitInfo.emptyFluentFuture()).when(transaction).commit();
+
+ final PatchStatusContext status = brokerFacade.patchConfigurationDataWithinTransaction(patchContext);
+
+ // assert success
+ assertTrue("Patch operation should be successful on mounted device", status.isOk());
+ }
+
+ /**
+ * Negative test for Patch operation when mounted device does not support {@link DOMDataBroker service.}
+ * Patch operation should fail with global error.
+ */
+ @Test
+ public void testPatchConfigurationDataWithinTransactionMountFail() throws Exception {
+ final PatchContext patchContext = mock(PatchContext.class);
+ final DOMMountPoint mountPoint = mock(DOMMountPoint.class);
+
+ doReturn(InstanceIdentifierContext.ofPath(SchemaInferenceStack.of(mock(EffectiveModelContext.class)),
+ mock(DataSchemaNode.class), YangInstanceIdentifier.empty(), mountPoint))
+ .when(patchContext).getInstanceIdentifierContext();
+
+ // missing broker on mounted device
+ when(mountPoint.getService(DOMDataBroker.class)).thenReturn(Optional.empty());
+ when(mountPoint.getService(DOMSchemaService.class)).thenReturn(Optional.empty());
+
+ final PatchStatusContext status = brokerFacade.patchConfigurationDataWithinTransaction(patchContext);
+
+ // assert not successful operation with error
+ assertNotNull(status.getGlobalErrors());
+ assertEquals(1, status.getGlobalErrors().size());
+ assertEquals(ErrorType.APPLICATION, status.getGlobalErrors().get(0).getErrorType());
+ assertEquals(ErrorTag.OPERATION_FAILED, status.getGlobalErrors().get(0).getErrorTag());
+
+ assertFalse("Patch operation should fail on mounted device without Broker", status.isOk());
+ }
+}
diff --git a/netconf/restconf/restconf-nb-bierman02/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/Bug3595Test.java b/netconf/restconf/restconf-nb-bierman02/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/Bug3595Test.java
new file mode 100644
index 0000000..0d7241d
--- /dev/null
+++ b/netconf/restconf/restconf-nb-bierman02/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/Bug3595Test.java
@@ -0,0 +1,53 @@
+/*
+ * Copyright (c) 2015 Cisco Systems, Inc. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.controller.sal.restconf.impl.test;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+
+import java.io.FileNotFoundException;
+import org.junit.BeforeClass;
+import org.junit.Test;
+import org.opendaylight.controller.md.sal.rest.common.TestRestconfUtils;
+import org.opendaylight.netconf.sal.restconf.impl.ControllerContext;
+import org.opendaylight.restconf.common.context.InstanceIdentifierContext;
+import org.opendaylight.yangtools.yang.common.QName;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifierWithPredicates;
+import org.opendaylight.yangtools.yang.model.api.EffectiveModelContext;
+import org.opendaylight.yangtools.yang.model.api.Module;
+
+public class Bug3595Test {
+
+ private static final QName CONT_QNAME = QName.create("leafref:module", "2014-04-17", "cont");
+ private static final QName LST_WITH_LFREF_KEY_QNAME = QName.create(CONT_QNAME, "lst-with-lfref-key");
+ private static final QName LFREF_KEY_QNAME = QName.create(CONT_QNAME, "lfref-key");
+ private static EffectiveModelContext schemaContext;
+
+ private final ControllerContext controllerContext = TestRestconfUtils.newControllerContext(schemaContext);
+
+ @BeforeClass
+ public static void initialize() throws FileNotFoundException {
+ schemaContext = TestUtils.loadSchemaContext("/leafref/yang");
+ Module module = TestUtils.findModule(schemaContext.getModules(), "leafref-module");
+ assertNotNull(module);
+ module = TestUtils.findModule(schemaContext.getModules(), "referenced-module");
+ assertNotNull(module);
+ }
+
+ @Test
+ public void testLeafrefListKeyDeserializtion() {
+ final YangInstanceIdentifier node1IIexpected = YangInstanceIdentifier.of(CONT_QNAME)
+ .node(LST_WITH_LFREF_KEY_QNAME).node(NodeIdentifierWithPredicates.of(
+ LST_WITH_LFREF_KEY_QNAME, LFREF_KEY_QNAME, "node1"));
+ final InstanceIdentifierContext iiContext =
+ controllerContext.toInstanceIdentifier("leafref-module:cont/lst-with-lfref-key/node1");
+ iiContext.getInstanceIdentifier();
+ assertEquals(node1IIexpected, iiContext.getInstanceIdentifier());
+ }
+}
diff --git a/netconf/restconf/restconf-nb-bierman02/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/Bug8072Test.java b/netconf/restconf/restconf-nb-bierman02/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/Bug8072Test.java
new file mode 100644
index 0000000..a65babd
--- /dev/null
+++ b/netconf/restconf/restconf-nb-bierman02/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/Bug8072Test.java
@@ -0,0 +1,71 @@
+/*
+ * Copyright (c) 2017 Cisco Systems, Inc. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.controller.sal.restconf.impl.test;
+
+import static org.junit.Assert.assertEquals;
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.mock;
+
+import java.io.FileNotFoundException;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Optional;
+import org.junit.BeforeClass;
+import org.junit.Test;
+import org.opendaylight.controller.md.sal.rest.common.TestRestconfUtils;
+import org.opendaylight.mdsal.dom.api.DOMMountPoint;
+import org.opendaylight.mdsal.dom.api.DOMSchemaService;
+import org.opendaylight.mdsal.dom.spi.FixedDOMSchemaService;
+import org.opendaylight.netconf.sal.restconf.impl.ControllerContext;
+import org.opendaylight.restconf.common.context.InstanceIdentifierContext;
+import org.opendaylight.yangtools.yang.common.QName;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifierWithPredicates;
+import org.opendaylight.yangtools.yang.model.api.EffectiveModelContext;
+import org.opendaylight.yangtools.yang.parser.spi.meta.ReactorException;
+
+public class Bug8072Test {
+ private static final String EXTERNAL_MODULE_NAME = "test-module";
+ private static final QName MODULES_QNAME = QName.create("test:module", "2014-01-09", "modules");
+ private static final QName MODULE_QNAME = QName.create("test:module", "2014-01-09", "module");
+ private static final QName NAME_QNAME = QName.create("test:module", "2014-01-09", "name");
+ private static final QName TYPE_QNAME = QName.create("test:module", "2014-01-09", "type");
+ private static final QName MODULE_TYPE_QNAME = QName.create("test:module", "2014-01-09", "module-type");
+
+ private static EffectiveModelContext schemaContext;
+
+ private final ControllerContext controllerContext;
+
+ public Bug8072Test() throws FileNotFoundException {
+ final EffectiveModelContext mountPointContext = TestUtils.loadSchemaContext("/full-versions/test-module");
+ final DOMMountPoint mountInstance = mock(DOMMountPoint.class);
+ controllerContext = TestRestconfUtils.newControllerContext(schemaContext, mountInstance);
+ doReturn(Optional.of(FixedDOMSchemaService.of(() -> mountPointContext))).when(mountInstance)
+ .getService(DOMSchemaService.class);
+ }
+
+ @BeforeClass
+ public static void init() throws FileNotFoundException, ReactorException {
+ schemaContext = TestUtils.loadSchemaContext("/full-versions/yangs");
+ assertEquals(0, schemaContext.findModules(EXTERNAL_MODULE_NAME).size());
+ }
+
+ @Test
+ public void testIdentityRefFromExternalModule() throws FileNotFoundException, ReactorException {
+ final InstanceIdentifierContext ctx = controllerContext.toInstanceIdentifier(
+ "simple-nodes:users/yang-ext:mount/test-module:modules/module/test-module:module-type/name");
+
+ final Map<QName, Object> keyValues = new HashMap<>();
+ keyValues.put(NAME_QNAME, "name");
+ keyValues.put(TYPE_QNAME, MODULE_TYPE_QNAME);
+ final YangInstanceIdentifier expectedYII = YangInstanceIdentifier.of(MODULES_QNAME).node(MODULE_QNAME)
+ .node(NodeIdentifierWithPredicates.of(MODULE_QNAME, keyValues));
+
+ assertEquals(expectedYII, ctx.getInstanceIdentifier());
+ }
+}
diff --git a/netconf/restconf/restconf-nb-bierman02/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/CnSnToXmlAndJsonInstanceIdentifierTest.java b/netconf/restconf/restconf-nb-bierman02/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/CnSnToXmlAndJsonInstanceIdentifierTest.java
new file mode 100644
index 0000000..96100cb
--- /dev/null
+++ b/netconf/restconf/restconf-nb-bierman02/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/CnSnToXmlAndJsonInstanceIdentifierTest.java
@@ -0,0 +1,150 @@
+/*
+ * Copyright (c) 2014 Cisco Systems, Inc. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.controller.sal.restconf.impl.test;
+
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+
+import java.io.ByteArrayInputStream;
+import java.io.FileNotFoundException;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import javax.xml.stream.XMLEventReader;
+import javax.xml.stream.XMLInputFactory;
+import javax.xml.stream.XMLStreamException;
+import javax.xml.stream.events.StartElement;
+import javax.xml.stream.events.XMLEvent;
+import org.junit.BeforeClass;
+import org.opendaylight.yangtools.yang.common.QName;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifier;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifierWithPredicates;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeWithValue;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.PathArgument;
+import org.opendaylight.yangtools.yang.parser.spi.meta.ReactorException;
+
+public class CnSnToXmlAndJsonInstanceIdentifierTest extends YangAndXmlAndDataSchemaLoader {
+
+ @BeforeClass
+ public static void initialize() throws FileNotFoundException, ReactorException {
+ dataLoad("/instanceidentifier/yang", 4, "instance-identifier-module", "cont");
+ }
+
+
+ private static void validateXmlOutput(final String xml) throws XMLStreamException {
+ final XMLInputFactory xmlInFactory = XMLInputFactory.newInstance();
+ XMLEventReader eventReader;
+
+ eventReader = xmlInFactory.createXMLEventReader(new ByteArrayInputStream(xml.getBytes()));
+ String augmentAugmentModulePrefix = null;
+ String augmentModulePrefix = null;
+ String instanceIdentifierModulePrefix = null;
+ while (eventReader.hasNext()) {
+ final XMLEvent nextEvent = eventReader.nextEvent();
+ if (nextEvent.isStartElement()) {
+ final StartElement startElement = (StartElement) nextEvent;
+ if (startElement.getName().getLocalPart().equals("lf111")) {
+ final Iterator<?> prefixes =
+ startElement.getNamespaceContext().getPrefixes("augment:augment:module");
+
+ while (prefixes.hasNext() && augmentAugmentModulePrefix == null) {
+ final String prefix = (String) prefixes.next();
+ if (!prefix.isEmpty()) {
+ augmentAugmentModulePrefix = prefix;
+ }
+ }
+
+ augmentModulePrefix = startElement.getNamespaceContext().getPrefix("augment:module");
+ instanceIdentifierModulePrefix =
+ startElement.getNamespaceContext().getPrefix("instance:identifier:module");
+ break;
+ }
+ }
+ }
+
+ assertNotNull(augmentAugmentModulePrefix);
+ assertNotNull(augmentModulePrefix);
+ assertNotNull(instanceIdentifierModulePrefix);
+
+ final String instanceIdentifierValue = "/" + instanceIdentifierModulePrefix + ":cont/"
+ + instanceIdentifierModulePrefix + ":cont1/" + augmentModulePrefix + ":lst11[" + augmentModulePrefix
+ + ":keyvalue111='value1'][" + augmentModulePrefix + ":keyvalue112='value2']/"
+ + augmentAugmentModulePrefix + ":lf112";
+
+ assertTrue(xml.contains(instanceIdentifierValue));
+
+ }
+
+ private static void validateXmlOutputWithLeafList(final String xml) throws XMLStreamException {
+ final XMLInputFactory xmlInFactory = XMLInputFactory.newInstance();
+ XMLEventReader eventReader;
+
+ eventReader = xmlInFactory.createXMLEventReader(new ByteArrayInputStream(xml.getBytes()));
+ String augmentModuleLfLstPrefix = null;
+ String iiModulePrefix = null;
+ while (eventReader.hasNext()) {
+ final XMLEvent nextEvent = eventReader.nextEvent();
+ if (nextEvent.isStartElement()) {
+ final StartElement startElement = (StartElement) nextEvent;
+ if (startElement.getName().getLocalPart().equals("lf111")) {
+ final Iterator<?> prefixes =
+ startElement.getNamespaceContext().getPrefixes("augment:module:leaf:list");
+
+ while (prefixes.hasNext() && augmentModuleLfLstPrefix == null) {
+ final String prefix = (String) prefixes.next();
+ if (!prefix.isEmpty()) {
+ augmentModuleLfLstPrefix = prefix;
+ }
+ }
+ iiModulePrefix = startElement.getNamespaceContext().getPrefix("instance:identifier:module");
+ break;
+ }
+ }
+ }
+
+ assertNotNull(augmentModuleLfLstPrefix);
+ assertNotNull(iiModulePrefix);
+
+ final String instanceIdentifierValue = "/" + iiModulePrefix + ":cont/" + iiModulePrefix + ":cont1/"
+ + augmentModuleLfLstPrefix + ":lflst11[.='lflst11_1']";
+
+ assertTrue(xml.contains(instanceIdentifierValue));
+
+ }
+
+ private static YangInstanceIdentifier createInstanceIdentifier() {
+ final List<PathArgument> pathArguments = new ArrayList<>();
+ pathArguments.add(new NodeIdentifier(QName.create("instance:identifier:module", "cont")));
+ pathArguments.add(new NodeIdentifier(QName.create("instance:identifier:module", "cont1")));
+
+ final QName qName = QName.create("augment:module", "lst11");
+ final Map<QName, Object> keyValues = new HashMap<>();
+ keyValues.put(QName.create("augment:module", "keyvalue111"), "value1");
+ keyValues.put(QName.create("augment:module", "keyvalue112"), "value2");
+ final NodeIdentifierWithPredicates nodeIdentifierWithPredicates =
+ NodeIdentifierWithPredicates.of(qName, keyValues);
+ pathArguments.add(nodeIdentifierWithPredicates);
+
+ pathArguments.add(new NodeIdentifier(QName.create("augment:augment:module", "lf112")));
+
+ return YangInstanceIdentifier.create(pathArguments);
+ }
+
+ private static YangInstanceIdentifier createInstanceIdentifierWithLeafList() {
+ final List<PathArgument> pathArguments = new ArrayList<>();
+ pathArguments.add(new NodeIdentifier(QName.create("instance:identifier:module", "cont")));
+ pathArguments.add(new NodeIdentifier(QName.create("instance:identifier:module", "cont1")));
+ pathArguments.add(new NodeWithValue<>(QName.create("augment:module:leaf:list", "lflst11"), "lflst11_1"));
+
+ return YangInstanceIdentifier.create(pathArguments);
+ }
+
+}
diff --git a/netconf/restconf/restconf-nb-bierman02/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/CodecsExceptionsCatchingTest.java b/netconf/restconf/restconf-nb-bierman02/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/CodecsExceptionsCatchingTest.java
new file mode 100644
index 0000000..2110848
--- /dev/null
+++ b/netconf/restconf/restconf-nb-bierman02/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/CodecsExceptionsCatchingTest.java
@@ -0,0 +1,68 @@
+/*
+ * Copyright (c) 2014, 2015 Brocade Communication Systems, Inc., Cisco Systems, Inc. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+
+package org.opendaylight.controller.sal.restconf.impl.test;
+
+import static org.junit.Assert.assertTrue;
+import static org.mockito.Mockito.mock;
+
+import java.io.FileNotFoundException;
+import javax.ws.rs.client.Entity;
+import javax.ws.rs.core.Application;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.Response;
+import org.glassfish.jersey.server.ResourceConfig;
+import org.glassfish.jersey.test.JerseyTest;
+import org.junit.Before;
+import org.junit.Ignore;
+import org.junit.Test;
+import org.opendaylight.controller.md.sal.rest.common.TestRestconfUtils;
+import org.opendaylight.netconf.sal.rest.impl.JsonNormalizedNodeBodyReader;
+import org.opendaylight.netconf.sal.rest.impl.NormalizedNodeJsonBodyWriter;
+import org.opendaylight.netconf.sal.rest.impl.NormalizedNodeXmlBodyWriter;
+import org.opendaylight.netconf.sal.rest.impl.XmlNormalizedNodeBodyReader;
+import org.opendaylight.netconf.sal.restconf.impl.BrokerFacade;
+import org.opendaylight.netconf.sal.restconf.impl.ControllerContext;
+import org.opendaylight.netconf.sal.restconf.impl.RestconfImpl;
+import org.opendaylight.yangtools.yang.parser.spi.meta.ReactorException;
+
+public class CodecsExceptionsCatchingTest extends JerseyTest {
+
+ private RestconfImpl restConf;
+ private ControllerContext controllerContext;
+
+ @Before
+ public void init() throws FileNotFoundException, ReactorException {
+ restConf = RestconfImpl.newInstance(mock(BrokerFacade.class), controllerContext);
+ controllerContext = TestRestconfUtils.newControllerContext(TestUtils.loadSchemaContext(
+ "/decoding-exception/yang"));
+ }
+
+ @Override
+ protected Application configure() {
+ /* enable/disable Jersey logs to console */
+ // enable(TestProperties.LOG_TRAFFIC);
+ // enable(TestProperties.DUMP_ENTITY);
+ // enable(TestProperties.RECORD_LOG_LEVEL);
+ // set(TestProperties.RECORD_LOG_LEVEL, Level.ALL.intValue());
+ ResourceConfig resourceConfig = new ResourceConfig();
+ resourceConfig = resourceConfig.registerInstances(restConf, new NormalizedNodeJsonBodyWriter(),
+ new NormalizedNodeXmlBodyWriter(), new XmlNormalizedNodeBodyReader(controllerContext),
+ new JsonNormalizedNodeBodyReader(controllerContext));
+ return resourceConfig;
+ }
+
+ @Test
+ @Ignore // TODO RestconfDocumentedExceptionMapper needs be fixed before
+ public void stringToNumberConversionError() {
+ final Response response = target("/config/number:cont").request(MediaType.APPLICATION_XML).put(
+ Entity.entity("<cont xmlns=\"number\"><lf>3f</lf></cont>", MediaType.APPLICATION_XML));
+ final String exceptionMessage = response.readEntity(String.class);
+ assertTrue(exceptionMessage.contains("invalid-value"));
+ }
+}
diff --git a/netconf/restconf/restconf-nb-bierman02/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/CutDataToCorrectDepthTest.java b/netconf/restconf/restconf-nb-bierman02/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/CutDataToCorrectDepthTest.java
new file mode 100644
index 0000000..e379b3a
--- /dev/null
+++ b/netconf/restconf/restconf-nb-bierman02/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/CutDataToCorrectDepthTest.java
@@ -0,0 +1,388 @@
+/*
+ * Copyright (c) 2014 Cisco Systems, Inc. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.controller.sal.restconf.impl.test;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.util.HashMap;
+import java.util.Map;
+import javax.ws.rs.Consumes;
+import javax.ws.rs.Encoded;
+import javax.ws.rs.GET;
+import javax.ws.rs.PUT;
+import javax.ws.rs.Path;
+import javax.ws.rs.PathParam;
+import javax.ws.rs.Produces;
+import javax.ws.rs.WebApplicationException;
+import javax.ws.rs.client.Entity;
+import javax.ws.rs.core.Application;
+import javax.ws.rs.core.Context;
+import javax.ws.rs.core.Response;
+import javax.ws.rs.core.UriInfo;
+import org.glassfish.jersey.server.ResourceConfig;
+import org.glassfish.jersey.test.JerseyTest;
+import org.junit.BeforeClass;
+import org.opendaylight.controller.md.sal.rest.common.TestRestconfUtils;
+import org.opendaylight.netconf.sal.rest.impl.JsonNormalizedNodeBodyReader;
+import org.opendaylight.netconf.sal.rest.impl.NormalizedNodeContext;
+import org.opendaylight.netconf.sal.rest.impl.NormalizedNodeJsonBodyWriter;
+import org.opendaylight.netconf.sal.rest.impl.NormalizedNodeXmlBodyWriter;
+import org.opendaylight.netconf.sal.rest.impl.RestconfDocumentedExceptionMapper;
+import org.opendaylight.netconf.sal.rest.impl.WriterParameters;
+import org.opendaylight.netconf.sal.rest.impl.XmlNormalizedNodeBodyReader;
+import org.opendaylight.netconf.sal.restconf.impl.ControllerContext;
+import org.opendaylight.netconf.sal.restconf.impl.QueryParametersParser;
+import org.opendaylight.restconf.common.context.InstanceIdentifierContext;
+import org.opendaylight.yangtools.yang.common.QName;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifier;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifierWithPredicates;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeWithValue;
+import org.opendaylight.yangtools.yang.data.api.schema.ContainerNode;
+import org.opendaylight.yangtools.yang.data.api.schema.DataContainerChild;
+import org.opendaylight.yangtools.yang.data.api.schema.LeafNode;
+import org.opendaylight.yangtools.yang.data.api.schema.LeafSetNode;
+import org.opendaylight.yangtools.yang.data.api.schema.MapEntryNode;
+import org.opendaylight.yangtools.yang.data.api.schema.MapNode;
+import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
+import org.opendaylight.yangtools.yang.data.api.schema.SystemLeafSetNode;
+import org.opendaylight.yangtools.yang.data.api.schema.SystemMapNode;
+import org.opendaylight.yangtools.yang.data.api.schema.UnkeyedListEntryNode;
+import org.opendaylight.yangtools.yang.data.api.schema.UnkeyedListNode;
+import org.opendaylight.yangtools.yang.data.api.schema.builder.CollectionNodeBuilder;
+import org.opendaylight.yangtools.yang.data.api.schema.builder.DataContainerNodeBuilder;
+import org.opendaylight.yangtools.yang.data.api.schema.builder.ListNodeBuilder;
+import org.opendaylight.yangtools.yang.data.impl.schema.Builders;
+import org.opendaylight.yangtools.yang.model.api.EffectiveModelContext;
+import org.opendaylight.yangtools.yang.model.api.Module;
+import org.opendaylight.yangtools.yang.parser.spi.meta.ReactorException;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class CutDataToCorrectDepthTest extends JerseyTest {
+
+ private static final Logger LOG = LoggerFactory.getLogger(JerseyTest.class);
+
+ private static NormalizedNode depth1Cont;
+ private static NormalizedNode depth2Cont1;
+ private NormalizedNode globalPayload;
+ private static EffectiveModelContext schemaContextModules;
+
+ private final ControllerContext controllerContext =
+ TestRestconfUtils.newControllerContext(schemaContextModules, null);
+
+ @Path("/")
+ public class RestImpl {
+
+ @GET
+ @Path("/config/{identifier:.+}")
+ @Produces({ "application/json", "application/xml" })
+ public NormalizedNodeContext getData(@Encoded @PathParam("identifier") final String identifier,
+ @Context final UriInfo uriInfo) {
+
+ final InstanceIdentifierContext iiWithData = controllerContext.toInstanceIdentifier(identifier);
+
+ NormalizedNode data = null;
+ if (identifier.equals("nested-module:depth1-cont/depth2-cont1")) {
+ data = depth2Cont1;
+ } else if (identifier.equals("nested-module:depth1-cont")) {
+ data = depth1Cont;
+ }
+
+ final WriterParameters writerParameters = QueryParametersParser.parseWriterParameters(uriInfo);
+ return new NormalizedNodeContext(iiWithData, data, writerParameters);
+ }
+
+ @GET
+ @Path("/operational/{identifier:.+}")
+ @Produces({ "application/json", "application/xml" })
+ public NormalizedNodeContext getDataOperational(@Encoded @PathParam("identifier") final String identifier,
+ @Context final UriInfo uriInfo) {
+ return getData(identifier, uriInfo);
+ }
+
+ @PUT
+ @Path("/config/{identifier:.+}")
+ @Consumes({ "application/json", "application/xml" })
+ public void normalizedData(@Encoded @PathParam("identifier") final String identifier,
+ final NormalizedNodeContext payload) throws InterruptedException {
+ LOG.info("Payload: {}.", payload);
+ LOG.info("Instance identifier of payload: {}.",
+ payload.getInstanceIdentifierContext().getInstanceIdentifier());
+ LOG.info("Data of payload: {}.", payload.getData());
+ globalPayload = payload.getData();
+ }
+
+ @PUT
+ @Path("/operational/{identifier:.+}")
+ @Consumes({ "application/json", "application/xml" })
+ public void normalizedDataOperational(@Encoded @PathParam("identifier") final String identifier,
+ final NormalizedNodeContext payload) throws InterruptedException {
+ normalizedData(identifier, payload);
+ }
+ }
+
+ @BeforeClass
+ public static void initialize() throws FileNotFoundException, ReactorException {
+ schemaContextModules = TestUtils.loadSchemaContext("/modules");
+ final Module module = TestUtils.findModule(schemaContextModules.getModules(), "nested-module");
+ assertNotNull(module);
+
+ final UnkeyedListNode listAsUnkeyedList = unkeyedList(
+ "depth2-cont1",
+ unkeyedEntry("depth2-cont1",
+ container("depth3-cont1",
+ container("depth4-cont1", leaf("depth5-leaf1", "depth5-leaf1-value")),
+ leaf("depth4-leaf1", "depth4-leaf1-value")), leaf("depth3-leaf1", "depth3-leaf1-value")));
+
+ final MapNode listAsMap = mapNode(
+ "depth2-list2",
+ mapEntryNode("depth2-list2", 2, leaf("depth3-lf1-key", "depth3-lf1-key-value"),
+ leaf("depth3-lf2-key", "depth3-lf2-key-value"), leaf("depth3-lf3", "depth3-lf3-value")));
+
+ depth1Cont = container(
+ "depth1-cont",
+ listAsUnkeyedList,
+ listAsMap,
+ leafList("depth2-lfLst1", "depth2-lflst1-value1", "depth2-lflst1-value2", "depth2-lflst1-value3"),
+ container(
+ "depth2-cont2",
+ container("depth3-cont2",
+ container("depth4-cont2", leaf("depth5-leaf2", "depth5-leaf2-value")),
+ leaf("depth4-leaf2", "depth4-leaf2-value")), leaf("depth3-leaf2", "depth3-leaf2-value")),
+ leaf("depth2-leaf1", "depth2-leaf1-value"));
+
+ depth2Cont1 = listAsUnkeyedList;
+ }
+
+ // TODO: These tests should be fixed/rewriten because they fail randomly due to data not being de-serialized
+ // properly in readers
+ //@Test
+ public void getDataWithUriDepthParameterTest() throws WebApplicationException, IOException {
+ getDataWithUriDepthParameter("application/json");
+ getDataWithUriDepthParameter("application/xml");
+ }
+
+ public void getDataWithUriDepthParameter(final String mediaType) throws WebApplicationException, IOException {
+ Response response;
+
+ // Test config with depth 1
+ response = target("/config/nested-module:depth1-cont").queryParam("depth", "1").request(mediaType)
+ .get();
+ txtDataToNormalizedNode(response, mediaType, "/config/nested-module:depth1-cont");
+ verifyResponse(nodeDataDepth1());
+
+ // Test config with depth 2
+ response = target("/config/nested-module:depth1-cont").queryParam("depth", "2").request(mediaType)
+ .get();
+ txtDataToNormalizedNode(response, mediaType, "/config/nested-module:depth1-cont");
+ verifyResponse(nodeDataDepth2());
+
+ // Test config with depth 3
+ response = target("/config/nested-module:depth1-cont").queryParam("depth", "3").request(mediaType)
+ .get();
+ txtDataToNormalizedNode(response, mediaType, "/config/nested-module:depth1-cont");
+ verifyResponse(nodeDataDepth3());
+
+ // Test config with depth 4
+ response = target("/config/nested-module:depth1-cont").queryParam("depth", "4").request(mediaType)
+ .get();
+ txtDataToNormalizedNode(response, mediaType, "/config/nested-module:depth1-cont");
+ verifyResponse(nodeDataDepth4());
+
+ // Test config with depth 5
+ response = target("/config/nested-module:depth1-cont").queryParam("depth", "5").request(mediaType)
+ .get();
+ txtDataToNormalizedNode(response, mediaType, "/config/nested-module:depth1-cont");
+ verifyResponse(nodeDataDepth5());
+
+ // Test config with depth unbounded
+
+ response = target("/config/nested-module:depth1-cont").queryParam("depth", "unbounded")
+ .request(mediaType).get();
+ txtDataToNormalizedNode(response, mediaType, "/config/nested-module:depth1-cont");
+ verifyResponse(nodeDataDepth5());
+ }
+
+ private void txtDataToNormalizedNode(final Response response, final String mediaType, final String uri) {
+ final String responseStr = response.readEntity(String.class);
+ LOG.info("Response entity message: {}.", responseStr);
+ target(uri).request(mediaType).put(Entity.entity(responseStr, mediaType));
+ }
+
+ private void verifyResponse(final NormalizedNode nodeData) throws WebApplicationException, IOException {
+ assertNotNull(globalPayload);
+ assertEquals(globalPayload, nodeData);
+ globalPayload = null;
+ }
+
+ @Override
+ protected Application configure() {
+ ResourceConfig resourceConfig = new ResourceConfig();
+ resourceConfig = resourceConfig.registerInstances(new RestImpl());
+ resourceConfig.registerClasses(XmlNormalizedNodeBodyReader.class, NormalizedNodeXmlBodyWriter.class,
+ JsonNormalizedNodeBodyReader.class, NormalizedNodeJsonBodyWriter.class,
+ RestconfDocumentedExceptionMapper.class);
+ return resourceConfig;
+ }
+
+ private static LeafNode<?> leaf(final String localName, final Object value) {
+ return Builders.leafBuilder().withNodeIdentifier(toIdentifier(localName)).withValue(value).build();
+ }
+
+ private static ContainerNode container(final String localName, final DataContainerChild... children) {
+ final DataContainerNodeBuilder<NodeIdentifier, ContainerNode> containerBuilder =
+ Builders.containerBuilder();
+ for (final DataContainerChild child : children) {
+ containerBuilder.withChild(child);
+ }
+ containerBuilder.withNodeIdentifier(toIdentifier(localName));
+ return containerBuilder.build();
+ }
+
+ private static UnkeyedListNode unkeyedList(
+ final String localName,
+ final UnkeyedListEntryNode... entryNodes) {
+ final CollectionNodeBuilder<UnkeyedListEntryNode, UnkeyedListNode> builder = Builders.unkeyedListBuilder();
+ final NodeIdentifier identifier = toIdentifier(localName);
+ builder.withNodeIdentifier(identifier);
+ for (final UnkeyedListEntryNode unkeyedListEntryNode : entryNodes) {
+ builder.withChild(unkeyedListEntryNode);
+ }
+ return builder.build();
+ }
+
+ private static UnkeyedListEntryNode unkeyedEntry(final String localName, final DataContainerChild... children) {
+ final DataContainerNodeBuilder<NodeIdentifier, UnkeyedListEntryNode> builder =
+ Builders.unkeyedListEntryBuilder();
+ builder.withNodeIdentifier(toIdentifier(localName));
+ for (final DataContainerChild child : children) {
+ builder.withChild(child);
+ }
+ return builder.build();
+ }
+
+ private static MapNode mapNode(final String localName, final MapEntryNode... entryNodes) {
+ final CollectionNodeBuilder<MapEntryNode, SystemMapNode> builder = Builders.mapBuilder();
+ builder.withNodeIdentifier(toIdentifier(localName));
+ for (final MapEntryNode mapEntryNode : entryNodes) {
+ builder.withChild(mapEntryNode);
+ }
+ return builder.build();
+ }
+
+ private static MapEntryNode mapEntryNode(final String localName, final int keysNumber,
+ final DataContainerChild... children) {
+ final DataContainerNodeBuilder<NodeIdentifierWithPredicates, MapEntryNode> builder =
+ Builders.mapEntryBuilder();
+ final Map<QName, Object> keys = new HashMap<>();
+ for (int i = 0; i < keysNumber; i++) {
+ keys.put(children[i].getIdentifier().getNodeType(), children[i].body());
+ }
+ builder.withNodeIdentifier(toIdentifier(localName, keys));
+
+ for (final DataContainerChild child : children) {
+ builder.withChild(child);
+ }
+ return builder.build();
+ }
+
+ private static LeafSetNode<?> leafList(final String localName, final String... children) {
+ final ListNodeBuilder<Object, SystemLeafSetNode<Object>> builder = Builders.leafSetBuilder();
+ builder.withNodeIdentifier(toIdentifier(localName));
+ for (final String child : children) {
+ builder.withChild(Builders.leafSetEntryBuilder().withNodeIdentifier(toIdentifier(localName, child))
+ .withValue(child).build());
+ }
+ return builder.build();
+ }
+
+ private static NodeIdentifier toIdentifier(final String localName) {
+ return new NodeIdentifier(QName.create("urn:nested:module", "2014-06-03", localName));
+ }
+
+ private static NodeIdentifierWithPredicates toIdentifier(final String localName, final Map<QName, Object> keys) {
+ return NodeIdentifierWithPredicates.of(QName.create("urn:nested:module", "2014-06-03", localName), keys);
+ }
+
+ private static NodeWithValue<?> toIdentifier(final String localName, final Object value) {
+ return new NodeWithValue<>(QName.create("urn:nested:module", "2014-06-03", localName), value);
+ }
+
+ private static UnkeyedListEntryNode nodeDataDepth3Operational() {
+ return unkeyedEntry("depth2-cont1",
+ container("depth3-cont1", container("depth4-cont1"), leaf("depth4-leaf1", "depth4-leaf1-value")),
+ leaf("depth3-leaf1", "depth3-leaf1-value"));
+ }
+
+ private static ContainerNode nodeDataDepth5() {
+ return container(
+ "depth1-cont",
+ unkeyedList(
+ "depth2-cont1",
+ unkeyedEntry("depth2-cont1",
+ container("depth3-cont1",
+ container("depth4-cont1", leaf("depth5-leaf1", "depth5-leaf1-value")),
+ leaf("depth4-leaf1", "depth4-leaf1-value")),
+ leaf("depth3-leaf1", "depth3-leaf1-value"))),
+ mapNode("depth2-list2",
+ mapEntryNode("depth2-list2", 2, leaf("depth3-lf1-key", "depth3-lf1-key-value"),
+ leaf("depth3-lf2-key", "depth3-lf2-key-value"), leaf("depth3-lf3", "depth3-lf3-value"))),
+ leafList("depth2-lfLst1", "depth2-lflst1-value1", "depth2-lflst1-value2", "depth2-lflst1-value3"),
+ container(
+ "depth2-cont2",
+ container("depth3-cont2",
+ container("depth4-cont2", leaf("depth5-leaf2", "depth5-leaf2-value")),
+ leaf("depth4-leaf2", "depth4-leaf2-value")), leaf("depth3-leaf2", "depth3-leaf2-value")),
+ leaf("depth2-leaf1", "depth2-leaf1-value"));
+ }
+
+ private static ContainerNode nodeDataDepth4() {
+ return container(
+ "depth1-cont",
+ unkeyedList("depth2-cont1", nodeDataDepth3Operational()),
+ mapNode("depth2-list2",
+ mapEntryNode("depth2-list2", 2, leaf("depth3-lf1-key", "depth3-lf1-key-value"),
+ leaf("depth3-lf2-key", "depth3-lf2-key-value"), leaf("depth3-lf3", "depth3-lf3-value"))),
+ leafList("depth2-lfLst1", "depth2-lflst1-value1", "depth2-lflst1-value2", "depth2-lflst1-value3"),
+ container(
+ "depth2-cont2",
+ container("depth3-cont2", container("depth4-cont2"), leaf("depth4-leaf2", "depth4-leaf2-value")),
+ leaf("depth3-leaf2", "depth3-leaf2-value")), leaf("depth2-leaf1", "depth2-leaf1-value"));
+ }
+
+ private static ContainerNode nodeDataDepth3() {
+ return container(
+ "depth1-cont",
+ unkeyedList("depth2-cont1",
+ unkeyedEntry("depth2-cont1", container("depth3-cont1"), leaf("depth3-leaf1", "depth3-leaf1-value"))),
+ mapNode("depth2-list2",
+ mapEntryNode("depth2-list2", 2, leaf("depth3-lf1-key", "depth3-lf1-key-value"),
+ leaf("depth3-lf2-key", "depth3-lf2-key-value"), leaf("depth3-lf3", "depth3-lf3-value"))),
+ leafList("depth2-lfLst1", "depth2-lflst1-value1", "depth2-lflst1-value2", "depth2-lflst1-value3"),
+ container("depth2-cont2", container("depth3-cont2"), leaf("depth3-leaf2", "depth3-leaf2-value")),
+ leaf("depth2-leaf1", "depth2-leaf1-value"));
+ }
+
+ private static ContainerNode nodeDataDepth2() {
+ return container(
+ "depth1-cont",
+ unkeyedList("depth2-cont1", unkeyedEntry("depth2-cont1")),
+ mapNode("depth2-list2",
+ mapEntryNode("depth2-list2", 2, leaf("depth3-lf1-key", "depth3-lf1-key-value"),
+ leaf("depth3-lf2-key", "depth3-lf2-key-value"))), container("depth2-cont2"),
+// leafList("depth2-lfLst1"),
+ leaf("depth2-leaf1", "depth2-leaf1-value"));
+ }
+
+ private static ContainerNode nodeDataDepth1() {
+ return container("depth1-cont");
+ }
+}
diff --git a/netconf/restconf/restconf-nb-bierman02/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/DummyFuture.java b/netconf/restconf/restconf-nb-bierman02/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/DummyFuture.java
new file mode 100644
index 0000000..30a0c50
--- /dev/null
+++ b/netconf/restconf/restconf-nb-bierman02/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/DummyFuture.java
@@ -0,0 +1,94 @@
+/*
+ * Copyright (c) 2014 Cisco Systems, Inc. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.controller.sal.restconf.impl.test;
+
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.Future;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.TimeoutException;
+import org.opendaylight.yangtools.yang.common.RpcResult;
+
+public class DummyFuture<T> implements Future<RpcResult<T>> {
+
+ private final boolean cancel;
+ private final boolean isCancelled;
+ private final boolean isDone;
+ private final RpcResult<T> result;
+
+ public DummyFuture() {
+ cancel = false;
+ isCancelled = false;
+ isDone = false;
+ result = null;
+ }
+
+ private DummyFuture(final Builder<T> builder) {
+ cancel = builder.cancel;
+ isCancelled = builder.isCancelled;
+ isDone = builder.isDone;
+ result = builder.result;
+ }
+
+ @Override
+ public boolean cancel(final boolean mayInterruptIfRunning) {
+ return cancel;
+ }
+
+ @Override
+ public boolean isCancelled() {
+ return isCancelled;
+ }
+
+ @Override
+ public boolean isDone() {
+ return isDone;
+ }
+
+ @Override
+ public RpcResult<T> get() throws InterruptedException, ExecutionException {
+ return result;
+ }
+
+ @Override
+ public RpcResult<T> get(final long timeout, final TimeUnit unit) throws InterruptedException, ExecutionException,
+ TimeoutException {
+ return result;
+ }
+
+ public static class Builder<T> {
+
+ private boolean cancel;
+ private boolean isCancelled;
+ private boolean isDone;
+ private RpcResult<T> result;
+
+ public Builder<T> cancel(final boolean newCancel) {
+ this.cancel = newCancel;
+ return this;
+ }
+
+ public Builder<T> isCancelled(final boolean cancelled) {
+ this.isCancelled = cancelled;
+ return this;
+ }
+
+ public Builder<T> isDone(final boolean done) {
+ this.isDone = done;
+ return this;
+ }
+
+ public Builder<T> rpcResult(final RpcResult<T> newResult) {
+ this.result = newResult;
+ return this;
+ }
+
+ public Future<RpcResult<T>> build() {
+ return new DummyFuture<>(this);
+ }
+ }
+}
diff --git a/netconf/restconf/restconf-nb-bierman02/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/DummyRpcResult.java b/netconf/restconf/restconf-nb-bierman02/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/DummyRpcResult.java
new file mode 100644
index 0000000..ff01937
--- /dev/null
+++ b/netconf/restconf/restconf-nb-bierman02/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/DummyRpcResult.java
@@ -0,0 +1,71 @@
+/*
+ * Copyright (c) 2014 Cisco Systems, Inc. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.controller.sal.restconf.impl.test;
+
+import java.util.List;
+import org.opendaylight.yangtools.yang.common.RpcError;
+import org.opendaylight.yangtools.yang.common.RpcResult;
+
+public class DummyRpcResult<T> implements RpcResult<T> {
+
+ private final boolean isSuccessful;
+ private final T result;
+ private final List<RpcError> errors;
+
+ public DummyRpcResult() {
+ isSuccessful = false;
+ result = null;
+ errors = null;
+ }
+
+ private DummyRpcResult(final Builder<T> builder) {
+ isSuccessful = builder.isSuccessful;
+ result = builder.result;
+ errors = builder.errors;
+ }
+
+ @Override
+ public boolean isSuccessful() {
+ return isSuccessful;
+ }
+
+ @Override
+ public T getResult() {
+ return result;
+ }
+
+ @Override
+ public List<RpcError> getErrors() {
+ return errors;
+ }
+
+ public static class Builder<T> {
+ private boolean isSuccessful;
+ private T result;
+ private List<RpcError> errors;
+
+ public Builder<T> isSuccessful(final boolean successful) {
+ this.isSuccessful = successful;
+ return this;
+ }
+
+ public Builder<T> result(final T newResult) {
+ this.result = newResult;
+ return this;
+ }
+
+ public Builder<T> errors(final List<RpcError> newErrors) {
+ this.errors = newErrors;
+ return this;
+ }
+
+ public RpcResult<T> build() {
+ return new DummyRpcResult<>(this);
+ }
+ }
+}
diff --git a/netconf/restconf/restconf-nb-bierman02/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/DummyType.java b/netconf/restconf/restconf-nb-bierman02/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/DummyType.java
new file mode 100644
index 0000000..af408e6
--- /dev/null
+++ b/netconf/restconf/restconf-nb-bierman02/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/DummyType.java
@@ -0,0 +1,62 @@
+/*
+ * Copyright (c) 2014 Cisco Systems, Inc. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.controller.sal.restconf.impl.test;
+
+import java.util.List;
+import java.util.Optional;
+import org.opendaylight.yangtools.yang.common.QName;
+import org.opendaylight.yangtools.yang.model.api.Status;
+import org.opendaylight.yangtools.yang.model.api.TypeDefinition;
+import org.opendaylight.yangtools.yang.model.api.UnknownSchemaNode;
+
+public class DummyType implements TypeDefinition<DummyType> {
+ QName dummyQName = TestUtils.buildQName("dummy type", "simple:uri", "2012-12-17");
+
+ @Override
+ public QName getQName() {
+ return dummyQName;
+ }
+
+ @Override
+ public Optional<String> getDescription() {
+ return Optional.empty();
+ }
+
+ @Override
+ public Optional<String> getReference() {
+ return Optional.empty();
+ }
+
+ @Override
+ public Status getStatus() {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ @Override
+ public List<UnknownSchemaNode> getUnknownSchemaNodes() {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ @Override
+ public DummyType getBaseType() {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ @Override
+ public Optional<String> getUnits() {
+ return Optional.empty();
+ }
+
+ @Override
+ public Optional<? extends Object> getDefaultValue() {
+ return Optional.empty();
+ }
+}
diff --git a/netconf/restconf/restconf-nb-bierman02/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/ExpressionParserTest.java b/netconf/restconf/restconf-nb-bierman02/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/ExpressionParserTest.java
new file mode 100644
index 0000000..f4ed8f9
--- /dev/null
+++ b/netconf/restconf/restconf-nb-bierman02/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/ExpressionParserTest.java
@@ -0,0 +1,171 @@
+/*
+ * Copyright (c) 2016 Cisco Systems, Inc. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.controller.sal.restconf.impl.test;
+
+import java.io.BufferedReader;
+import java.io.File;
+import java.io.FileReader;
+import java.io.IOException;
+import java.lang.reflect.Method;
+import java.nio.charset.StandardCharsets;
+import java.time.Instant;
+import java.util.Collection;
+import java.util.Optional;
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Test;
+import org.mockito.Mockito;
+import org.opendaylight.controller.md.sal.rest.common.TestRestconfUtils;
+import org.opendaylight.netconf.sal.streams.listeners.ListenerAdapter;
+import org.opendaylight.netconf.sal.streams.listeners.Notificator;
+import org.opendaylight.yang.gen.v1.urn.sal.restconf.event.subscription.rev140708.NotificationOutputTypeGrouping.NotificationOutputType;
+import org.opendaylight.yangtools.yang.common.QName;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifier;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.PathArgument;
+
+public class ExpressionParserTest {
+
+ private Collection<File> xmls;
+
+ @Before
+ public void setup() throws Exception {
+ this.xmls = TestRestconfUtils.loadFiles("/notifications/xml/output/");
+ }
+
+ @Test
+ public void trueDownFilterTest() throws Exception {
+ final boolean parser =
+ parser("notification/data-changed-notification/data-change-event/data/toasterStatus='down'",
+ "data_change_notification_toaster_status_DOWN.xml");
+ Assert.assertTrue(parser);
+ }
+
+ @Test
+ public void falseDownFilterTest() throws Exception {
+ final boolean parser =
+ parser("notification/data-changed-notification/data-change-event/data/toasterStatus='up'",
+ "data_change_notification_toaster_status_DOWN.xml");
+ Assert.assertFalse(parser);
+ }
+
+ @Test
+ public void trueNumberEqualsFilterTest() throws Exception {
+ final boolean parser = parser(
+ "notification/data-changed-notification/data-change-event/data/toasterStatus=1",
+ "data_change_notification_toaster_status_NUMBER.xml");
+ Assert.assertTrue(parser);
+ }
+
+ @Test
+ public void falseNumberEqualsFilterTest() throws Exception {
+ final boolean parser = parser("notification/data-changed-notification/data-change-event/data/toasterStatus=0",
+ "data_change_notification_toaster_status_NUMBER.xml");
+ Assert.assertFalse(parser);
+ }
+
+ @Test
+ public void trueNumberLessFilterTest() throws Exception {
+ final boolean parser = parser("notification/data-changed-notification/data-change-event/data/toasterStatus<2",
+ "data_change_notification_toaster_status_NUMBER.xml");
+ Assert.assertTrue(parser);
+ }
+
+ @Test
+ public void falseNumberLessFilterTest() throws Exception {
+ final boolean parser = parser("notification/data-changed-notification/data-change-event/data/toasterStatus<0",
+ "data_change_notification_toaster_status_NUMBER.xml");
+ Assert.assertFalse(parser);
+ }
+
+ @Test
+ public void trueNumberLessEqualsFilterTest() throws Exception {
+ final boolean parser = parser("notification/data-changed-notification/data-change-event/data/toasterStatus<=2",
+ "data_change_notification_toaster_status_NUMBER.xml");
+ Assert.assertTrue(parser);
+ }
+
+ @Test
+ public void falseNumberLessEqualsFilterTest() throws Exception {
+ final boolean parser = parser("notification/data-changed-notification/data-change-event/data/toasterStatus<=-1",
+ "data_change_notification_toaster_status_NUMBER.xml");
+ Assert.assertFalse(parser);
+ }
+
+ @Test
+ public void trueNumberGreaterFilterTest() throws Exception {
+ final boolean parser = parser("notification/data-changed-notification/data-change-event/data/toasterStatus>0",
+ "data_change_notification_toaster_status_NUMBER.xml");
+ Assert.assertTrue(parser);
+ }
+
+ @Test
+ public void falseNumberGreaterFilterTest() throws Exception {
+ final boolean parser = parser("notification/data-changed-notification/data-change-event/data/toasterStatus>5",
+ "data_change_notification_toaster_status_NUMBER.xml");
+ Assert.assertFalse(parser);
+ }
+
+ @Test
+ public void trueNumberGreaterEqualsFilterTest() throws Exception {
+ final boolean parser = parser("notification/data-changed-notification/data-change-event/data/toasterStatus>=0",
+ "data_change_notification_toaster_status_NUMBER.xml");
+ Assert.assertTrue(parser);
+ }
+
+ @Test
+ public void falseNumberGreaterEqualsFilterTest() throws Exception {
+ final boolean parser = parser("notification/data-changed-notification/data-change-event/data/toasterStatus>=5",
+ "data_change_notification_toaster_status_NUMBER.xml");
+ Assert.assertFalse(parser);
+ }
+
+ private boolean parser(final String filter, final String fileName) throws Exception {
+ File xml = null;
+ for (final File file : this.xmls) {
+ if (file.getName().equals(fileName)) {
+ xml = file;
+ }
+ }
+ final YangInstanceIdentifier path = Mockito.mock(YangInstanceIdentifier.class);
+ final PathArgument pathValue = NodeIdentifier.create(QName.create("module", "2016-12-14", "localName"));
+ Mockito.when(path.getLastPathArgument()).thenReturn(pathValue);
+ final ListenerAdapter listener = Notificator.createListener(path, "streamName", NotificationOutputType.JSON,
+ null);
+ listener.setQueryParams(Instant.now(), Optional.empty(), Optional.ofNullable(filter), false, false);
+
+ // FIXME: do not use reflection here
+ final Class<?> superclass = listener.getClass().getSuperclass().getSuperclass();
+ Method method = null;
+ for (final Method met : superclass.getDeclaredMethods()) {
+ if (met.getName().equals("parseFilterParam")) {
+ method = met;
+ }
+ }
+ if (method == null) {
+ throw new Exception("Methode parseFilterParam doesn't exist in " + superclass.getName());
+ }
+ method.setAccessible(true);
+ return (boolean) method.invoke(listener, readFile(xml));
+ }
+
+ private static String readFile(final File xml) throws IOException {
+ try (BufferedReader br = new BufferedReader(new FileReader(xml, StandardCharsets.UTF_8))) {
+ final StringBuilder sb = new StringBuilder();
+ String line = br.readLine();
+
+ while (line != null) {
+ sb.append(line);
+ sb.append("\n");
+ line = br.readLine();
+ }
+ return sb.toString();
+ }
+ }
+
+}
diff --git a/netconf/restconf/restconf-nb-bierman02/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/InvokeRpcMethodTest.java b/netconf/restconf/restconf-nb-bierman02/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/InvokeRpcMethodTest.java
new file mode 100644
index 0000000..19386a1
--- /dev/null
+++ b/netconf/restconf/restconf-nb-bierman02/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/InvokeRpcMethodTest.java
@@ -0,0 +1,344 @@
+/*
+ * Copyright (c) 2013, 2015 Brocade Communication Systems, Inc., Cisco Systems, Inc. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.controller.sal.restconf.impl.test;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertSame;
+import static org.junit.Assert.assertThrows;
+import static org.junit.Assert.assertTrue;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.doCallRealMethod;
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.mock;
+import static org.opendaylight.yangtools.util.concurrent.FluentFutures.immediateFailedFluentFuture;
+import static org.opendaylight.yangtools.util.concurrent.FluentFutures.immediateFluentFuture;
+
+import java.io.FileNotFoundException;
+import java.util.Collection;
+import java.util.List;
+import java.util.Optional;
+import java.util.Set;
+import javax.ws.rs.WebApplicationException;
+import javax.ws.rs.core.MultivaluedHashMap;
+import javax.ws.rs.core.MultivaluedMap;
+import javax.ws.rs.core.Response;
+import javax.ws.rs.core.UriInfo;
+import org.junit.BeforeClass;
+import org.junit.Ignore;
+import org.junit.Test;
+import org.opendaylight.controller.md.sal.rest.common.TestRestconfUtils;
+import org.opendaylight.mdsal.dom.api.DOMRpcImplementationNotAvailableException;
+import org.opendaylight.mdsal.dom.api.DOMRpcResult;
+import org.opendaylight.mdsal.dom.spi.DefaultDOMRpcResult;
+import org.opendaylight.netconf.sal.rest.impl.NormalizedNodeContext;
+import org.opendaylight.netconf.sal.restconf.impl.BrokerFacade;
+import org.opendaylight.netconf.sal.restconf.impl.ControllerContext;
+import org.opendaylight.netconf.sal.restconf.impl.RestconfImpl;
+import org.opendaylight.restconf.common.ErrorTags;
+import org.opendaylight.restconf.common.context.InstanceIdentifierContext;
+import org.opendaylight.restconf.common.errors.RestconfDocumentedException;
+import org.opendaylight.restconf.common.errors.RestconfError;
+import org.opendaylight.yangtools.yang.common.ErrorTag;
+import org.opendaylight.yangtools.yang.common.ErrorType;
+import org.opendaylight.yangtools.yang.common.QName;
+import org.opendaylight.yangtools.yang.common.RpcError;
+import org.opendaylight.yangtools.yang.common.RpcResultBuilder;
+import org.opendaylight.yangtools.yang.common.XMLNamespace;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifier;
+import org.opendaylight.yangtools.yang.data.api.schema.ContainerNode;
+import org.opendaylight.yangtools.yang.data.api.schema.LeafNode;
+import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
+import org.opendaylight.yangtools.yang.data.api.schema.builder.DataContainerNodeBuilder;
+import org.opendaylight.yangtools.yang.data.api.schema.builder.NormalizedNodeBuilder;
+import org.opendaylight.yangtools.yang.data.impl.schema.SchemaAwareBuilders;
+import org.opendaylight.yangtools.yang.model.api.ContainerLike;
+import org.opendaylight.yangtools.yang.model.api.ContainerSchemaNode;
+import org.opendaylight.yangtools.yang.model.api.DataSchemaNode;
+import org.opendaylight.yangtools.yang.model.api.EffectiveModelContext;
+import org.opendaylight.yangtools.yang.model.api.InputSchemaNode;
+import org.opendaylight.yangtools.yang.model.api.LeafSchemaNode;
+import org.opendaylight.yangtools.yang.model.api.Module;
+import org.opendaylight.yangtools.yang.model.api.RpcDefinition;
+import org.opendaylight.yangtools.yang.model.api.SchemaContext;
+import org.opendaylight.yangtools.yang.parser.spi.meta.ReactorException;
+
+public class InvokeRpcMethodTest {
+
+ private static UriInfo uriInfo;
+ private static EffectiveModelContext schemaContext;
+
+ private final RestconfImpl restconfImpl;
+ private final ControllerContext controllerContext;
+ private final BrokerFacade brokerFacade = mock(BrokerFacade.class);
+
+ public InvokeRpcMethodTest() {
+ controllerContext = TestRestconfUtils.newControllerContext(schemaContext);
+ restconfImpl = RestconfImpl.newInstance(brokerFacade, controllerContext);
+ }
+
+ @BeforeClass
+ public static void init() throws FileNotFoundException, ReactorException {
+ schemaContext = TestUtils.loadSchemaContext("/full-versions/yangs", "/invoke-rpc");
+ final Collection<? extends Module> allModules = schemaContext.getModules();
+ assertNotNull(allModules);
+ final Module module = TestUtils.resolveModule("invoke-rpc-module", allModules);
+ assertNotNull(module);
+
+ uriInfo = mock(UriInfo.class);
+ final MultivaluedMap<String, String> map = new MultivaluedHashMap<>();
+ map.put("prettyPrint", List.of("true"));
+ doReturn(map).when(uriInfo).getQueryParameters(any(Boolean.class));
+ }
+
+ /**
+ * Test method invokeRpc in RestconfImpl class tests if composite node as input parameter of method invokeRpc
+ * (second argument) is wrapped to parent composite node which has QName equals to QName of rpc (resolved from
+ * string - first argument).
+ */
+ @Test
+ public void invokeRpcMethodTest() {
+ controllerContext.findModuleNameByNamespace(XMLNamespace.of("invoke:rpc:module"));
+
+ final NormalizedNodeContext payload = prepareDomPayload();
+
+ final NormalizedNodeContext rpcResponse =
+ restconfImpl.invokeRpc("invoke-rpc-module:rpc-test", payload, uriInfo);
+ assertNotNull(rpcResponse);
+ assertNull(rpcResponse.getData());
+
+ }
+
+ private NormalizedNodeContext prepareDomPayload() {
+ final EffectiveModelContext schema = controllerContext.getGlobalSchema();
+ final Module rpcModule = schema.findModules("invoke-rpc-module").iterator().next();
+ assertNotNull(rpcModule);
+ final QName rpcQName = QName.create(rpcModule.getQNameModule(), "rpc-test");
+ RpcDefinition rpcSchemaNode = null;
+ for (final RpcDefinition rpc : rpcModule.getRpcs()) {
+ if (rpcQName.isEqualWithoutRevision(rpc.getQName())) {
+ rpcSchemaNode = rpc;
+ break;
+ }
+ }
+ assertNotNull(rpcSchemaNode);
+ final InputSchemaNode rpcInputSchemaNode = rpcSchemaNode.getInput();
+ final DataContainerNodeBuilder<NodeIdentifier, ContainerNode> container =
+ SchemaAwareBuilders.containerBuilder(rpcInputSchemaNode);
+
+ final QName contQName = QName.create(rpcModule.getQNameModule(), "cont");
+ final DataSchemaNode contSchemaNode = rpcInputSchemaNode.getDataChildByName(contQName);
+ assertTrue(contSchemaNode instanceof ContainerSchemaNode);
+ final DataContainerNodeBuilder<NodeIdentifier, ContainerNode> contNode =
+ SchemaAwareBuilders.containerBuilder((ContainerSchemaNode) contSchemaNode);
+
+ final QName lfQName = QName.create(rpcModule.getQNameModule(), "lf");
+ final DataSchemaNode lfSchemaNode = ((ContainerSchemaNode) contSchemaNode).getDataChildByName(lfQName);
+ assertTrue(lfSchemaNode instanceof LeafSchemaNode);
+ final LeafNode<Object> lfNode =
+ SchemaAwareBuilders.leafBuilder((LeafSchemaNode) lfSchemaNode).withValue("any value").build();
+ contNode.withChild(lfNode);
+ container.withChild(contNode.build());
+
+ return new NormalizedNodeContext(InstanceIdentifierContext.ofRpcInput(schema, rpcSchemaNode, null),
+ container.build());
+ }
+
+ @Test
+ public void testInvokeRpcWithNoPayloadRpc_FailNoErrors() {
+ final QName qname = QName.create("(http://netconfcentral.org/ns/toaster?revision=2009-11-20)cancel-toast");
+
+ doReturn(immediateFailedFluentFuture(new DOMRpcImplementationNotAvailableException("testExeption")))
+ .when(brokerFacade).invokeRpc(eq(qname), any());
+
+ final RestconfDocumentedException ex = assertThrows(RestconfDocumentedException.class,
+ () -> restconfImpl.invokeRpc("toaster:cancel-toast", null, uriInfo));
+ verifyRestconfDocumentedException(ex, 0, ErrorType.APPLICATION, ErrorTag.OPERATION_NOT_SUPPORTED,
+ Optional.empty(), Optional.empty());
+ }
+
+ void verifyRestconfDocumentedException(final RestconfDocumentedException restDocumentedException, final int index,
+ final ErrorType expErrorType, final ErrorTag expErrorTag, final Optional<String> expErrorMsg,
+ final Optional<String> expAppTag) {
+
+ final List<RestconfError> errors = restDocumentedException.getErrors();
+ assertTrue("RestconfError not found at index " + index, errors.size() > index);
+
+ RestconfError actual = errors.get(index);
+
+ assertEquals("getErrorType", expErrorType, actual.getErrorType());
+ assertEquals("getErrorTag", expErrorTag, actual.getErrorTag());
+ assertNotNull("getErrorMessage is null", actual.getErrorMessage());
+
+ if (expErrorMsg.isPresent()) {
+ assertEquals("getErrorMessage", expErrorMsg.get(), actual.getErrorMessage());
+ }
+
+ if (expAppTag.isPresent()) {
+ assertEquals("getErrorAppTag", expAppTag.get(), actual.getErrorAppTag());
+ }
+ }
+
+ @Test
+ public void testInvokeRpcWithNoPayloadRpc_FailWithRpcError() {
+ final List<RpcError> rpcErrors = List.of(
+ RpcResultBuilder.newError(ErrorType.TRANSPORT, new ErrorTag("bogusTag"), "foo"),
+ RpcResultBuilder.newWarning(ErrorType.RPC, ErrorTag.IN_USE, "bar", "app-tag", null, null));
+
+ final DOMRpcResult result = new DefaultDOMRpcResult(rpcErrors);
+ final QName path = QName.create("(http://netconfcentral.org/ns/toaster?revision=2009-11-20)cancel-toast");
+ doReturn(immediateFluentFuture(result)).when(brokerFacade).invokeRpc(eq(path), any());
+
+ final RestconfDocumentedException ex = assertThrows(RestconfDocumentedException.class,
+ () -> restconfImpl.invokeRpc("toaster:cancel-toast", null, uriInfo));
+
+ // We are performing pass-through here of error-tag, hence the tag remains as specified, but we want to make
+ // sure the HTTP status remains the same as
+ final ErrorTag bogus = new ErrorTag("bogusTag");
+ verifyRestconfDocumentedException(ex, 0, ErrorType.TRANSPORT, bogus, Optional.of("foo"), Optional.empty());
+ assertEquals(ErrorTags.statusOf(ErrorTag.OPERATION_FAILED), ErrorTags.statusOf(bogus));
+
+ verifyRestconfDocumentedException(ex, 1, ErrorType.RPC, ErrorTag.IN_USE, Optional.of("bar"),
+ Optional.of("app-tag"));
+ }
+
+ @Test
+ public void testInvokeRpcWithNoPayload_Success() {
+ final NormalizedNode resultObj = null;
+ final DOMRpcResult expResult = new DefaultDOMRpcResult(resultObj);
+
+ final QName qname = QName.create("(http://netconfcentral.org/ns/toaster?revision=2009-11-20)cancel-toast");
+
+ doReturn(immediateFluentFuture(expResult)).when(brokerFacade).invokeRpc(eq(qname), any());
+
+ final NormalizedNodeContext output = restconfImpl.invokeRpc("toaster:cancel-toast", null, uriInfo);
+ assertNotNull(output);
+ assertEquals(null, output.getData());
+ // additional validation in the fact that the restconfImpl does not
+ // throw an exception.
+ }
+
+ @Test
+ public void testInvokeRpcWithEmptyOutput() {
+ final ContainerNode resultObj = mock(ContainerNode.class);
+ doReturn(Set.of()).when(resultObj).body();
+ doCallRealMethod().when(resultObj).isEmpty();
+ final DOMRpcResult expResult = new DefaultDOMRpcResult(resultObj);
+
+ final QName qname = QName.create("(http://netconfcentral.org/ns/toaster?revision=2009-11-20)cancel-toast");
+ doReturn(immediateFluentFuture(expResult)).when(brokerFacade).invokeRpc(eq(qname), any());
+
+ WebApplicationException exceptionToBeThrown = assertThrows(WebApplicationException.class,
+ () -> restconfImpl.invokeRpc("toaster:cancel-toast", null, uriInfo));
+ assertEquals(Response.Status.NO_CONTENT.getStatusCode(), exceptionToBeThrown.getResponse().getStatus());
+ }
+
+ @Test
+ public void testInvokeRpcMethodWithBadMethodName() {
+ final RestconfDocumentedException ex = assertThrows(RestconfDocumentedException.class,
+ () -> restconfImpl.invokeRpc("toaster:bad-method", null, uriInfo));
+ verifyRestconfDocumentedException(ex, 0, ErrorType.RPC, ErrorTag.UNKNOWN_ELEMENT,
+ Optional.empty(), Optional.empty());
+ }
+
+ @Test
+ @Ignore
+ public void testInvokeRpcMethodWithInput() {
+ final DOMRpcResult expResult = mock(DOMRpcResult.class);
+ final QName path = QName.create("(http://netconfcentral.org/ns/toaster?revision=2009-11-20)make-toast");
+
+ final Module rpcModule = schemaContext.findModules("toaster").iterator().next();
+ assertNotNull(rpcModule);
+ final QName rpcQName = QName.create(rpcModule.getQNameModule(), "make-toast");
+
+ RpcDefinition rpcDef = null;
+ for (final RpcDefinition rpc : rpcModule.getRpcs()) {
+ if (rpcQName.isEqualWithoutRevision(rpc.getQName())) {
+ rpcDef = rpc;
+ break;
+ }
+ }
+
+ assertNotNull(rpcDef);
+
+ final NormalizedNodeContext payload = new NormalizedNodeContext(
+ InstanceIdentifierContext.ofLocalRpcInput(schemaContext, rpcDef),
+ SchemaAwareBuilders.containerBuilder(rpcDef.getInput()).build());
+
+ doReturn(immediateFluentFuture(expResult)).when(brokerFacade).invokeRpc(eq(path), any(NormalizedNode.class));
+
+ final NormalizedNodeContext output = restconfImpl.invokeRpc("toaster:make-toast", payload, uriInfo);
+ assertNotNull(output);
+ assertEquals(null, output.getData());
+ // additional validation in the fact that the restconfImpl does not
+ // throw an exception.
+ }
+
+ @Test
+ public void testThrowExceptionWhenSlashInModuleName() {
+ final RestconfDocumentedException ex = assertThrows(RestconfDocumentedException.class,
+ () -> restconfImpl.invokeRpc("toaster/slash", null, uriInfo));
+ verifyRestconfDocumentedException(ex, 0, ErrorType.PROTOCOL, ErrorTag.INVALID_VALUE,
+ Optional.empty(), Optional.empty());
+ }
+
+ @Test
+ public void testInvokeRpcWithNoPayloadWithOutput_Success() {
+ final SchemaContext schema = controllerContext.getGlobalSchema();
+ final Module rpcModule = schema.findModules("toaster").iterator().next();
+ assertNotNull(rpcModule);
+ final QName rpcQName = QName.create(rpcModule.getQNameModule(), "testOutput");
+ final QName rpcOutputQName = QName.create(rpcModule.getQNameModule(),"output");
+
+ RpcDefinition rpcDef = null;
+ ContainerLike rpcOutputSchemaNode = null;
+ for (final RpcDefinition rpc : rpcModule.getRpcs()) {
+ if (rpcQName.isEqualWithoutRevision(rpc.getQName())) {
+ rpcOutputSchemaNode = rpc.getOutput();
+ rpcDef = rpc;
+ break;
+ }
+ }
+ assertNotNull(rpcDef);
+ assertNotNull(rpcOutputSchemaNode);
+ final DataContainerNodeBuilder<NodeIdentifier, ContainerNode> containerBuilder =
+ SchemaAwareBuilders.containerBuilder(rpcOutputSchemaNode);
+ final DataSchemaNode leafSchema = rpcOutputSchemaNode
+ .getDataChildByName(QName.create(rpcModule.getQNameModule(), "textOut"));
+ assertTrue(leafSchema instanceof LeafSchemaNode);
+ final NormalizedNodeBuilder<NodeIdentifier, Object, LeafNode<Object>> leafBuilder =
+ SchemaAwareBuilders.leafBuilder((LeafSchemaNode) leafSchema);
+ leafBuilder.withValue("brm");
+ containerBuilder.withChild(leafBuilder.build());
+ final ContainerNode container = containerBuilder.build();
+
+ final DOMRpcResult result = new DefaultDOMRpcResult(container);
+
+ doReturn(immediateFluentFuture(result)).when(brokerFacade).invokeRpc(eq(rpcDef.getQName()), any());
+
+ final NormalizedNodeContext output = restconfImpl.invokeRpc("toaster:testOutput", null, uriInfo);
+ assertNotNull(output);
+ assertNotNull(output.getData());
+ assertSame(container, output.getData());
+ assertNotNull(output.getInstanceIdentifierContext());
+ assertNotNull(output.getInstanceIdentifierContext().getSchemaContext());
+ }
+
+ /**
+ * Tests calling of RestConfImpl method invokeRpc. In the method there is searched rpc in remote schema context.
+ * This rpc is then executed.
+ * I wasn't able to simulate calling of rpc on remote device therefore this testing method raise method when rpc is
+ * invoked.
+ */
+ @Test
+ public void testMountedRpcCallNoPayload_Success() throws Exception {
+ // FIXME find how to use mockito for it
+ }
+}
diff --git a/netconf/restconf/restconf-nb-bierman02/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/JSONRestconfServiceImplTest.java b/netconf/restconf/restconf-nb-bierman02/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/JSONRestconfServiceImplTest.java
new file mode 100644
index 0000000..48db5de
--- /dev/null
+++ b/netconf/restconf/restconf-nb-bierman02/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/JSONRestconfServiceImplTest.java
@@ -0,0 +1,532 @@
+/*
+ * Copyright (c) 2015 Brocade Communications Systems, Inc. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.controller.sal.restconf.impl.test;
+
+import static org.hamcrest.CoreMatchers.containsString;
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyString;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.ArgumentMatchers.isNull;
+import static org.mockito.ArgumentMatchers.same;
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+import static org.opendaylight.yangtools.util.concurrent.FluentFutures.immediateFailedFluentFuture;
+import static org.opendaylight.yangtools.util.concurrent.FluentFutures.immediateFluentFuture;
+
+import com.google.common.io.Resources;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.nio.charset.StandardCharsets;
+import java.util.List;
+import java.util.Optional;
+import javax.ws.rs.core.Response.Status;
+import org.junit.Before;
+import org.junit.BeforeClass;
+import org.junit.Test;
+import org.mockito.ArgumentCaptor;
+import org.opendaylight.controller.md.sal.rest.common.TestRestconfUtils;
+import org.opendaylight.mdsal.common.api.CommitInfo;
+import org.opendaylight.mdsal.common.api.LogicalDatastoreType;
+import org.opendaylight.mdsal.common.api.TransactionCommitFailedException;
+import org.opendaylight.mdsal.dom.api.DOMMountPoint;
+import org.opendaylight.mdsal.dom.api.DOMRpcException;
+import org.opendaylight.mdsal.dom.api.DOMRpcImplementationNotAvailableException;
+import org.opendaylight.mdsal.dom.api.DOMRpcResult;
+import org.opendaylight.mdsal.dom.api.DOMSchemaService;
+import org.opendaylight.mdsal.dom.spi.DefaultDOMRpcResult;
+import org.opendaylight.mdsal.dom.spi.FixedDOMSchemaService;
+import org.opendaylight.netconf.sal.restconf.impl.BrokerFacade;
+import org.opendaylight.netconf.sal.restconf.impl.ControllerContext;
+import org.opendaylight.netconf.sal.restconf.impl.JSONRestconfServiceImpl;
+import org.opendaylight.netconf.sal.restconf.impl.PutResult;
+import org.opendaylight.netconf.sal.restconf.impl.RestconfImpl;
+import org.opendaylight.restconf.common.patch.PatchContext;
+import org.opendaylight.restconf.common.patch.PatchStatusContext;
+import org.opendaylight.restconf.common.patch.PatchStatusEntity;
+import org.opendaylight.yangtools.yang.common.OperationFailedException;
+import org.opendaylight.yangtools.yang.common.QName;
+import org.opendaylight.yangtools.yang.common.Uint32;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifier;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifierWithPredicates;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.PathArgument;
+import org.opendaylight.yangtools.yang.data.api.schema.ContainerNode;
+import org.opendaylight.yangtools.yang.data.api.schema.DataContainerChild;
+import org.opendaylight.yangtools.yang.data.api.schema.DataContainerNode;
+import org.opendaylight.yangtools.yang.data.api.schema.MapEntryNode;
+import org.opendaylight.yangtools.yang.data.api.schema.MapNode;
+import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
+import org.opendaylight.yangtools.yang.data.impl.schema.ImmutableNodes;
+import org.opendaylight.yangtools.yang.data.impl.schema.builder.impl.ImmutableContainerNodeBuilder;
+import org.opendaylight.yangtools.yang.model.api.EffectiveModelContext;
+import org.opendaylight.yangtools.yang.parser.spi.meta.ReactorException;
+
+/**
+ * Unit tests for JSONRestconfServiceImpl.
+ *
+ * @author Thomas Pantelis
+ */
+@Deprecated
+public class JSONRestconfServiceImplTest {
+ static final String IETF_INTERFACES_NS = "urn:ietf:params:xml:ns:yang:ietf-interfaces";
+ static final String IETF_INTERFACES_VERSION = "2013-07-04";
+ static final QName INTERFACES_QNAME = QName.create(IETF_INTERFACES_NS, IETF_INTERFACES_VERSION, "interfaces");
+ static final QName INTERFACE_QNAME = QName.create(IETF_INTERFACES_NS, IETF_INTERFACES_VERSION, "interface");
+ static final QName NAME_QNAME = QName.create(IETF_INTERFACES_NS, IETF_INTERFACES_VERSION, "name");
+ static final QName TYPE_QNAME = QName.create(IETF_INTERFACES_NS, IETF_INTERFACES_VERSION, "type");
+ static final QName ENABLED_QNAME = QName.create(IETF_INTERFACES_NS, IETF_INTERFACES_VERSION, "enabled");
+ static final QName DESC_QNAME = QName.create(IETF_INTERFACES_NS, IETF_INTERFACES_VERSION, "description");
+
+ static final String TEST_MODULE_NS = "test:module";
+ static final String TEST_MODULE_VERSION = "2014-01-09";
+ static final QName TEST_CONT_QNAME = QName.create(TEST_MODULE_NS, TEST_MODULE_VERSION, "cont");
+ static final QName TEST_CONT1_QNAME = QName.create(TEST_MODULE_NS, TEST_MODULE_VERSION, "cont1");
+ static final QName TEST_LF11_QNAME = QName.create(TEST_MODULE_NS, TEST_MODULE_VERSION, "lf11");
+ static final QName TEST_LF12_QNAME = QName.create(TEST_MODULE_NS, TEST_MODULE_VERSION, "lf12");
+
+ static final String TOASTER_MODULE_NS = "http://netconfcentral.org/ns/toaster";
+ static final String TOASTER_MODULE_VERSION = "2009-11-20";
+ static final QName TOASTER_DONENESS_QNAME =
+ QName.create(TOASTER_MODULE_NS, TOASTER_MODULE_VERSION, "toasterDoneness");
+ static final QName TOASTER_TYPE_QNAME = QName.create(TOASTER_MODULE_NS, TOASTER_MODULE_VERSION, "toasterToastType");
+ static final QName WHEAT_BREAD_QNAME = QName.create(TOASTER_MODULE_NS, TOASTER_MODULE_VERSION, "wheat-bread");
+ static final QName MAKE_TOAST_QNAME = QName.create(TOASTER_MODULE_NS, TOASTER_MODULE_VERSION, "make-toast");
+ static final QName CANCEL_TOAST_QNAME = QName.create(TOASTER_MODULE_NS, TOASTER_MODULE_VERSION, "cancel-toast");
+ static final QName TEST_OUTPUT_QNAME = QName.create(TOASTER_MODULE_NS, TOASTER_MODULE_VERSION, "testOutput");
+ static final QName TEXT_OUT_QNAME = QName.create(TOASTER_MODULE_NS, TOASTER_MODULE_VERSION, "textOut");
+
+ private static EffectiveModelContext schemaContext;
+
+ private final BrokerFacade brokerFacade = mock(BrokerFacade.class);
+ private final DOMMountPoint mockMountPoint = mock(DOMMountPoint.class);
+ private JSONRestconfServiceImpl service;
+
+ @BeforeClass
+ public static void init() throws IOException, ReactorException {
+ schemaContext = TestUtils.loadSchemaContext("/full-versions/yangs");
+ }
+
+ @Before
+ public void setup() throws FileNotFoundException {
+ final EffectiveModelContext mountPointSchemaContext = TestUtils.loadSchemaContext("/full-versions/test-module");
+ final ControllerContext controllerContext =
+ TestRestconfUtils.newControllerContext(schemaContext, mockMountPoint);
+ doReturn(java.util.Optional.of(FixedDOMSchemaService.of(() -> mountPointSchemaContext))).when(mockMountPoint)
+ .getService(eq(DOMSchemaService.class));
+
+ service = new JSONRestconfServiceImpl(controllerContext,
+ RestconfImpl.newInstance(brokerFacade, controllerContext));
+ }
+
+ private static String loadData(final String path) throws IOException {
+ return Resources.asCharSource(JSONRestconfServiceImplTest.class.getResource(path),
+ StandardCharsets.UTF_8).read();
+ }
+
+ @Test
+ public void testPut() throws Exception {
+ final PutResult result = mock(PutResult.class);
+ when(brokerFacade.commitConfigurationDataPut(any(EffectiveModelContext.class),
+ any(YangInstanceIdentifier.class), any(NormalizedNode.class), isNull(), isNull()))
+ .thenReturn(result);
+ doReturn(CommitInfo.emptyFluentFuture()).when(result).getFutureOfPutData();
+ when(result.getStatus()).thenReturn(Status.OK);
+ final String uriPath = "ietf-interfaces:interfaces/interface/eth0";
+ final String payload = loadData("/parts/ietf-interfaces_interfaces.json");
+ service.put(uriPath, payload);
+
+ final ArgumentCaptor<YangInstanceIdentifier> capturedPath =
+ ArgumentCaptor.forClass(YangInstanceIdentifier.class);
+ final ArgumentCaptor<NormalizedNode> capturedNode = ArgumentCaptor.forClass(NormalizedNode.class);
+ verify(brokerFacade).commitConfigurationDataPut(any(EffectiveModelContext.class), capturedPath.capture(),
+ capturedNode.capture(), isNull(), isNull());
+
+ verifyPath(capturedPath.getValue(), INTERFACES_QNAME, INTERFACE_QNAME,
+ new Object[]{INTERFACE_QNAME, NAME_QNAME, "eth0"});
+
+ assertTrue("Expected MapEntryNode. Actual " + capturedNode.getValue().getClass(),
+ capturedNode.getValue() instanceof MapEntryNode);
+ final MapEntryNode actualNode = (MapEntryNode) capturedNode.getValue();
+ assertEquals("MapEntryNode node type", INTERFACE_QNAME, actualNode.getIdentifier().getNodeType());
+ verifyLeafNode(actualNode, NAME_QNAME, "eth0");
+ verifyLeafNode(actualNode, TYPE_QNAME, "ethernetCsmacd");
+ verifyLeafNode(actualNode, ENABLED_QNAME, Boolean.FALSE);
+ verifyLeafNode(actualNode, DESC_QNAME, "some interface");
+ }
+
+ @Test
+ public void testPutBehindMountPoint() throws Exception {
+ final PutResult result = mock(PutResult.class);
+ when(brokerFacade.commitMountPointDataPut(any(DOMMountPoint.class),
+ any(YangInstanceIdentifier.class), any(NormalizedNode.class), isNull(), isNull()))
+ .thenReturn(result);
+ doReturn(CommitInfo.emptyFluentFuture()).when(result).getFutureOfPutData();
+ when(result.getStatus()).thenReturn(Status.OK);
+ final String uriPath = "ietf-interfaces:interfaces/yang-ext:mount/test-module:cont/cont1";
+ final String payload = loadData("/full-versions/testCont1Data.json");
+
+ service.put(uriPath, payload);
+
+ final ArgumentCaptor<YangInstanceIdentifier> capturedPath =
+ ArgumentCaptor.forClass(YangInstanceIdentifier.class);
+ final ArgumentCaptor<NormalizedNode> capturedNode = ArgumentCaptor.forClass(NormalizedNode.class);
+ verify(brokerFacade).commitMountPointDataPut(same(mockMountPoint), capturedPath.capture(),
+ capturedNode.capture(), isNull(), isNull());
+
+ verifyPath(capturedPath.getValue(), TEST_CONT_QNAME, TEST_CONT1_QNAME);
+
+ assertTrue("Expected ContainerNode", capturedNode.getValue() instanceof ContainerNode);
+ final ContainerNode actualNode = (ContainerNode) capturedNode.getValue();
+ assertEquals("ContainerNode node type", TEST_CONT1_QNAME, actualNode.getIdentifier().getNodeType());
+ verifyLeafNode(actualNode, TEST_LF11_QNAME, "lf11 data");
+ verifyLeafNode(actualNode, TEST_LF12_QNAME, "lf12 data");
+ }
+
+ @Test(expected = OperationFailedException.class)
+ @SuppressWarnings("checkstyle:IllegalThrows")
+ public void testPutFailure() throws Throwable {
+ final PutResult result = mock(PutResult.class);
+
+ doReturn(immediateFailedFluentFuture(new TransactionCommitFailedException("mock"))).when(result)
+ .getFutureOfPutData();
+ when(result.getStatus()).thenReturn(Status.OK);
+ when(brokerFacade.commitConfigurationDataPut(any(EffectiveModelContext.class),
+ any(YangInstanceIdentifier.class), any(NormalizedNode.class), anyString(),
+ anyString())).thenReturn(result);
+
+ final String uriPath = "ietf-interfaces:interfaces/interface/eth0";
+ final String payload = loadData("/parts/ietf-interfaces_interfaces.json");
+
+ service.put(uriPath, payload);
+ }
+
+ @Test
+ public void testPost() throws Exception {
+ doReturn(CommitInfo.emptyFluentFuture()).when(brokerFacade).commitConfigurationDataPost(
+ any(EffectiveModelContext.class), any(YangInstanceIdentifier.class), any(NormalizedNode.class),
+ isNull(), isNull());
+
+ final String uriPath = null;
+ final String payload = loadData("/parts/ietf-interfaces_interfaces_absolute_path.json");
+
+ service.post(uriPath, payload);
+
+ final ArgumentCaptor<YangInstanceIdentifier> capturedPath =
+ ArgumentCaptor.forClass(YangInstanceIdentifier.class);
+ final ArgumentCaptor<NormalizedNode> capturedNode = ArgumentCaptor.forClass(NormalizedNode.class);
+ verify(brokerFacade).commitConfigurationDataPost(any(EffectiveModelContext.class), capturedPath.capture(),
+ capturedNode.capture(), isNull(), isNull());
+
+ verifyPath(capturedPath.getValue(), INTERFACES_QNAME);
+
+ assertTrue("Expected ContainerNode", capturedNode.getValue() instanceof ContainerNode);
+ final ContainerNode actualNode = (ContainerNode) capturedNode.getValue();
+ assertEquals("ContainerNode node type", INTERFACES_QNAME, actualNode.getIdentifier().getNodeType());
+
+ final java.util.Optional<DataContainerChild> mapChild = actualNode.findChildByArg(
+ new NodeIdentifier(INTERFACE_QNAME));
+ assertEquals(INTERFACE_QNAME.toString() + " present", true, mapChild.isPresent());
+ assertTrue("Expected MapNode. Actual " + mapChild.get().getClass(), mapChild.get() instanceof MapNode);
+ final MapNode mapNode = (MapNode)mapChild.get();
+
+ final NodeIdentifierWithPredicates entryNodeID = NodeIdentifierWithPredicates.of(
+ INTERFACE_QNAME, NAME_QNAME, "eth0");
+ final java.util.Optional<MapEntryNode> entryChild = mapNode.findChildByArg(entryNodeID);
+ assertEquals(entryNodeID.toString() + " present", true, entryChild.isPresent());
+ final MapEntryNode entryNode = entryChild.get();
+ verifyLeafNode(entryNode, NAME_QNAME, "eth0");
+ verifyLeafNode(entryNode, TYPE_QNAME, "ethernetCsmacd");
+ verifyLeafNode(entryNode, ENABLED_QNAME, Boolean.FALSE);
+ verifyLeafNode(entryNode, DESC_QNAME, "some interface");
+ }
+
+ @Test
+ public void testPostBehindMountPoint() throws Exception {
+ doReturn(CommitInfo.emptyFluentFuture()).when(brokerFacade).commitConfigurationDataPost(
+ any(DOMMountPoint.class), any(YangInstanceIdentifier.class), any(NormalizedNode.class),
+ isNull(), isNull());
+
+ final String uriPath = "ietf-interfaces:interfaces/yang-ext:mount/test-module:cont";
+ final String payload = loadData("/full-versions/testCont1Data.json");
+
+ service.post(uriPath, payload);
+
+ final ArgumentCaptor<YangInstanceIdentifier> capturedPath =
+ ArgumentCaptor.forClass(YangInstanceIdentifier.class);
+ final ArgumentCaptor<NormalizedNode> capturedNode = ArgumentCaptor.forClass(NormalizedNode.class);
+ verify(brokerFacade).commitConfigurationDataPost(same(mockMountPoint), capturedPath.capture(),
+ capturedNode.capture(), isNull(), isNull());
+
+ verifyPath(capturedPath.getValue(), TEST_CONT_QNAME, TEST_CONT1_QNAME);
+
+ assertTrue("Expected ContainerNode", capturedNode.getValue() instanceof ContainerNode);
+ final ContainerNode actualNode = (ContainerNode) capturedNode.getValue();
+ assertEquals("ContainerNode node type", TEST_CONT1_QNAME, actualNode.getIdentifier().getNodeType());
+ verifyLeafNode(actualNode, TEST_LF11_QNAME, "lf11 data");
+ verifyLeafNode(actualNode, TEST_LF12_QNAME, "lf12 data");
+ }
+
+ @Test(expected = TransactionCommitFailedException.class)
+ @SuppressWarnings({ "checkstyle:IllegalThrows", "checkstyle:avoidHidingCauseException" })
+ public void testPostFailure() throws Throwable {
+ doReturn(immediateFailedFluentFuture(new TransactionCommitFailedException("mock"))).when(brokerFacade)
+ .commitConfigurationDataPost(any(EffectiveModelContext.class), any(YangInstanceIdentifier.class),
+ any(NormalizedNode.class), isNull(), isNull());
+
+ final String uriPath = null;
+ final String payload = loadData("/parts/ietf-interfaces_interfaces_absolute_path.json");
+
+ try {
+ service.post(uriPath, payload);
+ } catch (final OperationFailedException e) {
+ assertNotNull(e.getCause());
+ throw e.getCause();
+ }
+ }
+
+ @Test
+ public void testPatch() throws Exception {
+ final PatchStatusContext result = mock(PatchStatusContext.class);
+ when(brokerFacade.patchConfigurationDataWithinTransaction(any(PatchContext.class)))
+ .thenReturn(result);
+
+ when(result.getEditCollection()).thenReturn(List.of(new PatchStatusEntity("edit1", true, null)));
+ when(result.getGlobalErrors()).thenReturn(List.of());
+ when(result.getPatchId()).thenReturn("1");
+ final String uriPath = "ietf-interfaces:interfaces/interface/eth0";
+ final String payload = loadData("/parts/ietf-interfaces_interfaces_patch.json");
+ final Optional<String> patchResult = service.patch(uriPath, payload);
+
+ assertTrue(patchResult.get().contains("\"ok\":[null]"));
+ }
+
+ @Test
+ public void testPatchBehindMountPoint() throws Exception {
+ final PatchStatusContext result = mock(PatchStatusContext.class);
+ when(brokerFacade.patchConfigurationDataWithinTransaction(any(PatchContext.class))).thenReturn(result);
+
+ when(result.getEditCollection()).thenReturn(List.of(new PatchStatusEntity("edit1", true, null)));
+ when(result.getGlobalErrors()).thenReturn(List.of());
+ when(result.getPatchId()).thenReturn("1");
+
+ final String uriPath = "ietf-interfaces:interfaces/yang-ext:mount/test-module:cont/cont1";
+ final String payload = loadData("/full-versions/testCont1DataPatch.json");
+
+ final Optional<String> patchResult = service.patch(uriPath, payload);
+
+ assertTrue(patchResult.get().contains("\"ok\":[null]"));
+ }
+
+ @Test(expected = OperationFailedException.class)
+ @SuppressWarnings("checkstyle:IllegalThrows")
+ public void testPatchFailure() throws Throwable {
+ final PatchStatusContext result = mock(PatchStatusContext.class);
+ when(brokerFacade.patchConfigurationDataWithinTransaction(any(PatchContext.class)))
+ .thenThrow(new TransactionCommitFailedException("Transaction failed"));
+
+ final String uriPath = "ietf-interfaces:interfaces/interface/eth0";
+ final String payload = loadData("/parts/ietf-interfaces_interfaces_patch.json");
+
+ final Optional<String> patchResult = service.patch(uriPath, payload);
+
+ assertTrue("Patch output is not null", patchResult.isPresent());
+ String patch = patchResult.get();
+ assertTrue(patch.contains("TransactionCommitFailedException"));
+ }
+
+ @Test
+ public void testDelete() throws Exception {
+ doReturn(CommitInfo.emptyFluentFuture()).when(brokerFacade)
+ .commitConfigurationDataDelete(any(YangInstanceIdentifier.class));
+
+ final String uriPath = "ietf-interfaces:interfaces/interface/eth0";
+
+ service.delete(uriPath);
+
+ final ArgumentCaptor<YangInstanceIdentifier> capturedPath =
+ ArgumentCaptor.forClass(YangInstanceIdentifier.class);
+ verify(brokerFacade).commitConfigurationDataDelete(capturedPath.capture());
+
+ verifyPath(capturedPath.getValue(), INTERFACES_QNAME, INTERFACE_QNAME,
+ new Object[]{INTERFACE_QNAME, NAME_QNAME, "eth0"});
+ }
+
+ @Test(expected = OperationFailedException.class)
+ public void testDeleteFailure() throws Exception {
+ final String invalidUriPath = "ietf-interfaces:interfaces/invalid";
+
+ service.delete(invalidUriPath);
+ }
+
+ @Test
+ public void testGetConfig() throws Exception {
+ testGet(LogicalDatastoreType.CONFIGURATION);
+ }
+
+ @Test
+ public void testGetOperational() throws Exception {
+ testGet(LogicalDatastoreType.OPERATIONAL);
+ }
+
+ @Test
+ public void testGetWithNoData() throws OperationFailedException {
+ doReturn(null).when(brokerFacade).readConfigurationData(any(YangInstanceIdentifier.class), anyString());
+ final String uriPath = "ietf-interfaces:interfaces";
+ service.get(uriPath, LogicalDatastoreType.CONFIGURATION);
+ }
+
+ @Test(expected = OperationFailedException.class)
+ public void testGetFailure() throws Exception {
+ final String invalidUriPath = "/ietf-interfaces:interfaces/invalid";
+ service.get(invalidUriPath, LogicalDatastoreType.CONFIGURATION);
+ }
+
+ @Test
+ public void testInvokeRpcWithInput() throws Exception {
+ final DOMRpcResult expResult = new DefaultDOMRpcResult((NormalizedNode)null);
+ doReturn(immediateFluentFuture(expResult)).when(brokerFacade).invokeRpc(eq(MAKE_TOAST_QNAME),
+ any(NormalizedNode.class));
+
+ final String uriPath = "toaster:make-toast";
+ final String input = loadData("/full-versions/make-toast-rpc-input.json");
+
+ final Optional<String> output = service.invokeRpc(uriPath, Optional.of(input));
+
+ assertEquals("Output present", false, output.isPresent());
+
+ final ArgumentCaptor<NormalizedNode> capturedNode = ArgumentCaptor.forClass(NormalizedNode.class);
+ verify(brokerFacade).invokeRpc(eq(MAKE_TOAST_QNAME), capturedNode.capture());
+
+ assertTrue("Expected ContainerNode. Actual " + capturedNode.getValue().getClass(),
+ capturedNode.getValue() instanceof ContainerNode);
+ final ContainerNode actualNode = (ContainerNode) capturedNode.getValue();
+ verifyLeafNode(actualNode, TOASTER_DONENESS_QNAME, Uint32.valueOf(10));
+ verifyLeafNode(actualNode, TOASTER_TYPE_QNAME, WHEAT_BREAD_QNAME);
+ }
+
+ @Test
+ public void testInvokeRpcWithNoInput() throws Exception {
+ final DOMRpcResult expResult = new DefaultDOMRpcResult((NormalizedNode)null);
+ doReturn(immediateFluentFuture(expResult)).when(brokerFacade).invokeRpc(any(QName.class), any());
+
+ final String uriPath = "toaster:cancel-toast";
+
+ final Optional<String> output = service.invokeRpc(uriPath, Optional.empty());
+
+ assertEquals("Output present", false, output.isPresent());
+
+ verify(brokerFacade).invokeRpc(eq(CANCEL_TOAST_QNAME), any());
+ }
+
+ @Test
+ public void testInvokeRpcWithOutput() throws Exception {
+ final NormalizedNode outputNode = ImmutableContainerNodeBuilder.create()
+ .withNodeIdentifier(new YangInstanceIdentifier.NodeIdentifier(TEST_OUTPUT_QNAME))
+ .withChild(ImmutableNodes.leafNode(TEXT_OUT_QNAME, "foo")).build();
+ final DOMRpcResult expResult = new DefaultDOMRpcResult(outputNode);
+ doReturn(immediateFluentFuture(expResult)).when(brokerFacade).invokeRpc(any(QName.class), any());
+
+ final String uriPath = "toaster:testOutput";
+
+ final Optional<String> output = service.invokeRpc(uriPath, Optional.empty());
+
+ assertEquals("Output present", true, output.isPresent());
+ assertNotNull("Returned null response", output.get());
+ assertThat("Missing \"textOut\"", output.get(), containsString("\"textOut\":\"foo\""));
+
+ verify(brokerFacade).invokeRpc(eq(TEST_OUTPUT_QNAME), any());
+ }
+
+ @Test(expected = OperationFailedException.class)
+ public void testInvokeRpcFailure() throws Exception {
+ final DOMRpcException exception = new DOMRpcImplementationNotAvailableException("testExeption");
+ doReturn(immediateFailedFluentFuture(exception)).when(brokerFacade).invokeRpc(any(QName.class),
+ any(NormalizedNode.class));
+
+ final String uriPath = "toaster:cancel-toast";
+
+ service.invokeRpc(uriPath, Optional.empty());
+ }
+
+ void testGet(final LogicalDatastoreType datastoreType) throws OperationFailedException {
+ final MapEntryNode entryNode = ImmutableNodes.mapEntryBuilder(INTERFACE_QNAME, NAME_QNAME, "eth0")
+ .withChild(ImmutableNodes.leafNode(NAME_QNAME, "eth0"))
+ .withChild(ImmutableNodes.leafNode(TYPE_QNAME, "ethernetCsmacd"))
+ .withChild(ImmutableNodes.leafNode(ENABLED_QNAME, Boolean.TRUE))
+ .withChild(ImmutableNodes.leafNode(DESC_QNAME, "eth interface"))
+ .build();
+
+ if (datastoreType == LogicalDatastoreType.CONFIGURATION) {
+ doReturn(entryNode).when(brokerFacade).readConfigurationData(any(YangInstanceIdentifier.class),
+ isNull());
+ } else {
+ doReturn(entryNode).when(brokerFacade).readOperationalData(any(YangInstanceIdentifier.class));
+ }
+
+ final String uriPath = "/ietf-interfaces:interfaces/interface/eth0";
+
+ final Optional<String> optionalResp = service.get(uriPath, datastoreType);
+ assertEquals("Response present", true, optionalResp.isPresent());
+ final String jsonResp = optionalResp.get();
+
+ assertNotNull("Returned null response", jsonResp);
+ assertThat("Missing \"name\"", jsonResp, containsString("\"name\":\"eth0\""));
+ assertThat("Missing \"type\"", jsonResp, containsString("\"type\":\"ethernetCsmacd\""));
+ assertThat("Missing \"enabled\"", jsonResp, containsString("\"enabled\":true"));
+ assertThat("Missing \"description\"", jsonResp, containsString("\"description\":\"eth interface\""));
+
+ final ArgumentCaptor<YangInstanceIdentifier> capturedPath =
+ ArgumentCaptor.forClass(YangInstanceIdentifier.class);
+ if (datastoreType == LogicalDatastoreType.CONFIGURATION) {
+ verify(brokerFacade).readConfigurationData(capturedPath.capture(), isNull());
+ } else {
+ verify(brokerFacade).readOperationalData(capturedPath.capture());
+ }
+
+ verifyPath(capturedPath.getValue(), INTERFACES_QNAME, INTERFACE_QNAME,
+ new Object[]{INTERFACE_QNAME, NAME_QNAME, "eth0"});
+ }
+
+ void verifyLeafNode(final DataContainerNode parent, final QName leafType, final Object leafValue) {
+ final java.util.Optional<DataContainerChild> leafChild = parent.findChildByArg(new NodeIdentifier(leafType));
+ assertTrue(leafType.toString() + " present", leafChild.isPresent());
+ assertEquals(leafType.toString() + " value", leafValue, leafChild.get().body());
+ }
+
+ void verifyPath(final YangInstanceIdentifier path, final Object... expArgs) {
+ final List<PathArgument> pathArgs = path.getPathArguments();
+ assertEquals("Arg count for actual path " + path, expArgs.length, pathArgs.size());
+ int index = 0;
+ for (final PathArgument actual: pathArgs) {
+ QName expNodeType;
+ if (expArgs[index] instanceof Object[]) {
+ final Object[] listEntry = (Object[]) expArgs[index];
+ expNodeType = (QName) listEntry[0];
+
+ assertTrue(actual instanceof NodeIdentifierWithPredicates);
+ final NodeIdentifierWithPredicates nip = (NodeIdentifierWithPredicates)actual;
+ assertEquals(String.format("Path arg %d keyValues size", index + 1), 1, nip.size());
+ final QName expKey = (QName) listEntry[1];
+ assertEquals(String.format("Path arg %d keyValue for %s", index + 1, expKey), listEntry[2],
+ nip.getValue(expKey));
+ } else {
+ expNodeType = (QName) expArgs[index];
+ }
+
+ assertEquals(String.format("Path arg %d node type", index + 1), expNodeType, actual.getNodeType());
+ index++;
+ }
+
+ }
+}
diff --git a/netconf/restconf/restconf-nb-bierman02/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/MediaTypesTest.java b/netconf/restconf/restconf-nb-bierman02/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/MediaTypesTest.java
new file mode 100644
index 0000000..2bddec2
--- /dev/null
+++ b/netconf/restconf/restconf-nb-bierman02/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/MediaTypesTest.java
@@ -0,0 +1,260 @@
+/*
+ * Copyright (c) 2014 Cisco Systems, Inc. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.controller.sal.restconf.impl.test;
+
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+import static org.opendaylight.controller.sal.restconf.impl.test.RestOperationUtils.JSON;
+import static org.opendaylight.controller.sal.restconf.impl.test.RestOperationUtils.XML;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.UnsupportedEncodingException;
+import javax.ws.rs.client.Entity;
+import javax.ws.rs.core.Application;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.UriInfo;
+import org.glassfish.jersey.server.ResourceConfig;
+import org.glassfish.jersey.test.JerseyTest;
+import org.junit.BeforeClass;
+import org.junit.Ignore;
+import org.junit.Test;
+import org.mockito.Mockito;
+import org.opendaylight.netconf.sal.rest.api.Draft02;
+import org.opendaylight.netconf.sal.rest.api.RestconfService;
+import org.opendaylight.netconf.sal.rest.impl.NormalizedNodeContext;
+import org.opendaylight.netconf.sal.rest.impl.NormalizedNodeJsonBodyWriter;
+import org.opendaylight.netconf.sal.rest.impl.NormalizedNodeXmlBodyWriter;
+
+public class MediaTypesTest extends JerseyTest {
+
+ private static String jsonData;
+ private static String xmlData;
+
+ private RestconfService restconfService;
+
+ @BeforeClass
+ public static void init() throws IOException {
+ final String jsonPath = RestconfImplTest.class.getResource("/parts/ietf-interfaces_interfaces.json").getPath();
+ jsonData = TestUtils.loadTextFile(jsonPath);
+ final InputStream xmlStream =
+ RestconfImplTest.class.getResourceAsStream("/parts/ietf-interfaces_interfaces.xml");
+ xmlData = TestUtils.getDocumentInPrintableForm(TestUtils.loadDocumentFrom(xmlStream));
+ }
+
+ @Override
+ protected Application configure() {
+ /* enable/disable Jersey logs to console */
+ // enable(TestProperties.LOG_TRAFFIC);
+ // enable(TestProperties.DUMP_ENTITY);
+ // enable(TestProperties.RECORD_LOG_LEVEL);
+ // set(TestProperties.RECORD_LOG_LEVEL, Level.ALL.intValue());'
+ restconfService = mock(RestconfService.class);
+ ResourceConfig resourceConfig = new ResourceConfig();
+ resourceConfig = resourceConfig.registerInstances(restconfService, new NormalizedNodeJsonBodyWriter(),
+ new NormalizedNodeXmlBodyWriter());
+ return resourceConfig;
+ }
+
+ @Test
+ @Ignore
+ public void testPostOperationsWithInputDataMediaTypes() throws UnsupportedEncodingException {
+ final String uriPrefix = "/operations/";
+ final String uriPath = "ietf-interfaces:interfaces";
+ final String uri = uriPrefix + uriPath;
+ when(restconfService.invokeRpc(eq(uriPath), any(NormalizedNodeContext.class), any(UriInfo.class)))
+ .thenReturn(null);
+ post(uri, Draft02.MediaTypes.OPERATION + JSON, Draft02.MediaTypes.OPERATION + JSON, jsonData);
+ verify(restconfService, times(1)).invokeRpc(eq(uriPath), any(NormalizedNodeContext.class), any(UriInfo.class));
+ post(uri, Draft02.MediaTypes.OPERATION + XML, Draft02.MediaTypes.OPERATION + XML, xmlData);
+ verify(restconfService, times(2)).invokeRpc(eq(uriPath), any(NormalizedNodeContext.class), any(UriInfo.class));
+ post(uri, MediaType.APPLICATION_JSON, MediaType.APPLICATION_JSON, jsonData);
+ verify(restconfService, times(3)).invokeRpc(eq(uriPath), any(NormalizedNodeContext.class), any(UriInfo.class));
+ post(uri, MediaType.APPLICATION_XML, MediaType.APPLICATION_XML, xmlData);
+ verify(restconfService, times(4)).invokeRpc(eq(uriPath), any(NormalizedNodeContext.class), any(UriInfo.class));
+ post(uri, MediaType.TEXT_XML, MediaType.TEXT_XML, xmlData);
+ verify(restconfService, times(5)).invokeRpc(eq(uriPath), any(NormalizedNodeContext.class), any(UriInfo.class));
+ post(uri, null, MediaType.TEXT_XML, xmlData);
+ verify(restconfService, times(6)).invokeRpc(eq(uriPath), any(NormalizedNodeContext.class), any(UriInfo.class));
+
+ // negative tests
+ post(uri, MediaType.TEXT_PLAIN, MediaType.TEXT_XML, xmlData);
+ verify(restconfService, times(6)).invokeRpc(eq(uriPath), any(NormalizedNodeContext.class), any(UriInfo.class));
+ post(uri, MediaType.TEXT_XML, MediaType.TEXT_PLAIN, xmlData);
+ verify(restconfService, times(6)).invokeRpc(eq(uriPath), any(NormalizedNodeContext.class), any(UriInfo.class));
+ }
+
+ @Test
+ public void testGetConfigMediaTypes() throws UnsupportedEncodingException {
+ final String uriPrefix = "/config/";
+ final String uriPath = "ietf-interfaces:interfaces";
+ final String uri = uriPrefix + uriPath;
+ when(restconfService.readConfigurationData(eq(uriPath), any(UriInfo.class))).thenReturn(null);
+ get(uri, Draft02.MediaTypes.DATA + JSON);
+ verify(restconfService, times(1)).readConfigurationData(eq(uriPath), any(UriInfo.class));
+ get(uri, Draft02.MediaTypes.DATA + XML);
+ verify(restconfService, times(2)).readConfigurationData(eq(uriPath), any(UriInfo.class));
+ get(uri, MediaType.APPLICATION_JSON);
+ verify(restconfService, times(3)).readConfigurationData(eq(uriPath), any(UriInfo.class));
+ get(uri, MediaType.APPLICATION_XML);
+ verify(restconfService, times(4)).readConfigurationData(eq(uriPath), any(UriInfo.class));
+ get(uri, MediaType.TEXT_XML);
+ verify(restconfService, times(5)).readConfigurationData(eq(uriPath), any(UriInfo.class));
+
+ // negative tests
+ get(uri, MediaType.TEXT_PLAIN);
+ verify(restconfService, times(5)).readConfigurationData(eq(uriPath), any(UriInfo.class));
+ }
+
+ @Test
+ public void testGetOperationalMediaTypes() throws UnsupportedEncodingException {
+ final String uriPrefix = "/operational/";
+ final String uriPath = "ietf-interfaces:interfaces";
+ final String uri = uriPrefix + uriPath;
+ when(restconfService.readOperationalData(eq(uriPath), any(UriInfo.class))).thenReturn(null);
+ get(uri, Draft02.MediaTypes.DATA + JSON);
+ verify(restconfService, times(1)).readOperationalData(eq(uriPath), any(UriInfo.class));
+ get(uri, Draft02.MediaTypes.DATA + XML);
+ verify(restconfService, times(2)).readOperationalData(eq(uriPath), any(UriInfo.class));
+ get(uri, MediaType.APPLICATION_JSON);
+ verify(restconfService, times(3)).readOperationalData(eq(uriPath), any(UriInfo.class));
+ get(uri, MediaType.APPLICATION_XML);
+ verify(restconfService, times(4)).readOperationalData(eq(uriPath), any(UriInfo.class));
+ get(uri, MediaType.TEXT_XML);
+ verify(restconfService, times(5)).readOperationalData(eq(uriPath), any(UriInfo.class));
+
+ // negative tests
+ get(uri, MediaType.TEXT_PLAIN);
+ verify(restconfService, times(5)).readOperationalData(eq(uriPath), any(UriInfo.class));
+ }
+
+ @Test
+ @Ignore
+ public void testPutConfigMediaTypes() throws UnsupportedEncodingException {
+ final String uriPrefix = "/config/";
+ final String uriPath = "ietf-interfaces:interfaces";
+ final String uri = uriPrefix + uriPath;
+ final UriInfo uriInfo = Mockito.mock(UriInfo.class);
+ when(restconfService.updateConfigurationData(eq(uriPath), any(NormalizedNodeContext.class), uriInfo))
+ .thenReturn(null);
+ put(uri, null, Draft02.MediaTypes.DATA + JSON, jsonData);
+ verify(restconfService, times(1)).updateConfigurationData(eq(uriPath), any(NormalizedNodeContext.class),
+ uriInfo);
+ put(uri, null, Draft02.MediaTypes.DATA + XML, xmlData);
+ verify(restconfService, times(2)).updateConfigurationData(eq(uriPath), any(NormalizedNodeContext.class),
+ uriInfo);
+ put(uri, null, MediaType.APPLICATION_JSON, jsonData);
+ verify(restconfService, times(3)).updateConfigurationData(eq(uriPath), any(NormalizedNodeContext.class),
+ uriInfo);
+ put(uri, null, MediaType.APPLICATION_XML, xmlData);
+ verify(restconfService, times(4)).updateConfigurationData(eq(uriPath), any(NormalizedNodeContext.class),
+ uriInfo);
+ put(uri, null, MediaType.TEXT_XML, xmlData);
+ verify(restconfService, times(5)).updateConfigurationData(eq(uriPath), any(NormalizedNodeContext.class),
+ uriInfo);
+ put(uri, "fooMediaType", MediaType.TEXT_XML, xmlData);
+ verify(restconfService, times(6)).updateConfigurationData(eq(uriPath), any(NormalizedNodeContext.class),
+ uriInfo);
+ }
+
+ @Test
+ @Ignore
+ public void testPostConfigWithPathMediaTypes() throws UnsupportedEncodingException {
+ final String uriPrefix = "/config/";
+ final String uriPath = "ietf-interfaces:interfaces";
+ final String uri = uriPrefix + uriPath;
+ when(restconfService.createConfigurationData(eq(uriPath), any(NormalizedNodeContext.class),
+ any(UriInfo.class))).thenReturn(null);
+ post(uri, null, Draft02.MediaTypes.DATA + JSON, jsonData);
+ verify(restconfService, times(1)).createConfigurationData(eq(uriPath),
+ any(NormalizedNodeContext.class), any(UriInfo.class));
+ post(uri, null, Draft02.MediaTypes.DATA + XML, xmlData);
+ verify(restconfService, times(2)).createConfigurationData(eq(uriPath),
+ any(NormalizedNodeContext.class), any(UriInfo.class));
+ post(uri, null, MediaType.APPLICATION_JSON, jsonData);
+ verify(restconfService, times(3)).createConfigurationData(eq(uriPath),
+ any(NormalizedNodeContext.class), any(UriInfo.class));
+ post(uri, null, MediaType.APPLICATION_XML, xmlData);
+ verify(restconfService, times(4)).createConfigurationData(eq(uriPath),
+ any(NormalizedNodeContext.class), any(UriInfo.class));
+ post(uri, null, MediaType.TEXT_XML, xmlData);
+ verify(restconfService, times(5)).createConfigurationData(eq(uriPath),
+ any(NormalizedNodeContext.class), any(UriInfo.class));
+ post(uri, "fooMediaType", MediaType.TEXT_XML, xmlData);
+ verify(restconfService, times(6)).createConfigurationData(eq(uriPath),
+ any(NormalizedNodeContext.class), any(UriInfo.class));
+ }
+
+ @Test
+ @Ignore
+ public void testPostConfigMediaTypes() throws UnsupportedEncodingException {
+ final String uriPrefix = "/config/";
+ final String uri = uriPrefix;
+ when(restconfService.createConfigurationData(any(NormalizedNodeContext.class),
+ any(UriInfo.class))).thenReturn(null);
+ post(uri, null, Draft02.MediaTypes.DATA + JSON, jsonData);
+ verify(restconfService, times(1)).createConfigurationData(
+ any(NormalizedNodeContext.class), any(UriInfo.class));
+ post(uri, null, Draft02.MediaTypes.DATA + XML, xmlData);
+ verify(restconfService, times(2)).createConfigurationData(
+ any(NormalizedNodeContext.class), any(UriInfo.class));
+ post(uri, null, MediaType.APPLICATION_JSON, jsonData);
+ verify(restconfService, times(3)).createConfigurationData(
+ any(NormalizedNodeContext.class), any(UriInfo.class));
+ post(uri, null, MediaType.APPLICATION_XML, xmlData);
+ verify(restconfService, times(4)).createConfigurationData(
+ any(NormalizedNodeContext.class), any(UriInfo.class));
+ post(uri, null, MediaType.TEXT_XML, xmlData);
+ verify(restconfService, times(5)).createConfigurationData(
+ any(NormalizedNodeContext.class), any(UriInfo.class));
+ post(uri, "fooMediaType", MediaType.TEXT_XML, xmlData);
+ verify(restconfService, times(6)).createConfigurationData(
+ any(NormalizedNodeContext.class), any(UriInfo.class));
+ }
+
+ @Test
+ public void testDeleteConfigMediaTypes() throws UnsupportedEncodingException {
+ final String uriPrefix = "/config/";
+ final String uriPath = "ietf-interfaces:interfaces";
+ final String uri = uriPrefix + uriPath;
+ when(restconfService.deleteConfigurationData(eq(uriPath))).thenReturn(null);
+ target(uri).request("fooMediaType").delete();
+ verify(restconfService, times(1)).deleteConfigurationData(uriPath);
+ }
+
+ private int get(final String uri, final String acceptMediaType) {
+ return target(uri).request(acceptMediaType).get().getStatus();
+ }
+
+ private int put(final String uri, final String acceptMediaType, final String contentTypeMediaType,
+ final String data) {
+ if (acceptMediaType == null) {
+ return target(uri).request().put(Entity.entity(data, contentTypeMediaType)).getStatus();
+ }
+ return target(uri).request(acceptMediaType).put(Entity.entity(data, contentTypeMediaType)).getStatus();
+ }
+
+ private int post(final String uri, final String acceptMediaType, final String contentTypeMediaType,
+ final String data) {
+ if (acceptMediaType == null) {
+ if (contentTypeMediaType == null || data == null) {
+ return target(uri).request().post(null).getStatus();
+ }
+ return target(uri).request().post(Entity.entity(data, contentTypeMediaType)).getStatus();
+ }
+ if (contentTypeMediaType == null || data == null) {
+ return target(uri).request(acceptMediaType).post(null).getStatus();
+ }
+ return target(uri).request(acceptMediaType).post(Entity.entity(data, contentTypeMediaType)).getStatus();
+ }
+
+}
diff --git a/netconf/restconf/restconf-nb-bierman02/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/NormalizeNodeTest.java b/netconf/restconf/restconf-nb-bierman02/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/NormalizeNodeTest.java
new file mode 100644
index 0000000..3af5f96
--- /dev/null
+++ b/netconf/restconf/restconf-nb-bierman02/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/NormalizeNodeTest.java
@@ -0,0 +1,21 @@
+/*
+ * Copyright (c) 2014 Cisco Systems, Inc. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.controller.sal.restconf.impl.test;
+
+import java.io.FileNotFoundException;
+import org.junit.BeforeClass;
+import org.opendaylight.yangtools.yang.parser.spi.meta.ReactorException;
+
+public class NormalizeNodeTest extends YangAndXmlAndDataSchemaLoader {
+
+ @BeforeClass
+ public static void initialization() throws FileNotFoundException, ReactorException {
+ dataLoad("/normalize-node/yang/");
+ }
+
+}
diff --git a/netconf/restconf/restconf-nb-bierman02/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/RestCodecExceptionsTest.java b/netconf/restconf/restconf-nb-bierman02/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/RestCodecExceptionsTest.java
new file mode 100644
index 0000000..bd2d48b
--- /dev/null
+++ b/netconf/restconf/restconf-nb-bierman02/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/RestCodecExceptionsTest.java
@@ -0,0 +1,38 @@
+/*
+ * Copyright (c) 2014 Cisco Systems, Inc. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.controller.sal.restconf.impl.test;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNull;
+import static org.mockito.Mockito.mock;
+
+import org.junit.Test;
+import org.opendaylight.netconf.sal.restconf.impl.RestCodec;
+import org.opendaylight.yangtools.concepts.IllegalArgumentCodec;
+import org.opendaylight.yangtools.yang.common.QName;
+import org.opendaylight.yangtools.yang.model.api.type.IdentityrefTypeDefinition;
+import org.opendaylight.yangtools.yang.model.ri.type.BaseTypes;
+
+public class RestCodecExceptionsTest {
+ @Test
+ public void serializeExceptionTest() {
+ final IllegalArgumentCodec<Object, Object> codec = RestCodec.from(
+ BaseTypes.bitsTypeBuilder(QName.create("test", "2014-05-30", "test")).build(), null, null);
+ final String serializedValue = (String) codec.serialize("incorrect value"); // set
+ // expected
+ assertEquals("incorrect value", serializedValue);
+ }
+
+ @Test
+ public void deserializeExceptionTest() {
+ final IdentityrefTypeDefinition mockedIidentityrefType = mock(IdentityrefTypeDefinition.class);
+
+ final IllegalArgumentCodec<Object, Object> codec = RestCodec.from(mockedIidentityrefType, null, null);
+ assertNull(codec.deserialize("incorrect value"));
+ }
+}
diff --git a/netconf/restconf/restconf-nb-bierman02/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/RestDeleteOperationTest.java b/netconf/restconf/restconf-nb-bierman02/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/RestDeleteOperationTest.java
new file mode 100644
index 0000000..3ebbf28
--- /dev/null
+++ b/netconf/restconf/restconf-nb-bierman02/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/RestDeleteOperationTest.java
@@ -0,0 +1,96 @@
+/*
+ * Copyright (c) 2014 Cisco Systems, Inc. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.controller.sal.restconf.impl.test;
+
+import static org.junit.Assert.assertEquals;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.doThrow;
+import static org.mockito.Mockito.mock;
+import static org.opendaylight.yangtools.util.concurrent.FluentFutures.immediateFailedFluentFuture;
+
+import java.io.FileNotFoundException;
+import java.io.UnsupportedEncodingException;
+import javax.ws.rs.core.Application;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.Response;
+import org.glassfish.jersey.server.ResourceConfig;
+import org.glassfish.jersey.test.JerseyTest;
+import org.junit.BeforeClass;
+import org.junit.Test;
+import org.opendaylight.controller.md.sal.rest.common.TestRestconfUtils;
+import org.opendaylight.mdsal.common.api.CommitInfo;
+import org.opendaylight.mdsal.common.api.TransactionCommitFailedException;
+import org.opendaylight.netconf.sal.rest.impl.JsonNormalizedNodeBodyReader;
+import org.opendaylight.netconf.sal.rest.impl.NormalizedNodeJsonBodyWriter;
+import org.opendaylight.netconf.sal.rest.impl.NormalizedNodeXmlBodyWriter;
+import org.opendaylight.netconf.sal.rest.impl.RestconfDocumentedExceptionMapper;
+import org.opendaylight.netconf.sal.rest.impl.XmlNormalizedNodeBodyReader;
+import org.opendaylight.netconf.sal.restconf.impl.BrokerFacade;
+import org.opendaylight.netconf.sal.restconf.impl.ControllerContext;
+import org.opendaylight.netconf.sal.restconf.impl.RestconfImpl;
+import org.opendaylight.restconf.common.errors.RestconfDocumentedException;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
+import org.opendaylight.yangtools.yang.model.api.EffectiveModelContext;
+import org.opendaylight.yangtools.yang.parser.spi.meta.ReactorException;
+
+public class RestDeleteOperationTest extends JerseyTest {
+ private static EffectiveModelContext schemaContext;
+
+ private ControllerContext controllerContext;
+ private BrokerFacade brokerFacade;
+ private RestconfImpl restconfImpl;
+
+ @BeforeClass
+ public static void init() throws FileNotFoundException, ReactorException {
+ schemaContext = TestUtils.loadSchemaContext("/test-config-data/yang1");
+ }
+
+ @Override
+ protected Application configure() {
+ /* enable/disable Jersey logs to console */
+ // enable(TestProperties.LOG_TRAFFIC);
+ // enable(TestProperties.DUMP_ENTITY);
+ // enable(TestProperties.RECORD_LOG_LEVEL);
+ // set(TestProperties.RECORD_LOG_LEVEL, Level.ALL.intValue());
+ controllerContext = TestRestconfUtils.newControllerContext(schemaContext);
+ controllerContext.setSchemas(schemaContext);
+ brokerFacade = mock(BrokerFacade.class);
+ restconfImpl = RestconfImpl.newInstance(brokerFacade, controllerContext);
+
+ ResourceConfig resourceConfig = new ResourceConfig();
+ resourceConfig = resourceConfig.registerInstances(restconfImpl, new NormalizedNodeJsonBodyWriter(),
+ new NormalizedNodeXmlBodyWriter(), new XmlNormalizedNodeBodyReader(controllerContext),
+ new JsonNormalizedNodeBodyReader(controllerContext),
+ new RestconfDocumentedExceptionMapper(controllerContext));
+ return resourceConfig;
+ }
+
+ @Test
+ public void deleteConfigStatusCodes() throws UnsupportedEncodingException {
+ final String uri = "/config/test-interface:interfaces";
+ doReturn(CommitInfo.emptyFluentFuture()).when(brokerFacade)
+ .commitConfigurationDataDelete(any(YangInstanceIdentifier.class));
+ Response response = target(uri).request(MediaType.APPLICATION_XML).delete();
+ assertEquals(200, response.getStatus());
+
+ doThrow(RestconfDocumentedException.class).when(brokerFacade).commitConfigurationDataDelete(
+ any(YangInstanceIdentifier.class));
+ response = target(uri).request(MediaType.APPLICATION_XML).delete();
+ assertEquals(500, response.getStatus());
+ }
+
+ @Test
+ public void deleteFailTest() throws Exception {
+ final String uri = "/config/test-interface:interfaces";
+ doReturn(immediateFailedFluentFuture(new TransactionCommitFailedException("failed test"))).when(brokerFacade)
+ .commitConfigurationDataDelete(any(YangInstanceIdentifier.class));
+ final Response response = target(uri).request(MediaType.APPLICATION_XML).delete();
+ assertEquals(500, response.getStatus());
+ }
+}
diff --git a/netconf/restconf/restconf-nb-bierman02/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/RestGetAugmentedElementWhenEqualNamesTest.java b/netconf/restconf/restconf-nb-bierman02/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/RestGetAugmentedElementWhenEqualNamesTest.java
new file mode 100644
index 0000000..d0b30cb
--- /dev/null
+++ b/netconf/restconf/restconf-nb-bierman02/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/RestGetAugmentedElementWhenEqualNamesTest.java
@@ -0,0 +1,52 @@
+/*
+ * Copyright (c) 2014 Cisco Systems, Inc. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.controller.sal.restconf.impl.test;
+
+import static org.hamcrest.CoreMatchers.containsString;
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertThrows;
+
+import java.io.FileNotFoundException;
+import org.junit.BeforeClass;
+import org.junit.Test;
+import org.opendaylight.controller.md.sal.rest.common.TestRestconfUtils;
+import org.opendaylight.netconf.sal.restconf.impl.ControllerContext;
+import org.opendaylight.restconf.common.context.InstanceIdentifierContext;
+import org.opendaylight.restconf.common.errors.RestconfDocumentedException;
+import org.opendaylight.yangtools.yang.common.XMLNamespace;
+import org.opendaylight.yangtools.yang.model.api.EffectiveModelContext;
+
+public class RestGetAugmentedElementWhenEqualNamesTest {
+
+ private static EffectiveModelContext schemaContext;
+
+ private final ControllerContext controllerContext = TestRestconfUtils.newControllerContext(schemaContext);
+
+ @BeforeClass
+ public static void init() throws FileNotFoundException {
+ schemaContext = TestUtils.loadSchemaContext("/common/augment/yang");
+ }
+
+ @Test
+ public void augmentedNodesInUri() {
+ InstanceIdentifierContext iiWithData =
+ controllerContext.toInstanceIdentifier("main:cont/augment-main-a:cont1");
+ assertEquals(XMLNamespace.of("ns:augment:main:a"), iiWithData.getSchemaNode().getQName().getNamespace());
+ iiWithData = controllerContext.toInstanceIdentifier("main:cont/augment-main-b:cont1");
+ assertEquals(XMLNamespace.of("ns:augment:main:b"), iiWithData.getSchemaNode().getQName().getNamespace());
+ }
+
+ @Test
+ public void nodeWithoutNamespaceHasMoreAugments() {
+ final var ex = assertThrows(RestconfDocumentedException.class,
+ () -> controllerContext.toInstanceIdentifier("main:cont/cont1"));
+ assertThat(ex.getErrors().get(0).getErrorMessage(),
+ containsString("is added as augment from more than one module"));
+ }
+}
diff --git a/netconf/restconf/restconf-nb-bierman02/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/RestGetOperationTest.java b/netconf/restconf/restconf-nb-bierman02/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/RestGetOperationTest.java
new file mode 100644
index 0000000..65fa8e0
--- /dev/null
+++ b/netconf/restconf/restconf-nb-bierman02/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/RestGetOperationTest.java
@@ -0,0 +1,742 @@
+/*
+ * Copyright (c) 2014 Cisco Systems, Inc. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.controller.sal.restconf.impl.test;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.ArgumentMatchers.isNull;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+import com.google.common.collect.ImmutableMap;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Optional;
+import java.util.Set;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+import javax.ws.rs.core.Application;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.MultivaluedHashMap;
+import javax.ws.rs.core.MultivaluedMap;
+import javax.ws.rs.core.Response;
+import javax.ws.rs.core.UriInfo;
+import org.glassfish.jersey.server.ResourceConfig;
+import org.glassfish.jersey.test.JerseyTest;
+import org.junit.BeforeClass;
+import org.junit.Ignore;
+import org.junit.Test;
+import org.opendaylight.controller.md.sal.rest.common.TestRestconfUtils;
+import org.opendaylight.mdsal.dom.api.DOMMountPoint;
+import org.opendaylight.mdsal.dom.api.DOMSchemaService;
+import org.opendaylight.mdsal.dom.spi.FixedDOMSchemaService;
+import org.opendaylight.netconf.sal.rest.impl.JsonNormalizedNodeBodyReader;
+import org.opendaylight.netconf.sal.rest.impl.NormalizedNodeJsonBodyWriter;
+import org.opendaylight.netconf.sal.rest.impl.NormalizedNodeXmlBodyWriter;
+import org.opendaylight.netconf.sal.rest.impl.RestconfDocumentedExceptionMapper;
+import org.opendaylight.netconf.sal.rest.impl.XmlNormalizedNodeBodyReader;
+import org.opendaylight.netconf.sal.restconf.impl.BrokerFacade;
+import org.opendaylight.netconf.sal.restconf.impl.ControllerContext;
+import org.opendaylight.netconf.sal.restconf.impl.RestconfImpl;
+import org.opendaylight.restconf.common.errors.RestconfDocumentedException;
+import org.opendaylight.yangtools.yang.common.QName;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifier;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifierWithPredicates;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.PathArgument;
+import org.opendaylight.yangtools.yang.data.api.schema.ContainerNode;
+import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
+import org.opendaylight.yangtools.yang.data.impl.schema.Builders;
+import org.opendaylight.yangtools.yang.data.impl.schema.ImmutableNodes;
+import org.opendaylight.yangtools.yang.data.impl.schema.builder.impl.ImmutableLeafNodeBuilder;
+import org.opendaylight.yangtools.yang.data.impl.schema.builder.impl.ImmutableMapEntryNodeBuilder;
+import org.opendaylight.yangtools.yang.data.impl.schema.builder.impl.ImmutableMapNodeBuilder;
+import org.opendaylight.yangtools.yang.model.api.EffectiveModelContext;
+import org.opendaylight.yangtools.yang.model.api.Module;
+import org.opendaylight.yangtools.yang.model.api.RpcDefinition;
+import org.opendaylight.yangtools.yang.model.api.SchemaContext;
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
+import org.w3c.dom.NodeList;
+
+public class RestGetOperationTest extends JerseyTest {
+
+ static class NodeData {
+ Object key;
+ Object data; // List for a CompositeNode, value Object for a SimpleNode
+
+ NodeData(final Object key, final Object data) {
+ this.key = key;
+ this.data = data;
+ }
+ }
+
+ private static EffectiveModelContext schemaContextYangsIetf;
+ private static EffectiveModelContext schemaContextTestModule;
+ private static EffectiveModelContext schemaContextModules;
+ private static EffectiveModelContext schemaContextBehindMountPoint;
+
+ private static NormalizedNode answerFromGet;
+
+ private BrokerFacade brokerFacade;
+ private RestconfImpl restconfImpl;
+ private ControllerContext controllerContext;
+ private DOMMountPoint mountInstance;
+
+ private static final String RESTCONF_NS = "urn:ietf:params:xml:ns:yang:ietf-restconf";
+
+ @BeforeClass
+ public static void init() throws Exception {
+ schemaContextYangsIetf = TestUtils.loadSchemaContext("/full-versions/yangs");
+ schemaContextTestModule = TestUtils.loadSchemaContext("/full-versions/test-module");
+ schemaContextModules = TestUtils.loadSchemaContext("/modules");
+ schemaContextBehindMountPoint = TestUtils.loadSchemaContext("/modules/modules-behind-mount-point");
+
+ answerFromGet = TestUtils.prepareNormalizedNodeWithIetfInterfacesInterfacesData();
+ }
+
+ @Override
+ protected Application configure() {
+ /* enable/disable Jersey logs to console */
+ // enable(TestProperties.LOG_TRAFFIC);
+ // enable(TestProperties.DUMP_ENTITY);
+ // enable(TestProperties.RECORD_LOG_LEVEL);
+ // set(TestProperties.RECORD_LOG_LEVEL, Level.ALL.intValue());
+
+ mountInstance = mock(DOMMountPoint.class);
+ controllerContext = TestRestconfUtils.newControllerContext(schemaContextYangsIetf, mountInstance);
+ brokerFacade = mock(BrokerFacade.class);
+ restconfImpl = RestconfImpl.newInstance(brokerFacade, controllerContext);
+
+ ResourceConfig resourceConfig = new ResourceConfig();
+ resourceConfig = resourceConfig.registerInstances(restconfImpl, new NormalizedNodeJsonBodyWriter(),
+ new NormalizedNodeXmlBodyWriter(), new XmlNormalizedNodeBodyReader(controllerContext),
+ new JsonNormalizedNodeBodyReader(controllerContext),
+ new RestconfDocumentedExceptionMapper(controllerContext));
+ return resourceConfig;
+ }
+
+ private void setControllerContext(final EffectiveModelContext schemaContext) {
+ controllerContext.setSchemas(schemaContext);
+ }
+
+ /**
+ * Tests of status codes for "/operational/{identifier}".
+ */
+ @Test
+ public void getOperationalStatusCodes() throws Exception {
+ setControllerContext(schemaContextYangsIetf);
+ mockReadOperationalDataMethod();
+ String uri = "/operational/ietf-interfaces:interfaces/interface/eth0";
+ assertEquals(200, get(uri, MediaType.APPLICATION_XML));
+
+ uri = "/operational/wrong-module:interfaces/interface/eth0";
+ assertEquals(400, get(uri, MediaType.APPLICATION_XML));
+ }
+
+ /**
+ * Tests of status codes for "/config/{identifier}".
+ */
+ @Test
+ public void getConfigStatusCodes() throws Exception {
+ setControllerContext(schemaContextYangsIetf);
+ mockReadConfigurationDataMethod();
+ String uri = "/config/ietf-interfaces:interfaces/interface/eth0";
+ assertEquals(200, get(uri, MediaType.APPLICATION_XML));
+
+ uri = "/config/wrong-module:interfaces/interface/eth0";
+ assertEquals(400, get(uri, MediaType.APPLICATION_XML));
+ }
+
+ /**
+ * MountPoint test. URI represents mount point.
+ */
+ @Test
+ public void getDataWithUrlMountPoint() throws Exception {
+ when(brokerFacade.readConfigurationData(any(DOMMountPoint.class), any(YangInstanceIdentifier.class),
+ isNull())).thenReturn(prepareCnDataForMountPointTest(false));
+ when(mountInstance.getService(DOMSchemaService.class))
+ .thenReturn(Optional.of(FixedDOMSchemaService.of(schemaContextTestModule)));
+
+ String uri = "/config/ietf-interfaces:interfaces/interface/0/yang-ext:mount/test-module:cont/cont1";
+ assertEquals(200, get(uri, MediaType.APPLICATION_XML));
+
+ uri = "/config/ietf-interfaces:interfaces/yang-ext:mount/test-module:cont/cont1";
+ assertEquals(200, get(uri, MediaType.APPLICATION_XML));
+ }
+
+ /**
+ * MountPoint test. URI represents mount point.
+ * Slashes in URI behind mount point. lst1 element with key GigabitEthernet0%2F0%2F0%2F0 (GigabitEthernet0/0/0/0) is
+ * requested via GET HTTP operation. It is tested whether %2F character is replaced with simple / in
+ * InstanceIdentifier parameter in method
+ * {@link BrokerFacade#readConfigurationData(DOMMountPoint, YangInstanceIdentifier)} which is called in
+ * method {@link RestconfImpl#readConfigurationData}
+ */
+ @Test
+ public void getDataWithSlashesBehindMountPoint() throws Exception {
+ final YangInstanceIdentifier awaitedInstanceIdentifier = prepareInstanceIdentifierForList();
+ when(brokerFacade.readConfigurationData(any(DOMMountPoint.class), eq(awaitedInstanceIdentifier),
+ isNull())).thenReturn(prepareCnDataForSlashesBehindMountPointTest());
+ when(mountInstance.getService(DOMSchemaService.class))
+ .thenReturn(Optional.of(FixedDOMSchemaService.of(schemaContextTestModule)));
+
+ final String uri = "/config/ietf-interfaces:interfaces/interface/0/yang-ext:mount/"
+ + "test-module:cont/lst1/GigabitEthernet0%2F0%2F0%2F0";
+ assertEquals(200, get(uri, MediaType.APPLICATION_XML));
+ }
+
+ private static YangInstanceIdentifier prepareInstanceIdentifierForList() throws Exception {
+ final List<PathArgument> parameters = new ArrayList<>();
+
+ final QName qNameCont = newTestModuleQName("cont");
+ final QName qNameList = newTestModuleQName("lst1");
+ final QName qNameKeyList = newTestModuleQName("lf11");
+
+ parameters.add(new NodeIdentifier(qNameCont));
+ parameters.add(new NodeIdentifier(qNameList));
+ parameters.add(NodeIdentifierWithPredicates.of(qNameList, qNameKeyList, "GigabitEthernet0/0/0/0"));
+ return YangInstanceIdentifier.create(parameters);
+ }
+
+ private static QName newTestModuleQName(final String localPart) throws Exception {
+ return QName.create("test:module", "2014-01-09", localPart);
+ }
+
+ @Test
+ public void getDataMountPointIntoHighestElement() throws Exception {
+ when(brokerFacade.readConfigurationData(any(DOMMountPoint.class), any(YangInstanceIdentifier.class),
+ isNull())).thenReturn(prepareCnDataForMountPointTest(true));
+ when(mountInstance.getService(DOMSchemaService.class))
+ .thenReturn(Optional.of(FixedDOMSchemaService.of(schemaContextTestModule)));
+
+ final String uri = "/config/ietf-interfaces:interfaces/interface/0/yang-ext:mount/test-module:cont";
+ assertEquals(200, get(uri, MediaType.APPLICATION_XML));
+ }
+
+ @Test
+ public void getDataWithIdentityrefInURL() throws Exception {
+ setControllerContext(schemaContextTestModule);
+
+ final QName moduleQN = newTestModuleQName("module");
+ final ImmutableMap<QName, Object> keyMap = ImmutableMap.of(
+ newTestModuleQName("type"), newTestModuleQName("test-identity"),
+ newTestModuleQName("name"), "foo");
+ final YangInstanceIdentifier iid = YangInstanceIdentifier.builder().node(newTestModuleQName("modules"))
+ .node(moduleQN).nodeWithKey(moduleQN, keyMap).build();
+ final NormalizedNode data = ImmutableMapNodeBuilder.create()
+ .withNodeIdentifier(new NodeIdentifier(moduleQN))
+ .withChild(ImmutableNodes.mapEntryBuilder()
+ .withNodeIdentifier(NodeIdentifierWithPredicates.of(moduleQN, keyMap))
+ .withChild(ImmutableNodes.leafNode(newTestModuleQName("type"), newTestModuleQName("test-identity")))
+ .withChild(ImmutableNodes.leafNode(newTestModuleQName("name"), "foo"))
+ .withChild(ImmutableNodes.leafNode(newTestModuleQName("data"), "bar")).build()).build();
+ when(brokerFacade.readConfigurationData(iid, null)).thenReturn(data);
+
+ final String uri = "/config/test-module:modules/module/test-module:test-identity/foo";
+ assertEquals(200, get(uri, MediaType.APPLICATION_XML));
+ }
+
+ // /modules
+ @Test
+ public void getModulesTest() throws Exception {
+ setControllerContext(schemaContextModules);
+
+ final String uri = "/modules";
+
+ Response response = target(uri).request("application/yang.api+json").get();
+ validateModulesResponseJson(response);
+
+ response = target(uri).request("application/yang.api+xml").get();
+ validateModulesResponseXml(response,schemaContextModules);
+ }
+
+ // /streams/
+ @Test
+ @Ignore // FIXME : find why it is fail by in gerrit build
+ public void getStreamsTest() throws Exception {
+ setControllerContext(schemaContextModules);
+
+ final String uri = "/streams";
+
+ Response response = target(uri).request("application/yang.api+json").get();
+ final String responseBody = response.readEntity(String.class);
+ assertEquals(200, response.getStatus());
+ assertNotNull(responseBody);
+ assertTrue(responseBody.contains("streams"));
+
+ response = target(uri).request("application/yang.api+xml").get();
+ assertEquals(200, response.getStatus());
+ final Document responseXmlBody = response.readEntity(Document.class);
+ assertNotNull(responseXmlBody);
+ final Element rootNode = responseXmlBody.getDocumentElement();
+
+ assertEquals("streams", rootNode.getLocalName());
+ assertEquals(RESTCONF_NS, rootNode.getNamespaceURI());
+ }
+
+ // /modules/module
+ @Test
+ public void getModuleTest() throws Exception {
+ setControllerContext(schemaContextModules);
+
+ final String uri = "/modules/module/module2/2014-01-02";
+
+ Response response = target(uri).request("application/yang.api+xml").get();
+ assertEquals(200, response.getStatus());
+ final Document responseXml = response.readEntity(Document.class);
+
+ final QName qname = assertedModuleXmlToModuleQName(responseXml.getDocumentElement());
+ assertNotNull(qname);
+
+ assertEquals("module2", qname.getLocalName());
+ assertEquals("module:2", qname.getNamespace().toString());
+ assertEquals("2014-01-02", qname.getRevision().get().toString());
+
+ response = target(uri).request("application/yang.api+json").get();
+ assertEquals(200, response.getStatus());
+ final String responseBody = response.readEntity(String.class);
+ assertTrue("Module2 in json wasn't found", prepareJsonRegex("module2", "2014-01-02", "module:2", responseBody)
+ .find());
+ final String[] split = responseBody.split("\"module\"");
+ assertEquals("\"module\" element is returned more then once", 2, split.length);
+
+ }
+
+ // /operations
+ @Ignore
+ @Test
+ public void getOperationsTest() throws Exception {
+ setControllerContext(schemaContextModules);
+
+ final String uri = "/operations";
+
+ Response response = target(uri).request("application/yang.api+xml").get();
+ assertEquals(500, response.getStatus());
+ final Document responseDoc = response.readEntity(Document.class);
+ validateOperationsResponseXml(responseDoc, schemaContextModules);
+
+ response = target(uri).request("application/yang.api+json").get();
+ assertEquals(200, response.getStatus());
+ final String responseBody = response.readEntity(String.class);
+ assertTrue("Json response for /operations dummy-rpc1-module1 is incorrect",
+ validateOperationsResponseJson(responseBody, "dummy-rpc1-module1", "module1").find());
+ assertTrue("Json response for /operations dummy-rpc2-module1 is incorrect",
+ validateOperationsResponseJson(responseBody, "dummy-rpc2-module1", "module1").find());
+ assertTrue("Json response for /operations dummy-rpc1-module2 is incorrect",
+ validateOperationsResponseJson(responseBody, "dummy-rpc1-module2", "module2").find());
+ assertTrue("Json response for /operations dummy-rpc2-module2 is incorrect",
+ validateOperationsResponseJson(responseBody, "dummy-rpc2-module2", "module2").find());
+ }
+
+ private static void validateOperationsResponseXml(final Document responseDoc, final SchemaContext schemaContext) {
+
+ final Element operationsElem = responseDoc.getDocumentElement();
+ assertEquals(RESTCONF_NS, operationsElem.getNamespaceURI());
+ assertEquals("operations", operationsElem.getLocalName());
+
+ final NodeList operationsList = operationsElem.getChildNodes();
+ final HashSet<String> foundOperations = new HashSet<>();
+
+ for (int i = 0; i < operationsList.getLength(); i++) {
+ final org.w3c.dom.Node operation = operationsList.item(i);
+ foundOperations.add(operation.getLocalName());
+ }
+
+ for (final RpcDefinition schemaOp : schemaContext.getOperations()) {
+ assertTrue(foundOperations.contains(schemaOp.getQName().getLocalName()));
+ }
+ }
+
+ // /operations/pathToMountPoint/yang-ext:mount
+ @Ignore
+ @Test
+ public void getOperationsBehindMountPointTest() throws Exception {
+ setControllerContext(schemaContextModules);
+
+ mockMountPoint();
+
+ final String uri = "/operations/ietf-interfaces:interfaces/interface/0/yang-ext:mount/";
+
+ Response response = target(uri).request("application/yang.api+xml").get();
+ assertEquals(500, response.getStatus());
+
+ final Document responseDoc = response.readEntity(Document.class);
+ validateOperationsResponseXml(responseDoc, schemaContextBehindMountPoint);
+
+ response = target(uri).request("application/yang.api+json").get();
+ assertEquals(200, response.getStatus());
+ final String responseBody = response.readEntity(String.class);
+ assertTrue("Json response for /operations/mount_point rpc-behind-module1 is incorrect",
+ validateOperationsResponseJson(responseBody, "rpc-behind-module1", "module1-behind-mount-point").find());
+ assertTrue("Json response for /operations/mount_point rpc-behind-module2 is incorrect",
+ validateOperationsResponseJson(responseBody, "rpc-behind-module2", "module2-behind-mount-point").find());
+
+ }
+
+ private static Matcher validateOperationsResponseJson(final String searchIn, final String rpcName,
+ final String moduleName) {
+ final StringBuilder regex = new StringBuilder();
+ regex.append(".*\"" + rpcName + "\"");
+ final Pattern ptrn = Pattern.compile(regex.toString(), Pattern.DOTALL);
+ return ptrn.matcher(searchIn);
+
+ }
+
+ // /restconf/modules/pathToMountPoint/yang-ext:mount
+ @Test
+ public void getModulesBehindMountPoint() throws Exception {
+ setControllerContext(schemaContextModules);
+
+ mockMountPoint();
+
+ final String uri = "/modules/ietf-interfaces:interfaces/interface/0/yang-ext:mount/";
+
+ Response response = target(uri).request("application/yang.api+json").get();
+ assertEquals(200, response.getStatus());
+ final String responseBody = response.readEntity(String.class);
+
+ assertTrue(
+ "module1-behind-mount-point in json wasn't found",
+ prepareJsonRegex("module1-behind-mount-point", "2014-02-03", "module:1:behind:mount:point",
+ responseBody).find());
+ assertTrue(
+ "module2-behind-mount-point in json wasn't found",
+ prepareJsonRegex("module2-behind-mount-point", "2014-02-04", "module:2:behind:mount:point",
+ responseBody).find());
+
+ response = target(uri).request("application/yang.api+xml").get();
+ assertEquals(200, response.getStatus());
+ validateModulesResponseXml(response, schemaContextBehindMountPoint);
+
+ }
+
+ // /restconf/modules/module/pathToMountPoint/yang-ext:mount/moduleName/revision
+ @Test
+ public void getModuleBehindMountPoint() throws Exception {
+ setControllerContext(schemaContextModules);
+
+ mockMountPoint();
+
+ final String uri = "/modules/module/ietf-interfaces:interfaces/interface/0/yang-ext:mount/"
+ + "module1-behind-mount-point/2014-02-03";
+
+ Response response = target(uri).request("application/yang.api+json").get();
+ assertEquals(200, response.getStatus());
+ final String responseBody = response.readEntity(String.class);
+
+ assertTrue(
+ "module1-behind-mount-point in json wasn't found",
+ prepareJsonRegex("module1-behind-mount-point", "2014-02-03", "module:1:behind:mount:point",
+ responseBody).find());
+ final String[] split = responseBody.split("\"module\"");
+ assertEquals("\"module\" element is returned more then once", 2, split.length);
+
+ response = target(uri).request("application/yang.api+xml").get();
+ assertEquals(200, response.getStatus());
+ final Document responseXml = response.readEntity(Document.class);
+
+ final QName module = assertedModuleXmlToModuleQName(responseXml.getDocumentElement());
+
+ assertEquals("module1-behind-mount-point", module.getLocalName());
+ assertEquals("2014-02-03", module.getRevision().get().toString());
+ assertEquals("module:1:behind:mount:point", module.getNamespace().toString());
+ }
+
+ private static void validateModulesResponseXml(final Response response, final SchemaContext schemaContext) {
+ assertEquals(200, response.getStatus());
+ final Document responseBody = response.readEntity(Document.class);
+ final NodeList moduleNodes = responseBody.getDocumentElement().getElementsByTagNameNS(RESTCONF_NS, "module");
+
+ assertTrue(moduleNodes.getLength() > 0);
+
+ final HashSet<QName> foundModules = new HashSet<>();
+
+ for (int i = 0; i < moduleNodes.getLength(); i++) {
+ final org.w3c.dom.Node module = moduleNodes.item(i);
+
+ final QName name = assertedModuleXmlToModuleQName(module);
+ foundModules.add(name);
+ }
+
+ assertAllModules(foundModules,schemaContext);
+ }
+
+ private static void assertAllModules(final Set<QName> foundModules, final SchemaContext schemaContext) {
+ for (final Module module : schemaContext.getModules()) {
+ final QName current = QName.create(module.getQNameModule(), module.getName());
+ assertTrue("Module not found in response.", foundModules.contains(current));
+ }
+
+ }
+
+ private static QName assertedModuleXmlToModuleQName(final org.w3c.dom.Node module) {
+ assertEquals("module", module.getLocalName());
+ assertEquals(RESTCONF_NS, module.getNamespaceURI());
+ String revision = null;
+ String namespace = null;
+ String name = null;
+
+
+ final NodeList childNodes = module.getChildNodes();
+
+ for (int i = 0; i < childNodes.getLength(); i++) {
+ final org.w3c.dom.Node child = childNodes.item(i);
+ assertEquals(RESTCONF_NS, child.getNamespaceURI());
+
+ switch (child.getLocalName()) {
+ case "name":
+ assertNull("Name element appeared multiple times", name);
+ name = child.getTextContent().trim();
+ break;
+ case "revision":
+ assertNull("Revision element appeared multiple times", revision);
+ revision = child.getTextContent().trim();
+ break;
+ case "namespace":
+ assertNull("Namespace element appeared multiple times", namespace);
+ namespace = child.getTextContent().trim();
+ break;
+ default:
+ break;
+ }
+ }
+
+ assertNotNull("Revision was not part of xml",revision);
+ assertNotNull("Module namespace was not part of xml",namespace);
+ assertNotNull("Module identiffier was not part of xml",name);
+
+ return QName.create(namespace,revision,name);
+ }
+
+ private static void validateModulesResponseJson(final Response response) {
+ assertEquals(200, response.getStatus());
+ final String responseBody = response.readEntity(String.class);
+
+ assertTrue("Module1 in json wasn't found", prepareJsonRegex("module1", "2014-01-01", "module:1", responseBody)
+ .find());
+ assertTrue("Module2 in json wasn't found", prepareJsonRegex("module2", "2014-01-02", "module:2", responseBody)
+ .find());
+ assertTrue("Module3 in json wasn't found", prepareJsonRegex("module3", "2014-01-03", "module:3", responseBody)
+ .find());
+ }
+
+ private static Matcher prepareJsonRegex(final String module, final String revision, final String namespace,
+ final String searchIn) {
+ final StringBuilder regex = new StringBuilder();
+ regex.append("^");
+
+ regex.append(".*\\{");
+ regex.append(".*\"name\"");
+ regex.append(".*:");
+ regex.append(".*\"" + module + "\",");
+
+ regex.append(".*\"revision\"");
+ regex.append(".*:");
+ regex.append(".*\"" + revision + "\",");
+
+ regex.append(".*\"namespace\"");
+ regex.append(".*:");
+ regex.append(".*\"" + namespace + "\"");
+
+ regex.append(".*\\}");
+
+ regex.append(".*");
+ regex.append("$");
+ final Pattern ptrn = Pattern.compile(regex.toString(), Pattern.DOTALL);
+ return ptrn.matcher(searchIn);
+
+ }
+
+
+ private int get(final String uri, final String mediaType) {
+ return target(uri).request(mediaType).get().getStatus();
+ }
+
+ /**
+ * Container structure.
+ *
+ * <p>
+ * container cont {
+ * container cont1 {
+ * leaf lf11 {
+ * type string;
+ * }
+ */
+ private static NormalizedNode prepareCnDataForMountPointTest(final boolean wrapToCont) throws Exception {
+ final String testModuleDate = "2014-01-09";
+ final ContainerNode contChild = Builders
+ .containerBuilder()
+ .withNodeIdentifier(TestUtils.getNodeIdentifier("cont1", "test:module", testModuleDate))
+ .withChild(
+ Builders.leafBuilder()
+ .withNodeIdentifier(TestUtils.getNodeIdentifier("lf11", "test:module", testModuleDate))
+ .withValue("lf11 value").build()).build();
+
+ if (wrapToCont) {
+ return Builders.containerBuilder()
+ .withNodeIdentifier(TestUtils.getNodeIdentifier("cont", "test:module", testModuleDate))
+ .withChild(contChild).build();
+ }
+ return contChild;
+
+ }
+
+ private void mockReadOperationalDataMethod() {
+ when(brokerFacade.readOperationalData(any(YangInstanceIdentifier.class))).thenReturn(answerFromGet);
+ }
+
+ private void mockReadConfigurationDataMethod() {
+ when(brokerFacade.readConfigurationData(any(YangInstanceIdentifier.class), isNull()))
+ .thenReturn(answerFromGet);
+ }
+
+ private static NormalizedNode prepareCnDataForSlashesBehindMountPointTest() throws Exception {
+ return ImmutableMapEntryNodeBuilder.create()
+ .withNodeIdentifier(
+ TestUtils.getNodeIdentifierPredicate("lst1", "test:module", "2014-01-09", "lf11",
+ "GigabitEthernet0/0/0/0"))
+ .withChild(
+ ImmutableLeafNodeBuilder.create()
+ .withNodeIdentifier(TestUtils.getNodeIdentifier("lf11", "test:module", "2014-01-09"))
+ .withValue("GigabitEthernet0/0/0/0").build()).build();
+
+ }
+
+ /**
+ * If includeWhiteChars URI parameter is set to false then no white characters can be included in returned output.
+ */
+ @Test
+ public void getDataWithUriIncludeWhiteCharsParameterTest() throws Exception {
+ getDataWithUriIncludeWhiteCharsParameter("config");
+ getDataWithUriIncludeWhiteCharsParameter("operational");
+ }
+
+ private void getDataWithUriIncludeWhiteCharsParameter(final String target) throws Exception {
+ mockReadConfigurationDataMethod();
+ mockReadOperationalDataMethod();
+ final String uri = "/" + target + "/ietf-interfaces:interfaces/interface/eth0";
+ Response response = target(uri).queryParam("prettyPrint", "false").request("application/xml").get();
+ final String xmlData = response.readEntity(String.class);
+
+ Pattern pattern = Pattern.compile(".*(>\\s+|\\s+<).*", Pattern.DOTALL);
+ Matcher matcher = pattern.matcher(xmlData);
+ // XML element can't surrounded with white character (e.g "> " or
+ // " <")
+ assertFalse(matcher.matches());
+
+ response = target(uri).queryParam("prettyPrint", "false").request("application/json").get();
+ final String jsonData = response.readEntity(String.class);
+ pattern = Pattern.compile(".*(\\}\\s+|\\s+\\{|\\]\\s+|\\s+\\[|\\s+:|:\\s+).*", Pattern.DOTALL);
+ matcher = pattern.matcher(jsonData);
+ // JSON element can't surrounded with white character (e.g "} ", " {",
+ // "] ", " [", " :" or ": ")
+ assertFalse(matcher.matches());
+ }
+
+ /**
+ * Tests behavior when invalid value of depth URI parameter.
+ */
+ @Test
+ @Ignore
+ public void getDataWithInvalidDepthParameterTest() {
+ setControllerContext(schemaContextModules);
+
+ final MultivaluedMap<String, String> paramMap = new MultivaluedHashMap<>();
+ paramMap.putSingle("depth", "1o");
+ final UriInfo mockInfo = mock(UriInfo.class);
+ when(mockInfo.getQueryParameters(false)).thenAnswer(invocation -> paramMap);
+
+ getDataWithInvalidDepthParameterTest(mockInfo);
+
+ paramMap.putSingle("depth", "0");
+ getDataWithInvalidDepthParameterTest(mockInfo);
+
+ paramMap.putSingle("depth", "-1");
+ getDataWithInvalidDepthParameterTest(mockInfo);
+ }
+
+ private void getDataWithInvalidDepthParameterTest(final UriInfo uriInfo) {
+ try {
+ final QName qNameDepth1Cont = QName.create("urn:nested:module", "2014-06-3", "depth1-cont");
+ final YangInstanceIdentifier ii = YangInstanceIdentifier.builder().node(qNameDepth1Cont).build();
+ final NormalizedNode value =
+ Builders.containerBuilder().withNodeIdentifier(new NodeIdentifier(qNameDepth1Cont)).build();
+ when(brokerFacade.readConfigurationData(eq(ii))).thenReturn(value);
+ restconfImpl.readConfigurationData("nested-module:depth1-cont", uriInfo);
+ fail("Expected RestconfDocumentedException");
+ } catch (final RestconfDocumentedException e) {
+ assertTrue("Unexpected error message: " + e.getErrors().get(0).getErrorMessage(), e.getErrors().get(0)
+ .getErrorMessage().contains("depth"));
+ }
+ }
+
+ @SuppressWarnings("unused")
+ private void verifyXMLResponse(final Response response, final NodeData nodeData) {
+ final Document doc = response.readEntity(Document.class);
+ assertNotNull("Could not parse XML document", doc);
+
+ verifyContainerElement(doc.getDocumentElement(), nodeData);
+ }
+
+ @SuppressWarnings("unchecked")
+ private void verifyContainerElement(final Element element, final NodeData nodeData) {
+
+ assertEquals("Element local name", nodeData.key, element.getLocalName());
+
+ final NodeList childNodes = element.getChildNodes();
+ if (nodeData.data == null) { // empty container
+ assertTrue(
+ "Expected no child elements for \"" + element.getLocalName() + "\"", childNodes.getLength() == 0);
+ return;
+ }
+
+ final Map<String, NodeData> expChildMap = new HashMap<>();
+ for (final NodeData expChild : (List<NodeData>) nodeData.data) {
+ expChildMap.put(expChild.key.toString(), expChild);
+ }
+
+ for (int i = 0; i < childNodes.getLength(); i++) {
+ final org.w3c.dom.Node actualChild = childNodes.item(i);
+ if (!(actualChild instanceof Element)) {
+ continue;
+ }
+
+ final Element actualElement = (Element) actualChild;
+ final NodeData expChild = expChildMap.remove(actualElement.getLocalName());
+ assertNotNull(
+ "Unexpected child element for parent \"" + element.getLocalName() + "\": "
+ + actualElement.getLocalName(), expChild);
+
+ if (expChild.data == null || expChild.data instanceof List) {
+ verifyContainerElement(actualElement, expChild);
+ } else {
+ assertEquals("Text content for element: " + actualElement.getLocalName(), expChild.data,
+ actualElement.getTextContent());
+ }
+ }
+
+ if (!expChildMap.isEmpty()) {
+ fail("Missing elements for parent \"" + element.getLocalName() + "\": " + expChildMap.keySet());
+ }
+ }
+
+ private void mockMountPoint() {
+ when(mountInstance.getService(DOMSchemaService.class))
+ .thenReturn(Optional.of(FixedDOMSchemaService.of(schemaContextBehindMountPoint)));
+ }
+}
diff --git a/netconf/restconf/restconf-nb-bierman02/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/RestOperationUtils.java b/netconf/restconf/restconf-nb-bierman02/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/RestOperationUtils.java
new file mode 100644
index 0000000..bdc9679
--- /dev/null
+++ b/netconf/restconf/restconf-nb-bierman02/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/RestOperationUtils.java
@@ -0,0 +1,17 @@
+/*
+ * Copyright (c) 2014 Cisco Systems, Inc. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.controller.sal.restconf.impl.test;
+
+public final class RestOperationUtils {
+
+ public static final String JSON = "+json";
+ public static final String XML = "+xml";
+
+ private RestOperationUtils() {
+ }
+}
diff --git a/netconf/restconf/restconf-nb-bierman02/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/RestPostOperationTest.java b/netconf/restconf/restconf-nb-bierman02/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/RestPostOperationTest.java
new file mode 100644
index 0000000..3aa6a9c
--- /dev/null
+++ b/netconf/restconf/restconf-nb-bierman02/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/RestPostOperationTest.java
@@ -0,0 +1,182 @@
+/*
+ * Copyright (c) 2014 Cisco Systems, Inc. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.controller.sal.restconf.impl.test;
+
+import static org.junit.Assert.assertEquals;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.isNull;
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+import static org.opendaylight.controller.sal.restconf.impl.test.RestOperationUtils.XML;
+
+import com.google.common.collect.ImmutableList;
+import com.google.common.util.concurrent.FluentFuture;
+import java.io.IOException;
+import java.io.UnsupportedEncodingException;
+import java.net.URISyntaxException;
+import java.text.ParseException;
+import java.util.Optional;
+import javax.ws.rs.client.Entity;
+import javax.ws.rs.core.Application;
+import javax.ws.rs.core.MediaType;
+import org.glassfish.jersey.server.ResourceConfig;
+import org.glassfish.jersey.test.JerseyTest;
+import org.junit.BeforeClass;
+import org.junit.Ignore;
+import org.junit.Test;
+import org.mockito.ArgumentCaptor;
+import org.opendaylight.controller.md.sal.rest.common.TestRestconfUtils;
+import org.opendaylight.mdsal.common.api.CommitInfo;
+import org.opendaylight.mdsal.dom.api.DOMMountPoint;
+import org.opendaylight.mdsal.dom.api.DOMSchemaService;
+import org.opendaylight.mdsal.dom.spi.FixedDOMSchemaService;
+import org.opendaylight.netconf.sal.rest.api.Draft02;
+import org.opendaylight.netconf.sal.rest.impl.JsonNormalizedNodeBodyReader;
+import org.opendaylight.netconf.sal.rest.impl.NormalizedNodeJsonBodyWriter;
+import org.opendaylight.netconf.sal.rest.impl.NormalizedNodeXmlBodyWriter;
+import org.opendaylight.netconf.sal.rest.impl.RestconfDocumentedExceptionMapper;
+import org.opendaylight.netconf.sal.rest.impl.XmlNormalizedNodeBodyReader;
+import org.opendaylight.netconf.sal.restconf.impl.BrokerFacade;
+import org.opendaylight.netconf.sal.restconf.impl.ControllerContext;
+import org.opendaylight.netconf.sal.restconf.impl.RestconfImpl;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
+import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
+import org.opendaylight.yangtools.yang.model.api.EffectiveModelContext;
+
+public class RestPostOperationTest extends JerseyTest {
+
+ private static String xmlBlockData;
+ private static String xmlData3;
+ private static String xmlData4;
+
+ private static EffectiveModelContext schemaContextYangsIetf;
+ private static EffectiveModelContext schemaContextTestModule;
+ private static EffectiveModelContext schemaContext;
+
+ private BrokerFacade brokerFacade;
+ private RestconfImpl restconfImpl;
+ private ControllerContext controllerContext;
+ private DOMMountPoint mountInstance;
+
+ @BeforeClass
+ public static void init() throws URISyntaxException, IOException {
+ schemaContextYangsIetf = TestUtils.loadSchemaContext("/full-versions/yangs");
+ schemaContextTestModule = TestUtils.loadSchemaContext("/full-versions/test-module");
+ schemaContext = TestUtils.loadSchemaContext("/test-config-data/yang1");
+ loadData();
+ }
+
+ @Override
+ protected Application configure() {
+ /* enable/disable Jersey logs to console */
+ // enable(TestProperties.LOG_TRAFFIC);
+ // enable(TestProperties.DUMP_ENTITY);
+ // enable(TestProperties.RECORD_LOG_LEVEL);
+ // set(TestProperties.RECORD_LOG_LEVEL, Level.ALL.intValue());
+
+ mountInstance = mock(DOMMountPoint.class);
+ controllerContext = TestRestconfUtils.newControllerContext(schemaContext, mountInstance);
+ brokerFacade = mock(BrokerFacade.class);
+ restconfImpl = RestconfImpl.newInstance(brokerFacade, controllerContext);
+
+ ResourceConfig resourceConfig = new ResourceConfig();
+ resourceConfig = resourceConfig.registerInstances(restconfImpl,
+ new XmlNormalizedNodeBodyReader(controllerContext), new NormalizedNodeXmlBodyWriter(),
+ new JsonNormalizedNodeBodyReader(controllerContext), new NormalizedNodeJsonBodyWriter(),
+ new RestconfDocumentedExceptionMapper(controllerContext));
+ return resourceConfig;
+ }
+
+ private void setSchemaControllerContext(final EffectiveModelContext schema) {
+ controllerContext.setSchemas(schema);
+ }
+
+ @SuppressWarnings("unchecked")
+ @Test
+ @Ignore /// xmlData* need netconf-yang
+ public void postDataViaUrlMountPoint() throws UnsupportedEncodingException {
+ setSchemaControllerContext(schemaContextYangsIetf);
+ when(brokerFacade.commitConfigurationDataPost(any(DOMMountPoint.class), any(YangInstanceIdentifier.class),
+ any(NormalizedNode.class), null, null)).thenReturn(mock(FluentFuture.class));
+
+ when(mountInstance.getService(DOMSchemaService.class))
+ .thenReturn(Optional.of(FixedDOMSchemaService.of(schemaContextTestModule)));
+
+ String uri = "/config/ietf-interfaces:interfaces/interface/0/";
+ assertEquals(204, post(uri, Draft02.MediaTypes.DATA + XML, xmlData4));
+ uri = "/config/ietf-interfaces:interfaces/interface/0/yang-ext:mount/test-module:cont";
+ assertEquals(204, post(uri, Draft02.MediaTypes.DATA + XML, xmlData3));
+
+ assertEquals(400, post(uri, MediaType.APPLICATION_JSON, ""));
+ }
+
+ @SuppressWarnings("unchecked")
+ @Test
+ @Ignore //jenkins has problem with JerseyTest
+ // - we expecting problems with singletons ControllerContext as schemaContext holder
+ public void createConfigurationDataTest() throws UnsupportedEncodingException, ParseException {
+ when(brokerFacade.commitConfigurationDataPost((EffectiveModelContext) null, any(YangInstanceIdentifier.class),
+ any(NormalizedNode.class), null, null))
+ .thenReturn(mock(FluentFuture.class));
+
+ final ArgumentCaptor<YangInstanceIdentifier> instanceIdCaptor =
+ ArgumentCaptor.forClass(YangInstanceIdentifier.class);
+ final ArgumentCaptor<NormalizedNode> compNodeCaptor = ArgumentCaptor.forClass(NormalizedNode.class);
+
+
+ // FIXME : identify who is set the schemaContext
+// final String URI_1 = "/config";
+// assertEquals(204, post(URI_1, Draft02.MediaTypes.DATA + XML, xmlTestInterface));
+// verify(brokerFacade).commitConfigurationDataPost(instanceIdCaptor.capture(), compNodeCaptor.capture());
+ final String identifier = "[(urn:ietf:params:xml:ns:yang:test-interface?revision=2014-07-01)interfaces]";
+// assertEquals(identifier, ImmutableList.copyOf(instanceIdCaptor.getValue().getPathArguments()).toString());
+
+ final String URI_2 = "/config/test-interface:interfaces";
+ assertEquals(204, post(URI_2, Draft02.MediaTypes.DATA + XML, xmlBlockData));
+ // FIXME : NEVER test a nr. of call some service in complex test suite
+// verify(brokerFacade, times(2))
+ verify(brokerFacade, times(1))
+ .commitConfigurationDataPost((EffectiveModelContext) null, instanceIdCaptor.capture(),
+ compNodeCaptor.capture(), null, null);
+// identifier = "[(urn:ietf:params:xml:ns:yang:test-interface?revision=2014-07-01)interfaces," +
+// "(urn:ietf:params:xml:ns:yang:test-interface?revision=2014-07-01)block]";
+ assertEquals(identifier, ImmutableList.copyOf(instanceIdCaptor.getValue().getPathArguments()).toString());
+ }
+
+ @Test
+ public void createConfigurationDataNullTest() throws UnsupportedEncodingException {
+ doReturn(CommitInfo.emptyFluentFuture()).when(brokerFacade).commitConfigurationDataPost(
+ any(EffectiveModelContext.class), any(YangInstanceIdentifier.class), any(NormalizedNode.class), isNull(),
+ isNull());
+
+ //FIXME : find who is set schemaContext
+// final String URI_1 = "/config";
+// assertEquals(204, post(URI_1, Draft02.MediaTypes.DATA + XML, xmlTestInterface));
+
+ final String URI_2 = "/config/test-interface:interfaces";
+ assertEquals(204, post(URI_2, Draft02.MediaTypes.DATA + XML, xmlBlockData));
+ }
+
+ private int post(final String uri, final String mediaType, final String data) {
+ return target(uri).request(mediaType).post(Entity.entity(data, mediaType)).getStatus();
+ }
+
+ private static void loadData() throws IOException, URISyntaxException {
+ final String xmlPathBlockData =
+ RestconfImplTest.class.getResource("/test-config-data/xml/block-data.xml").getPath();
+ xmlBlockData = TestUtils.loadTextFile(xmlPathBlockData);
+ final String data3Input = RestconfImplTest.class.getResource("/full-versions/test-data2/data3.xml").getPath();
+ xmlData3 = TestUtils.loadTextFile(data3Input);
+ final String data4Input = RestconfImplTest.class.getResource("/full-versions/test-data2/data7.xml").getPath();
+ xmlData4 = TestUtils.loadTextFile(data4Input);
+ }
+
+}
diff --git a/netconf/restconf/restconf-nb-bierman02/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/RestPutConfigTest.java b/netconf/restconf/restconf-nb-bierman02/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/RestPutConfigTest.java
new file mode 100644
index 0000000..9cd03d8
--- /dev/null
+++ b/netconf/restconf/restconf-nb-bierman02/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/RestPutConfigTest.java
@@ -0,0 +1,135 @@
+/*
+ * Copyright (c) 2015 Cisco Systems, Inc. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.controller.sal.restconf.impl.test;
+
+import java.io.FileNotFoundException;
+import java.util.HashSet;
+import javax.ws.rs.core.MultivaluedMap;
+import javax.ws.rs.core.Response.Status;
+import javax.ws.rs.core.UriInfo;
+import org.junit.Before;
+import org.junit.BeforeClass;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.Mockito;
+import org.mockito.junit.MockitoJUnitRunner;
+import org.opendaylight.controller.md.sal.rest.common.TestRestconfUtils;
+import org.opendaylight.mdsal.common.api.CommitInfo;
+import org.opendaylight.netconf.sal.rest.impl.NormalizedNodeContext;
+import org.opendaylight.netconf.sal.restconf.impl.BrokerFacade;
+import org.opendaylight.netconf.sal.restconf.impl.ControllerContext;
+import org.opendaylight.netconf.sal.restconf.impl.PutResult;
+import org.opendaylight.netconf.sal.restconf.impl.RestconfImpl;
+import org.opendaylight.restconf.common.context.InstanceIdentifierContext;
+import org.opendaylight.restconf.common.errors.RestconfDocumentedException;
+import org.opendaylight.yangtools.yang.common.QName;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifierWithPredicates;
+import org.opendaylight.yangtools.yang.data.api.schema.MapEntryNode;
+import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
+import org.opendaylight.yangtools.yang.model.api.EffectiveModelContext;
+
+@RunWith(MockitoJUnitRunner.class)
+public class RestPutConfigTest {
+
+ private static EffectiveModelContext schemaContext;
+ private RestconfImpl restconfService;
+ private ControllerContext controllerCx;
+
+ @Mock
+ private BrokerFacade brokerFacade;
+
+ @BeforeClass
+ public static void staticInit() throws FileNotFoundException {
+ schemaContext = TestRestconfUtils.loadSchemaContext("/test-config-data/yang1/", null);
+ }
+
+ @Before
+ public void init() {
+ controllerCx = TestRestconfUtils.newControllerContext(schemaContext);
+ restconfService = RestconfImpl.newInstance(brokerFacade, controllerCx);
+ }
+
+ @Test
+ public void testPutConfigData() {
+ final String identifier = "test-interface:interfaces/interface/key";
+ final InstanceIdentifierContext iiCx = controllerCx.toInstanceIdentifier(identifier);
+ final MapEntryNode data = Mockito.mock(MapEntryNode.class);
+ final QName qName = QName.create("urn:ietf:params:xml:ns:yang:test-interface", "2014-07-01", "interface");
+ final QName qNameKey = QName.create("urn:ietf:params:xml:ns:yang:test-interface", "2014-07-01", "name");
+ final NodeIdentifierWithPredicates identWithPredicates =
+ NodeIdentifierWithPredicates.of(qName, qNameKey, "key");
+ Mockito.when(data.getIdentifier()).thenReturn(identWithPredicates);
+ final NormalizedNodeContext payload = new NormalizedNodeContext(iiCx, data);
+
+ mockingBrokerPut(iiCx.getInstanceIdentifier(), data);
+
+ final UriInfo uriInfo = Mockito.mock(UriInfo.class);
+ final MultivaluedMap<String, String> value = Mockito.mock(MultivaluedMap.class);
+ Mockito.when(value.entrySet()).thenReturn(new HashSet<>());
+ Mockito.when(uriInfo.getQueryParameters()).thenReturn(value);
+ restconfService.updateConfigurationData(identifier, payload, uriInfo);
+ }
+
+ @Test
+ public void testPutConfigDataCheckOnlyLastElement() {
+ final String identifier = "test-interface:interfaces/interface/key/sub-interface/subkey";
+ final InstanceIdentifierContext iiCx = controllerCx.toInstanceIdentifier(identifier);
+ final MapEntryNode data = Mockito.mock(MapEntryNode.class);
+ final QName qName = QName.create("urn:ietf:params:xml:ns:yang:test-interface", "2014-07-01", "sub-interface");
+ final QName qNameSubKey = QName.create("urn:ietf:params:xml:ns:yang:test-interface", "2014-07-01", "sub-name");
+ final NodeIdentifierWithPredicates identWithPredicates =
+ NodeIdentifierWithPredicates.of(qName, qNameSubKey, "subkey");
+ Mockito.when(data.getIdentifier()).thenReturn(identWithPredicates);
+ final NormalizedNodeContext payload = new NormalizedNodeContext(iiCx, data);
+
+ mockingBrokerPut(iiCx.getInstanceIdentifier(), data);
+
+ final UriInfo uriInfo = Mockito.mock(UriInfo.class);
+ final MultivaluedMap<String, String> value = Mockito.mock(MultivaluedMap.class);
+ Mockito.when(value.entrySet()).thenReturn(new HashSet<>());
+ Mockito.when(uriInfo.getQueryParameters()).thenReturn(value);
+ restconfService.updateConfigurationData(identifier, payload, uriInfo);
+ }
+
+ @Test(expected = RestconfDocumentedException.class)
+ public void testPutConfigDataMissingUriKey() {
+ final String identifier = "test-interface:interfaces/interface";
+ controllerCx.toInstanceIdentifier(identifier);
+ }
+
+ @Test(expected = RestconfDocumentedException.class)
+ public void testPutConfigDataDiferentKey() {
+ final String identifier = "test-interface:interfaces/interface/key";
+ final InstanceIdentifierContext iiCx = controllerCx.toInstanceIdentifier(identifier);
+ final MapEntryNode data = Mockito.mock(MapEntryNode.class);
+ final QName qName = QName.create("urn:ietf:params:xml:ns:yang:test-interface", "2014-07-01", "interface");
+ final QName qNameKey = QName.create("urn:ietf:params:xml:ns:yang:test-interface", "2014-07-01", "name");
+ final NodeIdentifierWithPredicates identWithPredicates =
+ NodeIdentifierWithPredicates.of(qName, qNameKey, "notSameKey");
+ Mockito.when(data.getIdentifier()).thenReturn(identWithPredicates);
+ final NormalizedNodeContext payload = new NormalizedNodeContext(iiCx, data);
+
+ mockingBrokerPut(iiCx.getInstanceIdentifier(), data);
+
+ final UriInfo uriInfo = Mockito.mock(UriInfo.class);
+ final MultivaluedMap<String, String> value = Mockito.mock(MultivaluedMap.class);
+ Mockito.when(value.entrySet()).thenReturn(new HashSet<>());
+ Mockito.when(uriInfo.getQueryParameters()).thenReturn(value);
+ restconfService.updateConfigurationData(identifier, payload, uriInfo);
+ }
+
+ private void mockingBrokerPut(final YangInstanceIdentifier yii, final NormalizedNode data) {
+ final PutResult result = Mockito.mock(PutResult.class);
+ Mockito.when(brokerFacade.commitConfigurationDataPut(schemaContext, yii, data, null, null))
+ .thenReturn(result);
+ Mockito.doReturn(CommitInfo.emptyFluentFuture()).when(result).getFutureOfPutData();
+ Mockito.when(result.getStatus()).thenReturn(Status.OK);
+ }
+}
diff --git a/netconf/restconf/restconf-nb-bierman02/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/RestPutOperationTest.java b/netconf/restconf/restconf-nb-bierman02/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/RestPutOperationTest.java
new file mode 100644
index 0000000..8c04e50
--- /dev/null
+++ b/netconf/restconf/restconf-nb-bierman02/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/RestPutOperationTest.java
@@ -0,0 +1,220 @@
+/*
+ * Copyright (c) 2014 Cisco Systems, Inc. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.controller.sal.restconf.impl.test;
+
+import static org.junit.Assert.assertEquals;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.doThrow;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.UnsupportedEncodingException;
+import java.net.URISyntaxException;
+import java.util.Optional;
+import javax.ws.rs.client.Entity;
+import javax.ws.rs.core.Application;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.Response;
+import javax.ws.rs.core.Response.Status;
+import org.glassfish.jersey.server.ResourceConfig;
+import org.glassfish.jersey.test.JerseyTest;
+import org.junit.BeforeClass;
+import org.junit.Ignore;
+import org.junit.Test;
+import org.opendaylight.controller.md.sal.rest.common.TestRestconfUtils;
+import org.opendaylight.mdsal.common.api.CommitInfo;
+import org.opendaylight.mdsal.common.api.OptimisticLockFailedException;
+import org.opendaylight.mdsal.common.api.TransactionCommitFailedException;
+import org.opendaylight.mdsal.dom.api.DOMMountPoint;
+import org.opendaylight.mdsal.dom.api.DOMSchemaService;
+import org.opendaylight.mdsal.dom.spi.FixedDOMSchemaService;
+import org.opendaylight.netconf.sal.rest.impl.JsonNormalizedNodeBodyReader;
+import org.opendaylight.netconf.sal.rest.impl.NormalizedNodeJsonBodyWriter;
+import org.opendaylight.netconf.sal.rest.impl.NormalizedNodeXmlBodyWriter;
+import org.opendaylight.netconf.sal.rest.impl.RestconfDocumentedExceptionMapper;
+import org.opendaylight.netconf.sal.rest.impl.XmlNormalizedNodeBodyReader;
+import org.opendaylight.netconf.sal.restconf.impl.BrokerFacade;
+import org.opendaylight.netconf.sal.restconf.impl.ControllerContext;
+import org.opendaylight.netconf.sal.restconf.impl.PutResult;
+import org.opendaylight.netconf.sal.restconf.impl.RestconfImpl;
+import org.opendaylight.restconf.common.errors.RestconfDocumentedException;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
+import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
+import org.opendaylight.yangtools.yang.model.api.EffectiveModelContext;
+import org.opendaylight.yangtools.yang.parser.spi.meta.ReactorException;
+
+//TODO UNSTABLE TESTS - FIX ME
+@Ignore
+public class RestPutOperationTest extends JerseyTest {
+
+ private static String xmlData;
+ private static String xmlData2;
+ private static String xmlData3;
+
+ private static EffectiveModelContext schemaContextYangsIetf;
+ private static EffectiveModelContext schemaContextTestModule;
+
+ private BrokerFacade brokerFacade;
+ private RestconfImpl restconfImpl;
+ private DOMMountPoint mountInstance;
+
+ @BeforeClass
+ public static void init() throws IOException, ReactorException {
+ schemaContextYangsIetf = TestUtils.loadSchemaContext("/full-versions/yangs");
+ schemaContextTestModule = TestUtils.loadSchemaContext("/full-versions/test-module");
+ loadData();
+ }
+
+ private static void loadData() throws IOException {
+ final InputStream xmlStream =
+ RestconfImplTest.class.getResourceAsStream("/parts/ietf-interfaces_interfaces.xml");
+ xmlData = TestUtils.getDocumentInPrintableForm(TestUtils.loadDocumentFrom(xmlStream));
+ final InputStream xmlStream2 =
+ RestconfImplTest.class.getResourceAsStream("/full-versions/test-data2/data2.xml");
+ xmlData2 = TestUtils.getDocumentInPrintableForm(TestUtils.loadDocumentFrom(xmlStream2));
+ final InputStream xmlStream3 =
+ RestconfImplTest.class.getResourceAsStream("/full-versions/test-data2/data7.xml");
+ xmlData3 = TestUtils.getDocumentInPrintableForm(TestUtils.loadDocumentFrom(xmlStream3));
+ }
+
+ @Override
+ protected Application configure() {
+ /* enable/disable Jersey logs to console */
+ // enable(TestProperties.LOG_TRAFFIC);
+ // enable(TestProperties.DUMP_ENTITY);
+ // enable(TestProperties.RECORD_LOG_LEVEL);
+ // set(TestProperties.RECORD_LOG_LEVEL, Level.ALL.intValue());
+
+ mountInstance = mock(DOMMountPoint.class);
+ final ControllerContext controllerContext =
+ TestRestconfUtils.newControllerContext(schemaContextYangsIetf, mountInstance);
+ brokerFacade = mock(BrokerFacade.class);
+ restconfImpl = RestconfImpl.newInstance(brokerFacade, controllerContext);
+
+ ResourceConfig resourceConfig = new ResourceConfig();
+ resourceConfig = resourceConfig.registerInstances(restconfImpl,
+ new XmlNormalizedNodeBodyReader(controllerContext), new NormalizedNodeXmlBodyWriter(),
+ new JsonNormalizedNodeBodyReader(controllerContext), new NormalizedNodeJsonBodyWriter(),
+ new RestconfDocumentedExceptionMapper(controllerContext));
+ return resourceConfig;
+ }
+
+ /**
+ * Tests of status codes for "/config/{identifier}".
+ */
+ @Test
+ public void putConfigStatusCodes() throws UnsupportedEncodingException {
+ final String uri = "/config/ietf-interfaces:interfaces/interface/eth0";
+ mockCommitConfigurationDataPutMethod(true);
+ assertEquals(500, put(uri, MediaType.APPLICATION_XML, xmlData));
+
+ mockCommitConfigurationDataPutMethod(false);
+ assertEquals(500, put(uri, MediaType.APPLICATION_XML, xmlData));
+
+ assertEquals(400, put(uri, MediaType.APPLICATION_JSON, ""));
+ }
+
+ @Test
+ public void putConfigStatusCodesEmptyBody() throws UnsupportedEncodingException {
+ final String uri = "/config/ietf-interfaces:interfaces/interface/eth0";
+ @SuppressWarnings("unused")
+ final Response resp = target(uri).request(MediaType.APPLICATION_JSON).put(
+ Entity.entity("", MediaType.APPLICATION_JSON));
+ assertEquals(400, put(uri, MediaType.APPLICATION_JSON, ""));
+ }
+
+ @Test
+ public void testRpcResultCommitedToStatusCodesWithMountPoint() throws UnsupportedEncodingException,
+ FileNotFoundException, URISyntaxException {
+ final PutResult result = mock(PutResult.class);
+ when(brokerFacade.commitMountPointDataPut(any(DOMMountPoint.class), any(YangInstanceIdentifier.class),
+ any(NormalizedNode.class), null, null)).thenReturn(result);
+ doReturn(CommitInfo.emptyFluentFuture()).when(result).getFutureOfPutData();
+ when(result.getStatus()).thenReturn(Status.OK);
+
+ mockMountPoint();
+
+ String uri = "/config/ietf-interfaces:interfaces/interface/0/yang-ext:mount/test-module:cont";
+ assertEquals(200, put(uri, MediaType.APPLICATION_XML, xmlData2));
+
+ uri = "/config/ietf-interfaces:interfaces/yang-ext:mount/test-module:cont";
+ assertEquals(200, put(uri, MediaType.APPLICATION_XML, xmlData2));
+ }
+
+ @Test
+ public void putDataMountPointIntoHighestElement() throws UnsupportedEncodingException, URISyntaxException {
+ final PutResult result = mock(PutResult.class);
+ doReturn(result).when(brokerFacade).commitMountPointDataPut(any(DOMMountPoint.class),
+ any(YangInstanceIdentifier.class), any(NormalizedNode.class), null, null);
+ doReturn(CommitInfo.emptyFluentFuture()).when(result).getFutureOfPutData();
+ when(result.getStatus()).thenReturn(Status.OK);
+
+ mockMountPoint();
+
+ final String uri = "/config/ietf-interfaces:interfaces/yang-ext:mount";
+ assertEquals(200, put(uri, MediaType.APPLICATION_XML, xmlData3));
+ }
+
+ @Test
+ public void putWithOptimisticLockFailedException() throws UnsupportedEncodingException {
+
+ final String uri = "/config/ietf-interfaces:interfaces/interface/eth0";
+
+ doThrow(OptimisticLockFailedException.class).when(brokerFacade).commitConfigurationDataPut(
+ any(EffectiveModelContext.class), any(YangInstanceIdentifier.class), any(NormalizedNode.class), null,
+ null);
+
+ assertEquals(500, put(uri, MediaType.APPLICATION_XML, xmlData));
+
+ doThrow(OptimisticLockFailedException.class).doReturn(mock(PutResult.class)).when(brokerFacade)
+ .commitConfigurationDataPut(any(EffectiveModelContext.class), any(YangInstanceIdentifier.class),
+ any(NormalizedNode.class), null, null);
+
+ assertEquals(500, put(uri, MediaType.APPLICATION_XML, xmlData));
+ }
+
+ @Test
+ public void putWithTransactionCommitFailedException() throws UnsupportedEncodingException {
+
+ final String uri = "/config/ietf-interfaces:interfaces/interface/eth0";
+
+ doThrow(TransactionCommitFailedException.class)
+ .when(brokerFacade).commitConfigurationDataPut(
+ any(EffectiveModelContext.class), any(YangInstanceIdentifier.class), any(NormalizedNode.class),
+ null, null);
+
+ assertEquals(500, put(uri, MediaType.APPLICATION_XML, xmlData));
+ }
+
+ private int put(final String uri, final String mediaType, final String data) throws UnsupportedEncodingException {
+ return target(uri).request(mediaType).put(Entity.entity(data, mediaType)).getStatus();
+ }
+
+ private void mockMountPoint() {
+ when(mountInstance.getService(DOMSchemaService.class))
+ .thenReturn(Optional.of(FixedDOMSchemaService.of(schemaContextTestModule)));
+ }
+
+ private void mockCommitConfigurationDataPutMethod(final boolean noErrors) {
+ final PutResult putResMock = mock(PutResult.class);
+ if (noErrors) {
+ doReturn(putResMock).when(brokerFacade).commitConfigurationDataPut(
+ any(EffectiveModelContext.class), any(YangInstanceIdentifier.class), any(NormalizedNode.class),
+ null, null);
+ } else {
+ doThrow(RestconfDocumentedException.class).when(brokerFacade).commitConfigurationDataPut(
+ any(EffectiveModelContext.class), any(YangInstanceIdentifier.class), any(NormalizedNode.class),
+ null, null);
+ }
+ }
+
+}
diff --git a/netconf/restconf/restconf-nb-bierman02/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/RestconfDocumentedExceptionMapperTest.java b/netconf/restconf/restconf-nb-bierman02/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/RestconfDocumentedExceptionMapperTest.java
new file mode 100644
index 0000000..f4ddb35
--- /dev/null
+++ b/netconf/restconf/restconf-nb-bierman02/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/RestconfDocumentedExceptionMapperTest.java
@@ -0,0 +1,831 @@
+/*
+ * Copyright (c) 2014 Brocade Communications Systems, Inc. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.controller.sal.restconf.impl.test;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.reset;
+import static org.mockito.Mockito.when;
+
+import com.google.common.collect.Iterators;
+import com.google.gson.JsonArray;
+import com.google.gson.JsonElement;
+import com.google.gson.JsonParser;
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.Set;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+import javax.ws.rs.core.Application;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.Response;
+import javax.ws.rs.core.Response.Status;
+import javax.ws.rs.core.UriInfo;
+import javax.xml.namespace.NamespaceContext;
+import javax.xml.xpath.XPath;
+import javax.xml.xpath.XPathConstants;
+import javax.xml.xpath.XPathExpression;
+import javax.xml.xpath.XPathFactory;
+import org.glassfish.jersey.server.ResourceConfig;
+import org.glassfish.jersey.test.JerseyTest;
+import org.junit.Before;
+import org.junit.BeforeClass;
+import org.junit.Ignore;
+import org.junit.Test;
+import org.opendaylight.controller.md.sal.rest.common.TestRestconfUtils;
+import org.opendaylight.netconf.sal.rest.api.Draft02;
+import org.opendaylight.netconf.sal.rest.api.RestconfService;
+import org.opendaylight.netconf.sal.rest.impl.JsonNormalizedNodeBodyReader;
+import org.opendaylight.netconf.sal.rest.impl.NormalizedNodeContext;
+import org.opendaylight.netconf.sal.rest.impl.NormalizedNodeJsonBodyWriter;
+import org.opendaylight.netconf.sal.rest.impl.NormalizedNodeXmlBodyWriter;
+import org.opendaylight.netconf.sal.rest.impl.RestconfDocumentedExceptionMapper;
+import org.opendaylight.netconf.sal.rest.impl.XmlNormalizedNodeBodyReader;
+import org.opendaylight.netconf.sal.restconf.impl.ControllerContext;
+import org.opendaylight.restconf.common.errors.RestconfDocumentedException;
+import org.opendaylight.restconf.common.errors.RestconfError;
+import org.opendaylight.yangtools.util.xml.UntrustedXML;
+import org.opendaylight.yangtools.yang.common.ErrorTag;
+import org.opendaylight.yangtools.yang.common.ErrorType;
+import org.opendaylight.yangtools.yang.model.api.EffectiveModelContext;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.w3c.dom.Document;
+import org.w3c.dom.Node;
+import org.w3c.dom.NodeList;
+import org.xml.sax.SAXException;
+
+/**
+ * Unit tests for RestconfDocumentedExceptionMapper.
+ *
+ * @author Thomas Pantelis
+ */
+public class RestconfDocumentedExceptionMapperTest extends JerseyTest {
+
+ interface ErrorInfoVerifier {
+ void verifyXML(Node errorInfoNode);
+
+ void verifyJson(JsonElement errorInfoElement);
+ }
+
+ static class SimpleErrorInfoVerifier implements ErrorInfoVerifier {
+
+ String expTextContent;
+
+ SimpleErrorInfoVerifier(final String expErrorInfo) {
+ expTextContent = expErrorInfo;
+ }
+
+ void verifyContent(final String actualContent) {
+ assertNotNull("Actual \"error-info\" text content is null", actualContent);
+ assertTrue("", actualContent.contains(expTextContent));
+ }
+
+ @Override
+ public void verifyXML(final Node errorInfoNode) {
+ verifyContent(errorInfoNode.getTextContent());
+ }
+
+ @Override
+ public void verifyJson(final JsonElement errorInfoElement) {
+ verifyContent(errorInfoElement.getAsString());
+ }
+ }
+
+ private static final Logger LOG = LoggerFactory.getLogger(RestconfDocumentedExceptionMapperTest.class);
+ private static final String IETF_RESTCONF = "ietf-restconf";
+ static RestconfService mockRestConf = mock(RestconfService.class);
+
+ static XPath XPATH = XPathFactory.newInstance().newXPath();
+ static XPathExpression ERROR_LIST;
+ static XPathExpression ERROR_TYPE;
+ static XPathExpression ERROR_TAG;
+ static XPathExpression ERROR_MESSAGE;
+ static XPathExpression ERROR_APP_TAG;
+ static XPathExpression ERROR_INFO;
+
+ private static EffectiveModelContext schemaContext;
+
+ @BeforeClass
+ public static void init() throws Exception {
+ schemaContext = TestUtils.loadSchemaContext("/modules");
+
+ final NamespaceContext nsContext = new NamespaceContext() {
+ @Override
+ public Iterator<String> getPrefixes(final String namespaceURI) {
+ return Iterators.singletonIterator(IETF_RESTCONF);
+ }
+
+ @Override
+ public String getPrefix(final String namespaceURI) {
+ return null;
+ }
+
+ @Override
+ public String getNamespaceURI(final String prefix) {
+ return IETF_RESTCONF.equals(prefix) ? Draft02.RestConfModule.NAMESPACE : null;
+ }
+ };
+
+ XPATH.setNamespaceContext(nsContext);
+ ERROR_LIST = XPATH.compile("ietf-restconf:errors/ietf-restconf:error");
+ ERROR_TYPE = XPATH.compile("ietf-restconf:error-type");
+ ERROR_TAG = XPATH.compile("ietf-restconf:error-tag");
+ ERROR_MESSAGE = XPATH.compile("ietf-restconf:error-message");
+ ERROR_APP_TAG = XPATH.compile("ietf-restconf:error-app-tag");
+ ERROR_INFO = XPATH.compile("ietf-restconf:error-info");
+ }
+
+ @Override
+ @Before
+ public void setUp() throws Exception {
+ reset(mockRestConf);
+ super.setUp();
+ }
+
+ @Override
+ protected Application configure() {
+ ResourceConfig resourceConfig = new ResourceConfig();
+ ControllerContext controllerContext = TestRestconfUtils.newControllerContext(schemaContext);
+ resourceConfig = resourceConfig.registerInstances(mockRestConf,
+ new XmlNormalizedNodeBodyReader(controllerContext), new JsonNormalizedNodeBodyReader(controllerContext),
+ new NormalizedNodeJsonBodyWriter(), new NormalizedNodeXmlBodyWriter(),
+ new RestconfDocumentedExceptionMapper(controllerContext));
+ return resourceConfig;
+ }
+
+ void stageMockEx(final RestconfDocumentedException ex) {
+ reset(mockRestConf);
+ when(mockRestConf.readOperationalData(any(String.class), any(UriInfo.class))).thenThrow(ex);
+ }
+
+ void testJsonResponse(final RestconfDocumentedException ex, final Status expStatus, final ErrorType expErrorType,
+ final ErrorTag expErrorTag, final String expErrorMessage, final String expErrorAppTag,
+ final ErrorInfoVerifier errorInfoVerifier) throws Exception {
+
+ stageMockEx(ex);
+
+ final Response resp = target("/operational/foo").request(MediaType.APPLICATION_JSON).get();
+
+ final InputStream stream = verifyResponse(resp, MediaType.APPLICATION_JSON, expStatus);
+
+ verifyJsonResponseBody(stream, expErrorType, expErrorTag, expErrorMessage, expErrorAppTag, errorInfoVerifier);
+ }
+
+ @Test
+ public void testToJsonResponseWithMessageOnly() throws Exception {
+
+ testJsonResponse(new RestconfDocumentedException("mock error"), Status.INTERNAL_SERVER_ERROR,
+ ErrorType.APPLICATION, ErrorTag.OPERATION_FAILED, "mock error", null, null);
+
+
+ // To test verification code
+ // String json =
+ // "{ errors: {" +
+ // " error: [{" +
+ // " error-tag : \"operation-failed\"" +
+ // " ,error-type : \"application\"" +
+ // " ,error-message : \"An error occurred\"" +
+ // " ,error-info : {" +
+ // " session-id: \"123\"" +
+ // " ,address: \"1.2.3.4\"" +
+ // " }" +
+ // " }]" +
+ // " }" +
+ // "}";
+ //
+ // verifyJsonResponseBody( new java.io.StringBufferInputStream(json ),
+ // ErrorType.APPLICATION,
+ // ErrorTag.OPERATION_FAILED, "An error occurred", null,
+ // com.google.common.collect.ImmutableMap.of( "session-id", "123",
+ // "address", "1.2.3.4" ) );
+ }
+
+ @Test
+ public void testToJsonResponseWithInUseErrorTag() throws Exception {
+
+ testJsonResponse(new RestconfDocumentedException("mock error", ErrorType.PROTOCOL, ErrorTag.IN_USE),
+ Status.CONFLICT, ErrorType.PROTOCOL, ErrorTag.IN_USE, "mock error", null, null);
+ }
+
+ @Test
+ public void testToJsonResponseWithInvalidValueErrorTag() throws Exception {
+
+ testJsonResponse(new RestconfDocumentedException("mock error", ErrorType.RPC, ErrorTag.INVALID_VALUE),
+ Status.BAD_REQUEST, ErrorType.RPC, ErrorTag.INVALID_VALUE, "mock error", null, null);
+
+ }
+
+ @Test
+ public void testToJsonResponseWithTooBigErrorTag() throws Exception {
+
+ testJsonResponse(new RestconfDocumentedException("mock error", ErrorType.TRANSPORT, ErrorTag.TOO_BIG),
+ Status.REQUEST_ENTITY_TOO_LARGE, ErrorType.TRANSPORT, ErrorTag.TOO_BIG, "mock error", null, null);
+
+ }
+
+ @Test
+ public void testToJsonResponseWithMissingAttributeErrorTag() throws Exception {
+
+ testJsonResponse(new RestconfDocumentedException("mock error", ErrorType.PROTOCOL, ErrorTag.MISSING_ATTRIBUTE),
+ Status.BAD_REQUEST, ErrorType.PROTOCOL, ErrorTag.MISSING_ATTRIBUTE, "mock error", null, null);
+ }
+
+ @Test
+ public void testToJsonResponseWithBadAttributeErrorTag() throws Exception {
+
+ testJsonResponse(new RestconfDocumentedException("mock error", ErrorType.PROTOCOL, ErrorTag.BAD_ATTRIBUTE),
+ Status.BAD_REQUEST, ErrorType.PROTOCOL, ErrorTag.BAD_ATTRIBUTE, "mock error", null, null);
+ }
+
+ @Test
+ public void testToJsonResponseWithUnknownAttributeErrorTag() throws Exception {
+
+ testJsonResponse(new RestconfDocumentedException("mock error", ErrorType.PROTOCOL, ErrorTag.UNKNOWN_ATTRIBUTE),
+ Status.BAD_REQUEST, ErrorType.PROTOCOL, ErrorTag.UNKNOWN_ATTRIBUTE, "mock error", null, null);
+ }
+
+ @Test
+ public void testToJsonResponseWithBadElementErrorTag() throws Exception {
+
+ testJsonResponse(new RestconfDocumentedException("mock error", ErrorType.PROTOCOL, ErrorTag.BAD_ELEMENT),
+ Status.BAD_REQUEST, ErrorType.PROTOCOL, ErrorTag.BAD_ELEMENT, "mock error", null, null);
+ }
+
+ @Test
+ public void testToJsonResponseWithUnknownElementErrorTag() throws Exception {
+
+ testJsonResponse(new RestconfDocumentedException("mock error", ErrorType.PROTOCOL, ErrorTag.UNKNOWN_ELEMENT),
+ Status.BAD_REQUEST, ErrorType.PROTOCOL, ErrorTag.UNKNOWN_ELEMENT, "mock error", null, null);
+ }
+
+ @Test
+ public void testToJsonResponseWithUnknownNamespaceErrorTag() throws Exception {
+
+ testJsonResponse(new RestconfDocumentedException("mock error", ErrorType.PROTOCOL, ErrorTag.UNKNOWN_NAMESPACE),
+ Status.BAD_REQUEST, ErrorType.PROTOCOL, ErrorTag.UNKNOWN_NAMESPACE, "mock error", null, null);
+ }
+
+ @Test
+ public void testToJsonResponseWithMalformedMessageErrorTag() throws Exception {
+
+ testJsonResponse(new RestconfDocumentedException("mock error", ErrorType.PROTOCOL, ErrorTag.MALFORMED_MESSAGE),
+ Status.BAD_REQUEST, ErrorType.PROTOCOL, ErrorTag.MALFORMED_MESSAGE, "mock error", null, null);
+ }
+
+ @Test
+ public void testToJsonResponseWithAccessDeniedErrorTag() throws Exception {
+
+ testJsonResponse(new RestconfDocumentedException("mock error", ErrorType.PROTOCOL, ErrorTag.ACCESS_DENIED),
+ Status.FORBIDDEN, ErrorType.PROTOCOL, ErrorTag.ACCESS_DENIED, "mock error", null, null);
+ }
+
+ @Test
+ public void testToJsonResponseWithLockDeniedErrorTag() throws Exception {
+
+ testJsonResponse(new RestconfDocumentedException("mock error", ErrorType.PROTOCOL, ErrorTag.LOCK_DENIED),
+ Status.CONFLICT, ErrorType.PROTOCOL, ErrorTag.LOCK_DENIED, "mock error", null, null);
+ }
+
+ @Test
+ public void testToJsonResponseWithResourceDeniedErrorTag() throws Exception {
+
+ testJsonResponse(new RestconfDocumentedException("mock error", ErrorType.PROTOCOL, ErrorTag.RESOURCE_DENIED),
+ Status.CONFLICT, ErrorType.PROTOCOL, ErrorTag.RESOURCE_DENIED, "mock error", null, null);
+ }
+
+ @Test
+ public void testToJsonResponseWithRollbackFailedErrorTag() throws Exception {
+
+ testJsonResponse(new RestconfDocumentedException("mock error", ErrorType.PROTOCOL, ErrorTag.ROLLBACK_FAILED),
+ Status.INTERNAL_SERVER_ERROR, ErrorType.PROTOCOL, ErrorTag.ROLLBACK_FAILED, "mock error", null, null);
+ }
+
+ @Test
+ public void testToJsonResponseWithDataExistsErrorTag() throws Exception {
+
+ testJsonResponse(new RestconfDocumentedException("mock error", ErrorType.PROTOCOL, ErrorTag.DATA_EXISTS),
+ Status.CONFLICT, ErrorType.PROTOCOL, ErrorTag.DATA_EXISTS, "mock error", null, null);
+ }
+
+ @Test
+ public void testToJsonResponseWithDataMissingErrorTag() throws Exception {
+
+ testJsonResponse(new RestconfDocumentedException("mock error", ErrorType.PROTOCOL, ErrorTag.DATA_MISSING),
+ Status.CONFLICT, ErrorType.PROTOCOL, ErrorTag.DATA_MISSING, "mock error", null, null);
+ }
+
+ @Test
+ public void testToJsonResponseWithOperationNotSupportedErrorTag() throws Exception {
+
+ testJsonResponse(new RestconfDocumentedException("mock error", ErrorType.PROTOCOL,
+ ErrorTag.OPERATION_NOT_SUPPORTED), Status.NOT_IMPLEMENTED, ErrorType.PROTOCOL,
+ ErrorTag.OPERATION_NOT_SUPPORTED, "mock error", null, null);
+ }
+
+ @Test
+ public void testToJsonResponseWithOperationFailedErrorTag() throws Exception {
+
+ testJsonResponse(new RestconfDocumentedException("mock error", ErrorType.PROTOCOL, ErrorTag.OPERATION_FAILED),
+ Status.INTERNAL_SERVER_ERROR, ErrorType.PROTOCOL, ErrorTag.OPERATION_FAILED, "mock error", null, null);
+ }
+
+ @Test
+ public void testToJsonResponseWithPartialOperationErrorTag() throws Exception {
+
+ testJsonResponse(new RestconfDocumentedException("mock error", ErrorType.PROTOCOL, ErrorTag.PARTIAL_OPERATION),
+ Status.INTERNAL_SERVER_ERROR, ErrorType.PROTOCOL, ErrorTag.PARTIAL_OPERATION, "mock error", null, null);
+ }
+
+ @Test
+ public void testToJsonResponseWithErrorAppTag() throws Exception {
+
+ testJsonResponse(new RestconfDocumentedException(new RestconfError(ErrorType.APPLICATION,
+ ErrorTag.INVALID_VALUE, "mock error", "mock-app-tag")), Status.BAD_REQUEST, ErrorType.APPLICATION,
+ ErrorTag.INVALID_VALUE, "mock error", "mock-app-tag", null);
+ }
+
+ @Test
+ @Ignore // FIXME : find why it return "error-type" RPC no expected APPLICATION
+ public void testToJsonResponseWithMultipleErrors() throws Exception {
+
+ final List<RestconfError> errorList = Arrays.asList(
+ new RestconfError(ErrorType.APPLICATION, ErrorTag.LOCK_DENIED, "mock error1"),
+ new RestconfError(ErrorType.RPC, ErrorTag.ROLLBACK_FAILED, "mock error2"));
+ stageMockEx(new RestconfDocumentedException("mock", null, errorList));
+
+ final Response resp = target("/operational/foo").request(MediaType.APPLICATION_JSON).get();
+
+ final InputStream stream = verifyResponse(resp, MediaType.APPLICATION_JSON, Status.CONFLICT);
+
+ final JsonArray arrayElement = parseJsonErrorArrayElement(stream);
+
+ assertEquals("\"error\" Json array element length", 2, arrayElement.size());
+
+ verifyJsonErrorNode(
+ arrayElement.get(0), ErrorType.APPLICATION, ErrorTag.LOCK_DENIED, "mock error1", null, null);
+
+ verifyJsonErrorNode(arrayElement.get(1), ErrorType.RPC, ErrorTag.ROLLBACK_FAILED, "mock error2", null, null);
+ }
+
+ @Test
+ public void testToJsonResponseWithErrorInfo() throws Exception {
+
+ final String errorInfo = "<address>1.2.3.4</address> <session-id>123</session-id>";
+ testJsonResponse(new RestconfDocumentedException(new RestconfError(ErrorType.APPLICATION,
+ ErrorTag.INVALID_VALUE, "mock error", "mock-app-tag", errorInfo)), Status.BAD_REQUEST,
+ ErrorType.APPLICATION, ErrorTag.INVALID_VALUE, "mock error", "mock-app-tag",
+ new SimpleErrorInfoVerifier(errorInfo));
+ }
+
+ @Test
+ public void testToJsonResponseWithExceptionCause() throws Exception {
+
+ final Exception cause = new Exception("mock exception cause");
+ testJsonResponse(new RestconfDocumentedException("mock error", cause), Status.INTERNAL_SERVER_ERROR,
+ ErrorType.APPLICATION, ErrorTag.OPERATION_FAILED, "mock error", null,
+ new SimpleErrorInfoVerifier(cause.getMessage()));
+ }
+
+ void testXMLResponse(final RestconfDocumentedException ex, final Status expStatus, final ErrorType expErrorType,
+ final ErrorTag expErrorTag, final String expErrorMessage, final String expErrorAppTag,
+ final ErrorInfoVerifier errorInfoVerifier) throws Exception {
+ stageMockEx(ex);
+
+ final Response resp = target("/operational/foo").request(MediaType.APPLICATION_XML).get();
+
+ final InputStream stream = verifyResponse(resp, MediaType.APPLICATION_XML, expStatus);
+
+ verifyXMLResponseBody(stream, expErrorType, expErrorTag, expErrorMessage, expErrorAppTag, errorInfoVerifier);
+ }
+
+ @Test
+ public void testToXMLResponseWithMessageOnly() throws Exception {
+
+ testXMLResponse(new RestconfDocumentedException("mock error"), Status.INTERNAL_SERVER_ERROR,
+ ErrorType.APPLICATION, ErrorTag.OPERATION_FAILED, "mock error", null, null);
+
+ // To test verification code
+ // String xml =
+ // "<errors xmlns=\"urn:ietf:params:xml:ns:yang:ietf-restconf\">"+
+ // " <error>" +
+ // " <error-type>application</error-type>"+
+ // " <error-tag>operation-failed</error-tag>"+
+ // " <error-message>An error occurred</error-message>"+
+ // " <error-info>" +
+ // " <session-id>123</session-id>" +
+ // " <address>1.2.3.4</address>" +
+ // " </error-info>" +
+ // " </error>" +
+ // "</errors>";
+ //
+ // verifyXMLResponseBody( new java.io.StringBufferInputStream(xml),
+ // ErrorType.APPLICATION,
+ // ErrorTag.OPERATION_FAILED, "An error occurred", null,
+ // com.google.common.collect.ImmutableMap.of( "session-id", "123",
+ // "address", "1.2.3.4" ) );
+ }
+
+ @Test
+ public void testToXMLResponseWithInUseErrorTag() throws Exception {
+
+ testXMLResponse(new RestconfDocumentedException("mock error", ErrorType.PROTOCOL, ErrorTag.IN_USE),
+ Status.CONFLICT, ErrorType.PROTOCOL, ErrorTag.IN_USE, "mock error", null, null);
+ }
+
+ @Test
+ public void testToXMLResponseWithInvalidValueErrorTag() throws Exception {
+
+ testXMLResponse(new RestconfDocumentedException("mock error", ErrorType.RPC, ErrorTag.INVALID_VALUE),
+ Status.BAD_REQUEST, ErrorType.RPC, ErrorTag.INVALID_VALUE, "mock error", null, null);
+ }
+
+ @Test
+ public void testToXMLResponseWithTooBigErrorTag() throws Exception {
+
+ testXMLResponse(new RestconfDocumentedException("mock error", ErrorType.TRANSPORT, ErrorTag.TOO_BIG),
+ Status.REQUEST_ENTITY_TOO_LARGE, ErrorType.TRANSPORT, ErrorTag.TOO_BIG, "mock error", null, null);
+ }
+
+ @Test
+ public void testToXMLResponseWithMissingAttributeErrorTag() throws Exception {
+
+ testXMLResponse(new RestconfDocumentedException("mock error", ErrorType.PROTOCOL, ErrorTag.MISSING_ATTRIBUTE),
+ Status.BAD_REQUEST, ErrorType.PROTOCOL, ErrorTag.MISSING_ATTRIBUTE, "mock error", null, null);
+ }
+
+ @Test
+ public void testToXMLResponseWithBadAttributeErrorTag() throws Exception {
+
+ testXMLResponse(new RestconfDocumentedException("mock error", ErrorType.PROTOCOL, ErrorTag.BAD_ATTRIBUTE),
+ Status.BAD_REQUEST, ErrorType.PROTOCOL, ErrorTag.BAD_ATTRIBUTE, "mock error", null, null);
+ }
+
+ @Test
+ public void testToXMLResponseWithUnknownAttributeErrorTag() throws Exception {
+
+ testXMLResponse(new RestconfDocumentedException("mock error", ErrorType.PROTOCOL, ErrorTag.UNKNOWN_ATTRIBUTE),
+ Status.BAD_REQUEST, ErrorType.PROTOCOL, ErrorTag.UNKNOWN_ATTRIBUTE, "mock error", null, null);
+ }
+
+ @Test
+ public void testToXMLResponseWithBadElementErrorTag() throws Exception {
+
+ testXMLResponse(new RestconfDocumentedException("mock error", ErrorType.PROTOCOL, ErrorTag.BAD_ELEMENT),
+ Status.BAD_REQUEST, ErrorType.PROTOCOL, ErrorTag.BAD_ELEMENT, "mock error", null, null);
+ }
+
+ @Test
+ public void testToXMLResponseWithUnknownElementErrorTag() throws Exception {
+
+ testXMLResponse(new RestconfDocumentedException("mock error", ErrorType.PROTOCOL, ErrorTag.UNKNOWN_ELEMENT),
+ Status.BAD_REQUEST, ErrorType.PROTOCOL, ErrorTag.UNKNOWN_ELEMENT, "mock error", null, null);
+ }
+
+ @Test
+ public void testToXMLResponseWithUnknownNamespaceErrorTag() throws Exception {
+
+ testXMLResponse(new RestconfDocumentedException("mock error", ErrorType.PROTOCOL, ErrorTag.UNKNOWN_NAMESPACE),
+ Status.BAD_REQUEST, ErrorType.PROTOCOL, ErrorTag.UNKNOWN_NAMESPACE, "mock error", null, null);
+ }
+
+ @Test
+ public void testToXMLResponseWithMalformedMessageErrorTag() throws Exception {
+
+ testXMLResponse(new RestconfDocumentedException("mock error", ErrorType.PROTOCOL, ErrorTag.MALFORMED_MESSAGE),
+ Status.BAD_REQUEST, ErrorType.PROTOCOL, ErrorTag.MALFORMED_MESSAGE, "mock error", null, null);
+ }
+
+ @Test
+ public void testToXMLResponseWithAccessDeniedErrorTag() throws Exception {
+
+ testXMLResponse(new RestconfDocumentedException("mock error", ErrorType.PROTOCOL, ErrorTag.ACCESS_DENIED),
+ Status.FORBIDDEN, ErrorType.PROTOCOL, ErrorTag.ACCESS_DENIED, "mock error", null, null);
+ }
+
+ @Test
+ public void testToXMLResponseWithLockDeniedErrorTag() throws Exception {
+
+ testXMLResponse(new RestconfDocumentedException("mock error", ErrorType.PROTOCOL, ErrorTag.LOCK_DENIED),
+ Status.CONFLICT, ErrorType.PROTOCOL, ErrorTag.LOCK_DENIED, "mock error", null, null);
+ }
+
+ @Test
+ public void testToXMLResponseWithResourceDeniedErrorTag() throws Exception {
+
+ testXMLResponse(new RestconfDocumentedException("mock error", ErrorType.PROTOCOL, ErrorTag.RESOURCE_DENIED),
+ Status.CONFLICT, ErrorType.PROTOCOL, ErrorTag.RESOURCE_DENIED, "mock error", null, null);
+ }
+
+ @Test
+ public void testToXMLResponseWithRollbackFailedErrorTag() throws Exception {
+
+ testXMLResponse(new RestconfDocumentedException("mock error", ErrorType.PROTOCOL, ErrorTag.ROLLBACK_FAILED),
+ Status.INTERNAL_SERVER_ERROR, ErrorType.PROTOCOL, ErrorTag.ROLLBACK_FAILED, "mock error", null, null);
+ }
+
+ @Test
+ public void testToXMLResponseWithDataExistsErrorTag() throws Exception {
+
+ testXMLResponse(new RestconfDocumentedException("mock error", ErrorType.PROTOCOL, ErrorTag.DATA_EXISTS),
+ Status.CONFLICT, ErrorType.PROTOCOL, ErrorTag.DATA_EXISTS, "mock error", null, null);
+ }
+
+ @Test
+ public void testToXMLResponseWithDataMissingErrorTag() throws Exception {
+
+ testXMLResponse(new RestconfDocumentedException("mock error", ErrorType.PROTOCOL, ErrorTag.DATA_MISSING),
+ Status.CONFLICT, ErrorType.PROTOCOL, ErrorTag.DATA_MISSING, "mock error", null, null);
+ }
+
+ @Test
+ public void testToXMLResponseWithOperationNotSupportedErrorTag() throws Exception {
+
+ testXMLResponse(new RestconfDocumentedException("mock error", ErrorType.PROTOCOL,
+ ErrorTag.OPERATION_NOT_SUPPORTED), Status.NOT_IMPLEMENTED, ErrorType.PROTOCOL,
+ ErrorTag.OPERATION_NOT_SUPPORTED, "mock error", null, null);
+ }
+
+ @Test
+ public void testToXMLResponseWithOperationFailedErrorTag() throws Exception {
+
+ testXMLResponse(new RestconfDocumentedException("mock error", ErrorType.PROTOCOL, ErrorTag.OPERATION_FAILED),
+ Status.INTERNAL_SERVER_ERROR, ErrorType.PROTOCOL, ErrorTag.OPERATION_FAILED, "mock error", null, null);
+ }
+
+ @Test
+ public void testToXMLResponseWithPartialOperationErrorTag() throws Exception {
+
+ testXMLResponse(new RestconfDocumentedException("mock error", ErrorType.PROTOCOL, ErrorTag.PARTIAL_OPERATION),
+ Status.INTERNAL_SERVER_ERROR, ErrorType.PROTOCOL, ErrorTag.PARTIAL_OPERATION, "mock error", null, null);
+ }
+
+ @Test
+ public void testToXMLResponseWithErrorAppTag() throws Exception {
+
+ testXMLResponse(new RestconfDocumentedException(new RestconfError(ErrorType.APPLICATION,
+ ErrorTag.INVALID_VALUE, "mock error", "mock-app-tag")), Status.BAD_REQUEST, ErrorType.APPLICATION,
+ ErrorTag.INVALID_VALUE, "mock error", "mock-app-tag", null);
+ }
+
+ @Test
+ public void testToXMLResponseWithErrorInfo() throws Exception {
+
+ final String errorInfo = "<address>1.2.3.4</address> <session-id>123</session-id>";
+ testXMLResponse(new RestconfDocumentedException(new RestconfError(ErrorType.APPLICATION,
+ ErrorTag.INVALID_VALUE, "mock error", "mock-app-tag", errorInfo)), Status.BAD_REQUEST,
+ ErrorType.APPLICATION, ErrorTag.INVALID_VALUE, "mock error", "mock-app-tag",
+ new SimpleErrorInfoVerifier(errorInfo));
+ }
+
+ @Test
+ public void testToXMLResponseWithExceptionCause() throws Exception {
+
+ final Exception cause = new Exception("mock exception cause");
+ testXMLResponse(new RestconfDocumentedException("mock error", cause), Status.INTERNAL_SERVER_ERROR,
+ ErrorType.APPLICATION, ErrorTag.OPERATION_FAILED, "mock error", null,
+ new SimpleErrorInfoVerifier(cause.getMessage()));
+ }
+
+ @Test
+ @Ignore // FIXME : find why it return error-type as RPC no APPLICATION
+ public void testToXMLResponseWithMultipleErrors() throws Exception {
+
+ final List<RestconfError> errorList = Arrays.asList(
+ new RestconfError(ErrorType.APPLICATION, ErrorTag.LOCK_DENIED, "mock error1"),
+ new RestconfError(ErrorType.RPC, ErrorTag.ROLLBACK_FAILED, "mock error2"));
+ stageMockEx(new RestconfDocumentedException("mock", null, errorList));
+
+ final Response resp = target("/operational/foo").request(MediaType.APPLICATION_XML).get();
+
+ final InputStream stream = verifyResponse(resp, MediaType.APPLICATION_XML, Status.CONFLICT);
+
+ final Document doc = parseXMLDocument(stream);
+
+ final NodeList children = getXMLErrorList(doc, 2);
+
+ verifyXMLErrorNode(children.item(0), ErrorType.APPLICATION, ErrorTag.LOCK_DENIED, "mock error1", null, null);
+
+ verifyXMLErrorNode(children.item(1), ErrorType.RPC, ErrorTag.ROLLBACK_FAILED, "mock error2", null, null);
+ }
+
+ @Test
+ public void testToResponseWithAcceptHeader() throws Exception {
+
+ stageMockEx(new RestconfDocumentedException("mock error"));
+
+ final Response resp = target("/operational/foo").request().header("Accept", MediaType.APPLICATION_JSON).get();
+
+ final InputStream stream = verifyResponse(resp, MediaType.APPLICATION_JSON, Status.INTERNAL_SERVER_ERROR);
+
+ verifyJsonResponseBody(stream, ErrorType.APPLICATION, ErrorTag.OPERATION_FAILED, "mock error", null, null);
+ }
+
+ @Test
+ @Ignore
+ public void testToResponseWithStatusOnly() throws Exception {
+
+ // The StructuredDataToJsonProvider should throw a
+ // RestconfDocumentedException with no data
+
+ when(mockRestConf.readOperationalData(any(String.class), any(UriInfo.class))).thenReturn(
+ new NormalizedNodeContext(null, null));
+
+ final Response resp = target("/operational/foo").request(MediaType.APPLICATION_JSON).get();
+
+ verifyResponse(resp, MediaType.TEXT_PLAIN, Status.NOT_FOUND);
+ }
+
+ InputStream verifyResponse(final Response resp, final String expMediaType, final Status expStatus) {
+ assertEquals("getMediaType", MediaType.valueOf(expMediaType), resp.getMediaType());
+ assertEquals("getStatus", expStatus.getStatusCode(), resp.getStatus());
+
+ final Object entity = resp.getEntity();
+ assertEquals("Response entity", true, entity instanceof InputStream);
+ final InputStream stream = (InputStream) entity;
+ return stream;
+ }
+
+ void verifyJsonResponseBody(final InputStream stream, final ErrorType expErrorType, final ErrorTag expErrorTag,
+ final String expErrorMessage, final String expErrorAppTag, final ErrorInfoVerifier errorInfoVerifier)
+ throws Exception {
+
+ final JsonArray arrayElement = parseJsonErrorArrayElement(stream);
+
+ assertEquals("\"error\" Json array element length", 1, arrayElement.size());
+
+ verifyJsonErrorNode(arrayElement.get(0), expErrorType, expErrorTag, expErrorMessage, expErrorAppTag,
+ errorInfoVerifier);
+ }
+
+ @SuppressWarnings("checkstyle:IllegalCatch")
+ private static JsonArray parseJsonErrorArrayElement(final InputStream stream) throws IOException {
+ final ByteArrayOutputStream bos = new ByteArrayOutputStream();
+ stream.transferTo(bos);
+
+ LOG.info("JSON: {}", bos);
+
+ JsonElement rootElement;
+ try {
+ rootElement = JsonParser.parseReader(new InputStreamReader(new ByteArrayInputStream(bos.toByteArray())));
+ } catch (final Exception e) {
+ throw new IllegalArgumentException("Invalid JSON response:\n" + bos.toString(), e);
+ }
+
+ assertTrue("Root element of Json is not an Object", rootElement.isJsonObject());
+
+ final Set<Entry<String, JsonElement>> errorsEntrySet = rootElement.getAsJsonObject().entrySet();
+ assertEquals("Json Object element set count", 1, errorsEntrySet.size());
+
+ final Entry<String, JsonElement> errorsEntry = errorsEntrySet.iterator().next();
+ final JsonElement errorsElement = errorsEntry.getValue();
+ assertEquals("First Json element name", "errors", errorsEntry.getKey());
+ assertTrue("\"errors\" Json element is not an Object", errorsElement.isJsonObject());
+
+ final Set<Entry<String, JsonElement>> errorListEntrySet = errorsElement.getAsJsonObject().entrySet();
+ assertEquals("Root \"errors\" element child count", 1, errorListEntrySet.size());
+
+ final JsonElement errorListElement = errorListEntrySet.iterator().next().getValue();
+ assertEquals("\"errors\" child Json element name", "error", errorListEntrySet.iterator().next().getKey());
+ assertTrue("\"error\" Json element is not an Array", errorListElement.isJsonArray());
+
+ // As a final check, make sure there aren't multiple "error" array
+ // elements. Unfortunately,
+ // the call above to getAsJsonObject().entrySet() will out duplicate
+ // "error" elements. So
+ // we'll use regex on the json string to verify this.
+
+ final Matcher matcher = Pattern.compile("\"error\"[ ]*:[ ]*\\[", Pattern.DOTALL).matcher(bos.toString());
+ assertTrue("Expected 1 \"error\" element", matcher.find());
+ assertFalse("Found multiple \"error\" elements", matcher.find());
+
+ return errorListElement.getAsJsonArray();
+ }
+
+ void verifyJsonErrorNode(final JsonElement errorEntryElement, final ErrorType expErrorType,
+ final ErrorTag expErrorTag, final String expErrorMessage, final String expErrorAppTag,
+ final ErrorInfoVerifier errorInfoVerifier) {
+
+ JsonElement errorInfoElement = null;
+ final Map<String, String> leafMap = new HashMap<>();
+ for (final Entry<String, JsonElement> entry : errorEntryElement.getAsJsonObject().entrySet()) {
+ final String leafName = entry.getKey();
+ final JsonElement leafElement = entry.getValue();
+
+ if ("error-info".equals(leafName)) {
+ assertNotNull("Found unexpected \"error-info\" element", errorInfoVerifier);
+ errorInfoElement = leafElement;
+ } else {
+ assertTrue("\"error\" leaf Json element " + leafName + " is not a Primitive",
+ leafElement.isJsonPrimitive());
+
+ leafMap.put(leafName, leafElement.getAsString());
+ }
+ }
+
+ assertEquals("error-type", expErrorType.elementBody(), leafMap.remove("error-type"));
+ assertEquals("error-tag", expErrorTag.elementBody(), leafMap.remove("error-tag"));
+
+ verifyOptionalJsonLeaf(leafMap.remove("error-message"), expErrorMessage, "error-message");
+ verifyOptionalJsonLeaf(leafMap.remove("error-app-tag"), expErrorAppTag, "error-app-tag");
+
+ if (!leafMap.isEmpty()) {
+ fail("Found unexpected Json leaf elements for \"error\" element: " + leafMap);
+ }
+
+ if (errorInfoVerifier != null) {
+ assertNotNull("Missing \"error-info\" element", errorInfoElement);
+ errorInfoVerifier.verifyJson(errorInfoElement);
+ }
+ }
+
+ void verifyOptionalJsonLeaf(final String actualValue, final String expValue, final String tagName) {
+ if (expValue != null) {
+ assertEquals(tagName, expValue, actualValue);
+ } else {
+ assertNull("Found unexpected \"error\" leaf entry for: " + tagName, actualValue);
+ }
+ }
+
+ void verifyXMLResponseBody(final InputStream stream, final ErrorType expErrorType, final ErrorTag expErrorTag,
+ final String expErrorMessage, final String expErrorAppTag, final ErrorInfoVerifier errorInfoVerifier)
+ throws Exception {
+
+ final Document doc = parseXMLDocument(stream);
+
+ final NodeList children = getXMLErrorList(doc, 1);
+
+ verifyXMLErrorNode(children.item(0), expErrorType, expErrorTag, expErrorMessage, expErrorAppTag,
+ errorInfoVerifier);
+ }
+
+ private static Document parseXMLDocument(final InputStream stream) throws IOException, SAXException {
+ final ByteArrayOutputStream bos = new ByteArrayOutputStream();
+ stream.transferTo(bos);
+
+ LOG.debug("XML: {}", bos);
+
+ return UntrustedXML.newDocumentBuilder().parse(new ByteArrayInputStream(bos.toByteArray()));
+ }
+
+ void verifyXMLErrorNode(final Node errorNode, final ErrorType expErrorType, final ErrorTag expErrorTag,
+ final String expErrorMessage, final String expErrorAppTag, final ErrorInfoVerifier errorInfoVerifier)
+ throws Exception {
+
+ final String errorType = (String) ERROR_TYPE.evaluate(errorNode, XPathConstants.STRING);
+ assertEquals("error-type", expErrorType.elementBody(), errorType);
+
+ final String errorTag = (String) ERROR_TAG.evaluate(errorNode, XPathConstants.STRING);
+ assertEquals("error-tag", expErrorTag.elementBody(), errorTag);
+
+ verifyOptionalXMLLeaf(errorNode, ERROR_MESSAGE, expErrorMessage, "error-message");
+ verifyOptionalXMLLeaf(errorNode, ERROR_APP_TAG, expErrorAppTag, "error-app-tag");
+
+ final Node errorInfoNode = (Node) ERROR_INFO.evaluate(errorNode, XPathConstants.NODE);
+ if (errorInfoVerifier != null) {
+ assertNotNull("Missing \"error-info\" node", errorInfoNode);
+
+ errorInfoVerifier.verifyXML(errorInfoNode);
+ } else {
+ assertNull("Found unexpected \"error-info\" node", errorInfoNode);
+ }
+ }
+
+ void verifyOptionalXMLLeaf(final Node fromNode, final XPathExpression xpath, final String expValue,
+ final String tagName) throws Exception {
+ if (expValue != null) {
+ final String actual = (String) xpath.evaluate(fromNode, XPathConstants.STRING);
+ assertEquals(tagName, expValue, actual);
+ } else {
+ assertNull("Found unexpected \"error\" leaf entry for: " + tagName,
+ xpath.evaluate(fromNode, XPathConstants.NODE));
+ }
+ }
+
+ NodeList getXMLErrorList(final Node fromNode, final int count) throws Exception {
+ final NodeList errorList = (NodeList) ERROR_LIST.evaluate(fromNode, XPathConstants.NODESET);
+ assertNotNull("Root errors node is empty", errorList);
+ assertEquals("Root errors node child count", count, errorList.getLength());
+ return errorList;
+ }
+}
diff --git a/netconf/restconf/restconf-nb-bierman02/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/RestconfErrorTest.java b/netconf/restconf/restconf-nb-bierman02/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/RestconfErrorTest.java
new file mode 100644
index 0000000..30a0449
--- /dev/null
+++ b/netconf/restconf/restconf-nb-bierman02/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/RestconfErrorTest.java
@@ -0,0 +1,147 @@
+/*
+ * Copyright (c) 2014 Brocade Communications Systems, Inc. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.controller.sal.restconf.impl.test;
+
+import static org.hamcrest.CoreMatchers.equalTo;
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.junit.Assert.assertEquals;
+
+import org.hamcrest.BaseMatcher;
+import org.hamcrest.Description;
+import org.hamcrest.Matcher;
+import org.junit.Test;
+import org.opendaylight.restconf.common.errors.RestconfError;
+import org.opendaylight.yangtools.yang.common.ErrorTag;
+import org.opendaylight.yangtools.yang.common.ErrorType;
+import org.opendaylight.yangtools.yang.common.RpcError;
+import org.opendaylight.yangtools.yang.common.RpcResultBuilder;
+
+/**
+ * Unit tests for RestconfError.
+ *
+ * @author Devin Avery
+ * @author Thomas Pantelis
+ *
+ */
+public class RestconfErrorTest {
+
+ static class Contains extends BaseMatcher<String> {
+
+ private final String text;
+
+ Contains(final String text) {
+ this.text = text;
+ }
+
+ @Override
+ public void describeTo(final Description desc) {
+ desc.appendText("contains ").appendValue(text);
+ }
+
+ @Override
+ public boolean matches(final Object arg) {
+ return arg != null && arg.toString().contains(text);
+ }
+ }
+
+ @Test
+ public void testRestConfDocumentedException_NoCause() {
+ String expectedMessage = "Message";
+ ErrorType expectedErrorType = ErrorType.RPC;
+ ErrorTag expectedErrorTag = ErrorTag.IN_USE;
+ RestconfError error = new RestconfError(expectedErrorType, expectedErrorTag, expectedMessage);
+
+ validateRestConfError(expectedMessage, expectedErrorType, expectedErrorTag, null, (String) null, error);
+ }
+
+ @Test
+ public void testRestConfDocumentedException_WithAppTag() {
+ String expectedMessage = "Message";
+ ErrorType expectedErrorType = ErrorType.RPC;
+ ErrorTag expectedErrorTag = ErrorTag.IN_USE;
+ String expectedErrorAppTag = "application.tag";
+
+ RestconfError error =
+ new RestconfError(expectedErrorType, expectedErrorTag, expectedMessage, expectedErrorAppTag);
+
+ validateRestConfError(expectedMessage, expectedErrorType, expectedErrorTag, expectedErrorAppTag, (String) null,
+ error);
+ }
+
+ @Test
+ public void testRestConfDocumentedException_WithAppTagErrorInfo() {
+ String expectedMessage = "Message";
+ ErrorType expectedErrorType = ErrorType.RPC;
+ ErrorTag expectedErrorTag = ErrorTag.IN_USE;
+ String expectedErrorAppTag = "application.tag";
+ String errorInfo = "<extra><sessionid>session.id</sessionid></extra>";
+
+ RestconfError error =
+ new RestconfError(expectedErrorType, expectedErrorTag, expectedMessage, expectedErrorAppTag, errorInfo);
+
+ validateRestConfError(expectedMessage, expectedErrorType, expectedErrorTag, expectedErrorAppTag, errorInfo,
+ error);
+ }
+
+ @Test
+ public void testRestConfErrorWithRpcError() {
+
+ // All fields set
+ RpcError rpcError = RpcResultBuilder.newError(ErrorType.PROTOCOL, ErrorTag.BAD_ATTRIBUTE, "mock error-message",
+ "mock app-tag", "mock error-info", new Exception("mock cause"));
+
+ validateRestConfError("mock error-message", ErrorType.PROTOCOL, ErrorTag.BAD_ATTRIBUTE, "mock app-tag",
+ "mock error-info", new RestconfError(rpcError));
+
+ // All fields set except 'info' - expect error-info set to 'cause'
+ rpcError = RpcResultBuilder.newError(ErrorType.PROTOCOL, ErrorTag.BAD_ATTRIBUTE, "mock error-message",
+ "mock app-tag", null, new Exception("mock cause"));
+
+ validateRestConfError("mock error-message", ErrorType.PROTOCOL, ErrorTag.BAD_ATTRIBUTE, "mock app-tag",
+ new Contains("mock cause"), new RestconfError(rpcError));
+
+ // Some fields set - expect error-info set to ErrorSeverity
+ rpcError = RpcResultBuilder.newError(ErrorType.RPC, ErrorTag.ACCESS_DENIED, null, null, null, null);
+
+ validateRestConfError(null, ErrorType.RPC, ErrorTag.ACCESS_DENIED, null, "<severity>error</severity>",
+ new RestconfError(rpcError));
+
+ // 'tag' field not mapped to ErrorTag - expect error-tag set to OPERATION_FAILED
+ rpcError = RpcResultBuilder.newWarning(ErrorType.TRANSPORT, new ErrorTag("not mapped"), null, null, null, null);
+
+ validateRestConfError(null, ErrorType.TRANSPORT, new ErrorTag("not mapped"), null,
+ "<severity>warning</severity>", new RestconfError(rpcError));
+
+ // No fields set - edge case
+ rpcError = RpcResultBuilder.newError(ErrorType.APPLICATION, null, null, null, null, null);
+
+ validateRestConfError(null, ErrorType.APPLICATION, ErrorTag.OPERATION_FAILED,
+ null, "<severity>error</severity>", new RestconfError(rpcError));
+ }
+
+ private static void validateRestConfError(final String expectedMessage, final ErrorType expectedErrorType,
+ final ErrorTag expectedErrorTag, final String expectedErrorAppTag, final String errorInfo,
+ final RestconfError error) {
+
+ validateRestConfError(expectedMessage, expectedErrorType, expectedErrorTag, expectedErrorAppTag,
+ equalTo(errorInfo), error);
+ }
+
+ private static void validateRestConfError(final String expectedMessage, final ErrorType expectedErrorType,
+ final ErrorTag expectedErrorTag, final String expectedErrorAppTag, final Matcher<String> errorInfoMatcher,
+ final RestconfError error) {
+
+ assertEquals("getErrorMessage", expectedMessage, error.getErrorMessage());
+ assertEquals("getErrorType", expectedErrorType, error.getErrorType());
+ assertEquals("getErrorTag", expectedErrorTag, error.getErrorTag());
+ assertEquals("getErrorAppTag", expectedErrorAppTag, error.getErrorAppTag());
+ assertThat("getErrorInfo", error.getErrorInfo(), errorInfoMatcher);
+ error.toString(); // really just checking for NPE etc. Don't care about
+ // contents.
+ }
+}
diff --git a/netconf/restconf/restconf-nb-bierman02/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/RestconfImplNotificationSubscribingTest.java b/netconf/restconf/restconf-nb-bierman02/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/RestconfImplNotificationSubscribingTest.java
new file mode 100644
index 0000000..b69d105
--- /dev/null
+++ b/netconf/restconf/restconf-nb-bierman02/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/RestconfImplNotificationSubscribingTest.java
@@ -0,0 +1,168 @@
+/*
+ * Copyright (c) 2016 Cisco Systems, Inc. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.controller.sal.restconf.impl.test;
+
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+import java.io.FileNotFoundException;
+import java.time.Instant;
+import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.Set;
+import javax.ws.rs.core.MultivaluedMap;
+import javax.ws.rs.core.UriBuilder;
+import javax.ws.rs.core.UriInfo;
+import org.junit.AfterClass;
+import org.junit.Before;
+import org.junit.BeforeClass;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.junit.MockitoJUnitRunner;
+import org.opendaylight.controller.md.sal.rest.common.TestRestconfUtils;
+import org.opendaylight.netconf.sal.restconf.impl.BrokerFacade;
+import org.opendaylight.netconf.sal.restconf.impl.ControllerContext;
+import org.opendaylight.netconf.sal.restconf.impl.RestconfImpl;
+import org.opendaylight.netconf.sal.streams.listeners.ListenerAdapter;
+import org.opendaylight.netconf.sal.streams.listeners.Notificator;
+import org.opendaylight.netconf.sal.streams.websockets.WebSocketServer;
+import org.opendaylight.restconf.common.errors.RestconfDocumentedException;
+import org.opendaylight.yang.gen.v1.urn.sal.restconf.event.subscription.rev140708.NotificationOutputTypeGrouping.NotificationOutputType;
+import org.opendaylight.yangtools.yang.common.QName;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifier;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.PathArgument;
+import org.opendaylight.yangtools.yang.model.api.EffectiveModelContext;
+import org.opendaylight.yangtools.yang.test.util.YangParserTestUtils;
+
+@RunWith(MockitoJUnitRunner.StrictStubs.class)
+public class RestconfImplNotificationSubscribingTest {
+
+ private final String identifier = "data-change-event-subscription/datastore=OPERATIONAL/scope=ONE";
+
+ private static EffectiveModelContext schemaContext;
+
+ @Mock
+ private BrokerFacade broker;
+
+ @Mock
+ private UriInfo uriInfo;
+
+ private ControllerContext controllerContext;
+ private RestconfImpl restconfImpl;
+
+ @BeforeClass
+ public static void init() throws FileNotFoundException {
+ schemaContext = YangParserTestUtils.parseYangFiles(TestRestconfUtils.loadFiles("/notifications"));
+ }
+
+ @AfterClass
+ public static void cleanUp() {
+ WebSocketServer.destroyInstance(); // NETCONF-604
+ }
+
+ @Before
+ public void setup() {
+ controllerContext = TestRestconfUtils.newControllerContext(schemaContext);
+ restconfImpl = RestconfImpl.newInstance(broker, controllerContext);
+
+ final YangInstanceIdentifier path = mock(YangInstanceIdentifier.class);
+ Notificator.createListener(path, identifier, NotificationOutputType.XML, controllerContext);
+ }
+
+ @Test
+ public void startTimeTest() {
+ subscribe(Set.of(Map.entry("start-time", List.of("2014-10-25T10:02:00Z"))));
+ Notificator.removeAllListeners();
+ }
+
+ @Test
+ public void milisecsTest() {
+ subscribe(Set.of(Map.entry("start-time", List.of("2014-10-25T10:02:00.12345Z"))));
+ Notificator.removeAllListeners();
+ }
+
+ @Test
+ public void zonesPlusTest() {
+ subscribe(Set.of(Map.entry("start-time", List.of("2014-10-25T10:02:00+01:00"))));
+ Notificator.removeAllListeners();
+ }
+
+ @Test
+ public void zonesMinusTest() {
+ subscribe(Set.of(Map.entry("start-time", List.of("2014-10-25T10:02:00-01:00"))));
+ Notificator.removeAllListeners();
+ }
+
+ @Test
+ public void startAndStopTimeTest() {
+ subscribe(Set.of(Map.entry("start-time", List.of("2014-10-25T10:02:00Z")),
+ Map.entry("stop-time", List.of("2014-10-25T12:31:00Z"))));
+ Notificator.removeAllListeners();
+ }
+
+ @Test(expected = RestconfDocumentedException.class)
+ public void stopTimeTest() {
+ subscribe(Set.of(Map.entry("stop-time", List.of("2014-10-25T12:31:00Z"))));
+ Notificator.removeAllListeners();
+ }
+
+ @Test(expected = RestconfDocumentedException.class)
+ public void badParamTest() {
+ subscribe(Set.of(Map.entry("time", List.of("2014-10-25T12:31:00Z"))));
+ Notificator.removeAllListeners();
+ }
+
+ @Test(expected = IllegalArgumentException.class)
+ public void badValueTest() {
+ subscribe(Set.of(Map.entry("start-time", List.of("badvalue"))));
+ Notificator.removeAllListeners();
+ }
+
+ @Test(expected = IllegalArgumentException.class)
+ public void badZonesTest() {
+ subscribe(Set.of(Map.entry("start-time", List.of("2014-10-25T10:02:00Z+1:00"))));
+ Notificator.removeAllListeners();
+ }
+
+ @Test(expected = IllegalArgumentException.class)
+ public void badMilisecsTest() {
+ subscribe(Set.of(Map.entry("start-time", List.of("2014-10-25T10:02:00:0026Z"))));
+ Notificator.removeAllListeners();
+ }
+
+ @Test
+ public void onNotifiTest() throws Exception {
+ final YangInstanceIdentifier path = mock(YangInstanceIdentifier.class);
+ final PathArgument pathValue = NodeIdentifier.create(QName.create("module", "2016-12-14", "localName"));
+ final ListenerAdapter listener = Notificator.createListener(path, identifier, NotificationOutputType.XML,
+ controllerContext);
+
+ subscribe(Set.of(Map.entry("start-time", List.of("2014-10-25T10:02:00Z"))));
+
+ Instant startOrig = listener.getStart();
+ assertNotNull(startOrig);
+ listener.onDataTreeChanged(List.of());
+
+ startOrig = listener.getStart();
+ assertNull(startOrig);
+ }
+
+ private void subscribe(final Set<Entry<String, List<String>>> entries) {
+ final MultivaluedMap<String, String> map = mock(MultivaluedMap.class);
+ when(uriInfo.getQueryParameters()).thenReturn(map);
+ final UriBuilder uriBuilder = UriBuilder.fromPath("http://localhost:8181/" + identifier);
+ when(uriInfo.getAbsolutePathBuilder()).thenReturn(uriBuilder);
+ when(map.entrySet()).thenReturn(entries);
+ restconfImpl.subscribeToStream(identifier, uriInfo);
+ }
+}
diff --git a/netconf/restconf/restconf-nb-bierman02/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/RestconfImplTest.java b/netconf/restconf/restconf-nb-bierman02/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/RestconfImplTest.java
new file mode 100644
index 0000000..3174908
--- /dev/null
+++ b/netconf/restconf/restconf-nb-bierman02/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/RestconfImplTest.java
@@ -0,0 +1,306 @@
+/*
+ * Copyright (c) 2014 Cisco Systems, Inc. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.controller.sal.restconf.impl.test;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyBoolean;
+import static org.mockito.ArgumentMatchers.isNull;
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+import static org.mockito.Mockito.withSettings;
+import static org.opendaylight.yangtools.util.concurrent.FluentFutures.immediateFluentFuture;
+
+import java.io.FileNotFoundException;
+import java.net.URI;
+import java.text.ParseException;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.Optional;
+import java.util.Set;
+import javax.ws.rs.core.MultivaluedHashMap;
+import javax.ws.rs.core.MultivaluedMap;
+import javax.ws.rs.core.UriBuilder;
+import javax.ws.rs.core.UriInfo;
+import org.junit.AfterClass;
+import org.junit.BeforeClass;
+import org.junit.Test;
+import org.opendaylight.controller.md.sal.rest.common.TestRestconfUtils;
+import org.opendaylight.mdsal.dom.api.DOMMountPoint;
+import org.opendaylight.mdsal.dom.api.DOMRpcResult;
+import org.opendaylight.mdsal.dom.api.DOMRpcService;
+import org.opendaylight.mdsal.dom.api.DOMSchemaService;
+import org.opendaylight.mdsal.dom.spi.FixedDOMSchemaService;
+import org.opendaylight.netconf.sal.rest.api.Draft02;
+import org.opendaylight.netconf.sal.rest.impl.NormalizedNodeContext;
+import org.opendaylight.netconf.sal.restconf.impl.BrokerFacade;
+import org.opendaylight.netconf.sal.restconf.impl.ControllerContext;
+import org.opendaylight.netconf.sal.restconf.impl.RestconfImpl;
+import org.opendaylight.netconf.sal.streams.listeners.Notificator;
+import org.opendaylight.netconf.sal.streams.websockets.WebSocketServer;
+import org.opendaylight.restconf.common.context.InstanceIdentifierContext;
+import org.opendaylight.restconf.common.errors.RestconfDocumentedException;
+import org.opendaylight.restconf.common.errors.RestconfError;
+import org.opendaylight.yangtools.yang.common.Empty;
+import org.opendaylight.yangtools.yang.common.ErrorTag;
+import org.opendaylight.yangtools.yang.common.ErrorType;
+import org.opendaylight.yangtools.yang.common.QName;
+import org.opendaylight.yangtools.yang.common.YangConstants;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifierWithPredicates;
+import org.opendaylight.yangtools.yang.data.api.schema.ContainerNode;
+import org.opendaylight.yangtools.yang.data.api.schema.DataContainerChild;
+import org.opendaylight.yangtools.yang.data.api.schema.LeafSetEntryNode;
+import org.opendaylight.yangtools.yang.data.api.schema.LeafSetNode;
+import org.opendaylight.yangtools.yang.data.api.schema.MapEntryNode;
+import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
+import org.opendaylight.yangtools.yang.data.api.schema.builder.DataContainerNodeBuilder;
+import org.opendaylight.yangtools.yang.data.impl.schema.SchemaAwareBuilders;
+import org.opendaylight.yangtools.yang.model.api.DataSchemaNode;
+import org.opendaylight.yangtools.yang.model.api.EffectiveModelContext;
+import org.opendaylight.yangtools.yang.model.api.InputSchemaNode;
+import org.opendaylight.yangtools.yang.model.api.LeafSchemaNode;
+import org.opendaylight.yangtools.yang.model.api.ListSchemaNode;
+import org.opendaylight.yangtools.yang.model.api.Module;
+import org.opendaylight.yangtools.yang.model.api.OutputSchemaNode;
+import org.opendaylight.yangtools.yang.model.api.RpcDefinition;
+import org.opendaylight.yangtools.yang.model.api.stmt.InputEffectiveStatement;
+import org.opendaylight.yangtools.yang.model.api.stmt.ModuleEffectiveStatement;
+import org.opendaylight.yangtools.yang.model.api.stmt.OutputEffectiveStatement;
+import org.opendaylight.yangtools.yang.model.api.stmt.RpcEffectiveStatement;
+import org.opendaylight.yangtools.yang.model.api.stmt.SchemaNodeIdentifier.Absolute;
+import org.opendaylight.yangtools.yang.parser.spi.meta.ReactorException;
+
+/**
+ * See {@link InvokeRpcMethodTest}.
+ */
+public class RestconfImplTest {
+
+ private static EffectiveModelContext schemaContext;
+
+ private final BrokerFacade brokerFacade = mock(BrokerFacade.class);
+ private final ControllerContext controllerContext = TestRestconfUtils.newControllerContext(schemaContext);
+ private final RestconfImpl restconfImpl = RestconfImpl.newInstance(brokerFacade, controllerContext);
+
+ @BeforeClass
+ public static void init() throws FileNotFoundException, ReactorException {
+ schemaContext = TestUtils.loadSchemaContext("/full-versions/yangs", "/modules/restconf-module-testing");
+ }
+
+ @AfterClass
+ public static void cleanUp() {
+ WebSocketServer.destroyInstance(); // NETCONF-604
+ }
+
+ @Test
+ public void binaryKeyTest() {
+ final List<Byte> al = new ArrayList<>();
+ al.add((byte) 1);
+ binaryKeyTest(al, al);
+ }
+
+ private static void binaryKeyTest(final List<Byte> al, final List<Byte> al2) {
+
+ final QName keyDef = QName.create("test:key:binary", "2017-08-14", "b1");
+
+ final Map<QName, Object> uriKeyValues = new HashMap<>();
+ uriKeyValues.put(keyDef, al.toArray());
+
+ final MapEntryNode payload = mock(MapEntryNode.class);
+ final NodeIdentifierWithPredicates nodeIdWithPred =
+ NodeIdentifierWithPredicates.of(keyDef, keyDef, al2.toArray());
+ when(payload.getIdentifier()).thenReturn(nodeIdWithPred);
+
+ final List<QName> keyDefinitions = new ArrayList<>();
+ keyDefinitions.add(keyDef);
+ RestconfImpl.isEqualUriAndPayloadKeyValues(uriKeyValues, payload, keyDefinitions);
+ }
+
+ @Test
+ public void binaryKeyFailTest() {
+ final List<Byte> al = new ArrayList<>();
+ al.add((byte) 1);
+ final List<Byte> al2 = new ArrayList<>();
+ try {
+ binaryKeyTest(al, al2);
+ } catch (final RestconfDocumentedException e) {
+ final RestconfError err = e.getErrors().iterator().next();
+ assertEquals(ErrorType.PROTOCOL, err.getErrorType());
+ assertEquals(ErrorTag.INVALID_VALUE, err.getErrorTag());
+ }
+ }
+
+ @Test
+ public void testExample() throws FileNotFoundException, ParseException {
+ final NormalizedNode normalizedNodeData = TestUtils.prepareNormalizedNodeWithIetfInterfacesInterfacesData();
+ when(brokerFacade.readOperationalData(isNull())).thenReturn(normalizedNodeData);
+ assertEquals(normalizedNodeData,
+ brokerFacade.readOperationalData(null));
+ }
+
+ @Test
+ public void testRpcForMountpoint() throws Exception {
+ final QName qname = QName.create("namespace", "2010-10-10", "localname");
+ final UriInfo uriInfo = mock(UriInfo.class);
+ doReturn(new MultivaluedHashMap<>()).when(uriInfo).getQueryParameters(anyBoolean());
+
+ final NormalizedNodeContext ctx = mock(NormalizedNodeContext.class);
+ final RpcDefinition rpc = mock(RpcDefinition.class,
+ withSettings().extraInterfaces(RpcEffectiveStatement.class));
+ doReturn(qname).when(rpc).getQName();
+
+ final InputSchemaNode input = mock(InputSchemaNode.class,
+ withSettings().extraInterfaces(InputEffectiveStatement.class));
+ final QName inputQName = YangConstants.operationInputQName(qname.getModule());
+ doReturn(input).when(rpc).getInput();
+ doReturn(inputQName).when(input).getQName();
+ doReturn(Optional.of(input)).when((RpcEffectiveStatement) rpc).findSchemaTreeNode(inputQName);
+
+ final OutputSchemaNode output = mock(OutputSchemaNode.class,
+ withSettings().extraInterfaces(OutputEffectiveStatement.class));
+ final QName outputQName = YangConstants.operationInputQName(qname.getModule());
+ doReturn(output).when(rpc).getOutput();
+ doReturn(outputQName).when(output).getQName();
+ doReturn(Optional.of(output)).when((RpcEffectiveStatement) rpc).findSchemaTreeNode(outputQName);
+
+ final EffectiveModelContext mountContext = mock(EffectiveModelContext.class);
+ final ModuleEffectiveStatement mountModule = mock(ModuleEffectiveStatement.class);
+ doReturn(Map.of(qname.getModule(), mountModule)).when(mountContext).getModuleStatements();
+ doReturn(Optional.of(rpc)).when(mountModule).findSchemaTreeNode(qname);
+
+ final DOMMountPoint mount = mock(DOMMountPoint.class);
+ doReturn(Optional.of(FixedDOMSchemaService.of(mountContext))).when(mount).getService(DOMSchemaService.class);
+
+ doReturn(InstanceIdentifierContext.ofRpcInput(mountContext, rpc, mount))
+ .when(ctx).getInstanceIdentifierContext();
+
+ final DOMRpcService rpcService = mock(DOMRpcService.class);
+ doReturn(Optional.of(rpcService)).when(mount).getService(DOMRpcService.class);
+ doReturn(immediateFluentFuture(mock(DOMRpcResult.class))).when(rpcService)
+ .invokeRpc(any(QName.class), any(NormalizedNode.class));
+ restconfImpl.invokeRpc("randomId", ctx, uriInfo);
+ restconfImpl.invokeRpc("ietf-netconf", ctx, uriInfo);
+ verify(rpcService, times(2)).invokeRpc(any(QName.class), any());
+ }
+
+ /**
+ * Create notification stream for toaster module.
+ */
+ @Test
+ public void createNotificationStreamTest() {
+ final QName rpcQName = QName.create("urn:opendaylight:params:xml:ns:yang:controller:md:sal:remote",
+ "2014-01-14", "create-notification-stream");
+
+ final RpcDefinition schemaNode = schemaContext.getOperations().stream()
+ .filter(rpc -> rpc.getQName().equals(rpcQName))
+ .findFirst()
+ .orElseThrow();
+
+ final NormalizedNodeContext payload = mock(NormalizedNodeContext.class);
+ doReturn(InstanceIdentifierContext.ofRpcInput(schemaContext, schemaNode, null)).when(payload)
+ .getInstanceIdentifierContext();
+
+ final Set<DataContainerChild> children = new HashSet<>();
+ final LeafSetNode child = mock(LeafSetNode.class);
+
+ final LeafSetEntryNode entryNode = mock(LeafSetEntryNode.class);
+ when(entryNode.body()).thenReturn("(http://netconfcentral.org/ns/toaster?revision=2009-11-20)toastDone");
+ when(child.body()).thenReturn(Set.of(entryNode));
+ children.add(child);
+
+ final ContainerNode normalizedNode = mock(ContainerNode.class);
+ doReturn(normalizedNode).when(payload).getData();
+ doReturn(children).when(normalizedNode).body();
+
+ // register notification
+ final NormalizedNodeContext context = restconfImpl
+ .invokeRpc("sal-remote:create-notification-stream", payload, null);
+ assertNotNull(context);
+ }
+
+ /**
+ * Tests stream entry node.
+ */
+ @Test
+ public void toStreamEntryNodeTest() {
+ final Module restconfModule = controllerContext.getRestconfModule();
+ final DataSchemaNode streamSchemaNode = controllerContext
+ .getRestconfModuleRestConfSchemaNode(restconfModule, Draft02.RestConfModule.STREAM_LIST_SCHEMA_NODE);
+ final ListSchemaNode listStreamSchemaNode = (ListSchemaNode) streamSchemaNode;
+ final DataContainerNodeBuilder<NodeIdentifierWithPredicates, MapEntryNode> streamNodeValues =
+ SchemaAwareBuilders.mapEntryBuilder(listStreamSchemaNode);
+ var instanceDataChildrenByName =
+ ControllerContext.findInstanceDataChildrenByName(listStreamSchemaNode, "name");
+ final DataSchemaNode nameSchemaNode = instanceDataChildrenByName.get(0).child;
+ streamNodeValues.withChild(SchemaAwareBuilders.leafBuilder((LeafSchemaNode) nameSchemaNode)
+ .withValue("")
+ .build());
+
+ instanceDataChildrenByName =
+ ControllerContext.findInstanceDataChildrenByName(listStreamSchemaNode, "description");
+ final DataSchemaNode descriptionSchemaNode = instanceDataChildrenByName.get(0).child;
+ streamNodeValues.withChild(SchemaAwareBuilders.leafBuilder((LeafSchemaNode) nameSchemaNode)
+ .withValue("DESCRIPTION_PLACEHOLDER")
+ .build());
+
+ instanceDataChildrenByName =
+ ControllerContext.findInstanceDataChildrenByName(listStreamSchemaNode, "replay-support");
+ final DataSchemaNode replaySupportSchemaNode = instanceDataChildrenByName.get(0).child;
+ streamNodeValues.withChild(
+ SchemaAwareBuilders.leafBuilder((LeafSchemaNode) replaySupportSchemaNode).withValue(Boolean.TRUE).build());
+
+ instanceDataChildrenByName =
+ ControllerContext.findInstanceDataChildrenByName(listStreamSchemaNode, "replay-log-creation-time");
+ final DataSchemaNode replayLogCreationTimeSchemaNode = instanceDataChildrenByName.get(0).child;
+ streamNodeValues.withChild(
+ SchemaAwareBuilders.leafBuilder((LeafSchemaNode) replayLogCreationTimeSchemaNode).withValue("").build());
+ instanceDataChildrenByName = ControllerContext.findInstanceDataChildrenByName(listStreamSchemaNode, "events");
+ final DataSchemaNode eventsSchemaNode = instanceDataChildrenByName.get(0).child;
+ streamNodeValues.withChild(
+ SchemaAwareBuilders.leafBuilder((LeafSchemaNode) eventsSchemaNode).withValue(Empty.value()).build());
+ assertNotNull(streamNodeValues.build());
+ }
+
+ /**
+ * Subscribe for notification stream of toaster module.
+ */
+ @Test
+ public void subscribeToNotificationStreamTest() throws Exception {
+ final String identifier = "create-notification-stream/toaster:toastDone";
+
+ // register test notification stream
+ Notificator.createNotificationListener(
+ List.of(Absolute.of(QName.create("http://netconfcentral.org/ns/toaster", "2009-11-20", "toastDone"))),
+ identifier, "XML", controllerContext);
+
+ final UriInfo uriInfo = mock(UriInfo.class);
+ final UriBuilder uriBuilder = mock(UriBuilder.class);
+ when(uriBuilder.port(8181)).thenReturn(uriBuilder);
+ when(uriBuilder.replacePath(identifier)).thenReturn(uriBuilder);
+ when(uriBuilder.build()).thenReturn(new URI(""));
+ when(uriBuilder.scheme("ws")).thenReturn(uriBuilder);
+ when(uriInfo.getAbsolutePathBuilder()).thenReturn(uriBuilder);
+ final MultivaluedMap<String, String> map = mock(MultivaluedMap.class);
+ final Set<Entry<String, List<String>>> set = new HashSet<>();
+ when(map.entrySet()).thenReturn(set);
+ when(uriInfo.getQueryParameters()).thenReturn(map);
+
+ // subscribe to stream and verify response
+ final NormalizedNodeContext response = restconfImpl.subscribeToStream(identifier, uriInfo);
+
+ // remove test notification stream
+ Notificator.removeAllListeners();
+ }
+}
diff --git a/netconf/restconf/restconf-nb-bierman02/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/TestUtils.java b/netconf/restconf/restconf-nb-bierman02/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/TestUtils.java
new file mode 100644
index 0000000..d96cc77
--- /dev/null
+++ b/netconf/restconf/restconf-nb-bierman02/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/TestUtils.java
@@ -0,0 +1,258 @@
+/*
+ * Copyright (c) 2014 Cisco Systems, Inc. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.controller.sal.restconf.impl.test;
+
+import static com.google.common.base.Preconditions.checkArgument;
+import static java.util.Objects.requireNonNull;
+import static org.junit.Assert.assertNotNull;
+
+import java.io.BufferedReader;
+import java.io.ByteArrayOutputStream;
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.FileReader;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStreamWriter;
+import java.nio.charset.StandardCharsets;
+import java.text.ParseException;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+import javax.xml.transform.OutputKeys;
+import javax.xml.transform.Transformer;
+import javax.xml.transform.TransformerException;
+import javax.xml.transform.TransformerFactory;
+import javax.xml.transform.dom.DOMSource;
+import javax.xml.transform.stream.StreamResult;
+import org.opendaylight.yangtools.util.xml.UntrustedXML;
+import org.opendaylight.yangtools.yang.common.QName;
+import org.opendaylight.yangtools.yang.common.Revision;
+import org.opendaylight.yangtools.yang.common.XMLNamespace;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifier;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifierWithPredicates;
+import org.opendaylight.yangtools.yang.data.api.schema.MapEntryNode;
+import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
+import org.opendaylight.yangtools.yang.data.api.schema.builder.DataContainerNodeBuilder;
+import org.opendaylight.yangtools.yang.data.impl.schema.builder.impl.ImmutableLeafNodeBuilder;
+import org.opendaylight.yangtools.yang.data.impl.schema.builder.impl.ImmutableMapEntryNodeBuilder;
+import org.opendaylight.yangtools.yang.model.api.DataSchemaNode;
+import org.opendaylight.yangtools.yang.model.api.EffectiveModelContext;
+import org.opendaylight.yangtools.yang.model.api.Module;
+import org.opendaylight.yangtools.yang.test.util.YangParserTestUtils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.w3c.dom.Document;
+import org.xml.sax.SAXException;
+
+public final class TestUtils {
+
+ private static final Logger LOG = LoggerFactory.getLogger(TestUtils.class);
+
+ private TestUtils() {
+
+ }
+
+ public static EffectiveModelContext loadSchemaContext(final String... yangPath) throws FileNotFoundException {
+ final List<File> files = new ArrayList<>();
+ for (final String path : yangPath) {
+ final String pathToFile = TestUtils.class.getResource(path).getPath();
+ final File testDir = new File(pathToFile);
+ final String[] fileList = testDir.list();
+ if (fileList == null) {
+ throw new FileNotFoundException(pathToFile);
+ }
+
+ for (final String fileName : fileList) {
+ final File file = new File(testDir, fileName);
+ if (file.isDirectory() == false) {
+ files.add(file);
+ }
+ }
+ }
+
+ return YangParserTestUtils.parseYangFiles(files);
+ }
+
+ public static Module findModule(final Collection<? extends Module> modules, final String moduleName) {
+ for (final Module module : modules) {
+ if (module.getName().equals(moduleName)) {
+ return module;
+ }
+ }
+ return null;
+ }
+
+ public static Document loadDocumentFrom(final InputStream inputStream) {
+ try {
+ return UntrustedXML.newDocumentBuilder().parse(inputStream);
+ } catch (SAXException | IOException e) {
+ LOG.error("Error during loading Document from XML", e);
+ return null;
+ }
+ }
+
+ public static String getDocumentInPrintableForm(final Document doc) {
+ try {
+ final ByteArrayOutputStream out = new ByteArrayOutputStream();
+ 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");
+
+ transformer.transform(new DOMSource(requireNonNull(doc)), new StreamResult(new OutputStreamWriter(out,
+ StandardCharsets.UTF_8)));
+ final byte[] charData = out.toByteArray();
+ return new String(charData, StandardCharsets.UTF_8);
+ } catch (final TransformerException e) {
+ final String msg = "Error during transformation of Document into String";
+ LOG.error(msg, e);
+ return msg;
+ }
+
+ }
+
+ /**
+ * Searches module with name {@code searchedModuleName} in {@code modules}. If module name isn't specified and
+ * module set has only one element then this element is returned.
+ *
+ */
+ public static Module resolveModule(final String searchedModuleName, final Collection<? extends Module> modules) {
+ assertNotNull("Modules can't be null.", modules);
+ if (searchedModuleName != null) {
+ for (final Module m : modules) {
+ if (m.getName().equals(searchedModuleName)) {
+ return m;
+ }
+ }
+ } else if (modules.size() == 1) {
+ return modules.iterator().next();
+ }
+ return null;
+ }
+
+ public static DataSchemaNode resolveDataSchemaNode(final String searchedDataSchemaName, final Module module) {
+ assertNotNull("Module can't be null", module);
+
+ if (searchedDataSchemaName != null) {
+ for (final DataSchemaNode dsn : module.getChildNodes()) {
+ if (dsn.getQName().getLocalName().equals(searchedDataSchemaName)) {
+ return dsn;
+ }
+ }
+ } else if (module.getChildNodes().size() == 1) {
+ return module.getChildNodes().iterator().next();
+ }
+ return null;
+ }
+
+ public static QName buildQName(final String name, final String uri, final String date, final String prefix) {
+ return QName.create(XMLNamespace.of(uri), Revision.ofNullable(date), name);
+ }
+
+ public static QName buildQName(final String name, final String uri, final String date) {
+ return buildQName(name, uri, date, null);
+ }
+
+ public static QName buildQName(final String name) {
+ return buildQName(name, "", null);
+ }
+
+ public static String loadTextFile(final String filePath) throws IOException {
+ final FileReader fileReader = new FileReader(filePath, StandardCharsets.UTF_8);
+ final BufferedReader bufReader = new BufferedReader(fileReader);
+
+ String line = null;
+ final StringBuilder result = new StringBuilder();
+ while ((line = bufReader.readLine()) != null) {
+ result.append(line);
+ }
+ bufReader.close();
+ return result.toString();
+ }
+
+ private static Pattern patternForStringsSeparatedByWhiteChars(final String... substrings) {
+ final StringBuilder pattern = new StringBuilder();
+ pattern.append(".*");
+ for (final String substring : substrings) {
+ pattern.append(substring);
+ pattern.append("\\s*");
+ }
+ pattern.append(".*");
+ return Pattern.compile(pattern.toString(), Pattern.DOTALL);
+ }
+
+ public static boolean containsStringData(final String jsonOutput, final String... substrings) {
+ final Pattern pattern = patternForStringsSeparatedByWhiteChars(substrings);
+ final Matcher matcher = pattern.matcher(jsonOutput);
+ return matcher.matches();
+ }
+
+ public static NodeIdentifier getNodeIdentifier(final String localName, final String namespace,
+ final String revision) throws ParseException {
+ return new NodeIdentifier(QName.create(namespace, revision, localName));
+ }
+
+ public static NodeIdentifierWithPredicates getNodeIdentifierPredicate(final String localName,
+ final String namespace, final String revision, final Map<String, Object> keys) throws ParseException {
+ final Map<QName, Object> predicate = new HashMap<>();
+ for (final String key : keys.keySet()) {
+ predicate.put(QName.create(namespace, revision, key), keys.get(key));
+ }
+
+ return NodeIdentifierWithPredicates.of(QName.create(namespace, revision, localName), predicate);
+ }
+
+ public static NodeIdentifierWithPredicates getNodeIdentifierPredicate(final String localName,
+ final String namespace, final String revision, final String... keysAndValues) throws ParseException {
+ checkArgument(keysAndValues.length % 2 == 0, "number of keys argument have to be divisible by 2 (map)");
+ final Map<QName, Object> predicate = new HashMap<>();
+
+ int index = 0;
+ while (index < keysAndValues.length) {
+ predicate.put(QName.create(namespace, revision, keysAndValues[index++]), keysAndValues[index++]);
+ }
+
+ return NodeIdentifierWithPredicates.of(QName.create(namespace, revision, localName), predicate);
+ }
+
+ public static NormalizedNode prepareNormalizedNodeWithIetfInterfacesInterfacesData() throws ParseException {
+ final String ietfInterfacesDate = "2013-07-04";
+ final String namespace = "urn:ietf:params:xml:ns:yang:ietf-interfaces";
+ final DataContainerNodeBuilder<NodeIdentifierWithPredicates, MapEntryNode> mapEntryNode =
+ ImmutableMapEntryNodeBuilder.create();
+
+ final Map<String, Object> predicates = new HashMap<>();
+ predicates.put("name", "eth0");
+
+ mapEntryNode.withNodeIdentifier(getNodeIdentifierPredicate("interface", namespace, ietfInterfacesDate,
+ predicates));
+ mapEntryNode
+ .withChild(new ImmutableLeafNodeBuilder<String>()
+ .withNodeIdentifier(getNodeIdentifier("name", namespace, ietfInterfacesDate)).withValue("eth0")
+ .build());
+ mapEntryNode.withChild(new ImmutableLeafNodeBuilder<String>()
+ .withNodeIdentifier(getNodeIdentifier("type", namespace, ietfInterfacesDate))
+ .withValue("ethernetCsmacd").build());
+ mapEntryNode.withChild(new ImmutableLeafNodeBuilder<Boolean>()
+ .withNodeIdentifier(getNodeIdentifier("enabled", namespace, ietfInterfacesDate))
+ .withValue(Boolean.FALSE).build());
+ mapEntryNode.withChild(new ImmutableLeafNodeBuilder<String>()
+ .withNodeIdentifier(getNodeIdentifier("description", namespace, ietfInterfacesDate))
+ .withValue("some interface").build());
+
+ return mapEntryNode.build();
+ }
+}
diff --git a/netconf/restconf/restconf-nb-bierman02/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/URIParametersParsing.java b/netconf/restconf/restconf-nb-bierman02/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/URIParametersParsing.java
new file mode 100644
index 0000000..1b61ea1
--- /dev/null
+++ b/netconf/restconf/restconf-nb-bierman02/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/URIParametersParsing.java
@@ -0,0 +1,172 @@
+/*
+ * Copyright (c) 2014 Cisco Systems, Inc. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.controller.sal.restconf.impl.test;
+
+import static java.util.Objects.requireNonNull;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+import java.io.FileNotFoundException;
+import javax.ws.rs.core.MultivaluedMap;
+import javax.ws.rs.core.UriBuilder;
+import javax.ws.rs.core.UriInfo;
+import org.junit.Before;
+import org.junit.Test;
+import org.mockito.Mockito;
+import org.opendaylight.controller.md.sal.rest.common.TestRestconfUtils;
+import org.opendaylight.mdsal.common.api.LogicalDatastoreType;
+import org.opendaylight.netconf.sal.rest.impl.NormalizedNodeContext;
+import org.opendaylight.netconf.sal.restconf.impl.BrokerFacade;
+import org.opendaylight.netconf.sal.restconf.impl.ControllerContext;
+import org.opendaylight.netconf.sal.restconf.impl.RestconfImpl;
+import org.opendaylight.netconf.sal.streams.listeners.ListenerAdapter;
+import org.opendaylight.netconf.sal.streams.listeners.Notificator;
+import org.opendaylight.restconf.common.context.InstanceIdentifierContext;
+import org.opendaylight.yang.gen.v1.urn.sal.restconf.event.subscription.rev140708.CreateDataChangeEventSubscriptionInput1.Scope;
+import org.opendaylight.yang.gen.v1.urn.sal.restconf.event.subscription.rev140708.NotificationOutputTypeGrouping.NotificationOutputType;
+import org.opendaylight.yangtools.yang.common.QName;
+import org.opendaylight.yangtools.yang.common.Revision;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.AugmentationIdentifier;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.InstanceIdentifierBuilder;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifier;
+import org.opendaylight.yangtools.yang.data.api.schema.AugmentationNode;
+import org.opendaylight.yangtools.yang.data.api.schema.ContainerNode;
+import org.opendaylight.yangtools.yang.data.api.schema.LeafNode;
+import org.opendaylight.yangtools.yang.data.api.schema.builder.DataContainerNodeBuilder;
+import org.opendaylight.yangtools.yang.data.impl.schema.SchemaAwareBuilders;
+import org.opendaylight.yangtools.yang.model.api.AugmentationSchemaNode;
+import org.opendaylight.yangtools.yang.model.api.ContainerLike;
+import org.opendaylight.yangtools.yang.model.api.DataSchemaNode;
+import org.opendaylight.yangtools.yang.model.api.EffectiveModelContext;
+import org.opendaylight.yangtools.yang.model.api.InputSchemaNode;
+import org.opendaylight.yangtools.yang.model.api.LeafSchemaNode;
+import org.opendaylight.yangtools.yang.model.api.Module;
+import org.opendaylight.yangtools.yang.model.api.RpcDefinition;
+import org.opendaylight.yangtools.yang.parser.spi.meta.ReactorException;
+
+public class URIParametersParsing {
+
+ private RestconfImpl restconf;
+ private BrokerFacade mockedBrokerFacade;
+ private ControllerContext controllerContext;
+
+ @Before
+ public void init() throws FileNotFoundException, ReactorException {
+ mockedBrokerFacade = mock(BrokerFacade.class);
+ controllerContext = TestRestconfUtils.newControllerContext(
+ TestUtils.loadSchemaContext("/datastore-and-scope-specification"));
+ restconf = RestconfImpl.newInstance(mockedBrokerFacade, controllerContext);
+ }
+
+ @Test
+ public void resolveURIParametersConcreteValues() {
+ resolveURIParameters("OPERATIONAL", "SUBTREE", LogicalDatastoreType.OPERATIONAL, Scope.SUBTREE);
+ }
+
+ @Test
+ public void resolveURIParametersDefaultValues() {
+ resolveURIParameters(null, null, LogicalDatastoreType.CONFIGURATION, Scope.BASE);
+ }
+
+ private void resolveURIParameters(final String datastore, final String scope,
+ final LogicalDatastoreType datastoreExpected, final Scope scopeExpected) {
+
+ final InstanceIdentifierBuilder iiBuilder = YangInstanceIdentifier.builder();
+ iiBuilder.node(QName.create("", "dummyStreamName"));
+
+ final String datastoreValue = datastore == null ? "CONFIGURATION" : datastore;
+ final String scopeValue = scope == null ? "BASE" : scope + "";
+ Notificator.createListener(iiBuilder.build(), "dummyStreamName/datastore=" + datastoreValue + "/scope="
+ + scopeValue, NotificationOutputType.XML, controllerContext);
+
+ final UriInfo mockedUriInfo = mock(UriInfo.class);
+ @SuppressWarnings("unchecked")
+ final MultivaluedMap<String, String> mockedMultivaluedMap = mock(MultivaluedMap.class);
+ when(mockedMultivaluedMap.getFirst(eq("datastore"))).thenReturn(datastoreValue);
+ when(mockedMultivaluedMap.getFirst(eq("scope"))).thenReturn(scopeValue);
+
+ when(mockedUriInfo.getQueryParameters(eq(false))).thenReturn(mockedMultivaluedMap);
+
+ final UriBuilder uriBuilder = UriBuilder.fromUri("www.whatever.com");
+ when(mockedUriInfo.getAbsolutePathBuilder()).thenReturn(uriBuilder);
+
+ restconf.invokeRpc("sal-remote:create-data-change-event-subscription",
+ prepareDomRpcNode(datastoreValue, scopeValue), mockedUriInfo);
+
+ final ListenerAdapter listener =
+ Notificator.getListenerFor("data-change-event-subscription/opendaylight-inventory:nodes/datastore="
+ + datastoreValue + "/scope=" + scopeValue);
+ assertNotNull(listener);
+ }
+
+ private NormalizedNodeContext prepareDomRpcNode(final String datastore, final String scope) {
+ final EffectiveModelContext schema = controllerContext.getGlobalSchema();
+ final Module rpcSalRemoteModule = schema.findModule("sal-remote", Revision.of("2014-01-14")).get();
+ final QName rpcQName =
+ QName.create(rpcSalRemoteModule.getQNameModule(), "create-data-change-event-subscription");
+ final RpcDefinition rpcDef = Mockito.mock(RpcDefinition.class);
+ ContainerLike rpcInputSchemaNode = null;
+ for (final RpcDefinition rpc : rpcSalRemoteModule.getRpcs()) {
+ if (rpcQName.isEqualWithoutRevision(rpc.getQName())) {
+ rpcInputSchemaNode = rpc.getInput();
+ break;
+ }
+ }
+ assertNotNull("RPC ContainerSchemaNode was not found!", rpcInputSchemaNode);
+
+ final DataContainerNodeBuilder<NodeIdentifier, ContainerNode> container =
+ SchemaAwareBuilders.containerBuilder(rpcInputSchemaNode);
+
+ final QName pathQName =
+ QName.create("urn:opendaylight:params:xml:ns:yang:controller:md:sal:remote", "2014-01-14", "path");
+ final DataSchemaNode pathSchemaNode = rpcInputSchemaNode.getDataChildByName(pathQName);
+ assertTrue(pathSchemaNode instanceof LeafSchemaNode);
+ final LeafNode<Object> pathNode = SchemaAwareBuilders.leafBuilder((LeafSchemaNode) pathSchemaNode)
+ .withValue(YangInstanceIdentifier.builder()
+ .node(QName.create("urn:opendaylight:inventory", "2013-08-19", "nodes")).build()).build();
+ container.withChild(pathNode);
+
+ final AugmentationSchemaNode augmentationSchema = requireNonNull(rpcInputSchemaNode.getAvailableAugmentations()
+ .iterator().next());
+ final DataContainerNodeBuilder<AugmentationIdentifier, AugmentationNode> augmentationBuilder =
+ SchemaAwareBuilders.augmentationBuilder(augmentationSchema);
+
+ final QName dataStoreQName = QName.create("urn:sal:restconf:event:subscription", "2014-07-08", "datastore");
+ final DataSchemaNode dsSchemaNode = augmentationSchema.getDataChildByName(dataStoreQName);
+ assertTrue(dsSchemaNode instanceof LeafSchemaNode);
+ final LeafNode<Object> dsNode = SchemaAwareBuilders.leafBuilder((LeafSchemaNode) dsSchemaNode)
+ .withValue(datastore).build();
+ augmentationBuilder.withChild(dsNode);
+
+ final QName scopeQName = QName.create("urn:sal:restconf:event:subscription", "2014-07-08", "scope");
+ final DataSchemaNode scopeSchemaNode = augmentationSchema.getDataChildByName(scopeQName);
+ assertTrue(scopeSchemaNode instanceof LeafSchemaNode);
+ final LeafNode<Object> scopeNode = SchemaAwareBuilders.leafBuilder((LeafSchemaNode) scopeSchemaNode)
+ .withValue(scope).build();
+ augmentationBuilder.withChild(scopeNode);
+
+ final QName outputQName =
+ QName.create("urn:sal:restconf:event:subscription", "2014-07-08", "notification-output-type");
+ final DataSchemaNode outputSchemaNode = augmentationSchema.getDataChildByName(outputQName);
+ assertTrue(outputSchemaNode instanceof LeafSchemaNode);
+ final LeafNode<Object> outputNode =
+ SchemaAwareBuilders.leafBuilder((LeafSchemaNode) outputSchemaNode).withValue("XML").build();
+ augmentationBuilder.withChild(outputNode);
+
+ container.withChild(augmentationBuilder.build());
+
+ when(rpcDef.getInput()).thenReturn((InputSchemaNode) rpcInputSchemaNode);
+ when(rpcDef.getQName()).thenReturn(rpcQName);
+
+ return new NormalizedNodeContext(InstanceIdentifierContext.ofRpcInput(schema, rpcDef, null), container.build());
+ }
+}
diff --git a/netconf/restconf/restconf-nb-bierman02/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/URITest.java b/netconf/restconf/restconf-nb-bierman02/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/URITest.java
new file mode 100644
index 0000000..8178674
--- /dev/null
+++ b/netconf/restconf/restconf-nb-bierman02/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/URITest.java
@@ -0,0 +1,163 @@
+/*
+ * Copyright (c) 2014 Cisco Systems, Inc. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.controller.sal.restconf.impl.test;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertThrows;
+import static org.junit.Assert.assertTrue;
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.mock;
+
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.Iterables;
+import java.io.FileNotFoundException;
+import java.util.Optional;
+import org.junit.BeforeClass;
+import org.junit.Test;
+import org.opendaylight.controller.md.sal.rest.common.TestRestconfUtils;
+import org.opendaylight.mdsal.dom.api.DOMMountPoint;
+import org.opendaylight.mdsal.dom.api.DOMSchemaService;
+import org.opendaylight.mdsal.dom.spi.FixedDOMSchemaService;
+import org.opendaylight.netconf.sal.restconf.impl.ControllerContext;
+import org.opendaylight.restconf.common.context.InstanceIdentifierContext;
+import org.opendaylight.restconf.common.errors.RestconfDocumentedException;
+import org.opendaylight.yangtools.yang.model.api.ContainerSchemaNode;
+import org.opendaylight.yangtools.yang.model.api.EffectiveModelContext;
+import org.opendaylight.yangtools.yang.parser.spi.meta.ReactorException;
+
+public class URITest {
+
+ private static EffectiveModelContext schemaContext;
+ private static EffectiveModelContext mountSchemaContext;
+
+ private final DOMMountPoint mountInstance = mock(DOMMountPoint.class);
+ private final ControllerContext controllerContext =
+ TestRestconfUtils.newControllerContext(schemaContext, mountInstance);
+
+ @BeforeClass
+ public static void init() throws FileNotFoundException, ReactorException {
+ schemaContext = TestUtils.loadSchemaContext("/full-versions/yangs");
+ mountSchemaContext = TestUtils.loadSchemaContext("/test-config-data/yang2");
+ }
+
+ @Test
+ public void testToInstanceIdentifierList() {
+ InstanceIdentifierContext instanceIdentifier = controllerContext
+ .toInstanceIdentifier("simple-nodes:userWithoutClass/foo");
+ assertEquals(instanceIdentifier.getSchemaNode().getQName().getLocalName(), "userWithoutClass");
+
+ instanceIdentifier = controllerContext.toInstanceIdentifier("simple-nodes:userWithoutClass/foo");
+ assertEquals(instanceIdentifier.getSchemaNode().getQName().getLocalName(), "userWithoutClass");
+
+ instanceIdentifier = controllerContext.toInstanceIdentifier("simple-nodes:user/foo/boo");
+ assertEquals(instanceIdentifier.getSchemaNode().getQName().getLocalName(), "user");
+
+ instanceIdentifier = controllerContext.toInstanceIdentifier("simple-nodes:user//boo");
+ assertEquals(instanceIdentifier.getSchemaNode().getQName().getLocalName(), "user");
+
+ }
+
+ @Test
+ public void testToInstanceIdentifierWithDoubleSlash() {
+ InstanceIdentifierContext instanceIdentifier = controllerContext
+ .toInstanceIdentifier("simple-nodes:food//nonalcoholic");
+ assertEquals(instanceIdentifier.getSchemaNode().getQName().getLocalName(), "nonalcoholic");
+
+ instanceIdentifier = controllerContext
+ .toInstanceIdentifier("simple-nodes:userWithoutClass//");
+ assertEquals(instanceIdentifier.getSchemaNode().getQName().getLocalName(), "userWithoutClass");
+
+ instanceIdentifier = controllerContext
+ .toInstanceIdentifier("simple-nodes:userWithoutClass///inner-container");
+ assertEquals(instanceIdentifier.getSchemaNode().getQName().getLocalName(), "inner-container");
+ }
+
+ @Test
+ public void testToInstanceIdentifierListWithNullKey() {
+ assertThrows(RestconfDocumentedException.class,
+ () -> controllerContext.toInstanceIdentifier("simple-nodes:user/null/boo"));
+ }
+
+ @Test
+ public void testToInstanceIdentifierListWithMissingKey() {
+ assertThrows(RestconfDocumentedException.class,
+ () -> controllerContext.toInstanceIdentifier("simple-nodes:user/foo"));
+ }
+
+ @Test
+ public void testToInstanceIdentifierContainer() {
+ final InstanceIdentifierContext instanceIdentifier =
+ controllerContext.toInstanceIdentifier("simple-nodes:users");
+ assertEquals(instanceIdentifier.getSchemaNode().getQName().getLocalName(), "users");
+ assertTrue(instanceIdentifier.getSchemaNode() instanceof ContainerSchemaNode);
+ assertEquals(2, ((ContainerSchemaNode) instanceIdentifier.getSchemaNode()).getChildNodes().size());
+ }
+
+ @Test
+ public void testToInstanceIdentifierChoice() {
+ final InstanceIdentifierContext instanceIdentifier = controllerContext
+ .toInstanceIdentifier("simple-nodes:food/nonalcoholic");
+ assertEquals(instanceIdentifier.getSchemaNode().getQName().getLocalName(), "nonalcoholic");
+ }
+
+ @Test
+ public void testToInstanceIdentifierChoiceException() {
+ assertThrows(RestconfDocumentedException.class,
+ () -> controllerContext.toInstanceIdentifier("simple-nodes:food/snack"));
+ }
+
+ @Test
+ public void testToInstanceIdentifierCaseException() {
+ assertThrows(RestconfDocumentedException.class,
+ () -> controllerContext.toInstanceIdentifier("simple-nodes:food/sports-arena"));
+ }
+
+ @Test
+ public void testToInstanceIdentifierChoiceCaseException() {
+ assertThrows(RestconfDocumentedException.class,
+ () -> controllerContext.toInstanceIdentifier("simple-nodes:food/snack/sports-arena"));
+ }
+
+ @Test
+ public void testToInstanceIdentifierWithoutNode() {
+ assertThrows(RestconfDocumentedException.class,
+ () -> controllerContext.toInstanceIdentifier("simple-nodes"));
+ }
+
+ @Test
+ public void testMountPointWithExternModul() {
+ initSchemaService();
+ final InstanceIdentifierContext instanceIdentifier = controllerContext
+ .toInstanceIdentifier("simple-nodes:users/yang-ext:mount/test-interface2:class/student/name");
+ assertEquals(
+ "[(urn:ietf:params:xml:ns:yang:test-interface2?revision=2014-08-01)class, "
+ + "(urn:ietf:params:xml:ns:yang:test-interface2?revision=2014-08-01)student, "
+ + "(urn:ietf:params:xml:ns:yang:test-interface2?revision=2014-08-01)student"
+ + "[{(urn:ietf:params:xml:ns:yang:test-interface2?revision=2014-08-01)name=name}]]",
+ ImmutableList.copyOf(instanceIdentifier.getInstanceIdentifier().getPathArguments()).toString());
+ }
+
+ @Test
+ public void testMountPointWithoutExternModul() {
+ initSchemaService();
+ final InstanceIdentifierContext instanceIdentifier = controllerContext
+ .toInstanceIdentifier("simple-nodes:users/yang-ext:mount/");
+ assertTrue(Iterables.isEmpty(instanceIdentifier.getInstanceIdentifier().getPathArguments()));
+ }
+
+ @Test
+ public void testMountPointWithoutMountPointSchema() {
+ assertThrows(RestconfDocumentedException.class,
+ () -> controllerContext.toInstanceIdentifier("simple-nodes:users/yang-ext:mount/test-interface2:class"));
+ }
+
+ private void initSchemaService() {
+ doReturn(Optional.of(FixedDOMSchemaService.of(mountSchemaContext))).when(mountInstance)
+ .getService(DOMSchemaService.class);
+ }
+}
diff --git a/netconf/restconf/restconf-nb-bierman02/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/XmlAndJsonToCnSnInstanceIdentifierTest.java b/netconf/restconf/restconf-nb-bierman02/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/XmlAndJsonToCnSnInstanceIdentifierTest.java
new file mode 100644
index 0000000..b0dd7a2
--- /dev/null
+++ b/netconf/restconf/restconf-nb-bierman02/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/XmlAndJsonToCnSnInstanceIdentifierTest.java
@@ -0,0 +1,21 @@
+/*
+ * Copyright (c) 2014 Cisco Systems, Inc. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.controller.sal.restconf.impl.test;
+
+import java.io.FileNotFoundException;
+import org.junit.BeforeClass;
+import org.opendaylight.yangtools.yang.parser.spi.meta.ReactorException;
+
+public class XmlAndJsonToCnSnInstanceIdentifierTest extends YangAndXmlAndDataSchemaLoader {
+
+ @BeforeClass
+ public static void initialize() throws FileNotFoundException, ReactorException {
+ dataLoad("/instanceidentifier/yang", 4, "instance-identifier-module", "cont");
+ }
+
+}
diff --git a/netconf/restconf/restconf-nb-bierman02/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/XmlAndJsonToCnSnLeafRefTest.java b/netconf/restconf/restconf-nb-bierman02/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/XmlAndJsonToCnSnLeafRefTest.java
new file mode 100644
index 0000000..df13bb8
--- /dev/null
+++ b/netconf/restconf/restconf-nb-bierman02/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/XmlAndJsonToCnSnLeafRefTest.java
@@ -0,0 +1,30 @@
+/*
+ * Copyright (c) 2014 Cisco Systems, Inc. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.controller.sal.restconf.impl.test;
+
+import java.io.FileNotFoundException;
+import org.junit.BeforeClass;
+import org.opendaylight.yangtools.yang.common.QName;
+import org.opendaylight.yangtools.yang.parser.spi.meta.ReactorException;
+
+public class XmlAndJsonToCnSnLeafRefTest extends YangAndXmlAndDataSchemaLoader {
+
+ final QName refContQName = QName.create("referenced:module", "2014-04-17", "cont");
+ final QName refLf1QName = QName.create(this.refContQName, "lf1");
+ final QName contQName = QName.create("leafref:module", "2014-04-17", "cont");
+ final QName lf1QName = QName.create(this.contQName, "lf1");
+ final QName lf2QName = QName.create(this.contQName, "lf2");
+ final QName lf3QName = QName.create(this.contQName, "lf3");
+
+ @BeforeClass
+ public static void initialize() throws FileNotFoundException, ReactorException {
+ dataLoad("/leafref/yang", 2, "leafref-module", "cont");
+ }
+
+
+}
diff --git a/netconf/restconf/restconf-nb-bierman02/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/YangAndXmlAndDataSchemaLoader.java b/netconf/restconf/restconf-nb-bierman02/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/YangAndXmlAndDataSchemaLoader.java
new file mode 100644
index 0000000..9192691
--- /dev/null
+++ b/netconf/restconf/restconf-nb-bierman02/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/YangAndXmlAndDataSchemaLoader.java
@@ -0,0 +1,42 @@
+/*
+ * Copyright (c) 2014 Cisco Systems, Inc. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.controller.sal.restconf.impl.test;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+
+import java.io.FileNotFoundException;
+import java.util.Collection;
+import org.opendaylight.yangtools.yang.model.api.DataSchemaNode;
+import org.opendaylight.yangtools.yang.model.api.Module;
+
+public abstract class YangAndXmlAndDataSchemaLoader {
+ protected static Collection<? extends Module> modules;
+ protected static DataSchemaNode dataSchemaNode;
+ protected static String searchedModuleName;
+ protected static String searchedDataSchemaName;
+ protected static String schemaNodePath;
+
+ protected static void dataLoad(final String yangPath) throws FileNotFoundException {
+ dataLoad(yangPath, 1, null, null);
+ }
+
+ protected static void dataLoad(final String yangPath, final int modulesNumber, final String moduleName,
+ final String dataSchemaName) throws FileNotFoundException {
+ modules = TestUtils.loadSchemaContext(yangPath).getModules();
+ assertEquals(modulesNumber, modules.size());
+ final Module module = TestUtils.resolveModule(moduleName, modules);
+ searchedModuleName = module == null ? "" : module.getName();
+ assertNotNull(module);
+ dataSchemaNode = TestUtils.resolveDataSchemaNode(dataSchemaName, module);
+ searchedDataSchemaName = dataSchemaNode == null ? "" : dataSchemaNode.getQName().getLocalName();
+ assertNotNull(dataSchemaNode);
+ schemaNodePath = searchedModuleName + ":" + searchedDataSchemaName;
+ }
+
+}
diff --git a/netconf/restconf/restconf-nb-bierman02/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/incubate/InMemoryMdsalModule.java b/netconf/restconf/restconf-nb-bierman02/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/incubate/InMemoryMdsalModule.java
new file mode 100644
index 0000000..cabdc6c
--- /dev/null
+++ b/netconf/restconf/restconf-nb-bierman02/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/incubate/InMemoryMdsalModule.java
@@ -0,0 +1,127 @@
+/*
+ * Copyright (c) 2019 Red Hat, Inc. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.controller.sal.restconf.impl.test.incubate;
+
+import com.google.inject.AbstractModule;
+import com.google.inject.Provides;
+import javax.annotation.PreDestroy;
+import javax.inject.Singleton;
+import org.opendaylight.mdsal.binding.api.DataBroker;
+import org.opendaylight.mdsal.binding.dom.adapter.test.AbstractBaseDataBrokerTest;
+import org.opendaylight.mdsal.binding.dom.adapter.test.AbstractConcurrentDataBrokerTest;
+import org.opendaylight.mdsal.dom.api.DOMDataBroker;
+import org.opendaylight.mdsal.dom.api.DOMMountPointService;
+import org.opendaylight.mdsal.dom.api.DOMNotificationPublishService;
+import org.opendaylight.mdsal.dom.api.DOMNotificationService;
+import org.opendaylight.mdsal.dom.api.DOMRpcService;
+import org.opendaylight.mdsal.dom.api.DOMSchemaService;
+import org.opendaylight.mdsal.dom.broker.DOMMountPointServiceImpl;
+import org.opendaylight.mdsal.dom.broker.DOMNotificationRouter;
+import org.opendaylight.mdsal.dom.broker.DOMRpcRouter;
+import org.opendaylight.mdsal.dom.spi.DOMNotificationSubscriptionListenerRegistry;
+import org.opendaylight.mdsal.dom.store.inmemory.InMemoryDOMDataStore;
+import org.opendaylight.yangtools.yang.model.api.EffectiveModelContextProvider;
+
+/**
+ * Guice Module which binds the mdsal (not controller) {@link DataBroker} & Co.
+ * in-memory implementation suitable for tests.
+ *
+ * <p>This class is here only temporarily and it can and should be removed and
+ * replaced when the equivalent will be offered by the mdsal project itself; see
+ * <a href="https://jira.opendaylight.org/browse/MDSAL-418">MDSAL-418</a>. It is
+ * also copy/pasted to org.opendaylight.restconf.nb.rfc8040.test.incubate.InMemoryMdsalModule.
+ *
+ * <p>BEWARE: Do *NOT* use this module in component tests or applications mixing
+ * code requiring the old controller and the new mdsal {@link DataBroker} & Co.
+ * APIs together - because this binds a *SEPARATE* {@link InMemoryDOMDataStore},
+ * and doesn't delegate to controller's InMemoryDOMDataStore. This is just fine
+ * for tests where all code under test already uses only the mdsal APIs.
+ *
+ * @author Michael Vorburger.ch
+ */
+public class InMemoryMdsalModule extends AbstractModule {
+
+ private static final int NOTIFICATION_SERVICE_QUEUE_DEPTH = 128;
+
+ private final AbstractBaseDataBrokerTest dataBrokerTest;
+ private final DOMNotificationRouter domNotificationRouter;
+
+ public InMemoryMdsalModule() throws Exception {
+ dataBrokerTest = new AbstractConcurrentDataBrokerTest(true) { // NOT AbstractDataBrokerTest
+ };
+ dataBrokerTest.setup();
+
+ domNotificationRouter = DOMNotificationRouter.create(NOTIFICATION_SERVICE_QUEUE_DEPTH);
+ }
+
+ @Override
+ protected void configure() {
+ }
+
+ @Provides
+ @Singleton
+ DataBroker getDataBroker() {
+ return dataBrokerTest.getDataBroker();
+ }
+
+ @Provides
+ @Singleton DOMDataBroker getDOMDataBroker() {
+ return dataBrokerTest.getDomBroker();
+ }
+
+ @Provides
+ @Singleton DOMNotificationRouter getDOMNotificationRouter() {
+ return dataBrokerTest.getDataBrokerTestCustomizer().getDomNotificationRouter();
+ }
+
+ @Provides
+ @Singleton DOMSchemaService getSchemaService() {
+ return dataBrokerTest.getDataBrokerTestCustomizer().getSchemaService();
+ }
+
+ @Provides
+ @Singleton EffectiveModelContextProvider getSchemaContextProvider() {
+ DOMSchemaService schemaService = dataBrokerTest.getDataBrokerTestCustomizer().getSchemaService();
+ if (schemaService instanceof EffectiveModelContextProvider) {
+ return (EffectiveModelContextProvider) schemaService;
+ }
+ throw new IllegalStateException(
+ "The schema service isn't a SchemaContextProvider, it's a " + schemaService.getClass());
+ }
+
+ @Provides
+ @Singleton DOMMountPointService getDOMMountPoint() {
+ return new DOMMountPointServiceImpl();
+ }
+
+ @Provides
+ @Singleton DOMNotificationService getDOMNotificationService() {
+ return domNotificationRouter;
+ }
+
+ @Provides
+ @Singleton DOMNotificationPublishService getDOMNotificationPublishService() {
+ return domNotificationRouter;
+ }
+
+ @Provides
+ @Singleton DOMNotificationSubscriptionListenerRegistry getDOMNotificationSubscriptionListenerRegistry() {
+ return domNotificationRouter;
+ }
+
+ @Provides
+ @Singleton DOMRpcService getDOMRpcService(DOMSchemaService schemaService) {
+ return DOMRpcRouter.newInstance(schemaService).getRpcService();
+ }
+
+ @PreDestroy
+ public void close() {
+ // TODO When moving this to mdsal, must close components to shut down Threads etc.
+ // but cannot do this here (in netconf) yet, because we need to change AbstractBaseDataBrokerTest & Co..
+ }
+}
diff --git a/netconf/restconf/restconf-nb-bierman02/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/incubate/InMemoryMdsalModuleTest.java b/netconf/restconf/restconf-nb-bierman02/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/incubate/InMemoryMdsalModuleTest.java
new file mode 100644
index 0000000..6e01ecd
--- /dev/null
+++ b/netconf/restconf/restconf-nb-bierman02/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/incubate/InMemoryMdsalModuleTest.java
@@ -0,0 +1,35 @@
+/*
+ * Copyright (c) 2018 Red Hat, Inc. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.controller.sal.restconf.impl.test.incubate;
+
+import java.util.concurrent.ExecutionException;
+import javax.inject.Inject;
+import org.junit.Rule;
+import org.junit.Test;
+import org.opendaylight.infrautils.inject.guice.testutils.AnnotationsModule;
+import org.opendaylight.infrautils.inject.guice.testutils.GuiceRule;
+import org.opendaylight.mdsal.binding.api.DataBroker;
+
+/**
+ * Test for {@link InMemoryMdsalModule}.
+ *
+ * <p>This will be removed when the local {@link InMemoryMdsalModule} incubating here
+ * in netconf will be replaced by the one from mdsal.
+ *
+ * @author Michael Vorburger.ch
+ */
+public class InMemoryMdsalModuleTest {
+
+ public @Rule GuiceRule guice = new GuiceRule(InMemoryMdsalModule.class, AnnotationsModule.class);
+
+ @Inject DataBroker dataBroker;
+
+ @Test public void testDataBroker() throws InterruptedException, ExecutionException {
+ dataBroker.newReadWriteTransaction().commit().get();
+ }
+}
diff --git a/netconf/restconf/restconf-nb-bierman02/src/test/java/org/opendaylight/controller/sal/restconf/impl/websockets/client/IClientMessageCallback.java b/netconf/restconf/restconf-nb-bierman02/src/test/java/org/opendaylight/controller/sal/restconf/impl/websockets/client/IClientMessageCallback.java
new file mode 100644
index 0000000..a5323fb
--- /dev/null
+++ b/netconf/restconf/restconf-nb-bierman02/src/test/java/org/opendaylight/controller/sal/restconf/impl/websockets/client/IClientMessageCallback.java
@@ -0,0 +1,17 @@
+/*
+ * Copyright (c) 2014, 2015 Cisco Systems, Inc. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+
+package org.opendaylight.controller.sal.restconf.impl.websockets.client;
+
+/**
+ * Created by mbobak on 1/22/14.
+ */
+public interface IClientMessageCallback {
+
+ void onMessageReceived(Object message);
+}
diff --git a/netconf/restconf/restconf-nb-bierman02/src/test/java/org/opendaylight/controller/sal/restconf/impl/websockets/client/WebSocketClient.java b/netconf/restconf/restconf-nb-bierman02/src/test/java/org/opendaylight/controller/sal/restconf/impl/websockets/client/WebSocketClient.java
new file mode 100644
index 0000000..a67a491
--- /dev/null
+++ b/netconf/restconf/restconf-nb-bierman02/src/test/java/org/opendaylight/controller/sal/restconf/impl/websockets/client/WebSocketClient.java
@@ -0,0 +1,130 @@
+/*
+ * Copyright (c) 2013 Cisco Systems, Inc. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.controller.sal.restconf.impl.websockets.client;
+
+import io.netty.bootstrap.Bootstrap;
+import io.netty.buffer.Unpooled;
+import io.netty.channel.Channel;
+import io.netty.channel.ChannelInitializer;
+import io.netty.channel.ChannelPipeline;
+import io.netty.channel.EventLoopGroup;
+import io.netty.channel.nio.NioEventLoopGroup;
+import io.netty.channel.socket.SocketChannel;
+import io.netty.channel.socket.nio.NioSocketChannel;
+import io.netty.handler.codec.http.HttpClientCodec;
+import io.netty.handler.codec.http.HttpObjectAggregator;
+import io.netty.handler.codec.http.websocketx.CloseWebSocketFrame;
+import io.netty.handler.codec.http.websocketx.PingWebSocketFrame;
+import io.netty.handler.codec.http.websocketx.TextWebSocketFrame;
+import io.netty.handler.codec.http.websocketx.WebSocketClientHandshakerFactory;
+import io.netty.handler.codec.http.websocketx.WebSocketVersion;
+import java.io.BufferedReader;
+import java.io.InputStreamReader;
+import java.net.URI;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class WebSocketClient {
+
+ private static final Logger LOG = LoggerFactory.getLogger(WebSocketClient.class);
+
+ private final URI uri;
+ private final Bootstrap bootstrap = new Bootstrap();
+ private final WebSocketClientHandler clientHandler;
+ private Channel clientChannel;
+ private final EventLoopGroup group = new NioEventLoopGroup();
+
+ public WebSocketClient(final URI uri, final IClientMessageCallback clientMessageCallback) {
+ this.uri = uri;
+ clientHandler = new WebSocketClientHandler(WebSocketClientHandshakerFactory.newHandshaker(uri,
+ WebSocketVersion.V13, null, false, null), clientMessageCallback);
+ // last null could be replaced with DefaultHttpHeaders
+ initialize();
+ }
+
+ private void initialize() {
+
+ String protocol = uri.getScheme();
+ if (!"ws".equals(protocol)) {
+ throw new IllegalArgumentException("Unsupported protocol: " + protocol);
+ }
+
+ bootstrap.group(group).channel(NioSocketChannel.class).handler(new ChannelInitializer<SocketChannel>() {
+ @Override
+ public void initChannel(final SocketChannel ch) throws Exception {
+ ChannelPipeline pipeline = ch.pipeline();
+ pipeline.addLast("http-codec", new HttpClientCodec());
+ pipeline.addLast("aggregator", new HttpObjectAggregator(8192));
+ pipeline.addLast("ws-handler", clientHandler);
+ }
+ });
+ }
+
+ public void connect() throws InterruptedException {
+ LOG.info("WebSocket Client connecting");
+ clientChannel = bootstrap.connect(uri.getHost(), uri.getPort()).sync().channel();
+ clientHandler.handshakeFuture().sync();
+ }
+
+ public void writeAndFlush(final String message) {
+ clientChannel.writeAndFlush(new TextWebSocketFrame(message));
+ }
+
+ public void writeAndFlush(final Object message) {
+ clientChannel.writeAndFlush(message);
+ }
+
+ public void ping() {
+ clientChannel.writeAndFlush(new PingWebSocketFrame(Unpooled.copiedBuffer(new byte[] { 1, 2, 3, 4, 5, 6 })));
+ }
+
+ public void close(final String reasonText) throws InterruptedException {
+ CloseWebSocketFrame closeWebSocketFrame = new CloseWebSocketFrame(1000, reasonText);
+ clientChannel.writeAndFlush(closeWebSocketFrame);
+
+ // WebSocketClientHandler will close the connection when the server
+ // responds to the CloseWebSocketFrame.
+ clientChannel.closeFuture().sync();
+ group.shutdownGracefully();
+ }
+
+ public static void main(final String[] args) throws Exception {
+ URI uri;
+ if (args.length > 0) {
+ uri = new URI(args[0]);
+ } else {
+ uri = new URI("http://192.168.1.101:8181/opendaylight-inventory:nodes");
+ }
+ IClientMessageCallback messageCallback = new ClientMessageCallback();
+ WebSocketClient webSocketClient = new WebSocketClient(uri, messageCallback);
+ webSocketClient.connect();
+
+ while (true) {
+ BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
+ String input = br.readLine();
+ if (input.equals("q")) {
+ LOG.info("Would you like to close stream? (Y = yes, empty = yes)\n");
+ input = br.readLine();
+ if (input.equals("yes") || input.isEmpty()) {
+ webSocketClient.close("opendaylight-inventory:nodes");
+ break;
+ }
+ }
+ }
+ }
+
+ private static class ClientMessageCallback implements IClientMessageCallback {
+ @Override
+ public void onMessageReceived(final Object message) {
+ if (message instanceof TextWebSocketFrame) {
+ LOG.info("received message {}" + ((TextWebSocketFrame) message).text());
+ }
+ }
+ }
+
+}
diff --git a/netconf/restconf/restconf-nb-bierman02/src/test/java/org/opendaylight/controller/sal/restconf/impl/websockets/client/WebSocketClientHandler.java b/netconf/restconf/restconf-nb-bierman02/src/test/java/org/opendaylight/controller/sal/restconf/impl/websockets/client/WebSocketClientHandler.java
new file mode 100644
index 0000000..19dbbc3
--- /dev/null
+++ b/netconf/restconf/restconf-nb-bierman02/src/test/java/org/opendaylight/controller/sal/restconf/impl/websockets/client/WebSocketClientHandler.java
@@ -0,0 +1,92 @@
+/*
+ * Copyright (c) 2013 Cisco Systems, Inc. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.controller.sal.restconf.impl.websockets.client;
+
+import io.netty.channel.Channel;
+import io.netty.channel.ChannelFuture;
+import io.netty.channel.ChannelHandlerContext;
+import io.netty.channel.ChannelPromise;
+import io.netty.channel.SimpleChannelInboundHandler;
+import io.netty.handler.codec.http.FullHttpResponse;
+import io.netty.handler.codec.http.websocketx.CloseWebSocketFrame;
+import io.netty.handler.codec.http.websocketx.PongWebSocketFrame;
+import io.netty.handler.codec.http.websocketx.WebSocketClientHandshaker;
+import io.netty.handler.codec.http.websocketx.WebSocketFrame;
+import io.netty.util.CharsetUtil;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class WebSocketClientHandler extends SimpleChannelInboundHandler<Object> {
+
+ private static final Logger LOG = LoggerFactory.getLogger(WebSocketClientHandler.class.toString());
+ private final WebSocketClientHandshaker handshaker;
+ private ChannelPromise handshakeFuture;
+ private final IClientMessageCallback messageListener;
+
+ public WebSocketClientHandler(final WebSocketClientHandshaker handshaker, final IClientMessageCallback listener) {
+ this.handshaker = handshaker;
+ this.messageListener = listener;
+ }
+
+ public ChannelFuture handshakeFuture() {
+ return handshakeFuture;
+ }
+
+ @Override
+ public void handlerAdded(final ChannelHandlerContext ctx) throws Exception {
+ handshakeFuture = ctx.newPromise();
+ }
+
+ @Override
+ public void channelActive(final ChannelHandlerContext ctx) throws Exception {
+ handshaker.handshake(ctx.channel());
+ }
+
+ @Override
+ public void channelInactive(final ChannelHandlerContext ctx) throws Exception {
+ LOG.info("WebSocket Client disconnected!");
+ }
+
+ @Override
+ public void channelRead0(final ChannelHandlerContext ctx, final Object msg) throws Exception {
+ Channel ch = ctx.channel();
+ if (!handshaker.isHandshakeComplete()) {
+ handshaker.finishHandshake(ch, (FullHttpResponse) msg);
+ LOG.info("WebSocket Client connected!");
+ handshakeFuture.setSuccess();
+ return;
+ }
+
+ if (msg instanceof FullHttpResponse) {
+ FullHttpResponse response = (FullHttpResponse) msg;
+ throw new Exception("Unexpected FullHttpResponse (getStatus=" + response.status() + ", content="
+ + response.content().toString(CharsetUtil.UTF_8) + ')');
+ }
+
+ messageListener.onMessageReceived(msg);
+ WebSocketFrame frame = (WebSocketFrame) msg;
+
+ if (frame instanceof PongWebSocketFrame) {
+ LOG.info("WebSocket Client received pong");
+ } else if (frame instanceof CloseWebSocketFrame) {
+ LOG.info("WebSocket Client received closing");
+ ch.close();
+ }
+ }
+
+ @Override
+ public void exceptionCaught(final ChannelHandlerContext ctx, final Throwable cause) throws Exception {
+ LOG.info("Cause: {} .", cause.toString());
+
+ if (!handshakeFuture.isDone()) {
+ handshakeFuture.setFailure(cause);
+ }
+
+ ctx.close();
+ }
+}
diff --git a/netconf/restconf/restconf-nb-bierman02/src/test/java/org/opendaylight/controller/sal/restconf/impl/websockets/test/RestStreamTest.java b/netconf/restconf/restconf-nb-bierman02/src/test/java/org/opendaylight/controller/sal/restconf/impl/websockets/test/RestStreamTest.java
new file mode 100644
index 0000000..0163ce0
--- /dev/null
+++ b/netconf/restconf/restconf-nb-bierman02/src/test/java/org/opendaylight/controller/sal/restconf/impl/websockets/test/RestStreamTest.java
@@ -0,0 +1,132 @@
+/*
+ * Copyright (c) 2014 Cisco Systems, Inc. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.controller.sal.restconf.impl.websockets.test;
+
+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 java.io.FileNotFoundException;
+import java.io.UnsupportedEncodingException;
+import java.net.URI;
+import javax.ws.rs.client.Entity;
+import javax.ws.rs.core.Application;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.Response;
+import org.glassfish.jersey.server.ResourceConfig;
+import org.glassfish.jersey.test.JerseyTest;
+import org.junit.BeforeClass;
+import org.junit.Ignore;
+import org.junit.Test;
+import org.opendaylight.controller.md.sal.rest.common.TestRestconfUtils;
+import org.opendaylight.controller.sal.restconf.impl.test.TestUtils;
+import org.opendaylight.netconf.sal.rest.impl.JsonNormalizedNodeBodyReader;
+import org.opendaylight.netconf.sal.rest.impl.NormalizedNodeJsonBodyWriter;
+import org.opendaylight.netconf.sal.rest.impl.NormalizedNodeXmlBodyWriter;
+import org.opendaylight.netconf.sal.rest.impl.RestconfDocumentedExceptionMapper;
+import org.opendaylight.netconf.sal.rest.impl.XmlNormalizedNodeBodyReader;
+import org.opendaylight.netconf.sal.restconf.impl.BrokerFacade;
+import org.opendaylight.netconf.sal.restconf.impl.ControllerContext;
+import org.opendaylight.netconf.sal.restconf.impl.RestconfImpl;
+import org.opendaylight.yangtools.yang.model.api.EffectiveModelContext;
+import org.opendaylight.yangtools.yang.parser.spi.meta.ReactorException;
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
+import org.w3c.dom.Node;
+
+public class RestStreamTest extends JerseyTest {
+
+ private static EffectiveModelContext schemaContextYangsIetf;
+
+ private BrokerFacade brokerFacade;
+ private RestconfImpl restconfImpl;
+
+ @BeforeClass
+ public static void init() throws FileNotFoundException, ReactorException {
+ schemaContextYangsIetf = TestUtils.loadSchemaContext("/full-versions/yangs");
+ }
+
+ @Override
+ protected Application configure() {
+ /* enable/disable Jersey logs to console */
+ // enable(TestProperties.LOG_TRAFFIC);
+ // enable(TestProperties.DUMP_ENTITY);
+ // enable(TestProperties.RECORD_LOG_LEVEL);
+ // set(TestProperties.RECORD_LOG_LEVEL, Level.ALL.intValue());
+
+ final ControllerContext controllerContext = TestRestconfUtils.newControllerContext(schemaContextYangsIetf);
+ brokerFacade = mock(BrokerFacade.class);
+ restconfImpl = RestconfImpl.newInstance(brokerFacade, controllerContext);
+
+ ResourceConfig resourceConfig = new ResourceConfig();
+ resourceConfig = resourceConfig.registerInstances(restconfImpl, new NormalizedNodeJsonBodyWriter(),
+ new NormalizedNodeXmlBodyWriter(), new XmlNormalizedNodeBodyReader(controllerContext),
+ new JsonNormalizedNodeBodyReader(controllerContext),
+ new RestconfDocumentedExceptionMapper(controllerContext));
+ return resourceConfig;
+ }
+
+ @Test
+ @Ignore // Sporadic failures where jersey does not correctly pass post data to XmlNormalizedNodeBodyReader.readFrom
+ public void testCallRpcCallGet() throws UnsupportedEncodingException, InterruptedException {
+ createAndSubscribe(null);
+ }
+
+ @Test
+ @Ignore // Sporadic failures where jersey does not correctly pass post data to XmlNormalizedNodeBodyReader.readFrom
+ public void testCallRpcCallGetLeaves() throws UnsupportedEncodingException, InterruptedException {
+ createAndSubscribe("odl-leaf-nodes-only", "true");
+ }
+
+ private void createAndSubscribe(final String queryParamName, final Object... values)
+ throws UnsupportedEncodingException, InterruptedException {
+ String uri = "/operations/sal-remote:create-data-change-event-subscription";
+ String rpcInput = getRpcInput();
+ final Response responseWithStreamName = post(uri, MediaType.APPLICATION_XML, rpcInput);
+ final Document xmlResponse = responseWithStreamName.readEntity(Document.class);
+ assertNotNull(xmlResponse);
+ final Element outputElement = xmlResponse.getDocumentElement();
+ assertEquals("output",outputElement.getLocalName());
+
+ final Node streamNameElement = outputElement.getFirstChild();
+ assertEquals("stream-name",streamNameElement.getLocalName());
+ assertEquals("data-change-event-subscription/ietf-interfaces:interfaces/ietf-interfaces:interface/eth0/"
+ + "datastore=CONFIGURATION/scope=BASE",streamNameElement.getTextContent());
+
+ uri = "/streams/stream/data-change-event-subscription/ietf-interfaces:interfaces/ietf-interfaces:interface/"
+ + "eth0/datastore=CONFIGURATION/scope=BASE";
+ final Response responseWithRedirectionUri = get(uri, MediaType.APPLICATION_XML, null);
+ final URI websocketServerUri = responseWithRedirectionUri.getLocation();
+ assertNotNull(websocketServerUri);
+ assertTrue(websocketServerUri.toString().matches(".*ws://localhost:[\\d]+/data-change-event-subscription/"
+ + "ietf-interfaces:interfaces/ietf-interfaces:interface/eth0.*"));
+ }
+
+ private Response post(final String uri, final String mediaType, final String data) {
+ return target(uri).request(mediaType).post(Entity.entity(data, mediaType));
+ }
+
+ private Response get(final String uri, final String mediaType, final String queryParam, final Object... values) {
+ if (queryParam != null) {
+ return target(uri).queryParam(queryParam, values).request(mediaType).get();
+ } else {
+ return target(uri).request(mediaType).get();
+ }
+ }
+
+ private static String getRpcInput() {
+ final StringBuilder sb = new StringBuilder();
+ sb.append("<input xmlns=\"urn:opendaylight:params:xml:ns:yang:controller:md:sal:remote\">");
+ sb.append("<path xmlns:int=\"urn:ietf:params:xml:ns:yang:ietf-interfaces\">/"
+ + "int:interfaces/int:interface[int:name='eth0']</path>");
+ sb.append("</input>");
+ return sb.toString();
+ }
+
+}
diff --git a/netconf/restconf/restconf-nb-bierman02/src/test/java/org/opendaylight/controller/sal/restconf/impl/xml/to/cnsn/test/XmlAugmentedElementToCnSnTest.java b/netconf/restconf/restconf-nb-bierman02/src/test/java/org/opendaylight/controller/sal/restconf/impl/xml/to/cnsn/test/XmlAugmentedElementToCnSnTest.java
new file mode 100644
index 0000000..2a6f7de
--- /dev/null
+++ b/netconf/restconf/restconf-nb-bierman02/src/test/java/org/opendaylight/controller/sal/restconf/impl/xml/to/cnsn/test/XmlAugmentedElementToCnSnTest.java
@@ -0,0 +1,13 @@
+/*
+ * Copyright (c) 2014 Cisco Systems, Inc. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.controller.sal.restconf.impl.xml.to.cnsn.test;
+
+
+public class XmlAugmentedElementToCnSnTest {
+
+}
diff --git a/netconf/restconf/restconf-nb-bierman02/src/test/java/org/opendaylight/controller/sal/restconf/impl/xml/to/cnsn/test/XmlToCnSnTest.java b/netconf/restconf/restconf-nb-bierman02/src/test/java/org/opendaylight/controller/sal/restconf/impl/xml/to/cnsn/test/XmlToCnSnTest.java
new file mode 100644
index 0000000..1cac018
--- /dev/null
+++ b/netconf/restconf/restconf-nb-bierman02/src/test/java/org/opendaylight/controller/sal/restconf/impl/xml/to/cnsn/test/XmlToCnSnTest.java
@@ -0,0 +1,22 @@
+/*
+ * Copyright (c) 2014 Cisco Systems, Inc. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.controller.sal.restconf.impl.xml.to.cnsn.test;
+
+import java.io.FileNotFoundException;
+import org.junit.BeforeClass;
+import org.opendaylight.controller.sal.restconf.impl.test.YangAndXmlAndDataSchemaLoader;
+import org.opendaylight.yangtools.yang.parser.spi.meta.ReactorException;
+
+public class XmlToCnSnTest extends YangAndXmlAndDataSchemaLoader {
+
+ @BeforeClass
+ public static void initialize() throws FileNotFoundException, ReactorException {
+ dataLoad("/xml-to-cnsn/leafref");
+ }
+
+}
diff --git a/netconf/restconf/restconf-nb-bierman02/src/test/java/org/opendaylight/netconf/sal/rest/impl/DepthAwareNormalizedNodeWriterTest.java b/netconf/restconf/restconf-nb-bierman02/src/test/java/org/opendaylight/netconf/sal/rest/impl/DepthAwareNormalizedNodeWriterTest.java
new file mode 100644
index 0000000..58debcb
--- /dev/null
+++ b/netconf/restconf/restconf-nb-bierman02/src/test/java/org/opendaylight/netconf/sal/rest/impl/DepthAwareNormalizedNodeWriterTest.java
@@ -0,0 +1,343 @@
+/*
+ * Copyright (c) 2016 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.sal.rest.impl;
+
+import static org.mockito.Mockito.inOrder;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.verifyNoMoreInteractions;
+import static org.mockito.Mockito.when;
+
+import com.google.common.collect.Sets;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Optional;
+import org.junit.Before;
+import org.junit.Ignore;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.InOrder;
+import org.mockito.Mock;
+import org.mockito.junit.MockitoJUnitRunner;
+import org.opendaylight.yangtools.yang.common.QName;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifier;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifierWithPredicates;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeWithValue;
+import org.opendaylight.yangtools.yang.data.api.schema.ContainerNode;
+import org.opendaylight.yangtools.yang.data.api.schema.DataContainerChild;
+import org.opendaylight.yangtools.yang.data.api.schema.LeafNode;
+import org.opendaylight.yangtools.yang.data.api.schema.LeafSetEntryNode;
+import org.opendaylight.yangtools.yang.data.api.schema.LeafSetNode;
+import org.opendaylight.yangtools.yang.data.api.schema.MapEntryNode;
+import org.opendaylight.yangtools.yang.data.api.schema.MapNode;
+import org.opendaylight.yangtools.yang.data.api.schema.stream.NormalizedNodeStreamWriter;
+
+@RunWith(MockitoJUnitRunner.StrictStubs.class)
+public class DepthAwareNormalizedNodeWriterTest {
+
+ @Mock
+ private NormalizedNodeStreamWriter writer;
+ @Mock
+ private ContainerNode containerNodeData;
+ @Mock
+ private MapNode mapNodeData;
+ @Mock
+ private MapEntryNode mapEntryNodeData;
+ @Mock
+ private LeafSetNode<String> leafSetNodeData;
+ @Mock
+ private LeafSetEntryNode<String> leafSetEntryNodeData;
+ @Mock
+ private LeafNode<String> keyLeafNodeData;
+ @Mock
+ private LeafNode<String> anotherLeafNodeData;
+
+ private NodeIdentifier containerNodeIdentifier;
+ private NodeIdentifier mapNodeIdentifier;
+ private NodeIdentifierWithPredicates mapEntryNodeIdentifier;
+ private NodeIdentifier leafSetNodeIdentifier;
+ private NodeWithValue<String> leafSetEntryNodeIdentifier;
+ private NodeIdentifier keyLeafNodeIdentifier;
+ private NodeIdentifier anotherLeafNodeIdentifier;
+
+ private Collection<DataContainerChild> containerNodeValue;
+ private Collection<MapEntryNode> mapNodeValue;
+ private Collection<DataContainerChild> mapEntryNodeValue;
+ private Collection<LeafSetEntryNode<String>> leafSetNodeValue;
+ private String leafSetEntryNodeValue;
+ private String keyLeafNodeValue;
+ private String anotherLeafNodeValue;
+
+ @Before
+ public void setUp() {
+ // identifiers
+ containerNodeIdentifier = NodeIdentifier.create(QName.create("namespace", "container"));
+ when(containerNodeData.getIdentifier()).thenReturn(containerNodeIdentifier);
+
+ mapNodeIdentifier = NodeIdentifier.create(QName.create("namespace", "list"));
+ when(mapNodeData.getIdentifier()).thenReturn(mapNodeIdentifier);
+
+ final QName leafSetEntryNodeQName = QName.create("namespace", "leaf-set-entry");
+ leafSetEntryNodeValue = "leaf-set-value";
+ leafSetEntryNodeIdentifier = new NodeWithValue<>(leafSetEntryNodeQName, leafSetEntryNodeValue);
+ when(leafSetEntryNodeData.getIdentifier()).thenReturn(leafSetEntryNodeIdentifier);
+
+ leafSetNodeIdentifier = NodeIdentifier.create(QName.create("namespace", "leaf-set"));
+ when(leafSetNodeData.getIdentifier()).thenReturn(leafSetNodeIdentifier);
+
+ final QName mapEntryNodeKey = QName.create("namespace", "key-field");
+ keyLeafNodeIdentifier = NodeIdentifier.create(mapEntryNodeKey);
+ keyLeafNodeValue = "key-value";
+
+ mapEntryNodeIdentifier = NodeIdentifierWithPredicates.of(
+ QName.create("namespace", "list-entry"), mapEntryNodeKey, keyLeafNodeValue);
+ when(mapEntryNodeData.getIdentifier()).thenReturn(mapEntryNodeIdentifier);
+ when(mapEntryNodeData.findChildByArg(keyLeafNodeIdentifier)).thenReturn(Optional.of(keyLeafNodeData));
+
+ when(keyLeafNodeData.body()).thenReturn(keyLeafNodeValue);
+ when(keyLeafNodeData.getIdentifier()).thenReturn(keyLeafNodeIdentifier);
+
+ anotherLeafNodeIdentifier = NodeIdentifier.create(QName.create("namespace", "another-field"));
+ anotherLeafNodeValue = "another-value";
+
+ when(anotherLeafNodeData.body()).thenReturn(anotherLeafNodeValue);
+ when(anotherLeafNodeData.getIdentifier()).thenReturn(anotherLeafNodeIdentifier);
+
+ // values
+ when(leafSetEntryNodeData.body()).thenReturn(leafSetEntryNodeValue);
+
+ leafSetNodeValue = Collections.singletonList(leafSetEntryNodeData);
+ when(leafSetNodeData.body()).thenReturn(leafSetNodeValue);
+
+ containerNodeValue = Collections.singleton(leafSetNodeData);
+ when(containerNodeData.body()).thenReturn(containerNodeValue);
+
+ mapEntryNodeValue = Sets.newHashSet(keyLeafNodeData, anotherLeafNodeData);
+ when(mapEntryNodeData.body()).thenReturn(mapEntryNodeValue);
+
+ mapNodeValue = Collections.singleton(mapEntryNodeData);
+ when(mapNodeData.body()).thenReturn(mapNodeValue);
+ }
+
+ /**
+ * Test write {@link ContainerNode} with children but write data only to depth 1 (children will not be written).
+ */
+ @Test
+ public void writeContainerWithoutChildrenTest() throws Exception {
+ final DepthAwareNormalizedNodeWriter depthWriter = DepthAwareNormalizedNodeWriter.forStreamWriter(writer, 1);
+
+ depthWriter.write(containerNodeData);
+
+ final InOrder inOrder = inOrder(writer);
+ inOrder.verify(writer, times(1)).startContainerNode(containerNodeIdentifier, containerNodeValue.size());
+ inOrder.verify(writer, times(1)).endNode();
+ verifyNoMoreInteractions(writer);
+ }
+
+ /**
+ * Test write {@link ContainerNode} with children and write also all its children.
+ */
+ @Test
+ public void writeContainerWithChildrenTest() throws Exception {
+ final DepthAwareNormalizedNodeWriter depthWriter = DepthAwareNormalizedNodeWriter.forStreamWriter(
+ writer, Integer.MAX_VALUE);
+
+ depthWriter.write(containerNodeData);
+
+ final InOrder inOrder = inOrder(writer);
+ inOrder.verify(writer, times(1)).startContainerNode(containerNodeIdentifier, containerNodeValue.size());
+ inOrder.verify(writer, times(1)).startLeafSet(leafSetNodeIdentifier, leafSetNodeValue.size());
+ inOrder.verify(writer, times(1)).startLeafSetEntryNode(leafSetEntryNodeIdentifier);
+ inOrder.verify(writer, times(1)).scalarValue(leafSetEntryNodeValue);
+ inOrder.verify(writer, times(3)).endNode();
+ verifyNoMoreInteractions(writer);
+ }
+
+ /**
+ * Test write with {@link MapNode} with children but write data only to depth 1 (children will not be written).
+ */
+ @Test
+ public void writeMapNodeWithoutChildrenTest() throws Exception {
+ final DepthAwareNormalizedNodeWriter depthWriter = DepthAwareNormalizedNodeWriter.forStreamWriter(writer, 1);
+
+ depthWriter.write(mapNodeData);
+
+ final InOrder inOrder = inOrder(writer);
+ inOrder.verify(writer, times(1)).startMapNode(mapNodeIdentifier, mapNodeValue.size());
+ inOrder.verify(writer, times(1)).startMapEntryNode(mapEntryNodeIdentifier, mapEntryNodeValue.size());
+ inOrder.verify(writer, times(1)).startLeafNode(keyLeafNodeIdentifier);
+ inOrder.verify(writer, times(1)).scalarValue(keyLeafNodeValue);
+ inOrder.verify(writer, times(3)).endNode();
+ verifyNoMoreInteractions(writer);
+ }
+
+ /**
+ * Test write {@link MapNode} with children and write also all its children.
+ * FIXME
+ * Although ordered writer is used leaves are not written in expected order.
+ *
+ */
+ @Ignore
+ @Test
+ public void writeMapNodeWithChildrenTest() throws Exception {
+ final DepthAwareNormalizedNodeWriter depthWriter = DepthAwareNormalizedNodeWriter.forStreamWriter(
+ writer, Integer.MAX_VALUE);
+
+ depthWriter.write(mapNodeData);
+
+ final InOrder inOrder = inOrder(writer);
+ inOrder.verify(writer, times(1)).startMapNode(mapNodeIdentifier, mapNodeValue.size());
+ inOrder.verify(writer, times(1)).startMapEntryNode(mapEntryNodeIdentifier, mapEntryNodeValue.size());
+ inOrder.verify(writer, times(1)).startLeafNode(keyLeafNodeIdentifier);
+ inOrder.verify(writer, times(1)).scalarValue(keyLeafNodeValue);
+ inOrder.verify(writer, times(1)).endNode();
+ inOrder.verify(writer, times(1)).startLeafNode(keyLeafNodeIdentifier);
+ inOrder.verify(writer, times(1)).scalarValue(keyLeafNodeValue);
+ inOrder.verify(writer, times(1)).endNode();
+
+ // FIXME this assertion is not working because leaves are not written in expected order
+ inOrder.verify(writer, times(1)).startLeafNode(anotherLeafNodeIdentifier);
+ inOrder.verify(writer, times(1)).scalarValue(anotherLeafNodeValue);
+ inOrder.verify(writer, times(3)).endNode();
+ verifyNoMoreInteractions(writer);
+ }
+
+ /**
+ * Test write with {@link LeafSetNode} with depth 1 (children will not be written).
+ */
+ @Test
+ public void writeLeafSetNodeWithoutChildrenTest() throws Exception {
+ final DepthAwareNormalizedNodeWriter depthWriter = DepthAwareNormalizedNodeWriter.forStreamWriter(
+ writer, 1);
+
+ depthWriter.write(leafSetNodeData);
+
+ final InOrder inOrder = inOrder(writer);
+ inOrder.verify(writer, times(1)).startLeafSet(leafSetNodeIdentifier, leafSetNodeValue.size());
+ inOrder.verify(writer, times(1)).endNode();
+ verifyNoMoreInteractions(writer);
+ }
+
+ /**
+ * Test write with {@link LeafSetNode} when all its children will be written.
+ */
+ @Test
+ public void writeLeafSetNodeWithChildrenTest() throws Exception {
+ final DepthAwareNormalizedNodeWriter depthWriter = DepthAwareNormalizedNodeWriter.forStreamWriter(
+ writer, Integer.MAX_VALUE);
+
+ depthWriter.write(leafSetNodeData);
+
+ final InOrder inOrder = inOrder(writer);
+ inOrder.verify(writer, times(1)).startLeafSet(leafSetNodeIdentifier, leafSetNodeValue.size());
+ inOrder.verify(writer, times(1)).startLeafSetEntryNode(leafSetEntryNodeIdentifier);
+ inOrder.verify(writer, times(1)).scalarValue(leafSetEntryNodeValue);
+ inOrder.verify(writer, times(2)).endNode();
+ verifyNoMoreInteractions(writer);
+ }
+
+ /**
+ * Test write with {@link LeafSetEntryNode}.
+ */
+ @Test
+ public void writeLeafSetEntryNodeTest() throws Exception {
+ final DepthAwareNormalizedNodeWriter depthWriter = DepthAwareNormalizedNodeWriter.forStreamWriter(
+ writer, Integer.MAX_VALUE);
+
+ depthWriter.write(leafSetEntryNodeData);
+
+ final InOrder inOrder = inOrder(writer);
+ inOrder.verify(writer, times(1)).startLeafSetEntryNode(leafSetEntryNodeIdentifier);
+ inOrder.verify(writer, times(1)).scalarValue(leafSetEntryNodeValue);
+ inOrder.verify(writer, times(1)).endNode();
+ verifyNoMoreInteractions(writer);
+ }
+
+ /**
+ * Test write with {@link MapEntryNode} unordered to depth 1 to write only keys.
+ */
+ @Test
+ public void writeMapEntryNodeUnorderedOnlyKeysTest() throws Exception {
+ final DepthAwareNormalizedNodeWriter depthWriter = DepthAwareNormalizedNodeWriter.forStreamWriter(
+ writer, false, 1);
+
+ depthWriter.write(mapEntryNodeData);
+
+ final InOrder inOrder = inOrder(writer);
+ inOrder.verify(writer, times(1)).startMapEntryNode(mapEntryNodeIdentifier, mapEntryNodeValue.size());
+ // write only the key
+ inOrder.verify(writer, times(1)).startLeafNode(keyLeafNodeIdentifier);
+ inOrder.verify(writer, times(1)).scalarValue(keyLeafNodeValue);
+ inOrder.verify(writer, times(2)).endNode();
+ verifyNoMoreInteractions(writer);
+ }
+
+ /**
+ * Test write with {@link MapEntryNode} unordered with full depth.
+ */
+ @Test
+ public void writeMapEntryNodeUnorderedTest() throws Exception {
+ final DepthAwareNormalizedNodeWriter depthWriter = DepthAwareNormalizedNodeWriter.forStreamWriter(
+ writer, false, Integer.MAX_VALUE);
+
+ depthWriter.write(mapEntryNodeData);
+
+ // unordered
+ verify(writer, times(1)).startMapEntryNode(mapEntryNodeIdentifier, mapEntryNodeValue.size());
+ verify(writer, times(1)).startLeafNode(keyLeafNodeIdentifier);
+ verify(writer, times(1)).scalarValue(keyLeafNodeValue);
+ verify(writer, times(1)).startLeafNode(anotherLeafNodeIdentifier);
+ verify(writer, times(1)).scalarValue(anotherLeafNodeValue);
+ verify(writer, times(3)).endNode();
+ verifyNoMoreInteractions(writer);
+ }
+
+ /**
+ * Test write with {@link MapEntryNode} ordered with depth 1 (children will not be written).
+ */
+ @Test
+ public void writeMapEntryNodeOrderedWithoutChildrenTest() throws Exception {
+ final DepthAwareNormalizedNodeWriter depthWriter = DepthAwareNormalizedNodeWriter.forStreamWriter(
+ writer, true, 1);
+
+ depthWriter.write(mapEntryNodeData);
+
+ final InOrder inOrder = inOrder(writer);
+ inOrder.verify(writer, times(1)).startMapEntryNode(mapEntryNodeIdentifier, mapEntryNodeValue.size());
+ inOrder.verify(writer, times(1)).startLeafNode(keyLeafNodeIdentifier);
+ inOrder.verify(writer, times(1)).scalarValue(keyLeafNodeValue);
+ inOrder.verify(writer, times(2)).endNode();
+ verifyNoMoreInteractions(writer);
+ }
+
+ /**
+ * Test write with {@link MapEntryNode} ordered and write also all its children.
+ * FIXME
+ * Although ordered writer is used leaves are not written in expected order.
+ *
+ */
+ @Ignore
+ @Test
+ public void writeMapEntryNodeOrderedTest() throws Exception {
+ final DepthAwareNormalizedNodeWriter depthWriter = DepthAwareNormalizedNodeWriter.forStreamWriter(
+ writer, true, Integer.MAX_VALUE);
+
+ depthWriter.write(mapEntryNodeData);
+
+ final InOrder inOrder = inOrder(writer);
+ inOrder.verify(writer, times(1)).startMapEntryNode(mapEntryNodeIdentifier, mapEntryNodeValue.size());
+ inOrder.verify(writer, times(2)).startLeafNode(keyLeafNodeIdentifier);
+ inOrder.verify(writer, times(2)).scalarValue(keyLeafNodeValue);
+ inOrder.verify(writer, times(1)).endNode();
+ // FIXME this assertion is not working because leaves are not written in expected order
+ inOrder.verify(writer, times(1)).startLeafNode(anotherLeafNodeIdentifier);
+ inOrder.verify(writer, times(2)).scalarValue(anotherLeafNodeValue);
+ inOrder.verify(writer, times(2)).endNode();
+ verifyNoMoreInteractions(writer);
+ }
+} \ No newline at end of file
diff --git a/netconf/restconf/restconf-nb-bierman02/src/test/java/org/opendaylight/netconf/sal/restconf/impl/InstanceIdentifierCodecImplTest.java b/netconf/restconf/restconf-nb-bierman02/src/test/java/org/opendaylight/netconf/sal/restconf/impl/InstanceIdentifierCodecImplTest.java
new file mode 100644
index 0000000..e0d48bb
--- /dev/null
+++ b/netconf/restconf/restconf-nb-bierman02/src/test/java/org/opendaylight/netconf/sal/restconf/impl/InstanceIdentifierCodecImplTest.java
@@ -0,0 +1,99 @@
+/*
+ * Copyright (c) 2016 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.sal.restconf.impl;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNull;
+
+import java.io.FileNotFoundException;
+import org.junit.Before;
+import org.junit.BeforeClass;
+import org.junit.Test;
+import org.opendaylight.controller.md.sal.rest.common.TestRestconfUtils;
+import org.opendaylight.netconf.sal.restconf.impl.RestCodec.InstanceIdentifierCodecImpl;
+import org.opendaylight.restconf.common.util.IdentityValuesDTO;
+import org.opendaylight.yangtools.yang.common.QName;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifierWithPredicates;
+import org.opendaylight.yangtools.yang.model.api.EffectiveModelContext;
+import org.opendaylight.yangtools.yang.test.util.YangParserTestUtils;
+
+public class InstanceIdentifierCodecImplTest {
+ private static EffectiveModelContext schemaContext;
+
+ private InstanceIdentifierCodecImpl instanceIdentifierDTO;
+ private YangInstanceIdentifier instanceIdentifierBadNamespace;
+ private YangInstanceIdentifier instanceIdentifierOKList;
+ private YangInstanceIdentifier instanceIdentifierOKLeafList;
+
+ @BeforeClass
+ public static void init() throws FileNotFoundException {
+ schemaContext = YangParserTestUtils.parseYangFiles(
+ TestRestconfUtils.loadFiles("/restconf/parser/deserializer"));
+ }
+
+ @Before
+ public void setUp() throws Exception {
+ ControllerContext controllerContext = TestRestconfUtils.newControllerContext(schemaContext);
+
+ this.instanceIdentifierDTO = new InstanceIdentifierCodecImpl(null, controllerContext);
+
+ final QName baseQName = QName.create("deserializer:test", "2016-06-06", "deserializer-test");
+ final QName contA = QName.create(baseQName, "contA");
+ final QName leafList = QName.create(baseQName, "leaf-list-A");
+
+ this.instanceIdentifierOKLeafList = YangInstanceIdentifier.builder()
+ .node(contA)
+ .node(new YangInstanceIdentifier.NodeWithValue<>(leafList, "instance"))
+ .build();
+
+ this.instanceIdentifierOKList = YangInstanceIdentifier.builder()
+ .node(NodeIdentifierWithPredicates.of(
+ QName.create(baseQName, "list-one-key"),
+ QName.create(QName.create(baseQName, "list-one-key"), "name"), "value"))
+ .build();
+
+ this.instanceIdentifierBadNamespace = YangInstanceIdentifier.builder()
+ .nodeWithKey(QName.create("nonexistent:module", "2016-10-17", "nonexistent-1"),
+ QName.create("nonexistent:module", "2016-10-17", "nonexistent"),
+ "value")
+ .build();
+ }
+
+ @Test
+ public void testSerializeDeserializeList() throws Exception {
+ final IdentityValuesDTO valuesDTO =
+ this.instanceIdentifierDTO.serialize(this.instanceIdentifierOKList);
+
+ final YangInstanceIdentifier deserializedIdentifier =
+ this.instanceIdentifierDTO.deserialize(valuesDTO);
+ assertEquals(this.instanceIdentifierOKList, deserializedIdentifier);
+ }
+
+ @Test
+ public void testSerializeDeserializeLeafList() throws Exception {
+ final IdentityValuesDTO valuesDTO =
+ this.instanceIdentifierDTO.serialize(this.instanceIdentifierOKLeafList);
+
+ final YangInstanceIdentifier deserializedIdentifier =
+ this.instanceIdentifierDTO.deserialize(valuesDTO);
+ assertEquals(this.instanceIdentifierOKLeafList, deserializedIdentifier);
+ }
+
+ @Test
+ public void testSerializeDeserializeBadModuleNamespace() throws Exception {
+ final IdentityValuesDTO valuesDTO =
+ this.instanceIdentifierDTO.serialize(this.instanceIdentifierBadNamespace);
+ assertEquals("nonexistent-1", valuesDTO.getValuesWithNamespaces().get(0).getValue());
+ assertEquals("nonexistent:module", valuesDTO.getValuesWithNamespaces().get(0).getNamespace());
+
+ final YangInstanceIdentifier deserializedIdentifier =
+ this.instanceIdentifierDTO.deserialize(valuesDTO);
+ assertNull(deserializedIdentifier);
+ }
+}
diff --git a/netconf/restconf/restconf-nb-bierman02/src/test/java/org/opendaylight/netconf/sal/streams/listeners/ListenerAdapterTest.java b/netconf/restconf/restconf-nb-bierman02/src/test/java/org/opendaylight/netconf/sal/streams/listeners/ListenerAdapterTest.java
new file mode 100644
index 0000000..453f077
--- /dev/null
+++ b/netconf/restconf/restconf-nb-bierman02/src/test/java/org/opendaylight/netconf/sal/streams/listeners/ListenerAdapterTest.java
@@ -0,0 +1,220 @@
+/*
+ * Copyright (c) 2017 Red Hat, 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.sal.streams.listeners;
+
+import static java.time.Instant.EPOCH;
+
+import java.io.IOException;
+import java.net.URISyntaxException;
+import java.net.URL;
+import java.nio.charset.StandardCharsets;
+import java.nio.file.Files;
+import java.nio.file.Paths;
+import java.util.Optional;
+import org.json.JSONObject;
+import org.junit.Before;
+import org.junit.BeforeClass;
+import org.junit.Test;
+import org.opendaylight.controller.md.sal.rest.common.TestRestconfUtils;
+import org.opendaylight.mdsal.binding.api.DataBroker;
+import org.opendaylight.mdsal.binding.api.WriteTransaction;
+import org.opendaylight.mdsal.binding.dom.adapter.test.AbstractConcurrentDataBrokerTest;
+import org.opendaylight.mdsal.common.api.LogicalDatastoreType;
+import org.opendaylight.mdsal.dom.api.DOMDataBroker;
+import org.opendaylight.mdsal.dom.api.DOMDataTreeChangeService;
+import org.opendaylight.mdsal.dom.api.DOMDataTreeIdentifier;
+import org.opendaylight.netconf.sal.restconf.impl.ControllerContext;
+import org.opendaylight.yang.gen.v1.instance.identifier.patch.module.rev151121.PatchCont;
+import org.opendaylight.yang.gen.v1.instance.identifier.patch.module.rev151121.patch.cont.MyList1;
+import org.opendaylight.yang.gen.v1.instance.identifier.patch.module.rev151121.patch.cont.MyList1Builder;
+import org.opendaylight.yang.gen.v1.instance.identifier.patch.module.rev151121.patch.cont.MyList1Key;
+import org.opendaylight.yang.gen.v1.urn.sal.restconf.event.subscription.rev140708.NotificationOutputTypeGrouping;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
+import org.opendaylight.yangtools.yang.model.api.EffectiveModelContext;
+import org.opendaylight.yangtools.yang.test.util.YangParserTestUtils;
+import org.skyscreamer.jsonassert.JSONAssert;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class ListenerAdapterTest extends AbstractConcurrentDataBrokerTest {
+ private static final Logger LOG = LoggerFactory.getLogger(ListenerAdapterTest.class);
+
+ private static final String JSON_NOTIF_LEAVES_CREATE = "/listener-adapter-test/notif-leaves-create.json";
+ private static final String JSON_NOTIF_LEAVES_UPDATE = "/listener-adapter-test/notif-leaves-update.json";
+ private static final String JSON_NOTIF_LEAVES_DEL = "/listener-adapter-test/notif-leaves-del.json";
+ private static final String JSON_NOTIF_CREATE = "/listener-adapter-test/notif-create.json";
+ private static final String JSON_NOTIF_UPDATE = "/listener-adapter-test/notif-update.json";
+ private static final String JSON_NOTIF_DEL = "/listener-adapter-test/notif-del.json";
+ private static final String JSON_NOTIF_WITHOUT_DATA_CREATE =
+ "/listener-adapter-test/notif-without-data-create.json";
+ private static final String JSON_NOTIF_WITHOUT_DATA_UPDATE =
+ "/listener-adapter-test/notif-without-data-update.json";
+ private static final String JSON_NOTIF_WITHOUT_DATA_DELETE =
+ "/listener-adapter-test/notif-without-data-del.json";
+
+
+ private static final YangInstanceIdentifier PATCH_CONT_YIID =
+ YangInstanceIdentifier.create(new YangInstanceIdentifier.NodeIdentifier(PatchCont.QNAME));
+
+ private static EffectiveModelContext schemaContext;
+
+ private DataBroker dataBroker;
+ private DOMDataBroker domDataBroker;
+ private ControllerContext controllerContext;
+
+ @BeforeClass
+ public static void init() {
+ schemaContext = YangParserTestUtils.parseYangResource(
+ "/instanceidentifier/yang/instance-identifier-patch-module.yang");
+ }
+
+ @Before
+ public void setUp() throws Exception {
+ dataBroker = getDataBroker();
+ domDataBroker = getDomBroker();
+ controllerContext = TestRestconfUtils.newControllerContext(schemaContext);
+ }
+
+ class ListenerAdapterTester extends ListenerAdapter {
+
+ private String lastNotification = null;
+
+ ListenerAdapterTester(final YangInstanceIdentifier path, final String streamName,
+ final NotificationOutputTypeGrouping.NotificationOutputType outputType,
+ final boolean leafNodesOnly, final boolean skipNotificationData) {
+ super(path, streamName, outputType, controllerContext);
+ setQueryParams(EPOCH, Optional.empty(), Optional.empty(), leafNodesOnly, skipNotificationData);
+ }
+
+ @Override
+ protected void post(final Event event) {
+ this.lastNotification = event.getData();
+ }
+
+ public void assertGot(final String json) throws Exception {
+ long start = System.currentTimeMillis();
+ while (true) {
+ if (lastNotification != null) {
+ break;
+ }
+ if (System.currentTimeMillis() - start > 1000) {
+ throw new Exception("TIMED OUT waiting for notification with " + json);
+ }
+ Thread.currentThread();
+ Thread.sleep(200);
+ }
+ LOG.debug("Comparing {} {}", json, lastNotification);
+ JSONAssert.assertEquals(json, withFakeDate(lastNotification), false);
+ this.lastNotification = null;
+ }
+ }
+
+ static String withFakeDate(final String in) {
+ JSONObject doc = new JSONObject(in);
+ JSONObject notification = doc.getJSONObject("notification");
+ if (notification == null) {
+ return in;
+ }
+ notification.put("eventTime", "someDate");
+ return doc.toString();
+ }
+
+ private String getNotifJson(final String path) throws IOException, URISyntaxException {
+ URL url = getClass().getResource(path);
+ byte[] bytes = Files.readAllBytes(Paths.get(url.toURI()));
+ return withFakeDate(new String(bytes, StandardCharsets.UTF_8));
+ }
+
+ @Test
+ public void testJsonNotifsLeaves() throws Exception {
+ ListenerAdapterTester adapter = new ListenerAdapterTester(PATCH_CONT_YIID, "Casey",
+ NotificationOutputTypeGrouping.NotificationOutputType.JSON, true, false);
+ DOMDataTreeChangeService changeService = domDataBroker.getExtensions()
+ .getInstance(DOMDataTreeChangeService.class);
+ DOMDataTreeIdentifier root = new DOMDataTreeIdentifier(LogicalDatastoreType.CONFIGURATION, PATCH_CONT_YIID);
+ changeService.registerDataTreeChangeListener(root, adapter);
+
+ WriteTransaction writeTransaction = dataBroker.newWriteOnlyTransaction();
+ MyList1Builder builder = new MyList1Builder().setMyLeaf11("Jed").setName("Althea");
+ InstanceIdentifier<MyList1> iid = InstanceIdentifier.create(PatchCont.class)
+ .child(MyList1.class, new MyList1Key("Althea"));
+ writeTransaction.mergeParentStructurePut(LogicalDatastoreType.CONFIGURATION, iid, builder.build());
+ writeTransaction.commit();
+ adapter.assertGot(getNotifJson(JSON_NOTIF_LEAVES_CREATE));
+
+ writeTransaction = dataBroker.newWriteOnlyTransaction();
+ builder = new MyList1Builder().withKey(new MyList1Key("Althea")).setMyLeaf12("Bertha");
+ writeTransaction.mergeParentStructureMerge(LogicalDatastoreType.CONFIGURATION, iid, builder.build());
+ writeTransaction.commit();
+ adapter.assertGot(getNotifJson(JSON_NOTIF_LEAVES_UPDATE));
+
+ writeTransaction = dataBroker.newWriteOnlyTransaction();
+ writeTransaction.delete(LogicalDatastoreType.CONFIGURATION, iid);
+ writeTransaction.commit();
+ adapter.assertGot(getNotifJson(JSON_NOTIF_LEAVES_DEL));
+ }
+
+ @Test
+ public void testJsonNotifs() throws Exception {
+ ListenerAdapterTester adapter = new ListenerAdapterTester(PATCH_CONT_YIID, "Casey",
+ NotificationOutputTypeGrouping.NotificationOutputType.JSON, false, false);
+ DOMDataTreeChangeService changeService = domDataBroker.getExtensions()
+ .getInstance(DOMDataTreeChangeService.class);
+ DOMDataTreeIdentifier root = new DOMDataTreeIdentifier(LogicalDatastoreType.CONFIGURATION, PATCH_CONT_YIID);
+ changeService.registerDataTreeChangeListener(root, adapter);
+
+ WriteTransaction writeTransaction = dataBroker.newWriteOnlyTransaction();
+ MyList1Builder builder = new MyList1Builder().setMyLeaf11("Jed").setName("Althea");
+ InstanceIdentifier<MyList1> iid = InstanceIdentifier.create(PatchCont.class)
+ .child(MyList1.class, new MyList1Key("Althea"));
+ writeTransaction.mergeParentStructurePut(LogicalDatastoreType.CONFIGURATION, iid, builder.build());
+ writeTransaction.commit();
+ adapter.assertGot(getNotifJson(JSON_NOTIF_CREATE));
+
+ writeTransaction = dataBroker.newWriteOnlyTransaction();
+ builder = new MyList1Builder().withKey(new MyList1Key("Althea")).setMyLeaf12("Bertha");
+ writeTransaction.mergeParentStructureMerge(LogicalDatastoreType.CONFIGURATION, iid, builder.build());
+ writeTransaction.commit();
+ adapter.assertGot(getNotifJson(JSON_NOTIF_UPDATE));
+
+ writeTransaction = dataBroker.newWriteOnlyTransaction();
+ writeTransaction.delete(LogicalDatastoreType.CONFIGURATION, iid);
+ writeTransaction.commit();
+ adapter.assertGot(getNotifJson(JSON_NOTIF_DEL));
+ }
+
+ @Test
+ public void testJsonNotifsWithoutData() throws Exception {
+ ListenerAdapterTester adapter = new ListenerAdapterTester(PATCH_CONT_YIID, "Casey",
+ NotificationOutputTypeGrouping.NotificationOutputType.JSON, false, true);
+ DOMDataTreeChangeService changeService = domDataBroker.getExtensions()
+ .getInstance(DOMDataTreeChangeService.class);
+ DOMDataTreeIdentifier root = new DOMDataTreeIdentifier(LogicalDatastoreType.CONFIGURATION, PATCH_CONT_YIID);
+ changeService.registerDataTreeChangeListener(root, adapter);
+
+ WriteTransaction writeTransaction = dataBroker.newWriteOnlyTransaction();
+ MyList1Builder builder = new MyList1Builder().setMyLeaf11("Jed").setName("Althea");
+ InstanceIdentifier<MyList1> iid = InstanceIdentifier.create(PatchCont.class)
+ .child(MyList1.class, new MyList1Key("Althea"));
+ writeTransaction.mergeParentStructurePut(LogicalDatastoreType.CONFIGURATION, iid, builder.build());
+ writeTransaction.commit();
+ adapter.assertGot(getNotifJson(JSON_NOTIF_WITHOUT_DATA_CREATE));
+
+ writeTransaction = dataBroker.newWriteOnlyTransaction();
+ builder = new MyList1Builder().withKey(new MyList1Key("Althea")).setMyLeaf12("Bertha");
+ writeTransaction.mergeParentStructureMerge(LogicalDatastoreType.CONFIGURATION, iid, builder.build());
+ writeTransaction.commit();
+ adapter.assertGot(getNotifJson(JSON_NOTIF_WITHOUT_DATA_UPDATE));
+
+ writeTransaction = dataBroker.newWriteOnlyTransaction();
+ writeTransaction.delete(LogicalDatastoreType.CONFIGURATION, iid);
+ writeTransaction.commit();
+ adapter.assertGot(getNotifJson(JSON_NOTIF_WITHOUT_DATA_DELETE));
+ }
+}
diff --git a/netconf/restconf/restconf-nb-bierman02/src/test/java/org/opendaylight/netconf/sal/streams/listeners/NotificationListenerTest.java b/netconf/restconf/restconf-nb-bierman02/src/test/java/org/opendaylight/netconf/sal/streams/listeners/NotificationListenerTest.java
new file mode 100644
index 0000000..732c327
--- /dev/null
+++ b/netconf/restconf/restconf-nb-bierman02/src/test/java/org/opendaylight/netconf/sal/streams/listeners/NotificationListenerTest.java
@@ -0,0 +1,206 @@
+/*
+ * Copyright (c) 2016 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.sal.streams.listeners;
+
+import static java.util.Objects.requireNonNull;
+import static org.junit.Assert.assertTrue;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+import java.io.FileNotFoundException;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+import java.util.Set;
+import org.junit.Before;
+import org.junit.BeforeClass;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.junit.MockitoJUnitRunner;
+import org.opendaylight.controller.md.sal.rest.common.TestRestconfUtils;
+import org.opendaylight.controller.sal.restconf.impl.test.TestUtils;
+import org.opendaylight.mdsal.dom.api.DOMNotification;
+import org.opendaylight.netconf.sal.restconf.impl.ControllerContext;
+import org.opendaylight.yang.gen.v1.urn.sal.restconf.event.subscription.rev140708.NotificationOutputTypeGrouping.NotificationOutputType;
+import org.opendaylight.yangtools.yang.common.QName;
+import org.opendaylight.yangtools.yang.common.QNameModule;
+import org.opendaylight.yangtools.yang.common.Revision;
+import org.opendaylight.yangtools.yang.common.XMLNamespace;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.AugmentationIdentifier;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifier;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifierWithPredicates;
+import org.opendaylight.yangtools.yang.data.api.schema.AugmentationNode;
+import org.opendaylight.yangtools.yang.data.api.schema.ContainerNode;
+import org.opendaylight.yangtools.yang.data.api.schema.DataContainerChild;
+import org.opendaylight.yangtools.yang.data.api.schema.LeafNode;
+import org.opendaylight.yangtools.yang.data.api.schema.MapEntryNode;
+import org.opendaylight.yangtools.yang.data.impl.schema.Builders;
+import org.opendaylight.yangtools.yang.data.impl.schema.ImmutableNodes;
+import org.opendaylight.yangtools.yang.model.api.EffectiveModelContext;
+import org.opendaylight.yangtools.yang.model.api.stmt.SchemaNodeIdentifier.Absolute;
+
+@RunWith(MockitoJUnitRunner.StrictStubs.class)
+public class NotificationListenerTest {
+ private static final QNameModule MODULE = QNameModule.create(XMLNamespace.of("notifi:mod"),
+ Revision.of("2016-11-23"));
+
+ private static EffectiveModelContext schemaContext;
+
+ private ControllerContext controllerContext;
+
+ @BeforeClass
+ public static void staticInit() throws FileNotFoundException {
+ schemaContext = TestUtils.loadSchemaContext("/notifications");
+ }
+
+ @Before
+ public void init() {
+ controllerContext = TestRestconfUtils.newControllerContext(schemaContext);
+ }
+
+ @Test
+ public void notifi_leafTest() {
+ final Absolute schemaPathNotifi = Absolute.of(QName.create(MODULE, "notifi-leaf"));
+
+ final DOMNotification notificationData = mock(DOMNotification.class);
+
+ final LeafNode<String> leaf = mockLeaf(QName.create(MODULE, "lf"));
+ final ContainerNode notifiBody = mockCont(schemaPathNotifi.lastNodeIdentifier(), leaf);
+
+ when(notificationData.getType()).thenReturn(schemaPathNotifi);
+ when(notificationData.getBody()).thenReturn(notifiBody);
+
+ final String result = prepareJson(notificationData, schemaPathNotifi);
+
+ assertTrue(result.contains("ietf-restconf:notification"));
+ assertTrue(result.contains("event-time"));
+ assertTrue(result.contains("notifi-module:notifi-leaf"));
+ assertTrue(result.contains("lf" + '"' + ":" + '"' + "value"));
+ }
+
+ @Test
+ public void notifi_cont_leafTest() {
+ final Absolute schemaPathNotifi = Absolute.of(QName.create(MODULE, "notifi-cont"));
+
+ final DOMNotification notificationData = mock(DOMNotification.class);
+
+ final LeafNode<String> leaf = mockLeaf(QName.create(MODULE, "lf"));
+ final ContainerNode cont = mockCont(QName.create(MODULE, "cont"), leaf);
+ final ContainerNode notifiBody = mockCont(schemaPathNotifi.lastNodeIdentifier(), cont);
+
+ when(notificationData.getType()).thenReturn(schemaPathNotifi);
+ when(notificationData.getBody()).thenReturn(notifiBody);
+
+ final String result = prepareJson(notificationData, schemaPathNotifi);
+
+ assertTrue(result.contains("ietf-restconf:notification"));
+ assertTrue(result.contains("event-time"));
+ assertTrue(result.contains("notifi-module:notifi-cont"));
+ assertTrue(result.contains("cont"));
+ assertTrue(result.contains("lf" + '"' + ":" + '"' + "value"));
+ }
+
+ @Test
+ public void notifi_list_Test() {
+ final Absolute schemaPathNotifi = Absolute.of(QName.create(MODULE, "notifi-list"));
+
+ final ContainerNode notifiBody = mockCont(schemaPathNotifi.lastNodeIdentifier(), ImmutableNodes.mapNodeBuilder()
+ .withNodeIdentifier(NodeIdentifier.create(QName.create(MODULE, "lst")))
+ .withChild(mockMapEntry(QName.create(MODULE, "lst"), mockLeaf(QName.create(MODULE, "lf"))))
+ .build());
+
+ final DOMNotification notificationData = mock(DOMNotification.class);
+ when(notificationData.getType()).thenReturn(schemaPathNotifi);
+ when(notificationData.getBody()).thenReturn(notifiBody);
+
+ final String result = prepareJson(notificationData, schemaPathNotifi);
+
+ assertTrue(result.contains("ietf-restconf:notification"));
+ assertTrue(result.contains("event-time"));
+ assertTrue(result.contains("notifi-module:notifi-list"));
+ assertTrue(result.contains("lst"));
+ assertTrue(result.contains("lf" + '"' + ":" + '"' + "value"));
+ }
+
+ @Test
+ public void notifi_grpTest() {
+ final Absolute schemaPathNotifi = Absolute.of(QName.create(MODULE, "notifi-grp"));
+
+ final DOMNotification notificationData = mock(DOMNotification.class);
+
+ final LeafNode<String> leaf = mockLeaf(QName.create(MODULE, "lf"));
+ final ContainerNode notifiBody = mockCont(schemaPathNotifi.lastNodeIdentifier(), leaf);
+
+ when(notificationData.getType()).thenReturn(schemaPathNotifi);
+ when(notificationData.getBody()).thenReturn(notifiBody);
+
+ final String result = prepareJson(notificationData, schemaPathNotifi);
+
+ assertTrue(result.contains("ietf-restconf:notification"));
+ assertTrue(result.contains("event-time"));
+ assertTrue(result.contains("lf" + '"' + ":" + '"' + "value"));
+ }
+
+ @Test
+ public void notifi_augmTest() {
+ final Absolute schemaPathNotifi = Absolute.of(QName.create(MODULE, "notifi-augm"));
+
+ final DOMNotification notificationData = mock(DOMNotification.class);
+
+ final LeafNode<String> leaf = mockLeaf(QName.create(MODULE, "lf-augm"));
+ final AugmentationNode augm = mockAugm(leaf);
+ final ContainerNode notifiBody = mockCont(schemaPathNotifi.lastNodeIdentifier(), augm);
+
+ when(notificationData.getType()).thenReturn(schemaPathNotifi);
+ when(notificationData.getBody()).thenReturn(notifiBody);
+
+ final String result = prepareJson(notificationData, schemaPathNotifi);
+
+ assertTrue(result.contains("ietf-restconf:notification"));
+ assertTrue(result.contains("event-time"));
+ assertTrue(result.contains("lf-augm" + '"' + ":" + '"' + "value"));
+ }
+
+ private static AugmentationNode mockAugm(final LeafNode<String> leaf) {
+ final AugmentationNode augm = mock(AugmentationNode.class);
+ final AugmentationIdentifier augmId = new AugmentationIdentifier(Set.of(leaf.getIdentifier().getNodeType()));
+ when(augm.getIdentifier()).thenReturn(augmId);
+
+ final Collection<DataContainerChild> childs = new ArrayList<>();
+ childs.add(leaf);
+
+ when(augm.body()).thenReturn(childs);
+ return augm;
+ }
+
+ private static MapEntryNode mockMapEntry(final QName entryQName, final LeafNode<String> leaf) {
+ return Builders.mapEntryBuilder()
+ .withNodeIdentifier(NodeIdentifierWithPredicates.of(entryQName, leaf.getIdentifier().getNodeType(),
+ leaf.body()))
+ .withChild(leaf)
+ .build();
+ }
+
+ private static ContainerNode mockCont(final QName contQName, final DataContainerChild child) {
+ return Builders.containerBuilder()
+ .withNodeIdentifier(NodeIdentifier.create(contQName))
+ .withChild(child)
+ .build();
+ }
+
+ private static LeafNode<String> mockLeaf(final QName leafQName) {
+ return ImmutableNodes.leafNode(leafQName, "value");
+ }
+
+ private String prepareJson(final DOMNotification notificationData, final Absolute schemaPathNotifi) {
+ final List<NotificationListenerAdapter> listNotifi = Notificator.createNotificationListener(
+ List.of(schemaPathNotifi), "stream-name", NotificationOutputType.JSON.toString(), controllerContext);
+ final NotificationListenerAdapter notifi = listNotifi.get(0);
+ return requireNonNull(notifi.prepareJson(schemaContext, notificationData));
+ }
+}
diff --git a/netconf/restconf/restconf-nb-bierman02/src/test/java/org/opendaylight/yang/gen/v1/urn/ietf/params/xml/ns/yang/ietf/restconf/rev131019/DatastoreIdentifierBuilderTest.java b/netconf/restconf/restconf-nb-bierman02/src/test/java/org/opendaylight/yang/gen/v1/urn/ietf/params/xml/ns/yang/ietf/restconf/rev131019/DatastoreIdentifierBuilderTest.java
new file mode 100644
index 0000000..f3ab6f9
--- /dev/null
+++ b/netconf/restconf/restconf-nb-bierman02/src/test/java/org/opendaylight/yang/gen/v1/urn/ietf/params/xml/ns/yang/ietf/restconf/rev131019/DatastoreIdentifierBuilderTest.java
@@ -0,0 +1,23 @@
+/*
+ * Copyright (c) 2016 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.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.restconf.rev131019;
+
+import static org.junit.Assert.assertNotNull;
+
+import org.junit.Test;
+
+public class DatastoreIdentifierBuilderTest {
+
+ @Test(expected = IllegalArgumentException.class)
+ public void testDatastoreIdentifierBuilder() {
+ final DatastoreIdentifierBuilder datastoreIdentifierBuilder = new DatastoreIdentifierBuilder();
+ assertNotNull(datastoreIdentifierBuilder);
+ DatastoreIdentifierBuilder.getDefaultInstance("");
+ }
+} \ No newline at end of file
diff --git a/netconf/restconf/restconf-nb-bierman02/src/test/java/org/opendaylight/yang/gen/v1/urn/ietf/params/xml/ns/yang/ietf/restconf/rev131019/restconf/restconf/modules/ModuleBuilderTest.java b/netconf/restconf/restconf-nb-bierman02/src/test/java/org/opendaylight/yang/gen/v1/urn/ietf/params/xml/ns/yang/ietf/restconf/rev131019/restconf/restconf/modules/ModuleBuilderTest.java
new file mode 100644
index 0000000..a834b15
--- /dev/null
+++ b/netconf/restconf/restconf-nb-bierman02/src/test/java/org/opendaylight/yang/gen/v1/urn/ietf/params/xml/ns/yang/ietf/restconf/rev131019/restconf/restconf/modules/ModuleBuilderTest.java
@@ -0,0 +1,70 @@
+/*
+ * Copyright (c) 2016 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.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.restconf.rev131019.restconf.restconf.modules;
+
+import static junit.framework.TestCase.assertTrue;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+
+import com.google.common.collect.ImmutableSet;
+import java.util.Set;
+import org.junit.Test;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.Uri;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.restconf.rev131019.RevisionIdentifier;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.YangIdentifier;
+
+public class ModuleBuilderTest {
+
+ @Test
+ public void testModuleBuilder() {
+ final ModuleBuilder moduleBuilder = new ModuleBuilder();
+ final Module.Revision revision = new Module.Revision(new RevisionIdentifier("2016-10-11"));
+ final YangIdentifier yangIdentifierOne = new YangIdentifier("YangIdentifier1");
+ final YangIdentifier yangIdentifierTwo = new YangIdentifier("YangIdentifier2");
+ final Uri namespace = new Uri("namespace");
+ final Set<YangIdentifier> yangIdentifierList = ImmutableSet.of(yangIdentifierOne, yangIdentifierTwo);
+ final ModuleKey moduleKeyOne = new ModuleKey(yangIdentifierOne, revision);
+ final ModuleKey moduleKeyTwo = new ModuleKey(moduleKeyOne);
+ moduleBuilder.setRevision(revision);
+ moduleBuilder.setDeviation(yangIdentifierList);
+ moduleBuilder.setFeature(yangIdentifierList);
+ moduleBuilder.setName(yangIdentifierOne);
+ moduleBuilder.setNamespace(namespace);
+ moduleBuilder.withKey(moduleKeyOne);
+ final Module moduleOne = moduleBuilder.build();
+ final Module moduleTwo = new ModuleBuilder(moduleOne).build();
+
+ assertNotNull(moduleBuilder);
+ assertNotNull(revision);
+ assertNotNull(yangIdentifierOne);
+ assertNotNull(yangIdentifierTwo);
+ assertNotNull(namespace);
+ assertNotNull(yangIdentifierList);
+ assertNotNull(moduleKeyOne);
+ assertNotNull(moduleKeyOne.hashCode());
+ assertNotNull(moduleKeyOne.toString());
+ assertNotNull(moduleBuilder.toString());
+ assertNotNull(moduleBuilder.hashCode());
+
+ assertEquals(moduleKeyOne, moduleKeyTwo);
+ assertEquals(revision, moduleKeyOne.getRevision());
+ assertEquals(yangIdentifierOne, moduleKeyOne.getName());
+ assertEquals(revision, moduleBuilder.getRevision());
+ assertEquals(yangIdentifierList, moduleBuilder.getDeviation());
+ assertEquals(yangIdentifierList, moduleBuilder.getFeature());
+ assertEquals(yangIdentifierOne, moduleBuilder.getName());
+ assertEquals(namespace, moduleBuilder.getNamespace());
+ assertEquals(moduleKeyOne, moduleBuilder.key());
+ assertEquals(moduleOne.toString(), moduleTwo.toString());
+ assertEquals(moduleKeyOne.toString(), moduleKeyTwo.toString());
+
+ assertTrue(moduleOne.equals(moduleTwo));
+ assertTrue(moduleKeyOne.equals(moduleKeyTwo));
+ }
+}
diff --git a/netconf/restconf/restconf-nb-bierman02/src/test/java/org/opendaylight/yang/gen/v1/urn/ietf/params/xml/ns/yang/ietf/restconf/rev131019/restconf/restconf/modules/ModuleRevisionBuilderTest.java b/netconf/restconf/restconf-nb-bierman02/src/test/java/org/opendaylight/yang/gen/v1/urn/ietf/params/xml/ns/yang/ietf/restconf/rev131019/restconf/restconf/modules/ModuleRevisionBuilderTest.java
new file mode 100644
index 0000000..578d2dd
--- /dev/null
+++ b/netconf/restconf/restconf-nb-bierman02/src/test/java/org/opendaylight/yang/gen/v1/urn/ietf/params/xml/ns/yang/ietf/restconf/rev131019/restconf/restconf/modules/ModuleRevisionBuilderTest.java
@@ -0,0 +1,28 @@
+/*
+ * Copyright (c) 2016 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.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.restconf.rev131019.restconf.restconf.modules;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+
+import org.junit.Test;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.restconf.rev131019.restconf.restconf.modules.Module.Revision;
+
+public class ModuleRevisionBuilderTest {
+
+ @Test
+ public void testModuleRevisionBuilder() {
+ final ModuleRevisionBuilder moduleRevisionBuilder = new ModuleRevisionBuilder();
+ assertNotNull(moduleRevisionBuilder);
+ final Revision revision = ModuleRevisionBuilder.getDefaultInstance("");
+ assertNotNull(revision);
+ assertEquals("", revision.getString());
+ assertEquals(null, revision.getRevisionIdentifier());
+ }
+} \ No newline at end of file
diff --git a/netconf/restconf/restconf-nb-bierman02/src/test/java/org/opendaylight/yang/gen/v1/urn/ietf/params/xml/ns/yang/ietf/restconf/rev131019/restconf/restconf/modules/RevisionBuilderTest.java b/netconf/restconf/restconf-nb-bierman02/src/test/java/org/opendaylight/yang/gen/v1/urn/ietf/params/xml/ns/yang/ietf/restconf/rev131019/restconf/restconf/modules/RevisionBuilderTest.java
new file mode 100644
index 0000000..5c2eba1
--- /dev/null
+++ b/netconf/restconf/restconf-nb-bierman02/src/test/java/org/opendaylight/yang/gen/v1/urn/ietf/params/xml/ns/yang/ietf/restconf/rev131019/restconf/restconf/modules/RevisionBuilderTest.java
@@ -0,0 +1,49 @@
+/*
+ * Copyright (c) 2014 Brocade Communications 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.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.restconf.rev131019.restconf.restconf.modules;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+
+import org.junit.Test;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.restconf.rev131019.RevisionIdentifier;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.restconf.rev131019.restconf.restconf.modules.Module.Revision;
+
+public class RevisionBuilderTest {
+ @Test
+ public void testEmptyString() {
+ final RevisionBuilder revisionBuilder = new RevisionBuilder();
+ assertNotNull(revisionBuilder);
+ final Revision revision = RevisionBuilder.getDefaultInstance("");
+ validate(revision, "", null);
+ }
+
+ @Test
+ public void testValidDataString() {
+ final String dateString = "2014-04-23";
+ final Revision revision = RevisionBuilder.getDefaultInstance(dateString);
+ validate(revision, null, new RevisionIdentifier(dateString));
+ }
+
+ @Test(expected = IllegalArgumentException.class)
+ public void testNullString() {
+ RevisionBuilder.getDefaultInstance(null);
+ }
+
+ @Test(expected = IllegalArgumentException.class)
+ public void testBadFormatString() {
+ RevisionBuilder.getDefaultInstance("badFormat");
+ }
+
+ private static void validate(final Revision revisionUnderTest, final String expectedRevisionString,
+ final RevisionIdentifier expectedRevisionIdentifier) {
+ assertNotNull(revisionUnderTest);
+ assertEquals(expectedRevisionString, revisionUnderTest.getString());
+ assertEquals(expectedRevisionIdentifier, revisionUnderTest.getRevisionIdentifier());
+ }
+} \ No newline at end of file