diff --git a/src/main/java/org/mifos/integrationtest/config/AirtelConfig.java b/src/main/java/org/mifos/integrationtest/config/AirtelConfig.java new file mode 100644 index 00000000..226dbc75 --- /dev/null +++ b/src/main/java/org/mifos/integrationtest/config/AirtelConfig.java @@ -0,0 +1,20 @@ +package org.mifos.integrationtest.config; + +import org.springframework.beans.factory.annotation.Value; +import org.springframework.boot.context.properties.ConfigurationProperties; +import org.springframework.boot.context.properties.EnableConfigurationProperties; +import org.springframework.context.annotation.Configuration; +import org.springframework.stereotype.Component; + +@Configuration +@EnableConfigurationProperties +@ConfigurationProperties(prefix = "airtel-connector.mock-airtel") +@Component +public class AirtelConfig { + + @Value("${airtel-connector.contactpoint}") + public String airtelConnectorContactPoint; + + @Value("${callback_url}") + public String callbackURL; +} diff --git a/src/main/resources/application.yaml b/src/main/resources/application.yaml index 7f2b52f3..56804f83 100644 --- a/src/main/resources/application.yaml +++ b/src/main/resources/application.yaml @@ -154,6 +154,8 @@ mock-payment-schema: mock-batch-authorization: "/batches/" actuator: "/actuator/health" +airtel-connector: + contactpoint: "http://localhost:8080" netflix-conductor: server: diff --git a/src/test/java/org/mifos/integrationtest/ClientCorrelationIdTest.java b/src/test/java/org/mifos/integrationtest/ClientCorrelationIdTest.java index d467f355..e5d3b030 100644 --- a/src/test/java/org/mifos/integrationtest/ClientCorrelationIdTest.java +++ b/src/test/java/org/mifos/integrationtest/ClientCorrelationIdTest.java @@ -54,7 +54,7 @@ public void setup() { @Disabled public void testSendCollectionRequest() throws JSONException { requestSpec.header(Utils.X_CORRELATIONID, clientCorrelationId); - JSONObject collectionRequestBody = CollectionHelper.getCollectionRequestBody("1", "254708374149", "24450523"); + JSONObject collectionRequestBody = CollectionHelper.getCollectionRequestBody("1", "USD", "254708374149", "24450523"); logger.info(String.valueOf(collectionRequestBody)); String json = RestAssured.given(requestSpec).baseUri(channelConnectorConfig.channelConnectorContactPoint) .body(collectionRequestBody.toString()).expect().spec(statusOkResponseSpec).when().post("/channel/collection").andReturn() diff --git a/src/test/java/org/mifos/integrationtest/ExternalIdTest.java b/src/test/java/org/mifos/integrationtest/ExternalIdTest.java index 17ccb296..c71a3940 100644 --- a/src/test/java/org/mifos/integrationtest/ExternalIdTest.java +++ b/src/test/java/org/mifos/integrationtest/ExternalIdTest.java @@ -44,7 +44,7 @@ public void setup() { @Test @Disabled public void testSendCollectionRequest() throws JSONException { - JSONObject collectionRequestBody = CollectionHelper.getCollectionRequestBody("1", "254708374149", "24450523"); + JSONObject collectionRequestBody = CollectionHelper.getCollectionRequestBody("1", "USD", "254708374149", "24450523"); log.debug("{}", collectionRequestBody); String json = RestAssured.given(requestSpec).baseUri("http://localhost:5002").body(collectionRequestBody.toString()).expect() .spec(statusOkResponseSpec).when().post("/channel/collection").andReturn().asString(); diff --git a/src/test/java/org/mifos/integrationtest/common/CollectionHelper.java b/src/test/java/org/mifos/integrationtest/common/CollectionHelper.java index 6da79a96..793348aa 100644 --- a/src/test/java/org/mifos/integrationtest/common/CollectionHelper.java +++ b/src/test/java/org/mifos/integrationtest/common/CollectionHelper.java @@ -15,15 +15,18 @@ public final class CollectionHelper { private CollectionHelper() {} - public static JSONObject getCollectionRequestBody(String amount, String msisdn, String accountId) throws JSONException { + public static JSONObject getCollectionRequestBody(String amount, String currency, String msisdn, String accountId) + throws JSONException { List> payers = new ArrayList<>(); payers.add(new Pair<>("MSISDN", msisdn)); payers.add(new Pair<>("ACCOUNTID", accountId)); JSONObject body = new JSONObject(); body.put("payer", getPayerArray(payers)); - body.put("amount", getAmountObject(amount)); + body.put("amount", getAmountObject(amount, currency)); body.put("transactionType", getTransactionTypeObject()); + body.put("customData", new JSONArray()); + body.put("note", "Testing"); return body; } @@ -34,7 +37,7 @@ public static JSONObject getCollectionRequestBody(String key1, String key2) thro JSONObject body = new JSONObject(); body.put("payer", getPayerArray(payers)); - body.put("amount", getAmountObject("1")); + body.put("amount", getAmountObject("1", "USD")); body.put("transactionType", getTransactionTypeObject()); return body; } @@ -58,16 +61,16 @@ private static JSONObject getPayerObject(String key, String value) throws JSONEx return payerObject; } - private static JSONObject getAmountObject(String amount) throws JSONException { + private static JSONObject getAmountObject(String amount, String currency) throws JSONException { JSONObject amountObject = new JSONObject(); - amountObject.put("currency", "USD"); + amountObject.put("currency", currency); amountObject.put("amount", amount); return amountObject; } private static JSONObject getTransactionTypeObject() throws JSONException { JSONObject txnType = new JSONObject(); - txnType.put("scenario", "MPESA"); + txnType.put("scenario", "AIRTEL"); txnType.put("subScenario", "BUYGOODS"); txnType.put("initiator", "PAYEE"); txnType.put("initiatorType", "BUSINESS"); diff --git a/src/test/java/org/mifos/integrationtest/common/Utils.java b/src/test/java/org/mifos/integrationtest/common/Utils.java index 4114e53f..e0592430 100644 --- a/src/test/java/org/mifos/integrationtest/common/Utils.java +++ b/src/test/java/org/mifos/integrationtest/common/Utils.java @@ -35,6 +35,8 @@ private Utils() {} public static final String QUERY_PARAM_TYPE = "type"; public static final String HEADER_REGISTERING_INSTITUTE_ID = "X-Registering-Institution-ID"; public static final String HEADER_PROGRAM_ID = "X-Program-ID"; + public static final String X_PAYEMENTSCHEMA = "X-Payment-Scheme"; + public static final String X_COUNTRY = "X-Country"; public static void initializeRESTAssured() { RestAssured.baseURI = "https://localhost"; diff --git a/src/test/java/org/mifos/integrationtest/cucumber/stepdef/AirtelStepDef.java b/src/test/java/org/mifos/integrationtest/cucumber/stepdef/AirtelStepDef.java new file mode 100644 index 00000000..a648b6d6 --- /dev/null +++ b/src/test/java/org/mifos/integrationtest/cucumber/stepdef/AirtelStepDef.java @@ -0,0 +1,78 @@ +package org.mifos.integrationtest.cucumber.stepdef; + +import static com.github.tomakehurst.wiremock.client.WireMock.equalTo; +import static com.github.tomakehurst.wiremock.client.WireMock.matchingJsonPath; +import static com.github.tomakehurst.wiremock.client.WireMock.postRequestedFor; +import static com.github.tomakehurst.wiremock.client.WireMock.urlEqualTo; +import static com.github.tomakehurst.wiremock.client.WireMock.verify; +import static com.google.common.truth.Truth.assertThat; +import static java.util.concurrent.TimeUnit.SECONDS; +import static org.awaitility.Awaitility.await; + +import io.cucumber.java.en.And; +import io.cucumber.java.en.Given; +import io.cucumber.java.en.Then; +import org.json.JSONException; +import org.json.JSONObject; +import org.mifos.integrationtest.common.CollectionHelper; +import org.mifos.integrationtest.config.AirtelConfig; +import org.springframework.beans.factory.annotation.Autowired; + +public class AirtelStepDef extends BaseStepDef { + + @Autowired + AirtelConfig airtelConfig; + + @Given("I have MSISDN as {string}") + public void iHaveMSISDNAs(String msisdn) { + scenarioScopeState.msisdn = msisdn; + assertThat(scenarioScopeState.msisdn).isNotEmpty(); + } + + @Given("I have clientCorrelationId as {string}") + public void iHaveClientCorrelationIdAs(String clientCorrelationId) { + scenarioScopeState.clientCorrelationId = clientCorrelationId; + assertThat(scenarioScopeState.clientCorrelationId).isNotEmpty(); + } + + @Given("I have accountId as {string}") + public void iHaveAccountId(String accountId) { + scenarioScopeState.accountId = accountId; + assertThat(scenarioScopeState.accountId).isNotEmpty(); + } + + @And("I have transaction id as {string}") + public void iHaveTransactionIdAs(String transactionId) { + scenarioScopeState.transactionId = transactionId; + assertThat(scenarioScopeState.transactionId).isNotEmpty(); + } + + @And("I have amount as {string}") + public void iHaveAmountAs(String amount) { + scenarioScopeState.amount = amount; + assertThat(scenarioScopeState.amount).isNotEmpty(); + } + + @And("I have currency as {string}") + public void iHaveCurrencyAs(String currency) { + scenarioScopeState.currency = currency; + assertThat(scenarioScopeState.currency).isNotEmpty(); + } + + @And("I have the request body with payer ams identifiers using keys MSISDN and accountId, currency {string}, and amount {string}") + public void iHaveRequestBody(String currency, String amount) throws JSONException { + JSONObject collectionRequestBody = CollectionHelper.getCollectionRequestBody(amount, currency, scenarioScopeState.msisdn, + scenarioScopeState.accountId); + scenarioScopeState.requestBody = collectionRequestBody; + logger.info(String.valueOf(scenarioScopeState.requestBody)); + } + + @Then("I should be able to verify that {string} endpoint received {int} request with status code {string}") + public void iShouldBeAbleToVerifyThatEndpointReceivedRequestWithStatusCode(String endpoint, int numberOfRequest, String statusCode) { + await().atMost(awaitMost, SECONDS).pollInterval(pollInterval, SECONDS).untilAsserted(() -> { + verify(numberOfRequest, postRequestedFor(urlEqualTo(endpoint)) + .withRequestBody(matchingJsonPath("$.transaction.statusCode", equalTo(statusCode)))); + }); + } + +} diff --git a/src/test/java/org/mifos/integrationtest/cucumber/stepdef/ChannelCollectionStepDef.java b/src/test/java/org/mifos/integrationtest/cucumber/stepdef/ChannelCollectionStepDef.java index 9ba4fb84..83c5781b 100644 --- a/src/test/java/org/mifos/integrationtest/cucumber/stepdef/ChannelCollectionStepDef.java +++ b/src/test/java/org/mifos/integrationtest/cucumber/stepdef/ChannelCollectionStepDef.java @@ -9,13 +9,13 @@ import io.restassured.RestAssured; import io.restassured.builder.ResponseSpecBuilder; import io.restassured.specification.RequestSpecification; -import java.util.UUID; import org.json.JSONException; import org.json.JSONObject; import org.mifos.integrationtest.common.CollectionHelper; import org.mifos.integrationtest.common.Utils; import org.mifos.integrationtest.common.dto.CollectionResponse; import org.mifos.integrationtest.common.dto.operationsapp.GetTransactionRequestResponse; +import org.mifos.integrationtest.config.AirtelConfig; import org.springframework.beans.factory.annotation.Autowired; public class ChannelCollectionStepDef extends BaseStepDef { @@ -23,6 +23,9 @@ public class ChannelCollectionStepDef extends BaseStepDef { @Autowired ScenarioScopeState scenarioScopeState; + @Autowired + AirtelConfig mockAirtelConfig; + @And("I have the request body with payer ams identifier keys as {string} and {string}") public void iHaveRequestBody(String key1, String key2) throws JSONException { JSONObject collectionRequestBody = CollectionHelper.getCollectionRequestBody(key1, key2); @@ -33,7 +36,7 @@ public void iHaveRequestBody(String key1, String key2) throws JSONException { @When("I call the channel collection API with client correlation id and expected status of {int}") public void iCallChannelCollectionAPI(int expectedStatus) { RequestSpecification requestSpec = Utils.getDefaultSpec(scenarioScopeState.tenant); - requestSpec.header(Utils.X_CORRELATIONID, UUID.randomUUID()); + requestSpec.header(Utils.X_CORRELATIONID, "123456"); scenarioScopeState.response = RestAssured.given(requestSpec).baseUri(channelConnectorConfig.channelConnectorContactPoint) // BaseStepDef.response = RestAssured.given(requestSpec).baseUri("https://localhost:8443") .body(scenarioScopeState.requestBody.toString()).expect() @@ -41,10 +44,23 @@ public void iCallChannelCollectionAPI(int expectedStatus) { .post(channelConnectorConfig.collectionEndpoint).andReturn().asString(); } + @When("I call the channel collection API with client correlation id, country {string}, callback {string}, payment schema {string} and expected status of {int}") + public void iCallChannelCollectionsAPII(String country, String callback, String paymentSchema, int expectedStatus) { + RequestSpecification requestSpec = Utils.getDefaultSpec(scenarioScopeState.tenant, scenarioScopeState.clientCorrelationId); + requestSpec.header(Utils.X_PAYEMENTSCHEMA, paymentSchema); + requestSpec.header(Utils.X_COUNTRY, country); + requestSpec.header(Utils.X_CallbackURL, "http://127.0.0.1:53013" + callback); + scenarioScopeState.response = RestAssured.given(requestSpec).baseUri(channelConnectorConfig.channelConnectorContactPoint) + .body(scenarioScopeState.requestBody.toString()).expect() + .spec(new ResponseSpecBuilder().expectStatusCode(expectedStatus).build()).when() + .post(channelConnectorConfig.collectionEndpoint).andReturn().asString(); + } + @Then("I should get transaction id in response") public void iGetTransactionIdInResponse() { CollectionResponse response = (new Gson()).fromJson(scenarioScopeState.response, CollectionResponse.class); scenarioScopeState.transactionId = response.getTransactionId(); + logger.info("THE TXN ID IS BEING PASSED {}", scenarioScopeState.transactionId); assertThat(response.getTransactionId()).isNotNull(); } @@ -61,7 +77,7 @@ public void iCallTheTxnAPIWithTransactionId() throws InterruptedException { requestSpec.header("Authorization", "Bearer " + scenarioScopeState.accessToken); } requestSpec.queryParam("transactionId", scenarioScopeState.transactionId); - + logger.info("the transactionID is {}", scenarioScopeState.transactionId); scenarioScopeState.response = RestAssured.given(requestSpec).baseUri(operationsAppConfig.operationAppContactPoint).expect() .spec(new ResponseSpecBuilder().expectStatusCode(200).build()).when().get(operationsAppConfig.transactionRequestsEndpoint) .andReturn().asString(); @@ -73,6 +89,7 @@ public void iCallTheTxnAPIWithTransactionId() throws InterruptedException { public void assertValues() { GetTransactionRequestResponse transactionRequestResponse = (new Gson()).fromJson(scenarioScopeState.response, GetTransactionRequestResponse.class); + assertThat(transactionRequestResponse.getContent().size()).isEqualTo(1); assertThat(transactionRequestResponse.getContent().get(0).getState()).isAnyOf("ACCEPTED", "FAILED"); assertThat(transactionRequestResponse.getContent().get(0).getExternalId()).isNotNull(); diff --git a/src/test/java/org/mifos/integrationtest/cucumber/stepdef/GetTxnApiDef.java b/src/test/java/org/mifos/integrationtest/cucumber/stepdef/GetTxnApiDef.java index 6d6b7486..08fd59ce 100644 --- a/src/test/java/org/mifos/integrationtest/cucumber/stepdef/GetTxnApiDef.java +++ b/src/test/java/org/mifos/integrationtest/cucumber/stepdef/GetTxnApiDef.java @@ -81,7 +81,7 @@ public void checkDate() { public void iCallCollectionApiWithExpectedStatus(int expectedStatus) throws JSONException { RequestSpecification requestSpec = Utils.getDefaultSpec(scenarioScopeState.tenant); requestSpec.header(Utils.X_CORRELATIONID, clientCorrelationId); - JSONObject collectionRequestBody = CollectionHelper.getCollectionRequestBody("1", "254708374149", "24450523"); + JSONObject collectionRequestBody = CollectionHelper.getCollectionRequestBody("1", "USD", "254708374149", "24450523"); logger.info(String.valueOf(collectionRequestBody)); String json = RestAssured.given(requestSpec).baseUri(channelConnectorConfig.channelConnectorContactPoint) .body(collectionRequestBody.toString()).expect().spec(new ResponseSpecBuilder().expectStatusCode(expectedStatus).build()) diff --git a/src/test/java/org/mifos/integrationtest/cucumber/stepdef/IdempotencyStepDef.java b/src/test/java/org/mifos/integrationtest/cucumber/stepdef/IdempotencyStepDef.java index d2acfc27..eb6b205c 100644 --- a/src/test/java/org/mifos/integrationtest/cucumber/stepdef/IdempotencyStepDef.java +++ b/src/test/java/org/mifos/integrationtest/cucumber/stepdef/IdempotencyStepDef.java @@ -38,7 +38,7 @@ public void iCallCollectionApiWithClientCorrelationIdExpectedStatus(int expected RequestSpecification requestSpec = Utils.getDefaultSpec(scenarioScopeState.tenant); requestSpec.header(Utils.X_CORRELATIONID, scenarioScopeState.clientCorrelationId); logger.info("X-CorrelationId: {}", scenarioScopeState.clientCorrelationId); - JSONObject collectionRequestBody = CollectionHelper.getCollectionRequestBody("1", "254708374149", "24450523"); + JSONObject collectionRequestBody = CollectionHelper.getCollectionRequestBody("1", "USD", "254708374149", "24450523"); String json = RestAssured.given(requestSpec).baseUri(channelConnectorConfig.channelConnectorContactPoint) .body(collectionRequestBody.toString()).expect().spec(new ResponseSpecBuilder().expectStatusCode(expectedStatus).build()) .when().post(channelConnectorConfig.collectionEndpoint).andReturn().asString(); @@ -50,7 +50,7 @@ public void iCallCollectionApiWithClientCorrelationIdExpectedStatus(int expected public void iCallCollectionApiWithClientCorrelationIdErrorExpectedStatus(int expectedStatus) throws JSONException { RequestSpecification requestSpec = Utils.getDefaultSpec(scenarioScopeState.tenant); requestSpec.header(Utils.X_CORRELATIONID, scenarioScopeState.clientCorrelationId); - JSONObject collectionRequestBody = CollectionHelper.getCollectionRequestBody("1", "254708374149", "24450523"); + JSONObject collectionRequestBody = CollectionHelper.getCollectionRequestBody("1", "USD", "254708374149", "24450523"); scenarioScopeState.response = RestAssured.given(requestSpec).baseUri(channelConnectorConfig.channelConnectorContactPoint) .body(collectionRequestBody.toString()).expect().spec(new ResponseSpecBuilder().expectStatusCode(expectedStatus).build()) .when().post(channelConnectorConfig.collectionEndpoint).andReturn().asString(); diff --git a/src/test/java/org/mifos/integrationtest/cucumber/stepdef/ScenarioScopeState.java b/src/test/java/org/mifos/integrationtest/cucumber/stepdef/ScenarioScopeState.java index 0bc37d16..db3f5f2a 100644 --- a/src/test/java/org/mifos/integrationtest/cucumber/stepdef/ScenarioScopeState.java +++ b/src/test/java/org/mifos/integrationtest/cucumber/stepdef/ScenarioScopeState.java @@ -122,4 +122,9 @@ public class ScenarioScopeState { protected String createTransactionChannelRequestBody; protected String createGsmaTransferRequestBody; protected String rtpId; + protected String msisdn; + protected String accountId; + protected String transactionStatusCode; + protected String amount; + protected String currency; } diff --git a/src/test/java/resources/airtel.feature b/src/test/java/resources/airtel.feature new file mode 100644 index 00000000..0e4a42ad --- /dev/null +++ b/src/test/java/resources/airtel.feature @@ -0,0 +1,40 @@ +@airtel +Feature: Airtel Test + + Scenario: AM-001 + Given I can inject MockServer + And I can start mock server + Then I should be able to get instance of mock server + And I can register the stub with "/airtelCallback" endpoint for "POST" request with status of 200 + Then I will update the mock server and register stub as done + Given I have tenant as "payerfsp" + And I have clientCorrelationId as "123456" + And I have MSISDN as "1580354289" + And I have accountId as "L000000001" + And I have amount as "100" + And I have currency as "KES" + And I have the request body with payer ams identifiers using keys MSISDN and accountId, currency "KES", and amount "100" + When I call the channel collection API with client correlation id, country "kenya", callback "/airtelCallback", payment schema "airtel" and expected status of 200 + Then I should get transaction id in response + Then I should be able to verify that "/airtelCallback" endpoint received 1 request with status code "TS" + When I call the get txn API in ops app with transactionId as parameter + Then I should get transaction state as completed and externalId not null + + @aar + Scenario: AM-002 + Given I can inject MockServer + And I can start mock server + And I can register the stub with "/airtelCallback" endpoint for "POST" request with status of 200 + Then I will update the mock server and register stub as done + Given I have tenant as "payerfsp" + And I have clientCorrelationId as "1278320" + And I have MSISDN as "1103687051" + And I have accountId as "L000000001" + And I have amount as "100" + And I have currency as "KES" + And I have the request body with payer ams identifiers using keys MSISDN and accountId, currency "KES", and amount "100" + When I call the channel collection API with client correlation id, country "kenya", callback "/airtelCallback", payment schema "airtel" and expected status of 200 + Then I should get transaction id in response + Then I should be able to verify that "/airtelCallback" endpoint received 1 request with status code "TF" + When I call the get txn API in ops app with transactionId as parameter + Then I should get transaction state as completed and externalId not null diff --git a/src/test/java/resources/channelCollection.feature b/src/test/java/resources/channelCollection.feature index dd351f13..e58252ff 100644 --- a/src/test/java/resources/channelCollection.feature +++ b/src/test/java/resources/channelCollection.feature @@ -11,7 +11,6 @@ Feature: Channel Collection API test | tenant | key1 | key2 | | gorilla | MSISDN | accountid | - Scenario Outline: Post channel collection API with non-existing BPMN flows Given I have tenant as "" And I have the request body with payer ams identifier keys as "" and ""