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