X-Git-Url: https://git.opendaylight.org/gerrit/gitweb?p=controller.git;a=blobdiff_plain;f=opendaylight%2Fmd-sal%2Fsal-rest-connector%2Fsrc%2Ftest%2Fjava%2Forg%2Fopendaylight%2Fcontroller%2Fsal%2Frestconf%2Fimpl%2Ftest%2FInvokeRpcMethodTest.java;h=2f045ce381ca0572cbeff4ad43147834fb59d2cf;hp=b42178a9c6cfbc965c92957b5e28420d4764c4bf;hb=51e91f6bdcc88c5aa96f956e516d31dbb5e5d5e0;hpb=b692b07e81933ff8c85a936a90a934cf778282e2 diff --git a/opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/InvokeRpcMethodTest.java b/opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/InvokeRpcMethodTest.java index b42178a9c6..2f045ce381 100644 --- a/opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/InvokeRpcMethodTest.java +++ b/opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/InvokeRpcMethodTest.java @@ -19,32 +19,38 @@ import static org.mockito.Mockito.mock; import static org.mockito.Mockito.spy; import static org.mockito.Mockito.when; +import com.google.common.base.Optional; +import com.google.common.util.concurrent.Futures; +import com.google.common.util.concurrent.ListenableFuture; import java.io.FileNotFoundException; import java.net.URI; import java.net.URISyntaxException; +import java.util.Arrays; +import java.util.Collections; import java.util.HashSet; -import java.util.LinkedList; import java.util.List; import java.util.Set; - -import javax.ws.rs.core.Response.Status; - +import javax.ws.rs.core.MultivaluedHashMap; +import javax.ws.rs.core.MultivaluedMap; +import javax.ws.rs.core.UriInfo; import org.junit.Before; import org.junit.BeforeClass; import org.junit.Test; -import org.mockito.ArgumentCaptor; -import org.mockito.invocation.InvocationOnMock; -import org.mockito.stubbing.Answer; -import org.opendaylight.controller.sal.core.api.mount.MountInstance; +import org.opendaylight.controller.md.sal.dom.api.DOMMountPoint; +import org.opendaylight.controller.sal.core.api.RpcProvisionRegistry; import org.opendaylight.controller.sal.restconf.impl.BrokerFacade; import org.opendaylight.controller.sal.restconf.impl.ControllerContext; import org.opendaylight.controller.sal.restconf.impl.InstanceIdWithSchemaNode; -import org.opendaylight.controller.sal.restconf.impl.ResponseException; +import org.opendaylight.controller.sal.restconf.impl.RestconfDocumentedException; +import org.opendaylight.controller.sal.restconf.impl.RestconfError; +import org.opendaylight.controller.sal.restconf.impl.RestconfError.ErrorTag; +import org.opendaylight.controller.sal.restconf.impl.RestconfError.ErrorType; import org.opendaylight.controller.sal.restconf.impl.RestconfImpl; import org.opendaylight.controller.sal.restconf.impl.StructuredData; import org.opendaylight.yangtools.yang.common.QName; import org.opendaylight.yangtools.yang.common.RpcError; import org.opendaylight.yangtools.yang.common.RpcResult; +import org.opendaylight.yangtools.yang.common.RpcResultBuilder; import org.opendaylight.yangtools.yang.data.api.CompositeNode; import org.opendaylight.yangtools.yang.data.api.ModifyAction; import org.opendaylight.yangtools.yang.data.api.MutableCompositeNode; @@ -54,50 +60,41 @@ import org.opendaylight.yangtools.yang.model.api.Module; import org.opendaylight.yangtools.yang.model.api.RpcDefinition; import org.opendaylight.yangtools.yang.model.api.SchemaContext; -import com.google.common.util.concurrent.ListenableFuture; - public class InvokeRpcMethodTest { private RestconfImpl restconfImpl = null; private static ControllerContext controllerContext = null; - - private class AnswerImpl implements Answer> { - @Override - public RpcResult answer(InvocationOnMock invocation) throws Throwable { - CompositeNode compNode = (CompositeNode) invocation.getArguments()[1]; - return new DummyRpcResult.Builder().result(compNode).isSuccessful(true).build(); - } - } + private static UriInfo uriInfo; @BeforeClass public static void init() throws FileNotFoundException { - Set allModules = new HashSet( TestUtils - .loadModulesFrom("/full-versions/yangs") ); - allModules.addAll( TestUtils.loadModulesFrom("/invoke-rpc") ); + Set allModules = new HashSet(TestUtils.loadModulesFrom("/full-versions/yangs")); + allModules.addAll(TestUtils.loadModulesFrom("/invoke-rpc")); assertNotNull(allModules); Module module = TestUtils.resolveModule("invoke-rpc-module", allModules); assertNotNull(module); SchemaContext schemaContext = TestUtils.loadSchemaContext(allModules); - controllerContext = spy( ControllerContext.getInstance() ); + controllerContext = spy(ControllerContext.getInstance()); controllerContext.setSchemas(schemaContext); - + uriInfo = mock(UriInfo.class); + MultivaluedMap map = new MultivaluedHashMap<>(); + map.put("prettyPrint", Collections.singletonList("true")); + when(uriInfo.getQueryParameters(any(Boolean.class))).thenReturn(map); } @Before - public void initMethod() - { + public void initMethod() { restconfImpl = RestconfImpl.getInstance(); - restconfImpl.setControllerContext( controllerContext ); + restconfImpl.setControllerContext(controllerContext); } /** - * Test method invokeRpc in RestconfImpl class tests if composite node as - * input parameter of method invokeRpc (second argument) is wrapped to - * parent composite node which has QName equals to QName of rpc (resolved - * from string - first argument). + * Test method invokeRpc in RestconfImpl class tests if composite node as input parameter of method invokeRpc + * (second argument) is wrapped to parent composite node which has QName equals to QName of rpc (resolved from + * string - first argument). */ @Test - public void invokeRpcMtethodTest() { + public void invokeRpcMethodTest() { ControllerContext contContext = controllerContext; try { contContext.findModuleNameByNamespace(new URI("invoke:rpc:module")); @@ -111,9 +108,12 @@ public class InvokeRpcMethodTest { restconf.setBroker(mockedBrokerFacade); restconf.setControllerContext(contContext); - when(mockedBrokerFacade.invokeRpc(any(QName.class), any(CompositeNode.class))).thenAnswer(new AnswerImpl()); + CompositeNode payload = preparePayload(); + + when(mockedBrokerFacade.invokeRpc(any(QName.class), any(CompositeNode.class))).thenReturn( + Futures.> immediateFuture(RpcResultBuilder.success().build())); - StructuredData structData = restconf.invokeRpc("invoke-rpc-module:rpc-test", preparePayload()); + StructuredData structData = restconf.invokeRpc("invoke-rpc-module:rpc-test", payload, uriInfo); assertTrue(structData == null); } @@ -123,7 +123,7 @@ public class InvokeRpcMethodTest { TestUtils.buildQName("cont", "nmspc", "2013-12-04"), null, null, ModifyAction.CREATE, null); MutableSimpleNode lf = NodeFactory.createMutableSimpleNode( TestUtils.buildQName("lf", "nmspc", "2013-12-04"), cont, "any value", ModifyAction.CREATE, null); - cont.getChildren().add(lf); + cont.getValue().add(lf); cont.init(); return cont; @@ -131,110 +131,123 @@ public class InvokeRpcMethodTest { @Test public void testInvokeRpcWithNoPayloadRpc_FailNoErrors() { - RpcResult rpcResult = mock(RpcResult.class); - when(rpcResult.isSuccessful()).thenReturn(false); + RpcResult rpcResult = RpcResultBuilder.failed().build(); - ArgumentCaptor payload = ArgumentCaptor - .forClass(CompositeNode.class); BrokerFacade brokerFacade = mock(BrokerFacade.class); when( brokerFacade.invokeRpc( eq(QName.create("(http://netconfcentral.org/ns/toaster?revision=2009-11-20)cancel-toast")), - payload.capture())).thenReturn(rpcResult); + any(CompositeNode.class))).thenReturn( + Futures.> immediateFuture(rpcResult)); restconfImpl.setBroker(brokerFacade); try { - restconfImpl.invokeRpc("toaster:cancel-toast", ""); + restconfImpl.invokeRpc("toaster:cancel-toast", "", uriInfo); fail("Expected an exception to be thrown."); - } catch (ResponseException e) { - assertEquals(e.getMessage(), - Status.INTERNAL_SERVER_ERROR.getStatusCode(), e - .getResponse().getStatus()); + } catch (RestconfDocumentedException e) { + verifyRestconfDocumentedException(e, 0, ErrorType.APPLICATION, ErrorTag.OPERATION_FAILED, + Optional. absent(), Optional. absent()); } } - @Test - public void testInvokeRpcWithNoPayloadRpc_FailWithRpcError() { - List rpcErrors = new LinkedList(); + void verifyRestconfDocumentedException(final RestconfDocumentedException e, final int index, + final ErrorType expErrorType, final ErrorTag expErrorTag, final Optional expErrorMsg, + final Optional expAppTag) { + RestconfError actual = null; + try { + actual = e.getErrors().get(index); + } catch (ArrayIndexOutOfBoundsException ex) { + fail("RestconfError not found at index " + index); + } + + assertEquals("getErrorType", expErrorType, actual.getErrorType()); + assertEquals("getErrorTag", expErrorTag, actual.getErrorTag()); + assertNotNull("getErrorMessage is null", actual.getErrorMessage()); + + if (expErrorMsg.isPresent()) { + assertEquals("getErrorMessage", expErrorMsg.get(), actual.getErrorMessage()); + } - RpcError unknownError = mock(RpcError.class); - when( unknownError.getTag() ).thenReturn( "bogusTag" ); - rpcErrors.add( unknownError ); + if (expAppTag.isPresent()) { + assertEquals("getErrorAppTag", expAppTag.get(), actual.getErrorAppTag()); + } + } - RpcError knownError = mock( RpcError.class ); - when( knownError.getTag() ).thenReturn( "in-use" ); - rpcErrors.add( knownError ); + @Test + public void testInvokeRpcWithNoPayloadRpc_FailWithRpcError() { + List rpcErrors = Arrays.asList( + RpcResultBuilder.newError( RpcError.ErrorType.TRANSPORT, "bogusTag", "foo" ), + RpcResultBuilder.newWarning( RpcError.ErrorType.RPC, "in-use", "bar", + "app-tag", null, null ) ); - RpcResult rpcResult = mock(RpcResult.class); - when(rpcResult.isSuccessful()).thenReturn(false); - when(rpcResult.getErrors()).thenReturn( rpcErrors ); + RpcResult rpcResult = RpcResultBuilder.failed() + .withRpcErrors(rpcErrors).build(); - ArgumentCaptor payload = ArgumentCaptor - .forClass(CompositeNode.class); BrokerFacade brokerFacade = mock(BrokerFacade.class); when( brokerFacade.invokeRpc( eq(QName.create("(http://netconfcentral.org/ns/toaster?revision=2009-11-20)cancel-toast")), - payload.capture())).thenReturn(rpcResult); + any(CompositeNode.class))).thenReturn( + Futures.> immediateFuture(rpcResult)); restconfImpl.setBroker(brokerFacade); try { - restconfImpl.invokeRpc("toaster:cancel-toast", ""); + restconfImpl.invokeRpc("toaster:cancel-toast", "", uriInfo); fail("Expected an exception to be thrown."); - } catch (ResponseException e) { - //TODO: Change to a 409 in the future - waiting on additional BUG to enhance this. - assertEquals(e.getMessage(), 500, e.getResponse().getStatus()); + } catch (RestconfDocumentedException e) { + verifyRestconfDocumentedException(e, 0, ErrorType.TRANSPORT, ErrorTag.OPERATION_FAILED, Optional.of("foo"), + Optional. absent()); + verifyRestconfDocumentedException(e, 1, ErrorType.RPC, ErrorTag.IN_USE, Optional.of("bar"), + Optional.of("app-tag")); } } @Test public void testInvokeRpcWithNoPayload_Success() { - RpcResult rpcResult = mock(RpcResult.class); - when(rpcResult.isSuccessful()).thenReturn(true); + RpcResult rpcResult = RpcResultBuilder.success().build(); BrokerFacade brokerFacade = mock(BrokerFacade.class); when( brokerFacade.invokeRpc( eq(QName.create("(http://netconfcentral.org/ns/toaster?revision=2009-11-20)cancel-toast")), - any( CompositeNode.class ))).thenReturn(rpcResult); + any(CompositeNode.class))).thenReturn( + Futures.> immediateFuture(rpcResult)); restconfImpl.setBroker(brokerFacade); - StructuredData output = restconfImpl.invokeRpc("toaster:cancel-toast", - ""); + StructuredData output = restconfImpl.invokeRpc("toaster:cancel-toast", "", uriInfo); assertEquals(null, output); - //additional validation in the fact that the restconfImpl does not throw an exception. + // additional validation in the fact that the restconfImpl does not + // throw an exception. } @Test public void testInvokeRpcMethodExpectingNoPayloadButProvidePayload() { try { - restconfImpl.invokeRpc("toaster:cancel-toast", " a payload "); + restconfImpl.invokeRpc("toaster:cancel-toast", " a payload ", uriInfo); fail("Expected an exception"); - } catch (ResponseException e) { - assertEquals(e.getMessage(), - Status.UNSUPPORTED_MEDIA_TYPE.getStatusCode(), e - .getResponse().getStatus()); + } catch (RestconfDocumentedException e) { + verifyRestconfDocumentedException(e, 0, ErrorType.PROTOCOL, ErrorTag.INVALID_VALUE, + Optional. absent(), Optional. absent()); } } @Test public void testInvokeRpcMethodWithBadMethodName() { try { - restconfImpl.invokeRpc("toaster:bad-method", ""); + restconfImpl.invokeRpc("toaster:bad-method", "", uriInfo); fail("Expected an exception"); - } catch (ResponseException e) { - assertEquals(e.getMessage(), Status.NOT_FOUND.getStatusCode(), e - .getResponse().getStatus()); + } catch (RestconfDocumentedException e) { + verifyRestconfDocumentedException(e, 0, ErrorType.RPC, ErrorTag.UNKNOWN_ELEMENT, + Optional. absent(), Optional. absent()); } } @Test public void testInvokeRpcMethodWithInput() { - RpcResult rpcResult = mock(RpcResult.class); - when(rpcResult.isSuccessful()).thenReturn(true); + RpcResult rpcResult = RpcResultBuilder.success().build(); CompositeNode payload = mock(CompositeNode.class); @@ -242,85 +255,101 @@ public class InvokeRpcMethodTest { when( brokerFacade.invokeRpc( eq(QName.create("(http://netconfcentral.org/ns/toaster?revision=2009-11-20)make-toast")), - any(CompositeNode.class))).thenReturn(rpcResult); + any(CompositeNode.class))).thenReturn( + Futures.> immediateFuture(rpcResult)); restconfImpl.setBroker(brokerFacade); - StructuredData output = restconfImpl.invokeRpc("toaster:make-toast", - payload); + StructuredData output = restconfImpl.invokeRpc("toaster:make-toast", payload, uriInfo); assertEquals(null, output); - //additional validation in the fact that the restconfImpl does not throw an exception. + // additional validation in the fact that the restconfImpl does not + // throw an exception. } @Test public void testThrowExceptionWhenSlashInModuleName() { try { - restconfImpl.invokeRpc("toaster/slash", ""); + restconfImpl.invokeRpc("toaster/slash", "", uriInfo); fail("Expected an exception."); - } catch (ResponseException e) { - assertEquals(e.getMessage(), Status.NOT_FOUND.getStatusCode(), e - .getResponse().getStatus()); + } catch (RestconfDocumentedException e) { + verifyRestconfDocumentedException(e, 0, ErrorType.PROTOCOL, ErrorTag.INVALID_VALUE, + Optional. absent(), Optional. absent()); } } @Test public void testInvokeRpcWithNoPayloadWithOutput_Success() { - RpcResult rpcResult = mock(RpcResult.class); - when(rpcResult.isSuccessful()).thenReturn(true); - - CompositeNode compositeNode = mock( CompositeNode.class ); - when( rpcResult.getResult() ).thenReturn( compositeNode ); + CompositeNode compositeNode = mock(CompositeNode.class); + RpcResult rpcResult = + RpcResultBuilder.success(compositeNode).build(); BrokerFacade brokerFacade = mock(BrokerFacade.class); - when( brokerFacade.invokeRpc( + when( + brokerFacade.invokeRpc( eq(QName.create("(http://netconfcentral.org/ns/toaster?revision=2009-11-20)testOutput")), - any( CompositeNode.class ))).thenReturn(rpcResult); + any(CompositeNode.class))).thenReturn( + Futures.> immediateFuture(rpcResult)); restconfImpl.setBroker(brokerFacade); - StructuredData output = restconfImpl.invokeRpc("toaster:testOutput", - ""); - assertNotNull( output ); - assertSame( compositeNode, output.getData() ); - assertNotNull( output.getSchema() ); + StructuredData output = restconfImpl.invokeRpc("toaster:testOutput", "", uriInfo); + assertNotNull(output); + assertSame(compositeNode, output.getData()); + assertNotNull(output.getSchema()); } + /** + * + * Tests calling of RestConfImpl method invokeRpc. In the method there is searched rpc in remote schema context. + * This rpc is then executed. + * + * I wasn't able to simulate calling of rpc on remote device therefore this testing method raise method when rpc is + * invoked. + */ @Test - public void testMountedRpcCallNoPayload_Success() throws Exception - { - RpcResult rpcResult = mock(RpcResult.class); - when(rpcResult.isSuccessful()).thenReturn(true); + public void testMountedRpcCallNoPayload_Success() throws Exception { + RpcResult rpcResult = RpcResultBuilder.success().build(); - ListenableFuture> mockListener = mock( ListenableFuture.class ); - when( mockListener.get() ).thenReturn( rpcResult ); + ListenableFuture> mockListener = mock(ListenableFuture.class); + when(mockListener.get()).thenReturn(rpcResult); - QName cancelToastQName = QName.create( "cancelToast" ); + QName cancelToastQName = QName.create("namespace", "2014-05-28", "cancelToast"); - RpcDefinition mockRpc = mock( RpcDefinition.class ); - when( mockRpc.getQName() ).thenReturn( cancelToastQName ); + RpcDefinition mockRpc = mock(RpcDefinition.class); + when(mockRpc.getQName()).thenReturn(cancelToastQName); - MountInstance mockMountPoint = mock( MountInstance.class ); - when( mockMountPoint.rpc( eq( cancelToastQName ), any( CompositeNode.class ) ) ) - .thenReturn( mockListener ); + DOMMountPoint mockMountPoint = mock(DOMMountPoint.class); + RpcProvisionRegistry mockedRpcProvisionRegistry = mock(RpcProvisionRegistry.class); + when(mockedRpcProvisionRegistry.invokeRpc(eq(cancelToastQName), any(CompositeNode.class))).thenReturn(mockListener); + when(mockMountPoint.getService(eq(RpcProvisionRegistry.class))).thenReturn(Optional.of(mockedRpcProvisionRegistry)); + when(mockMountPoint.getSchemaContext()).thenReturn(TestUtils.loadSchemaContext("/invoke-rpc")); - InstanceIdWithSchemaNode mockedInstanceId = mock( InstanceIdWithSchemaNode.class ); - when( mockedInstanceId.getMountPoint() ).thenReturn( mockMountPoint ); + InstanceIdWithSchemaNode mockedInstanceId = mock(InstanceIdWithSchemaNode.class); + when(mockedInstanceId.getMountPoint()).thenReturn(mockMountPoint); - ControllerContext mockedContext = mock( ControllerContext.class ); - String cancelToastStr = "toaster:cancel-toast"; - when( mockedContext.urlPathArgDecode( cancelToastStr ) ).thenReturn( cancelToastStr ); - when( mockedContext.getRpcDefinition( cancelToastStr ) ).thenReturn( mockRpc ); - when( mockedContext.toMountPointIdentifier( "opendaylight-inventory:nodes/node/" - + "REMOTE_HOST/yang-ext:mount/toaster:cancel-toast" ) ).thenReturn( mockedInstanceId ); + ControllerContext mockedContext = mock(ControllerContext.class); + String rpcNoop = "invoke-rpc-module:rpc-noop"; + when(mockedContext.urlPathArgDecode(rpcNoop)).thenReturn(rpcNoop); + when(mockedContext.getRpcDefinition(rpcNoop)).thenReturn(mockRpc); + when( + mockedContext.toMountPointIdentifier(eq("opendaylight-inventory:nodes/node/" + + "REMOTE_HOST/yang-ext:mount/invoke-rpc-module:rpc-noop"))).thenReturn(mockedInstanceId); - restconfImpl.setControllerContext( mockedContext ); - StructuredData output = restconfImpl.invokeRpc( - "opendaylight-inventory:nodes/node/REMOTE_HOST/yang-ext:mount/toaster:cancel-toast", - ""); - assertEquals(null, output); + restconfImpl.setControllerContext(mockedContext); + try { + restconfImpl.invokeRpc( + "opendaylight-inventory:nodes/node/REMOTE_HOST/yang-ext:mount/invoke-rpc-module:rpc-noop", "", + uriInfo); + fail("RestconfDocumentedException wasn't raised"); + } catch (RestconfDocumentedException e) { + List errors = e.getErrors(); + assertNotNull(errors); + assertEquals(1, errors.size()); + assertEquals(ErrorType.APPLICATION, errors.iterator().next().getErrorType()); + assertEquals(ErrorTag.OPERATION_FAILED, errors.iterator().next().getErrorTag()); + } - //additional validation in the fact that the restconfImpl does not throw an exception. + // additional validation in the fact that the restconfImpl does not + // throw an exception. } - - }