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=b90097bc94a0e7888b589f33960343cc94d36c12;hp=b42178a9c6cfbc965c92957b5e28420d4764c4bf;hb=a9533db1d57a2729772ee192a2f96d358c71bede;hpb=b78e63501576638e1f000fd46663f8c42340f9e2 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..b90097bc94 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,31 +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.common.util.RpcErrors; +import org.opendaylight.controller.sal.common.util.Rpcs; import org.opendaylight.controller.sal.core.api.mount.MountInstance; 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.RpcError.ErrorSeverity; import org.opendaylight.yangtools.yang.common.RpcResult; import org.opendaylight.yangtools.yang.data.api.CompositeNode; import org.opendaylight.yangtools.yang.data.api.ModifyAction; @@ -54,20 +61,12 @@ 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 static UriInfo uriInfo; - 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(); - } - } @BeforeClass public static void init() throws FileNotFoundException { @@ -80,7 +79,10 @@ public class InvokeRpcMethodTest { SchemaContext schemaContext = TestUtils.loadSchemaContext(allModules); 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 @@ -111,9 +113,13 @@ public class InvokeRpcMethodTest { restconf.setBroker(mockedBrokerFacade); restconf.setControllerContext(contContext); - when(mockedBrokerFacade.invokeRpc(any(QName.class), any(CompositeNode.class))).thenAnswer(new AnswerImpl()); + CompositeNode payload = preparePayload(); - StructuredData structData = restconf.invokeRpc("invoke-rpc-module:rpc-test", preparePayload()); + when(mockedBrokerFacade.invokeRpc(any(QName.class), any(CompositeNode.class))) + .thenReturn( Futures.>immediateFuture( + Rpcs.getRpcResult( true ) ) ); + + StructuredData structData = restconf.invokeRpc("invoke-rpc-module:rpc-test", payload,uriInfo); assertTrue(structData == null); } @@ -123,7 +129,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,79 +137,95 @@ public class InvokeRpcMethodTest { @Test public void testInvokeRpcWithNoPayloadRpc_FailNoErrors() { - RpcResult rpcResult = mock(RpcResult.class); - when(rpcResult.isSuccessful()).thenReturn(false); + RpcResult rpcResult = Rpcs.getRpcResult( false ); - 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); + when( brokerFacade.invokeRpc( + eq(QName.create("(http://netconfcentral.org/ns/toaster?revision=2009-11-20)cancel-toast")), + 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.RPC, 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 ); + } - RpcError unknownError = mock(RpcError.class); - when( unknownError.getTag() ).thenReturn( "bogusTag" ); - rpcErrors.add( unknownError ); + assertEquals( "getErrorType", expErrorType, actual.getErrorType() ); + assertEquals( "getErrorTag", expErrorTag, actual.getErrorTag() ); + assertNotNull( "getErrorMessage is null", actual.getErrorMessage() ); - RpcError knownError = mock( RpcError.class ); - when( knownError.getTag() ).thenReturn( "in-use" ); - rpcErrors.add( knownError ); + if( expErrorMsg.isPresent() ) { + assertEquals( "getErrorMessage", expErrorMsg.get(), actual.getErrorMessage() ); + } + + if( expAppTag.isPresent() ) { + assertEquals( "getErrorAppTag", expAppTag.get(), actual.getErrorAppTag() ); + } + } - RpcResult rpcResult = mock(RpcResult.class); - when(rpcResult.isSuccessful()).thenReturn(false); - when(rpcResult.getErrors()).thenReturn( rpcErrors ); + @Test + public void testInvokeRpcWithNoPayloadRpc_FailWithRpcError() { + List rpcErrors = Arrays.asList( + RpcErrors.getRpcError( null, "bogusTag", null, ErrorSeverity.ERROR, "foo", + RpcError.ErrorType.TRANSPORT, null ), + RpcErrors.getRpcError( "app-tag", "in-use", null, ErrorSeverity.WARNING, "bar", + RpcError.ErrorType.RPC, null )); + + RpcResult rpcResult = Rpcs.getRpcResult( false, rpcErrors ); - 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); + when( brokerFacade.invokeRpc( + eq(QName.create("(http://netconfcentral.org/ns/toaster?revision=2009-11-20)cancel-toast")), + 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 = Rpcs.getRpcResult( true ); 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); + when( brokerFacade.invokeRpc( + eq(QName.create("(http://netconfcentral.org/ns/toaster?revision=2009-11-20)cancel-toast")), + any( CompositeNode.class ))) + .thenReturn( Futures.>immediateFuture( rpcResult ) ); restconfImpl.setBroker(brokerFacade); StructuredData output = restconfImpl.invokeRpc("toaster:cancel-toast", - ""); + "",uriInfo); assertEquals(null, output); //additional validation in the fact that the restconfImpl does not throw an exception. } @@ -211,43 +233,42 @@ public class InvokeRpcMethodTest { @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 = Rpcs.getRpcResult( true ); CompositeNode payload = mock(CompositeNode.class); BrokerFacade brokerFacade = mock(BrokerFacade.class); - when( - brokerFacade.invokeRpc( - eq(QName.create("(http://netconfcentral.org/ns/toaster?revision=2009-11-20)make-toast")), - any(CompositeNode.class))).thenReturn(rpcResult); + when( brokerFacade.invokeRpc( + eq(QName.create("(http://netconfcentral.org/ns/toaster?revision=2009-11-20)make-toast")), + any(CompositeNode.class))) + .thenReturn( Futures.>immediateFuture( rpcResult ) ); restconfImpl.setBroker(brokerFacade); StructuredData output = restconfImpl.invokeRpc("toaster:make-toast", - payload); + payload,uriInfo); assertEquals(null, output); //additional validation in the fact that the restconfImpl does not throw an exception. } @@ -255,31 +276,30 @@ public class InvokeRpcMethodTest { @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 ); + RpcResult rpcResult = Rpcs.getRpcResult( true, compositeNode, + Collections.emptyList() ); BrokerFacade brokerFacade = mock(BrokerFacade.class); 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", - ""); + StructuredData output = restconfImpl.invokeRpc("toaster:testOutput", "",uriInfo); assertNotNull( output ); assertSame( compositeNode, output.getData() ); assertNotNull( output.getSchema() ); @@ -288,20 +308,19 @@ public class InvokeRpcMethodTest { @Test public void testMountedRpcCallNoPayload_Success() throws Exception { - RpcResult rpcResult = mock(RpcResult.class); - when(rpcResult.isSuccessful()).thenReturn(true); + RpcResult rpcResult = Rpcs.getRpcResult( true ); 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 ); MountInstance mockMountPoint = mock( MountInstance.class ); when( mockMountPoint.rpc( eq( cancelToastQName ), any( CompositeNode.class ) ) ) - .thenReturn( mockListener ); + .thenReturn( mockListener ); InstanceIdWithSchemaNode mockedInstanceId = mock( InstanceIdWithSchemaNode.class ); when( mockedInstanceId.getMountPoint() ).thenReturn( mockMountPoint ); @@ -315,12 +334,10 @@ public class InvokeRpcMethodTest { restconfImpl.setControllerContext( mockedContext ); StructuredData output = restconfImpl.invokeRpc( - "opendaylight-inventory:nodes/node/REMOTE_HOST/yang-ext:mount/toaster:cancel-toast", - ""); + "opendaylight-inventory:nodes/node/REMOTE_HOST/yang-ext:mount/toaster:cancel-toast", + "",uriInfo); assertEquals(null, output); //additional validation in the fact that the restconfImpl does not throw an exception. } - - }