/**
* 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.workflow.drools;
import static org.hamcrest.CoreMatchers.is;
import static org.junit.Assert.assertThat;
import static org.mockito.Matchers.any;
import static org.mockito.Mockito.doAnswer;
import static org.mockito.Mockito.timeout;
import static org.mockito.Mockito.verify;
import java.util.HashMap;
import java.util.Hashtable;
import java.util.Map;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
import org.junit.Before;
import org.junit.Test;
import org.mockito.invocation.InvocationOnMock;
import org.mockito.stubbing.Answer;
import org.openengsb.core.api.remote.MethodCallMessage;
import org.openengsb.core.api.remote.OutgoingPort;
import org.openengsb.core.api.remote.OutgoingPortUtilService;
import org.openengsb.core.api.remote.RequestHandler;
import org.openengsb.core.services.internal.DefaultOutgoingPortUtilService;
import org.openengsb.core.services.internal.RequestHandlerImpl;
import org.openengsb.core.util.DefaultOsgiUtilsService;
import org.openengsb.core.workflow.api.EventRegistrationService;
import org.openengsb.core.workflow.api.model.RemoteEvent;
import org.openengsb.core.workflow.api.model.RuleBaseElementId;
import org.openengsb.core.workflow.api.model.RuleBaseElementType;
import org.openengsb.core.workflow.drools.internal.RegistrationServiceImpl;
public class RegistrationServiceTest extends AbstractWorkflowServiceTest {
private EventRegistrationService regService;
private RequestHandler requestHandler;
private OutgoingPort outgoingPort;
private ExecutorService executorService = Executors.newSingleThreadExecutor();
@Override
@Before
public void setUp() throws Exception {
super.setUp();
requestHandler = getRequestHandler();
regService = getRegistrationService();
registerServiceViaId(requestHandler, "requestHandler", RequestHandler.class);
outgoingPort = mockService(OutgoingPort.class, "testPort");
doAnswer(new Answer<Void>() {
@Override
public Void answer(final InvocationOnMock invocation) throws Throwable {
Runnable runnable = new Runnable() {
@Override
public void run() {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
requestHandler.handleCall(((MethodCallMessage) invocation.getArguments()[0]).getMethodCall());
};
};
executorService.execute(runnable);
return null;
}
}).when(outgoingPort).send(any(MethodCallMessage.class));
DefaultOutgoingPortUtilService outgoingPortUtilService =
new DefaultOutgoingPortUtilService(new DefaultOsgiUtilsService(bundleContext));
registerService(outgoingPortUtilService, new Hashtable<String, Object>(), OutgoingPortUtilService.class);
}
private RequestHandler getRequestHandler() {
RequestHandlerImpl requestHandlerImpl = new RequestHandlerImpl();
requestHandlerImpl.setUtilsService(new DefaultOsgiUtilsService(bundleContext));
return requestHandlerImpl;
}
private RegistrationServiceImpl getRegistrationService() {
RegistrationServiceImpl registrationServiceImpl = new RegistrationServiceImpl();
registrationServiceImpl.setRuleManager(manager);
return registrationServiceImpl;
}
@Test
public void testWrapRemoteEvent_shouldWrapEvent() throws Exception {
TestEvent event = new TestEvent(3L, "bla");
RemoteEvent wrapEvent = RemoteEventUtil.wrapEvent(event);
Map<String, String> properties = wrapEvent.getNestedEventProperties();
assertThat(wrapEvent.getClassName(), is(TestEvent.class.getName()));
assertThat(properties.get("processId"), is("3"));
}
@Test
public void testRegisterEvent_shouldRegisterEvent() throws Exception {
RemoteEvent reg = new RemoteEvent(TestEvent.class.getName());
reg.setProcessId(3L);
regService.registerEvent(reg, "testPort", "test://localhost");
service.processEvent(new TestEvent());
verify(outgoingPort, timeout(5000)).send(any(MethodCallMessage.class));
}
@Test
public void testRegisterEvent_shouldCreateRule() throws Exception {
RemoteEvent reg = new RemoteEvent(TestEvent.class.getName());
int oldCount = manager.listAll(RuleBaseElementType.Rule).size();
regService.registerEvent(reg, "testPort", "test://localhost");
assertThat(manager.listAll(RuleBaseElementType.Rule).size(), is(oldCount + 1));
}
@Test
public void testRegisterEvent_shouldProcessRemoteEvent() throws Exception {
CountDownLatch latch = new CountDownLatch(1);
trackInvocations((DummyExampleDomain) domains.get("example"), latch).doSomething("it works");
RemoteEvent reg = new RemoteEvent(TestEvent.class.getName());
regService.registerEvent(reg, "testPort", "test://localhost", "workflowService");
String ruleCode = "when RemoteEvent() then example.doSomething(\"it works\");";
manager.add(new RuleBaseElementId(RuleBaseElementType.Rule, "react to remote-event"), ruleCode);
service.processEvent(new TestEvent());
assertThat("did not call example.doSomething() after RemoteEvent", latch.await(5, TimeUnit.SECONDS), is(true));
executorService.shutdown();
executorService.awaitTermination(3, TimeUnit.SECONDS);
}
@Test
public void testRegisterMultipleEvents_shouldOnlyProcessOneEvent() throws Exception {
CountDownLatch latch = new CountDownLatch(1);
trackInvocations((DummyExampleDomain) domains.get("example"), latch).doSomething("it works");
RemoteEvent reg = new RemoteEvent(TestEvent.class.getName());
regService.registerEvent(reg, "testPort", "test://localhost", "workflowService");
RemoteEvent reg2 = new RemoteEvent(TestEvent.class.getName());
Map<String, String> nestedEventProperties = new HashMap<String, String>();
nestedEventProperties.put("value", "testValue");
reg2.setNestedEventProperties(nestedEventProperties);
regService.registerEvent(reg2, "testPort", "test://localhost", "workflowService");
String ruleCode = "when RemoteEvent() then example.doSomething(\"it works\");";
manager.add(new RuleBaseElementId(RuleBaseElementType.Rule, "react to remote-event"), ruleCode);
service.processEvent(new TestEvent());
assertThat(latch.await(5, TimeUnit.SECONDS), is(true));
executorService.shutdown();
executorService.awaitTermination(3, TimeUnit.SECONDS);
}
private <T> T trackInvocations(T mock, final CountDownLatch latch) {
return doAnswer(new Answer<Void>() {
@Override
public Void answer(InvocationOnMock invocation) throws Throwable {
latch.countDown();
return null;
}
}).when(mock);
}
}