assertSame(tiJoin.getFOE(),tiEnd.getFOE());
	public void testLoopingJoin() throws Exception {						ComplexProcessDef pd = new ComplexProcessDef("complexTest1");						MockStateFactory msf = new MockStateFactory();		IEngine engine = new Engine(msf);		MockProcessInstance processInstance = (MockProcessInstance) engine.createProcess(pd);		// first transition test - runs the workflow up to the point where it hits the JOIN		doPart1(pd, engine, processInstance);						MockTaskInstance ti = processInstance.findTask(pd.tdParallel_2,MockTaskInstance.STATE_READY);		assertNotNull("Failed to find the task to run",ti);				ti.setConditionAction(ComplexProcessDef.GOTO + pd.tdSplit.getName());		engine.transitionTask(ti);				/*		 * check to see if we have the expected number of object in the audit trail		 * 1 x process		 * 1 x tdStart (complete)		 * 2 x tdSplit (complete)		 * 1 x tdJoin (awaiting sync)		 * 2 x tdParallel-1 (complete)		 * 2 x tdParallel-2 (1 x complete, 1 x ready)		 */		assertEquals(9,msf.getAuditTrail().size());		assertEquals(1,msf.countInstances(pd));		assertEquals(1,msf.countInstances(pd.tdStart, MockTaskInstance.STATE_DELETED));		assertEquals(2,msf.countInstances(pd.tdSplit, MockTaskInstance.STATE_DELETED));		assertEquals(1,msf.countInstances(pd.tdJoin, MockTaskInstance.STATE_AWAITINGSYNC));		assertEquals(2,msf.countInstances(pd.tdParallel_1, MockTaskInstance.STATE_DELETED));		assertEquals(1,msf.countInstances(pd.tdParallel_2, MockTaskInstance.STATE_DELETED));		assertEquals(1,msf.countInstances(pd.tdParallel_2, MockTaskInstance.STATE_READY));				/*		 * check that we've got what we expect in the process instance		 * 1 x tdJoin		 * 1 x tdParallel2		 */		assertEquals(2,processInstance.getTaskInstances().size());		assertEquals(1,processInstance.countInstances(pd.tdParallel_2,MockTaskInstance.STATE_READY));		assertEquals(1,processInstance.countInstances(pd.tdJoin,MockTaskInstance.STATE_AWAITINGSYNC));				/*		 * now transition again, but go to the JOIN		 */		ti = processInstance.findTask(pd.tdParallel_2,MockTaskInstance.STATE_READY);		assertNotNull("Failed to find the task to run",ti);		ti.setConditionAction(ComplexProcessDef.GOTO + pd.tdJoin.getName());		engine.transitionTask(ti);				/*		 * check that we've got what we expect in the processinstance		 * 1 x tdEnd		 */		assertEquals(1,processInstance.getTaskInstances().size());		assertEquals(1,processInstance.countInstances(pd.tdEnd,MockTaskInstance.STATE_READY));				/*		 * check that we've still only got one Join task in the audit trail		 */		assertEquals(1,msf.countInstances(pd.tdJoin));				/*		 * now transition again to complete		 */		ti = processInstance.findTask(pd.tdEnd,MockTaskInstance.STATE_READY);		assertNotNull("Failed to find the task to run",ti);		engine.transitionTask(ti);				/*		 * check there are no outstanding tasks & the process is complete 		 */		assertEquals(0,processInstance.getTaskInstances().size());		assertTrue(processInstance.getState()==IProcessInstance.STATE_COMPLETE);				/*		 * check to see if we have the expected number of object in the audit trail		 * 1 x process		 * 1 x tdStart (complete)		 * 2 x tdSplit (complete)		 * 1 x tdJoin (complete)		 * 2 x tdParallel-1 (complete)		 * 2 x tdParallel-2 (complete)		 * 1 x tdEnd (complete)		 * 0 x tdAlternateEnding		 */		assertEquals(10,msf.getAuditTrail().size());		assertEquals(1,msf.countInstances(pd));		assertEquals(1,msf.countInstances(pd.tdStart, MockTaskInstance.STATE_DELETED));		assertEquals(2,msf.countInstances(pd.tdSplit, MockTaskInstance.STATE_DELETED));		assertEquals(1,msf.countInstances(pd.tdJoin, MockTaskInstance.STATE_DELETED));		assertEquals(2,msf.countInstances(pd.tdParallel_1, MockTaskInstance.STATE_DELETED));		assertEquals(2,msf.countInstances(pd.tdParallel_2, MockTaskInstance.STATE_DELETED));		assertEquals(1,msf.countInstances(pd.tdEnd, MockTaskInstance.STATE_DELETED));		assertEquals(0,msf.countInstances(pd.tdAlternateEnding));			}