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.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;
53 public class ReadDataTransactionUtilTest {
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"));
59 private TransactionVarsWrapper wrapper;
61 private DOMTransactionChain transactionChain;
63 private InstanceIdentifierContext<ContainerSchemaNode> context;
65 private DOMDataReadOnlyTransaction read;
67 private SchemaContext schemaContext;
69 private ContainerSchemaNode containerSchemaNode;
71 private LeafSchemaNode containerChildNode;
72 private QName containerChildQName;
76 MockitoAnnotations.initMocks(this);
78 containerChildQName = QName.create("ns", "2016-02-28", "container-child");
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);
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));
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);
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);
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);
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);
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
152 .withNodeIdentifier(NODE_IDENTIFIER)
153 .withChild(DATA.contentLeaf)
154 .withChild(DATA.contentLeaf2)
156 assertEquals(checkingData, normalizedNode);
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
170 .withNodeIdentifier(NODE_IDENTIFIER)
171 .withChild(DATA.contentLeaf)
172 .withChild(DATA.contentLeaf2)
174 assertEquals(checkingData, normalizedNode);
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
189 .withNodeIdentifier(new YangInstanceIdentifier.NodeIdentifier(QName.create("ns", "2016-02-28", "list")))
190 .withChild(DATA.checkData)
192 assertEquals(checkingData, normalizedNode);
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();
203 final NormalizedNode<?, ?> normalizedNode =
204 ReadDataTransactionUtil.readData(RestconfDataServiceConstant.ReadData.ALL, wrapper, schemaContext);
206 final MapNode expectedData = Builders.orderedMapBuilder()
207 .withNodeIdentifier(new YangInstanceIdentifier.NodeIdentifier(DATA.listQname)).withChild(DATA.checkData)
209 assertEquals(expectedData, normalizedNode);
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();
220 final NormalizedNode<?, ?> normalizedNode =
221 ReadDataTransactionUtil.readData(RestconfDataServiceConstant.ReadData.ALL, wrapper, schemaContext);
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);
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();
240 final NormalizedNode<?, ?> normalizedNode =
241 ReadDataTransactionUtil.readData(RestconfDataServiceConstant.ReadData.ALL, wrapper, schemaContext);
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);
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();
258 final NormalizedNode<?, ?> normalizedNode =
259 ReadDataTransactionUtil.readData(RestconfDataServiceConstant.ReadData.ALL, wrapper, schemaContext);
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);
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);
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);
288 * Test of parsing default parameters from URI request.
291 public void parseUriParametersDefaultTest() {
292 final UriInfo uriInfo = Mockito.mock(UriInfo.class);
293 final MultivaluedHashMap<String, String> parameters = new MultivaluedHashMap<>();
295 // no parameters, default values should be used
296 when(uriInfo.getQueryParameters()).thenReturn(parameters);
298 final WriterParameters parsedParameters = ReadDataTransactionUtil.parseUriParameters(context, uriInfo);
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());
309 * Test of parsing user defined parameters from URI request.
312 public void parseUriParametersUserDefinedTest() {
313 final UriInfo uriInfo = Mockito.mock(UriInfo.class);
314 final MultivaluedHashMap<String, String> parameters = new MultivaluedHashMap<>();
316 final String content = "config";
317 final String depth = "10";
318 final String fields = containerChildQName.getLocalName();
320 parameters.put("content", Collections.singletonList(content));
321 parameters.put("depth", Collections.singletonList(depth));
322 parameters.put("fields", Collections.singletonList(fields));
324 when(uriInfo.getQueryParameters()).thenReturn(parameters);
326 final WriterParameters parsedParameters = ReadDataTransactionUtil.parseUriParameters(context, uriInfo);
329 assertEquals("Not correctly parsed URI parameter",
330 content, parsedParameters.getContent());
333 assertNotNull("Not correctly parsed URI parameter",
334 parsedParameters.getDepth());
335 assertEquals("Not correctly parsed URI parameter",
336 depth, parsedParameters.getDepth().toString());
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());
350 * Negative test of parsing request URI parameters when content parameter has not allowed value.
353 public void parseUriParametersContentParameterNegativeTest() {
354 final UriInfo uriInfo = Mockito.mock(UriInfo.class);
355 final MultivaluedHashMap<String, String> parameters = new MultivaluedHashMap<>();
357 parameters.put("content", Collections.singletonList("not-allowed-parameter-value"));
358 when(uriInfo.getQueryParameters()).thenReturn(parameters);
361 ReadDataTransactionUtil.parseUriParameters(context, uriInfo);
362 fail("Test expected to fail due to not allowed parameter value");
363 } catch (final RestconfDocumentedException e) {
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());
372 * Negative test of parsing request URI parameters when depth parameter has not allowed value.
375 public void parseUriParametersDepthParameterNegativeTest() {
376 final UriInfo uriInfo = Mockito.mock(UriInfo.class);
377 final MultivaluedHashMap<String, String> parameters = new MultivaluedHashMap<>();
379 // inserted value is not allowed
380 parameters.put("depth", Collections.singletonList("bounded"));
381 when(uriInfo.getQueryParameters()).thenReturn(parameters);
384 ReadDataTransactionUtil.parseUriParameters(context, uriInfo);
385 fail("Test expected to fail due to not allowed parameter value");
386 } catch (final RestconfDocumentedException e) {
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());
395 * Negative test of parsing request URI parameters when depth parameter has not allowed value (less than minimum).
398 public void parseUriParametersDepthMinimalParameterNegativeTest() {
399 final UriInfo uriInfo = Mockito.mock(UriInfo.class);
400 final MultivaluedHashMap<String, String> parameters = new MultivaluedHashMap<>();
402 // inserted value is too low
404 "depth", Collections.singletonList(String.valueOf(RestconfDataServiceConstant.ReadData.MIN_DEPTH - 1)));
405 when(uriInfo.getQueryParameters()).thenReturn(parameters);
408 ReadDataTransactionUtil.parseUriParameters(context, uriInfo);
409 fail("Test expected to fail due to not allowed parameter value");
410 } catch (final RestconfDocumentedException e) {
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());
419 * Negative test of parsing request URI parameters when depth parameter has not allowed value (more than maximum).
422 public void parseUriParametersDepthMaximalParameterNegativeTest() {
423 final UriInfo uriInfo = Mockito.mock(UriInfo.class);
424 final MultivaluedHashMap<String, String> parameters = new MultivaluedHashMap<>();
426 // inserted value is too high
428 "depth", Collections.singletonList(String.valueOf(RestconfDataServiceConstant.ReadData.MAX_DEPTH + 1)));
429 when(uriInfo.getQueryParameters()).thenReturn(parameters);
432 ReadDataTransactionUtil.parseUriParameters(context, uriInfo);
433 fail("Test expected to fail due to not allowed parameter value");
434 } catch (final RestconfDocumentedException e) {
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());