All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.mule.tck.functional.ResponseAssertionMessageProcessor Maven / Gradle / Ivy

/*
 * Copyright (c) MuleSoft, Inc.  All rights reserved.  http://www.mulesoft.com
 * The software in this package is published under the terms of the CPAL v1.0
 * license, a copy of which has been included with this distribution in the
 * LICENSE.txt file.
 */
package org.mule.tck.functional;

import org.mule.DefaultMuleEvent;
import org.mule.NonBlockingVoidMuleEvent;
import org.mule.VoidMuleEvent;
import org.mule.api.MessagingException;
import org.mule.api.MuleEvent;
import org.mule.api.MuleException;
import org.mule.api.MuleMessage;
import org.mule.api.NonBlockingSupported;
import org.mule.api.construct.FlowConstructAware;
import org.mule.api.lifecycle.InitialisationException;
import org.mule.api.lifecycle.Startable;
import org.mule.api.processor.InterceptingMessageProcessor;
import org.mule.api.processor.MessageProcessor;
import org.mule.api.transport.ReplyToHandler;
import org.mule.execution.MessageProcessorExecutionTemplate;
import org.mule.processor.chain.ProcessorExecutorFactory;

import java.util.Collections;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;

import org.junit.Assert;

public class ResponseAssertionMessageProcessor extends AssertionMessageProcessor implements
        InterceptingMessageProcessor, FlowConstructAware, Startable, NonBlockingSupported
{

    protected String responseExpression = "#[true]";
    private int responseCount = 1;
    private boolean responseSameThread = true;

    private MessageProcessor next;
    private Thread requestThread;
    private Thread responseThread;
    private CountDownLatch responseLatch;
    private int responseInvocationCount = 0;
    private MuleEvent responseEvent;
    private boolean responseResult = true;

    @Override
    public void start() throws InitialisationException
    {
        super.start();
        this.expressionManager.validateExpression(responseExpression);
        responseLatch = new CountDownLatch(responseCount);
        FlowAssert.addAssertion(flowConstruct.getName(), this);
    }

    @Override
    public MuleEvent process(MuleEvent event) throws MuleException
    {
        if (event == null)
        {
            return null;
        }

        if (event.isAllowNonBlocking() && event.getReplyToHandler() != null)
        {
            final ReplyToHandler originalReplyToHandler = event.getReplyToHandler();
            event = new DefaultMuleEvent(event, new ReplyToHandler()
            {
                @Override
                public void processReplyTo(MuleEvent event, MuleMessage returnMessage, Object replyTo) throws
                                                                                                       MuleException
                {
                    originalReplyToHandler.processReplyTo(processResponse(event), null, null);
                }

                @Override
                public void processExceptionReplyTo(MessagingException exception, Object replyTo)
                {
                    originalReplyToHandler.processExceptionReplyTo(exception, replyTo);
                }
            });
        }
        MuleEvent result = processNext(processRequest(event));
        if (!(result instanceof NonBlockingVoidMuleEvent))
        {
            return processResponse(result);
        }
        else
        {
            return result;
        }
    }

    public MuleEvent processRequest(MuleEvent event) throws MuleException
    {
        requestThread = Thread.currentThread();
        return super.process(event);
    }

    public MuleEvent processResponse(MuleEvent event) throws MuleException
    {
        if (event == null || VoidMuleEvent.getInstance().equals(event))
        {
            return event;
        }
        responseThread = Thread.currentThread();
        this.responseEvent = event;
        responseResult = responseResult && expressionManager.evaluateBoolean(responseExpression, event, false, true);
        increaseResponseCount();
        responseLatch.countDown();
        return event;
    }

    private MuleEvent processNext(MuleEvent event) throws MuleException
    {
        if (event != null || event instanceof VoidMuleEvent)
        {
            try
            {
                return new ProcessorExecutorFactory().createProcessorExecutor(event, Collections.singletonList(next),
                                                                              MessageProcessorExecutionTemplate
                                                                                      .createExceptionTransformerExecutionTemplate(), false).execute();
            }
            catch (MessagingException e)
            {
                event.getSession().setValid(false);
                throw e;
            }
        }
        else
        {
            return event;
        }
    }

    @Override
    public void verify() throws InterruptedException
    {
        super.verify();
        if (responseCountFailOrNullEvent())
        {
            Assert.fail("Flow assertion '" + message + "' failed. No response message received or if responseCount " +
                        "attribute was set then it was no matched.");
        }
        else if (responseExpressionFailed())
        {
            Assert.fail("Flow assertion '" + message + "' failed. Response expression " + expression
                        + " evaluated false.");
        }
        else if (responseCount > 0 && responseSameThread && (requestThread != responseThread))
        {
            Assert.fail("Flow assertion '" + message + "' failed. Response thread was not same as request thread");
        }
        else if (responseCount > 0 && !responseSameThread && (requestThread == responseThread))
        {
            Assert.fail("Flow assertion '" + message + "' failed. Response thread was same as request thread");
        }
    }

    public Boolean responseCountFailOrNullEvent() throws InterruptedException
    {
        return !isResponseProcessesCountCorrect();
    }

    public Boolean responseExpressionFailed()  //added for testing (cant assert on asserts)
    {
        return !responseResult;
    }

    @Override
    public void setListener(MessageProcessor listener)
    {
        this.next = listener;
    }

    private void increaseResponseCount()
    {
        responseInvocationCount++;
    }

    public void setResponseExpression(String responseExpression)
    {
        this.responseExpression = responseExpression;
    }

    public void setResponseCount(int responseCount)
    {
        this.responseCount = responseCount;
    }

    public void setResponseSameThread(boolean responseSameThread)
    {
        this.responseSameThread = responseSameThread;
    }

    /**
     * The semantics of the count are as follows:
     * - count was set & count processes were done => ok
     * - count was set & count processes were not done => fail
     * - count was not set & at least one processing were done => ok
     *
     * @return
     * @throws InterruptedException
     */
    synchronized private boolean isResponseProcessesCountCorrect() throws InterruptedException
    {
        boolean countReached = responseLatch.await(timeout, TimeUnit.MILLISECONDS);
        if (needToMatchCount)
        {
            return responseCount == responseInvocationCount;
        }
        else
        {
            return countReached;
        }
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy