Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[GOV-75] #187

Open
wants to merge 4 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -169,6 +169,7 @@ dependencies {
implementation 'com.diffplug.spotless:spotless-plugin-gradle:6.17.0'
implementation 'org.mifos:openapi-java-client:2.0.3-SNAPSHOT'
testImplementation 'org.hamcrest:hamcrest:2.2'
testImplementation 'org.apache.commons:commons-csv:1.5'
}

tasks.named('test') {
Expand Down
6 changes: 5 additions & 1 deletion src/main/resources/application.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ paybill:
settlement: "/confirmation"

bulk-processor:
contactpoint: "https://bulk-connector.sandbox.fynarfin.io"
contactpoint: "https://localhost:8443"
endpoints:
bulk-transactions: "/batchtransactions"
simulate: "/simulate"
Expand Down Expand Up @@ -167,6 +167,10 @@ keycloak:
secret: "toCozdqKQut8dpVi7WiXXGVeEqKrrTjp"
grant_type: "password"

config:
completion-threshold-check:
completion-threshold: 90

payerFundTransfer:
tenant:
payer: "gorilla"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -362,7 +362,7 @@ public void callBatchTransactionsRawEndpoint(int expectedStatus) {

@And("I can mock the Batch Transaction Request DTO without payer info")
public void mockBatchTransactionRequestDTOWithoutPayer() throws JsonProcessingException {
BatchRequestDTO batchRequestDTO = mockBatchTransactionRequestDTO();
BatchRequestDTO batchRequestDTO = mockBatchTransactionRequestDTO("mojaloop");
batchRequestDTO = setCreditPartyInMockBatchTransactionRequestDTO(batchRequestDTO);
batchRequestDTO = setDebitPartyInMockBatchTransactionRequestDTO(batchRequestDTO);
assertThat(batchRequestDTO).isNotNull();
Expand Down Expand Up @@ -446,11 +446,11 @@ public void batchTearDown() {
BaseStepDef.response = null;
}

public BatchRequestDTO mockBatchTransactionRequestDTO() {
public BatchRequestDTO mockBatchTransactionRequestDTO(String paymentMode) {
BatchRequestDTO batchRequestDTO = new BatchRequestDTO();
batchRequestDTO.setAmount("100");
batchRequestDTO.setCurrency("USD");
batchRequestDTO.setSubType("mojaloop");
batchRequestDTO.setSubType(paymentMode);
batchRequestDTO.setDescriptionText("Integration test");
return batchRequestDTO;
}
Expand Down Expand Up @@ -648,4 +648,21 @@ public void iShouldAssertTotalTxnCountAndSuccessfulTxnCountInPaymentBatchDetailR
assertThat(BaseStepDef.paymentBatchDetail).isNotNull();
assertThat(BaseStepDef.paymentBatchDetail.getInstructionList().size()).isEqualTo(3);
}
@And("I can mock the Batch Transaction Request DTO without closed loop")
public void iCanMockTheBatchTransactionRequestDTOWithoutClosedLoop() throws JsonProcessingException {
BatchRequestDTO batchRequestDTO = mockBatchTransactionRequestDTO("closedloop");
batchRequestDTO = setCreditPartyInMockBatchTransactionRequestDTO(batchRequestDTO);
batchRequestDTO = setDebitPartyInMockBatchTransactionRequestDTO(batchRequestDTO);
assertThat(batchRequestDTO).isNotNull();
assertThat(batchRequestDTO.getCurrency()).isNotEmpty();
assertThat(batchRequestDTO.getAmount()).isNotEmpty();
assertThat(batchRequestDTO.getSubType()).isNotEmpty();
assertThat(batchRequestDTO.getCreditParty()).isNotEmpty();
BaseStepDef.batchRequestDTO = batchRequestDTO;

List<BatchRequestDTO> batchRequestDTOS = new ArrayList<>();
batchRequestDTOS.add(batchRequestDTO);
BaseStepDef.batchRawRequest = objectMapper.writeValueAsString(batchRequestDTOS);
assertThat(BaseStepDef.batchRawRequest).isNotEmpty();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,162 @@
package org.mifos.integrationtest.cucumber.stepdef;

import com.google.gson.Gson;
import io.cucumber.java.en.And;
import io.cucumber.java.en.Given;
import io.cucumber.java.en.Then;
import io.cucumber.java.en.When;
import io.restassured.RestAssured;
import io.restassured.builder.MultiPartSpecBuilder;
import io.restassured.builder.RequestSpecBuilder;
import io.restassured.builder.ResponseSpecBuilder;
import io.restassured.specification.MultiPartSpecification;
import io.restassured.specification.RequestSpecification;
import org.apache.commons.csv.CSVFormat;
import org.apache.commons.csv.CSVParser;
import org.apache.commons.csv.CSVRecord;
import org.mifos.integrationtest.common.BatchSummaryResponse;
import org.mifos.integrationtest.common.Utils;
import org.mifos.integrationtest.config.BulkProcessorConfig;
import org.mifos.integrationtest.config.OperationsAppConfig;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;

import java.io.File;
import java.io.FileReader;
import java.io.IOException;
import java.io.Reader;
import java.net.URL;
import java.util.HashMap;
import java.util.Map;
import java.util.StringJoiner;

import static com.google.common.truth.Truth.assertThat;

public class BulkPaymentStepDef extends BaseStepDef {

private String batchId;

private int completionPercent;

@Value("${config.completion-threshold-check.completion-threshold}")
private int thresholdPercent;

@Autowired
BulkProcessorConfig bulkProcessorConfig;

@Autowired
OperationsAppConfig operationsAppConfig;

@Given("the CSV file is available")
public boolean isCsvFileAvailable(){
String fileName = "bulk-payment.csv";
ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
URL resource = classLoader.getResource(fileName);
return resource != null && resource.getPath().endsWith(".csv");
}

@When("initiate the batch transaction API with the input CSV file with tenant as {string}")
public void initiateTheBatchTransactionAPIWithTheInputCSVFileWithTenantAs(String tenant) {
Map<String, String> headers = new HashMap<>();
headers.put("Purpose", "test payment");
headers.put("filename", "bulk_payment.csv");
headers.put("X-CorrelationID", "12345678-6897-6798-6798-098765432134");
headers.put("Platform-TenantId", tenant);
String fileContent = getFileContent("bulk-payment.csv");
logger.info("file content: " + fileContent);
RequestSpecification requestSpec = getDefaultSpec();
String response = RestAssured.given(requestSpec)
.baseUri(bulkProcessorConfig.bulkProcessorContactPoint)
.multiPart(getMultiPart(fileContent))
.queryParam("type", "csv")
.headers(headers)
.expect()
.spec(new ResponseSpecBuilder().expectStatusCode(200).build())
.when()
.post(bulkProcessorConfig.bulkTransactionEndpoint)
.andReturn().asString();
batchId = fetchBatchId(response);
logger.info(batchId);
logger.info("Batch transaction API response: " + response);
}

@Given("the batch ID for the submitted CSV file")
public void isBatchIdAvailable(){
assertThat(batchId).isNotEmpty();
}

@And("poll the batch summary API using the batch ID and tenant as {string}")
public void pollTheBatchSummaryAPIUsingTheBatchIDAndTenantAs(String tenant) {
int retries = 5;
int intervalInSeconds = 30;

Map<String, String> headers = new HashMap<>();
headers.put("Platform-TenantId", tenant);
RequestSpecification requestSpec = getDefaultSpec();

for(int index = 0; index < retries; index++) {
String response = RestAssured.given(requestSpec)
.baseUri(operationsAppConfig.operationAppContactPoint)
.param("batchId", batchId)
.headers(headers)
.expect()
.spec(new ResponseSpecBuilder().expectStatusCode(200).build())
.when()
.get(operationsAppConfig.batchSummaryEndpoint)
.andReturn().asString();
Gson gson = new Gson();
BatchSummaryResponse batchSummaryResponse = gson.fromJson(response, BatchSummaryResponse.class);
assertThat(batchSummaryResponse).isNotNull();

if(batchSummaryResponse.getTotal() != 0){
completionPercent = (int) (batchSummaryResponse.getSuccessful()/ batchSummaryResponse.getTotal() * 100);
}
Utils.sleep(intervalInSeconds);
}
}

@Then("successful transactions percentage should be greater than or equal to minimum threshold")
public void batchSummarySuccessful(){
assertThat(completionPercent).isNotNull();
assertThat(completionPercent).isGreaterThan(thresholdPercent);
}

private static RequestSpecification getDefaultSpec() {
RequestSpecification requestSpec = new RequestSpecBuilder().build();
requestSpec.relaxedHTTPSValidation();
return requestSpec;
}

private MultiPartSpecification getMultiPart(String fileContent) {
return new MultiPartSpecBuilder(fileContent.getBytes()).
fileName("test.csv").
controlName("file").
mimeType("text/plain").
build();
}

private String getFileContent(String filePath) {
File file = new File(filePath);
Reader reader;
CSVFormat csvFormat;
CSVParser csvParser = null;
try {
reader = new FileReader(file);
csvFormat = CSVFormat.DEFAULT.withDelimiter(',');
csvParser = new CSVParser(reader, csvFormat);
} catch (IOException e) {
throw new RuntimeException(e);
}
StringJoiner stringJoiner = new StringJoiner("\n");

for (CSVRecord csvRecord : csvParser) {
stringJoiner.add(csvRecord.toString());
}
return stringJoiner.toString();
}

private String fetchBatchId(String response) {
String[] split = response.split(",");
return split[0].substring(31);
}
}
11 changes: 11 additions & 0 deletions src/test/java/resources/batch_demo_csv/bulk_payment.csv
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
id,request_id,payment_mode,payer_identifier_type,payer_identifier,payee_identifier_type,payee_identifier,amount,currency,note
0,f1e22fe3-9740-4fba-97b6-78f43bfa7f2f,closedloop,msisdn,835322416,msisdn,277138039112,10,USD,Moja bulk test
1,39f6ac4d052e-72aa3ea4-e6f6-4880-877f,closedloop,msisdn,835322416,msisdn,277138039122,10,USD,Moja bulk test
2,a27631f6-6dd4-4d69-b4fc-8932bd721913,closedloop,msisdn,835322416,msisdn,277138039123,10,USD,Moja bulk test
3,3d21e6ea-c583-44ed-b94f-af909fa7616e,closedloop,msisdn,835322416,msisdn,277138039124,10,USD,Moja bulk test
4,15f9a0b0-2299-436d-8433-da564140ba66,closedloop,msisdn,835322416,msisdn,277138039512,10,USD,Moja bulk test
5,f1e22fe3-9740-4fba-97b6-78f49bfa7f2f,closedloop,msisdn,835322416,msisdn,277138039612,10,USD,Moja bulk test
6,39f6ac4d052e-72aa3ea4-e6f6-4380-877f,closedloop,msisdn,835322416,msisdn,277138039172,10,USD,Moja bulk test
7,a27631f6-6dd4-4d69-b4fc-8452bd721913,closedloop,msisdn,835322416,msisdn,277138039182,10,USD,Moja bulk test
8,3d21e6ea-c583-44ed-b94f-af909fu7616e,closedloop,msisdn,835322416,msisdn,277138039192,10,USD,Moja bulk test
9,15f9a0b0-2299-436d-8433-da667140ba66,closedloop,msisdn,835322416,msisdn,277138039120,10,USD,Moja bulk test
19 changes: 19 additions & 0 deletions src/test/java/resources/bulkPayment.feature
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
@gov
Feature: Test ability to make payment to individual with bank account

Scenario: Input CSV file using the batch transaction API and poll batch summary API till we get completed status
Given I have tenant as "gorilla"
And I have the demo csv file "bulk_payment.csv"
And I create a new clientCorrelationId
And I have private key
And I generate signature
When I call the batch transactions endpoint with expected status of 202
Then I should get non empty response
And I am able to parse batch transactions response
And I fetch batch ID from batch transaction API's response
Then I will sleep for 10000 millisecond
Given I have tenant as "gorilla"
When I call the batch summary API with expected status of 200
Then I am able to parse batch summary response
And Status of transaction is "COMPLETED"
And I should have matching total txn count and successful txn count in response