Add an explicit constants for WithDefaults parameter 59/93059/7
authorRobert Varga <robert.varga@pantheon.tech>
Wed, 14 Oct 2020 15:58:33 +0000 (17:58 +0200)
committerRobert Varga <nite@hq.sk>
Mon, 26 Oct 2020 11:51:41 +0000 (11:51 +0000)
RFC8040 explicitly enumerates allowed values, make sure we validate
them accordingly. Also fix the bug of ignoring unknown values.

JIRA: NETCONF-733
Change-Id: I5e4a19061c2c082563385a32ba574ddf97a8c967
Signed-off-by: Robert Varga <robert.varga@pantheon.tech>
restconf/restconf-nb-rfc8040/src/main/java/org/opendaylight/restconf/nb/rfc8040/rests/utils/ReadDataTransactionUtil.java
restconf/restconf-nb-rfc8040/src/main/java/org/opendaylight/restconf/nb/rfc8040/rests/utils/RestconfDataServiceConstant.java
restconf/restconf-nb-rfc8040/src/test/java/org/opendaylight/restconf/nb/rfc8040/rests/utils/ReadDataTransactionUtilTest.java

index 5558a714b0d78d0d81c55271f5ceb8aba5203306..bf65a4aee97afb2e96c03897ddc4b674abbc6937 100644 (file)
@@ -32,6 +32,7 @@ import org.opendaylight.restconf.common.errors.RestconfError;
 import org.opendaylight.restconf.common.errors.RestconfError.ErrorTag;
 import org.opendaylight.restconf.common.errors.RestconfError.ErrorType;
 import org.opendaylight.restconf.nb.rfc8040.rests.transactions.RestconfStrategy;
+import org.opendaylight.restconf.nb.rfc8040.rests.utils.RestconfDataServiceConstant.ReadData.WithDefaults;
 import org.opendaylight.restconf.nb.rfc8040.utils.parser.ParserFieldsParameter;
 import org.opendaylight.yangtools.yang.common.QName;
 import org.opendaylight.yangtools.yang.common.QNameModule;
