Fix patch target parsing 10/97210/10
authorRobert Varga <robert.varga@pantheon.tech>
Fri, 13 Aug 2021 20:28:24 +0000 (22:28 +0200)
committerRobert Varga <robert.varga@pantheon.tech>
Sat, 14 Aug 2021 12:14:47 +0000 (14:14 +0200)
Our tests were not updated for RFC8040, hence they are written with
weird codecs which utterly do not match RFC8072 definition of
yang-patch.

The problem is that patch edit's target is interpreted in terms of an
extension to the URL, i.e. it does NOT follow JSON nor XML parsing
rules, nor is it anything in-between -- we must use ParserIdentifier's
facilities.

Update the parsers and the test suites, ditching a lot of complexity
in process of doing so.

JIRA: NETCONF-804
Change-Id: If9d9c77e0e2397ffdcb8e8c0f0fef0b9b02bac8b
Signed-off-by: Robert Varga <robert.varga@pantheon.tech>
13 files changed:
restconf/restconf-nb-rfc8040/src/main/java/org/opendaylight/restconf/nb/rfc8040/jersey/providers/patch/JsonPatchBodyReader.java
restconf/restconf-nb-rfc8040/src/main/java/org/opendaylight/restconf/nb/rfc8040/jersey/providers/patch/XmlPatchBodyReader.java
restconf/restconf-nb-rfc8040/src/main/java/org/opendaylight/restconf/nb/rfc8040/utils/parser/ParserIdentifier.java
restconf/restconf-nb-rfc8040/src/test/java/org/opendaylight/restconf/nb/rfc8040/jersey/providers/patch/JsonPatchBodyReaderMountPointTest.java
restconf/restconf-nb-rfc8040/src/test/java/org/opendaylight/restconf/nb/rfc8040/jersey/providers/patch/XmlPatchBodyReaderMountPointTest.java
restconf/restconf-nb-rfc8040/src/test/java/org/opendaylight/restconf/nb/rfc8040/jersey/providers/patch/XmlPatchBodyReaderTest.java
restconf/restconf-nb-rfc8040/src/test/resources/instanceidentifier/json/jsonPATCHMergeOperationOnList.json
restconf/restconf-nb-rfc8040/src/test/resources/instanceidentifier/json/jsonPATCHSimpleLeafValue.json
restconf/restconf-nb-rfc8040/src/test/resources/instanceidentifier/json/jsonPATCHdata.json
restconf/restconf-nb-rfc8040/src/test/resources/instanceidentifier/json/jsonPATCHdataCreateAndDelete.json
restconf/restconf-nb-rfc8040/src/test/resources/instanceidentifier/xml/xmlPATCHdata.xml
restconf/restconf-nb-rfc8040/src/test/resources/instanceidentifier/xml/xmlPATCHdataAbsoluteTargetPath.xml
restconf/restconf-nb-rfc8040/src/test/resources/instanceidentifier/xml/xmlPATCHdataMergeOperationOnList.xml

