Merge "Untangle the XML/Hello message decoders"
[controller.git] / opendaylight / md-sal / sal-rest-connector / src / test / java / org / opendaylight / controller / sal / restconf / impl / test / RestGetOperationTest.java
1 /*
2  * Copyright (c) 2014 Cisco Systems, Inc. and others.  All rights reserved.
3  *
4  * This program and the accompanying materials are made available under the
5  * terms of the Eclipse Public License v1.0 which accompanies this distribution,
6  * and is available at http://www.eclipse.org/legal/epl-v10.html
7  */
8 package org.opendaylight.controller.sal.restconf.impl.test;
9
10 import static org.junit.Assert.assertEquals;
11 import static org.junit.Assert.assertTrue;
12 import static org.mockito.Matchers.any;
13 import static org.mockito.Mockito.mock;
14 import static org.mockito.Mockito.when;
15 import static org.opendaylight.controller.sal.restconf.impl.test.RestOperationUtils.createUri;
16
17 import java.io.FileNotFoundException;
18 import java.io.UnsupportedEncodingException;
19 import java.net.URI;
20 import java.net.URISyntaxException;
21 import java.util.ArrayList;
22 import java.util.List;
23 import java.util.regex.Matcher;
24 import java.util.regex.Pattern;
25
26 import javax.ws.rs.core.Application;
27 import javax.ws.rs.core.MediaType;
28 import javax.ws.rs.core.Response;
29
30 import org.glassfish.jersey.server.ResourceConfig;
31 import org.glassfish.jersey.test.JerseyTest;
32 import org.junit.BeforeClass;
33 import org.junit.Test;
34 import org.opendaylight.controller.sal.core.api.mount.MountInstance;
35 import org.opendaylight.controller.sal.core.api.mount.MountService;
36 import org.opendaylight.controller.sal.rest.impl.JsonToCompositeNodeProvider;
37 import org.opendaylight.controller.sal.rest.impl.StructuredDataToJsonProvider;
38 import org.opendaylight.controller.sal.rest.impl.StructuredDataToXmlProvider;
39 import org.opendaylight.controller.sal.rest.impl.XmlToCompositeNodeProvider;
40 import org.opendaylight.controller.sal.restconf.impl.BrokerFacade;
41 import org.opendaylight.controller.sal.restconf.impl.CompositeNodeWrapper;
42 import org.opendaylight.controller.sal.restconf.impl.ControllerContext;
43 import org.opendaylight.controller.sal.restconf.impl.RestconfImpl;
44 import org.opendaylight.controller.sal.restconf.impl.SimpleNodeWrapper;
45 import org.opendaylight.yangtools.yang.data.api.CompositeNode;
46 import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier;
47 import org.opendaylight.yangtools.yang.data.api.Node;
48 import org.opendaylight.yangtools.yang.model.api.SchemaContext;
49
50 public class RestGetOperationTest extends JerseyTest {
51
52     private static BrokerFacade brokerFacade;
53     private static RestconfImpl restconfImpl;
54     private static SchemaContext schemaContextYangsIetf;
55     private static SchemaContext schemaContextTestModule;
56     private static CompositeNode answerFromGet;
57
58     private static SchemaContext schemaContextModules;
59     private static SchemaContext schemaContextBehindMountPoint;
60
61     @BeforeClass
62     public static void init() throws FileNotFoundException {
63         schemaContextYangsIetf = TestUtils.loadSchemaContext("/full-versions/yangs");
64         schemaContextTestModule = TestUtils.loadSchemaContext("/full-versions/test-module");
65         ControllerContext controllerContext = ControllerContext.getInstance();
66         controllerContext.setSchemas(schemaContextYangsIetf);
67         brokerFacade = mock(BrokerFacade.class);
68         restconfImpl = RestconfImpl.getInstance();
69         restconfImpl.setBroker(brokerFacade);
70         restconfImpl.setControllerContext(controllerContext);
71         answerFromGet = prepareCompositeNodeWithIetfInterfacesInterfacesData();
72
73         schemaContextModules = TestUtils.loadSchemaContext("/modules");
74         schemaContextBehindMountPoint = TestUtils.loadSchemaContext("/modules/modules-behind-mount-point");
75     }
76
77     @Override
78     protected Application configure() {
79         /* enable/disable Jersey logs to console */
80         // enable(TestProperties.LOG_TRAFFIC);
81         // enable(TestProperties.DUMP_ENTITY);
82         // enable(TestProperties.RECORD_LOG_LEVEL);
83         // set(TestProperties.RECORD_LOG_LEVEL, Level.ALL.intValue());
84         ResourceConfig resourceConfig = new ResourceConfig();
85         resourceConfig = resourceConfig.registerInstances(restconfImpl, StructuredDataToXmlProvider.INSTANCE,
86                 StructuredDataToJsonProvider.INSTANCE, XmlToCompositeNodeProvider.INSTANCE,
87                 JsonToCompositeNodeProvider.INSTANCE);
88         return resourceConfig;
89     }
90
91     /**
92      * Tests of status codes for "/operational/{identifier}".
93      */
94     @Test
95     public void getOperationalStatusCodes() throws UnsupportedEncodingException {
96         mockReadOperationalDataMethod();
97         String uri = createUri("/operational/", "ietf-interfaces:interfaces/interface/eth0");
98         assertEquals(200, get(uri, MediaType.APPLICATION_XML));
99
100         uri = createUri("/operational/", "wrong-module:interfaces/interface/eth0");
101         assertEquals(400, get(uri, MediaType.APPLICATION_XML));
102     }
103
104     /**
105      * Tests of status codes for "/config/{identifier}".
106      */
107     @Test
108     public void getConfigStatusCodes() throws UnsupportedEncodingException {
109         mockReadConfigurationDataMethod();
110         String uri = createUri("/config/", "ietf-interfaces:interfaces/interface/eth0");
111         assertEquals(200, get(uri, MediaType.APPLICATION_XML));
112
113         uri = createUri("/config/", "wrong-module:interfaces/interface/eth0");
114         assertEquals(400, get(uri, MediaType.APPLICATION_XML));
115     }
116
117     /**
118      * MountPoint test. URI represents mount point.
119      */
120     @Test
121     public void getDataWithUrlMountPoint() throws UnsupportedEncodingException, URISyntaxException {
122         when(
123                 brokerFacade.readConfigurationDataBehindMountPoint(any(MountInstance.class),
124                         any(InstanceIdentifier.class))).thenReturn(prepareCnDataForMountPointTest());
125         MountInstance mountInstance = mock(MountInstance.class);
126         when(mountInstance.getSchemaContext()).thenReturn(schemaContextTestModule);
127         MountService mockMountService = mock(MountService.class);
128         when(mockMountService.getMountPoint(any(InstanceIdentifier.class))).thenReturn(mountInstance);
129
130         ControllerContext.getInstance().setMountService(mockMountService);
131
132         String uri = createUri("/config/",
133                 "ietf-interfaces:interfaces/interface/0/yang-ext:mount/test-module:cont/cont1");
134         assertEquals(200, get(uri, MediaType.APPLICATION_XML));
135
136         uri = createUri("/config/", "ietf-interfaces:interfaces/yang-ext:mount/test-module:cont/cont1");
137         assertEquals(200, get(uri, MediaType.APPLICATION_XML));
138     }
139
140     @Test
141     public void getDataMountPointIntoHighestElement() throws UnsupportedEncodingException, URISyntaxException {
142         when(
143                 brokerFacade.readConfigurationDataBehindMountPoint(any(MountInstance.class),
144                         any(InstanceIdentifier.class))).thenReturn(prepareCnDataForMountPointTest());
145         MountInstance mountInstance = mock(MountInstance.class);
146         when(mountInstance.getSchemaContext()).thenReturn(schemaContextTestModule);
147         MountService mockMountService = mock(MountService.class);
148         when(mockMountService.getMountPoint(any(InstanceIdentifier.class))).thenReturn(mountInstance);
149
150         ControllerContext.getInstance().setMountService(mockMountService);
151
152         String uri = createUri("/config/", "ietf-interfaces:interfaces/interface/0/yang-ext:mount/");
153         assertEquals(200, get(uri, MediaType.APPLICATION_XML));
154     }
155
156     // /modules
157     @Test
158     public void getModulesTest() throws UnsupportedEncodingException, FileNotFoundException {
159         ControllerContext.getInstance().setGlobalSchema(schemaContextModules);
160
161         String uri = createUri("/modules", "");
162
163         Response response = target(uri).request("application/yang.api+json").get();
164         validateModulesResponseJson(response);
165
166         response = target(uri).request("application/yang.api+xml").get();
167         validateModulesResponseXml(response);
168     }
169
170     // /modules/module
171     @Test
172     public void getModuleTest() throws FileNotFoundException, UnsupportedEncodingException {
173         ControllerContext.getInstance().setGlobalSchema(schemaContextModules);
174
175         String uri = createUri("/modules/module/module2/2014-01-02", "");
176
177         Response response = target(uri).request("application/yang.api+xml").get();
178         assertEquals(200, response.getStatus());
179         String responseBody = response.readEntity(String.class);
180         assertTrue("Module2 in xml wasn't found", prepareXmlRegex("module2", "2014-01-02", "module:2", responseBody)
181                 .find());
182         String[] split = responseBody.split("<module");
183         assertEquals("<module element is returned more then once",2,split.length);
184
185         response = target(uri).request("application/yang.api+json").get();
186         assertEquals(200, response.getStatus());
187         responseBody = response.readEntity(String.class);
188         assertTrue("Module2 in json wasn't found", prepareJsonRegex("module2", "2014-01-02", "module:2", responseBody)
189                 .find());
190         split = responseBody.split("\"module\"");
191         assertEquals("\"module\" element is returned more then once",2,split.length);
192
193     }
194
195     // /operations
196     @Test
197     public void getOperationsTest() throws FileNotFoundException, UnsupportedEncodingException {
198         ControllerContext.getInstance().setGlobalSchema(schemaContextModules);
199
200         String uri = createUri("/operations", "");
201
202         Response response = target(uri).request("application/yang.api+xml").get();
203         assertEquals(200, response.getStatus());
204         String responseBody = response.readEntity(String.class);
205         assertTrue("Xml response for /operations dummy-rpc1-module1 is incorrect",
206                 validateOperationsResponseXml(responseBody, "dummy-rpc1-module1", "module:1").find());
207         assertTrue("Xml response for /operations dummy-rpc2-module1 is incorrect",
208                 validateOperationsResponseXml(responseBody, "dummy-rpc2-module1", "module:1").find());
209         assertTrue("Xml response for /operations dummy-rpc1-module2 is incorrect",
210                 validateOperationsResponseXml(responseBody, "dummy-rpc1-module2", "module:2").find());
211         assertTrue("Xml response for /operations dummy-rpc2-module2 is incorrect",
212                 validateOperationsResponseXml(responseBody, "dummy-rpc2-module2", "module:2").find());
213
214         response = target(uri).request("application/yang.api+json").get();
215         assertEquals(200, response.getStatus());
216         responseBody = response.readEntity(String.class);
217         assertTrue("Json response for /operations dummy-rpc1-module1 is incorrect",
218                 validateOperationsResponseJson(responseBody, "dummy-rpc1-module1", "module1").find());
219         assertTrue("Json response for /operations dummy-rpc2-module1 is incorrect",
220                 validateOperationsResponseJson(responseBody, "dummy-rpc2-module1", "module1").find());
221         assertTrue("Json response for /operations dummy-rpc1-module2 is incorrect",
222                 validateOperationsResponseJson(responseBody, "dummy-rpc1-module2", "module2").find());
223         assertTrue("Json response for /operations dummy-rpc2-module2 is incorrect",
224                 validateOperationsResponseJson(responseBody, "dummy-rpc2-module2", "module2").find());
225
226     }
227
228     // /operations/pathToMountPoint/yang-ext:mount
229     @Test
230     public void getOperationsBehindMountPointTest() throws FileNotFoundException, UnsupportedEncodingException {
231         ControllerContext controllerContext = ControllerContext.getInstance();
232         controllerContext.setGlobalSchema(schemaContextModules);
233
234         MountInstance mountInstance = mock(MountInstance.class);
235         when(mountInstance.getSchemaContext()).thenReturn(schemaContextBehindMountPoint);
236         MountService mockMountService = mock(MountService.class);
237         when(mockMountService.getMountPoint(any(InstanceIdentifier.class))).thenReturn(mountInstance);
238
239         controllerContext.setMountService(mockMountService);
240
241         String uri = createUri("/operations/", "ietf-interfaces:interfaces/interface/0/yang-ext:mount/");
242
243         Response response = target(uri).request("application/yang.api+xml").get();
244         assertEquals(200, response.getStatus());
245         String responseBody = response.readEntity(String.class);
246         assertTrue("Xml response for /operations/mount_point rpc-behind-module1 is incorrect",
247                 validateOperationsResponseXml(responseBody, "rpc-behind-module1", "module:1:behind:mount:point").find());
248         assertTrue("Xml response for /operations/mount_point rpc-behind-module2 is incorrect",
249                 validateOperationsResponseXml(responseBody, "rpc-behind-module2", "module:2:behind:mount:point").find());
250
251         response = target(uri).request("application/yang.api+json").get();
252         assertEquals(200, response.getStatus());
253         responseBody = response.readEntity(String.class);
254         assertTrue("Json response for /operations/mount_point rpc-behind-module1 is incorrect",
255                 validateOperationsResponseJson(responseBody, "rpc-behind-module1", "module1-behind-mount-point").find());
256         assertTrue("Json response for /operations/mount_point rpc-behind-module2 is incorrect",
257                 validateOperationsResponseJson(responseBody, "rpc-behind-module2", "module2-behind-mount-point").find());
258
259     }
260
261     private Matcher validateOperationsResponseJson(String searchIn, String rpcName, String moduleName) {
262         StringBuilder regex = new StringBuilder();
263         regex.append("^");
264
265         regex.append(".*\\{");
266         regex.append(".*\"");
267
268         // operations prefix optional
269         regex.append("(");
270         regex.append("ietf-restconf:");
271         regex.append("|)");
272         // :operations prefix optional
273
274         regex.append("operations\"");
275         regex.append(".*:");
276         regex.append(".*\\{");
277
278         regex.append(".*\"" + moduleName);
279         regex.append(":");
280         regex.append(rpcName + "\"");
281         regex.append(".*\\[");
282         regex.append(".*null");
283         regex.append(".*\\]");
284
285         regex.append(".*\\}");
286         regex.append(".*\\}");
287
288         regex.append(".*");
289         regex.append("$");
290         Pattern ptrn = Pattern.compile(regex.toString(), Pattern.DOTALL);
291         return ptrn.matcher(searchIn);
292
293     }
294
295     private Matcher validateOperationsResponseXml(String searchIn, String rpcName, String namespace) {
296         StringBuilder regex = new StringBuilder();
297
298         regex.append("^");
299
300         regex.append(".*<operations");
301         regex.append(".*xmlns=\"urn:ietf:params:xml:ns:yang:ietf-restconf\"");
302         regex.append(".*>");
303
304         regex.append(".*<");
305         regex.append(".*" + rpcName);
306         regex.append(".*" + namespace);
307         regex.append(".*/");
308         regex.append(".*>");
309
310         regex.append(".*</operations.*");
311         regex.append(".*>");
312
313         regex.append(".*");
314         regex.append("$");
315         Pattern ptrn = Pattern.compile(regex.toString(), Pattern.DOTALL);
316         return ptrn.matcher(searchIn);
317     }
318
319     // /restconf/modules/pathToMountPoint/yang-ext:mount
320     @Test
321     public void getModulesBehindMountPoint() throws FileNotFoundException, UnsupportedEncodingException {
322         ControllerContext controllerContext = ControllerContext.getInstance();
323         controllerContext.setGlobalSchema(schemaContextModules);
324
325         MountInstance mountInstance = mock(MountInstance.class);
326         when(mountInstance.getSchemaContext()).thenReturn(schemaContextBehindMountPoint);
327         MountService mockMountService = mock(MountService.class);
328         when(mockMountService.getMountPoint(any(InstanceIdentifier.class))).thenReturn(mountInstance);
329
330         controllerContext.setMountService(mockMountService);
331
332         String uri = createUri("/modules/", "ietf-interfaces:interfaces/interface/0/yang-ext:mount/");
333
334         Response response = target(uri).request("application/yang.api+json").get();
335         assertEquals(200, response.getStatus());
336         String responseBody = response.readEntity(String.class);
337
338         assertTrue(
339                 "module1-behind-mount-point in json wasn't found",
340                 prepareJsonRegex("module1-behind-mount-point", "2014-02-03", "module:1:behind:mount:point",
341                         responseBody).find());
342         assertTrue(
343                 "module2-behind-mount-point in json wasn't found",
344                 prepareJsonRegex("module2-behind-mount-point", "2014-02-04", "module:2:behind:mount:point",
345                         responseBody).find());
346
347         response = target(uri).request("application/yang.api+xml").get();
348         assertEquals(200, response.getStatus());
349         responseBody = response.readEntity(String.class);
350         assertTrue(
351                 "module1-behind-mount-point in json wasn't found",
352                 prepareXmlRegex("module1-behind-mount-point", "2014-02-03", "module:1:behind:mount:point", responseBody)
353                         .find());
354         assertTrue(
355                 "module2-behind-mount-point in json wasn't found",
356                 prepareXmlRegex("module2-behind-mount-point", "2014-02-04", "module:2:behind:mount:point", responseBody)
357                         .find());
358
359     }
360
361     // /restconf/modules/module/pathToMountPoint/yang-ext:mount/moduleName/revision
362     @Test
363     public void getModuleBehindMountPoint() throws FileNotFoundException, UnsupportedEncodingException {
364         ControllerContext controllerContext = ControllerContext.getInstance();
365         controllerContext.setGlobalSchema(schemaContextModules);
366
367         MountInstance mountInstance = mock(MountInstance.class);
368         when(mountInstance.getSchemaContext()).thenReturn(schemaContextBehindMountPoint);
369         MountService mockMountService = mock(MountService.class);
370         when(mockMountService.getMountPoint(any(InstanceIdentifier.class))).thenReturn(mountInstance);
371
372         controllerContext.setMountService(mockMountService);
373
374         String uri = createUri("/modules/module/",
375                 "ietf-interfaces:interfaces/interface/0/yang-ext:mount/module1-behind-mount-point/2014-02-03");
376
377         Response response = target(uri).request("application/yang.api+json").get();
378         assertEquals(200, response.getStatus());
379         String responseBody = response.readEntity(String.class);
380
381         assertTrue(
382                 "module1-behind-mount-point in json wasn't found",
383                 prepareJsonRegex("module1-behind-mount-point", "2014-02-03", "module:1:behind:mount:point",
384                         responseBody).find());
385         String[] split = responseBody.split("\"module\"");
386         assertEquals("\"module\" element is returned more then once",2,split.length);
387
388
389         response = target(uri).request("application/yang.api+xml").get();
390         assertEquals(200, response.getStatus());
391         responseBody = response.readEntity(String.class);
392         assertTrue(
393                 "module1-behind-mount-point in json wasn't found",
394                 prepareXmlRegex("module1-behind-mount-point", "2014-02-03", "module:1:behind:mount:point", responseBody)
395                         .find());
396         split = responseBody.split("<module");
397         assertEquals("<module element is returned more then once",2,split.length);
398
399
400
401
402     }
403
404     private void validateModulesResponseXml(Response response) {
405         assertEquals(200, response.getStatus());
406         String responseBody = response.readEntity(String.class);
407
408         assertTrue("Module1 in xml wasn't found", prepareXmlRegex("module1", "2014-01-01", "module:1", responseBody)
409                 .find());
410         assertTrue("Module2 in xml wasn't found", prepareXmlRegex("module2", "2014-01-02", "module:2", responseBody)
411                 .find());
412         assertTrue("Module3 in xml wasn't found", prepareXmlRegex("module3", "2014-01-03", "module:3", responseBody)
413                 .find());
414     }
415
416     private void validateModulesResponseJson(Response response) {
417         assertEquals(200, response.getStatus());
418         String responseBody = response.readEntity(String.class);
419
420         assertTrue("Module1 in json wasn't found", prepareJsonRegex("module1", "2014-01-01", "module:1", responseBody)
421                 .find());
422         assertTrue("Module2 in json wasn't found", prepareJsonRegex("module2", "2014-01-02", "module:2", responseBody)
423                 .find());
424         assertTrue("Module3 in json wasn't found", prepareJsonRegex("module3", "2014-01-03", "module:3", responseBody)
425                 .find());
426     }
427
428     private Matcher prepareJsonRegex(String module, String revision, String namespace, String searchIn) {
429         StringBuilder regex = new StringBuilder();
430         regex.append("^");
431
432         regex.append(".*\\{");
433         regex.append(".*\"name\"");
434         regex.append(".*:");
435         regex.append(".*\"" + module + "\",");
436
437         regex.append(".*\"revision\"");
438         regex.append(".*:");
439         regex.append(".*\"" + revision + "\",");
440
441         regex.append(".*\"namespace\"");
442         regex.append(".*:");
443         regex.append(".*\"" + namespace + "\"");
444
445         regex.append(".*\\}");
446
447         regex.append(".*");
448         regex.append("$");
449         Pattern ptrn = Pattern.compile(regex.toString(), Pattern.DOTALL);
450         return ptrn.matcher(searchIn);
451
452     }
453
454     private Matcher prepareXmlRegex(String module, String revision, String namespace, String searchIn) {
455         StringBuilder regex = new StringBuilder();
456         regex.append("^");
457
458         regex.append(".*<module.*");
459         regex.append(".*>");
460
461         regex.append(".*<name>");
462         regex.append(".*" + module);
463         regex.append(".*<\\/name>");
464
465         regex.append(".*<revision>");
466         regex.append(".*" + revision);
467         regex.append(".*<\\/revision>");
468
469         regex.append(".*<namespace>");
470         regex.append(".*" + namespace);
471         regex.append(".*<\\/namespace>");
472
473         regex.append(".*<\\/module.*>");
474
475         regex.append(".*");
476         regex.append("$");
477
478         Pattern ptrn = Pattern.compile(regex.toString(), Pattern.DOTALL);
479         return ptrn.matcher(searchIn);
480     }
481
482     private void prepareMockForModulesTest(ControllerContext mockedControllerContext) throws FileNotFoundException {
483         SchemaContext schemaContext = TestUtils.loadSchemaContext("/modules");
484         mockedControllerContext.setGlobalSchema(schemaContext);
485         // when(mockedControllerContext.getGlobalSchema()).thenReturn(schemaContext);
486     }
487
488     private int get(String uri, String mediaType) {
489         return target(uri).request(mediaType).get().getStatus();
490     }
491
492     private CompositeNode prepareCnDataForMountPointTest() throws URISyntaxException {
493         CompositeNodeWrapper cont1 = new CompositeNodeWrapper(new URI("test:module"), "cont1");
494         SimpleNodeWrapper lf11 = new SimpleNodeWrapper(new URI("test:module"), "lf11", "lf11 value");
495         cont1.addValue(lf11);
496         return cont1.unwrap();
497     }
498
499     private void mockReadOperationalDataMethod() {
500         when(brokerFacade.readOperationalData(any(InstanceIdentifier.class))).thenReturn(answerFromGet);
501     }
502
503     private void mockReadConfigurationDataMethod() {
504         when(brokerFacade.readConfigurationData(any(InstanceIdentifier.class))).thenReturn(answerFromGet);
505     }
506
507     private static CompositeNode prepareCompositeNodeWithIetfInterfacesInterfacesData() {
508         CompositeNode intface;
509         try {
510             intface = new CompositeNodeWrapper(new URI("interface"), "interface");
511             List<Node<?>> childs = new ArrayList<>();
512
513             childs.add(new SimpleNodeWrapper(new URI("name"), "name", "eth0"));
514             childs.add(new SimpleNodeWrapper(new URI("type"), "type", "ethernetCsmacd"));
515             childs.add(new SimpleNodeWrapper(new URI("enabled"), "enabled", Boolean.FALSE));
516             childs.add(new SimpleNodeWrapper(new URI("description"), "description", "some interface"));
517             intface.setValue(childs);
518             return intface;
519         } catch (URISyntaxException e) {
520         }
521
522         return null;
523     }
524
525 }