2 * Copyright (c) 2016 Cisco Systems, Inc. and others. All rights reserved.
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
9 package org.opendaylight.restconf.nb.rfc8040.rests.utils;
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;
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;
51 public class ReadDataTransactionUtilTest {
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"));
57 private TransactionVarsWrapper wrapper;
59 private DOMTransactionChain transactionChain;
61 private InstanceIdentifierContext<ContainerSchemaNode> context;
63 private DOMDataReadOnlyTransaction read;
65 private SchemaContext schemaContext;
67 private ContainerSchemaNode containerSchemaNode;
69 private LeafSchemaNode containerChildNode;
70 private QName containerChildQName;
74 MockitoAnnotations.initMocks(this);
76 containerChildQName = QName.create("ns", "2016-02-28", "container-child");
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);
85 wrapper = new TransactionVarsWrapper(this.context, null, this.transactionChain);
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);
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);
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);
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);
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
148 .withNodeIdentifier(NODE_IDENTIFIER)
149 .withChild(DATA.contentLeaf)
150 .withChild(DATA.contentLeaf2)
152 assertEquals(checkingData, normalizedNode);
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
166 .withNodeIdentifier(NODE_IDENTIFIER)
167 .withChild(DATA.contentLeaf)
168 .withChild(DATA.contentLeaf2)
170 assertEquals(checkingData, normalizedNode);
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
185 .withNodeIdentifier(new YangInstanceIdentifier.NodeIdentifier(QName.create("ns", "2016-02-28", "list")))
186 .withChild(DATA.checkData)
188 assertEquals(checkingData, normalizedNode);
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();
199 final NormalizedNode<?, ?> normalizedNode =
200 ReadDataTransactionUtil.readData(RestconfDataServiceConstant.ReadData.ALL, wrapper, schemaContext);
202 final MapNode expectedData = Builders.orderedMapBuilder()
203 .withNodeIdentifier(new YangInstanceIdentifier.NodeIdentifier(DATA.listQname)).withChild(DATA.checkData)
205 assertEquals(expectedData, normalizedNode);
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();
216 final NormalizedNode<?, ?> normalizedNode =
217 ReadDataTransactionUtil.readData(RestconfDataServiceConstant.ReadData.ALL, wrapper, schemaContext);
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);
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();
236 final NormalizedNode<?, ?> normalizedNode =
237 ReadDataTransactionUtil.readData(RestconfDataServiceConstant.ReadData.ALL, wrapper, schemaContext);
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);
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();
254 final NormalizedNode<?, ?> normalizedNode =
255 ReadDataTransactionUtil.readData(RestconfDataServiceConstant.ReadData.ALL, wrapper, schemaContext);
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);
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);
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);
284 * Test of parsing default parameters from URI request.
287 public void parseUriParametersDefaultTest() {
288 final UriInfo uriInfo = Mockito.mock(UriInfo.class);
289 final MultivaluedHashMap<String, String> parameters = new MultivaluedHashMap<>();
291 // no parameters, default values should be used
292 when(uriInfo.getQueryParameters()).thenReturn(parameters);
294 final WriterParameters parsedParameters = ReadDataTransactionUtil.parseUriParameters(context, uriInfo);
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());
305 * Test of parsing user defined parameters from URI request.
308 public void parseUriParametersUserDefinedTest() {
309 final UriInfo uriInfo = Mockito.mock(UriInfo.class);
310 final MultivaluedHashMap<String, String> parameters = new MultivaluedHashMap<>();
312 final String content = "config";
313 final String depth = "10";
314 final String fields = containerChildQName.getLocalName();
316 parameters.put("content", Collections.singletonList(content));
317 parameters.put("depth", Collections.singletonList(depth));
318 parameters.put("fields", Collections.singletonList(fields));
320 when(uriInfo.getQueryParameters()).thenReturn(parameters);
322 final WriterParameters parsedParameters = ReadDataTransactionUtil.parseUriParameters(context, uriInfo);
325 assertEquals("Not correctly parsed URI parameter",
326 content, parsedParameters.getContent());
329 assertNotNull("Not correctly parsed URI parameter",
330 parsedParameters.getDepth());
331 assertEquals("Not correctly parsed URI parameter",
332 depth, parsedParameters.getDepth().toString());
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());
346 * Negative test of parsing request URI parameters when content parameter has not allowed value.
349 public void parseUriParametersContentParameterNegativeTest() {
350 final UriInfo uriInfo = Mockito.mock(UriInfo.class);
351 final MultivaluedHashMap<String, String> parameters = new MultivaluedHashMap<>();
353 parameters.put("content", Collections.singletonList("not-allowed-parameter-value"));
354 when(uriInfo.getQueryParameters()).thenReturn(parameters);
357 ReadDataTransactionUtil.parseUriParameters(context, uriInfo);
358 fail("Test expected to fail due to not allowed parameter value");
359 } catch (final RestconfDocumentedException e) {
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());
368 * Negative test of parsing request URI parameters when depth parameter has not allowed value.
371 public void parseUriParametersDepthParameterNegativeTest() {
372 final UriInfo uriInfo = Mockito.mock(UriInfo.class);
373 final MultivaluedHashMap<String, String> parameters = new MultivaluedHashMap<>();
375 // inserted value is not allowed
376 parameters.put("depth", Collections.singletonList("bounded"));
377 when(uriInfo.getQueryParameters()).thenReturn(parameters);
380 ReadDataTransactionUtil.parseUriParameters(context, uriInfo);
381 fail("Test expected to fail due to not allowed parameter value");
382 } catch (final RestconfDocumentedException e) {
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());
391 * Negative test of parsing request URI parameters when depth parameter has not allowed value (less than minimum).
394 public void parseUriParametersDepthMinimalParameterNegativeTest() {
395 final UriInfo uriInfo = Mockito.mock(UriInfo.class);
396 final MultivaluedHashMap<String, String> parameters = new MultivaluedHashMap<>();
398 // inserted value is too low
400 "depth", Collections.singletonList(String.valueOf(RestconfDataServiceConstant.ReadData.MIN_DEPTH - 1)));
401 when(uriInfo.getQueryParameters()).thenReturn(parameters);
404 ReadDataTransactionUtil.parseUriParameters(context, uriInfo);
405 fail("Test expected to fail due to not allowed parameter value");
406 } catch (final RestconfDocumentedException e) {
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());
415 * Negative test of parsing request URI parameters when depth parameter has not allowed value (more than maximum).
418 public void parseUriParametersDepthMaximalParameterNegativeTest() {
419 final UriInfo uriInfo = Mockito.mock(UriInfo.class);
420 final MultivaluedHashMap<String, String> parameters = new MultivaluedHashMap<>();
422 // inserted value is too high
424 "depth", Collections.singletonList(String.valueOf(RestconfDataServiceConstant.ReadData.MAX_DEPTH + 1)));
425 when(uriInfo.getQueryParameters()).thenReturn(parameters);
428 ReadDataTransactionUtil.parseUriParameters(context, uriInfo);
429 fail("Test expected to fail due to not allowed parameter value");
430 } catch (final RestconfDocumentedException e) {
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());