Merge "Convert netconf-util, netconf-ssh, netconf-tcp to blueprint"
[netconf.git] / restconf / restconf-nb-rfc8040 / src / test / java / org / opendaylight / restconf / nb / rfc8040 / rests / 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.nb.rfc8040.rests.utils;
10
11 import static org.junit.Assert.assertEquals;
12 import static org.junit.Assert.assertNotNull;
13 import static org.junit.Assert.assertNull;
14 import static org.junit.Assert.fail;
15 import static org.mockito.Mockito.doReturn;
16 import static org.mockito.Mockito.when;
17
18 import com.google.common.base.Optional;
19 import com.google.common.collect.ImmutableList;
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.restconf.common.context.InstanceIdentifierContext;
33 import org.opendaylight.restconf.common.context.WriterParameters;
34 import org.opendaylight.restconf.common.errors.RestconfDocumentedException;
35 import org.opendaylight.restconf.common.errors.RestconfError.ErrorTag;
36 import org.opendaylight.restconf.common.errors.RestconfError.ErrorType;
37 import org.opendaylight.restconf.nb.rfc8040.rests.transactions.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.LeafSetEntryNode;
42 import org.opendaylight.yangtools.yang.data.api.schema.LeafSetNode;
43 import org.opendaylight.yangtools.yang.data.api.schema.MapNode;
44 import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
45 import org.opendaylight.yangtools.yang.data.api.schema.UnkeyedListNode;
46 import org.opendaylight.yangtools.yang.data.impl.schema.Builders;
47 import org.opendaylight.yangtools.yang.model.api.ContainerSchemaNode;
48 import org.opendaylight.yangtools.yang.model.api.LeafSchemaNode;
49 import org.opendaylight.yangtools.yang.model.api.SchemaContext;
50
51 public class ReadDataTransactionUtilTest {
52
53     private static final TestData DATA = new TestData();
54     private static final YangInstanceIdentifier.NodeIdentifier NODE_IDENTIFIER = new YangInstanceIdentifier
55             .NodeIdentifier(QName.create("ns", "2016-02-28", "container"));
56
57     private TransactionVarsWrapper wrapper;
58     @Mock
59     private DOMTransactionChain transactionChain;
60     @Mock
61     private InstanceIdentifierContext<ContainerSchemaNode> context;
62     @Mock
63     private DOMDataReadOnlyTransaction read;
64     @Mock
65     private SchemaContext schemaContext;
66     @Mock
67     private ContainerSchemaNode containerSchemaNode;
68     @Mock
69     private LeafSchemaNode containerChildNode;
70     private QName containerChildQName;
71
72     @Before
73     public void setUp() {
74         MockitoAnnotations.initMocks(this);
75
76         containerChildQName = QName.create("ns", "2016-02-28", "container-child");
77
78         when(transactionChain.newReadOnlyTransaction()).thenReturn(read);
79         when(context.getSchemaContext()).thenReturn(schemaContext);
80         when(context.getSchemaNode()).thenReturn(containerSchemaNode);
81         when(containerSchemaNode.getQName()).thenReturn(NODE_IDENTIFIER.getNodeType());
82         when(containerChildNode.getQName()).thenReturn(containerChildQName);
83         when(containerSchemaNode.getDataChildByName(containerChildQName)).thenReturn(containerChildNode);
84
85         wrapper = new TransactionVarsWrapper(this.context, null, this.transactionChain);
86     }
87
88     @Test
89     public void readDataConfigTest() {
90         doReturn(Futures.immediateCheckedFuture(Optional.of(DATA.data3))).when(read)
91                 .read(LogicalDatastoreType.CONFIGURATION, DATA.path);
92         doReturn(DATA.path).when(context).getInstanceIdentifier();
93         final String valueOfContent = RestconfDataServiceConstant.ReadData.CONFIG;
94         final NormalizedNode<?, ?> normalizedNode =
95                 ReadDataTransactionUtil.readData(valueOfContent, wrapper, schemaContext);
96         assertEquals(DATA.data3, normalizedNode);
97     }
98
99     @Test
100     public void readAllHavingOnlyConfigTest() {
101         doReturn(Futures.immediateCheckedFuture(Optional.of(DATA.data3))).when(read)
102                 .read(LogicalDatastoreType.CONFIGURATION, DATA.path);
103         doReturn(Futures.immediateCheckedFuture(Optional.absent())).when(read)
104                 .read(LogicalDatastoreType.OPERATIONAL, DATA.path);
105         doReturn(DATA.path).when(context).getInstanceIdentifier();
106         final String valueOfContent = RestconfDataServiceConstant.ReadData.ALL;
107         final NormalizedNode<?, ?> normalizedNode =
108                 ReadDataTransactionUtil.readData(valueOfContent, wrapper, schemaContext);
109         assertEquals(DATA.data3, normalizedNode);
110     }
111
112     @Test
113     public void readAllHavingOnlyNonConfigTest() {
114         doReturn(Futures.immediateCheckedFuture(Optional.of(DATA.data2))).when(read)
115                 .read(LogicalDatastoreType.OPERATIONAL, DATA.path2);
116         doReturn(Futures.immediateCheckedFuture(Optional.absent())).when(read)
117                 .read(LogicalDatastoreType.CONFIGURATION, DATA.path2);
118         doReturn(DATA.path2).when(context).getInstanceIdentifier();
119         final String valueOfContent = RestconfDataServiceConstant.ReadData.ALL;
120         final NormalizedNode<?, ?> normalizedNode =
121                 ReadDataTransactionUtil.readData(valueOfContent, wrapper, schemaContext);
122         assertEquals(DATA.data2, normalizedNode);
123     }
124
125     @Test
126     public void readDataNonConfigTest() {
127         doReturn(Futures.immediateCheckedFuture(Optional.of(DATA.data2))).when(read)
128                 .read(LogicalDatastoreType.OPERATIONAL, DATA.path2);
129         doReturn(DATA.path2).when(context).getInstanceIdentifier();
130         final String valueOfContent = RestconfDataServiceConstant.ReadData.NONCONFIG;
131         final NormalizedNode<?, ?> normalizedNode =
132                 ReadDataTransactionUtil.readData(valueOfContent, wrapper, schemaContext);
133         assertEquals(DATA.data2, normalizedNode);
134     }
135
136     @Test
137     public void readContainerDataAllTest() {
138         doReturn(Futures.immediateCheckedFuture(Optional.of(DATA.data3))).when(read)
139                 .read(LogicalDatastoreType.CONFIGURATION, DATA.path);
140         doReturn(Futures.immediateCheckedFuture(Optional.of(DATA.data4))).when(read)
141                 .read(LogicalDatastoreType.OPERATIONAL, DATA.path);
142         doReturn(DATA.path).when(context).getInstanceIdentifier();
143         final String valueOfContent = RestconfDataServiceConstant.ReadData.ALL;
144         final NormalizedNode<?, ?> normalizedNode =
145                 ReadDataTransactionUtil.readData(valueOfContent, wrapper, schemaContext);
146         final ContainerNode checkingData = Builders
147                 .containerBuilder()
148                 .withNodeIdentifier(NODE_IDENTIFIER)
149                 .withChild(DATA.contentLeaf)
150                 .withChild(DATA.contentLeaf2)
151                 .build();
152         assertEquals(checkingData, normalizedNode);
153     }
154
155     @Test
156     public void readContainerDataConfigNoValueOfContentTest() {
157         doReturn(Futures.immediateCheckedFuture(Optional.of(DATA.data3))).when(read)
158                 .read(LogicalDatastoreType.CONFIGURATION, DATA.path);
159         doReturn(Futures.immediateCheckedFuture(Optional.of(DATA.data4))).when(read)
160                 .read(LogicalDatastoreType.OPERATIONAL, DATA.path);
161         doReturn(DATA.path).when(context).getInstanceIdentifier();
162         final NormalizedNode<?, ?> normalizedNode = ReadDataTransactionUtil.readData(
163                 RestconfDataServiceConstant.ReadData.ALL, wrapper, schemaContext);
164         final ContainerNode checkingData = Builders
165                 .containerBuilder()
166                 .withNodeIdentifier(NODE_IDENTIFIER)
167                 .withChild(DATA.contentLeaf)
168                 .withChild(DATA.contentLeaf2)
169                 .build();
170         assertEquals(checkingData, normalizedNode);
171     }
172
173     @Test
174     public void readListDataAllTest() {
175         doReturn(Futures.immediateCheckedFuture(Optional.of(DATA.listData))).when(read)
176                 .read(LogicalDatastoreType.OPERATIONAL, DATA.path3);
177         doReturn(Futures.immediateCheckedFuture(Optional.of(DATA.listData2))).when(read)
178                 .read(LogicalDatastoreType.CONFIGURATION, DATA.path3);
179         doReturn(DATA.path3).when(context).getInstanceIdentifier();
180         final String valueOfContent = RestconfDataServiceConstant.ReadData.ALL;
181         final NormalizedNode<?, ?> normalizedNode =
182                 ReadDataTransactionUtil.readData(valueOfContent, wrapper, schemaContext);
183         final MapNode checkingData = Builders
184                 .mapBuilder()
185                 .withNodeIdentifier(new YangInstanceIdentifier.NodeIdentifier(QName.create("ns", "2016-02-28", "list")))
186                 .withChild(DATA.checkData)
187                 .build();
188         assertEquals(checkingData, normalizedNode);
189     }
190
191     @Test
192     public void readOrderedListDataAllTest() {
193         doReturn(Futures.immediateCheckedFuture(Optional.of(DATA.orderedMapNode1))).when(read)
194                 .read(LogicalDatastoreType.OPERATIONAL, DATA.path3);
195         doReturn(Futures.immediateCheckedFuture(Optional.of(DATA.orderedMapNode2))).when(read)
196                 .read(LogicalDatastoreType.CONFIGURATION, DATA.path3);
197         doReturn(DATA.path3).when(context).getInstanceIdentifier();
198
199         final NormalizedNode<?, ?> normalizedNode =
200                 ReadDataTransactionUtil.readData(RestconfDataServiceConstant.ReadData.ALL, wrapper, schemaContext);
201
202         final MapNode expectedData = Builders.orderedMapBuilder()
203                 .withNodeIdentifier(new YangInstanceIdentifier.NodeIdentifier(DATA.listQname)).withChild(DATA.checkData)
204                 .build();
205         assertEquals(expectedData, normalizedNode);
206     }
207
208     @Test
209     public void readUnkeyedListDataAllTest() {
210         doReturn(Futures.immediateCheckedFuture(Optional.of(DATA.unkeyedListNode1))).when(read)
211                 .read(LogicalDatastoreType.OPERATIONAL, DATA.path3);
212         doReturn(Futures.immediateCheckedFuture(Optional.of(DATA.unkeyedListNode2))).when(read)
213                 .read(LogicalDatastoreType.CONFIGURATION, DATA.path3);
214         doReturn(DATA.path3).when(context).getInstanceIdentifier();
215
216         final NormalizedNode<?, ?> normalizedNode =
217                 ReadDataTransactionUtil.readData(RestconfDataServiceConstant.ReadData.ALL, wrapper, schemaContext);
218
219         final UnkeyedListNode expectedData = Builders.unkeyedListBuilder()
220                 .withNodeIdentifier(new YangInstanceIdentifier.NodeIdentifier(DATA.listQname))
221                 .withChild(Builders.unkeyedListEntryBuilder().withNodeIdentifier(
222                         new YangInstanceIdentifier.NodeIdentifier(DATA.listQname))
223                         .withChild(DATA.unkeyedListEntryNode1.getValue().iterator().next())
224                         .withChild(DATA.unkeyedListEntryNode2.getValue().iterator().next()).build()).build();
225         assertEquals(expectedData, normalizedNode);
226     }
227
228     @Test
229     public void readLeafListDataAllTest() {
230         doReturn(Futures.immediateCheckedFuture(Optional.of(DATA.leafSetNode1))).when(read)
231                 .read(LogicalDatastoreType.OPERATIONAL, DATA.leafSetNodePath);
232         doReturn(Futures.immediateCheckedFuture(Optional.of(DATA.leafSetNode2))).when(read)
233                 .read(LogicalDatastoreType.CONFIGURATION, DATA.leafSetNodePath);
234         doReturn(DATA.leafSetNodePath).when(context).getInstanceIdentifier();
235
236         final NormalizedNode<?, ?> normalizedNode =
237                 ReadDataTransactionUtil.readData(RestconfDataServiceConstant.ReadData.ALL, wrapper, schemaContext);
238
239         final LeafSetNode<String> expectedData = Builders.<String>leafSetBuilder().withNodeIdentifier(
240                 new YangInstanceIdentifier.NodeIdentifier(DATA.leafListQname)).withValue(
241                         ImmutableList.<LeafSetEntryNode<String>>builder().addAll(DATA.leafSetNode1.getValue())
242                         .addAll(DATA.leafSetNode2.getValue()).build()).build();
243         assertEquals(expectedData, normalizedNode);
244     }
245
246     @Test
247     public void readOrderedLeafListDataAllTest() {
248         doReturn(Futures.immediateCheckedFuture(Optional.of(DATA.orderedLeafSetNode1))).when(read)
249                 .read(LogicalDatastoreType.OPERATIONAL, DATA.leafSetNodePath);
250         doReturn(Futures.immediateCheckedFuture(Optional.of(DATA.orderedLeafSetNode2))).when(read)
251                 .read(LogicalDatastoreType.CONFIGURATION, DATA.leafSetNodePath);
252         doReturn(DATA.leafSetNodePath).when(context).getInstanceIdentifier();
253
254         final NormalizedNode<?, ?> normalizedNode =
255                 ReadDataTransactionUtil.readData(RestconfDataServiceConstant.ReadData.ALL, wrapper, schemaContext);
256
257         final LeafSetNode<String> expectedData = Builders.<String>orderedLeafSetBuilder().withNodeIdentifier(
258                 new YangInstanceIdentifier.NodeIdentifier(DATA.leafListQname)).withValue(
259                         ImmutableList.<LeafSetEntryNode<String>>builder().addAll(DATA.orderedLeafSetNode1.getValue())
260                         .addAll(DATA.orderedLeafSetNode2.getValue()).build()).build();
261         assertEquals(expectedData, normalizedNode);
262     }
263
264     @Test
265     public void readDataWrongPathOrNoContentTest() {
266         doReturn(Futures.immediateCheckedFuture(Optional.absent())).when(read)
267                 .read(LogicalDatastoreType.CONFIGURATION, DATA.path2);
268         doReturn(DATA.path2).when(context).getInstanceIdentifier();
269         final String valueOfContent = RestconfDataServiceConstant.ReadData.CONFIG;
270         final NormalizedNode<?, ?> normalizedNode =
271                 ReadDataTransactionUtil.readData(valueOfContent, wrapper, schemaContext);
272         assertNull(normalizedNode);
273     }
274
275     @Test(expected = RestconfDocumentedException.class)
276     public void readDataFailTest() {
277         final String valueOfContent = RestconfDataServiceConstant.ReadData.READ_TYPE_TX;
278         final NormalizedNode<?, ?> normalizedNode = ReadDataTransactionUtil.readData(
279                 valueOfContent, wrapper, schemaContext);
280         assertNull(normalizedNode);
281     }
282
283     /**
284      * Test of parsing default parameters from URI request.
285      */
286     @Test
287     public void parseUriParametersDefaultTest() {
288         final UriInfo uriInfo = Mockito.mock(UriInfo.class);
289         final MultivaluedHashMap<String, String> parameters = new MultivaluedHashMap<>();
290
291         // no parameters, default values should be used
292         when(uriInfo.getQueryParameters()).thenReturn(parameters);
293
294         final WriterParameters parsedParameters = ReadDataTransactionUtil.parseUriParameters(context, uriInfo);
295
296         assertEquals("Not correctly parsed URI parameter",
297                 RestconfDataServiceConstant.ReadData.ALL, parsedParameters.getContent());
298         assertNull("Not correctly parsed URI parameter",
299                 parsedParameters.getDepth());
300         assertNull("Not correctly parsed URI parameter",
301                 parsedParameters.getFields());
302     }
303
304     /**
305      * Test of parsing user defined parameters from URI request.
306      */
307     @Test
308     public void parseUriParametersUserDefinedTest() {
309         final UriInfo uriInfo = Mockito.mock(UriInfo.class);
310         final MultivaluedHashMap<String, String> parameters = new MultivaluedHashMap<>();
311
312         final String content = "config";
313         final String depth = "10";
314         final String fields = containerChildQName.getLocalName();
315
316         parameters.put("content", Collections.singletonList(content));
317         parameters.put("depth", Collections.singletonList(depth));
318         parameters.put("fields", Collections.singletonList(fields));
319
320         when(uriInfo.getQueryParameters()).thenReturn(parameters);
321
322         final WriterParameters parsedParameters = ReadDataTransactionUtil.parseUriParameters(context, uriInfo);
323
324         // content
325         assertEquals("Not correctly parsed URI parameter",
326                 content, parsedParameters.getContent());
327
328         // depth
329         assertNotNull("Not correctly parsed URI parameter",
330                 parsedParameters.getDepth());
331         assertEquals("Not correctly parsed URI parameter",
332                 depth, parsedParameters.getDepth().toString());
333
334         // fields
335         assertNotNull("Not correctly parsed URI parameter",
336                 parsedParameters.getFields());
337         assertEquals("Not correctly parsed URI parameter",
338                 1, parsedParameters.getFields().size());
339         assertEquals("Not correctly parsed URI parameter",
340                 1, parsedParameters.getFields().get(0).size());
341         assertEquals("Not correctly parsed URI parameter",
342                 containerChildQName, parsedParameters.getFields().get(0).iterator().next());
343     }
344
345     /**
346      * Negative test of parsing request URI parameters when content parameter has not allowed value.
347      */
348     @Test
349     public void parseUriParametersContentParameterNegativeTest() {
350         final UriInfo uriInfo = Mockito.mock(UriInfo.class);
351         final MultivaluedHashMap<String, String> parameters = new MultivaluedHashMap<>();
352
353         parameters.put("content", Collections.singletonList("not-allowed-parameter-value"));
354         when(uriInfo.getQueryParameters()).thenReturn(parameters);
355
356         try {
357             ReadDataTransactionUtil.parseUriParameters(context, uriInfo);
358             fail("Test expected to fail due to not allowed parameter value");
359         } catch (final RestconfDocumentedException e) {
360             // Bad request
361             assertEquals("Error type is not correct", ErrorType.PROTOCOL, e.getErrors().get(0).getErrorType());
362             assertEquals("Error tag is not correct", ErrorTag.INVALID_VALUE, e.getErrors().get(0).getErrorTag());
363             assertEquals("Error status code is not correct", 400, e.getErrors().get(0).getErrorTag().getStatusCode());
364         }
365     }
366
367     /**
368      * Negative test of parsing request URI parameters when depth parameter has not allowed value.
369      */
370     @Test
371     public void parseUriParametersDepthParameterNegativeTest() {
372         final UriInfo uriInfo = Mockito.mock(UriInfo.class);
373         final MultivaluedHashMap<String, String> parameters = new MultivaluedHashMap<>();
374
375         // inserted value is not allowed
376         parameters.put("depth", Collections.singletonList("bounded"));
377         when(uriInfo.getQueryParameters()).thenReturn(parameters);
378
379         try {
380             ReadDataTransactionUtil.parseUriParameters(context, uriInfo);
381             fail("Test expected to fail due to not allowed parameter value");
382         } catch (final RestconfDocumentedException e) {
383             // Bad request
384             assertEquals("Error type is not correct", ErrorType.PROTOCOL, e.getErrors().get(0).getErrorType());
385             assertEquals("Error tag is not correct", ErrorTag.INVALID_VALUE, e.getErrors().get(0).getErrorTag());
386             assertEquals("Error status code is not correct", 400, e.getErrors().get(0).getErrorTag().getStatusCode());
387         }
388     }
389
390     /**
391      * Negative test of parsing request URI parameters when depth parameter has not allowed value (less than minimum).
392      */
393     @Test
394     public void parseUriParametersDepthMinimalParameterNegativeTest() {
395         final UriInfo uriInfo = Mockito.mock(UriInfo.class);
396         final MultivaluedHashMap<String, String> parameters = new MultivaluedHashMap<>();
397
398         // inserted value is too low
399         parameters.put(
400                 "depth", Collections.singletonList(String.valueOf(RestconfDataServiceConstant.ReadData.MIN_DEPTH - 1)));
401         when(uriInfo.getQueryParameters()).thenReturn(parameters);
402
403         try {
404             ReadDataTransactionUtil.parseUriParameters(context, uriInfo);
405             fail("Test expected to fail due to not allowed parameter value");
406         } catch (final RestconfDocumentedException e) {
407             // Bad request
408             assertEquals("Error type is not correct", ErrorType.PROTOCOL, e.getErrors().get(0).getErrorType());
409             assertEquals("Error tag is not correct", ErrorTag.INVALID_VALUE, e.getErrors().get(0).getErrorTag());
410             assertEquals("Error status code is not correct", 400, e.getErrors().get(0).getErrorTag().getStatusCode());
411         }
412     }
413
414     /**
415      * Negative test of parsing request URI parameters when depth parameter has not allowed value (more than maximum).
416      */
417     @Test
418     public void parseUriParametersDepthMaximalParameterNegativeTest() {
419         final UriInfo uriInfo = Mockito.mock(UriInfo.class);
420         final MultivaluedHashMap<String, String> parameters = new MultivaluedHashMap<>();
421
422         // inserted value is too high
423         parameters.put(
424                 "depth", Collections.singletonList(String.valueOf(RestconfDataServiceConstant.ReadData.MAX_DEPTH + 1)));
425         when(uriInfo.getQueryParameters()).thenReturn(parameters);
426
427         try {
428             ReadDataTransactionUtil.parseUriParameters(context, uriInfo);
429             fail("Test expected to fail due to not allowed parameter value");
430         } catch (final RestconfDocumentedException e) {
431             // Bad request
432             assertEquals("Error type is not correct", ErrorType.PROTOCOL, e.getErrors().get(0).getErrorType());
433             assertEquals("Error tag is not correct", ErrorTag.INVALID_VALUE, e.getErrors().get(0).getErrorTag());
434             assertEquals("Error status code is not correct", 400, e.getErrors().get(0).getErrorTag().getStatusCode());
435         }
436     }
437 }