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
8 package org.opendaylight.restconf.nb.rfc8040.rests.utils;
10 import static org.junit.Assert.assertEquals;
11 import static org.junit.Assert.assertNotNull;
12 import static org.junit.Assert.assertNull;
13 import static org.junit.Assert.fail;
14 import static org.mockito.Mockito.doReturn;
15 import static org.mockito.Mockito.when;
16 import static org.opendaylight.yangtools.util.concurrent.FluentFutures.immediateFluentFuture;
18 import com.google.common.collect.ImmutableList;
19 import java.util.Collections;
20 import java.util.Optional;
21 import javax.ws.rs.core.MultivaluedHashMap;
22 import javax.ws.rs.core.UriInfo;
23 import org.junit.Before;
24 import org.junit.Test;
25 import org.mockito.Mock;
26 import org.mockito.Mockito;
27 import org.mockito.MockitoAnnotations;
28 import org.opendaylight.mdsal.common.api.LogicalDatastoreType;
29 import org.opendaylight.mdsal.dom.api.DOMDataBroker;
30 import org.opendaylight.mdsal.dom.api.DOMDataTreeReadTransaction;
31 import org.opendaylight.mdsal.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.handlers.TransactionChainHandler;
38 import org.opendaylight.restconf.nb.rfc8040.rests.transactions.TransactionVarsWrapper;
39 import org.opendaylight.yangtools.yang.common.QName;
40 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
41 import org.opendaylight.yangtools.yang.data.api.schema.ContainerNode;
42 import org.opendaylight.yangtools.yang.data.api.schema.LeafSetEntryNode;
43 import org.opendaylight.yangtools.yang.data.api.schema.LeafSetNode;
44 import org.opendaylight.yangtools.yang.data.api.schema.MapNode;
45 import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
46 import org.opendaylight.yangtools.yang.data.api.schema.UnkeyedListNode;
47 import org.opendaylight.yangtools.yang.data.impl.schema.Builders;
48 import org.opendaylight.yangtools.yang.model.api.ContainerSchemaNode;
49 import org.opendaylight.yangtools.yang.model.api.LeafSchemaNode;
50 import org.opendaylight.yangtools.yang.model.api.SchemaContext;
52 public class ReadDataTransactionUtilTest {
54 private static final TestData DATA = new TestData();
55 private static final YangInstanceIdentifier.NodeIdentifier NODE_IDENTIFIER = new YangInstanceIdentifier
56 .NodeIdentifier(QName.create("ns", "2016-02-28", "container"));
58 private TransactionVarsWrapper wrapper;
60 private DOMTransactionChain transactionChain;
62 private InstanceIdentifierContext<ContainerSchemaNode> context;
64 private DOMDataTreeReadTransaction read;
66 private SchemaContext schemaContext;
68 private ContainerSchemaNode containerSchemaNode;
70 private LeafSchemaNode containerChildNode;
71 private QName containerChildQName;
75 MockitoAnnotations.initMocks(this);
77 containerChildQName = QName.create("ns", "2016-02-28", "container-child");
79 when(transactionChain.newReadOnlyTransaction()).thenReturn(read);
80 when(context.getSchemaContext()).thenReturn(schemaContext);
81 when(context.getSchemaNode()).thenReturn(containerSchemaNode);
82 when(containerSchemaNode.getQName()).thenReturn(NODE_IDENTIFIER.getNodeType());
83 when(containerChildNode.getQName()).thenReturn(containerChildQName);
84 when(containerSchemaNode.getDataChildByName(containerChildQName)).thenReturn(containerChildNode);
86 DOMDataBroker mockDataBroker = Mockito.mock(DOMDataBroker.class);
87 Mockito.doReturn(transactionChain).when(mockDataBroker).createTransactionChain(Mockito.any());
88 wrapper = new TransactionVarsWrapper(this.context, null, new TransactionChainHandler(mockDataBroker));
92 public void readDataConfigTest() {
93 doReturn(immediateFluentFuture(Optional.of(DATA.data3))).when(read)
94 .read(LogicalDatastoreType.CONFIGURATION, DATA.path);
95 doReturn(DATA.path).when(context).getInstanceIdentifier();
96 final String valueOfContent = RestconfDataServiceConstant.ReadData.CONFIG;
97 final NormalizedNode<?, ?> normalizedNode =
98 ReadDataTransactionUtil.readData(valueOfContent, wrapper, schemaContext);
99 assertEquals(DATA.data3, normalizedNode);
103 public void readAllHavingOnlyConfigTest() {
104 doReturn(immediateFluentFuture(Optional.of(DATA.data3))).when(read)
105 .read(LogicalDatastoreType.CONFIGURATION, DATA.path);
106 doReturn(immediateFluentFuture(Optional.empty())).when(read)
107 .read(LogicalDatastoreType.OPERATIONAL, DATA.path);
108 doReturn(DATA.path).when(context).getInstanceIdentifier();
109 final String valueOfContent = RestconfDataServiceConstant.ReadData.ALL;
110 final NormalizedNode<?, ?> normalizedNode =
111 ReadDataTransactionUtil.readData(valueOfContent, wrapper, schemaContext);
112 assertEquals(DATA.data3, normalizedNode);
116 public void readAllHavingOnlyNonConfigTest() {
117 doReturn(immediateFluentFuture(Optional.of(DATA.data2))).when(read)
118 .read(LogicalDatastoreType.OPERATIONAL, DATA.path2);
119 doReturn(immediateFluentFuture(Optional.empty())).when(read)
120 .read(LogicalDatastoreType.CONFIGURATION, DATA.path2);
121 doReturn(DATA.path2).when(context).getInstanceIdentifier();
122 final String valueOfContent = RestconfDataServiceConstant.ReadData.ALL;
123 final NormalizedNode<?, ?> normalizedNode =
124 ReadDataTransactionUtil.readData(valueOfContent, wrapper, schemaContext);
125 assertEquals(DATA.data2, normalizedNode);
129 public void readDataNonConfigTest() {
130 doReturn(immediateFluentFuture(Optional.of(DATA.data2))).when(read)
131 .read(LogicalDatastoreType.OPERATIONAL, DATA.path2);
132 doReturn(DATA.path2).when(context).getInstanceIdentifier();
133 final String valueOfContent = RestconfDataServiceConstant.ReadData.NONCONFIG;
134 final NormalizedNode<?, ?> normalizedNode =
135 ReadDataTransactionUtil.readData(valueOfContent, wrapper, schemaContext);
136 assertEquals(DATA.data2, normalizedNode);
140 public void readContainerDataAllTest() {
141 doReturn(immediateFluentFuture(Optional.of(DATA.data3))).when(read)
142 .read(LogicalDatastoreType.CONFIGURATION, DATA.path);
143 doReturn(immediateFluentFuture(Optional.of(DATA.data4))).when(read)
144 .read(LogicalDatastoreType.OPERATIONAL, DATA.path);
145 doReturn(DATA.path).when(context).getInstanceIdentifier();
146 final String valueOfContent = RestconfDataServiceConstant.ReadData.ALL;
147 final NormalizedNode<?, ?> normalizedNode =
148 ReadDataTransactionUtil.readData(valueOfContent, wrapper, schemaContext);
149 final ContainerNode checkingData = Builders
151 .withNodeIdentifier(NODE_IDENTIFIER)
152 .withChild(DATA.contentLeaf)
153 .withChild(DATA.contentLeaf2)
155 assertEquals(checkingData, normalizedNode);
159 public void readContainerDataConfigNoValueOfContentTest() {
160 doReturn(immediateFluentFuture(Optional.of(DATA.data3))).when(read)
161 .read(LogicalDatastoreType.CONFIGURATION, DATA.path);
162 doReturn(immediateFluentFuture(Optional.of(DATA.data4))).when(read)
163 .read(LogicalDatastoreType.OPERATIONAL, DATA.path);
164 doReturn(DATA.path).when(context).getInstanceIdentifier();
165 final NormalizedNode<?, ?> normalizedNode = ReadDataTransactionUtil.readData(
166 RestconfDataServiceConstant.ReadData.ALL, wrapper, schemaContext);
167 final ContainerNode checkingData = Builders
169 .withNodeIdentifier(NODE_IDENTIFIER)
170 .withChild(DATA.contentLeaf)
171 .withChild(DATA.contentLeaf2)
173 assertEquals(checkingData, normalizedNode);
177 public void readListDataAllTest() {
178 doReturn(immediateFluentFuture(Optional.of(DATA.listData))).when(read)
179 .read(LogicalDatastoreType.OPERATIONAL, DATA.path3);
180 doReturn(immediateFluentFuture(Optional.of(DATA.listData2))).when(read)
181 .read(LogicalDatastoreType.CONFIGURATION, DATA.path3);
182 doReturn(DATA.path3).when(context).getInstanceIdentifier();
183 final String valueOfContent = RestconfDataServiceConstant.ReadData.ALL;
184 final NormalizedNode<?, ?> normalizedNode =
185 ReadDataTransactionUtil.readData(valueOfContent, wrapper, schemaContext);
186 final MapNode checkingData = Builders
188 .withNodeIdentifier(new YangInstanceIdentifier.NodeIdentifier(QName.create("ns", "2016-02-28", "list")))
189 .withChild(DATA.checkData)
191 assertEquals(checkingData, normalizedNode);
195 public void readOrderedListDataAllTest() {
196 doReturn(immediateFluentFuture(Optional.of(DATA.orderedMapNode1))).when(read)
197 .read(LogicalDatastoreType.OPERATIONAL, DATA.path3);
198 doReturn(immediateFluentFuture(Optional.of(DATA.orderedMapNode2))).when(read)
199 .read(LogicalDatastoreType.CONFIGURATION, DATA.path3);
200 doReturn(DATA.path3).when(context).getInstanceIdentifier();
202 final NormalizedNode<?, ?> normalizedNode =
203 ReadDataTransactionUtil.readData(RestconfDataServiceConstant.ReadData.ALL, wrapper, schemaContext);
205 final MapNode expectedData = Builders.orderedMapBuilder()
206 .withNodeIdentifier(new YangInstanceIdentifier.NodeIdentifier(DATA.listQname)).withChild(DATA.checkData)
208 assertEquals(expectedData, normalizedNode);
212 public void readUnkeyedListDataAllTest() {
213 doReturn(immediateFluentFuture(Optional.of(DATA.unkeyedListNode1))).when(read)
214 .read(LogicalDatastoreType.OPERATIONAL, DATA.path3);
215 doReturn(immediateFluentFuture(Optional.of(DATA.unkeyedListNode2))).when(read)
216 .read(LogicalDatastoreType.CONFIGURATION, DATA.path3);
217 doReturn(DATA.path3).when(context).getInstanceIdentifier();
219 final NormalizedNode<?, ?> normalizedNode =
220 ReadDataTransactionUtil.readData(RestconfDataServiceConstant.ReadData.ALL, wrapper, schemaContext);
222 final UnkeyedListNode expectedData = Builders.unkeyedListBuilder()
223 .withNodeIdentifier(new YangInstanceIdentifier.NodeIdentifier(DATA.listQname))
224 .withChild(Builders.unkeyedListEntryBuilder().withNodeIdentifier(
225 new YangInstanceIdentifier.NodeIdentifier(DATA.listQname))
226 .withChild(DATA.unkeyedListEntryNode1.getValue().iterator().next())
227 .withChild(DATA.unkeyedListEntryNode2.getValue().iterator().next()).build()).build();
228 assertEquals(expectedData, normalizedNode);
232 public void readLeafListDataAllTest() {
233 doReturn(immediateFluentFuture(Optional.of(DATA.leafSetNode1))).when(read)
234 .read(LogicalDatastoreType.OPERATIONAL, DATA.leafSetNodePath);
235 doReturn(immediateFluentFuture(Optional.of(DATA.leafSetNode2))).when(read)
236 .read(LogicalDatastoreType.CONFIGURATION, DATA.leafSetNodePath);
237 doReturn(DATA.leafSetNodePath).when(context).getInstanceIdentifier();
239 final NormalizedNode<?, ?> normalizedNode =
240 ReadDataTransactionUtil.readData(RestconfDataServiceConstant.ReadData.ALL, wrapper, schemaContext);
242 final LeafSetNode<String> expectedData = Builders.<String>leafSetBuilder().withNodeIdentifier(
243 new YangInstanceIdentifier.NodeIdentifier(DATA.leafListQname)).withValue(
244 ImmutableList.<LeafSetEntryNode<String>>builder().addAll(DATA.leafSetNode1.getValue())
245 .addAll(DATA.leafSetNode2.getValue()).build()).build();
246 assertEquals(expectedData, normalizedNode);
250 public void readOrderedLeafListDataAllTest() {
251 doReturn(immediateFluentFuture(Optional.of(DATA.orderedLeafSetNode1))).when(read)
252 .read(LogicalDatastoreType.OPERATIONAL, DATA.leafSetNodePath);
253 doReturn(immediateFluentFuture(Optional.of(DATA.orderedLeafSetNode2))).when(read)
254 .read(LogicalDatastoreType.CONFIGURATION, DATA.leafSetNodePath);
255 doReturn(DATA.leafSetNodePath).when(context).getInstanceIdentifier();
257 final NormalizedNode<?, ?> normalizedNode =
258 ReadDataTransactionUtil.readData(RestconfDataServiceConstant.ReadData.ALL, wrapper, schemaContext);
260 final LeafSetNode<String> expectedData = Builders.<String>orderedLeafSetBuilder().withNodeIdentifier(
261 new YangInstanceIdentifier.NodeIdentifier(DATA.leafListQname)).withValue(
262 ImmutableList.<LeafSetEntryNode<String>>builder().addAll(DATA.orderedLeafSetNode1.getValue())
263 .addAll(DATA.orderedLeafSetNode2.getValue()).build()).build();
264 assertEquals(expectedData, normalizedNode);
268 public void readDataWrongPathOrNoContentTest() {
269 doReturn(immediateFluentFuture(Optional.empty())).when(read)
270 .read(LogicalDatastoreType.CONFIGURATION, DATA.path2);
271 doReturn(DATA.path2).when(context).getInstanceIdentifier();
272 final String valueOfContent = RestconfDataServiceConstant.ReadData.CONFIG;
273 final NormalizedNode<?, ?> normalizedNode =
274 ReadDataTransactionUtil.readData(valueOfContent, wrapper, schemaContext);
275 assertNull(normalizedNode);
278 @Test(expected = RestconfDocumentedException.class)
279 public void readDataFailTest() {
280 final String valueOfContent = RestconfDataServiceConstant.ReadData.READ_TYPE_TX;
281 final NormalizedNode<?, ?> normalizedNode = ReadDataTransactionUtil.readData(
282 valueOfContent, wrapper, schemaContext);
283 assertNull(normalizedNode);
287 * Test of parsing default parameters from URI request.
290 public void parseUriParametersDefaultTest() {
291 final UriInfo uriInfo = Mockito.mock(UriInfo.class);
292 final MultivaluedHashMap<String, String> parameters = new MultivaluedHashMap<>();
294 // no parameters, default values should be used
295 when(uriInfo.getQueryParameters()).thenReturn(parameters);
297 final WriterParameters parsedParameters = ReadDataTransactionUtil.parseUriParameters(context, uriInfo);
299 assertEquals("Not correctly parsed URI parameter",
300 RestconfDataServiceConstant.ReadData.ALL, parsedParameters.getContent());
301 assertNull("Not correctly parsed URI parameter",
302 parsedParameters.getDepth());
303 assertNull("Not correctly parsed URI parameter",
304 parsedParameters.getFields());
308 * Test of parsing user defined parameters from URI request.
311 public void parseUriParametersUserDefinedTest() {
312 final UriInfo uriInfo = Mockito.mock(UriInfo.class);
313 final MultivaluedHashMap<String, String> parameters = new MultivaluedHashMap<>();
315 final String content = "config";
316 final String depth = "10";
317 final String fields = containerChildQName.getLocalName();
319 parameters.put("content", Collections.singletonList(content));
320 parameters.put("depth", Collections.singletonList(depth));
321 parameters.put("fields", Collections.singletonList(fields));
323 when(uriInfo.getQueryParameters()).thenReturn(parameters);
325 final WriterParameters parsedParameters = ReadDataTransactionUtil.parseUriParameters(context, uriInfo);
328 assertEquals("Not correctly parsed URI parameter",
329 content, parsedParameters.getContent());
332 assertNotNull("Not correctly parsed URI parameter",
333 parsedParameters.getDepth());
334 assertEquals("Not correctly parsed URI parameter",
335 depth, parsedParameters.getDepth().toString());
338 assertNotNull("Not correctly parsed URI parameter",
339 parsedParameters.getFields());
340 assertEquals("Not correctly parsed URI parameter",
341 1, parsedParameters.getFields().size());
342 assertEquals("Not correctly parsed URI parameter",
343 1, parsedParameters.getFields().get(0).size());
344 assertEquals("Not correctly parsed URI parameter",
345 containerChildQName, parsedParameters.getFields().get(0).iterator().next());
349 * Negative test of parsing request URI parameters when content parameter has not allowed value.
352 public void parseUriParametersContentParameterNegativeTest() {
353 final UriInfo uriInfo = Mockito.mock(UriInfo.class);
354 final MultivaluedHashMap<String, String> parameters = new MultivaluedHashMap<>();
356 parameters.put("content", Collections.singletonList("not-allowed-parameter-value"));
357 when(uriInfo.getQueryParameters()).thenReturn(parameters);
360 ReadDataTransactionUtil.parseUriParameters(context, uriInfo);
361 fail("Test expected to fail due to not allowed parameter value");
362 } catch (final RestconfDocumentedException e) {
364 assertEquals("Error type is not correct", ErrorType.PROTOCOL, e.getErrors().get(0).getErrorType());
365 assertEquals("Error tag is not correct", ErrorTag.INVALID_VALUE, e.getErrors().get(0).getErrorTag());
366 assertEquals("Error status code is not correct", 400, e.getErrors().get(0).getErrorTag().getStatusCode());
371 * Negative test of parsing request URI parameters when depth parameter has not allowed value.
374 public void parseUriParametersDepthParameterNegativeTest() {
375 final UriInfo uriInfo = Mockito.mock(UriInfo.class);
376 final MultivaluedHashMap<String, String> parameters = new MultivaluedHashMap<>();
378 // inserted value is not allowed
379 parameters.put("depth", Collections.singletonList("bounded"));
380 when(uriInfo.getQueryParameters()).thenReturn(parameters);
383 ReadDataTransactionUtil.parseUriParameters(context, uriInfo);
384 fail("Test expected to fail due to not allowed parameter value");
385 } catch (final RestconfDocumentedException e) {
387 assertEquals("Error type is not correct", ErrorType.PROTOCOL, e.getErrors().get(0).getErrorType());
388 assertEquals("Error tag is not correct", ErrorTag.INVALID_VALUE, e.getErrors().get(0).getErrorTag());
389 assertEquals("Error status code is not correct", 400, e.getErrors().get(0).getErrorTag().getStatusCode());
394 * Negative test of parsing request URI parameters when depth parameter has not allowed value (less than minimum).
397 public void parseUriParametersDepthMinimalParameterNegativeTest() {
398 final UriInfo uriInfo = Mockito.mock(UriInfo.class);
399 final MultivaluedHashMap<String, String> parameters = new MultivaluedHashMap<>();
401 // inserted value is too low
403 "depth", Collections.singletonList(String.valueOf(RestconfDataServiceConstant.ReadData.MIN_DEPTH - 1)));
404 when(uriInfo.getQueryParameters()).thenReturn(parameters);
407 ReadDataTransactionUtil.parseUriParameters(context, uriInfo);
408 fail("Test expected to fail due to not allowed parameter value");
409 } catch (final RestconfDocumentedException e) {
411 assertEquals("Error type is not correct", ErrorType.PROTOCOL, e.getErrors().get(0).getErrorType());
412 assertEquals("Error tag is not correct", ErrorTag.INVALID_VALUE, e.getErrors().get(0).getErrorTag());
413 assertEquals("Error status code is not correct", 400, e.getErrors().get(0).getErrorTag().getStatusCode());
418 * Negative test of parsing request URI parameters when depth parameter has not allowed value (more than maximum).
421 public void parseUriParametersDepthMaximalParameterNegativeTest() {
422 final UriInfo uriInfo = Mockito.mock(UriInfo.class);
423 final MultivaluedHashMap<String, String> parameters = new MultivaluedHashMap<>();
425 // inserted value is too high
427 "depth", Collections.singletonList(String.valueOf(RestconfDataServiceConstant.ReadData.MAX_DEPTH + 1)));
428 when(uriInfo.getQueryParameters()).thenReturn(parameters);
431 ReadDataTransactionUtil.parseUriParameters(context, uriInfo);
432 fail("Test expected to fail due to not allowed parameter value");
433 } catch (final RestconfDocumentedException e) {
435 assertEquals("Error type is not correct", ErrorType.PROTOCOL, e.getErrors().get(0).getErrorType());
436 assertEquals("Error tag is not correct", ErrorTag.INVALID_VALUE, e.getErrors().get(0).getErrorTag());
437 assertEquals("Error status code is not correct", 400, e.getErrors().get(0).getErrorTag().getStatusCode());