Generalize ResourceBodyTest 28/109128/4
authorRobert Varga <robert.varga@pantheon.tech>
Thu, 30 Nov 2023 10:53:42 +0000 (11:53 +0100)
committerRobert Varga <nite@hq.sk>
Thu, 30 Nov 2023 16:42:46 +0000 (16:42 +0000)
Use proper payloads instead of mucking with internals. This shows that
negative case is completely unreachable.

JIRA: NETCONF-1157
Change-Id: I88371fe99362bec68462f6872e874bb7bbf89e5a
Signed-off-by: Robert Varga <robert.varga@pantheon.tech>
restconf/restconf-nb/src/main/java/org/opendaylight/restconf/nb/rfc8040/databind/ResourceBody.java
restconf/restconf-nb/src/main/java/org/opendaylight/restconf/server/mdsal/MdsalRestconfServer.java
restconf/restconf-nb/src/test/java/org/opendaylight/restconf/nb/rfc8040/databind/AbstractResourceBodyTest.java
restconf/restconf-nb/src/test/java/org/opendaylight/restconf/nb/rfc8040/databind/JsonResourceBodyTest.java
restconf/restconf-nb/src/test/java/org/opendaylight/restconf/nb/rfc8040/databind/ResourceBodyTest.java [deleted file]
restconf/restconf-nb/src/test/java/org/opendaylight/restconf/nb/rfc8040/databind/XmlResourceBodyTest.java

index 21e879bbe13cb63236d6b59de67abdbf36e6732a..e20520369a0fe1933a1e827118cd9bd82979b3a7 100644 (file)
@@ -7,31 +7,22 @@
  */
 package org.opendaylight.restconf.nb.rfc8040.databind;
 
-import com.google.common.annotations.VisibleForTesting;
 import java.io.IOException;
 import java.io.InputStream;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
 import org.eclipse.jdt.annotation.NonNull;
 import org.opendaylight.restconf.common.errors.RestconfDocumentedException;
 import org.opendaylight.restconf.server.api.DataPutPath;
 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.restconf.rev170126.restconf.restconf.Data;
 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.YangInstanceIdentifier.PathArgument;
-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.stream.NormalizedNodeStreamWriter;
 import org.opendaylight.yangtools.yang.data.impl.schema.ImmutableNormalizedNodeStreamWriter;
 import org.opendaylight.yangtools.yang.data.impl.schema.NormalizationResultHolder;
-import org.opendaylight.yangtools.yang.model.api.ListSchemaNode;
-import org.opendaylight.yangtools.yang.model.api.SchemaNode;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -53,10 +44,8 @@ public abstract sealed class ResourceBody extends AbstractBody permits JsonResou
      * @param path A {@link YangInstanceIdentifier} corresponding to the body
      * @throws RestconfDocumentedException if the body cannot be decoded or it does not match {@code path}
      */
-    // TODO: pass down DatabindContext corresponding to inference
     @SuppressWarnings("checkstyle:illegalCatch")
-    public @NonNull NormalizedNode toNormalizedNode(final @NonNull DataPutPath path,
-            final @NonNull SchemaNode schemaNode) {
+    public @NonNull NormalizedNode toNormalizedNode(final @NonNull DataPutPath path) {
         final var instance = path.instance();
         final var expectedName = instance.isEmpty() ? DATA_NID : instance.getLastPathArgument();
         final var holder = new NormalizationResultHolder();
@@ -90,46 +79,9 @@ public abstract sealed class ResourceBody extends AbstractBody permits JsonResou
                 ErrorType.PROTOCOL, ErrorTag.MALFORMED_MESSAGE);
         }
 
-        validateListKeysEqualityInPayloadAndUri(schemaNode, instance, data);
         return data;
     }
 
     abstract void streamTo(@NonNull DataPutPath path, @NonNull PathArgument name, @NonNull InputStream inputStream,
         @NonNull NormalizedNodeStreamWriter writer) throws IOException;