index 4e34e1d57bddaf84645701eac85198136fa3d092..32a01510e3d8047e53ec57c1109ebf074004fdd7 100644 (file)
@@ -232,7 +232,7 @@ public class JsonPatchBodyReader extends AbstractPatchBodyReader {
                         edit.setTarget(path.getInstanceIdentifier());
                         edit.setTargetSchemaNode(path.getSchemaContext());
                     } else {
-                        edit.setTarget(codec.deserialize(codec.serialize(path.getInstanceIdentifier()).concat(target)));
+                        edit.setTarget(ParserIdentifier.parserPatchTarget(path, target));
 
                         final EffectiveStatement<?, ?> parentStmt = SchemaInferenceStack.ofInstantiatedPath(
                             path.getSchemaContext(),
index f3570b5ee66d7f19f92b13b5ddfd10a57fea7f71..59be92ce53b894f331dc16c26b034d46d2690443 100644 (file)
@@ -16,7 +16,6 @@ import java.io.IOException;
 import java.io.InputStream;
 import java.net.URISyntaxException;
 import java.util.ArrayList;
-import java.util.Iterator;
 import java.util.List;
 import java.util.Locale;
 import javax.ws.rs.Consumes;
@@ -26,7 +25,6 @@ import javax.xml.parsers.ParserConfigurationException;
 import javax.xml.stream.XMLStreamException;
 import javax.xml.transform.dom.DOMSource;
 import org.eclipse.jdt.annotation.NonNull;
-import org.eclipse.jdt.annotation.Nullable;
 import org.opendaylight.mdsal.dom.api.DOMMountPointService;
 import org.opendaylight.restconf.common.context.InstanceIdentifierContext;
 import org.opendaylight.restconf.common.errors.RestconfDocumentedException;
@@ -35,13 +33,10 @@ import org.opendaylight.restconf.common.patch.PatchContext;
 import org.opendaylight.restconf.common.patch.PatchEditOperation;
 import org.opendaylight.restconf.common.patch.PatchEntity;
 import org.opendaylight.restconf.nb.rfc8040.MediaTypes;
-import org.opendaylight.restconf.nb.rfc8040.codecs.StringModuleInstanceIdentifierCodec;
 import org.opendaylight.restconf.nb.rfc8040.handlers.SchemaContextHandler;
+import org.opendaylight.restconf.nb.rfc8040.utils.parser.ParserIdentifier;
 import org.opendaylight.yangtools.util.xml.UntrustedXML;
 import org.opendaylight.yangtools.yang.common.ErrorType;
-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;
 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifierWithPredicates;
 import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
@@ -49,11 +44,10 @@ import org.opendaylight.yangtools.yang.data.api.schema.stream.NormalizedNodeStre
 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.data.util.DataSchemaContextTree;
 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.ListSchemaNode;
-import org.opendaylight.yangtools.yang.model.api.Module;
 import org.opendaylight.yangtools.yang.model.api.SchemaNode;
 import org.opendaylight.yangtools.yang.model.api.meta.EffectiveStatement;
 import org.opendaylight.yangtools.yang.model.util.SchemaInferenceStack;
@@ -117,24 +111,12 @@ public class XmlPatchBodyReader extends AbstractPatchBodyReader {
                 targetII = pathContext.getInstanceIdentifier();
                 targetNode = pathContext.getSchemaContext();
             } else {
-                // get namespace according to schema node from path context or value
-                final XMLNamespace namespace = firstValueElement == null ? schemaNode.getQName().getNamespace()
-                    : XMLNamespace.of(firstValueElement.getNamespaceURI());
-
-                // find module according to namespace
-                final Module module = pathContext.getSchemaContext().findModules(namespace).iterator().next();
-
-                // initialize codec + set default prefix derived from module name
-                final StringModuleInstanceIdentifierCodec codec = new StringModuleInstanceIdentifierCodec(
-                        pathContext.getSchemaContext(), module.getName());
-
-                targetII = codec.deserialize(codec.serialize(pathContext.getInstanceIdentifier())
-                        .concat(prepareNonCondXpath(schemaNode, target.replaceFirst("/", ""), firstValueElement,
-                                namespace, module.getQNameModule().getRevision().orElse(null))));
+                // interpret as simple context
+                targetII = ParserIdentifier.parserPatchTarget(pathContext, target);
 
                 // move schema node
-                schemaNode = verifyNotNull(codec.getDataContextTree().findChild(targetII).orElseThrow()
-                    .getDataSchemaNode());
+                schemaNode = verifyNotNull(DataSchemaContextTree.from(pathContext.getSchemaContext())
+                    .findChild(targetII).orElseThrow().getDataSchemaNode());
 
                 final EffectiveStatement<?, ?> parentStmt = SchemaInferenceStack.ofInstantiatedPath(
                     pathContext.getSchemaContext(), schemaNode.getPath().getParent()).currentStatement();
@@ -211,73 +193,4 @@ public class XmlPatchBodyReader extends AbstractPatchBodyReader {
 
         return result;
     }
-
-    /**
-     * Prepare non-conditional XPath suitable for deserialization with {@link StringModuleInstanceIdentifierCodec}.
-     *
-     * @param schemaNode Top schema node
-     * @param target Edit operation target
-     * @param value Element with value
-     * @param namespace Module namespace
-     * @param revision Module revision
-     * @return Non-conditional XPath
-     */
-    private static String prepareNonCondXpath(final @NonNull DataSchemaNode schemaNode, final @NonNull String target,
-            final @NonNull Element value, final @NonNull XMLNamespace namespace, final @Nullable Revision revision) {
-        final Iterator<String> args = SLASH_SPLITTER.split(target.substring(target.indexOf(':') + 1)).iterator();
-
-        final StringBuilder nonCondXpath = new StringBuilder();
-        SchemaNode childNode = schemaNode;
-
-        while (args.hasNext()) {
-            final String s = args.next();
-            nonCondXpath.append("/");
-            nonCondXpath.append(s);
-            childNode = ((DataNodeContainer) childNode).getDataChildByName(QName.create(namespace, revision, s));
-
-            if (childNode instanceof ListSchemaNode && args.hasNext()) {
-                appendKeys(nonCondXpath, ((ListSchemaNode) childNode).getKeyDefinition().iterator(), args);
-            }
-        }
-
-        if (childNode instanceof ListSchemaNode && value != null) {
-            final Iterator<String> keyValues = readKeyValues(value,
-                    ((ListSchemaNode) childNode).getKeyDefinition().iterator());
-            appendKeys(nonCondXpath, ((ListSchemaNode) childNode).getKeyDefinition().iterator(), keyValues);
-        }
-
-        return nonCondXpath.toString();
-    }
-
-    /**
-     * Read value for every list key.
-     *
-     * @param value Value element
-     * @param keys Iterator of list keys names
-     * @return Iterator of list keys values
-     */
-    private static Iterator<String> readKeyValues(final @NonNull Element value, final @NonNull Iterator<QName> keys) {
-        final List<String> result = new ArrayList<>();
-
-        while (keys.hasNext()) {
-            result.add(value.getElementsByTagName(keys.next().getLocalName()).item(0).getFirstChild().getNodeValue());
-        }
-
-        return result.iterator();
-    }
-
-    /**
-     * Append key name - key value pairs for every list key to {@code nonCondXpath}.
-     *
-     * @param nonCondXpath Builder for creating non-conditional XPath
-     * @param keyNames Iterator of list keys names
-     * @param keyValues Iterator of list keys values
-     */
-    private static void appendKeys(final @NonNull StringBuilder nonCondXpath, final @NonNull Iterator<QName> keyNames,
-            final @NonNull Iterator<String> keyValues) {
-        while (keyNames.hasNext()) {
-            nonCondXpath.append('[').append(keyNames.next().getLocalName()).append("='").append(keyValues.next())
-                .append("']");
-        }
-    }
 }
index b2ce05424d5a2391bf5a228144f5f2be9d9fa396..0c3b362c1d79d721c49dfcd1c8e992c0013b3e95 100644 (file)
@@ -269,6 +269,20 @@ public final class ParserIdentifier {
         }
     }
 
+    public static YangInstanceIdentifier parserPatchTarget(final InstanceIdentifierContext<?> context,
+            final String target) {
+        final var schemaContext = context.getSchemaContext();
+        final var urlPath = context.getInstanceIdentifier();
+        final String targetUrl;
+        if (urlPath.isEmpty()) {
+            targetUrl = target.startsWith("/") ? target.substring(1) : target;
+        } else {
+            targetUrl = stringFromYangInstanceIdentifier(urlPath, schemaContext) + target;
+        }
+
+        return toInstanceIdentifier(targetUrl, schemaContext, Optional.empty()).getInstanceIdentifier();
+    }
+
     /**
      * Validation and parsing of revision.
      *
index df8042b5e03af6b5d0a44dc5cda19593b05cf3ee..505a4b41cc82fb250b85a2f11883f3377da3b1f9 100644 (file)
@@ -5,12 +5,11 @@
  * 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.restconf.nb.rfc8040.jersey.providers.patch;
 
 import static javax.ws.rs.core.MediaType.APPLICATION_JSON;
 import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.fail;
+import static org.junit.Assert.assertThrows;
 
 import java.io.InputStream;
 import javax.ws.rs.core.MediaType;
@@ -48,11 +47,8 @@ public class JsonPatchBodyReaderMountPointTest extends AbstractBodyReaderTest {
         final String uri = MOUNT_POINT + "instance-identifier-patch-module:patch-cont/my-list1=leaf1";
         mockBodyReader(uri, jsonToPatchBodyReader, false);
 
-        final InputStream inputStream = JsonBodyReaderTest.class
-                .getResourceAsStream("/instanceidentifier/json/jsonPATCHdata.json");
-
-        final PatchContext returnValue = jsonToPatchBodyReader
-                .readFrom(null, null, null, mediaType, null, inputStream);
+        final PatchContext returnValue = jsonToPatchBodyReader.readFrom(null, null, null, mediaType, null,
+            JsonBodyReaderTest.class.getResourceAsStream("/instanceidentifier/json/jsonPATCHdata.json"));
         checkPatchContextMountPoint(returnValue);
     }
 
@@ -64,11 +60,8 @@ public class JsonPatchBodyReaderMountPointTest extends AbstractBodyReaderTest {
         final String uri = MOUNT_POINT + "instance-identifier-patch-module:patch-cont/my-list1=leaf1";
         mockBodyReader(uri, jsonToPatchBodyReader, false);
 
-        final InputStream inputStream = JsonBodyReaderTest.class
-                .getResourceAsStream("/instanceidentifier/json/jsonPATCHdataCreateAndDelete.json");
-
-        final PatchContext returnValue = jsonToPatchBodyReader
-                .readFrom(null, null, null, mediaType, null, inputStream);
+        final PatchContext returnValue = jsonToPatchBodyReader.readFrom(null, null, null, mediaType, null,
+            JsonBodyReaderTest.class.getResourceAsStream("/instanceidentifier/json/jsonPATCHdataCreateAndDelete.json"));
         checkPatchContextMountPoint(returnValue);
     }
 
@@ -81,15 +74,11 @@ public class JsonPatchBodyReaderMountPointTest extends AbstractBodyReaderTest {
         final String uri = MOUNT_POINT + "instance-identifier-patch-module:patch-cont/my-list1=leaf1";
         mockBodyReader(uri, jsonToPatchBodyReader, false);
 
-        final InputStream inputStream = JsonBodyReaderTest.class
-                .getResourceAsStream("/instanceidentifier/json/jsonPATCHdataValueMissing.json");
-
-        try {
-            jsonToPatchBodyReader.readFrom(null, null, null, mediaType, null, inputStream);
-            fail("Test should return error 400 due to missing value node when attempt to invoke create operation");
-        } catch (final RestconfDocumentedException e) {
-            assertEquals("Error code 400 expected", 400, e.getErrors().get(0).getErrorTag().getStatusCode());
-        }
+        final InputStream inputStream = JsonBodyReaderTest.class.getResourceAsStream(
+            "/instanceidentifier/json/jsonPATCHdataValueMissing.json");
+        final RestconfDocumentedException ex = assertThrows(RestconfDocumentedException.class,
+            () -> jsonToPatchBodyReader.readFrom(null, null, null, mediaType, null, inputStream));
+        assertEquals("Error code 400 expected", 400, ex.getErrors().get(0).getErrorTag().getStatusCode());
     }
 
     /**
@@ -101,15 +90,11 @@ public class JsonPatchBodyReaderMountPointTest extends AbstractBodyReaderTest {
         final String uri = MOUNT_POINT + "instance-identifier-patch-module:patch-cont/my-list1=leaf1";
         mockBodyReader(uri, jsonToPatchBodyReader, false);
 
-        final InputStream inputStream = JsonBodyReaderTest.class
-                .getResourceAsStream("/instanceidentifier/json/jsonPATCHdataValueNotSupported.json");
-
-        try {
-            jsonToPatchBodyReader.readFrom(null, null, null, mediaType, null, inputStream);
-            fail("Test should return error 400 due to present value node when attempt to invoke delete operation");
-        } catch (final RestconfDocumentedException e) {
-            assertEquals("Error code 400 expected", 400, e.getErrors().get(0).getErrorTag().getStatusCode());
-        }
+        final InputStream inputStream = JsonBodyReaderTest.class.getResourceAsStream(
+            "/instanceidentifier/json/jsonPATCHdataValueNotSupported.json");
+        final RestconfDocumentedException ex = assertThrows(RestconfDocumentedException.class,
+            () -> jsonToPatchBodyReader.readFrom(null, null, null, mediaType, null, inputStream));
+        assertEquals("Error code 400 expected", 400, ex.getErrors().get(0).getErrorTag().getStatusCode());
     }
 
     /**
@@ -120,11 +105,9 @@ public class JsonPatchBodyReaderMountPointTest extends AbstractBodyReaderTest {
         final String uri = MOUNT_POINT + "instance-identifier-patch-module:patch-cont";
         mockBodyReader(uri, jsonToPatchBodyReader, false);
 
-        final InputStream inputStream = JsonBodyReaderTest.class
-                .getResourceAsStream("/instanceidentifier/json/jsonPATCHdataCompleteTargetInURI.json");
-
-        final PatchContext returnValue = jsonToPatchBodyReader
-                .readFrom(null, null, null, mediaType, null, inputStream);
+        final PatchContext returnValue = jsonToPatchBodyReader.readFrom(null, null, null, mediaType, null,
+            JsonBodyReaderTest.class.getResourceAsStream(
+                "/instanceidentifier/json/jsonPATCHdataCompleteTargetInURI.json"));
         checkPatchContextMountPoint(returnValue);
     }
 
@@ -136,11 +119,9 @@ public class JsonPatchBodyReaderMountPointTest extends AbstractBodyReaderTest {
         final String uri = MOUNT_POINT + "instance-identifier-patch-module:patch-cont/my-list1=leaf1";
         mockBodyReader(uri, jsonToPatchBodyReader, false);
 
-        final InputStream inputStream = JsonBodyReaderTest.class
-                .getResourceAsStream("/instanceidentifier/json/jsonPATCHMergeOperationOnList.json");
-
-        final PatchContext returnValue = jsonToPatchBodyReader
-                .readFrom(null, null, null, mediaType, null, inputStream);
+        final PatchContext returnValue = jsonToPatchBodyReader.readFrom(null, null, null, mediaType, null,
+            JsonBodyReaderTest.class.getResourceAsStream(
+                "/instanceidentifier/json/jsonPATCHMergeOperationOnList.json"));
         checkPatchContextMountPoint(returnValue);
     }
 
@@ -152,11 +133,9 @@ public class JsonPatchBodyReaderMountPointTest extends AbstractBodyReaderTest {
         final String uri = MOUNT_POINT + "instance-identifier-patch-module:patch-cont";
         mockBodyReader(uri, jsonToPatchBodyReader, false);
 
-        final InputStream inputStream = JsonBodyReaderTest.class
-                .getResourceAsStream("/instanceidentifier/json/jsonPATCHMergeOperationOnContainer.json");
-
-        final PatchContext returnValue = jsonToPatchBodyReader
-                .readFrom(null, null, null, mediaType, null, inputStream);
+        final PatchContext returnValue = jsonToPatchBodyReader.readFrom(null, null, null, mediaType, null,
+            JsonBodyReaderTest.class.getResourceAsStream(
+                "/instanceidentifier/json/jsonPATCHMergeOperationOnContainer.json"));
         checkPatchContextMountPoint(returnValue);
     }
 
@@ -168,12 +147,8 @@ public class JsonPatchBodyReaderMountPointTest extends AbstractBodyReaderTest {
         final String uri = MOUNT_POINT + "instance-identifier-patch-module:patch-cont/my-list1=leaf1";
         mockBodyReader(uri, jsonToPatchBodyReader, false);
 
-        final InputStream inputStream =
-                JsonBodyReaderTest.class
-                .getResourceAsStream("/instanceidentifier/json/jsonPATCHSimpleLeafValue.json");
-
-        final PatchContext returnValue = jsonToPatchBodyReader
-                .readFrom(null, null, null, mediaType, null, inputStream);
+        final PatchContext returnValue = jsonToPatchBodyReader.readFrom(null, null, null, mediaType, null,
+            JsonBodyReaderTest.class.getResourceAsStream("/instanceidentifier/json/jsonPATCHSimpleLeafValue.json"));
         checkPatchContext(returnValue);
     }
 }
index c080125c89ba7302f38f52a61a8040874fc49070..3eb8f43f687451fdf98027491ea44690966c8d81 100644 (file)
@@ -8,7 +8,7 @@
 package org.opendaylight.restconf.nb.rfc8040.jersey.providers.patch;
 
 import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.fail;
+import static org.junit.Assert.assertThrows;
 
 import java.io.InputStream;
 import javax.ws.rs.core.MediaType;
@@ -46,10 +46,9 @@ public class XmlPatchBodyReaderMountPointTest extends AbstractBodyReaderTest {
     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 = XmlBodyReaderTest.class
-                .getResourceAsStream("/instanceidentifier/xml/xmlPATCHdata.xml");
-        final PatchContext returnValue = xmlToPatchBodyReader
-                .readFrom(null, null, null, mediaType, null, inputStream);
+
+        final PatchContext returnValue = xmlToPatchBodyReader.readFrom(null, null, null, mediaType, null,
+            XmlBodyReaderTest.class.getResourceAsStream("/instanceidentifier/xml/xmlPATCHdata.xml"));
         checkPatchContextMountPoint(returnValue);
     }
 
@@ -60,14 +59,12 @@ public class XmlPatchBodyReaderMountPointTest extends AbstractBodyReaderTest {
     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 = XmlBodyReaderTest.class
-                .getResourceAsStream("/instanceidentifier/xml/xmlPATCHdataValueMissing.xml");
-        try {
-            xmlToPatchBodyReader.readFrom(null, null, null, mediaType, null, inputStream);
-            fail("Test should return error 400 due to missing value node when attempt to invoke create operation");
-        } catch (final RestconfDocumentedException e) {
-            assertEquals("Error code 400 expected", 400, e.getErrors().get(0).getErrorTag().getStatusCode());
-        }
+        final InputStream inputStream = XmlBodyReaderTest.class.getResourceAsStream(
+            "/instanceidentifier/xml/xmlPATCHdataValueMissing.xml");
+
+        final RestconfDocumentedException ex = assertThrows(RestconfDocumentedException.class,
+            () -> xmlToPatchBodyReader.readFrom(null, null, null, mediaType, null, inputStream));
+        assertEquals("Error code 400 expected", 400, ex.getErrors().get(0).getErrorTag().getStatusCode());
     }
 
     /**
@@ -78,14 +75,12 @@ public class XmlPatchBodyReaderMountPointTest extends AbstractBodyReaderTest {
     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 = XmlBodyReaderTest.class
-                .getResourceAsStream("/instanceidentifier/xml/xmlPATCHdataValueNotSupported.xml");
-        try {
-            xmlToPatchBodyReader.readFrom(null, null, null, mediaType, null, inputStream);
-            fail("Test should return error 400 due to present value node when attempt to invoke delete operation");
-        } catch (final RestconfDocumentedException e) {
-            assertEquals("Error code 400 expected", 400, e.getErrors().get(0).getErrorTag().getStatusCode());
-        }
+        final InputStream inputStream = XmlBodyReaderTest.class.getResourceAsStream(
+            "/instanceidentifier/xml/xmlPATCHdataValueNotSupported.xml");
+
+        final RestconfDocumentedException ex = assertThrows(RestconfDocumentedException.class,
+            () -> xmlToPatchBodyReader.readFrom(null, null, null, mediaType, null, inputStream));
+        assertEquals("Error code 400 expected", 400, ex.getErrors().get(0).getErrorTag().getStatusCode());
     }
 
 
@@ -96,10 +91,9 @@ public class XmlPatchBodyReaderMountPointTest extends AbstractBodyReaderTest {
     public void moduleDataAbsoluteTargetPathTest() throws Exception {
         final String uri = MOUNT_POINT;
         mockBodyReader(uri, xmlToPatchBodyReader, false);
-        final InputStream inputStream = XmlBodyReaderTest.class
-                .getResourceAsStream("/instanceidentifier/xml/xmlPATCHdataAbsoluteTargetPath.xml");
-        final PatchContext returnValue = xmlToPatchBodyReader
-                .readFrom(null, null, null, mediaType, null, inputStream);
+
+        final PatchContext returnValue = xmlToPatchBodyReader.readFrom(null, null, null, mediaType, null,
+            XmlBodyReaderTest.class.getResourceAsStream("/instanceidentifier/xml/xmlPATCHdataAbsoluteTargetPath.xml"));
         checkPatchContextMountPoint(returnValue);
     }
 
@@ -110,10 +104,9 @@ public class XmlPatchBodyReaderMountPointTest extends AbstractBodyReaderTest {
     public void modulePatchCompleteTargetInURITest() throws Exception {
         final String uri = MOUNT_POINT + "instance-identifier-patch-module:patch-cont";
         mockBodyReader(uri, xmlToPatchBodyReader, false);
-        final InputStream inputStream = XmlBodyReaderTest.class
-                .getResourceAsStream("/instanceidentifier/xml/xmlPATCHdataCompleteTargetInURI.xml");
-        final PatchContext returnValue = xmlToPatchBodyReader
-                .readFrom(null, null, null, mediaType, null, inputStream);
+
+        final PatchContext returnValue = xmlToPatchBodyReader.readFrom(null, null, null, mediaType, null,
+            XmlBodyReaderTest.class.getResourceAsStream("/instanceidentifier/xml/xmlPATCHdataCompleteTargetInURI.xml"));
         checkPatchContextMountPoint(returnValue);
     }
 
@@ -124,10 +117,10 @@ public class XmlPatchBodyReaderMountPointTest extends AbstractBodyReaderTest {
     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 = XmlBodyReaderTest.class
-                .getResourceAsStream("/instanceidentifier/xml/xmlPATCHdataMergeOperationOnList.xml");
-        final PatchContext returnValue = xmlToPatchBodyReader
-                .readFrom(null, null, null, mediaType, null, inputStream);
+
+        final PatchContext returnValue = xmlToPatchBodyReader.readFrom(null, null, null, mediaType, null,
+            XmlBodyReaderTest.class.getResourceAsStream(
+                "/instanceidentifier/xml/xmlPATCHdataMergeOperationOnList.xml"));
         checkPatchContextMountPoint(returnValue);
     }
 
@@ -138,10 +131,10 @@ public class XmlPatchBodyReaderMountPointTest extends AbstractBodyReaderTest {
     public void moduleDataMergeOperationOnContainerTest() throws Exception {
         final String uri = MOUNT_POINT + "instance-identifier-patch-module:patch-cont";
         mockBodyReader(uri, xmlToPatchBodyReader, false);
-        final InputStream inputStream = XmlBodyReaderTest.class
-                .getResourceAsStream("/instanceidentifier/xml/xmlPATCHdataMergeOperationOnContainer.xml");
-        final PatchContext returnValue = xmlToPatchBodyReader
-                .readFrom(null, null, null, mediaType, null, inputStream);
+
+        final PatchContext returnValue = xmlToPatchBodyReader.readFrom(null, null, null, mediaType, null,
+            XmlBodyReaderTest.class.getResourceAsStream(
+                "/instanceidentifier/xml/xmlPATCHdataMergeOperationOnContainer.xml"));
         checkPatchContextMountPoint(returnValue);
     }
 }
index 0282881f217ac7d851edbac7f5c24b5a996f20f7..cc29eadd5395767364415fae90982c5dfac90c9d 100644 (file)
@@ -8,7 +8,7 @@
 package org.opendaylight.restconf.nb.rfc8040.jersey.providers.patch;
 
 import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.fail;
+import static org.junit.Assert.assertThrows;
 
 import java.io.InputStream;
 import javax.ws.rs.core.MediaType;
@@ -44,10 +44,9 @@ public class XmlPatchBodyReaderTest extends AbstractBodyReaderTest {
     public void moduleDataTest() throws Exception {
         final String uri = "instance-identifier-patch-module:patch-cont/my-list1=leaf1";
         mockBodyReader(uri, xmlToPatchBodyReader, false);
-        final InputStream inputStream = XmlBodyReaderTest.class
-                .getResourceAsStream("/instanceidentifier/xml/xmlPATCHdata.xml");
-        final PatchContext returnValue = xmlToPatchBodyReader
-                .readFrom(null, null, null, mediaType, null, inputStream);
+
+        final PatchContext returnValue = xmlToPatchBodyReader.readFrom(null, null, null, mediaType, null,
+            XmlBodyReaderTest.class.getResourceAsStream("/instanceidentifier/xml/xmlPATCHdata.xml"));
         checkPatchContext(returnValue);
     }
 
@@ -58,14 +57,12 @@ public class XmlPatchBodyReaderTest extends AbstractBodyReaderTest {
     public void moduleDataValueMissingNegativeTest() throws Exception {
         final String uri = "instance-identifier-patch-module:patch-cont/my-list1=leaf1";
         mockBodyReader(uri, xmlToPatchBodyReader, false);
-        final InputStream inputStream = XmlBodyReaderTest.class
-                .getResourceAsStream("/instanceidentifier/xml/xmlPATCHdataValueMissing.xml");
-        try {
-            xmlToPatchBodyReader.readFrom(null, null, null, mediaType, null, inputStream);
-            fail("Test should return error 400 due to missing value node when attempt to invoke create operation");
-        } catch (final RestconfDocumentedException e) {
-            assertEquals("Error code 400 expected", 400, e.getErrors().get(0).getErrorTag().getStatusCode());
-        }
+        final InputStream inputStream = XmlBodyReaderTest.class.getResourceAsStream(
+            "/instanceidentifier/xml/xmlPATCHdataValueMissing.xml");
+
+        final RestconfDocumentedException ex = assertThrows(RestconfDocumentedException.class,
+            () -> xmlToPatchBodyReader.readFrom(null, null, null, mediaType, null, inputStream));
+        assertEquals("Error code 400 expected", 400, ex.getErrors().get(0).getErrorTag().getStatusCode());
     }
 
     /**
@@ -76,14 +73,12 @@ public class XmlPatchBodyReaderTest extends AbstractBodyReaderTest {
     public void moduleDataNotValueNotSupportedNegativeTest() throws Exception {
         final String uri = "instance-identifier-patch-module:patch-cont/my-list1=leaf1";
         mockBodyReader(uri, xmlToPatchBodyReader, false);
-        final InputStream inputStream = XmlBodyReaderTest.class
-                .getResourceAsStream("/instanceidentifier/xml/xmlPATCHdataValueNotSupported.xml");
-        try {
-            xmlToPatchBodyReader.readFrom(null, null, null, mediaType, null, inputStream);
-            fail("Test should return error 400 due to present value node when attempt to invoke delete operation");
-        } catch (final RestconfDocumentedException e) {
-            assertEquals("Error code 400 expected", 400, e.getErrors().get(0).getErrorTag().getStatusCode());
-        }
+        final InputStream inputStream = XmlBodyReaderTest.class.getResourceAsStream(
+            "/instanceidentifier/xml/xmlPATCHdataValueNotSupported.xml");
+
+        final RestconfDocumentedException ex = assertThrows(RestconfDocumentedException.class,
+            () -> xmlToPatchBodyReader.readFrom(null, null, null, mediaType, null, inputStream));
+        assertEquals("Error code 400 expected", 400, ex.getErrors().get(0).getErrorTag().getStatusCode());
     }
 
 
@@ -94,10 +89,9 @@ public class XmlPatchBodyReaderTest extends AbstractBodyReaderTest {
     public void moduleDataAbsoluteTargetPathTest() throws Exception {
         final String uri = "";
         mockBodyReader(uri, xmlToPatchBodyReader, false);
-        final InputStream inputStream = XmlBodyReaderTest.class
-                .getResourceAsStream("/instanceidentifier/xml/xmlPATCHdataAbsoluteTargetPath.xml");
-        final PatchContext returnValue = xmlToPatchBodyReader
-                .readFrom(null, null, null, mediaType, null, inputStream);
+
+        final PatchContext returnValue = xmlToPatchBodyReader.readFrom(null, null, null, mediaType, null,
+            XmlBodyReaderTest.class.getResourceAsStream("/instanceidentifier/xml/xmlPATCHdataAbsoluteTargetPath.xml"));
         checkPatchContext(returnValue);
     }
 
@@ -108,10 +102,9 @@ public class XmlPatchBodyReaderTest extends AbstractBodyReaderTest {
     public void modulePatchCompleteTargetInURITest() throws Exception {
         final String uri = "instance-identifier-patch-module:patch-cont";
         mockBodyReader(uri, xmlToPatchBodyReader, false);
-        final InputStream inputStream = XmlBodyReaderTest.class
-                .getResourceAsStream("/instanceidentifier/xml/xmlPATCHdataCompleteTargetInURI.xml");
-        final PatchContext returnValue = xmlToPatchBodyReader
-                .readFrom(null, null, null, mediaType, null, inputStream);
+
+        final PatchContext returnValue = xmlToPatchBodyReader.readFrom(null, null, null, mediaType, null,
+            XmlBodyReaderTest.class.getResourceAsStream("/instanceidentifier/xml/xmlPATCHdataCompleteTargetInURI.xml"));
         checkPatchContext(returnValue);
     }
 
@@ -122,10 +115,10 @@ public class XmlPatchBodyReaderTest extends AbstractBodyReaderTest {
     public void moduleDataMergeOperationOnListTest() throws Exception {
         final String uri = "instance-identifier-patch-module:patch-cont/my-list1=leaf1";
         mockBodyReader(uri, xmlToPatchBodyReader, false);
-        final InputStream inputStream = XmlBodyReaderTest.class
-                .getResourceAsStream("/instanceidentifier/xml/xmlPATCHdataMergeOperationOnList.xml");
-        final PatchContext returnValue = xmlToPatchBodyReader
-                .readFrom(null, null, null, mediaType, null, inputStream);
+
+        final PatchContext returnValue = xmlToPatchBodyReader.readFrom(null, null, null, mediaType, null,
+            XmlBodyReaderTest.class.getResourceAsStream(
+                "/instanceidentifier/xml/xmlPATCHdataMergeOperationOnList.xml"));
         checkPatchContext(returnValue);
     }
 
@@ -136,10 +129,9 @@ public class XmlPatchBodyReaderTest extends AbstractBodyReaderTest {
     public void moduleDataMergeOperationOnContainerTest() throws Exception {
         final String uri = "instance-identifier-patch-module:patch-cont";
         mockBodyReader(uri, xmlToPatchBodyReader, false);
-        final InputStream inputStream = XmlBodyReaderTest.class
-                .getResourceAsStream("/instanceidentifier/xml/xmlPATCHdataMergeOperationOnContainer.xml");
-        final PatchContext returnValue = xmlToPatchBodyReader
-                .readFrom(null, null, null, mediaType, null, inputStream);
+        final PatchContext returnValue = xmlToPatchBodyReader.readFrom(null, null, null, mediaType, null,
+            XmlBodyReaderTest.class.getResourceAsStream(
+                "/instanceidentifier/xml/xmlPATCHdataMergeOperationOnContainer.xml"));
         checkPatchContext(returnValue);
     }
 }
index 3b809e0061b38e9e60a6cda1c601ebffac592951..cbb67a97699ca9bba092ef782fed5a79275b0b7c 100644 (file)
@@ -6,7 +6,7 @@
       {
         "edit-id": "edit1",
         "operation": "replace",
-        "target": "/instance-identifier-patch-module:my-list2[instance-identifier-patch-module:name='my-leaf20']",
+        "target": "/my-list2=my-leaf20",
         "value": {
           "my-list2": {
             "name": "my-leaf20",
@@ -18,7 +18,7 @@
       {
         "edit-id": "edit2",
         "operation": "merge",
-        "target": "/instance-identifier-patch-module:my-list2[instance-identifier-patch-module:name='my-leaf21']",
+        "target": "/my-list2=my-leaf21",
         "value": {
           "my-list2": {
             "name": "my-leaf21",
@@ -29,4 +29,4 @@
       }
     ]
   }
-}
\ No newline at end of file
+}
index 4a109efb919e66f6533388ab6c04bdddb84a1418..d63d43b8fb3041590afc1312ea204052e010cbf4 100644 (file)
@@ -7,11 +7,11 @@
       {
         "edit-id": "edit1",
         "operation": "replace",
-        "target": "/instance-identifier-patch-module:my-list2[instance-identifier-patch-module:name='my-leaf20']/instance-identifier-patch-module:name",
+        "target": "/my-list2=my-leaf20/name",
         "value": {
           "name": "my-leaf20"
         }
       }
     ]
   }
-}
\ No newline at end of file
+}
index e027a7667283685ff9f4d020c38da0ccbb326179..24988264ac139c09432ce1b2da02ecdc3637ae8b 100644 (file)
@@ -7,7 +7,7 @@
       {
         "edit-id": "edit1",
         "operation": "replace",
-        "target": "/instance-identifier-patch-module:my-list2[instance-identifier-patch-module:name='my-leaf20']",
+        "target": "/my-list2=my-leaf20",
         "value": {
           "my-list2": {
             "name": "my-leaf20",
@@ -20,7 +20,7 @@
       {
         "edit-id": "edit2",
         "operation": "replace",
-        "target": "/instance-identifier-patch-module:my-list2[instance-identifier-patch-module:name='my-leaf20']",
+        "target": "/my-list2=my-leaf20",
         "value": {
           "my-list2": {
             "name": "my-leaf20",
index 44550381341f39a747657a0833f5944a37f9eff1..8d705a8fdd72f034e89bbceb88d590df0a53cf9a 100644 (file)
             }
           ]
         },
-        "target": "/instance-identifier-patch-module:my-list2[instance-identifier-patch-module:name='my-leaf20']",
+        "target": "/my-list2=my-leaf20",
         "operation": "create"
       },
       {
         "edit-id": "edit2",
         "operation": "delete",
-        "target": "/instance-identifier-patch-module:my-list2[instance-identifier-patch-module:name='my-leaf20']"
+        "target": "/my-list2=my-leaf20"
       }
     ]
   }
-}
\ No newline at end of file
+}
index d7d3a6bea6fc13e2c3a8b14871603f33ea1d7f74..3542c9133ab7efb010e2808c1e4a8654d6120e3e 100644 (file)
@@ -4,7 +4,7 @@
     <edit>
         <edit-id>edit1</edit-id>
         <operation>create</operation>
-        <target>/my-list2</target>
+        <target>/my-list2=my-leaf20</target>
         <value>
             <my-list2 xmlns="instance:identifier:patch:module">
                 <name>my-leaf20</name>
@@ -16,7 +16,7 @@
     <edit>
         <edit-id>edit2</edit-id>
         <operation>create</operation>
-        <target>/my-list2</target>
+        <target>/my-list2=my-leaf21</target>
         <value>
             <my-list2 xmlns="instance:identifier:patch:module">
                 <name>my-leaf21</name>
@@ -25,4 +25,4 @@
             </my-list2>
         </value>
     </edit>
-</yang-patch>
\ No newline at end of file
+</yang-patch>
index 6e84c47a49fbf49f0a632edbfa464a73e328b1a2..d792356a7d9d844f07149c12ee9bf9068a7d4af2 100644 (file)
@@ -11,7 +11,7 @@
     <edit>
         <edit-id>edit1</edit-id>
         <operation>create</operation>
-        <target>/instance-identifier-patch-module:patch-cont/my-list1/leaf1/my-list2</target>
+        <target>/instance-identifier-patch-module:patch-cont/my-list1=leaf1/my-list2=my-leaf20</target>
         <value>
             <my-list2 xmlns="instance:identifier:patch:module">
                 <name>my-leaf20</name>
@@ -23,7 +23,7 @@
     <edit>
         <edit-id>edit2</edit-id>
         <operation>create</operation>
-        <target>/instance-identifier-patch-module:patch-cont/my-list1/leaf1/my-list2</target>
+        <target>/instance-identifier-patch-module:patch-cont/my-list1=leaf1/my-list2=my-leaf21</target>
         <value>
             <my-list2 xmlns="instance:identifier:patch:module">
                 <name>my-leaf21</name>
@@ -32,4 +32,4 @@
             </my-list2>
         </value>
     </edit>
-</yang-patch>
\ No newline at end of file
+</yang-patch>
index ad130413a4107265b4f920ffaca202c44fa4a8b4..bf852877c4179cef6c44fa150ed00a1c9bb25288 100644 (file)
@@ -11,7 +11,7 @@
     <edit>
         <edit-id>edit1</edit-id>
         <operation>replace</operation>
-        <target>/my-list2</target>
+        <target>/my-list2=my-leaf20</target>
         <value>
             <my-list2 xmlns="instance:identifier:patch:module">
                 <name>my-leaf20</name>
@@ -23,7 +23,7 @@
     <edit>
         <edit-id>edit2</edit-id>
         <operation>merge</operation>
-        <target>/my-list2</target>
+        <target>/my-list2=my-leaf21</target>
         <value>
             <my-list2 xmlns="instance:identifier:patch:module">
                 <name>my-leaf21</name>
@@ -32,4 +32,4 @@
             </my-list2>
         </value>
     </edit>
-</yang-patch>
\ No newline at end of file
+</yang-patch>