/* * Copyright (C) 2006-2016 DLR, Germany * * All rights reserved * * http://www.rcenvironment.de/ */ package de.rcenvironment.core.communication.rpc.internal; import static de.rcenvironment.core.communication.testutils.CommunicationTestHelper.LOCAL_LOGICAL_NODE_SESSION_ID; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; import java.io.IOException; import java.io.Serializable; import java.util.HashMap; import java.util.List; import java.util.Map; import org.easymock.EasyMock; import org.junit.After; import org.junit.Before; import org.junit.Test; import org.osgi.framework.Bundle; import org.osgi.framework.BundleActivator; import de.rcenvironment.core.communication.api.PlatformService; import de.rcenvironment.core.communication.common.CommunicationException; import de.rcenvironment.core.communication.common.InstanceNodeSessionId; import de.rcenvironment.core.communication.common.LogicalNodeSessionId; import de.rcenvironment.core.communication.common.NodeIdentifierTestUtils; import de.rcenvironment.core.communication.internal.LiveNetworkIdResolutionServiceImpl; import de.rcenvironment.core.communication.legacy.internal.NetworkContact; import de.rcenvironment.core.communication.model.NetworkRequest; import de.rcenvironment.core.communication.model.NetworkResponse; import de.rcenvironment.core.communication.protocol.NetworkRequestFactory; import de.rcenvironment.core.communication.protocol.NetworkResponseFactory; import de.rcenvironment.core.communication.protocol.ProtocolConstants; import de.rcenvironment.core.communication.routing.MessageRoutingService; import de.rcenvironment.core.communication.rpc.ServiceCallRequest; import de.rcenvironment.core.communication.rpc.ServiceCallResult; import de.rcenvironment.core.communication.rpc.ServiceCallResultFactory; import de.rcenvironment.core.communication.rpc.api.CallbackProxyService; import de.rcenvironment.core.communication.rpc.api.CallbackService; import de.rcenvironment.core.communication.spi.CallbackObject; import de.rcenvironment.core.communication.testutils.PlatformServiceDefaultStub; import de.rcenvironment.core.communication.utils.MessageUtils; import de.rcenvironment.core.utils.common.rpc.RemoteOperationException; /** * Test cases for {@link ServiceProxyFactoryImpl}. * * @author Doreen Seider * @author Robert Mischke (reworked for 2.5.0+; 8.0.0 id adaptations) */ public class ServiceProxyFactoryImplTest { private static final LogicalNodeSessionId LOCAL_NODE_ID = NodeIdentifierTestUtils .createTestLogicalNodeSessionIdWithDisplayName("mockLocalNode", true); private static final InstanceNodeSessionId LOCAL_INSTANCE_SESSION_ID = LOCAL_NODE_ID.convertToInstanceNodeSessionId(); private final int sum = 3; private final ServiceCallResult addResult = ServiceCallResultFactory.wrapReturnValue(sum); private final ServiceCallResult callbackResult = ServiceCallResultFactory.wrapReturnValue(new Serializable() { private static final long serialVersionUID = -35724097511389572L; }); private final String value = new String("value"); private final ServiceCallResult valueResult = ServiceCallResultFactory.wrapReturnValue(value); private final IOException exception = new IOException("Simulated test exception"); private final ServiceCallResult exceptionResult = ServiceCallResultFactory.wrapMethodException(exception); private ServiceProxyFactoryImpl serviceProxyFactory; private RemoteServiceCallSenderServiceImpl remoteServiceCallService; private LiveNetworkIdResolutionServiceImpl liveIdResolver; /** * Common setup. */ @Before public void setUp() { // note that the routing service is bound in the individual tests - misc_ro remoteServiceCallService = new RemoteServiceCallSenderServiceImpl(); liveIdResolver = new LiveNetworkIdResolutionServiceImpl(); liveIdResolver.registerLocalInstanceNodeSessionId(LOCAL_INSTANCE_SESSION_ID); serviceProxyFactory = new ServiceProxyFactoryImpl(); serviceProxyFactory.bindCallbackService(new DummyCallbackService()); serviceProxyFactory.bindCallbackProxyService(EasyMock.createNiceMock(CallbackProxyService.class)); serviceProxyFactory.bindPlatformService(new DummyPlatformService()); serviceProxyFactory.bindRemoteServiceCallService(remoteServiceCallService); serviceProxyFactory.bindLiveNetworkIdResolutionService(liveIdResolver); } /** * Common teardown. */ @After public void tearDown() { serviceProxyFactory = null; } /** Test. **/ @Test public void testCreateServiceProxyForSuccess() { Object proxy = serviceProxyFactory.createServiceProxy(LOCAL_NODE_ID, MethodCallTestInterface.class, null); assertTrue(proxy instanceof MethodCallTestInterface); proxy = serviceProxyFactory.createServiceProxy(LOCAL_NODE_ID, MethodCallTestInterface.class, new Class<?>[] { BundleActivator.class, Bundle.class }); assertTrue(proxy instanceof MethodCallTestInterface); assertTrue(proxy instanceof BundleActivator); assertTrue(proxy instanceof Bundle); proxy = serviceProxyFactory.createServiceProxy(LOCAL_NODE_ID, MethodCallTestInterface.class, null); assertTrue(proxy instanceof MethodCallTestInterface); proxy = serviceProxyFactory.createServiceProxy(LOCAL_NODE_ID, MethodCallTestInterface.class, null); assertTrue(proxy instanceof MethodCallTestInterface); Map<String, String> properties = new HashMap<String, String>(); properties.put("rumpel", "false"); properties.put("pumpel", "true"); proxy = serviceProxyFactory.createServiceProxy(LOCAL_NODE_ID, MethodCallTestInterface.class, null); assertTrue(proxy instanceof MethodCallTestInterface); } /** * Tests an RPC call with an return value of type "int". * * @throws RemoteOperationException not expected; would indicate a test error */ @Test public void testNativeReturnValue() throws RemoteOperationException { MethodCallTestInterface proxy = (MethodCallTestInterface) serviceProxyFactory.createServiceProxy(LOCAL_NODE_ID, MethodCallTestInterface.class, null); Serializable expectedReturnValue; // create a network mock that simulates the remote generation of the expected result expectedReturnValue = Integer.valueOf(new MethodCallTestInterfaceImpl().add(1, 2)); MessageRoutingService routingServiceMock = createSingleCallNetworkMock(ServiceCallResultFactory.wrapReturnValue(expectedReturnValue)); remoteServiceCallService.bindMessageRoutingService(routingServiceMock); EasyMock.replay(routingServiceMock); assertEquals(3, proxy.add(1, 2)); EasyMock.verify(routingServiceMock); } /** * Tests an RPC call with a String return value. * * @throws RemoteOperationException not expected; would indicate a test error */ @Test public void testStringReturnValue() throws RemoteOperationException { MethodCallTestInterface proxy = (MethodCallTestInterface) serviceProxyFactory.createServiceProxy(LOCAL_NODE_ID, MethodCallTestInterface.class, null); Serializable expectedReturnValue; // create a network mock that simulates the remote generation of the expected result expectedReturnValue = new MethodCallTestInterfaceImpl().getString(); MessageRoutingService routingServiceMock = createSingleCallNetworkMock(ServiceCallResultFactory.wrapReturnValue(expectedReturnValue)); remoteServiceCallService.bindMessageRoutingService(routingServiceMock); EasyMock.replay(routingServiceMock); assertEquals(expectedReturnValue, proxy.getString()); EasyMock.verify(routingServiceMock); } /** * Tests that passing a callback object as a remote method parameter succeeds. * * @throws RemoteOperationException not expected; would indicate a test error **/ @Test public void testCallbackParameterDoesNotFail() throws RemoteOperationException { MethodCallTestInterface proxy = (MethodCallTestInterface) serviceProxyFactory.createServiceProxy(LOCAL_NODE_ID, MethodCallTestInterface.class, null); Serializable expectedReturnValue; // create a network mock that simulates the remote generation of the expected result expectedReturnValue = Integer.valueOf(3); MessageRoutingService routingServiceMock = createSingleCallNetworkMock(ServiceCallResultFactory.wrapReturnValue(expectedReturnValue)); remoteServiceCallService.bindMessageRoutingService(routingServiceMock); EasyMock.replay(routingServiceMock); // TODO check: test probably too weak // TODO add test for callback object return value, too? proxy.callbackTest(new DummyObject()); EasyMock.verify(routingServiceMock); } /** * Tests that exceptions throw by the target method are correctly forwarded to the caller. * * @throws RemoteOperationException not expected; would indicate a test error */ @Test public void testRemoteExceptionThrowing() throws RemoteOperationException { MethodCallTestInterface proxy = (MethodCallTestInterface) serviceProxyFactory.createServiceProxy(LOCAL_NODE_ID, MethodCallTestInterface.class, null); // create a network mock that simulates the remote generation of the expected result MessageRoutingService routingServiceMock = createSingleCallNetworkMock(ServiceCallResultFactory.wrapMethodException(exception)); remoteServiceCallService.bindMessageRoutingService(routingServiceMock); EasyMock.replay(routingServiceMock); try { proxy.ioExceptionThrower(); fail(); } catch (IOException e) { assertTrue(true); } EasyMock.verify(routingServiceMock); } /** * Test. * * TODO improve Javadoc */ @Test public void testCreateServiceProxyForFailure() { try { serviceProxyFactory.createServiceProxy(null, MethodCallTestInterface.class, null); fail(); } catch (IllegalArgumentException e) { assertTrue(true); } try { serviceProxyFactory.createServiceProxy(LOCAL_LOGICAL_NODE_SESSION_ID, null, null); fail(); } catch (IllegalArgumentException e) { assertTrue(true); } } private MessageRoutingService createSingleCallNetworkMock(final ServiceCallResult serviceCallResult) { // define expected calls MessageRoutingService routingServiceMock = EasyMock.createMock(MessageRoutingService.class); // a request is not available in this mock, so fake a request NetworkRequest request = NetworkRequestFactory .createNetworkRequest(null, ProtocolConstants.VALUE_MESSAGE_TYPE_RPC, LOCAL_INSTANCE_SESSION_ID, LOCAL_INSTANCE_SESSION_ID); NetworkResponse networkResponseMock = NetworkResponseFactory.generateSuccessResponse(request, MessageUtils.serializeSafeObject(serviceCallResult)); EasyMock.expect(routingServiceMock.performRoutedRequest(EasyMock.anyObject(byte[].class), EasyMock.eq(ProtocolConstants.VALUE_MESSAGE_TYPE_RPC), EasyMock.eq(LOCAL_INSTANCE_SESSION_ID))) .andReturn(networkResponseMock); return routingServiceMock; } /** * Test {@link ServiceCallSenderFactory} implementation. * * @author Doreen Seider */ private class DummyServiceCallSenderFactory implements ServiceCallSenderFactory { @Override public ServiceCallSender createServiceCallSender(NetworkContact contact) throws CommunicationException { return new DummyServiceCallSender(); } } /** * Test {@link ServiceCallSender} implementation. * * @author Doreen Seider */ private class DummyServiceCallSender implements ServiceCallSender { @Override public void initialize(NetworkContact contact) throws CommunicationException {} @Override public ServiceCallResult send(ServiceCallRequest serviceCallRequest) throws RemoteOperationException { ServiceCallResult result = null; if (serviceCallRequest.getTargetNodeId().equals(LOCAL_NODE_ID) && serviceCallRequest.getServiceName().equals(MethodCallTestInterface.class.getCanonicalName()) && serviceCallRequest.getMethodName().equals("add") && serviceCallRequest.getParameterList().get(0).equals(1) && serviceCallRequest.getParameterList().get(1).equals(2) && serviceCallRequest.getParameterList().size() == 2) { result = addResult; } else if (serviceCallRequest.getTargetNodeId().equals(LOCAL_NODE_ID) && serviceCallRequest.getServiceName().equals(MethodCallTestInterface.class.getCanonicalName()) && serviceCallRequest.getMethodName().equals("callbackTest") && (serviceCallRequest.getParameterList().get(0) instanceof CallbackProxy) && serviceCallRequest.getParameterList().size() == 1) { result = callbackResult; } else if (serviceCallRequest.getTargetNodeId().equals(LOCAL_NODE_ID) && serviceCallRequest.getServiceName().equals(MethodCallTestInterface.class.getCanonicalName()) && serviceCallRequest.getMethodName().equals("getValue") && serviceCallRequest.getParameterList().size() == 0) { result = valueResult; } else if (serviceCallRequest.getTargetNodeId().equals(LOCAL_NODE_ID) && serviceCallRequest.getServiceName().equals(MethodCallTestInterface.class.getCanonicalName()) && serviceCallRequest.getMethodName().equals("exceptionFunction") && serviceCallRequest.getParameterList().size() == 0) { result = exceptionResult; } return result; } } /** * Test object to call back. * * @author Doreen Seider */ private class DummyObject implements DummyInterface, Serializable { private static final long serialVersionUID = 1L; @Override public Class<?> getInterface() { return DummyInterface.class; } @Override public Object makePeng() { return null; } @Override public Object makePuff(String string) { return null; } } /** * Dummy interface. * * @author Doreen Seider */ private interface DummyInterface extends CallbackObject { Object makePuff(String string); Object makePeng(); } /** * Test implementation of the {@link PlatformService}. * * @author Doreen Seider */ private class DummyPlatformService extends PlatformServiceDefaultStub { @Override public InstanceNodeSessionId getLocalInstanceNodeSessionId() { return LOCAL_INSTANCE_SESSION_ID; } @Override public LogicalNodeSessionId getLocalDefaultLogicalNodeSessionId() { return LOCAL_LOGICAL_NODE_SESSION_ID; } } /** * Test {@link CallbackService} implementation. * * @author Doreen Seider */ private static class DummyCallbackService implements CallbackService, Serializable { private static final long serialVersionUID = 3384460645457699538L; private final String id = "id"; @Override public String addCallbackObject(Object callBackObject, InstanceNodeSessionId nodeId) { return null; } @Override public Object callback(String objectIdentifier, String methodName, List<? extends Serializable> parameters) throws RemoteOperationException { return null; } @Override public CallbackProxy createCallbackProxy(CallbackObject callbackObject, String objectIdentifier, InstanceNodeSessionId proxyHome) { if (objectIdentifier == id) { return new CallbackProxy() { private static final long serialVersionUID = -212249805288118195L; @Override public String getObjectIdentifier() { return id; } @Override public InstanceNodeSessionId getHomePlatform() { return LOCAL_INSTANCE_SESSION_ID; } }; } return null; } @Override public Object getCallbackObject(String objectIdentifier) { return new Serializable() { private static final long serialVersionUID = -5137415926803074469L; }; } @Override public String getCallbackObjectIdentifier(Object callbackObject) { return id; } @Override public void setTTL(String objectIdentifier, Long ttl) {} } }