Bug 6895 - Implement Query parameters - depth
[netconf.git] / restconf / sal-rest-connector / src / test / java / org / opendaylight / restconf / restful / utils / ReadDataTransactionUtilTest.java
1 /*
2  * Copyright (c) 2016 Cisco Systems, Inc. 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
9 package org.opendaylight.restconf.restful.utils;
10
11 import static org.junit.Assert.assertEquals;
12 import static org.junit.Assert.assertFalse;
13 import static org.junit.Assert.assertNull;
14 import static org.junit.Assert.assertTrue;
15 import static org.junit.Assert.fail;
16 import static org.mockito.Mockito.doReturn;
17 import static org.mockito.Mockito.when;
18
19 import com.google.common.base.Optional;
20 import com.google.common.util.concurrent.Futures;
21 import java.util.Collections;
22 import javax.ws.rs.core.MultivaluedHashMap;
23 import javax.ws.rs.core.UriInfo;
24 import org.junit.Before;
25 import org.junit.Test;
26 import org.mockito.Mock;
27 import org.mockito.Mockito;
28 import org.mockito.MockitoAnnotations;
29 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
30 import org.opendaylight.controller.md.sal.dom.api.DOMDataReadOnlyTransaction;
31 import org.opendaylight.controller.md.sal.dom.api.DOMTransactionChain;
32 import org.opendaylight.netconf.sal.restconf.impl.InstanceIdentifierContext;
33 import org.opendaylight.netconf.sal.restconf.impl.RestconfDocumentedException;
34 import org.opendaylight.netconf.sal.restconf.impl.RestconfError.ErrorTag;
35 import org.opendaylight.netconf.sal.restconf.impl.RestconfError.ErrorType;
36 import org.opendaylight.netconf.sal.restconf.impl.WriterParameters;
37 import org.opendaylight.restconf.restful.transaction.TransactionVarsWrapper;
38 import org.opendaylight.yangtools.yang.common.QName;
39 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
40 import org.opendaylight.yangtools.yang.data.api.schema.ContainerNode;
41 import org.opendaylight.yangtools.yang.data.api.schema.MapNode;
42 import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
43 import org.opendaylight.yangtools.yang.data.impl.schema.Builders;
44
45 public class ReadDataTransactionUtilTest {
46
47     private static final TestData data = new TestData();
48     private static final YangInstanceIdentifier.NodeIdentifier nodeIdentifier = new YangInstanceIdentifier
49             .NodeIdentifier(QName.create("ns", "2016-02-28", "container"));
50
51     private TransactionVarsWrapper wrapper;
52     @Mock
53     private DOMTransactionChain transactionChain;
54     @Mock
55     private InstanceIdentifierContext<?> context;
56     @Mock
57     private DOMDataReadOnlyTransaction read;
58
59     @Before
60     public void setUp() {
61         MockitoAnnotations.initMocks(this);
62
63         doReturn(read).when(transactionChain).newReadOnlyTransaction();
64         wrapper = new TransactionVarsWrapper(this.context, null, this.transactionChain);
65     }
66
67     @Test
68     public void readDataConfigTest() {
69         doReturn(Futures.immediateCheckedFuture(Optional.of(data.data3))).when(read)
70                 .read(LogicalDatastoreType.CONFIGURATION, data.path);
71         doReturn(data.path).when(context).getInstanceIdentifier();
72         final String valueOfContent = RestconfDataServiceConstant.ReadData.CONFIG;
73         final NormalizedNode<?, ?> normalizedNode = ReadDataTransactionUtil.readData(valueOfContent, wrapper);
74         assertEquals(data.data3, normalizedNode);
75     }
76
77     @Test
78     public void readAllHavingOnlyConfigTest() {
79         doReturn(Futures.immediateCheckedFuture(Optional.of(data.data3))).when(read)
80                 .read(LogicalDatastoreType.CONFIGURATION, data.path);
81         doReturn(Futures.immediateCheckedFuture(Optional.absent())).when(read)
82                 .read(LogicalDatastoreType.OPERATIONAL, data.path);
83         doReturn(data.path).when(context).getInstanceIdentifier();
84         final String valueOfContent = RestconfDataServiceConstant.ReadData.ALL;
85         final NormalizedNode<?, ?> normalizedNode = ReadDataTransactionUtil.readData(valueOfContent, wrapper);
86         assertEquals(data.data3, normalizedNode);
87     }
88
89     @Test
90     public void readAllHavingOnlyNonConfigTest() {
91         doReturn(Futures.immediateCheckedFuture(Optional.of(data.data2))).when(read)
92                 .read(LogicalDatastoreType.OPERATIONAL, data.path2);
93         doReturn(Futures.immediateCheckedFuture(Optional.absent())).when(read)
94                 .read(LogicalDatastoreType.CONFIGURATION, data.path2);
95         doReturn(data.path2).when(context).getInstanceIdentifier();
96         final String valueOfContent = RestconfDataServiceConstant.ReadData.ALL;
97         final NormalizedNode<?, ?> normalizedNode = ReadDataTransactionUtil.readData(valueOfContent, wrapper);
98         assertEquals(data.data2, normalizedNode);
99     }
100
101     @Test
102     public void readDataNonConfigTest() {
103         doReturn(Futures.immediateCheckedFuture(Optional.of(data.data2))).when(read)
104                 .read(LogicalDatastoreType.OPERATIONAL, data.path2);
105         doReturn(data.path2).when(context).getInstanceIdentifier();
106         final String valueOfContent = RestconfDataServiceConstant.ReadData.NONCONFIG;
107         final NormalizedNode<?, ?> normalizedNode = ReadDataTransactionUtil.readData(valueOfContent, wrapper);
108         assertEquals(data.data2, normalizedNode);
109     }
110
111     @Test
112     public void readContainerDataAllTest() {
113         doReturn(Futures.immediateCheckedFuture(Optional.of(data.data3))).when(read)
114                 .read(LogicalDatastoreType.CONFIGURATION, data.path);
115         doReturn(Futures.immediateCheckedFuture(Optional.of(data.data4))).when(read)
116                 .read(LogicalDatastoreType.OPERATIONAL, data.path);
117         doReturn(data.path).when(context).getInstanceIdentifier();
118         final String valueOfContent = RestconfDataServiceConstant.ReadData.ALL;
119         final NormalizedNode<?, ?> normalizedNode = ReadDataTransactionUtil.readData(valueOfContent, wrapper);
120         final ContainerNode checkingData = Builders
121                 .containerBuilder()
122                 .withNodeIdentifier(nodeIdentifier)
123                 .withChild(data.contentLeaf)
124                 .withChild(data.contentLeaf2)
125                 .build();
126         assertEquals(checkingData, normalizedNode);
127     }
128
129     @Test
130     public void readContainerDataConfigNoValueOfContentTest() {
131         doReturn(Futures.immediateCheckedFuture(Optional.of(data.data3))).when(read)
132                 .read(LogicalDatastoreType.CONFIGURATION, data.path);
133         doReturn(Futures.immediateCheckedFuture(Optional.of(data.data4))).when(read)
134                 .read(LogicalDatastoreType.OPERATIONAL, data.path);
135         doReturn(data.path).when(context).getInstanceIdentifier();
136         final NormalizedNode<?, ?> normalizedNode = ReadDataTransactionUtil.readData(
137                 RestconfDataServiceConstant.ReadData.ALL, wrapper);
138         final ContainerNode checkingData = Builders
139                 .containerBuilder()
140                 .withNodeIdentifier(nodeIdentifier)
141                 .withChild(data.contentLeaf)
142                 .withChild(data.contentLeaf2)
143                 .build();
144         assertEquals(checkingData, normalizedNode);
145     }
146
147     @Test
148     public void readListDataAllTest() {
149         doReturn(Futures.immediateCheckedFuture(Optional.of(data.listData))).when(read)
150                 .read(LogicalDatastoreType.OPERATIONAL, data.path3);
151         doReturn(Futures.immediateCheckedFuture(Optional.of(data.listData2))).when(read)
152                 .read(LogicalDatastoreType.CONFIGURATION, data.path3);
153         doReturn(data.path3).when(context).getInstanceIdentifier();
154         final String valueOfContent = RestconfDataServiceConstant.ReadData.ALL;
155         final NormalizedNode<?, ?> normalizedNode = ReadDataTransactionUtil.readData(valueOfContent, wrapper);
156         final MapNode checkingData = Builders
157                 .mapBuilder()
158                 .withNodeIdentifier(new YangInstanceIdentifier.NodeIdentifier(QName.create("ns", "2016-02-28", "list")))
159                 .withChild(data.checkData)
160                 .build();
161         assertEquals(checkingData, normalizedNode);
162     }
163
164     @Test
165     public void readDataWrongPathOrNoContentTest() {
166         doReturn(Futures.immediateCheckedFuture(Optional.absent())).when(read)
167                 .read(LogicalDatastoreType.CONFIGURATION, data.path2);
168         doReturn(data.path2).when(context).getInstanceIdentifier();
169         final String valueOfContent = RestconfDataServiceConstant.ReadData.CONFIG;
170         final NormalizedNode<?, ?> normalizedNode = ReadDataTransactionUtil.readData(valueOfContent, wrapper);
171         assertNull(normalizedNode);
172     }
173
174     @Test(expected = RestconfDocumentedException.class)
175     public void readDataFailTest() {
176         final String valueOfContent = RestconfDataServiceConstant.ReadData.READ_TYPE_TX;
177         final NormalizedNode<?, ?> normalizedNode = ReadDataTransactionUtil.readData(valueOfContent, null);
178         assertNull(normalizedNode);
179     }
180
181     /**
182      * Test of parsing default parameters from URI request
183      */
184     @Test
185     public void parseUriParametersDefaultTest() {
186         final UriInfo uriInfo = Mockito.mock(UriInfo.class);
187         final MultivaluedHashMap<String, String> parameters = new MultivaluedHashMap<>();
188
189         // no parameters, default values should be used
190         when(uriInfo.getQueryParameters()).thenReturn(parameters);
191
192         final WriterParameters parsedParameters = ReadDataTransactionUtil.parseUriParameters(uriInfo);
193
194         assertEquals("Not correctly parsed URI parameter",
195                 RestconfDataServiceConstant.ReadData.ALL, parsedParameters.getContent());
196         assertFalse("Not correctly parsed URI parameter",
197                 parsedParameters.getDepth().isPresent());
198     }
199
200     /**
201      * Test of parsing user defined parameters from URI request
202      */
203     @Test
204     public void parseUriParametersUserDefinedTest() {
205         final UriInfo uriInfo = Mockito.mock(UriInfo.class);
206         final MultivaluedHashMap<String, String> parameters = new MultivaluedHashMap<>();
207
208         final String content = "config";
209         final String depth = "10";
210
211         parameters.put("content", Collections.singletonList(content));
212         parameters.put("depth", Collections.singletonList(depth));
213
214         when(uriInfo.getQueryParameters()).thenReturn(parameters);
215
216         final WriterParameters parsedParameters = ReadDataTransactionUtil.parseUriParameters(uriInfo);
217
218         assertEquals("Not correctly parsed URI parameter",
219                 content, parsedParameters.getContent());
220         assertTrue("Not correctly parsed URI parameter",
221                 parsedParameters.getDepth().isPresent());
222         assertEquals("Not correctly parsed URI parameter",
223                 depth, parsedParameters.getDepth().get().toString());
224     }
225
226     /**
227      * Negative test of parsing request URI parameters when content parameter has not allowed value.
228      */
229     @Test
230     public void parseUriParametersContentParameterNegativeTest() {
231         final UriInfo uriInfo = Mockito.mock(UriInfo.class);
232         final MultivaluedHashMap<String, String> parameters = new MultivaluedHashMap<>();
233
234         parameters.put("content", Collections.singletonList("not-allowed-parameter-value"));
235         when(uriInfo.getQueryParameters()).thenReturn(parameters);
236
237         try {
238             ReadDataTransactionUtil.parseUriParameters(uriInfo);
239             fail("Test expected to fail due to not allowed parameter value");
240         } catch (final RestconfDocumentedException e) {
241             // Bad request
242             assertEquals("Error type is not correct", ErrorType.PROTOCOL, e.getErrors().get(0).getErrorType());
243             assertEquals("Error tag is not correct", ErrorTag.INVALID_VALUE, e.getErrors().get(0).getErrorTag());
244             assertEquals("Error status code is not correct", 400, e.getErrors().get(0).getErrorTag().getStatusCode());
245         }
246     }
247
248     /**
249      * Negative test of parsing request URI parameters when depth parameter has not allowed value.
250      */
251     @Test
252     public void parseUriParametersDepthParameterNegativeTest() {
253         final UriInfo uriInfo = Mockito.mock(UriInfo.class);
254         final MultivaluedHashMap<String, String> parameters = new MultivaluedHashMap<>();
255
256         // inserted value is not allowed
257         parameters.put("depth", Collections.singletonList("bounded"));
258         when(uriInfo.getQueryParameters()).thenReturn(parameters);
259
260         try {
261             ReadDataTransactionUtil.parseUriParameters(uriInfo);
262             fail("Test expected to fail due to not allowed parameter value");
263         } catch (final RestconfDocumentedException e) {
264             // Bad request
265             assertEquals("Error type is not correct", ErrorType.PROTOCOL, e.getErrors().get(0).getErrorType());
266             assertEquals("Error tag is not correct", ErrorTag.INVALID_VALUE, e.getErrors().get(0).getErrorTag());
267             assertEquals("Error status code is not correct", 400, e.getErrors().get(0).getErrorTag().getStatusCode());
268         }
269     }
270
271     /**
272      * Negative test of parsing request URI parameters when depth parameter has not allowed value (less than minimum).
273      */
274     @Test
275     public void parseUriParametersDepthMinimalParameterNegativeTest() {
276         final UriInfo uriInfo = Mockito.mock(UriInfo.class);
277         final MultivaluedHashMap<String, String> parameters = new MultivaluedHashMap<>();
278
279         // inserted value is too low
280         parameters.put(
281                 "depth", Collections.singletonList(String.valueOf(RestconfDataServiceConstant.ReadData.MIN_DEPTH - 1)));
282         when(uriInfo.getQueryParameters()).thenReturn(parameters);
283
284         try {
285             ReadDataTransactionUtil.parseUriParameters(uriInfo);
286             fail("Test expected to fail due to not allowed parameter value");
287         } catch (final RestconfDocumentedException e) {
288             // Bad request
289             assertEquals("Error type is not correct", ErrorType.PROTOCOL, e.getErrors().get(0).getErrorType());
290             assertEquals("Error tag is not correct", ErrorTag.INVALID_VALUE, e.getErrors().get(0).getErrorTag());
291             assertEquals("Error status code is not correct", 400, e.getErrors().get(0).getErrorTag().getStatusCode());
292         }
293     }
294
295     /**
296      * Negative test of parsing request URI parameters when depth parameter has not allowed value (more than maximum).
297      */
298     @Test
299     public void parseUriParametersDepthMaximalParameterNegativeTest() {
300         final UriInfo uriInfo = Mockito.mock(UriInfo.class);
301         final MultivaluedHashMap<String, String> parameters = new MultivaluedHashMap<>();
302
303         // inserted value is too high
304         parameters.put(
305                 "depth", Collections.singletonList(String.valueOf(RestconfDataServiceConstant.ReadData.MAX_DEPTH + 1)));
306         when(uriInfo.getQueryParameters()).thenReturn(parameters);
307
308         try {
309             ReadDataTransactionUtil.parseUriParameters(uriInfo);
310             fail("Test expected to fail due to not allowed parameter value");
311         } catch (final RestconfDocumentedException e) {
312             // Bad request
313             assertEquals("Error type is not correct", ErrorType.PROTOCOL, e.getErrors().get(0).getErrorType());
314             assertEquals("Error tag is not correct", ErrorTag.INVALID_VALUE, e.getErrors().get(0).getErrorTag());
315             assertEquals("Error status code is not correct", 400, e.getErrors().get(0).getErrorTag().getStatusCode());
316         }
317     }
318 }