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