PageRenderTime 41ms CodeModel.GetById 11ms RepoModel.GetById 1ms app.codeStats 0ms

/components/workflow/src/test/java/org/openengsb/core/workflow/drools/WorkflowServiceTest.java

https://github.com/chrcz/openengsb-framework
Java | 456 lines | 391 code | 47 blank | 18 comment | 5 complexity | ed979c01098f2311d1b0954628875166 MD5 | raw file
  1. /**
  2. * Licensed to the Austrian Association for Software Tool Integration (AASTI)
  3. * under one or more contributor license agreements. See the NOTICE file
  4. * distributed with this work for additional information regarding copyright
  5. * ownership. The AASTI licenses this file to you under the Apache License,
  6. * Version 2.0 (the "License"); you may not use this file except in compliance
  7. * with the License. You may obtain a copy of the License at
  8. *
  9. * http://www.apache.org/licenses/LICENSE-2.0
  10. *
  11. * Unless required by applicable law or agreed to in writing, software
  12. * distributed under the License is distributed on an "AS IS" BASIS,
  13. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  14. * See the License for the specific language governing permissions and
  15. * limitations under the License.
  16. */
  17. package org.openengsb.core.workflow.drools;
  18. import static org.hamcrest.CoreMatchers.is;
  19. import static org.hamcrest.CoreMatchers.not;
  20. import static org.hamcrest.CoreMatchers.nullValue;
  21. import static org.junit.Assert.assertThat;
  22. import static org.junit.Assert.fail;
  23. import static org.junit.matchers.JUnitMatchers.hasItem;
  24. import static org.mockito.Matchers.anyString;
  25. import static org.mockito.Matchers.eq;
  26. import static org.mockito.Mockito.atLeast;
  27. import static org.mockito.Mockito.inOrder;
  28. import static org.mockito.Mockito.mock;
  29. import static org.mockito.Mockito.times;
  30. import static org.mockito.Mockito.verify;
  31. import java.util.ArrayList;
  32. import java.util.HashMap;
  33. import java.util.List;
  34. import java.util.Map;
  35. import java.util.concurrent.Callable;
  36. import java.util.concurrent.ExecutorService;
  37. import java.util.concurrent.Executors;
  38. import java.util.concurrent.Future;
  39. import java.util.concurrent.atomic.AtomicBoolean;
  40. import java.util.concurrent.atomic.AtomicReference;
  41. import org.codehaus.jackson.map.ObjectMapper;
  42. import org.junit.Test;
  43. import org.mockito.InOrder;
  44. import org.openengsb.core.api.Domain;
  45. import org.openengsb.core.api.Event;
  46. import org.openengsb.core.api.context.ContextHolder;
  47. import org.openengsb.core.test.NullDomain;
  48. import org.openengsb.core.test.NullEvent3;
  49. import org.openengsb.core.workflow.api.RuleBaseException;
  50. import org.openengsb.core.workflow.api.model.InternalWorkflowEvent;
  51. import org.openengsb.core.workflow.api.model.ProcessBag;
  52. import org.openengsb.core.workflow.api.model.RuleBaseElementId;
  53. import org.openengsb.core.workflow.api.model.RuleBaseElementType;
  54. public class WorkflowServiceTest extends AbstractWorkflowServiceTest {
  55. private DummyExampleDomain logService;
  56. private DummyNotificationDomain notification;
  57. @Override
  58. public void setUp() throws Exception {
  59. super.setUp();
  60. logService = (DummyExampleDomain) domains.get("example");
  61. notification = (DummyNotificationDomain) domains.get("notification");
  62. }
  63. @Test
  64. public void testProcessEvent_shouldProcessEvent() throws Exception {
  65. service.processEvent(new Event());
  66. }
  67. @Test
  68. public void testProcessInternalWorkflowEvent_shouldNotFail() throws Exception {
  69. InternalWorkflowEvent event = new InternalWorkflowEvent();
  70. event.getProcessBag().setProcessId("0");
  71. service.processEvent(event);
  72. }
  73. @Test
  74. public void testProcessEvent_shouldTriggerHelloWorld() throws Exception {
  75. Event event = new Event();
  76. service.processEvent(event);
  77. verify(notification, atLeast(1)).notify("Hello");
  78. verify((DummyExampleDomain) domains.get("example"), atLeast(1)).doSomething("Hello World");
  79. verify(myservice, atLeast(1)).call();
  80. }
  81. @Test
  82. public void testUseLog_shouldLog() throws Exception {
  83. Event event = new Event("test-context");
  84. service.processEvent(event);
  85. verify(logService).doSomething("42");
  86. }
  87. @Test
  88. public void testUpdateRule_shouldWork() throws Exception {
  89. manager.update(new RuleBaseElementId(RuleBaseElementType.Rule, "hello1"),
  90. "when\n Event ( name == \"test-context\")\n then \n example.doSomething(\"21\");");
  91. Event event = new Event("test-context");
  92. service.processEvent(event);
  93. verify(logService).doSomething("21");
  94. }
  95. @Test
  96. public void testUseLogContent_shouldCallLogService() throws Exception {
  97. Event event = new Event("test-context");
  98. service.processEvent(event);
  99. verify(logService, times(2)).doSomething(anyString());
  100. }
  101. @Test
  102. public void testAddInvalidRule_shouldNotModifyRulebase() throws Exception {
  103. try {
  104. manager.add(new RuleBaseElementId(RuleBaseElementType.Rule, "hello"), "this*is_invalid");
  105. fail("expected Exception");
  106. } catch (RuleBaseException e) {
  107. // expected
  108. }
  109. Event event = new Event("test-context");
  110. service.processEvent(event);
  111. verify(logService, times(2)).doSomething(anyString());
  112. }
  113. @Test
  114. public void testInvalidModifyRule_shouldNotModifyRulebase() throws Exception {
  115. try {
  116. manager.update(new RuleBaseElementId(RuleBaseElementType.Rule, "hello1"), "this*is_invalid");
  117. fail("expected Exception");
  118. } catch (RuleBaseException e) {
  119. assertThat(e.getCause(), nullValue());
  120. }
  121. Event event = new Event("test-context");
  122. service.processEvent(event);
  123. verify(logService, times(2)).doSomething(anyString());
  124. }
  125. @Test
  126. public void testStartProcess_shouldRunScriptNodes() throws Exception {
  127. long id = service.startFlow("flowtest");
  128. service.waitForFlowToFinishIndefinitely(id);
  129. verify(logService).doSomething("context: " + ContextHolder.get().getCurrentContextId());
  130. }
  131. @Test
  132. public void testStartMultipleProcesses_shouldRunInCorrectContext() throws Exception {
  133. int tryThreads = 2;
  134. List<DummyExampleDomain> services = new ArrayList<DummyExampleDomain>();
  135. for (int i = 0; i < tryThreads; i++) {
  136. ContextHolder.get().setCurrentContextId(Integer.toString(i));
  137. services.add(registerDummyConnector(DummyExampleDomain.class, "example"));
  138. }
  139. for (int i = 0; i < tryThreads; i++) {
  140. ContextHolder.get().setCurrentContextId(Integer.toString(i));
  141. long id = service.startFlow("flowtest");
  142. service.waitForFlowToFinishIndefinitely(id);
  143. verify(services.get(i)).doSomething("context: " + ContextHolder.get().getCurrentContextId());
  144. }
  145. }
  146. @Test
  147. public void testStartProcessWithEvents_shouldRunScriptNodes() throws Exception {
  148. long id = service.startFlow("floweventtest");
  149. service.processEvent(new Event());
  150. service.processEvent(new TestEvent());
  151. service.waitForFlowToFinishIndefinitely(id);
  152. InOrder inOrder2 = inOrder(logService);
  153. inOrder2.verify(logService).doSomething("start testflow");
  154. inOrder2.verify(logService).doSomething("first event received");
  155. }
  156. @Test
  157. public void testStart2Processes_shouldOnlyTriggerSpecificEvents() throws Exception {
  158. long id1 = service.startFlow("floweventtest");
  159. long id2 = service.startFlow("floweventtest");
  160. service.processEvent(new Event("event", id1));
  161. service.processEvent(new TestEvent(id1));
  162. service.waitForFlowToFinishIndefinitely(id1);
  163. assertThat(service.getRunningFlows(), hasItem(id2));
  164. assertThat(service.getRunningFlows(), not(hasItem(id1)));
  165. }
  166. @Test
  167. public void testCiWorkflow_shouldRunWorkflow() throws Exception {
  168. long id = service.startFlow("ci");
  169. service.processEvent(new BuildSuccess());
  170. service.processEvent(new TestSuccess());
  171. service.waitForFlowToFinishIndefinitely(id);
  172. verify((DummyReport) domains.get("report"), times(1)).collectData();
  173. verify(notification, atLeast(1)).notify(anyString());
  174. verify((DummyDeploy) domains.get("deploy"), times(1)).deployProject();
  175. }
  176. @Test
  177. public void testStartInBackgroundWithoutStartedEvent_shouldRunInBackground() throws Exception {
  178. long id = service.startFlow("backgroundFlow");
  179. service.waitForFlowToFinish(id, 5000);
  180. verify(logService).doSomething(eq("" + id));
  181. }
  182. @Test
  183. public void testStartWorkflowTriggeredByEvent_shouldStartWorkflow() throws Exception {
  184. manager.add(new RuleBaseElementId(RuleBaseElementType.Rule, "test42"), "when\n" + " Event()\n" + "then\n"
  185. + " kcontext.getKnowledgeRuntime().startProcess(\"ci\");\n");
  186. service.processEvent(new Event());
  187. assertThat(service.getRunningFlows().isEmpty(), is(false));
  188. }
  189. @Test
  190. public void testRegisterWorkflowTrigger_shouldRegisterTrigger() throws Exception {
  191. service.registerFlowTriggerEvent(new Event("triggerEvent"), "ci");
  192. service.processEvent(new Event());
  193. service.processEvent(new Event("triggerEvent"));
  194. assertThat(service.getRunningFlows().size(), is(1));
  195. }
  196. @Test
  197. public void testRegisterWorkflowTriggerWithSubclass_shouldRegisterTrigger() throws Exception {
  198. NullEvent3 testEvent = new NullEvent3();
  199. testEvent.setName("triggerEvent");
  200. testEvent.setTestProperty("foo");
  201. testEvent.setTestStringProp("bar");
  202. testEvent.setTestBoolProp(true);
  203. testEvent.setTestIntProp(42);
  204. service.registerFlowTriggerEvent(testEvent, "ci");
  205. service.processEvent(new Event());
  206. service.processEvent(testEvent);
  207. assertThat(service.getRunningFlows().size(), is(1));
  208. }
  209. @Test
  210. public void testRegisterWorkflowTriggerIgnoreNullFields_shouldRegisterTrigger() throws Exception {
  211. NullEvent3 testEvent = new NullEvent3();
  212. testEvent.setName("triggerEvent");
  213. service.registerFlowTriggerEvent(testEvent, "ci");
  214. service.processEvent(new Event());
  215. service.processEvent(testEvent);
  216. assertThat(service.getRunningFlows().size(), is(1));
  217. }
  218. @Test
  219. public void testRegisterWorkflowTriggerIgnoreNullFieldsMixed_shouldRegisterTrigger() throws Exception {
  220. NullEvent3 testEvent = new NullEvent3();
  221. testEvent.setName("triggerEvent");
  222. testEvent.setTestStringProp("bar");
  223. testEvent.setTestIntProp(42);
  224. service.registerFlowTriggerEvent(testEvent, "ci");
  225. service.processEvent(new Event());
  226. service.processEvent(testEvent);
  227. assertThat(service.getRunningFlows().size(), is(1));
  228. }
  229. @Test(timeout = 3000)
  230. public void testRegisterWorkflowTriggerWithFlowStartedEvent_shouldRegisterTrigger() throws Exception {
  231. service.registerFlowTriggerEvent(new Event("triggerEvent"), "flowStartedEvent");
  232. service.processEvent(new Event("triggerEvent"));
  233. for (Long id : service.getRunningFlows()) {
  234. service.waitForFlowToFinishIndefinitely(id);
  235. }
  236. }
  237. @Test
  238. public void testIfEventIsRetracted_shouldWork() throws Exception {
  239. Event event = new Event();
  240. service.processEvent(event);
  241. event = new Event("test-context");
  242. service.processEvent(event);
  243. verify(logService, times(2)).doSomething("Hello World");
  244. }
  245. @Test
  246. public void testStartProcessWithProperyBagAndChangePropertyByScriptNode_shouldChangeProperty() throws Exception {
  247. ProcessBag processBag = new ProcessBag();
  248. Map<String, Object> parameterMap = new HashMap<String, Object>();
  249. parameterMap.put("processBag", processBag);
  250. long id = service.startFlowWithParameters("propertybagtest", parameterMap);
  251. service.waitForFlowToFinishIndefinitely(id);
  252. assertThat((String) processBag.getProperty("test"), is(String.valueOf(id)));
  253. }
  254. @Test
  255. public void testProcessEventsConcurrently_shouldProcessBothEvents() throws Exception {
  256. manager.addImport(TestEvent.class.getName());
  257. manager.add(new RuleBaseElementId(RuleBaseElementType.Rule, "concurrent test"), "when\n"
  258. + "TestEvent(value == \"0\")\n"
  259. + "then\n"
  260. + "example.doSomething(\"concurrent\");");
  261. manager.add(new RuleBaseElementId(RuleBaseElementType.Rule, "concurrent test1"), "when\n"
  262. + "TestEvent(value == \"1\")\n"
  263. + "then\n"
  264. + "Thread.sleep(1000);");
  265. Callable<Void> task = makeProcessEventTask(new TestEvent("1"));
  266. Callable<Void> task2 = makeProcessEventTask(new TestEvent("0"));
  267. ExecutorService executor = Executors.newCachedThreadPool();
  268. Future<Void> future1 = executor.submit(task);
  269. Thread.sleep(300);
  270. Future<Void> future2 = executor.submit(task2);
  271. future1.get();
  272. future2.get();
  273. verify(logService).doSomething("concurrent");
  274. }
  275. private Callable<Void> makeProcessEventTask(final Event event) {
  276. Callable<Void> task = new Callable<Void>() {
  277. @Override
  278. public Void call() throws Exception {
  279. service.processEvent(event);
  280. return null;
  281. }
  282. };
  283. return task;
  284. }
  285. @Test
  286. public void testExecuteWorkflow_shouldRunWorkFlow() throws Exception {
  287. ProcessBag result = service.executeWorkflow("simpleFlow", new ProcessBag());
  288. assertThat((Integer) result.getProperty("test"), is(42));
  289. assertThat((String) result.getProperty("alternativeName"),
  290. is("The answer to life the universe and everything"));
  291. }
  292. @Test
  293. public void testCancelWorkflow_shouldAbortWorkflow() throws Exception {
  294. long pid = service.startFlow("ci");
  295. service.cancelFlow(pid);
  296. service.waitForFlowToFinish(pid, 5000);
  297. }
  298. @Test
  299. public void testCancelWorkflowWithOpenTasks_shouldAbortWorkflow() throws Exception {
  300. long pid = service.startFlow("ci");
  301. ProcessBag bag = new ProcessBag();
  302. bag.setProcessId(Long.toString(pid));
  303. taskboxInternal.createNewTask(bag);
  304. service.cancelFlow(pid);
  305. service.waitForFlowToFinish(pid, 5000);
  306. assertThat("Tasks were not cancelled properly", taskbox.getOpenTasks().isEmpty(), is(true));
  307. }
  308. @Test
  309. public void testWaitForFlow_shouldReturnTrue() throws Exception {
  310. Long pid = service.startFlow("flowtest");
  311. boolean finished = service.waitForFlowToFinish(pid, 400);
  312. assertThat(finished, is(true));
  313. }
  314. @Test
  315. public void testWaitForFlowThatCannotFinish_shouldReturnFalse() throws Exception {
  316. Long pid = service.startFlow("floweventtest");
  317. service.processEvent(new Event("FirstEvent"));
  318. service.startFlow("flowtest");
  319. boolean finished = service.waitForFlowToFinish(pid, 400);
  320. assertThat(finished, is(false));
  321. }
  322. @Test
  323. public void testResponseRule_shouldProcessEvent() throws Exception {
  324. NullDomain nullDomainImpl = mock(NullDomain.class);
  325. registerServiceViaId(nullDomainImpl, "test-connector", NullDomain.class, Domain.class);
  326. manager.addImport(NullDomain.class.getName());
  327. manager.add(new RuleBaseElementId(RuleBaseElementType.Rule, "response-test"), ""
  328. + "when\n"
  329. + " e : Event()\n"
  330. + "then\n"
  331. + " NullDomain origin = (NullDomain) OsgiHelper.getResponseProxy(e, NullDomain.class);"
  332. + " origin.nullMethod(42);");
  333. Event event = new Event();
  334. event.setOrigin("test-connector");
  335. service.processEvent(event);
  336. verify(nullDomainImpl).nullMethod(42);
  337. }
  338. @Test
  339. public void testTriggerExceptionInEventProcessing_shouldNotKeepLocked() throws Exception {
  340. manager.add(new RuleBaseElementId(RuleBaseElementType.Rule, "response-test"), ""
  341. + "when\n"
  342. + " e : Event(name==\"evil\")\n"
  343. + "then\n"
  344. + " String testxx = null;"
  345. + " testxx.toString();"); // provoke NPE
  346. try {
  347. service.processEvent(new Event("evil"));
  348. fail("evil Event should trigger Exception");
  349. } catch (Exception e) {
  350. // expected
  351. }
  352. final AtomicReference<Exception> exceptionOccured = new AtomicReference<Exception>();
  353. final AtomicBoolean completed = new AtomicBoolean(false);
  354. Thread t = new Thread() {
  355. @Override
  356. public void run() {
  357. try {
  358. service.processEvent(new Event()); // should work because the evil Event should have been removed
  359. completed.set(true);
  360. } catch (Exception e) {
  361. exceptionOccured.set(e);
  362. }
  363. };
  364. };
  365. t.start();
  366. t.join(10000);
  367. assertThat("processEvent did not complete in time. Seems the workflow-engine is locked",
  368. completed.get(), is(true));
  369. if (exceptionOccured.get() != null) {
  370. throw exceptionOccured.get();
  371. }
  372. }
  373. @Test
  374. public void testSerializeConsequenceException_shouldReturnString() throws Exception {
  375. manager.add(new RuleBaseElementId(RuleBaseElementType.Rule, "response-test"), ""
  376. + "when\n"
  377. + " e : Event(name==\"evil\")\n"
  378. + "then\n"
  379. + " String testxx = null;"
  380. + " testxx.toString();"); // provoke NPE
  381. try {
  382. service.processEvent(new Event("evil"));
  383. fail("evil Event should trigger Exception");
  384. } catch (Exception e) {
  385. String exceptionString = new ObjectMapper().writeValueAsString(e);
  386. assertThat(exceptionString, not(nullValue()));
  387. }
  388. }
  389. @Test
  390. public void testThrowEvent_shouldAuditEvent() throws Exception {
  391. Event event = new Event("good");
  392. service.processEvent(event);
  393. verify(auditingMock).onEvent(event);
  394. }
  395. @Test
  396. public void testFlowListener_shouldTrigger() throws Exception {
  397. long id = service.startFlow("ci");
  398. service.processEvent(new BuildSuccess());
  399. Thread.sleep(300);
  400. verify(auditingMock).onNodeStart(eq("ci"), eq(id), eq("Start Tests"));
  401. service.processEvent(new TestSuccess());
  402. verify(auditingMock).onNodeStart(eq("ci"), eq(id), eq("deployProject"));
  403. service.waitForFlowToFinishIndefinitely(id);
  404. }
  405. private static class BuildSuccess extends Event {
  406. }
  407. private static class TestSuccess extends Event {
  408. }
  409. }