Merge "Bug 624 - Separate netty and exi specific classes from netconf-util."
[controller.git] / opendaylight / md-sal / sal-rest-connector / src / test / java / org / opendaylight / controller / sal / restconf / impl / test / InvokeRpcMethodTest.java
1 /*
2  * Copyright (c) 2014 Cisco Systems, Inc. and others.  All rights reserved.
3  * Copyright (c) 2014 Brocade Communications Systems, Inc.
4  *
5  * This program and the accompanying materials are made available under the
6  * terms of the Eclipse Public License v1.0 which accompanies this distribution,
7  * and is available at http://www.eclipse.org/legal/epl-v10.html
8  */
9 package org.opendaylight.controller.sal.restconf.impl.test;
10
11 import static org.junit.Assert.assertEquals;
12 import static org.junit.Assert.assertNotNull;
13 import static org.junit.Assert.assertSame;
14 import static org.junit.Assert.assertTrue;
15 import static org.junit.Assert.fail;
16 import static org.mockito.Matchers.any;
17 import static org.mockito.Matchers.eq;
18 import static org.mockito.Mockito.mock;
19 import static org.mockito.Mockito.spy;
20 import static org.mockito.Mockito.when;
21
22 import java.io.FileNotFoundException;
23 import java.net.URI;
24 import java.net.URISyntaxException;
25 import java.util.HashSet;
26 import java.util.LinkedList;
27 import java.util.List;
28 import java.util.Set;
29
30 import javax.ws.rs.core.Response.Status;
31
32 import org.junit.Before;
33 import org.junit.BeforeClass;
34 import org.junit.Test;
35 import org.mockito.ArgumentCaptor;
36 import org.mockito.invocation.InvocationOnMock;
37 import org.mockito.stubbing.Answer;
38 import org.opendaylight.controller.sal.core.api.mount.MountInstance;
39 import org.opendaylight.controller.sal.restconf.impl.BrokerFacade;
40 import org.opendaylight.controller.sal.restconf.impl.ControllerContext;
41 import org.opendaylight.controller.sal.restconf.impl.InstanceIdWithSchemaNode;
42 import org.opendaylight.controller.sal.restconf.impl.ResponseException;
43 import org.opendaylight.controller.sal.restconf.impl.RestconfImpl;
44 import org.opendaylight.controller.sal.restconf.impl.StructuredData;
45 import org.opendaylight.yangtools.yang.common.QName;
46 import org.opendaylight.yangtools.yang.common.RpcError;
47 import org.opendaylight.yangtools.yang.common.RpcResult;
48 import org.opendaylight.yangtools.yang.data.api.CompositeNode;
49 import org.opendaylight.yangtools.yang.data.api.ModifyAction;
50 import org.opendaylight.yangtools.yang.data.api.MutableCompositeNode;
51 import org.opendaylight.yangtools.yang.data.api.MutableSimpleNode;
52 import org.opendaylight.yangtools.yang.data.impl.NodeFactory;
53 import org.opendaylight.yangtools.yang.model.api.Module;
54 import org.opendaylight.yangtools.yang.model.api.RpcDefinition;
55 import org.opendaylight.yangtools.yang.model.api.SchemaContext;
56
57 import com.google.common.util.concurrent.ListenableFuture;
58
59 public class InvokeRpcMethodTest {
60
61     private RestconfImpl restconfImpl = null;
62     private static ControllerContext controllerContext = null;
63
64     private class AnswerImpl implements Answer<RpcResult<CompositeNode>> {
65         @Override
66         public RpcResult<CompositeNode> answer(InvocationOnMock invocation) throws Throwable {
67             CompositeNode compNode = (CompositeNode) invocation.getArguments()[1];
68             return new DummyRpcResult.Builder<CompositeNode>().result(compNode).isSuccessful(true).build();
69         }
70     }
71
72     @BeforeClass
73     public static void init() throws FileNotFoundException {
74         Set<Module> allModules = new HashSet<Module>( TestUtils
75                 .loadModulesFrom("/full-versions/yangs") );
76         allModules.addAll( TestUtils.loadModulesFrom("/invoke-rpc") );
77         assertNotNull(allModules);
78         Module module = TestUtils.resolveModule("invoke-rpc-module", allModules);
79         assertNotNull(module);
80         SchemaContext schemaContext = TestUtils.loadSchemaContext(allModules);
81         controllerContext = spy( ControllerContext.getInstance() );
82         controllerContext.setSchemas(schemaContext);
83
84     }
85
86     @Before
87     public void initMethod()
88     {
89         restconfImpl = RestconfImpl.getInstance();
90         restconfImpl.setControllerContext( controllerContext );
91     }
92
93     /**
94      * Test method invokeRpc in RestconfImpl class tests if composite node as
95      * input parameter of method invokeRpc (second argument) is wrapped to
96      * parent composite node which has QName equals to QName of rpc (resolved
97      * from string - first argument).
98      */
99     @Test
100     public void invokeRpcMtethodTest() {
101         ControllerContext contContext = controllerContext;
102         try {
103             contContext.findModuleNameByNamespace(new URI("invoke:rpc:module"));
104         } catch (URISyntaxException e) {
105             assertTrue("Uri wasn't created sucessfuly", false);
106         }
107
108         BrokerFacade mockedBrokerFacade = mock(BrokerFacade.class);
109
110         RestconfImpl restconf = RestconfImpl.getInstance();
111         restconf.setBroker(mockedBrokerFacade);
112         restconf.setControllerContext(contContext);
113
114         when(mockedBrokerFacade.invokeRpc(any(QName.class), any(CompositeNode.class))).thenAnswer(new AnswerImpl());
115
116         StructuredData structData = restconf.invokeRpc("invoke-rpc-module:rpc-test", preparePayload());
117         assertTrue(structData == null);
118
119     }
120
121     private CompositeNode preparePayload() {
122         MutableCompositeNode cont = NodeFactory.createMutableCompositeNode(
123                 TestUtils.buildQName("cont", "nmspc", "2013-12-04"), null, null, ModifyAction.CREATE, null);
124         MutableSimpleNode<?> lf = NodeFactory.createMutableSimpleNode(
125                 TestUtils.buildQName("lf", "nmspc", "2013-12-04"), cont, "any value", ModifyAction.CREATE, null);
126         cont.getChildren().add(lf);
127         cont.init();
128
129         return cont;
130     }
131
132     @Test
133     public void testInvokeRpcWithNoPayloadRpc_FailNoErrors() {
134         RpcResult<CompositeNode> rpcResult = mock(RpcResult.class);
135         when(rpcResult.isSuccessful()).thenReturn(false);
136
137         ArgumentCaptor<CompositeNode> payload = ArgumentCaptor
138                 .forClass(CompositeNode.class);
139         BrokerFacade brokerFacade = mock(BrokerFacade.class);
140         when(
141                 brokerFacade.invokeRpc(
142                         eq(QName.create("(http://netconfcentral.org/ns/toaster?revision=2009-11-20)cancel-toast")),
143                         payload.capture())).thenReturn(rpcResult);
144
145         restconfImpl.setBroker(brokerFacade);
146
147         try {
148             restconfImpl.invokeRpc("toaster:cancel-toast", "");
149             fail("Expected an exception to be thrown.");
150         } catch (ResponseException e) {
151             assertEquals(e.getMessage(),
152                     Status.INTERNAL_SERVER_ERROR.getStatusCode(), e
153                             .getResponse().getStatus());
154         }
155     }
156
157     @Test
158     public void testInvokeRpcWithNoPayloadRpc_FailWithRpcError() {
159         List<RpcError> rpcErrors = new LinkedList<RpcError>();
160
161         RpcError unknownError = mock(RpcError.class);
162         when( unknownError.getTag() ).thenReturn( "bogusTag" );
163         rpcErrors.add( unknownError );
164
165         RpcError knownError = mock( RpcError.class );
166         when( knownError.getTag() ).thenReturn( "in-use" );
167         rpcErrors.add( knownError );
168
169         RpcResult<CompositeNode> rpcResult = mock(RpcResult.class);
170         when(rpcResult.isSuccessful()).thenReturn(false);
171         when(rpcResult.getErrors()).thenReturn( rpcErrors  );
172
173         ArgumentCaptor<CompositeNode> payload = ArgumentCaptor
174                 .forClass(CompositeNode.class);
175         BrokerFacade brokerFacade = mock(BrokerFacade.class);
176         when(
177                 brokerFacade.invokeRpc(
178                         eq(QName.create("(http://netconfcentral.org/ns/toaster?revision=2009-11-20)cancel-toast")),
179                         payload.capture())).thenReturn(rpcResult);
180
181         restconfImpl.setBroker(brokerFacade);
182
183         try {
184             restconfImpl.invokeRpc("toaster:cancel-toast", "");
185             fail("Expected an exception to be thrown.");
186         } catch (ResponseException e) {
187             //TODO: Change to a 409 in the future - waiting on additional BUG to enhance this.
188             assertEquals(e.getMessage(), 500, e.getResponse().getStatus());
189         }
190     }
191
192     @Test
193     public void testInvokeRpcWithNoPayload_Success() {
194         RpcResult<CompositeNode> rpcResult = mock(RpcResult.class);
195         when(rpcResult.isSuccessful()).thenReturn(true);
196
197         BrokerFacade brokerFacade = mock(BrokerFacade.class);
198         when(
199                 brokerFacade.invokeRpc(
200                         eq(QName.create("(http://netconfcentral.org/ns/toaster?revision=2009-11-20)cancel-toast")),
201                         any( CompositeNode.class ))).thenReturn(rpcResult);
202
203         restconfImpl.setBroker(brokerFacade);
204
205         StructuredData output = restconfImpl.invokeRpc("toaster:cancel-toast",
206                 "");
207         assertEquals(null, output);
208         //additional validation in the fact that the restconfImpl does not throw an exception.
209     }
210
211     @Test
212     public void testInvokeRpcMethodExpectingNoPayloadButProvidePayload() {
213         try {
214             restconfImpl.invokeRpc("toaster:cancel-toast", " a payload ");
215             fail("Expected an exception");
216         } catch (ResponseException e) {
217             assertEquals(e.getMessage(),
218                     Status.UNSUPPORTED_MEDIA_TYPE.getStatusCode(), e
219                             .getResponse().getStatus());
220         }
221     }
222
223     @Test
224     public void testInvokeRpcMethodWithBadMethodName() {
225         try {
226             restconfImpl.invokeRpc("toaster:bad-method", "");
227             fail("Expected an exception");
228         } catch (ResponseException e) {
229             assertEquals(e.getMessage(), Status.NOT_FOUND.getStatusCode(), e
230                     .getResponse().getStatus());
231         }
232     }
233
234     @Test
235     public void testInvokeRpcMethodWithInput() {
236         RpcResult<CompositeNode> rpcResult = mock(RpcResult.class);
237         when(rpcResult.isSuccessful()).thenReturn(true);
238
239         CompositeNode payload = mock(CompositeNode.class);
240
241         BrokerFacade brokerFacade = mock(BrokerFacade.class);
242         when(
243                 brokerFacade.invokeRpc(
244                         eq(QName.create("(http://netconfcentral.org/ns/toaster?revision=2009-11-20)make-toast")),
245                         any(CompositeNode.class))).thenReturn(rpcResult);
246
247         restconfImpl.setBroker(brokerFacade);
248
249         StructuredData output = restconfImpl.invokeRpc("toaster:make-toast",
250                 payload);
251         assertEquals(null, output);
252         //additional validation in the fact that the restconfImpl does not throw an exception.
253     }
254
255     @Test
256     public void testThrowExceptionWhenSlashInModuleName() {
257         try {
258             restconfImpl.invokeRpc("toaster/slash", "");
259             fail("Expected an exception.");
260         } catch (ResponseException e) {
261             assertEquals(e.getMessage(), Status.NOT_FOUND.getStatusCode(), e
262                     .getResponse().getStatus());
263         }
264     }
265
266     @Test
267     public void testInvokeRpcWithNoPayloadWithOutput_Success() {
268         RpcResult<CompositeNode> rpcResult = mock(RpcResult.class);
269         when(rpcResult.isSuccessful()).thenReturn(true);
270
271         CompositeNode compositeNode = mock( CompositeNode.class );
272         when( rpcResult.getResult() ).thenReturn( compositeNode );
273
274         BrokerFacade brokerFacade = mock(BrokerFacade.class);
275         when( brokerFacade.invokeRpc(
276                         eq(QName.create("(http://netconfcentral.org/ns/toaster?revision=2009-11-20)testOutput")),
277                         any( CompositeNode.class ))).thenReturn(rpcResult);
278
279         restconfImpl.setBroker(brokerFacade);
280
281         StructuredData output = restconfImpl.invokeRpc("toaster:testOutput",
282                 "");
283         assertNotNull( output );
284         assertSame( compositeNode, output.getData() );
285         assertNotNull( output.getSchema() );
286     }
287
288     @Test
289     public void testMountedRpcCallNoPayload_Success() throws Exception
290     {
291         RpcResult<CompositeNode> rpcResult = mock(RpcResult.class);
292         when(rpcResult.isSuccessful()).thenReturn(true);
293
294         ListenableFuture<RpcResult<CompositeNode>> mockListener = mock( ListenableFuture.class );
295         when( mockListener.get() ).thenReturn( rpcResult );
296
297         QName cancelToastQName = QName.create( "cancelToast" );
298
299         RpcDefinition mockRpc = mock( RpcDefinition.class );
300         when( mockRpc.getQName() ).thenReturn( cancelToastQName );
301
302         MountInstance mockMountPoint = mock( MountInstance.class );
303         when( mockMountPoint.rpc( eq( cancelToastQName ), any( CompositeNode.class ) ) )
304                                                                         .thenReturn( mockListener );
305
306         InstanceIdWithSchemaNode mockedInstanceId = mock( InstanceIdWithSchemaNode.class );
307         when( mockedInstanceId.getMountPoint() ).thenReturn( mockMountPoint );
308
309         ControllerContext mockedContext = mock( ControllerContext.class );
310         String cancelToastStr = "toaster:cancel-toast";
311         when( mockedContext.urlPathArgDecode( cancelToastStr ) ).thenReturn( cancelToastStr );
312         when( mockedContext.getRpcDefinition( cancelToastStr ) ).thenReturn( mockRpc );
313         when( mockedContext.toMountPointIdentifier(  "opendaylight-inventory:nodes/node/"
314                 + "REMOTE_HOST/yang-ext:mount/toaster:cancel-toast" ) ).thenReturn( mockedInstanceId );
315
316         restconfImpl.setControllerContext( mockedContext );
317         StructuredData output = restconfImpl.invokeRpc(
318                "opendaylight-inventory:nodes/node/REMOTE_HOST/yang-ext:mount/toaster:cancel-toast",
319                "");
320         assertEquals(null, output);
321
322         //additional validation in the fact that the restconfImpl does not throw an exception.
323     }
324
325
326 }