You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@fineract.apache.org by ar...@apache.org on 2022/11/16 13:04:42 UTC

[fineract] branch develop updated: Fix credit bureau organisation result processing in the test case. FINERACT-1724 [x] Unit test for ThitsaWorksCreditBureauIntegrationWritePlatformServiceImpl [x] Integration test for CreditBureau with WireMock [x] Fix enum key case sensitivity on postgres [x] Fix update key typo [x] Add missing credit bureau organization fix for test cases

This is an automated email from the ASF dual-hosted git repository.

arnold pushed a commit to branch develop
in repository https://gitbox.apache.org/repos/asf/fineract.git


The following commit(s) were added to refs/heads/develop by this push:
     new 6ba5d7d5c Fix credit bureau organisation result processing in the test case. FINERACT-1724 [x] Unit test for ThitsaWorksCreditBureauIntegrationWritePlatformServiceImpl [x] Integration test for CreditBureau with WireMock [x] Fix enum key case sensitivity on postgres [x] Fix update key typo [x] Add missing credit bureau organization fix for test cases
6ba5d7d5c is described below

commit 6ba5d7d5c491db70a8069b6bc891fac897be09af
Author: Janos Haber <ja...@finesolution.hu>
AuthorDate: Fri Nov 11 15:31:05 2022 +0100

    Fix credit bureau organisation result processing in the test case.
    FINERACT-1724
    [x] Unit test for ThitsaWorksCreditBureauIntegrationWritePlatformServiceImpl
    [x] Integration test for CreditBureau with WireMock
    [x] Fix enum key case sensitivity on postgres
    [x] Fix update key typo
    [x] Add missing credit bureau organization fix for test cases
---
 .../domain/CreditBureauConfiguration.java          |   2 +-
 ...tBureauIntegrationWritePlatformServiceImpl.java |  11 +-
 ...eauIntegrationWritePlatformServiceImplTest.java | 572 +++++++++++++++++++++
 integration-tests/dependencies.gradle              |   1 +
 .../integrationtests/CreditBureauTest.java         | 187 +++++++
 .../common/CreditBureauConfigurationHelper.java    |  80 ++-
 .../common/CreditBureauIntegrationHelper.java      |  69 +++
 7 files changed, 910 insertions(+), 12 deletions(-)

