Rename restconf-nb-rfc8040 to restconf-nb
[netconf.git] / restconf / restconf-nb / src / test / java / org / opendaylight / restconf / nb / rfc8040 / databind / jaxrs / QueryParamsTest.java
diff --git a/restconf/restconf-nb/src/test/java/org/opendaylight/restconf/nb/rfc8040/databind/jaxrs/QueryParamsTest.java b/restconf/restconf-nb/src/test/java/org/opendaylight/restconf/nb/rfc8040/databind/jaxrs/QueryParamsTest.java
new file mode 100644 (file)
index 0000000..15de755
--- /dev/null
@@ -0,0 +1,245 @@
+/*
+ * Copyright (c) 2021 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.jaxrs;
+
+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.assertThrows;
+import static org.junit.Assert.assertTrue;
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.withSettings;
+
+import java.util.List;
+import java.util.Map;
+import java.util.Optional;
+import java.util.Set;
+import java.util.function.Function;
+import javax.ws.rs.core.MultivaluedHashMap;
+import javax.ws.rs.core.MultivaluedMap;
+import javax.ws.rs.core.UriInfo;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.junit.MockitoJUnitRunner;
+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.nb.rfc8040.ContentParam;
+import org.opendaylight.restconf.nb.rfc8040.DepthParam;
+import org.opendaylight.restconf.nb.rfc8040.InsertParam;
+import org.opendaylight.restconf.nb.rfc8040.RestconfQueryParam;
+import org.opendaylight.restconf.nb.rfc8040.WithDefaultsParam;
+import org.opendaylight.restconf.nb.rfc8040.legacy.QueryParameters;
+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.model.api.ContainerSchemaNode;
+import org.opendaylight.yangtools.yang.model.api.EffectiveModelContext;
+import org.opendaylight.yangtools.yang.model.api.LeafSchemaNode;
+import org.opendaylight.yangtools.yang.model.api.stmt.ContainerEffectiveStatement;
+import org.opendaylight.yangtools.yang.model.api.stmt.ModuleEffectiveStatement;
+import org.opendaylight.yangtools.yang.model.util.SchemaInferenceStack;
+
+@RunWith(MockitoJUnitRunner.StrictStubs.class)
+public class QueryParamsTest {
+    /**
+     * Test when parameter is present at most once.
+     */
+    @Test
+    public void optionalParamTest() {
+        assertEquals("all", QueryParams.optionalParam(ContentParam.uriName, List.of("all")));
+    }
+
+    /**
+     * Test when parameter is present more than once.
+     */
+    @Test
+    public void optionalParamMultipleTest() {
+        final RestconfDocumentedException ex = assertThrows(RestconfDocumentedException.class,
+            () -> QueryParams.optionalParam(ContentParam.uriName, List.of("config", "nonconfig", "all")));
+        final List<RestconfError> errors = ex.getErrors();
+        assertEquals(1, errors.size());
+
+        final RestconfError error = errors.get(0);
+        assertEquals("Error type is not correct", ErrorType.PROTOCOL, error.getErrorType());
+        assertEquals("Error tag is not correct", ErrorTag.INVALID_VALUE, error.getErrorTag());
+    }
+
+    /**
+     * Test when not allowed parameter type is used.
+     */
+    @Test
+    public void checkParametersTypesNegativeTest() {
+        assertUnknownParam(QueryParams::newNotificationQueryParams);
+        assertUnknownParam(QueryParams::newReadDataParams);
+        assertUnknownParam(QueryParams::newWriteDataParams);
+
+        assertInvalidParam(QueryParams::newNotificationQueryParams, ContentParam.ALL);
+        assertInvalidParam(QueryParams::newReadDataParams, InsertParam.LAST);
+        assertInvalidParam(QueryParams::newWriteDataParams, ContentParam.ALL);
+    }
+
+    /**
+     * Test of parsing default parameters from URI request.
+     */
+    @Test
+    public void parseUriParametersDefaultTest() {
+        // no parameters, default values should be used
+        final var params = assertParams(QueryParams::newReadDataParams, new MultivaluedHashMap<String, String>());
+        assertEquals(ContentParam.ALL, params.content());
+        assertNull(params.depth());
+        assertNull(params.fields());
+    }
+
+    @Test
+    public void testInvalidValueReadDataParams() {
+        assertInvalidValue(QueryParams::newReadDataParams, ContentParam.uriName);
+        assertInvalidValue(QueryParams::newReadDataParams, DepthParam.uriName);
+        assertInvalidValue(QueryParams::newReadDataParams, WithDefaultsParam.uriName);
+
+        // inserted value is too high
+        assertInvalidValue(QueryParams::newReadDataParams, DepthParam.uriName, "65536");
+        // inserted value is too low
+        assertInvalidValue(QueryParams::newReadDataParams, DepthParam.uriName, "0");
+    }
+
+    /**
+     * 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}.
+     */
+    @Test
+    public void parseUriParametersWithDefaultAndTaggedTest() {
+        final var params = assertParams(QueryParams::newReadDataParams, WithDefaultsParam.uriName, "report-all-tagged");
+        assertNull(params.withDefaults());
+        assertTrue(params.tagged());
+    }
+
+    /**
+     * Testing parsing of with-defaults parameter which value matches 'report-all' setting - default value should
+     * be set to {@code null} and tagged flag should be set to {@code false}.
+     */
+    @Test
+    public void parseUriParametersWithDefaultAndReportAllTest() {
+        final var params = assertParams(QueryParams::newReadDataParams, WithDefaultsParam.uriName, "report-all");
+        assertNull(params.withDefaults());
+        assertFalse(params.tagged());
+    }
+
+    /**
+     * Testing parsing of with-defaults parameter which value doesn't match report-all or report-all-tagged patterns
+     * - non-reporting setting.
+     */
+    @Test
+    public void parseUriParametersWithDefaultAndNonTaggedTest() {
+        final var params = assertParams(QueryParams::newReadDataParams, WithDefaultsParam.uriName, "explicit");
+        assertEquals(WithDefaultsParam.EXPLICIT, params.withDefaults());
+        assertFalse(params.tagged());
+    }
+
+    /**
+     * Test of parsing user defined parameters from URI request.
+     */
+    @Test
+    public void parseUriParametersUserDefinedTest() {
+        final QName containerChild = QName.create("ns", "container-child");
+
+        final var parameters = new MultivaluedHashMap<String, String>();
+        parameters.putSingle("content", "config");
+        parameters.putSingle("depth", "10");
+        parameters.putSingle("fields", "container-child");
+
+        final var params = assertParams(QueryParams::newReadDataParams, parameters);
+        // content
+        assertEquals(ContentParam.CONFIG, params.content());
+
+        // depth
+        final DepthParam depth = params.depth();
+        assertNotNull(depth);
+        assertEquals(10, depth.value());
+
+        // fields
+        assertNotNull(params.fields());
+
+        // fields for write filtering
+        final var containerSchema = mock(ContainerSchemaNode.class,
+            withSettings().extraInterfaces(ContainerEffectiveStatement.class));
+        final var containerQName = QName.create(containerChild, "container");
+        doReturn(containerQName).when(containerSchema).getQName();
+        final var containerChildSchema = mock(LeafSchemaNode.class);
+        doReturn(containerChild).when(containerChildSchema).getQName();
+        doReturn(containerChildSchema).when(containerSchema).dataChildByName(containerChild);
+
+        final var module = mock(ModuleEffectiveStatement.class);
+        doReturn(Optional.of(containerSchema)).when(module).findSchemaTreeNode(containerQName);
+        final var context = mock(EffectiveModelContext.class);
+        doReturn(Map.of(containerQName.getModule(), module)).when(context).getModuleStatements();
+
+        final var stack = SchemaInferenceStack.of(context);
+        stack.enterSchemaTree(containerQName);
+
+        final QueryParameters queryParameters = QueryParams.newQueryParameters(params,
+            InstanceIdentifierContext.ofStack(stack));
+        final List<Set<QName>> fields = queryParameters.fields();
+        assertNotNull(fields);
+        assertEquals(1, fields.size());
+        assertEquals(Set.of(containerChild), fields.get(0));
+    }
+
+    private static void assertInvalidParam(final Function<UriInfo, ?> paramsMethod, final RestconfQueryParam<?> param) {
+        final var params = new MultivaluedHashMap<String, String>();
+        params.putSingle(param.paramName(), "odl-test-value");
+        assertParamsThrows(ErrorTag.MALFORMED_MESSAGE, paramsMethod, params);
+    }
+
+    private static void assertUnknownParam(final Function<UriInfo, ?> paramsMethod) {
+        final var params = new MultivaluedHashMap<String, String>();
+        params.putSingle("odl-unknown-param", "odl-test-value");
+        assertParamsThrows(ErrorTag.UNKNOWN_ATTRIBUTE, paramsMethod, params);
+    }
+
+    private static void assertInvalidValue(final Function<UriInfo, ?> paramsMethod, final String name) {
+        assertInvalidValue(paramsMethod, name, "odl-invalid-value");
+    }
+
+    private static void assertInvalidValue(final Function<UriInfo, ?> paramsMethod, final String name,
+            final String value) {
+        final var params = new MultivaluedHashMap<String, String>();
+        params.putSingle(name, value);
+        assertParamsThrows(ErrorTag.INVALID_VALUE, paramsMethod, params);
+    }
+
+    private static void assertParamsThrows(final ErrorTag expectedTag, final Function<UriInfo, ?> paramsMethod,
+            final MultivaluedMap<String, String> params) {
+        final var uriInfo = mock(UriInfo.class);
+        doReturn(params).when(uriInfo).getQueryParameters();
+
+        final var ex = assertThrows(RestconfDocumentedException.class,  () -> paramsMethod.apply(uriInfo));
+        final var errors = ex.getErrors();
+        assertEquals(1, errors.size());
+
+        final var error = errors.get(0);
+        assertEquals(ErrorType.PROTOCOL, error.getErrorType());
+        assertEquals(expectedTag, error.getErrorTag());
+    }
+
+    private static <T> T assertParams(final Function<UriInfo, T> paramsMethod, final String name,
+            final String value) {
+        final var params = new MultivaluedHashMap<String, String>();
+        params.putSingle(name, value);
+        return assertParams(paramsMethod, params);
+    }
+
+    private static <T> T assertParams(final Function<UriInfo, T> paramsMethod,
+            final MultivaluedMap<String, String> params) {
+        final var uriInfo = mock(UriInfo.class);
+        doReturn(params).when(uriInfo).getQueryParameters();
+        return paramsMethod.apply(uriInfo);
+    }
+}