2 * Copyright (c) 2014 Cisco Systems, Inc. and others. All rights reserved.
3 * Copyright (c) 2014 Brocade Communications Systems, Inc.
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
9 package org.opendaylight.controller.sal.restconf.impl.test;
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;
22 import java.io.FileNotFoundException;
24 import java.net.URISyntaxException;
25 import java.util.HashSet;
26 import java.util.LinkedList;
27 import java.util.List;
30 import javax.ws.rs.core.Response.Status;
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;
57 import com.google.common.util.concurrent.ListenableFuture;
59 public class InvokeRpcMethodTest {
61 private RestconfImpl restconfImpl = null;
62 private static ControllerContext controllerContext = null;
64 private class AnswerImpl implements Answer<RpcResult<CompositeNode>> {
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();
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);
87 public void initMethod()
89 restconfImpl = RestconfImpl.getInstance();
90 restconfImpl.setControllerContext( controllerContext );
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).
100 public void invokeRpcMtethodTest() {
101 ControllerContext contContext = controllerContext;
103 contContext.findModuleNameByNamespace(new URI("invoke:rpc:module"));
104 } catch (URISyntaxException e) {
105 assertTrue("Uri wasn't created sucessfuly", false);
108 BrokerFacade mockedBrokerFacade = mock(BrokerFacade.class);
110 RestconfImpl restconf = RestconfImpl.getInstance();
111 restconf.setBroker(mockedBrokerFacade);
112 restconf.setControllerContext(contContext);
114 when(mockedBrokerFacade.invokeRpc(any(QName.class), any(CompositeNode.class))).thenAnswer(new AnswerImpl());
116 StructuredData structData = restconf.invokeRpc("invoke-rpc-module:rpc-test", preparePayload());
117 assertTrue(structData == null);
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);
133 public void testInvokeRpcWithNoPayloadRpc_FailNoErrors() {
134 RpcResult<CompositeNode> rpcResult = mock(RpcResult.class);
135 when(rpcResult.isSuccessful()).thenReturn(false);
137 ArgumentCaptor<CompositeNode> payload = ArgumentCaptor
138 .forClass(CompositeNode.class);
139 BrokerFacade brokerFacade = mock(BrokerFacade.class);
141 brokerFacade.invokeRpc(
142 eq(QName.create("(http://netconfcentral.org/ns/toaster?revision=2009-11-20)cancel-toast")),
143 payload.capture())).thenReturn(rpcResult);
145 restconfImpl.setBroker(brokerFacade);
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());
158 public void testInvokeRpcWithNoPayloadRpc_FailWithRpcError() {
159 List<RpcError> rpcErrors = new LinkedList<RpcError>();
161 RpcError unknownError = mock(RpcError.class);
162 when( unknownError.getTag() ).thenReturn( "bogusTag" );
163 rpcErrors.add( unknownError );
165 RpcError knownError = mock( RpcError.class );
166 when( knownError.getTag() ).thenReturn( "in-use" );
167 rpcErrors.add( knownError );
169 RpcResult<CompositeNode> rpcResult = mock(RpcResult.class);
170 when(rpcResult.isSuccessful()).thenReturn(false);
171 when(rpcResult.getErrors()).thenReturn( rpcErrors );
173 ArgumentCaptor<CompositeNode> payload = ArgumentCaptor
174 .forClass(CompositeNode.class);
175 BrokerFacade brokerFacade = mock(BrokerFacade.class);
177 brokerFacade.invokeRpc(
178 eq(QName.create("(http://netconfcentral.org/ns/toaster?revision=2009-11-20)cancel-toast")),
179 payload.capture())).thenReturn(rpcResult);
181 restconfImpl.setBroker(brokerFacade);
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());
193 public void testInvokeRpcWithNoPayload_Success() {
194 RpcResult<CompositeNode> rpcResult = mock(RpcResult.class);
195 when(rpcResult.isSuccessful()).thenReturn(true);
197 BrokerFacade brokerFacade = mock(BrokerFacade.class);
199 brokerFacade.invokeRpc(
200 eq(QName.create("(http://netconfcentral.org/ns/toaster?revision=2009-11-20)cancel-toast")),
201 any( CompositeNode.class ))).thenReturn(rpcResult);
203 restconfImpl.setBroker(brokerFacade);
205 StructuredData output = restconfImpl.invokeRpc("toaster:cancel-toast",
207 assertEquals(null, output);
208 //additional validation in the fact that the restconfImpl does not throw an exception.
212 public void testInvokeRpcMethodExpectingNoPayloadButProvidePayload() {
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());
224 public void testInvokeRpcMethodWithBadMethodName() {
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());
235 public void testInvokeRpcMethodWithInput() {
236 RpcResult<CompositeNode> rpcResult = mock(RpcResult.class);
237 when(rpcResult.isSuccessful()).thenReturn(true);
239 CompositeNode payload = mock(CompositeNode.class);
241 BrokerFacade brokerFacade = mock(BrokerFacade.class);
243 brokerFacade.invokeRpc(
244 eq(QName.create("(http://netconfcentral.org/ns/toaster?revision=2009-11-20)make-toast")),
245 any(CompositeNode.class))).thenReturn(rpcResult);
247 restconfImpl.setBroker(brokerFacade);
249 StructuredData output = restconfImpl.invokeRpc("toaster:make-toast",
251 assertEquals(null, output);
252 //additional validation in the fact that the restconfImpl does not throw an exception.
256 public void testThrowExceptionWhenSlashInModuleName() {
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());
267 public void testInvokeRpcWithNoPayloadWithOutput_Success() {
268 RpcResult<CompositeNode> rpcResult = mock(RpcResult.class);
269 when(rpcResult.isSuccessful()).thenReturn(true);
271 CompositeNode compositeNode = mock( CompositeNode.class );
272 when( rpcResult.getResult() ).thenReturn( compositeNode );
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);
279 restconfImpl.setBroker(brokerFacade);
281 StructuredData output = restconfImpl.invokeRpc("toaster:testOutput",
283 assertNotNull( output );
284 assertSame( compositeNode, output.getData() );
285 assertNotNull( output.getSchema() );
289 public void testMountedRpcCallNoPayload_Success() throws Exception
291 RpcResult<CompositeNode> rpcResult = mock(RpcResult.class);
292 when(rpcResult.isSuccessful()).thenReturn(true);
294 ListenableFuture<RpcResult<CompositeNode>> mockListener = mock( ListenableFuture.class );
295 when( mockListener.get() ).thenReturn( rpcResult );
297 QName cancelToastQName = QName.create( "cancelToast" );
299 RpcDefinition mockRpc = mock( RpcDefinition.class );
300 when( mockRpc.getQName() ).thenReturn( cancelToastQName );
302 MountInstance mockMountPoint = mock( MountInstance.class );
303 when( mockMountPoint.rpc( eq( cancelToastQName ), any( CompositeNode.class ) ) )
304 .thenReturn( mockListener );
306 InstanceIdWithSchemaNode mockedInstanceId = mock( InstanceIdWithSchemaNode.class );
307 when( mockedInstanceId.getMountPoint() ).thenReturn( mockMountPoint );
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 );
316 restconfImpl.setControllerContext( mockedContext );
317 StructuredData output = restconfImpl.invokeRpc(
318 "opendaylight-inventory:nodes/node/REMOTE_HOST/yang-ext:mount/toaster:cancel-toast",
320 assertEquals(null, output);
322 //additional validation in the fact that the restconfImpl does not throw an exception.