@Test(expected = MessagingException.class)
  public void testProcessOneWayNoThreadingWithException() throws Exception {
    ThreadingProfile threadingProfile =
        new ChainedThreadingProfile(muleContext.getDefaultThreadingProfile());
    threadingProfile.setDoThreading(false);
    threadingProfile.setMuleContext(muleContext);

    MessageProcessor mockListener = mock(MessageProcessor.class);
    when(mockListener.process((MuleEvent) any())).thenThrow(new RuntimeException());

    SedaStageInterceptingMessageProcessor sedaStageInterceptingMessageProcessor =
        new SedaStageInterceptingMessageProcessor(
            "testProcessOneWayNoThreadingWithException",
            "testProcessOneWayNoThreadingWithException",
            queueProfile,
            queueTimeout,
            threadingProfile,
            queueStatistics,
            muleContext);
    sedaStageInterceptingMessageProcessor.setListener(mockListener);
    sedaStageInterceptingMessageProcessor.initialise();
    sedaStageInterceptingMessageProcessor.start();

    MessagingExceptionHandler exceptionHandler = mock(MessagingExceptionHandler.class);
    Flow flow = mock(Flow.class);
    when(flow.getExceptionListener()).thenReturn(exceptionHandler);
    when(flow.getProcessingStrategy()).thenReturn(new AsynchronousProcessingStrategy());
    MuleEvent event = getTestEvent(TEST_MESSAGE, flow, MessageExchangePattern.ONE_WAY);

    sedaStageInterceptingMessageProcessor.process(event);
  }
  @Test
  public void testProcessOneWayThreadWaitTimeout() throws Exception {
    final int threadTimeout = 20;
    ThreadingProfile threadingProfile =
        new ChainedThreadingProfile(muleContext.getDefaultThreadingProfile());
    threadingProfile.setThreadWaitTimeout(threadTimeout);
    // Need 3 threads: 1 for polling, 2 to process work successfully without timeout
    threadingProfile.setMaxThreadsActive(3);
    threadingProfile.setPoolExhaustedAction(ThreadingProfile.WHEN_EXHAUSTED_WAIT);
    threadingProfile.setMuleContext(muleContext);

    MessageProcessor mockListener = mock(MessageProcessor.class);
    when(mockListener.process((MuleEvent) any()))
        .thenAnswer(
            new Answer<MuleEvent>() {
              public MuleEvent answer(InvocationOnMock invocation) throws Throwable {
                Thread.sleep(threadTimeout * 2);
                return (MuleEvent) invocation.getArguments()[0];
              }
            });

    SedaStageInterceptingMessageProcessor sedaStageInterceptingMessageProcessor =
        new SedaStageInterceptingMessageProcessor(
            "testProcessOneWayThreadWaitTimeout",
            "testProcessOneWayThreadWaitTimeout",
            queueProfile,
            queueTimeout,
            threadingProfile,
            queueStatistics,
            muleContext);
    sedaStageInterceptingMessageProcessor.setListener(mockListener);
    sedaStageInterceptingMessageProcessor.initialise();
    sedaStageInterceptingMessageProcessor.start();

    MessagingExceptionHandler exceptionHandler = mock(MessagingExceptionHandler.class);
    Flow flow = mock(Flow.class);
    when(flow.getExceptionListener()).thenReturn(exceptionHandler);
    when(flow.getProcessingStrategy()).thenReturn(new AsynchronousProcessingStrategy());
    final MuleEvent event = getTestEvent(TEST_MESSAGE, flow, MessageExchangePattern.ONE_WAY);

    for (int i = 0; i < 3; i++) {
      sedaStageInterceptingMessageProcessor.process(event);
    }

    ArgumentMatcher<MuleEvent> notSameEvent = createNotSameEventArgumentMatcher(event);

    // Two events are processed
    verify(mockListener, timeout(RECEIVE_TIMEOUT).times(2)).process(argThat(notSameEvent));

    // One event gets processed by the exception strategy
    verify(exceptionHandler, timeout(RECEIVE_TIMEOUT).times(1))
        .handleException((Exception) any(), argThat(notSameEvent));
  }
  @Test
  public void testProcessOneWayWithException() throws Exception {
    final Latch latch = new Latch();
    ThreadingProfile threadingProfile =
        new ChainedThreadingProfile(muleContext.getDefaultThreadingProfile());
    threadingProfile.setMuleContext(muleContext);

    MessageProcessor mockListener = mock(MessageProcessor.class);
    when(mockListener.process((MuleEvent) any()))
        .thenAnswer(
            new Answer<MuleEvent>() {
              public MuleEvent answer(InvocationOnMock invocation) throws Throwable {
                latch.countDown();
                throw new RuntimeException();
              }
            });

    SedaStageInterceptingMessageProcessor sedaStageInterceptingMessageProcessor =
        new SedaStageInterceptingMessageProcessor(
            "testProcessOneWayWithException",
            "testProcessOneWayWithException",
            queueProfile,
            queueTimeout,
            threadingProfile,
            queueStatistics,
            muleContext);
    sedaStageInterceptingMessageProcessor.setListener(mockListener);
    sedaStageInterceptingMessageProcessor.initialise();
    sedaStageInterceptingMessageProcessor.start();

    MessagingExceptionHandler exceptionHandler = mock(MessagingExceptionHandler.class);
    Flow flow = mock(Flow.class);
    when(flow.getExceptionListener()).thenReturn(exceptionHandler);
    when(flow.getProcessingStrategy()).thenReturn(new AsynchronousProcessingStrategy());
    final MuleEvent event = getTestEvent(TEST_MESSAGE, flow, MessageExchangePattern.ONE_WAY);

    sedaStageInterceptingMessageProcessor.process(event);

    assertTrue(latch.await(RECEIVE_TIMEOUT, TimeUnit.MILLISECONDS));

    ArgumentMatcher<MuleEvent> notSameEvent = createNotSameEventArgumentMatcher(event);

    // One event get processed but then throws an exception
    verify(mockListener, timeout(RECEIVE_TIMEOUT).times(1)).process(argThat(notSameEvent));

    // One event gets processed by the exception strategy
    verify(exceptionHandler, timeout(RECEIVE_TIMEOUT).times(1))
        .handleException((Exception) any(), argThat(notSameEvent));
  }