diff --git a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/creditbureau/domain/CreditBureauConfiguration.java b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/creditbureau/domain/CreditBureauConfiguration.java
index b00412b20..d7003cbe4 100644
--- a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/creditbureau/domain/CreditBureauConfiguration.java
+++ b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/creditbureau/domain/CreditBureauConfiguration.java
@@ -68,7 +68,7 @@ public class CreditBureauConfiguration extends AbstractPersistableCustom {
 
         final Map<String, Object> actualChanges = new LinkedHashMap<>(1);
 
-        final String configurationKey = "configurationKey";
+        final String configurationKey = "configkey";
 
         if (command.isChangeInStringParameterNamed(configurationKey, this.configurationKey)) {
             final String newValue = command.stringValueOfParameterNamed(configurationKey);
diff --git a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/creditbureau/service/ThitsaWorksCreditBureauIntegrationWritePlatformServiceImpl.java b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/creditbureau/service/ThitsaWorksCreditBureauIntegrationWritePlatformServiceImpl.java
index 1e1fd69a6..fd97328c7 100644
--- a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/creditbureau/service/ThitsaWorksCreditBureauIntegrationWritePlatformServiceImpl.java
+++ b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/creditbureau/service/ThitsaWorksCreditBureauIntegrationWritePlatformServiceImpl.java
@@ -73,11 +73,21 @@ public class ThitsaWorksCreditBureauIntegrationWritePlatformServiceImpl implemen
     private final CreditBureauConfigurationRepositoryWrapper configDataRepository;
     private final CreditBureauTokenCommandFromApiJsonDeserializer fromApiJsonDeserializer;
 
+    private final OkHttpClient client;
+
     @Autowired
     public ThitsaWorksCreditBureauIntegrationWritePlatformServiceImpl(final PlatformSecurityContext context,
             final FromJsonHelper fromApiJsonHelper, final TokenRepositoryWrapper tokenRepositoryWrapper,
             final CreditBureauConfigurationRepositoryWrapper configDataRepository,
             final CreditBureauTokenCommandFromApiJsonDeserializer fromApiJsonDeserializer) {
+        this(new OkHttpClient(), context, fromApiJsonHelper, tokenRepositoryWrapper, configDataRepository, fromApiJsonDeserializer);
+    }
+
+    public ThitsaWorksCreditBureauIntegrationWritePlatformServiceImpl(final OkHttpClient okHttpClient,
+            final PlatformSecurityContext context, final FromJsonHelper fromApiJsonHelper,
+            final TokenRepositoryWrapper tokenRepositoryWrapper, final CreditBureauConfigurationRepositoryWrapper configDataRepository,
+            final CreditBureauTokenCommandFromApiJsonDeserializer fromApiJsonDeserializer) {
+        this.client = okHttpClient;
         this.context = context;
         this.tokenRepositoryWrapper = tokenRepositoryWrapper;
         this.configDataRepository = configDataRepository;
@@ -93,7 +103,6 @@ public class ThitsaWorksCreditBureauIntegrationWritePlatformServiceImpl implemen
 
         String reponseMessage = null;
         RequestBody requestBody = null;
-        OkHttpClient client = new OkHttpClient();
 
         if (process.equals("UploadCreditReport")) {
             String fileName = fileData.getFileName();
diff --git a/fineract-provider/src/test/java/org/apache/fineract/infrastructure/creditbureau/service/ThitsaWorksCreditBureauIntegrationWritePlatformServiceImplTest.java b/fineract-provider/src/test/java/org/apache/fineract/infrastructure/creditbureau/service/ThitsaWorksCreditBureauIntegrationWritePlatformServiceImplTest.java
new file mode 100644
index 000000000..d241255ae
--- /dev/null
+++ b/fineract-provider/src/test/java/org/apache/fineract/infrastructure/creditbureau/service/ThitsaWorksCreditBureauIntegrationWritePlatformServiceImplTest.java
@@ -0,0 +1,572 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.fineract.infrastructure.creditbureau.service;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertNotNull;
+import static org.junit.jupiter.api.Assertions.assertNull;
+import static org.junit.jupiter.api.Assertions.assertThrows;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+import static org.mockito.Mockito.doNothing;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+import com.fasterxml.jackson.core.JsonProcessingException;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.fasterxml.jackson.databind.node.ArrayNode;
+import com.fasterxml.jackson.databind.node.ObjectNode;
+import com.google.gson.JsonParser;
+import io.vavr.CheckedFunction1;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.time.ZoneId;
+import java.time.ZonedDateTime;
+import java.time.format.DateTimeFormatterBuilder;
+import java.util.List;
+import java.util.function.Function;
+import java.util.function.Supplier;
+import okhttp3.Call;
+import okhttp3.MediaType;
+import okhttp3.OkHttpClient;
+import okhttp3.Request;
+import okhttp3.Response;
+import okhttp3.ResponseBody;
+import okio.BufferedSink;
+import okio.Okio;
+import org.apache.fineract.infrastructure.core.api.JsonCommand;
+import org.apache.fineract.infrastructure.core.exception.PlatformDataIntegrityException;
+import org.apache.fineract.infrastructure.core.serialization.FromJsonHelper;
+import org.apache.fineract.infrastructure.creditbureau.data.CreditBureauConfigurations;
+import org.apache.fineract.infrastructure.creditbureau.data.CreditBureauReportData;
+import org.apache.fineract.infrastructure.creditbureau.domain.CreditBureauConfiguration;
+import org.apache.fineract.infrastructure.creditbureau.domain.CreditBureauConfigurationRepositoryWrapper;
+import org.apache.fineract.infrastructure.creditbureau.domain.CreditBureauToken;
+import org.apache.fineract.infrastructure.creditbureau.domain.TokenRepositoryWrapper;
+import org.apache.fineract.infrastructure.creditbureau.serialization.CreditBureauTokenCommandFromApiJsonDeserializer;
+import org.apache.fineract.infrastructure.security.service.PlatformSecurityContext;
+import org.glassfish.jersey.media.multipart.FormDataContentDisposition;
+import org.jetbrains.annotations.NotNull;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import org.mockito.ArgumentCaptor;
+import org.mockito.InjectMocks;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+import org.mockito.Spy;
+
+public class ThitsaWorksCreditBureauIntegrationWritePlatformServiceImplTest {
+
+    @Spy
+    private FromJsonHelper fromJsonHelper = new FromJsonHelper();
+
+    @Spy
+    private CreditBureauTokenCommandFromApiJsonDeserializer fromApiJsonDeserializer = new CreditBureauTokenCommandFromApiJsonDeserializer(
+            fromJsonHelper);
+    @Mock
+    private OkHttpClient okHttpClient;
+
+    @Mock
+    private CreditBureauConfigurationRepositoryWrapper configurationRepositoryWrapper;
+
+    @Mock
+    private PlatformSecurityContext platformSecurityContext;
+
+    @Mock
+    private TokenRepositoryWrapper tokenRepositoryWrapper;
+
+    private final ObjectMapper mapper = new ObjectMapper();
+
+    @InjectMocks
+    private ThitsaWorksCreditBureauIntegrationWritePlatformServiceImpl underTest;
+
+    @BeforeEach
+    public void setup() {
+        MockitoAnnotations.openMocks(this);
+        when(configurationRepositoryWrapper.getCreditBureauConfigData(1, CreditBureauConfigurations.USERNAME.name()))
+                .thenReturn(new CreditBureauConfiguration().setValue("testUsername"));
+        when(configurationRepositoryWrapper.getCreditBureauConfigData(1, CreditBureauConfigurations.PASSWORD.name()))
+                .thenReturn(new CreditBureauConfiguration().setValue("testPassword"));
+        when(configurationRepositoryWrapper.getCreditBureauConfigData(1, CreditBureauConfigurations.CREDITREPORTURL.name()))
+                .thenReturn(new CreditBureauConfiguration().setValue("https://credit.report.url/api/"));
+        when(configurationRepositoryWrapper.getCreditBureauConfigData(1, CreditBureauConfigurations.SEARCHURL.name()))
+                .thenReturn(new CreditBureauConfiguration().setValue("https://search.report.url/api/"));
+        when(configurationRepositoryWrapper.getCreditBureauConfigData(1, CreditBureauConfigurations.TOKENURL.name()))
+                .thenReturn(new CreditBureauConfiguration().setValue("https://token.url/api/"));
+        when(configurationRepositoryWrapper.getCreditBureauConfigData(1, CreditBureauConfigurations.SUBSCRIPTIONID.name()))
+                .thenReturn(new CreditBureauConfiguration().setValue("subscriptionId"));
+        when(configurationRepositoryWrapper.getCreditBureauConfigData(1, CreditBureauConfigurations.SUBSCRIPTIONKEY.name()))
+                .thenReturn(new CreditBureauConfiguration().setValue("subscriptionKey"));
+
+    }
+
+    private String createResponseObjectArrayData(Supplier<String> responseMessageGenerator, Function<ArrayNode, ArrayNode> dataGenerator)
+            throws JsonProcessingException {
+        ObjectNode jsonResponse = mapper.createObjectNode();
+
+        jsonResponse.put("ResponseMessage", responseMessageGenerator.get());
+        jsonResponse.set("Data", dataGenerator.apply(mapper.createArrayNode()));
+        return mapper.writeValueAsString(jsonResponse);
+    }
+
+    private String createResponseObjectObjectData(Supplier<String> responseMessageGenerator, Function<ObjectNode, ObjectNode> dataGenerator)
+            throws JsonProcessingException {
+        ObjectNode jsonResponse = mapper.createObjectNode();
+
+        jsonResponse.put("ResponseMessage", responseMessageGenerator.get());
+        jsonResponse.set("Data", dataGenerator.apply(mapper.createObjectNode()));
+        return mapper.writeValueAsString(jsonResponse);
+    }
+
+    public void mockOkHttpCall(CheckedFunction1<Request, Response> responseGenerator) throws IOException {
+        ArgumentCaptor<Request> requestCaptor = ArgumentCaptor.forClass(Request.class);
+        Call callMock = mock(Call.class);
+        when(okHttpClient.newCall(requestCaptor.capture())).thenReturn(callMock);
+        when(callMock.execute()).thenAnswer(invocation -> responseGenerator.apply(requestCaptor.getValue()));
+    }
+
+    public Response createOkhttpResponse(Request request, String body) {
+        return new Response.Builder().request(request).protocol(okhttp3.Protocol.HTTP_1_1).code(200).message("")
+                .body(ResponseBody.create(body, MediaType.parse("application/json"))).build();
+    }
+
+    public Response createOkhttpResponse(Request request, int status, String message, ResponseBody body) {
+        return new Response.Builder().request(request).protocol(okhttp3.Protocol.HTTP_1_1).code(status).message(message).body(body).build();
+    }
+
+    public Response createOkhttpResponse(Request request, int status, String message) {
+        return new Response.Builder().request(request).protocol(okhttp3.Protocol.HTTP_1_1).code(status).message(message)
+                .body(ResponseBody.create(message, MediaType.parse("text/html"))).build();
+    }
+
+    @Test
+    public void okHttpInternalServerErrorTest() throws IOException {
+
+        mockOkHttpCall(request -> createOkhttpResponse(request, 500, "Internal Server Error"));
+
+        assertThrows(PlatformDataIntegrityException.class, () -> {
+            underTest.okHttpConnectionMethod("testUser", "testPassword", "subscriptionKey", "subscriptionId", "https://nrc.test.url.com",
+                    "AccessToken", null, null, 0L, "nrcId", "NRC");
+
+        });
+
+    }
+
+    @Test
+    public void okHttpIOExceptionTest() throws IOException {
+        mockOkHttpCall(request -> {
+            throw new IOException("IO Exception");
+        });
+
+        assertThrows(PlatformDataIntegrityException.class, () -> {
+            underTest.okHttpConnectionMethod("testUser", "testPassword", "subscriptionKey", "subscriptionId", "https://nrc.test.url.com",
+                    "AccessToken", null, null, 0L, "nrcId", "NRC");
+
+        });
+
+    }
+
+    @Test
+    public void okHttpNrcSuccessTest() throws IOException {
+
+        String jsonResponse = createResponseObjectArrayData(() -> "Success",
+                data -> data.add(mapper.createObjectNode().put("UniqueID", "123456")));
+
+        mockOkHttpCall(request -> {
+            assertEquals(request.header("Authorization"), "Bearer AccessToken");
+            assertEquals(request.header("mcix-subscription-key"), "subscriptionKey");
+            assertEquals(request.header("mcix-subscription-id"), "subscriptionId");
+            assertEquals(request.header("Content-Type"), "application/x-www-form-urlencoded");
+            BufferedSink sink = Okio.buffer(Okio.sink(new ByteArrayOutputStream()));
+            request.body().writeTo(sink);
+            String urlEncodedForm = sink.getBuffer().readUtf8();
+            assertTrue(urlEncodedForm.contains("nrc=nrcId"));
+            return createOkhttpResponse(request, jsonResponse);
+        });
+
+        String result = underTest.okHttpConnectionMethod("testUser", "testPassword", "subscriptionKey", "subscriptionId",
+                "https://nrc.test.url.com", "AccessToken", null, null, 0L, "nrcId", "NRC");
+        assertEquals(jsonResponse, result);
+    }
+
+    @Test
+    public void okHttpNrcNoTokenTest() throws IOException {
+
+        String jsonResponse = createResponseObjectArrayData(() -> "Success",
+                data -> data.add(mapper.createObjectNode().put("UniqueID", "123456")));
+
+        mockOkHttpCall(request -> {
+            List<String> auhtorizationHeaders = request.headers("Authorization");
+            assertTrue(auhtorizationHeaders.isEmpty());
+            assertEquals(request.header("mcix-subscription-key"), "subscriptionKey");
+            assertEquals(request.header("mcix-subscription-id"), "subscriptionId");
+            assertEquals(request.header("Content-Type"), "application/x-www-form-urlencoded");
+            BufferedSink sink = Okio.buffer(Okio.sink(new ByteArrayOutputStream()));
+            request.body().writeTo(sink);
+            String urlEncodedForm = sink.getBuffer().readUtf8();
+            assertTrue(urlEncodedForm.contains("nrc=nrcId"));
+            return createOkhttpResponse(request, jsonResponse);
+        });
+
+        String result = underTest.okHttpConnectionMethod("testUser", "testPassword", "subscriptionKey", "subscriptionId",
+                "https://nrc.test.url.com", null, null, null, 0L, "nrcId", "NRC");
+        assertEquals(jsonResponse, result);
+    }
+
+    @Test
+    public void okhttpUploadCreditReportTest() throws IOException {
+
+        String jsonResponse = createResponseObjectArrayData(() -> "UPLOADED", data -> data);
+
+        Path temp = Files.createTempFile("upload_test" + System.currentTimeMillis(), ".data");
+        Files.writeString(temp, "test");
+
+        mockOkHttpCall(request -> {
+            assertEquals(request.header("Authorization"), "Bearer AccessToken");
+            assertEquals(request.header("mcix-subscription-key"), "subscriptionKey");
+            assertEquals(request.header("mcix-subscription-id"), "subscriptionId");
+            assertEquals(request.header("Content-Type"), "multipart/form-data");
+            return createOkhttpResponse(request, jsonResponse);
+        });
+        FormDataContentDisposition fileDetail = mock(FormDataContentDisposition.class);
+        when(fileDetail.getFileName()).thenReturn("test.pdf");
+
+        PlatformDataIntegrityException resultException = assertThrows(PlatformDataIntegrityException.class, () -> {
+            underTest.okHttpConnectionMethod("testUser", "testPassword", "subscriptionKey", "subscriptionId", "https://upload.test.url.com",
+                    "AccessToken", temp.toFile(), fileDetail, 0L, "nrcId", "UploadCreditReport");
+        });
+        assertEquals("UPLOADED", resultException.getDefaultUserMessage());
+    }
+
+    @Test
+    public void okHttpNoTokenTest() throws IOException {
+        mockOkHttpCall(request -> {
+            List<String> auhtorizationHeaders = request.headers("Authorization");
+            assertTrue(auhtorizationHeaders.isEmpty());
+            assertEquals(request.header("mcix-subscription-key"), "subscriptionKey");
+            assertEquals(request.header("mcix-subscription-id"), "subscriptionId");
+            assertEquals(request.header("Content-Type"), "application/x-www-form-urlencoded");
+            BufferedSink sink = Okio.buffer(Okio.sink(new ByteArrayOutputStream()));
+            request.body().writeTo(sink);
+            String urlEncodedForm = sink.getBuffer().readUtf8();
+            assertTrue(urlEncodedForm.contains("grant_type=password"));
+            assertTrue(urlEncodedForm.contains("userName=testUser"));
+            assertTrue(urlEncodedForm.contains("password=testPassword"));
+            return createOkhttpResponse(request, 401, "Unauthorized");
+        });
+        assertThrows(PlatformDataIntegrityException.class, () -> {
+            underTest.okHttpConnectionMethod("testUser", "testPassword", "subscriptionKey", "subscriptionId", "https://nrc.test.url.com",
+                    null, null, null, 0L, "nrcId", "token");
+        });
+    }
+
+    @Test
+    public void okHttpGetNrcReportSuccessTest() throws IOException {
+
+        String jsonResponse = createResponseObjectArrayData(() -> "Success",
+                data -> data.add(mapper.createObjectNode().put("UniqueID", "123456")));
+
+        mockOkHttpCall(request -> {
+            assertEquals(request.header("Authorization"), "Bearer AccessToken");
+            assertEquals(request.header("mcix-subscription-key"), "subscriptionKey");
+            assertEquals(request.header("mcix-subscription-id"), "subscriptionId");
+            assertEquals(request.header("Content-Type"), "application/x-www-form-urlencoded");
+            return createOkhttpResponse(request, jsonResponse);
+        });
+
+        String result = underTest.okHttpConnectionMethod("testUser", "testPassword", "subscriptionKey", "subscriptionId",
+                "https://nrc.test.url.com", "AccessToken", null, null, 0L, "nrcId", "CreditReport");
+        assertEquals(jsonResponse, result);
+    }
+
+    @Test
+    public void okHttpForbiddenTest() throws IOException {
+        mockOkHttpCall(request -> createOkhttpResponse(request, 403, "Forbidden"));
+
+        assertThrows(PlatformDataIntegrityException.class, () -> {
+            underTest.okHttpConnectionMethod("testUser", "testPassword", "subscriptionKey", "subscriptionId", "https://nrc.test.url.com",
+                    "AccessToken", null, null, 0L, "nrcId", "CreditReport");
+        });
+    }
+
+    @Test // TODO: Null body not handled
+    public void okHttpNoBodyReturned() throws IOException {
+        mockOkHttpCall(request -> createOkhttpResponse(request, 200, "OK", null));
+
+        assertThrows(NullPointerException.class, () -> {
+            underTest.okHttpConnectionMethod("testUser", "testPassword", "subscriptionKey", "subscriptionId", "https://nrc.test.url.com",
+                    "AccessToken", null, null, 0L, "nrcId", "CreditReport");
+        });
+    }
+
+    @Test
+    public void extractUniqueIdSuccessTest() throws JsonProcessingException {
+        String json = createResponseObjectArrayData(() -> "Success", data -> data.add(mapper.createObjectNode().put("UniqueID", "123456")));
+        Long id = underTest.extractUniqueId(json);
+        assertEquals(123456L, id.longValue());
+    }
+
+    @Test
+    public void extractUniqueIdEmptyResultTest() throws JsonProcessingException {
+        String json = createResponseObjectArrayData(() -> "NoResult", data -> data);
+        PlatformDataIntegrityException result = assertThrows(PlatformDataIntegrityException.class, () -> {
+            underTest.extractUniqueId(json);
+        });
+        assertEquals("NoResult", result.getDefaultUserMessage());
+    }
+
+    @Test
+    public void extractUniqueIdMultipleResultTest() throws JsonProcessingException {
+        String json = createResponseObjectArrayData(() -> "NoResult",
+                data -> data.add(mapper.createObjectNode().put("UniqueID", "123456").put("NRC", "NRCID1"))
+                        .add(mapper.createObjectNode().put("UniqueID", "7654321").put("NRC", "NRCID2")));
+        PlatformDataIntegrityException result = assertThrows(PlatformDataIntegrityException.class, () -> {
+            underTest.extractUniqueId(json);
+        });
+        assertTrue(result.getDefaultUserMessage().contains("\"NRCID1\", \"NRCID2\""));
+    }
+
+    @Test
+    public void extractUniqueIdNoDataTest() throws JsonProcessingException {
+        String json = createResponseObjectArrayData(() -> "NoData", data -> null);
+        PlatformDataIntegrityException result = assertThrows(PlatformDataIntegrityException.class, () -> {
+            underTest.extractUniqueId(json);
+        });
+        assertEquals("NoData", result.getDefaultUserMessage());
+    }
+
+    @Test
+    public void createTokenTest() throws IOException {
+        mockTokenGeneration();
+        mockOkHttpCall(request -> {
+            List<String> auhtorizationHeaders = request.headers("Authorization");
+            assertTrue(auhtorizationHeaders.isEmpty());
+            assertEquals(request.header("mcix-subscription-key"), "subscriptionKey");
+            assertEquals(request.header("mcix-subscription-id"), "subscriptionId");
+            assertEquals(request.header("Content-Type"), "application/x-www-form-urlencoded");
+            BufferedSink sink = Okio.buffer(Okio.sink(new ByteArrayOutputStream()));
+            request.body().writeTo(sink);
+            String urlEncodedForm = sink.getBuffer().readUtf8();
+            assertTrue(urlEncodedForm.contains("grant_type=password"));
+            assertTrue(urlEncodedForm.contains("userName=testUser"));
+            assertTrue(urlEncodedForm.contains("password=testPassword"));
+
+            return createOkhttpResponse(request, 200, createValidToken());
+        });
+        CreditBureauToken token = underTest.createToken(1L);
+        assertNotNull(token);
+    }
+
+    @NotNull
+    private String createValidToken() throws JsonProcessingException {
+        ObjectNode jsonResponse = mapper.createObjectNode();
+        jsonResponse.put("access_token", "AccessToken");
+        jsonResponse.put("expires_in", 3600);
+        jsonResponse.put("token_type", "Bearer");
+        jsonResponse.put("userName", "testUser");
+        jsonResponse.put(".issued", "sample");
+        jsonResponse.put(".expires", ZonedDateTime.now(ZoneId.systemDefault()).plusSeconds(3600)
+                .format(new DateTimeFormatterBuilder().appendPattern("EEE, dd MMM yyyy kk:mm:ss zzz").toFormatter()));
+        return mapper.writeValueAsString(jsonResponse);
+    }
+
+    private JsonCommand initialJsonCommand() throws JsonProcessingException {
+        ObjectNode command = mapper.createObjectNode();
+        command.put("NRC", "NRCID");
+        command.put("creditBureauID", "1"); // Must match to the mocked config
+        String json = mapper.writeValueAsString(command);
+        return JsonCommand.from(json, JsonParser.parseString(json), fromJsonHelper, null, 1L, 2L, 3L, 4L, null, null, null, null, null,
+                null, null, null);
+    }
+
+    private void mockTokenGeneration() {
+        ArgumentCaptor<CreditBureauToken> tokenCaptor = ArgumentCaptor.forClass(CreditBureauToken.class);
+        when(tokenRepositoryWrapper.getToken()).thenAnswer(answer -> {
+            if (tokenCaptor.getAllValues().isEmpty()) {
+                return null;
+            }
+            return tokenCaptor.getValue();
+        });
+        doNothing().when(tokenRepositoryWrapper).save(tokenCaptor.capture());
+    }
+
+    @Test
+    public void getCreditReportFromThitsaWorksSuccessTest() throws IOException {
+        mockTokenGeneration();
+        mockOkHttpCall(request -> {
+            // NRC Call
+            if (request.url().host().equals("search.report.url")) {
+                return createOkhttpResponse(request, createResponseObjectArrayData(() -> "Success",
+                        data -> data.add(mapper.createObjectNode().put("UniqueID", "123456"))));
+            }
+            if (request.url().host().equals("credit.report.url")) {
+                assertTrue(request.url().encodedPath().endsWith("/123456"));
+                return createOkhttpResponse(request, createResponseObjectObjectData(() -> "Success", data -> {
+                    ObjectNode borrowerData = mapper.createObjectNode();
+                    borrowerData.put("Name", "Test Name");
+                    borrowerData.put("Gender", "Male");
+                    borrowerData.put("Address", "Test Address");
+                    data.set("BorrowerInfo", borrowerData);
+                    data.set("CreditScore", mapper.createObjectNode().put("Score", "123"));
+                    data.set("ActiveLoans", mapper.createArrayNode().add("Loan1").add("Loan2"));
+                    data.set("WriteOffLoans", mapper.createArrayNode().add("Loan3").add("Loan4"));
+                    return data;
+                }));
+            }
+            if (request.url().host().equals("token.url")) {
+                return createOkhttpResponse(request, 200, createValidToken());
+            }
+            return createOkhttpResponse(request, 404, "Not Found");
+        });
+
+        CreditBureauReportData result = underTest.getCreditReportFromThitsaWorks(initialJsonCommand());
+        assertNotNull(result);
+    }
+
+    @Test
+    public void addCreditReportTest() throws IOException {
+        mockTokenGeneration();
+
+        when(configurationRepositoryWrapper.getCreditBureauConfigData(1, "addCreditReporturl"))
+                .thenReturn(new CreditBureauConfiguration().setValue("https://addcredit.report.url/api/"));
+        String jsonResponse = createResponseObjectArrayData(() -> "ADD_CREDIT_RESPONSE", data -> data);
+
+        Path temp = Files.createTempFile("add_credit_report" + System.currentTimeMillis(), ".data");
+        Files.writeString(temp, "test");
+
+        mockOkHttpCall(request -> {
+            if (request.url().host().equals("addcredit.report.url")) {
+                return createOkhttpResponse(request, jsonResponse);
+            }
+            if (request.url().host().equals("token.url")) {
+                return createOkhttpResponse(request, 200, createValidToken());
+            }
+            return createOkhttpResponse(request, 404, "Not Found");
+        });
+        FormDataContentDisposition fileDetail = mock(FormDataContentDisposition.class);
+        when(fileDetail.getFileName()).thenReturn("test.pdf");
+
+        PlatformDataIntegrityException result = assertThrows(PlatformDataIntegrityException.class,
+                () -> underTest.addCreditReport(1L, temp.toFile(), fileDetail));
+        assertEquals("ADD_CREDIT_RESPONSE", result.getDefaultUserMessage());
+    }
+
+    // TODO: if no borrower is throw NPE
+    // @Test
+    public void getCreditReportFromThitsaWorksEmptyBorrowerTest() throws IOException {
+        mockTokenGeneration();
+        mockOkHttpCall(request -> {
+            // NRC Call
+            if (request.url().host().equals("search.report.url")) {
+                return createOkhttpResponse(request, createResponseObjectArrayData(() -> "Success",
+                        data -> data.add(mapper.createObjectNode().put("UniqueID", "123456"))));
+            }
+            if (request.url().host().equals("credit.report.url")) {
+                assertTrue(request.url().encodedPath().endsWith("/123456"));
+                return createOkhttpResponse(request, createResponseObjectObjectData(() -> "Success", data -> {
+                    data.set("CreditScore", mapper.createObjectNode().put("Score", "123"));
+                    data.set("ActiveLoans", mapper.createArrayNode().add("Loan1").add("Loan2"));
+                    data.set("WriteOffLoans", mapper.createArrayNode().add("Loan3").add("Loan4"));
+                    return data;
+                }));
+            }
+            if (request.url().host().equals("token.url")) {
+                return createOkhttpResponse(request, 200, createValidToken());
+            }
+            return createOkhttpResponse(request, 404, "Not Found");
+        });
+
+        CreditBureauReportData result = underTest.getCreditReportFromThitsaWorks(initialJsonCommand());
+        assertNotNull(result);
+        assertNull(result.getGender());
+        assertNotNull(result.getCreditScore());
+    }
+
+    // TODO: empty gender not handler correctly (NPE)
+    // @Test
+    public void getCreditReportFromThitsaWorksNoGenderTest() throws IOException {
+        mockTokenGeneration();
+        mockOkHttpCall(request -> {
+            // NRC Call
+            if (request.url().host().equals("search.report.url")) {
+                return createOkhttpResponse(request, createResponseObjectArrayData(() -> "Success",
+                        data -> data.add(mapper.createObjectNode().put("UniqueID", "123456"))));
+            }
+            if (request.url().host().equals("credit.report.url")) {
+                assertTrue(request.url().encodedPath().endsWith("/123456"));
+                return createOkhttpResponse(request, createResponseObjectObjectData(() -> "Success", data -> {
+                    ObjectNode borrowerData = mapper.createObjectNode();
+                    borrowerData.put("Name", "Test Name");
+                    borrowerData.put("Address", "Test Address");
+                    data.set("BorrowerInfo", borrowerData);
+                    data.set("CreditScore", mapper.createObjectNode().put("Score", "123"));
+                    data.set("ActiveLoans", mapper.createArrayNode().add("Loan1").add("Loan2"));
+                    data.set("WriteOffLoans", mapper.createArrayNode().add("Loan3").add("Loan4"));
+                    return data;
+                }));
+            }
+            if (request.url().host().equals("token.url")) {
+                return createOkhttpResponse(request, 200, createValidToken());
+            }
+            return createOkhttpResponse(request, 404, "Not Found");
+        });
+
+        CreditBureauReportData result = underTest.getCreditReportFromThitsaWorks(initialJsonCommand());
+        assertNotNull(result);
+        assertNull(result.getGender());
+        assertNotNull(result.getCreditScore());
+    }
+
+    // TODO: null credit script invalid result
+    // @Test
+    public void getCreditReportFromThitsaWorksNoLoansTest() throws IOException {
+        mockTokenGeneration();
+        mockOkHttpCall(request -> {
+            // NRC Call
+            if (request.url().host().equals("search.report.url")) {
+                return createOkhttpResponse(request, createResponseObjectArrayData(() -> "Success",
+                        data -> data.add(mapper.createObjectNode().put("UniqueID", "123456"))));
+            }
+            if (request.url().host().equals("credit.report.url")) {
+                assertTrue(request.url().encodedPath().endsWith("/123456"));
+                return createOkhttpResponse(request, createResponseObjectObjectData(() -> "Success", data -> {
+                    ObjectNode borrowerData = mapper.createObjectNode();
+                    borrowerData.put("Name", "Test Name");
+                    borrowerData.put("Gender", "Male");
+                    borrowerData.put("Address", "Test Address");
+                    data.set("BorrowerInfo", borrowerData);
+                    return data;
+                }));
+            }
+            if (request.url().host().equals("token.url")) {
+                return createOkhttpResponse(request, 200, createValidToken());
+            }
+            return createOkhttpResponse(request, 404, "Not Found");
+        });
+
+        CreditBureauReportData result = underTest.getCreditReportFromThitsaWorks(initialJsonCommand());
+        assertNotNull(result);
+        assertNotNull(result.getGender());
+        assertNull(result.getCreditScore());
+        assertNull(result.getOpenAccounts());
+        assertNull(result.getClosedAccounts());
+    }
+
+}
diff --git a/integration-tests/dependencies.gradle b/integration-tests/dependencies.gradle
index 7aa508437..69569b6b2 100644
--- a/integration-tests/dependencies.gradle
+++ b/integration-tests/dependencies.gradle
@@ -43,4 +43,5 @@ dependencies {
 
     testCompileOnly 'org.projectlombok:lombok'
     testAnnotationProcessor 'org.projectlombok:lombok'
+    testImplementation 'com.github.tomakehurst:wiremock-jre8:2.35.0'
 }
diff --git a/integration-tests/src/test/java/org/apache/fineract/integrationtests/CreditBureauTest.java b/integration-tests/src/test/java/org/apache/fineract/integrationtests/CreditBureauTest.java
new file mode 100644
index 000000000..7d11d8c6c
--- /dev/null
+++ b/integration-tests/src/test/java/org/apache/fineract/integrationtests/CreditBureauTest.java
@@ -0,0 +1,187 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.fineract.integrationtests;
+
+import static com.github.tomakehurst.wiremock.core.WireMockConfiguration.wireMockConfig;
+
+import com.fasterxml.jackson.core.JsonProcessingException;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.fasterxml.jackson.databind.node.ObjectNode;
+import com.github.tomakehurst.wiremock.client.WireMock;
+import com.github.tomakehurst.wiremock.junit5.WireMockExtension;
+import com.google.gson.Gson;
+import com.google.gson.JsonParser;
+import io.restassured.builder.RequestSpecBuilder;
+import io.restassured.builder.ResponseSpecBuilder;
+import io.restassured.http.ContentType;
+import io.restassured.specification.RequestSpecification;
+import io.restassured.specification.ResponseSpecification;
+import java.time.ZoneId;
+import java.time.ZonedDateTime;
+import java.time.format.DateTimeFormatterBuilder;
+import java.util.List;
+import java.util.Map;
+import org.apache.fineract.infrastructure.creditbureau.data.CreditBureauReportData;
+import org.apache.fineract.integrationtests.common.CreditBureauConfigurationHelper;
+import org.apache.fineract.integrationtests.common.CreditBureauIntegrationHelper;
+import org.apache.fineract.integrationtests.common.Utils;
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.RegisterExtension;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class CreditBureauTest {
+
+    private static final Logger LOG = LoggerFactory.getLogger(CreditBureauTest.class);
+    private ResponseSpecification responseSpec;
+    private RequestSpecification requestSpec;
+
+    private static final ObjectMapper MAPPER = new ObjectMapper();
+
+    @RegisterExtension
+    static WireMockExtension wm = WireMockExtension.newInstance().options(wireMockConfig().port(3558)).build();
+
+    @BeforeEach
+    public void setup() {
+        Utils.initializeRESTAssured();
+        this.requestSpec = new RequestSpecBuilder().setContentType(ContentType.JSON).build();
+        this.requestSpec.header("Authorization", "Basic " + Utils.loginIntoServerAndGetBase64EncodedAuthenticationKey());
+        this.responseSpec = new ResponseSpecBuilder().expectStatusCode(200).build();
+        configureCreditBureauService();
+    }
+
+    private void configureCreditBureauService() {
+        Object organisations = CreditBureauConfigurationHelper.getOrganizationCreditBureauConfiguration(this.requestSpec,
+                this.responseSpec);
+
+        if (new Gson().fromJson(String.valueOf(organisations), List.class).isEmpty()) {
+            CreditBureauConfigurationHelper.addOrganisationCreditBureau(this.requestSpec, this.responseSpec, "1", "SAMPLE_ALIAS", true);
+        } else {
+            CreditBureauConfigurationHelper.updateOrganisationCreditBureau(this.requestSpec, this.responseSpec, "1", true);
+        }
+        List<Map<String, Object>> configurations = CreditBureauConfigurationHelper.getCreditBureauConfiguration(requestSpec, responseSpec,
+                "1");
+        Assertions.assertNotNull(configurations);
+        Map<String, Integer> currentConfiguration = io.vavr.collection.List.ofAll(configurations)
+                .toMap(k -> String.valueOf(k.get("configurationKey")).toUpperCase(), v -> (int) v.get("creditBureauConfigurationId"))
+                .toJavaMap();
+        final Object usernameConfigurationId = CreditBureauConfigurationHelper.updateCreditBureauConfiguration(this.requestSpec,
+                this.responseSpec, currentConfiguration.get("USERNAME").intValue(), "USERNAME", "testUser");
+        Assertions.assertNotNull(usernameConfigurationId);
+        final Object passwordConfigurationId = CreditBureauConfigurationHelper.updateCreditBureauConfiguration(this.requestSpec,
+                this.responseSpec, currentConfiguration.get("PASSWORD").intValue(), "PASSWORD", "testPassword");
+        Assertions.assertNotNull(passwordConfigurationId);
+        final Object creditReportUrlConfigurationId = CreditBureauConfigurationHelper.updateCreditBureauConfiguration(this.requestSpec,
+                this.responseSpec, currentConfiguration.get("CREDITREPORTURL").intValue(), "CREDITREPORTURL",
+                "http://localhost:3558/report/");
+        Assertions.assertNotNull(creditReportUrlConfigurationId);
+        final Object searchUrlConfigurationId = CreditBureauConfigurationHelper.updateCreditBureauConfiguration(this.requestSpec,
+                this.responseSpec, currentConfiguration.get("SEARCHURL").intValue(), "SEARCHURL", "http://localhost:3558/search/");
+        Assertions.assertNotNull(searchUrlConfigurationId);
+        final Object tokenUrlConfigurationId = CreditBureauConfigurationHelper.updateCreditBureauConfiguration(this.requestSpec,
+                this.responseSpec, currentConfiguration.get("TOKENURL").intValue(), "TOKENURL", "http://localhost:3558/token/");
+        Assertions.assertNotNull(tokenUrlConfigurationId);
+        final Object subscriptionIdConfigurationId = CreditBureauConfigurationHelper.updateCreditBureauConfiguration(this.requestSpec,
+                this.responseSpec, currentConfiguration.get("SUBSCRIPTIONID").intValue(), "SUBSCRIPTIONID", "subscriptionID123");
+        Assertions.assertNotNull(subscriptionIdConfigurationId);
+        final Object subscriptionKeyConfigurationId = CreditBureauConfigurationHelper.updateCreditBureauConfiguration(this.requestSpec,
+                this.responseSpec, currentConfiguration.get("SUBSCRIPTIONKEY").intValue(), "SUBSCRIPTIONKEY", "subscriptionKey456");
+        Assertions.assertNotNull(subscriptionKeyConfigurationId);
+        final Object addCreditReportUrlId = CreditBureauConfigurationHelper.updateCreditBureauConfiguration(this.requestSpec,
+                this.responseSpec, currentConfiguration.get("ADDCREDITREPORTURL").intValue(), "addCreditReporturl",
+                "http://localhost:3558/upload/");
+        Assertions.assertNotNull(addCreditReportUrlId);
+
+    }
+
+    @Test
+    public void creditBureauIntegrationTest() throws JsonProcessingException {
+        ObjectNode jsonResponse = MAPPER.createObjectNode();
+        jsonResponse.put("access_token", "AccessToken");
+        jsonResponse.put("expires_in", 3600);
+        jsonResponse.put("token_type", "Bearer");
+        jsonResponse.put("userName", "testUser");
+        jsonResponse.put(".issued", "sample");
+        jsonResponse.put(".expires", ZonedDateTime.now(ZoneId.systemDefault()).plusSeconds(3600)
+                .format(new DateTimeFormatterBuilder().appendPattern("EEE, dd MMM yyyy kk:mm:ss zzz").toFormatter()));
+        wm.stubFor(WireMock.post("/token/").willReturn(WireMock.jsonResponse(MAPPER.writeValueAsString(jsonResponse), 200)));
+        wm.stubFor(WireMock.post("/search/NRC213")
+                .willReturn(WireMock.jsonResponse("{\"ResponseMessage\":\"OK\",\"Data\":[{\"UniqueID\":\"123456\"}]}", 200)));
+        wm.stubFor(WireMock.get("/report/123456").willReturn(
+                WireMock.jsonResponse("{\"ResponseMessage\":\"OK\",\"Data\":{" + "\"BorrowerInfo\":{" + "\"Name\":\"Test Name\","
+                        + "\"Gender\":\"male\"," + "\"Address\":\"Test Address\"" + "}," + "\"CreditScore\": {\"Score\":  \"500\"},"
+                        + "\"ActiveLoans\": [\"Loan1\", \"Loan2\"]," + "\"WriteOffLoans\": [\"Loan3\", \"Loan4\"]" + "}}", 200)));
+
+        Object serviceResult = CreditBureauIntegrationHelper.getCreditReport(this.requestSpec, this.responseSpec, "1", "NRC213");
+        Assertions.assertNotNull(serviceResult);
+        Gson gson = new Gson();
+        CreditBureauReportData responseData = gson.fromJson(
+                gson.toJson(JsonParser.parseString(String.valueOf(serviceResult)).getAsJsonObject().get("creditBureauReportData")),
+                CreditBureauReportData.class);
+        Assertions.assertEquals("\"Test Name\"", responseData.getName());
+        Assertions.assertEquals("{\"Score\":\"500\"}", responseData.getCreditScore());
+
+        Assertions.assertEquals("\"male\"", responseData.getGender());
+        Assertions.assertEquals("\"Test Address\"", responseData.getAddress());
+
+        Assertions.assertEquals(2, responseData.getClosedAccounts().length);
+        Assertions.assertEquals(2, responseData.getOpenAccounts().length);
+        Assertions.assertEquals("\"Loan3\"", responseData.getClosedAccounts()[0]);
+        Assertions.assertEquals("\"Loan4\"", responseData.getClosedAccounts()[1]);
+        Assertions.assertEquals("\"Loan1\"", responseData.getOpenAccounts()[0]);
+        Assertions.assertEquals("\"Loan2\"", responseData.getOpenAccounts()[1]);
+    }
+
+    @Test
+    public void creditBureauNoLoanTest() throws JsonProcessingException {
+        ObjectNode jsonResponse = MAPPER.createObjectNode();
+        jsonResponse.put("access_token", "AccessToken");
+        jsonResponse.put("expires_in", 3600);
+        jsonResponse.put("token_type", "Bearer");
+        jsonResponse.put("userName", "testUser");
+        jsonResponse.put(".issued", "sample");
+        jsonResponse.put(".expires", ZonedDateTime.now(ZoneId.systemDefault()).plusSeconds(3600)
+                .format(new DateTimeFormatterBuilder().appendPattern("EEE, dd MMM yyyy kk:mm:ss zzz").toFormatter()));
+        wm.stubFor(WireMock.post("/token/").willReturn(WireMock.jsonResponse(MAPPER.writeValueAsString(jsonResponse), 200)));
+        wm.stubFor(WireMock.post("/search/NRC213")
+                .willReturn(WireMock.jsonResponse("{\"ResponseMessage\":\"OK\",\"Data\":[{\"UniqueID\":\"123456\"}]}", 200)));
+        wm.stubFor(WireMock.get("/report/123456")
+                .willReturn(WireMock.jsonResponse("{\"ResponseMessage\":\"OK\",\"Data\":{" + "\"BorrowerInfo\":{"
+                        + "\"Name\":\"Test Name\"," + "\"Gender\":\"male\"," + "\"Address\":\"Test Address\"" + "},"
+                        + "\"CreditScore\": {\"Score\":  \"500\"}," + "\"ActiveLoans\": []," + "\"WriteOffLoans\": []" + "}}", 200)));
+
+        Object serviceResult = CreditBureauIntegrationHelper.getCreditReport(this.requestSpec, this.responseSpec, "1", "NRC213");
+        Assertions.assertNotNull(serviceResult);
+        Gson gson = new Gson();
+        CreditBureauReportData responseData = gson.fromJson(
+                gson.toJson(JsonParser.parseString(String.valueOf(serviceResult)).getAsJsonObject().get("creditBureauReportData")),
+                CreditBureauReportData.class);
+        Assertions.assertEquals("\"Test Name\"", responseData.getName());
+        Assertions.assertEquals("{\"Score\":\"500\"}", responseData.getCreditScore());
+
+        Assertions.assertEquals("\"male\"", responseData.getGender());
+        Assertions.assertEquals("\"Test Address\"", responseData.getAddress());
+
+        Assertions.assertEquals(0, responseData.getClosedAccounts().length);
+        Assertions.assertEquals(0, responseData.getOpenAccounts().length);
+    }
+
+}
diff --git a/integration-tests/src/test/java/org/apache/fineract/integrationtests/common/CreditBureauConfigurationHelper.java b/integration-tests/src/test/java/org/apache/fineract/integrationtests/common/CreditBureauConfigurationHelper.java
index 62c68d956..70bb3b43b 100644
--- a/integration-tests/src/test/java/org/apache/fineract/integrationtests/common/CreditBureauConfigurationHelper.java
+++ b/integration-tests/src/test/java/org/apache/fineract/integrationtests/common/CreditBureauConfigurationHelper.java
@@ -21,9 +21,12 @@ package org.apache.fineract.integrationtests.common;
 import com.google.gson.Gson;
 import com.google.gson.JsonObject;
 import com.google.gson.JsonParser;
+import io.restassured.path.json.JsonPath;
 import io.restassured.specification.RequestSpecification;
 import io.restassured.specification.ResponseSpecification;
 import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -40,18 +43,32 @@ public class CreditBureauConfigurationHelper {
         this.responseSpec = responseSpec;
     }
 
+    public static List<Map<String, Object>> getCreditBureauConfiguration(RequestSpecification requestSpec,
+            ResponseSpecification responseSpec, String creditBureauId) {
+        LOG.info("---------------------------------GET A CREDIT_BUREAU_CONFIGURATION---------------------------------------------");
+        final String CREDITBUREAU_CONFIGURATION_URL = "/fineract-provider/api/v1/CreditBureauConfiguration/config/" + creditBureauId + "?"
+                + Utils.TENANT_IDENTIFIER;
+        return JsonPath.from(Utils.performServerGet(requestSpec, responseSpec, CREDITBUREAU_CONFIGURATION_URL)).getList("");
+    }
+
     public static Integer createCreditBureauConfiguration(final RequestSpecification requestSpec, final ResponseSpecification responseSpec,
             String configKey) {
         return createCreditBureauConfiguration(requestSpec, responseSpec, "1", configKey);
     }
 
     public static Integer createCreditBureauConfiguration(final RequestSpecification requestSpec, final ResponseSpecification responseSpec,
-            final String creditBureauId, String configKey) {
+            final String creditBureauId, String configKey, String value, String description) {
         LOG.info("---------------------------------CREATING A CREDIT_BUREAU_CONFIGURATION---------------------------------------------");
-        final String CREDITBUREAU_CONFIGURATION_URL = " /fineract-provider/api/v1/CreditBureauConfiguration/configuration/" + creditBureauId
+        final String CREDITBUREAU_CONFIGURATION_URL = "/fineract-provider/api/v1/CreditBureauConfiguration/configuration/" + creditBureauId
                 + "?" + Utils.TENANT_IDENTIFIER;
         return Utils.performServerPost(requestSpec, responseSpec, CREDITBUREAU_CONFIGURATION_URL,
-                creditBureauConfigurationAsJson(configKey, "testConfigKeyValue", "description"), "resourceId");
+                creditBureauConfigurationAsJson(configKey, value, description), "resourceId");
+    }
+
+    public static Integer createCreditBureauConfiguration(final RequestSpecification requestSpec, final ResponseSpecification responseSpec,
+            final String creditBureauId, String configKey) {
+        LOG.info("---------------------------------CREATING A CREDIT_BUREAU_CONFIGURATION---------------------------------------------");
+        return createCreditBureauConfiguration(requestSpec, responseSpec, creditBureauId, configKey, "testConfigKeyValue", "description");
     }
 
     /*
@@ -63,7 +80,8 @@ public class CreditBureauConfigurationHelper {
     public static String updateCreditBureauConfiguration(final RequestSpecification requestSpec, final ResponseSpecification responseSpec,
             final Integer ConfigurationId) {
 
-        Object configurationObject = updateCreditBureauConfiguration(requestSpec, responseSpec, ConfigurationId, "updateConfigKeyValue");
+        Object configurationObject = updateCreditBureauConfiguration(requestSpec, responseSpec, ConfigurationId, null,
+                "updateConfigKeyValue");
         // Convert the Object to String and fetch updated value
         Gson gson = new Gson();
         String result = gson.toJson(configurationObject);
@@ -74,12 +92,52 @@ public class CreditBureauConfigurationHelper {
     }
 
     public static Object updateCreditBureauConfiguration(final RequestSpecification requestSpec, final ResponseSpecification responseSpec,
-            final Integer ConfigurationId, final String updateConfigKeyValue) {
+            final Integer ConfigurationId, String configKey, final String updateConfigKeyValue) {
         LOG.info("---------------------------------UPDATING A CREDIT_BUREAU_CONFIGURATION---------------------------------------------");
-        final String CREDITBUREAU_CONFIGURATION_URL = " /fineract-provider/api/v1/CreditBureauConfiguration/configuration/"
-                + ConfigurationId + "?" + Utils.TENANT_IDENTIFIER;
+        final String CREDITBUREAU_CONFIGURATION_URL = "/fineract-provider/api/v1/CreditBureauConfiguration/configuration/" + ConfigurationId
+                + "?" + Utils.TENANT_IDENTIFIER;
         return Utils.performServerPut(requestSpec, responseSpec, CREDITBUREAU_CONFIGURATION_URL,
-                updateCreditBureauConfigurationAsJson("updateConfigKeyValue", "description"), "changes");
+                updateCreditBureauConfigurationAsJson(configKey, updateConfigKeyValue), "changes");
+    }
+
+    public static Object getOrganizationCreditBureauConfiguration(final RequestSpecification requestSpec,
+            final ResponseSpecification responseSpec) {
+        LOG.info("---------------------------------GETTING A CREDIT_BUREAU_CONFIGURATION---------------------------------------------");
+        final String CREDITBUREAU_CONFIGURATION_URL = "/fineract-provider/api/v1/CreditBureauConfiguration/organisationCreditBureau?"
+                + Utils.TENANT_IDENTIFIER;
+        return Utils.performServerGet(requestSpec, responseSpec, CREDITBUREAU_CONFIGURATION_URL, null);
+    }
+
+    public static Object addOrganisationCreditBureau(final RequestSpecification requestSpec, final ResponseSpecification responseSpec,
+            final String creditBureauId, String alias, boolean isActive) {
+        LOG.info("---------------------------------CREATING A CREDIT_BUREAU_CONFIGURATION---------------------------------------------");
+        final String URL = "/fineract-provider/api/v1/CreditBureauConfiguration/organisationCreditBureau/" + creditBureauId + "?"
+                + Utils.TENANT_IDENTIFIER;
+        return Utils.performServerPost(requestSpec, responseSpec, URL, addOrganizationCreditBureauCreateAsJson(alias, isActive), null);
+    }
+
+    public static Object updateOrganisationCreditBureau(final RequestSpecification requestSpec, final ResponseSpecification responseSpec,
+            final String creditBureauId, boolean isActive) {
+        LOG.info("---------------------------------CREATING A CREDIT_BUREAU_CONFIGURATION---------------------------------------------");
+        final String URL = "/fineract-provider/api/v1/CreditBureauConfiguration/organisationCreditBureau?" + Utils.TENANT_IDENTIFIER;
+        return Utils.performServerPut(requestSpec, responseSpec, URL, updateOrganizationCreditBureauCreateAsJson(creditBureauId, isActive),
+                null);
+    }
+
+    public static String addOrganizationCreditBureauCreateAsJson(final String alias, final boolean isActive) {
+        final HashMap<String, Object> map = new HashMap<>();
+        map.put("alias", alias);
+        map.put("isActive", isActive);
+        LOG.info("map :  {}", map);
+        return new Gson().toJson(map);
+    }
+
+    public static String updateOrganizationCreditBureauCreateAsJson(final String creditBureauId, final boolean isActive) {
+        final HashMap<String, Object> map = new HashMap<>();
+        map.put("creditBureauId", creditBureauId);
+        map.put("isActive", isActive);
+        LOG.info("map :  {}", map);
+        return new Gson().toJson(map);
     }
 
     public static String creditBureauConfigurationAsJson(final String configkey, final String value, final String description) {
@@ -91,10 +149,12 @@ public class CreditBureauConfigurationHelper {
         return new Gson().toJson(map);
     }
 
-    public static String updateCreditBureauConfigurationAsJson(final String value, final String description) {
+    public static String updateCreditBureauConfigurationAsJson(final String configKey, final String value) {
         final HashMap<String, String> map = new HashMap<>();
+        if (configKey != null) {
+            map.put("configkey", configKey);
+        }
         map.put("value", value);
-        map.put("description", description);
         LOG.info("map :  {}", map);
         return new Gson().toJson(map);
     }
diff --git a/integration-tests/src/test/java/org/apache/fineract/integrationtests/common/CreditBureauIntegrationHelper.java b/integration-tests/src/test/java/org/apache/fineract/integrationtests/common/CreditBureauIntegrationHelper.java
new file mode 100644
index 000000000..4e19d0bfe
--- /dev/null
+++ b/integration-tests/src/test/java/org/apache/fineract/integrationtests/common/CreditBureauIntegrationHelper.java
@@ -0,0 +1,69 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.fineract.integrationtests.common;
+
+import static io.restassured.RestAssured.given;
+
+import com.google.gson.Gson;
+import io.restassured.specification.RequestSpecification;
+import io.restassured.specification.ResponseSpecification;
+import java.io.File;
+import java.util.HashMap;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class CreditBureauIntegrationHelper {
+
+    private static final Logger LOG = LoggerFactory.getLogger(CreditBureauIntegrationHelper.class);
+    private final RequestSpecification requestSpec;
+    private final ResponseSpecification responseSpec;
+
+    public CreditBureauIntegrationHelper(final RequestSpecification requestSpec, final ResponseSpecification responseSpec) {
+        this.requestSpec = requestSpec;
+        this.responseSpec = responseSpec;
+    }
+
+    public static Object getCreditReport(final RequestSpecification requestSpec, final ResponseSpecification responseSpec,
+            final String creditBureauId, String nrc) {
+        LOG.info("---------------------------------CREATING A CREDIT_BUREAU_CONFIGURATION---------------------------------------------");
+        final String CREDITBUREAU_CONFIGURATION_URL = "/fineract-provider/api/v1/creditBureauIntegration/creditReport?"
+                + Utils.TENANT_IDENTIFIER;
+        return Utils.performServerPost(requestSpec, responseSpec, CREDITBUREAU_CONFIGURATION_URL,
+                createGetCreditReportAsJson(creditBureauId, nrc), null);
+    }
+
+    public static String uploadCreditReport(final RequestSpecification requestSpec, final ResponseSpecification responseSpec,
+            final String creditBureauId, File file) {
+        LOG.info("---------------------------------CREATING A CREDIT_BUREAU_CONFIGURATION---------------------------------------------");
+        final String CREDITBUREAU_CONFIGURATION_URL = "/fineract-provider/api/v1/creditBureauIntegration/addCreditReport?"
+                + Utils.TENANT_IDENTIFIER;
+        return given().spec(requestSpec).queryParam("creditBureauId", creditBureauId).contentType("multipart/form-data")
+                .multiPart("file", file).expect().spec(responseSpec).log().ifError().when().post(CREDITBUREAU_CONFIGURATION_URL).andReturn()
+                .asString();
+    }
+
+    public static String createGetCreditReportAsJson(final String creditBureauId, final String nrc) {
+        final HashMap<String, String> map = new HashMap<>();
+        map.put("creditBureauID", creditBureauId);
+        map.put("NRC", nrc);
+        LOG.info("map :  {}", map);
+        return new Gson().toJson(map);
+    }
+
+}