/**
* Licensed to the Austrian Association for Software Tool Integration (AASTI)
* under one or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information regarding copyright
* ownership. The AASTI licenses this file to you under the Apache License,
* Version 2.0 (the "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.openengsb.core.services.internal;
import static org.hamcrest.CoreMatchers.is;
import static org.hamcrest.Matchers.equalTo;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertThat;
import static org.junit.Assert.fail;
import static org.mockito.Matchers.any;
import static org.mockito.Matchers.eq;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.concurrent.Semaphore;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
import org.junit.Before;
import org.junit.Test;
import org.mockito.invocation.InvocationOnMock;
import org.mockito.stubbing.Answer;
import org.openengsb.core.api.OpenEngSBService;
import org.openengsb.core.api.remote.MethodCall;
import org.openengsb.core.api.remote.MethodCallMessage;
import org.openengsb.core.api.remote.MethodResult;
import org.openengsb.core.api.remote.MethodResult.ReturnType;
import org.openengsb.core.api.remote.MethodResultMessage;
import org.openengsb.core.api.remote.OutgoingPort;
import org.openengsb.core.api.remote.OutgoingPortUtilService;
import org.openengsb.core.test.AbstractOsgiMockServiceTest;
import org.openengsb.core.util.DefaultOsgiUtilsService;
public class OutgoingPortUtilServiceTest extends AbstractOsgiMockServiceTest {
private OutgoingPortUtilService callrouter;
private RequestHandlerImpl requestHandler;
private TestService serviceMock;
private OutgoingPort outgoingPortMock;
private final String testURI = "jms://localhost";
private MethodCall methodCall;
@Before
public void setUp() throws Exception {
serviceMock = mockService(TestService.class, "foo");
outgoingPortMock = mockService(OutgoingPort.class, "jms+json-out");
callrouter = new DefaultOutgoingPortUtilService(new DefaultOsgiUtilsService(bundleContext));
requestHandler = new RequestHandlerImpl();
requestHandler.setUtilsService(new DefaultOsgiUtilsService(bundleContext));
Map<String, String> metaData = getMetadata("foo");
methodCall = new MethodCall("test", new Object[0], metaData);
}
@Test
public void testRecieveMethodCall_shouldCallService() throws Exception {
requestHandler.handleCall(methodCall);
verify(serviceMock).test();
}
private HashMap<String, String> getMetadata(String id) {
HashMap<String, String> metaData = new HashMap<String, String>();
metaData.put("serviceId", id);
return metaData;
}
@Test
public void testReceiveMethodCallWithArgument_shouldCallMethod() throws Exception {
MethodCall call2 = new MethodCall("test", new Object[]{ 42 }, getMetadata("foo"));
requestHandler.handleCall(call2);
verify(serviceMock, never()).test();
verify(serviceMock, times(1)).test(eq(42));
}
@Test
public void testRecieveMethodCall_shouldSendResponse() throws Exception {
when(serviceMock.getAnswer()).thenReturn(42);
MethodCall call2 = new MethodCall("getAnswer", new Object[0], getMetadata("foo"));
MethodResult result = requestHandler.handleCall(call2);
verify(serviceMock).getAnswer();
assertThat((Integer) result.getArg(), is(42));
}
@Test
public void testReceiveMethodCallWithVoidMethod_shouldSendResponseWithVoidType() throws Exception {
MethodResult result = requestHandler.handleCall(methodCall);
verify(serviceMock).test();
assertThat(result.getType(), equalTo(ReturnType.Void));
assertNull(result.getArg());
}
@Test
public void testSendMethodCall_shouldCallPort() throws Exception {
callrouter.sendMethodCall("jms+json-out", testURI, new MethodCall());
Thread.sleep(300);
verify(outgoingPortMock, times(1)).send(any(MethodCallMessage.class));
}
@Test
public void testSendSyncMethodCall_shouldReturnResult() throws Exception {
when(serviceMock.getAnswer()).thenReturn(42);
MethodResult expectedResult = new MethodResult();
MethodResultMessage value = mock(MethodResultMessage.class);
when(value.getResult()).thenReturn(expectedResult);
when(outgoingPortMock.sendSync(any(MethodCallMessage.class))).thenReturn(value);
MethodResult result = callrouter.sendMethodCallWithResult("jms+json-out", "jms://localhost", methodCall);
assertThat(result, is(expectedResult));
}
private class MethodCallable implements Callable<MethodResult> {
private final MethodCall call;
public MethodCallable(MethodCall call) {
this.call = call;
}
@Override
public MethodResult call() throws Exception {
return requestHandler.handleCall(call);
}
}
@Test(timeout = 10000)
public void testHandleCallsParallel_shouldWork() throws Exception {
when(serviceMock.getAnswer()).thenReturn(42);
final Semaphore sync = new Semaphore(0);
Answer<Long> answer = new Answer<Long>() {
@Override
public Long answer(InvocationOnMock invocationOnMock) {
try {
sync.acquire();
} catch (InterruptedException e) {
fail(e.toString());
}
return 42L;
}
};
when(serviceMock.getOtherAnswer()).thenAnswer(answer);
MethodCall blockingCall = new MethodCall("getOtherAnswer", new Object[0], getMetadata("foo"));
MethodCall normalCall = new MethodCall("getAnswer", new Object[0], getMetadata("foo"));
ExecutorService threadPool = Executors.newCachedThreadPool();
Future<MethodResult> blockingFuture = threadPool.submit(new MethodCallable(blockingCall));
Future<MethodResult> normalFuture = threadPool.submit(new MethodCallable(normalCall));
MethodResult normalResult = normalFuture.get();
verify(serviceMock).getAnswer();
/* getAnswer-call is finished */
assertThat((Integer) normalResult.getArg(), is(42));
try {
blockingFuture.get(200, TimeUnit.MILLISECONDS);
fail("blocking method returned premature");
} catch (TimeoutException e) {
// ignore, this is expceted
}
sync.release();
MethodResult blockingResult = blockingFuture.get();
assertThat((Long) blockingResult.getArg(), is(42L));
}
public interface TestService extends OpenEngSBService {
void test();
void test(Integer i);
Integer getAnswer();
Long getOtherAnswer();
}
}