@@ -162,14 +163,22 @@ public final class ReadDataTransactionUtil {
 
         // check and set withDefaults parameter
         if (!withDefaults.isEmpty()) {
-            switch (withDefaults.get(0)) {
-                case RestconfDataServiceConstant.ReadData.REPORT_ALL_TAGGED_DEFAULT_VALUE:
-                    builder.setTagged(true);
+            final String str = withDefaults.get(0);
+            final WithDefaults val = WithDefaults.forValue(str);
+            if (val == null) {
+                throw new RestconfDocumentedException(new RestconfError(RestconfError.ErrorType.PROTOCOL,
+                    RestconfError.ErrorTag.INVALID_VALUE, "Invalid with-defaults parameter: " + str, null,
+                    "The with-defaults parameter must be a string in " + WithDefaults.possibleValues()));
+            }
+
+            switch (val) {
+                case REPORT_ALL:
                     break;
-                case RestconfDataServiceConstant.ReadData.REPORT_ALL_DEFAULT_VALUE:
+                case REPORT_ALL_TAGGED:
+                    builder.setTagged(true);
                     break;
                 default:
-                    builder.setWithDefault(withDefaults.get(0));
+                    builder.setWithDefault(val.value());
             }
         }
         return builder.build();
index 27fabd4619699441ad76d63020d07e03d10838ba..c7ec32a140ca3fbbfb9d7de07415407e9a3f7104 100644 (file)
@@ -9,9 +9,10 @@ package org.opendaylight.restconf.nb.rfc8040.rests.utils;
 
 import static java.util.Objects.requireNonNull;
 
+import com.google.common.collect.ImmutableMap;
 import com.google.common.collect.Maps;
 import java.util.Arrays;
-import java.util.Map;
+import java.util.Set;
 import org.eclipse.jdt.annotation.NonNull;
 import org.eclipse.jdt.annotation.Nullable;
 import org.opendaylight.yangtools.yang.common.QName;
@@ -49,8 +50,50 @@ public final class RestconfDataServiceConstant {
         public static final int MAX_DEPTH = 65535;
 
         public static final String WITH_DEFAULTS = "with-defaults";
-        public static final String REPORT_ALL_DEFAULT_VALUE = "report-all";
-        public static final String REPORT_ALL_TAGGED_DEFAULT_VALUE = "report-all-tagged";
+
+        /**
+         * With-default values, as per
+         * <a href="https://tools.ietf.org/html/rfc8040#section-4.8.9">RFC8040 section 4.8.9</a>.
+         */
+        enum WithDefaults {
+            /**
+             * All data nodes are reported.
+             */
+            REPORT_ALL("report-all"),
+            /**
+             * Data nodes set to the YANG default are not reported.
+             */
+            TRIM("trim"),
+            /**
+             * Data nodes set to the YANG default by the client are reported.
+             */
+            EXPLICIT("explicit"),
+            /**
+             * All data nodes are reported, and defaults are tagged.
+             */
+            REPORT_ALL_TAGGED("report-all-tagged");
+
+            private static final ImmutableMap<String, WithDefaults> VALUES =
+                Maps.uniqueIndex(Arrays.asList(values()), WithDefaults::value);
+
+            private @NonNull String value;
+
+            WithDefaults(final @NonNull String value) {
+                this.value = value;
+            }
+
+            public @NonNull String value() {
+                return value;
+            }
+
+            static @Nullable WithDefaults forValue(final String value) {
+                return VALUES.get(requireNonNull(value));
+            }
+
+            static @Nullable Set<String> possibleValues() {
+                return VALUES.keySet();
+            }
+        }
 
         private ReadData() {
             throw new UnsupportedOperationException("Util class.");
@@ -85,7 +128,8 @@ public final class RestconfDataServiceConstant {
              */
             AFTER("after");
 
-            private static final Map<String, Insert> VALUES = Maps.uniqueIndex(Arrays.asList(values()), Insert::value);
+            private static final ImmutableMap<String, Insert> VALUES =
+                Maps.uniqueIndex(Arrays.asList(values()), Insert::value);
 
             private @NonNull String value;
 
index 428496125b29e898adadaf1aad0c8dd5ef551464..afad1bff1b528e516d440fc9ad4711a625ee9186 100644 (file)
@@ -11,6 +11,7 @@ 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.assertSame;
 import static org.junit.Assert.assertThrows;
 import static org.junit.Assert.assertTrue;
 import static org.junit.Assert.fail;
@@ -40,6 +41,7 @@ import org.opendaylight.netconf.dom.api.NetconfDataTreeService;
 import org.opendaylight.restconf.common.context.InstanceIdentifierContext;
 import org.opendaylight.restconf.common.context.WriterParameters;
 import org.opendaylight.restconf.common.errors.RestconfDocumentedException;
+import org.opendaylight.restconf.common.errors.RestconfError;
 import org.opendaylight.restconf.common.errors.RestconfError.ErrorTag;
 import org.opendaylight.restconf.common.errors.RestconfError.ErrorType;
 import org.opendaylight.restconf.nb.rfc8040.handlers.TransactionChainHandler;
@@ -47,6 +49,7 @@ import org.opendaylight.restconf.nb.rfc8040.rests.transactions.MdsalRestconfStra
 import org.opendaylight.restconf.nb.rfc8040.rests.transactions.NetconfRestconfStrategy;
 import org.opendaylight.restconf.nb.rfc8040.rests.transactions.RestconfStrategy;
 import org.opendaylight.restconf.nb.rfc8040.rests.utils.RestconfDataServiceConstant.ReadData;
+import org.opendaylight.restconf.nb.rfc8040.rests.utils.RestconfDataServiceConstant.ReadData.WithDefaults;
 import org.opendaylight.yangtools.yang.common.QName;
 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
 import org.opendaylight.yangtools.yang.data.api.schema.ContainerNode;
@@ -512,16 +515,32 @@ public class ReadDataTransactionUtilTest {
         // preparation of input data
         final UriInfo uriInfo = Mockito.mock(UriInfo.class);
         final MultivaluedHashMap<String, String> parameters = new MultivaluedHashMap<>();
-        final String preparedDefaultValue = "sample-default";
-        parameters.put(RestconfDataServiceConstant.ReadData.WITH_DEFAULTS,
-                Collections.singletonList(preparedDefaultValue));
+        parameters.put(RestconfDataServiceConstant.ReadData.WITH_DEFAULTS, Collections.singletonList("explicit"));
         when(uriInfo.getQueryParameters()).thenReturn(parameters);
 
         final WriterParameters writerParameters = ReadDataTransactionUtil.parseUriParameters(context, uriInfo);
-        assertEquals(preparedDefaultValue, writerParameters.getWithDefault());
+        assertSame(WithDefaults.EXPLICIT.value(), writerParameters.getWithDefault());
         assertFalse(writerParameters.isTagged());
     }
 
+    /**
+     * Testing parsing of with-defaults parameter which value which is not supported.
+     */
+    @Test
+    public void parseUriParametersWithDefaultInvalidTest() {
+        // preparation of input data
+        final UriInfo uriInfo = Mockito.mock(UriInfo.class);
+        final MultivaluedHashMap<String, String> parameters = new MultivaluedHashMap<>();
+        parameters.put(RestconfDataServiceConstant.ReadData.WITH_DEFAULTS, Collections.singletonList("invalid"));
+        when(uriInfo.getQueryParameters()).thenReturn(parameters);
+
+        final RestconfDocumentedException ex = assertThrows(RestconfDocumentedException.class,
+            () -> ReadDataTransactionUtil.parseUriParameters(context, uriInfo));
+        final List<RestconfError> errors = ex.getErrors();
+        assertEquals(1, errors.size());
+        assertEquals(ErrorTag.INVALID_VALUE, errors.get(0).getErrorTag());
+    }
+
     /**
      * Testing parsing of with-defaults parameter which value matches 'report-all-tagged' setting - default value should
      * be set to {@code null} and tagged flag should be set to {@code true}.
@@ -532,7 +551,7 @@ public class ReadDataTransactionUtilTest {
         final UriInfo uriInfo = Mockito.mock(UriInfo.class);
         final MultivaluedHashMap<String, String> parameters = new MultivaluedHashMap<>();
         parameters.put(RestconfDataServiceConstant.ReadData.WITH_DEFAULTS,
-                Collections.singletonList(ReadData.REPORT_ALL_TAGGED_DEFAULT_VALUE));
+                Collections.singletonList(ReadData.WithDefaults.REPORT_ALL_TAGGED.value()));
         when(uriInfo.getQueryParameters()).thenReturn(parameters);
 
         final WriterParameters writerParameters = ReadDataTransactionUtil.parseUriParameters(context, uriInfo);
@@ -550,7 +569,7 @@ public class ReadDataTransactionUtilTest {
         final UriInfo uriInfo = Mockito.mock(UriInfo.class);
         final MultivaluedHashMap<String, String> parameters = new MultivaluedHashMap<>();
         parameters.put(RestconfDataServiceConstant.ReadData.WITH_DEFAULTS,
-                Collections.singletonList(ReadData.REPORT_ALL_DEFAULT_VALUE));
+                Collections.singletonList(ReadData.WithDefaults.REPORT_ALL.value()));
         when(uriInfo.getQueryParameters()).thenReturn(parameters);
 
         final WriterParameters writerParameters = ReadDataTransactionUtil.parseUriParameters(context, uriInfo);