2 * Copyright (c) 2014 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.controller.sal.restconf.impl.test;
10 import static org.junit.Assert.assertNotNull;
11 import static org.junit.Assert.assertEquals;
12 import static org.junit.Assert.assertTrue;
13 import static org.junit.Assert.fail;
14 import static org.mockito.Matchers.any;
15 import static org.mockito.Matchers.eq;
16 import static org.mockito.Mockito.mock;
17 import static org.mockito.Mockito.when;
19 import java.io.FileNotFoundException;
20 import java.io.InputStream;
21 import java.io.UnsupportedEncodingException;
23 import java.net.URISyntaxException;
24 import java.text.ParseException;
25 import java.text.SimpleDateFormat;
26 import java.util.ArrayList;
27 import java.util.Date;
28 import java.util.List;
30 import java.util.regex.Matcher;
31 import java.util.regex.Pattern;
33 import javax.ws.rs.core.Application;
34 import javax.ws.rs.core.MediaType;
35 import javax.ws.rs.core.MultivaluedHashMap;
36 import javax.ws.rs.core.MultivaluedMap;
37 import javax.ws.rs.core.Response;
38 import javax.ws.rs.core.UriInfo;
40 import org.glassfish.jersey.server.ResourceConfig;
41 import org.glassfish.jersey.test.JerseyTest;
42 import org.junit.BeforeClass;
43 import org.junit.Test;
44 import org.mockito.invocation.InvocationOnMock;
45 import org.mockito.stubbing.Answer;
46 import org.opendaylight.controller.sal.core.api.mount.MountInstance;
47 import org.opendaylight.controller.sal.core.api.mount.MountService;
48 import org.opendaylight.controller.sal.rest.impl.JsonToCompositeNodeProvider;
49 import org.opendaylight.controller.sal.rest.impl.RestconfDocumentedExceptionMapper;
50 import org.opendaylight.controller.sal.rest.impl.StructuredDataToJsonProvider;
51 import org.opendaylight.controller.sal.rest.impl.StructuredDataToXmlProvider;
52 import org.opendaylight.controller.sal.rest.impl.XmlToCompositeNodeProvider;
53 import org.opendaylight.controller.sal.restconf.impl.BrokerFacade;
54 import org.opendaylight.controller.sal.restconf.impl.CompositeNodeWrapper;
55 import org.opendaylight.controller.sal.restconf.impl.ControllerContext;
56 import org.opendaylight.controller.sal.restconf.impl.RestconfDocumentedException;
57 import org.opendaylight.controller.sal.restconf.impl.RestconfImpl;
58 import org.opendaylight.controller.sal.restconf.impl.SimpleNodeWrapper;
59 import org.opendaylight.yangtools.yang.common.QName;
60 import org.opendaylight.yangtools.yang.data.api.CompositeNode;
61 import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier;
62 import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier.PathArgument;
63 import org.opendaylight.yangtools.yang.data.api.Node;
64 import org.opendaylight.yangtools.yang.data.impl.ImmutableCompositeNode;
65 import org.opendaylight.yangtools.yang.data.impl.util.CompositeNodeBuilder;
66 import org.opendaylight.yangtools.yang.model.api.SchemaContext;
67 import org.w3c.dom.Document;
68 import org.w3c.dom.Element;
69 import org.w3c.dom.NodeList;
71 import com.google.common.collect.Lists;
72 import com.google.common.collect.Maps;
74 public class RestGetOperationTest extends JerseyTest {
76 static class NodeData {
78 Object data; // List for a CompositeNode, value Object for a SimpleNode
80 NodeData( Object key, Object data ) {
86 private static BrokerFacade brokerFacade;
87 private static RestconfImpl restconfImpl;
88 private static SchemaContext schemaContextYangsIetf;
89 private static SchemaContext schemaContextTestModule;
90 private static CompositeNode answerFromGet;
92 private static SchemaContext schemaContextModules;
93 private static SchemaContext schemaContextBehindMountPoint;
96 public static void init() throws FileNotFoundException {
97 schemaContextYangsIetf = TestUtils.loadSchemaContext("/full-versions/yangs");
98 schemaContextTestModule = TestUtils.loadSchemaContext("/full-versions/test-module");
99 ControllerContext controllerContext = ControllerContext.getInstance();
100 controllerContext.setSchemas(schemaContextYangsIetf);
101 brokerFacade = mock(BrokerFacade.class);
102 restconfImpl = RestconfImpl.getInstance();
103 restconfImpl.setBroker(brokerFacade);
104 restconfImpl.setControllerContext(controllerContext);
105 answerFromGet = prepareCompositeNodeWithIetfInterfacesInterfacesData();
107 schemaContextModules = TestUtils.loadSchemaContext("/modules");
108 schemaContextBehindMountPoint = TestUtils.loadSchemaContext("/modules/modules-behind-mount-point");
112 protected Application configure() {
113 /* enable/disable Jersey logs to console */
114 // enable(TestProperties.LOG_TRAFFIC);
115 // enable(TestProperties.DUMP_ENTITY);
116 // enable(TestProperties.RECORD_LOG_LEVEL);
117 // set(TestProperties.RECORD_LOG_LEVEL, Level.ALL.intValue());
118 ResourceConfig resourceConfig = new ResourceConfig();
119 resourceConfig = resourceConfig.registerInstances(restconfImpl, StructuredDataToXmlProvider.INSTANCE,
120 StructuredDataToJsonProvider.INSTANCE, XmlToCompositeNodeProvider.INSTANCE,
121 JsonToCompositeNodeProvider.INSTANCE);
122 resourceConfig.registerClasses( RestconfDocumentedExceptionMapper.class );
123 return resourceConfig;
127 * Tests of status codes for "/operational/{identifier}".
130 public void getOperationalStatusCodes() throws UnsupportedEncodingException {
131 mockReadOperationalDataMethod();
132 String uri = "/operational/ietf-interfaces:interfaces/interface/eth0";
133 assertEquals(200, get(uri, MediaType.APPLICATION_XML));
135 uri = "/operational/wrong-module:interfaces/interface/eth0";
136 assertEquals(400, get(uri, MediaType.APPLICATION_XML));
140 * Tests of status codes for "/config/{identifier}".
143 public void getConfigStatusCodes() throws UnsupportedEncodingException {
144 mockReadConfigurationDataMethod();
145 String uri = "/config/ietf-interfaces:interfaces/interface/eth0";
146 assertEquals(200, get(uri, MediaType.APPLICATION_XML));
148 uri = "/config/wrong-module:interfaces/interface/eth0";
149 assertEquals(400, get(uri, MediaType.APPLICATION_XML));
153 * MountPoint test. URI represents mount point.
156 public void getDataWithUrlMountPoint() throws UnsupportedEncodingException, URISyntaxException {
158 brokerFacade.readConfigurationDataBehindMountPoint(any(MountInstance.class),
159 any(InstanceIdentifier.class))).thenReturn(prepareCnDataForMountPointTest());
160 MountInstance mountInstance = mock(MountInstance.class);
161 when(mountInstance.getSchemaContext()).thenReturn(schemaContextTestModule);
162 MountService mockMountService = mock(MountService.class);
163 when(mockMountService.getMountPoint(any(InstanceIdentifier.class))).thenReturn(mountInstance);
165 ControllerContext.getInstance().setMountService(mockMountService);
167 String uri = "/config/ietf-interfaces:interfaces/interface/0/yang-ext:mount/test-module:cont/cont1";
168 assertEquals(200, get(uri, MediaType.APPLICATION_XML));
170 uri = "/config/ietf-interfaces:interfaces/yang-ext:mount/test-module:cont/cont1";
171 assertEquals(200, get(uri, MediaType.APPLICATION_XML));
175 * MountPoint test. URI represents mount point.
177 * Slashes in URI behind mount point. lst1 element with key
178 * GigabitEthernet0%2F0%2F0%2F0 (GigabitEthernet0/0/0/0) is requested via
179 * GET HTTP operation. It is tested whether %2F character is replaced with
180 * simple / in InstanceIdentifier parameter in method
181 * {@link BrokerFacade#readConfigurationDataBehindMountPoint(MountInstance, InstanceIdentifier)}
182 * which is called in method {@link RestconfImpl#readConfigurationData}
185 * @throws ParseException
188 public void getDataWithSlashesBehindMountPoint() throws UnsupportedEncodingException, URISyntaxException,
190 InstanceIdentifier awaitedInstanceIdentifier = prepareInstanceIdentifierForList();
192 brokerFacade.readConfigurationDataBehindMountPoint(any(MountInstance.class),
193 eq(awaitedInstanceIdentifier))).thenReturn(prepareCnDataForMountPointTest());
194 MountInstance mountInstance = mock(MountInstance.class);
195 when(mountInstance.getSchemaContext()).thenReturn(schemaContextTestModule);
196 MountService mockMountService = mock(MountService.class);
197 when(mockMountService.getMountPoint(any(InstanceIdentifier.class))).thenReturn(mountInstance);
199 ControllerContext.getInstance().setMountService(mockMountService);
201 String uri = "/config/ietf-interfaces:interfaces/interface/0/yang-ext:mount/test-module:cont/lst1/GigabitEthernet0%2F0%2F0%2F0";
202 assertEquals(200, get(uri, MediaType.APPLICATION_XML));
205 private InstanceIdentifier prepareInstanceIdentifierForList() throws URISyntaxException, ParseException {
206 List<PathArgument> parameters = new ArrayList<>();
208 Date revision = new SimpleDateFormat("yyyy-MM-dd").parse("2014-01-09");
209 URI uri = new URI("test:module");
210 QName qNameCont = QName.create(uri, revision, "cont");
211 QName qNameList = QName.create(uri, revision, "lst1");
212 QName qNameKeyList = QName.create(uri, revision, "lf11");
214 parameters.add(new InstanceIdentifier.NodeIdentifier(qNameCont));
215 parameters.add(new InstanceIdentifier.NodeIdentifierWithPredicates(qNameList, qNameKeyList,
216 "GigabitEthernet0/0/0/0"));
217 return new InstanceIdentifier(parameters);
221 public void getDataMountPointIntoHighestElement() throws UnsupportedEncodingException, URISyntaxException {
223 brokerFacade.readConfigurationDataBehindMountPoint(any(MountInstance.class),
224 any(InstanceIdentifier.class))).thenReturn(prepareCnDataForMountPointTest());
225 MountInstance mountInstance = mock(MountInstance.class);
226 when(mountInstance.getSchemaContext()).thenReturn(schemaContextTestModule);
227 MountService mockMountService = mock(MountService.class);
228 when(mockMountService.getMountPoint(any(InstanceIdentifier.class))).thenReturn(mountInstance);
230 ControllerContext.getInstance().setMountService(mockMountService);
232 String uri = "/config/ietf-interfaces:interfaces/interface/0/yang-ext:mount/";
233 assertEquals(200, get(uri, MediaType.APPLICATION_XML));
238 public void getModulesTest() throws UnsupportedEncodingException, FileNotFoundException {
239 ControllerContext.getInstance().setGlobalSchema(schemaContextModules);
241 String uri = "/modules";
243 Response response = target(uri).request("application/yang.api+json").get();
244 validateModulesResponseJson(response);
246 response = target(uri).request("application/yang.api+xml").get();
247 validateModulesResponseXml(response);
252 public void getStreamsTest() throws UnsupportedEncodingException, FileNotFoundException {
253 ControllerContext.getInstance().setGlobalSchema(schemaContextModules);
255 String uri = "/streams";
257 Response response = target(uri).request("application/yang.api+json").get();
258 String responseBody = response.readEntity(String.class);
259 assertNotNull(responseBody);
260 assertTrue(responseBody.contains("streams"));
262 response = target(uri).request("application/yang.api+xml").get();
263 responseBody = response.readEntity(String.class);
264 assertNotNull(responseBody);
265 assertTrue(responseBody.contains("<streams xmlns=\"urn:ietf:params:xml:ns:yang:ietf-restconf\""));
270 public void getModuleTest() throws FileNotFoundException, UnsupportedEncodingException {
271 ControllerContext.getInstance().setGlobalSchema(schemaContextModules);
273 String uri = "/modules/module/module2/2014-01-02";
275 Response response = target(uri).request("application/yang.api+xml").get();
276 assertEquals(200, response.getStatus());
277 String responseBody = response.readEntity(String.class);
278 assertTrue("Module2 in xml wasn't found", prepareXmlRegex("module2", "2014-01-02", "module:2", responseBody)
280 String[] split = responseBody.split("<module");
281 assertEquals("<module element is returned more then once", 2, split.length);
283 response = target(uri).request("application/yang.api+json").get();
284 assertEquals(200, response.getStatus());
285 responseBody = response.readEntity(String.class);
286 assertTrue("Module2 in json wasn't found", prepareJsonRegex("module2", "2014-01-02", "module:2", responseBody)
288 split = responseBody.split("\"module\"");
289 assertEquals("\"module\" element is returned more then once", 2, split.length);
295 public void getOperationsTest() throws FileNotFoundException, UnsupportedEncodingException {
296 ControllerContext.getInstance().setGlobalSchema(schemaContextModules);
298 String uri = "/operations";
300 Response response = target(uri).request("application/yang.api+xml").get();
301 assertEquals(200, response.getStatus());
302 String responseBody = response.readEntity(String.class);
303 assertTrue("Xml response for /operations dummy-rpc1-module1 is incorrect",
304 validateOperationsResponseXml(responseBody, "dummy-rpc1-module1", "module:1").find());
305 assertTrue("Xml response for /operations dummy-rpc2-module1 is incorrect",
306 validateOperationsResponseXml(responseBody, "dummy-rpc2-module1", "module:1").find());
307 assertTrue("Xml response for /operations dummy-rpc1-module2 is incorrect",
308 validateOperationsResponseXml(responseBody, "dummy-rpc1-module2", "module:2").find());
309 assertTrue("Xml response for /operations dummy-rpc2-module2 is incorrect",
310 validateOperationsResponseXml(responseBody, "dummy-rpc2-module2", "module:2").find());
312 response = target(uri).request("application/yang.api+json").get();
313 assertEquals(200, response.getStatus());
314 responseBody = response.readEntity(String.class);
315 assertTrue("Json response for /operations dummy-rpc1-module1 is incorrect",
316 validateOperationsResponseJson(responseBody, "dummy-rpc1-module1", "module1").find());
317 assertTrue("Json response for /operations dummy-rpc2-module1 is incorrect",
318 validateOperationsResponseJson(responseBody, "dummy-rpc2-module1", "module1").find());
319 assertTrue("Json response for /operations dummy-rpc1-module2 is incorrect",
320 validateOperationsResponseJson(responseBody, "dummy-rpc1-module2", "module2").find());
321 assertTrue("Json response for /operations dummy-rpc2-module2 is incorrect",
322 validateOperationsResponseJson(responseBody, "dummy-rpc2-module2", "module2").find());
326 // /operations/pathToMountPoint/yang-ext:mount
328 public void getOperationsBehindMountPointTest() throws FileNotFoundException, UnsupportedEncodingException {
329 ControllerContext controllerContext = ControllerContext.getInstance();
330 controllerContext.setGlobalSchema(schemaContextModules);
332 MountInstance mountInstance = mock(MountInstance.class);
333 when(mountInstance.getSchemaContext()).thenReturn(schemaContextBehindMountPoint);
334 MountService mockMountService = mock(MountService.class);
335 when(mockMountService.getMountPoint(any(InstanceIdentifier.class))).thenReturn(mountInstance);
337 controllerContext.setMountService(mockMountService);
339 String uri = "/operations/ietf-interfaces:interfaces/interface/0/yang-ext:mount/";
341 Response response = target(uri).request("application/yang.api+xml").get();
342 assertEquals(200, response.getStatus());
343 String responseBody = response.readEntity(String.class);
344 assertTrue("Xml response for /operations/mount_point rpc-behind-module1 is incorrect",
345 validateOperationsResponseXml(responseBody, "rpc-behind-module1", "module:1:behind:mount:point").find());
346 assertTrue("Xml response for /operations/mount_point rpc-behind-module2 is incorrect",
347 validateOperationsResponseXml(responseBody, "rpc-behind-module2", "module:2:behind:mount:point").find());
349 response = target(uri).request("application/yang.api+json").get();
350 assertEquals(200, response.getStatus());
351 responseBody = response.readEntity(String.class);
352 assertTrue("Json response for /operations/mount_point rpc-behind-module1 is incorrect",
353 validateOperationsResponseJson(responseBody, "rpc-behind-module1", "module1-behind-mount-point").find());
354 assertTrue("Json response for /operations/mount_point rpc-behind-module2 is incorrect",
355 validateOperationsResponseJson(responseBody, "rpc-behind-module2", "module2-behind-mount-point").find());
359 private Matcher validateOperationsResponseJson(String searchIn, String rpcName, String moduleName) {
360 StringBuilder regex = new StringBuilder();
363 regex.append(".*\\{");
364 regex.append(".*\"");
366 // operations prefix optional
368 regex.append("ietf-restconf:");
370 // :operations prefix optional
372 regex.append("operations\"");
374 regex.append(".*\\{");
376 regex.append(".*\"" + moduleName);
378 regex.append(rpcName + "\"");
379 regex.append(".*\\[");
380 regex.append(".*null");
381 regex.append(".*\\]");
383 regex.append(".*\\}");
384 regex.append(".*\\}");
388 Pattern ptrn = Pattern.compile(regex.toString(), Pattern.DOTALL);
389 return ptrn.matcher(searchIn);
393 private Matcher validateOperationsResponseXml(String searchIn, String rpcName, String namespace) {
394 StringBuilder regex = new StringBuilder();
398 regex.append(".*<operations");
399 regex.append(".*xmlns=\"urn:ietf:params:xml:ns:yang:ietf-restconf\"");
403 regex.append(".*" + rpcName);
404 regex.append(".*" + namespace);
408 regex.append(".*</operations.*");
413 Pattern ptrn = Pattern.compile(regex.toString(), Pattern.DOTALL);
414 return ptrn.matcher(searchIn);
417 // /restconf/modules/pathToMountPoint/yang-ext:mount
419 public void getModulesBehindMountPoint() throws FileNotFoundException, UnsupportedEncodingException {
420 ControllerContext controllerContext = ControllerContext.getInstance();
421 controllerContext.setGlobalSchema(schemaContextModules);
423 MountInstance mountInstance = mock(MountInstance.class);
424 when(mountInstance.getSchemaContext()).thenReturn(schemaContextBehindMountPoint);
425 MountService mockMountService = mock(MountService.class);
426 when(mockMountService.getMountPoint(any(InstanceIdentifier.class))).thenReturn(mountInstance);
428 controllerContext.setMountService(mockMountService);
430 String uri = "/modules/ietf-interfaces:interfaces/interface/0/yang-ext:mount/";
432 Response response = target(uri).request("application/yang.api+json").get();
433 assertEquals(200, response.getStatus());
434 String responseBody = response.readEntity(String.class);
437 "module1-behind-mount-point in json wasn't found",
438 prepareJsonRegex("module1-behind-mount-point", "2014-02-03", "module:1:behind:mount:point",
439 responseBody).find());
441 "module2-behind-mount-point in json wasn't found",
442 prepareJsonRegex("module2-behind-mount-point", "2014-02-04", "module:2:behind:mount:point",
443 responseBody).find());
445 response = target(uri).request("application/yang.api+xml").get();
446 assertEquals(200, response.getStatus());
447 responseBody = response.readEntity(String.class);
449 "module1-behind-mount-point in json wasn't found",
450 prepareXmlRegex("module1-behind-mount-point", "2014-02-03", "module:1:behind:mount:point", responseBody)
453 "module2-behind-mount-point in json wasn't found",
454 prepareXmlRegex("module2-behind-mount-point", "2014-02-04", "module:2:behind:mount:point", responseBody)
459 // /restconf/modules/module/pathToMountPoint/yang-ext:mount/moduleName/revision
461 public void getModuleBehindMountPoint() throws FileNotFoundException, UnsupportedEncodingException {
462 ControllerContext controllerContext = ControllerContext.getInstance();
463 controllerContext.setGlobalSchema(schemaContextModules);
465 MountInstance mountInstance = mock(MountInstance.class);
466 when(mountInstance.getSchemaContext()).thenReturn(schemaContextBehindMountPoint);
467 MountService mockMountService = mock(MountService.class);
468 when(mockMountService.getMountPoint(any(InstanceIdentifier.class))).thenReturn(mountInstance);
470 controllerContext.setMountService(mockMountService);
472 String uri = "/modules/module/ietf-interfaces:interfaces/interface/0/yang-ext:mount/module1-behind-mount-point/2014-02-03";
474 Response response = target(uri).request("application/yang.api+json").get();
475 assertEquals(200, response.getStatus());
476 String responseBody = response.readEntity(String.class);
479 "module1-behind-mount-point in json wasn't found",
480 prepareJsonRegex("module1-behind-mount-point", "2014-02-03", "module:1:behind:mount:point",
481 responseBody).find());
482 String[] split = responseBody.split("\"module\"");
483 assertEquals("\"module\" element is returned more then once", 2, split.length);
485 response = target(uri).request("application/yang.api+xml").get();
486 assertEquals(200, response.getStatus());
487 responseBody = response.readEntity(String.class);
489 "module1-behind-mount-point in json wasn't found",
490 prepareXmlRegex("module1-behind-mount-point", "2014-02-03", "module:1:behind:mount:point", responseBody)
492 split = responseBody.split("<module");
493 assertEquals("<module element is returned more then once", 2, split.length);
497 private void validateModulesResponseXml(Response response) {
498 assertEquals(200, response.getStatus());
499 String responseBody = response.readEntity(String.class);
501 assertTrue("Module1 in xml wasn't found", prepareXmlRegex("module1", "2014-01-01", "module:1", responseBody)
503 assertTrue("Module2 in xml wasn't found", prepareXmlRegex("module2", "2014-01-02", "module:2", responseBody)
505 assertTrue("Module3 in xml wasn't found", prepareXmlRegex("module3", "2014-01-03", "module:3", responseBody)
509 private void validateModulesResponseJson(Response response) {
510 assertEquals(200, response.getStatus());
511 String responseBody = response.readEntity(String.class);
513 assertTrue("Module1 in json wasn't found", prepareJsonRegex("module1", "2014-01-01", "module:1", responseBody)
515 assertTrue("Module2 in json wasn't found", prepareJsonRegex("module2", "2014-01-02", "module:2", responseBody)
517 assertTrue("Module3 in json wasn't found", prepareJsonRegex("module3", "2014-01-03", "module:3", responseBody)
521 private Matcher prepareJsonRegex(String module, String revision, String namespace, String searchIn) {
522 StringBuilder regex = new StringBuilder();
525 regex.append(".*\\{");
526 regex.append(".*\"name\"");
528 regex.append(".*\"" + module + "\",");
530 regex.append(".*\"revision\"");
532 regex.append(".*\"" + revision + "\",");
534 regex.append(".*\"namespace\"");
536 regex.append(".*\"" + namespace + "\"");
538 regex.append(".*\\}");
542 Pattern ptrn = Pattern.compile(regex.toString(), Pattern.DOTALL);
543 return ptrn.matcher(searchIn);
547 private Matcher prepareXmlRegex(String module, String revision, String namespace, String searchIn) {
548 StringBuilder regex = new StringBuilder();
551 regex.append(".*<module.*");
554 regex.append(".*<name>");
555 regex.append(".*" + module);
556 regex.append(".*<\\/name>");
558 regex.append(".*<revision>");
559 regex.append(".*" + revision);
560 regex.append(".*<\\/revision>");
562 regex.append(".*<namespace>");
563 regex.append(".*" + namespace);
564 regex.append(".*<\\/namespace>");
566 regex.append(".*<\\/module.*>");
571 Pattern ptrn = Pattern.compile(regex.toString(), Pattern.DOTALL);
572 return ptrn.matcher(searchIn);
575 private void prepareMockForModulesTest(ControllerContext mockedControllerContext) throws FileNotFoundException {
576 SchemaContext schemaContext = TestUtils.loadSchemaContext("/modules");
577 mockedControllerContext.setGlobalSchema(schemaContext);
578 // when(mockedControllerContext.getGlobalSchema()).thenReturn(schemaContext);
581 private int get(String uri, String mediaType) {
582 return target(uri).request(mediaType).get().getStatus();
585 private CompositeNode prepareCnDataForMountPointTest() throws URISyntaxException {
586 CompositeNodeWrapper cont1 = new CompositeNodeWrapper(new URI("test:module"), "cont1");
587 SimpleNodeWrapper lf11 = new SimpleNodeWrapper(new URI("test:module"), "lf11", "lf11 value");
588 cont1.addValue(lf11);
589 return cont1.unwrap();
592 private void mockReadOperationalDataMethod() {
593 when(brokerFacade.readOperationalData(any(InstanceIdentifier.class))).thenReturn(answerFromGet);
596 private void mockReadConfigurationDataMethod() {
597 when(brokerFacade.readConfigurationData(any(InstanceIdentifier.class))).thenReturn(answerFromGet);
600 private static CompositeNode prepareCompositeNodeWithIetfInterfacesInterfacesData() {
601 CompositeNode intface;
603 intface = new CompositeNodeWrapper(new URI("interface"), "interface");
604 List<Node<?>> childs = new ArrayList<>();
606 childs.add(new SimpleNodeWrapper(new URI("name"), "name", "eth0"));
607 childs.add(new SimpleNodeWrapper(new URI("type"), "type", "ethernetCsmacd"));
608 childs.add(new SimpleNodeWrapper(new URI("enabled"), "enabled", Boolean.FALSE));
609 childs.add(new SimpleNodeWrapper(new URI("description"), "description", "some interface"));
610 intface.setValue(childs);
612 } catch (URISyntaxException e) {
619 public void getDataWithUriDepthParameterTest() throws UnsupportedEncodingException {
621 ControllerContext.getInstance().setGlobalSchema( schemaContextModules );
623 CompositeNode depth1Cont = toCompositeNode(
624 toCompositeNodeData( toNestedQName( "depth1-cont" ),
625 toCompositeNodeData( toNestedQName( "depth2-cont1" ),
626 toCompositeNodeData( toNestedQName( "depth3-cont1" ),
627 toCompositeNodeData( toNestedQName( "depth4-cont1" ),
628 toSimpleNodeData( toNestedQName( "depth5-leaf1" ), "depth5-leaf1-value" )
630 toSimpleNodeData( toNestedQName( "depth4-leaf1" ), "depth4-leaf1-value" )
632 toSimpleNodeData( toNestedQName( "depth3-leaf1" ), "depth3-leaf1-value" )
634 toCompositeNodeData( toNestedQName( "depth2-cont2" ),
635 toCompositeNodeData( toNestedQName( "depth3-cont2" ),
636 toCompositeNodeData( toNestedQName( "depth4-cont2" ),
637 toSimpleNodeData( toNestedQName( "depth5-leaf2" ), "depth5-leaf2-value" )
639 toSimpleNodeData( toNestedQName( "depth4-leaf2" ), "depth4-leaf2-value" )
641 toSimpleNodeData( toNestedQName( "depth3-leaf2" ), "depth3-leaf2-value" )
643 toSimpleNodeData( toNestedQName( "depth2-leaf1" ), "depth2-leaf1-value" )
646 when( brokerFacade.readConfigurationData( any( InstanceIdentifier.class ) ) )
647 .thenReturn( depth1Cont );
649 // Test config with depth 1
651 Response response = target( "/config/nested-module:depth1-cont" ).queryParam( "depth", "1" )
652 .request( "application/xml" ).get();
654 verifyXMLResponse( response, expectEmptyContainer( "depth1-cont" ) );
656 // Test config with depth 2
658 response = target( "/config/nested-module:depth1-cont" ).queryParam( "depth", "2" )
659 .request( "application/xml" ).get();
661 // String xml="<depth1-cont><depth2-cont1/><depth2-cont2/><depth2-leaf1>depth2-leaf1-value</depth2-leaf1></depth1-cont>";
662 // Response mr=mock(Response.class);
663 // when(mr.getEntity()).thenReturn( new java.io.StringBufferInputStream(xml) );
665 verifyXMLResponse( response,
666 expectContainer( "depth1-cont",
667 expectEmptyContainer( "depth2-cont1" ),
668 expectEmptyContainer( "depth2-cont2" ),
669 expectLeaf( "depth2-leaf1", "depth2-leaf1-value" )
672 // Test config with depth 3
674 response = target( "/config/nested-module:depth1-cont" ).queryParam( "depth", "3" )
675 .request( "application/xml" ).get();
677 verifyXMLResponse( response,
678 expectContainer( "depth1-cont",
679 expectContainer( "depth2-cont1",
680 expectEmptyContainer( "depth3-cont1" ),
681 expectLeaf( "depth3-leaf1", "depth3-leaf1-value" )
683 expectContainer( "depth2-cont2",
684 expectEmptyContainer( "depth3-cont2" ),
685 expectLeaf( "depth3-leaf2", "depth3-leaf2-value" )
687 expectLeaf( "depth2-leaf1", "depth2-leaf1-value" )
690 // Test config with depth 4
692 response = target( "/config/nested-module:depth1-cont" ).queryParam( "depth", "4" )
693 .request( "application/xml" ).get();
695 verifyXMLResponse( response,
696 expectContainer( "depth1-cont",
697 expectContainer( "depth2-cont1",
698 expectContainer( "depth3-cont1",
699 expectEmptyContainer( "depth4-cont1" ),
700 expectLeaf( "depth4-leaf1", "depth4-leaf1-value" )
702 expectLeaf( "depth3-leaf1", "depth3-leaf1-value" )
704 expectContainer( "depth2-cont2",
705 expectContainer( "depth3-cont2",
706 expectEmptyContainer( "depth4-cont2" ),
707 expectLeaf( "depth4-leaf2", "depth4-leaf2-value" )
709 expectLeaf( "depth3-leaf2", "depth3-leaf2-value" )
711 expectLeaf( "depth2-leaf1", "depth2-leaf1-value" )
714 // Test config with depth 5
716 response = target( "/config/nested-module:depth1-cont" ).queryParam( "depth", "5" )
717 .request( "application/xml" ).get();
719 verifyXMLResponse( response,
720 expectContainer( "depth1-cont",
721 expectContainer( "depth2-cont1",
722 expectContainer( "depth3-cont1",
723 expectContainer( "depth4-cont1",
724 expectLeaf( "depth5-leaf1", "depth5-leaf1-value" )
726 expectLeaf( "depth4-leaf1", "depth4-leaf1-value" )
728 expectLeaf( "depth3-leaf1", "depth3-leaf1-value" )
730 expectContainer( "depth2-cont2",
731 expectContainer( "depth3-cont2",
732 expectContainer( "depth4-cont2",
733 expectLeaf( "depth5-leaf2", "depth5-leaf2-value" )
735 expectLeaf( "depth4-leaf2", "depth4-leaf2-value" )
737 expectLeaf( "depth3-leaf2", "depth3-leaf2-value" )
739 expectLeaf( "depth2-leaf1", "depth2-leaf1-value" )
742 // Test config with depth unbounded
744 response = target( "/config/nested-module:depth1-cont" ).queryParam( "depth", "unbounded" )
745 .request( "application/xml" ).get();
747 verifyXMLResponse( response,
748 expectContainer( "depth1-cont",
749 expectContainer( "depth2-cont1",
750 expectContainer( "depth3-cont1",
751 expectContainer( "depth4-cont1",
752 expectLeaf( "depth5-leaf1", "depth5-leaf1-value" )
754 expectLeaf( "depth4-leaf1", "depth4-leaf1-value" )
756 expectLeaf( "depth3-leaf1", "depth3-leaf1-value" )
758 expectContainer( "depth2-cont2",
759 expectContainer( "depth3-cont2",
760 expectContainer( "depth4-cont2",
761 expectLeaf( "depth5-leaf2", "depth5-leaf2-value" )
763 expectLeaf( "depth4-leaf2", "depth4-leaf2-value" )
765 expectLeaf( "depth3-leaf2", "depth3-leaf2-value" )
767 expectLeaf( "depth2-leaf1", "depth2-leaf1-value" )
772 CompositeNode depth2Cont1 = toCompositeNode(
773 toCompositeNodeData( toNestedQName( "depth2-cont1" ),
774 toCompositeNodeData( toNestedQName( "depth3-cont1" ),
775 toCompositeNodeData( toNestedQName( "depth4-cont1" ),
776 toSimpleNodeData( toNestedQName( "depth5-leaf1" ), "depth5-leaf1-value" )
778 toSimpleNodeData( toNestedQName( "depth4-leaf1" ), "depth4-leaf1-value" )
780 toSimpleNodeData( toNestedQName( "depth3-leaf1" ), "depth3-leaf1-value" )
783 when( brokerFacade.readOperationalData( any( InstanceIdentifier.class ) ) )
784 .thenReturn( depth2Cont1 );
786 response = target( "/operational/nested-module:depth1-cont/depth2-cont1" )
787 .queryParam( "depth", "3" ).request( "application/xml" ).get();
789 verifyXMLResponse( response,
790 expectContainer( "depth2-cont1",
791 expectContainer( "depth3-cont1",
792 expectEmptyContainer( "depth4-cont1" ),
793 expectLeaf( "depth4-leaf1", "depth4-leaf1-value" )
795 expectLeaf( "depth3-leaf1", "depth3-leaf1-value" )
800 public void getDataWithInvalidDepthParameterTest() {
802 ControllerContext.getInstance().setGlobalSchema( schemaContextModules );
804 final MultivaluedMap<String,String> paramMap = new MultivaluedHashMap<>();
805 paramMap.putSingle( "depth", "1o" );
806 UriInfo mockInfo = mock( UriInfo.class );
807 when( mockInfo.getQueryParameters( false ) ).thenAnswer(
808 new Answer<MultivaluedMap<String,String>>() {
810 public MultivaluedMap<String, String> answer( InvocationOnMock invocation ) {
815 getDataWithInvalidDepthParameterTest( mockInfo );
817 paramMap.putSingle( "depth", "0" );
818 getDataWithInvalidDepthParameterTest( mockInfo );
820 paramMap.putSingle( "depth", "-1" );
821 getDataWithInvalidDepthParameterTest( mockInfo );
824 private void getDataWithInvalidDepthParameterTest( UriInfo uriInfo ) {
826 restconfImpl.readConfigurationData( "nested-module:depth1-cont", uriInfo );
827 fail( "Expected RestconfDocumentedException" );
829 catch( RestconfDocumentedException e ) {
830 assertTrue( "Unexpected error message: " + e.getErrors().get( 0 ).getErrorMessage(),
831 e.getErrors().get( 0 ).getErrorMessage().contains( "depth" ) );
835 private void verifyXMLResponse( Response response, NodeData nodeData ) {
837 Document doc = TestUtils.loadDocumentFrom( (InputStream) response.getEntity() );
838 assertNotNull( "Could not parse XML document", doc );
840 //System.out.println(TestUtils.getDocumentInPrintableForm( doc ));
842 verifyContainerElement( doc.getDocumentElement(), nodeData );
845 @SuppressWarnings("unchecked")
846 private void verifyContainerElement( Element element, NodeData nodeData ) {
848 assertEquals( "Element local name", nodeData.key, element.getNodeName() );
850 NodeList childNodes = element.getChildNodes();
851 if( nodeData.data == null ) { // empty container
852 assertTrue( "Expected no child elements for \"" + element.getNodeName() + "\"",
853 childNodes.getLength() == 0 );
857 Map<String,NodeData> expChildMap = Maps.newHashMap();
858 for( NodeData expChild: (List<NodeData>)nodeData.data ) {
859 expChildMap.put( expChild.key.toString(), expChild );
862 for( int i = 0; i < childNodes.getLength(); i++ ) {
863 org.w3c.dom.Node actualChild = childNodes.item( i );
864 if( !( actualChild instanceof Element ) ) {
868 Element actualElement = (Element)actualChild;
869 NodeData expChild = expChildMap.remove( actualElement.getNodeName() );
870 assertNotNull( "Unexpected child element for parent \"" + element.getNodeName() +
871 "\": " + actualElement.getNodeName(), expChild );
873 if( expChild.data == null || expChild.data instanceof List ) {
874 verifyContainerElement( actualElement, expChild );
877 assertEquals( "Text content for element: " + actualElement.getNodeName(),
878 expChild.data, actualElement.getTextContent() );
882 if( !expChildMap.isEmpty() ) {
883 fail( "Missing elements for parent \"" + element.getNodeName() +
884 "\": " + expChildMap.keySet() );
888 private NodeData expectContainer( String name, NodeData... childData ) {
889 return new NodeData( name, Lists.newArrayList( childData ) );
892 private NodeData expectEmptyContainer( String name ) {
893 return new NodeData( name, null );
896 private NodeData expectLeaf( String name, Object value ) {
897 return new NodeData( name, value );
900 private QName toNestedQName( String localName ) {
901 return QName.create( "urn:nested:module", "2014-06-3", localName );
904 @SuppressWarnings("unchecked")
905 private CompositeNode toCompositeNode( NodeData nodeData ) {
906 CompositeNodeBuilder<ImmutableCompositeNode> builder = ImmutableCompositeNode.builder();
907 builder.setQName( (QName) nodeData.key );
909 for( NodeData child: (List<NodeData>)nodeData.data ) {
910 if( child.data instanceof List ) {
911 builder.add( toCompositeNode( child ) );
914 builder.addLeaf( (QName) child.key, child.data );
918 return builder.toInstance();
921 private NodeData toCompositeNodeData( QName key, NodeData... childData ) {
922 return new NodeData( key, Lists.newArrayList( childData ) );
925 private NodeData toSimpleNodeData( QName key, Object value ) {
926 return new NodeData( key, value );