Expose parameter names as String constants
[netconf.git] / restconf / restconf-nb-rfc8040 / src / test / java / org / opendaylight / restconf / nb / rfc8040 / databind / jaxrs / QueryParamsTest.java
1 /*
2  * Copyright (c) 2021 PANTHEON.tech, s.r.o. and others.  All rights reserved.
3  *
4  * This program and the accompanying materials are made available under the
5  * terms of the Eclipse Public License v1.0 which accompanies this distribution,
6  * and is available at http://www.eclipse.org/legal/epl-v10.html
7  */
8 package org.opendaylight.restconf.nb.rfc8040.databind.jaxrs;
9
10 import static org.junit.Assert.assertEquals;
11 import static org.junit.Assert.assertFalse;
12 import static org.junit.Assert.assertNotNull;
13 import static org.junit.Assert.assertNull;
14 import static org.junit.Assert.assertThrows;
15 import static org.junit.Assert.assertTrue;
16 import static org.mockito.Mockito.doReturn;
17 import static org.mockito.Mockito.mock;
18
19 import java.util.List;
20 import java.util.Set;
21 import java.util.function.Function;
22 import javax.ws.rs.core.MultivaluedHashMap;
23 import javax.ws.rs.core.MultivaluedMap;
24 import javax.ws.rs.core.UriInfo;
25 import org.junit.Test;
26 import org.junit.runner.RunWith;
27 import org.mockito.junit.MockitoJUnitRunner;
28 import org.opendaylight.restconf.common.context.InstanceIdentifierContext;
29 import org.opendaylight.restconf.common.errors.RestconfDocumentedException;
30 import org.opendaylight.restconf.common.errors.RestconfError;
31 import org.opendaylight.restconf.nb.rfc8040.ContentParam;
32 import org.opendaylight.restconf.nb.rfc8040.DepthParam;
33 import org.opendaylight.restconf.nb.rfc8040.InsertParam;
34 import org.opendaylight.restconf.nb.rfc8040.RestconfQueryParam;
35 import org.opendaylight.restconf.nb.rfc8040.WithDefaultsParam;
36 import org.opendaylight.restconf.nb.rfc8040.legacy.QueryParameters;
37 import org.opendaylight.yangtools.yang.common.ErrorTag;
38 import org.opendaylight.yangtools.yang.common.ErrorType;
39 import org.opendaylight.yangtools.yang.common.QName;
40 import org.opendaylight.yangtools.yang.model.api.ContainerSchemaNode;
41 import org.opendaylight.yangtools.yang.model.api.EffectiveModelContext;
42 import org.opendaylight.yangtools.yang.model.api.LeafSchemaNode;
43
44 @RunWith(MockitoJUnitRunner.StrictStubs.class)
45 public class QueryParamsTest {
46     /**
47      * Test when parameter is present at most once.
48      */
49     @Test
50     public void optionalParamTest() {
51         assertEquals("all", QueryParams.optionalParam(ContentParam.uriName, List.of("all")));
52     }
53
54     /**
55      * Test when parameter is present more than once.
56      */
57     @Test
58     public void optionalParamMultipleTest() {
59         final RestconfDocumentedException ex = assertThrows(RestconfDocumentedException.class,
60             () -> QueryParams.optionalParam(ContentParam.uriName, List.of("config", "nonconfig", "all")));
61         final List<RestconfError> errors = ex.getErrors();
62         assertEquals(1, errors.size());
63
64         final RestconfError error = errors.get(0);
65         assertEquals("Error type is not correct", ErrorType.PROTOCOL, error.getErrorType());
66         assertEquals("Error tag is not correct", ErrorTag.INVALID_VALUE, error.getErrorTag());
67     }
68
69     /**
70      * Test when not allowed parameter type is used.
71      */
72     @Test
73     public void checkParametersTypesNegativeTest() {
74         assertUnknownParam(QueryParams::newNotificationQueryParams);
75         assertUnknownParam(QueryParams::newReadDataParams);
76         assertUnknownParam(QueryParams::newWriteDataParams);
77
78         assertInvalidParam(QueryParams::newNotificationQueryParams, ContentParam.ALL);
79         assertInvalidParam(QueryParams::newReadDataParams, InsertParam.LAST);
80         assertInvalidParam(QueryParams::newWriteDataParams, ContentParam.ALL);
81     }
82
83     /**
84      * Test of parsing default parameters from URI request.
85      */
86     @Test
87     public void parseUriParametersDefaultTest() {
88         // no parameters, default values should be used
89         final var params = assertParams(QueryParams::newReadDataParams, new MultivaluedHashMap<String, String>());
90         assertEquals(ContentParam.ALL, params.content());
91         assertNull(params.depth());
92         assertNull(params.fields());
93     }
94
95     @Test
96     public void testInvalidValueReadDataParams() {
97         assertInvalidValue(QueryParams::newReadDataParams, ContentParam.uriName);
98         assertInvalidValue(QueryParams::newReadDataParams, DepthParam.uriName);
99         assertInvalidValue(QueryParams::newReadDataParams, WithDefaultsParam.uriName);
100
101         // inserted value is too high
102         assertInvalidValue(QueryParams::newReadDataParams, DepthParam.uriName, "65536");
103         // inserted value is too low
104         assertInvalidValue(QueryParams::newReadDataParams, DepthParam.uriName, "0");
105     }
106
107     /**
108      * Testing parsing of with-defaults parameter which value matches 'report-all-tagged' setting - default value should
109      * be set to {@code null} and tagged flag should be set to {@code true}.
110      */
111     @Test
112     public void parseUriParametersWithDefaultAndTaggedTest() {
113         final var params = assertParams(QueryParams::newReadDataParams, WithDefaultsParam.uriName, "report-all-tagged");
114         assertNull(params.withDefaults());
115         assertTrue(params.tagged());
116     }
117
118     /**
119      * Testing parsing of with-defaults parameter which value matches 'report-all' setting - default value should
120      * be set to {@code null} and tagged flag should be set to {@code false}.
121      */
122     @Test
123     public void parseUriParametersWithDefaultAndReportAllTest() {
124         final var params = assertParams(QueryParams::newReadDataParams, WithDefaultsParam.uriName, "report-all");
125         assertNull(params.withDefaults());
126         assertFalse(params.tagged());
127     }
128
129     /**
130      * Testing parsing of with-defaults parameter which value doesn't match report-all or report-all-tagged patterns
131      * - non-reporting setting.
132      */
133     @Test
134     public void parseUriParametersWithDefaultAndNonTaggedTest() {
135         final var params = assertParams(QueryParams::newReadDataParams, WithDefaultsParam.uriName, "explicit");
136         assertEquals(WithDefaultsParam.EXPLICIT, params.withDefaults());
137         assertFalse(params.tagged());
138     }
139
140     /**
141      * Test of parsing user defined parameters from URI request.
142      */
143     @Test
144     public void parseUriParametersUserDefinedTest() {
145         final QName containerChild = QName.create("ns", "container-child");
146
147         final var parameters = new MultivaluedHashMap<String, String>();
148         parameters.putSingle("content", "config");
149         parameters.putSingle("depth", "10");
150         parameters.putSingle("fields", "container-child");
151
152         final var params = assertParams(QueryParams::newReadDataParams, parameters);
153         // content
154         assertEquals(ContentParam.CONFIG, params.content());
155
156         // depth
157         final DepthParam depth = params.depth();
158         assertNotNull(depth);
159         assertEquals(10, depth.value());
160
161         // fields
162         assertNotNull(params.fields());
163
164         // fields for write filtering
165         final var containerSchema = mock(ContainerSchemaNode.class);
166         doReturn(QName.create(containerChild, "container")).when(containerSchema).getQName();
167         final var containerChildSchema = mock(LeafSchemaNode.class);
168         doReturn(containerChild).when(containerChildSchema).getQName();
169         doReturn(containerChildSchema).when(containerSchema).dataChildByName(containerChild);
170         final var context = mock(InstanceIdentifierContext.class);
171         final var modelContext = mock(EffectiveModelContext.class);
172         doReturn(modelContext).when(context).getSchemaContext();
173         doReturn(containerSchema).when(context).getSchemaNode();
174
175         final QueryParameters queryParameters = QueryParams.newQueryParameters(params, context);
176         final List<Set<QName>> fields = queryParameters.fields();
177         assertNotNull(fields);
178         assertEquals(1, fields.size());
179         assertEquals(Set.of(containerChild), fields.get(0));
180     }
181
182     private static void assertInvalidParam(final Function<UriInfo, ?> paramsMethod, final RestconfQueryParam<?> param) {
183         final var params = new MultivaluedHashMap<String, String>();
184         params.putSingle(param.paramName(), "odl-test-value");
185         assertParamsThrows(ErrorTag.MALFORMED_MESSAGE, paramsMethod, params);
186     }
187
188     private static void assertUnknownParam(final Function<UriInfo, ?> paramsMethod) {
189         final var params = new MultivaluedHashMap<String, String>();
190         params.putSingle("odl-unknown-param", "odl-test-value");
191         assertParamsThrows(ErrorTag.UNKNOWN_ATTRIBUTE, paramsMethod, params);
192     }
193
194     private static void assertInvalidValue(final Function<UriInfo, ?> paramsMethod, final String name) {
195         assertInvalidValue(paramsMethod, name, "odl-invalid-value");
196     }
197
198     private static void assertInvalidValue(final Function<UriInfo, ?> paramsMethod, final String name,
199             final String value) {
200         final var params = new MultivaluedHashMap<String, String>();
201         params.putSingle(name, value);
202         assertParamsThrows(ErrorTag.INVALID_VALUE, paramsMethod, params);
203     }
204
205     private static void assertParamsThrows(final ErrorTag expectedTag, final Function<UriInfo, ?> paramsMethod,
206             final MultivaluedMap<String, String> params) {
207         final var uriInfo = mock(UriInfo.class);
208         doReturn(params).when(uriInfo).getQueryParameters();
209
210         final var ex = assertThrows(RestconfDocumentedException.class,  () -> paramsMethod.apply(uriInfo));
211         final var errors = ex.getErrors();
212         assertEquals(1, errors.size());
213
214         final var error = errors.get(0);
215         assertEquals(ErrorType.PROTOCOL, error.getErrorType());
216         assertEquals(expectedTag, error.getErrorTag());
217     }
218
219     private static <T> T assertParams(final Function<UriInfo, T> paramsMethod, final String name,
220             final String value) {
221         final var params = new MultivaluedHashMap<String, String>();
222         params.putSingle(name, value);
223         return assertParams(paramsMethod, params);
224     }
225
226     private static <T> T assertParams(final Function<UriInfo, T> paramsMethod,
227             final MultivaluedMap<String, String> params) {
228         final var uriInfo = mock(UriInfo.class);
229         doReturn(params).when(uriInfo).getQueryParameters();
230         return paramsMethod.apply(uriInfo);
231     }
232 }