-
-    /**
-     * Validates whether keys in {@code payload} are equal to values of keys in
-     * {@code iiWithData} for list schema node.
-     *
-     * @throws RestconfDocumentedException if key values or key count in payload and URI isn't equal
-     */
-    @VisibleForTesting
-    static final void validateListKeysEqualityInPayloadAndUri(final SchemaNode schemaNode,
-            final YangInstanceIdentifier path, final NormalizedNode data) {
-        if (schemaNode instanceof ListSchemaNode listSchema
-            && path.getLastPathArgument() instanceof NodeIdentifierWithPredicates nip
-            && data instanceof MapEntryNode mapEntry) {
-            isEqualUriAndPayloadKeyValues(nip.asMap(), mapEntry, listSchema.getKeyDefinition());
-        }
-    }
-
-    private static void isEqualUriAndPayloadKeyValues(final Map<QName, Object> uriKeyValues, final MapEntryNode payload,
-            final List<QName> keyDefinitions) {
-        final var mutableCopyUriKeyValues = new HashMap<>(uriKeyValues);
-        for (var keyDefinition : keyDefinitions) {
-            final var uriKeyValue = mutableCopyUriKeyValues.remove(keyDefinition);
-            if (uriKeyValue == null) {
-                throw new RestconfDocumentedException("Missing key " + keyDefinition + " in URI.",
-                    ErrorType.PROTOCOL, ErrorTag.DATA_MISSING);
-            }
-
-            final var dataKeyValue = payload.name().getValue(keyDefinition);
-            if (!uriKeyValue.equals(dataKeyValue)) {
-                throw new RestconfDocumentedException("The value '" + uriKeyValue
-                    + "' for key '" + keyDefinition.getLocalName()
-                    + "' specified in the URI doesn't match the value '" + dataKeyValue
-                    + "' specified in the message body. ", ErrorType.PROTOCOL, ErrorTag.INVALID_VALUE);
-            }
-        }
-    }
 }
\ No newline at end of file
index 89088e03c8e2e7a1a5c5b08c7000f3185a946392..4c0598d842297edb1b1fa5bc9920cd09492442e0 100644 (file)
@@ -661,7 +661,7 @@ public final class MdsalRestconfServer
             final ResourceBody body) {
         final var putPath = new DataPutPath(reqPath.databind(), reqPath.inference(), reqPath.getInstanceIdentifier());
         return new ResourceRequest(getRestconfStrategy(putPath.databind(), reqPath.getMountPoint()), putPath.instance(),
-            body.toNormalizedNode(putPath, reqPath.getSchemaNode()));
+            body.toNormalizedNode(putPath));
     }
 
     @VisibleForTesting
index 627ce0641df3ddc5a93e82978ade14d06f07e2b6..ad545be65cd180b28e88692beda79b908bd71259 100644 (file)
@@ -84,8 +84,7 @@ abstract class AbstractResourceBodyTest extends AbstractBodyTest {
         try (var body = bodyConstructor.apply(stringInputStream(patchBody))) {
             final var context = InstanceIdentifierContext.ofApiPath(apiPath, DATABIND, mountPointService);
             return body.toNormalizedNode(
-                new DataPutPath(context.databind(), context.inference(), context.getInstanceIdentifier()),
-                context.getSchemaNode());
+                new DataPutPath(context.databind(), context.inference(), context.getInstanceIdentifier()));
         }
     }
 
index fe03e2a5d057f1111ba3f49b34c1776d5d7f2230..f1c3dcb122854e627b42b6720606df694e7a8cc4 100644 (file)
@@ -8,11 +8,14 @@
 package org.opendaylight.restconf.nb.rfc8040.databind;
 
 import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertNull;
+import static org.junit.jupiter.api.Assertions.assertThrows;
 
 import java.util.Map;
 import org.junit.jupiter.api.Test;
 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;
@@ -81,7 +84,7 @@ class JsonResourceBodyTest extends AbstractResourceBodyTest {
     }
 
     @Test
