public virtual void testConcurrentExclusiveCorrelation()
        {
            InvocationLogListener.reset();

            // given a process instance
            runtimeService.StartProcessInstanceByKey("testProcess");

            // and two threads correlating in parallel
            ThreadControl thread1 = ExecuteControllableCommand(new ControllableMessageCorrelationCommand("Message", true));

            thread1.ReportInterrupts();
            ThreadControl thread2 = ExecuteControllableCommand(new ControllableMessageCorrelationCommand("Message", true));

            thread2.ReportInterrupts();

            // both threads open a transaction and wait before correlating the message
            thread1.WaitForSync();
            thread2.WaitForSync();

            // thread one correlates and acquires the exclusive lock
            thread1.MakeContinue();
            thread1.WaitForSync();

            // the service task was executed once
            Assert.AreEqual(1, InvocationLogListener.Invocations);

            // thread two attempts to acquire the exclusive lock but can't since thread 1 hasn't released it yet
            thread2.MakeContinue();
            Thread.Sleep(2000);

            // let the first thread ends its transaction
            thread1.MakeContinue();
            Assert.IsNull(thread1.Exception);

            // thread 2 can't continue because the event subscription it tried to lock was deleted
            thread2.WaitForSync();
            Assert.True(thread2.Exception != null);
            Assert.True(thread2.Exception is ProcessEngineException);
            AssertTextPresent("does not have a subscription to a message event with name 'Message'", thread2.Exception.Message);

            // the first thread ended successfully without an exception
            thread1.Join();
            Assert.IsNull(thread1.Exception);

            // the follow-up task was reached
            ITask afterMessageTask = taskService.CreateTaskQuery().First();

            Assert.AreEqual(afterMessageTask.TaskDefinitionKey, "afterMessageUserTask");

            // the service task was not executed a second time
            Assert.AreEqual(1, InvocationLogListener.Invocations);
        }
        public virtual void FAILING_testConcurrentMixedCorrelationCase2()
        {
            InvocationLogListener.reset();

            // given a process instance
            runtimeService.StartProcessInstanceByKey("testProcess");

            // and two threads correlating in parallel (one exclusive, one non-exclusive)
            ThreadControl thread1 = ExecuteControllableCommand(new ControllableMessageCorrelationCommand("Message", false));

            thread1.ReportInterrupts();
            ThreadControl thread2 = ExecuteControllableCommand(new ControllableMessageCorrelationCommand("Message", true));

            thread2.ReportInterrupts();

            // both threads open a transaction and wait before correlating the message
            thread1.WaitForSync();
            thread2.WaitForSync();

            // thread one correlates and acquires no lock
            thread1.MakeContinue();
            thread1.WaitForSync();

            // thread two acquires a lock and succeeds because thread one hasn't acquired one
            thread2.MakeContinue();
            thread2.WaitForSync();

            // the service task was executed twice
            Assert.AreEqual(2, InvocationLogListener.Invocations);

            // thread one ends its transaction and blocks on flush when it attempts to Delete the event subscription
            thread1.MakeContinue();
            Thread.Sleep(5000);
            Assert.IsNull(thread1.Exception);

            Assert.AreEqual(0, taskService.CreateTaskQuery().Count());

            // thread 2 flushes successfully and releases the lock
            thread2.WaitUntilDone();
            Assert.IsNull(thread2.Exception);

            ITask afterMessageTask = taskService.CreateTaskQuery().First();

            Assert.NotNull(afterMessageTask);
            Assert.AreEqual(afterMessageTask.TaskDefinitionKey, "afterMessageUserTask");

            // thread 1 flush fails with optimistic locking
            thread1.Join();
            Assert.True(thread1.Exception != null);
            Assert.True(thread1.Exception is OptimisticLockingException);
        }