package GROUPID.tests.serviceintegration;

import GROUPID.tests.library.sample.base.SampleTestBase;

import com.jayway.restassured.http.ContentType; import org.testng.annotations.BeforeClass; import org.testng.annotations.Test;

import java.util.concurrent.Callable; import java.util.concurrent.TimeUnit;

import static com.github.tomakehurst.wiremock.client.WireMock.aResponse; import static com.github.tomakehurst.wiremock.client.WireMock.any; import static com.github.tomakehurst.wiremock.client.WireMock.get; import static com.github.tomakehurst.wiremock.client.WireMock.urlMatching; import static com.github.tomakehurst.wiremock.stubbing.Scenario.STARTED; import static com.jayway.awaitility.Awaitility.await; import static com.jayway.restassured.RestAssured.given;

/**

* Sample test to demonstrate working with an asynchronous batch transaction.
* TODO: WireMock is used to stub responses but <b>should be removed for service integration testing</b>.
* Stubbing in this test is only for demonstrating purpose.
* @author eing
*/

public class SampleServiceIntegrationTest extends SampleTestBase {

public SampleServiceIntegrationTest() {
}

/**
 * Add stubs to WireMock server for this test.
 * TODO: Remove this for actual service integration testing.
 */
@BeforeClass
public void setup() {
    //@formatter:off
    // returns 202: request has been accepted for processing, but the processing has not been completed
    wireMockServer.
            givenThat(
                    any(urlMatching("/batch")).
                            willReturn(aResponse().
                                    withHeader("Content-Type", ContentType.JSON.toString()).
                                    withHeader("X-AX-TRANSACTIONID", "1290").
                                    withStatus(202)));
    // returns
    // 1. state:IN_PROGRESS in header for first and second requests
    // 2. state:COMPLETE in header on the third request
    wireMockServer.
            givenThat(
                    get(urlMatching("/batch/[0-9]+/status")).
                            inScenario("Get batch status").
                    whenScenarioStateIs(STARTED).
                            willReturn(aResponse().
                                withStatus(200).
                                withHeader("Content-Type", ContentType.JSON.toString()).
                                withHeader("state", "IN_PROGRESS")).
                            willSetStateTo("Second get status attempt"));

    wireMockServer.
            givenThat(
                    get(urlMatching("/batch/[0-9]+/status")).
                            inScenario("Get batch status").
                    whenScenarioStateIs("Second get status attempt").
                            willReturn(aResponse().
                                    withStatus(200).
                                    withHeader("Content-Type", ContentType.JSON.toString()).
                                    withHeader("state", "IN_PROGRESS")).
                            willSetStateTo("Third get status attempt"));

    wireMockServer.
            givenThat(
                    get(urlMatching("/batch/[0-9]+/status")).
                            inScenario("Get batch status").
                    whenScenarioStateIs("Third get status attempt").
                            willReturn(aResponse().
                                    withStatus(200).
                                    withHeader("Content-Type", ContentType.JSON.toString()).
                                    withHeader("state", "COMPLETE")).
                            willSetStateTo("Batch activity completed"));
    //@formatter:on
}

/**
 * Example of an asynchronous request and how to use awaitability.
 */
@Test
public void testAsyncOperation() throws Exception {
    /**
     * Typically an identifier is returned to the user on a batch process
     * so that you can use it to poll for its status.
     */
    //@formatter:off
    String batchId =
            given().
                spec(requestSpec).
            when().
                    post("/batch").
            then().
                    statusCode(202).
                    extract().header("X-AX-TRANSACTIONID");
    //@formatter:on
    await().atMost(3, TimeUnit.SECONDS).until(batchActivityCompleted(batchId));
}

/**
 * Callback method for Java7. In Java8, you can code it inline in the test i.e.
 * await().atMost(3, TimeUnit.SECONDS).until(() -> batchActivityCompleted(batchId));
 * @param batchId batch job identifier to check status on
 * @return true if state is completed
 * @throws Exception
 */
private Callable<Boolean> batchActivityCompleted(final String batchId) throws Exception {
    return new Callable<Boolean>() {
        public Boolean call() throws Exception {
            //@formatter:off
            String state =
                    given().
                        spec(requestSpec).
                    when().
                            get("/batch/{batchId}/status", batchId).
                    thenReturn().header("state");
            //@formatter:on
            return state.equals("COMPLETE");
        }
    };
}

}