-    void testRangeViolation() throws Exception {
+    void testRangeViolation() {
         assertRangeViolation(() -> parse("netconf786:foo", """
             {
               "netconf786:foo": {
@@ -91,7 +94,7 @@ class JsonResourceBodyTest extends AbstractResourceBodyTest {
     }
 
     @Test
-    void testMismatchedInput() throws Exception {
+    void testMismatchedInput() {
         final var error = assertError(() -> parse("base:cont", """
             {
               "ietf-restconf:restconf-state" : {
@@ -103,4 +106,35 @@ class JsonResourceBodyTest extends AbstractResourceBodyTest {
         assertEquals(ErrorType.PROTOCOL, error.getErrorType());
         assertEquals(ErrorTag.MALFORMED_MESSAGE, error.getErrorTag());
     }
+
+    @Test
+    void testMissingKeys() {
+        final var ex = assertThrows(IllegalArgumentException.class,
+            () -> parse("nested-module:depth1-cont/depth2-list2=one,two", """
+                {
+                  "depth2-list2" : {
+                    "depth3-lf1-key" : "one"
+                  }
+                }"""));
+        assertNull(ex.getMessage());
+    }
+
+    @Test
+    void testJukeboxBand() throws Exception {
+        final var one = QName.create("urn:nested:module", "2014-06-03", "depth3-lf1-key");
+        final var two = QName.create("urn:nested:module", "2014-06-03", "depth3-lf2-key");
+
+        assertEquals(Builders.mapEntryBuilder()
+            .withNodeIdentifier(NodeIdentifierWithPredicates.of(
+                QName.create("urn:nested:module", "2014-06-03", "depth2-list2"), Map.of(one, "one", two, "two")))
+            .withChild(ImmutableNodes.leafNode(one, "one"))
+            .withChild(ImmutableNodes.leafNode(two, "two"))
+            .build(), parse("nested-module:depth1-cont/depth2-list2=one,two", """
+            {
+              "depth2-list2" : {
+                "depth3-lf1-key" : "one",
+                "depth3-lf2-key" : "two"
+              }
+            }"""));
+    }
 }
diff --git a/restconf/restconf-nb/src/test/java/org/opendaylight/restconf/nb/rfc8040/databind/ResourceBodyTest.java b/restconf/restconf-nb/src/test/java/org/opendaylight/restconf/nb/rfc8040/databind/ResourceBodyTest.java
deleted file mode 100644 (file)
index d929e31..0000000
+++ /dev/null
@@ -1,26 +0,0 @@
-/*
- * Copyright (c) 2023 PANTHEON.tech, s.r.o. 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.restconf.nb.rfc8040.databind;
-
-import org.junit.Test;
-import org.opendaylight.restconf.nb.rfc8040.AbstractJukeboxTest;
-import org.opendaylight.restconf.nb.rfc8040.legacy.InstanceIdentifierContext;
-import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
-
-public class ResourceBodyTest extends AbstractJukeboxTest {
-    @Test
-    public void testValidateListKeysEqualityInPayloadAndUri() {
-        final var path = YangInstanceIdentifier.builder()
-            .node(JUKEBOX_QNAME)
-            .node(PLAYLIST_QNAME)
-            .nodeWithKey(PLAYLIST_QNAME, NAME_QNAME, "name of band")
-            .build();
-        final var iidContext = InstanceIdentifierContext.ofLocalPath(JUKEBOX_DATABIND, path);
-        ResourceBody.validateListKeysEqualityInPayloadAndUri(iidContext.getSchemaNode(), path, BAND_ENTRY);
-    }
-}
index e9621ff898e8d1ae354d2baae941924cf8ee0e52..be7e9baefa8a74235cfc6f91640928eb2d26a462 100644 (file)
@@ -8,6 +8,7 @@
 package org.opendaylight.restconf.nb.rfc8040.databind;
 
 import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertNull;
 import static org.junit.jupiter.api.Assertions.assertThrows;
 import static org.mockito.ArgumentMatchers.any;
 import static org.mockito.Mockito.doReturn;
@@ -195,4 +196,13 @@ class XmlResourceBodyTest extends AbstractResourceBodyTest {
         assertEquals(ErrorTag.MALFORMED_MESSAGE, error.getErrorTag());
     }
 
+    @Test
+    void testMissingKeys() throws Exception {
+        final var ex = assertThrows(IllegalArgumentException.class,
+            () -> parse("nested-module:depth1-cont/depth2-list2=one,two", """
+                <depth2-list2 xmlns="urn:nested:module">
+                  <depth3-lf1-key>one</depth3-lf1-key>
+                </depth2-list2>"""));
+        assertNull(ex.getMessage());
+    }
 }