<reponame>ManiLikhdhari/camelinaction2
package camelinaction;

import com.consol.citrus.actions.AbstractTestAction;
import com.consol.citrus.annotations.CitrusTest;
import com.consol.citrus.condition.AbstractCondition;
import com.consol.citrus.context.TestContext;
import com.consol.citrus.dsl.junit.JUnit4CitrusTestDesigner;
import com.consol.citrus.exceptions.CitrusRuntimeException;
import com.consol.citrus.http.client.HttpClient;
import com.consol.citrus.jms.endpoint.JmsEndpoint;
import com.consol.citrus.jms.message.JmsMessageHeaders;
import org.apache.camel.spring.SpringCamelContext;
import org.junit.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.test.context.ContextConfiguration;

/**
 * Citrus Integration test that test a Camel application.
 * We use Citrus as a HTTP client to send a message to a Camel application
 * that routes the messages to a JMS queue, which Citrus is simulating and
 * returning a reply message on the JMS reply queue, which Camel receives
 * and routes back to the calling HTTP client.
 * <p/>
 * In other words we have Citrus simulating a JMS backend, and as a client as well.
 * Notice how we can setup the test using the citrus designer.
 */
@ContextConfiguration(classes = EndpointConfig.class)
public class CitrusIT extends JUnit4CitrusTestDesigner {

    @Autowired
    private HttpClient statusHttpClient;

    @Autowired
    private JmsEndpoint statusEndpoint;

    @Autowired
    @SuppressWarnings("SpringJavaAutowiringInspection")
    private SpringCamelContext orderService;

    @Test
    @CitrusTest
    public void orderStatus() throws Exception {
        description("Checking order should be on hold");

        // random 5 digit order number
        variable("orderId", "citrus:randomNumber(5)");

        // the HTTP client is sending the order
        http().client(statusHttpClient)
            .send()
                .get("/status?id=${orderId}")
                .contentType("text/xml").accept("text/xml")
                // use fork so we can continue with the test design (otherwise this would be a synchronous call)
                .fork(true);

        echo("Sent HTTP Request with orderId: ${orderId}");

        // the Camel application will call a JMS backend so lets use Citrus to simulate this
        // on the JMS queue we expect to receive the following message
        // and capture the JMS correlation ID so we can send back the correct reply message
        receive(statusEndpoint)
                .payload("<order><id>${orderId}</id></order>")
                .extractFromHeader(JmsMessageHeaders.CORRELATION_ID, "cid");

        // send back the JMS reply message that the order is done
        // and with the correct JMSCorrelationID
        send(statusEndpoint)
                .payload("<order><id>${orderId}</id><status>ON HOLD</status></order>")
                .header(JmsMessageHeaders.CORRELATION_ID, "${cid}");

        // the HTTP client is expected to receive a 200 OK message with the following XML structure
        http().client(statusHttpClient)
            .receive()
                .response(HttpStatus.OK)
                .payload("<order><id>${orderId}</id><status>ON HOLD</status></order>")
                .contentType("text/xml");

        // wait for Camel to shutdown nicely (citrus should have this out of the box in citrus-camel)
        stopAndWaitForGracefulShutdown();
    }

    /**
     * Stop and wait for graceful shutdown of Camel context before closing the test.
     */
    private void stopAndWaitForGracefulShutdown() {
        // stop the Camel context with custom test action.
        action(new AbstractTestAction() {
            @Override
            public void doExecute(TestContext context) {
                try {
                    orderService.stop();
                } catch (Exception e) {
                    throw new CitrusRuntimeException("Failed to stop Camel context");
                }
            }
        });

        waitFor().condition(new AbstractCondition() {
            @Override
            public boolean isSatisfied(TestContext context) {
                return orderService.isStopped();
            }

            @Override
            public String getSuccessMessage(TestContext context) {
                return "Successfully stopped Camel context";
            }

            @Override
            public String getErrorMessage(TestContext context) {
                return "Failed to stop Camel context";
            }
        });
    }

}
