Skip to content

Commit abfde50

Browse files
committed
FINERACT-2116: Add validation integration tests for Credit Bureau Configuration APIs
1 parent f5951f1 commit abfde50

File tree

2 files changed

+276
-0
lines changed

2 files changed

+276
-0
lines changed
Lines changed: 246 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,246 @@
1+
/**
2+
* Licensed to the Apache Software Foundation (ASF) under one
3+
* or more contributor license agreements. See the NOTICE file
4+
* distributed with this work for additional information
5+
* regarding copyright ownership. The ASF licenses this file
6+
* to you under the Apache License, Version 2.0 (the
7+
* "License"); you may not use this file except in compliance
8+
* with the License. You may obtain a copy of the License at
9+
*
10+
* http://www.apache.org/licenses/LICENSE-2.0
11+
*
12+
* Unless required by applicable law or agreed to in writing,
13+
* software distributed under the License is distributed on an
14+
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15+
* KIND, either express or implied. See the License for the
16+
* specific language governing permissions and limitations
17+
* under the License.
18+
*/
19+
package org.apache.fineract.integrationtests;
20+
21+
import static org.junit.jupiter.api.Assertions.assertNotNull;
22+
import static org.junit.jupiter.api.Assertions.assertTrue;
23+
24+
import com.google.gson.Gson;
25+
import io.restassured.builder.RequestSpecBuilder;
26+
import io.restassured.builder.ResponseSpecBuilder;
27+
import io.restassured.http.ContentType;
28+
import io.restassured.specification.RequestSpecification;
29+
import io.restassured.specification.ResponseSpecification;
30+
import java.util.HashMap;
31+
import java.util.List;
32+
import java.util.Map;
33+
import lombok.extern.slf4j.Slf4j;
34+
import org.apache.fineract.integrationtests.common.CreditBureauConfigurationHelper;
35+
import org.apache.fineract.integrationtests.common.Utils;
36+
import org.apache.fineract.integrationtests.common.loans.LoanProductTestBuilder;
37+
import org.apache.fineract.integrationtests.common.loans.LoanTransactionHelper;
38+
import org.junit.jupiter.api.BeforeEach;
39+
import org.junit.jupiter.api.Test;
40+
import org.junit.jupiter.params.ParameterizedTest;
41+
import org.junit.jupiter.params.provider.CsvSource;
42+
43+
/**
44+
* Integration tests for Credit Bureau Configuration API validation.
45+
* <p>
46+
* Tests verify that the API correctly rejects requests with missing or invalid mandatory fields, returning HTTP 400 Bad
47+
* Request with appropriate validation error messages.
48+
* </p>
49+
*/
50+
@Slf4j
51+
public class CreditBureauConfigurationValidationTest {
52+
53+
private ResponseSpecification responseSpec200;
54+
private ResponseSpecification responseSpec400;
55+
private RequestSpecification requestSpec;
56+
private LoanTransactionHelper loanTransactionHelper;
57+
58+
// Prerequisites - ThitsaWorks credit bureau is seeded in DB with ID 1
59+
private static final Long VALID_CREDIT_BUREAU_ID = 1L;
60+
private Long validOrganisationCreditBureauId;
61+
private Long validLoanProductId;
62+
63+
@BeforeEach
64+
public void setup() {
65+
Utils.initializeRESTAssured();
66+
this.requestSpec = new RequestSpecBuilder().setContentType(ContentType.JSON).build();
67+
this.requestSpec.header("Authorization", "Basic " + Utils.loginIntoServerAndGetBase64EncodedAuthenticationKey());
68+
this.responseSpec200 = new ResponseSpecBuilder().expectStatusCode(200).build();
69+
this.responseSpec400 = new ResponseSpecBuilder().expectStatusCode(400).build();
70+
this.loanTransactionHelper = new LoanTransactionHelper(requestSpec, responseSpec200);
71+
72+
ensureOrganisationCreditBureauExists();
73+
74+
this.validLoanProductId = createTestLoanProduct();
75+
}
76+
77+
@ParameterizedTest(name = "Create configuration missing {0} should return 400")
78+
@CsvSource({ "configkey, value, description", "value, configkey, description", "description, configkey, value" })
79+
void testCreateConfiguration_MissingMandatoryFields(String fieldToOmit, String field1, String field2) {
80+
final Map<String, Object> jsonMap = new HashMap<>();
81+
jsonMap.put(field1, "testValue1");
82+
jsonMap.put(field2, "testValue2");
83+
final String jsonBody = new Gson().toJson(jsonMap);
84+
85+
Object response = CreditBureauConfigurationHelper.createCreditBureauConfigurationWithResponse(requestSpec, responseSpec400,
86+
validOrganisationCreditBureauId, jsonBody);
87+
88+
assertValidationError(response, fieldToOmit);
89+
}
90+
91+
@Test
92+
void testCreateConfiguration_BlankConfigKey_ShouldFail400() {
93+
final Map<String, Object> jsonMap = new HashMap<>();
94+
jsonMap.put("configkey", "");
95+
jsonMap.put("value", "testValue");
96+
jsonMap.put("description", "testDescription");
97+
final String jsonBody = new Gson().toJson(jsonMap);
98+
99+
Object response = CreditBureauConfigurationHelper.createCreditBureauConfigurationWithResponse(requestSpec, responseSpec400,
100+
validOrganisationCreditBureauId, jsonBody);
101+
102+
assertValidationError(response, "configkey");
103+
}
104+
105+
@Test
106+
void testCreateConfiguration_ExceedingLength_ShouldFail400() {
107+
final String longValue = "a".repeat(101);
108+
final Map<String, Object> jsonMap = new HashMap<>();
109+
jsonMap.put("configkey", longValue);
110+
jsonMap.put("value", "testValue");
111+
jsonMap.put("description", "testDescription");
112+
final String jsonBody = new Gson().toJson(jsonMap);
113+
114+
Object response = CreditBureauConfigurationHelper.createCreditBureauConfigurationWithResponse(requestSpec, responseSpec400,
115+
validOrganisationCreditBureauId, jsonBody);
116+
117+
assertValidationError(response, "configkey");
118+
}
119+
120+
@Test
121+
void testAddOrganisationCreditBureau_MissingAlias_ShouldFail400() {
122+
final Map<String, Object> jsonMap = new HashMap<>();
123+
jsonMap.put("isActive", true);
124+
final String jsonBody = new Gson().toJson(jsonMap);
125+
126+
Object response = CreditBureauConfigurationHelper.addOrganisationCreditBureauWithResponse(requestSpec, responseSpec400,
127+
VALID_CREDIT_BUREAU_ID, jsonBody);
128+
129+
assertValidationError(response, "alias");
130+
}
131+
132+
@Test
133+
void testAddOrganisationCreditBureau_BlankAlias_ShouldFail400() {
134+
final Map<String, Object> jsonMap = new HashMap<>();
135+
jsonMap.put("alias", "");
136+
jsonMap.put("isActive", true);
137+
final String jsonBody = new Gson().toJson(jsonMap);
138+
139+
Object response = CreditBureauConfigurationHelper.addOrganisationCreditBureauWithResponse(requestSpec, responseSpec400,
140+
VALID_CREDIT_BUREAU_ID, jsonBody);
141+
142+
assertValidationError(response, "alias");
143+
}
144+
145+
@Test
146+
void testAddOrganisationCreditBureau_ExceedingAliasLength_ShouldFail400() {
147+
final String longAlias = "a".repeat(101);
148+
final Map<String, Object> jsonMap = new HashMap<>();
149+
jsonMap.put("alias", longAlias);
150+
jsonMap.put("isActive", true);
151+
final String jsonBody = new Gson().toJson(jsonMap);
152+
153+
Object response = CreditBureauConfigurationHelper.addOrganisationCreditBureauWithResponse(requestSpec, responseSpec400,
154+
VALID_CREDIT_BUREAU_ID, jsonBody);
155+
156+
assertValidationError(response, "alias");
157+
}
158+
159+
@ParameterizedTest(name = "Create mapping missing {0} should return 400")
160+
@CsvSource({ "isCreditcheckMandatory", "skipCreditcheckInFailure", "stalePeriod" })
161+
void testCreateMapping_MissingMandatoryFields(String fieldToOmit) {
162+
final Map<String, Object> jsonMap = buildMappingJsonOmitting(fieldToOmit);
163+
final String jsonBody = new Gson().toJson(jsonMap);
164+
165+
Object response = CreditBureauConfigurationHelper.createLoanProductMappingWithResponse(requestSpec, responseSpec400,
166+
validOrganisationCreditBureauId, jsonBody);
167+
168+
assertValidationError(response, fieldToOmit);
169+
}
170+
171+
@Test
172+
void testCreateMapping_MissingLoanProductId_ShouldFail400() {
173+
final Map<String, Object> jsonMap = buildMappingJsonOmitting("loanProductId");
174+
final String jsonBody = new Gson().toJson(jsonMap);
175+
176+
Object response = CreditBureauConfigurationHelper.createLoanProductMappingWithResponse(requestSpec, responseSpec400,
177+
validOrganisationCreditBureauId, jsonBody);
178+
179+
assertValidationError(response, "loanProductId");
180+
}
181+
182+
private void ensureOrganisationCreditBureauExists() {
183+
final Map<String, Object> jsonMap = new HashMap<>();
184+
jsonMap.put("alias", "Test Credit Bureau " + System.currentTimeMillis());
185+
jsonMap.put("isActive", true);
186+
final String jsonBody = new Gson().toJson(jsonMap);
187+
final String url = "/fineract-provider/api/v1/CreditBureauConfiguration/organisationCreditBureau/" + VALID_CREDIT_BUREAU_ID + "?"
188+
+ Utils.TENANT_IDENTIFIER;
189+
Integer resourceId = Utils.performServerPost(requestSpec, responseSpec200, url, jsonBody, "resourceId");
190+
assertNotNull(resourceId, "Organisation credit bureau creation should return resourceId");
191+
this.validOrganisationCreditBureauId = resourceId.longValue();
192+
log.info("Created organisation credit bureau with ID: {}", validOrganisationCreditBureauId);
193+
}
194+
195+
private Long createTestLoanProduct() {
196+
final String loanProductJSON = new LoanProductTestBuilder().withPrincipal("1000").withRepaymentAfterEvery("1")
197+
.withRepaymentTypeAsMonth().withNumberOfRepayments("1").withInterestRateFrequencyTypeAsMonths()
198+
.withinterestRatePerPeriod("0").withInterestTypeAsDecliningBalance().withAmortizationTypeAsEqualInstallments().build(null);
199+
return (long) loanTransactionHelper.getLoanProductId(loanProductJSON);
200+
}
201+
202+
private Map<String, Object> buildMappingJsonOmitting(String fieldToOmit) {
203+
final Map<String, Object> jsonMap = new HashMap<>();
204+
if (!"loanProductId".equals(fieldToOmit)) {
205+
jsonMap.put("loanProductId", validLoanProductId);
206+
}
207+
if (!"isCreditcheckMandatory".equals(fieldToOmit)) {
208+
jsonMap.put("isCreditcheckMandatory", true);
209+
}
210+
if (!"skipCreditcheckInFailure".equals(fieldToOmit)) {
211+
jsonMap.put("skipCreditcheckInFailure", false);
212+
}
213+
if (!"stalePeriod".equals(fieldToOmit)) {
214+
jsonMap.put("stalePeriod", 30);
215+
}
216+
jsonMap.put("isActive", true);
217+
return jsonMap;
218+
}
219+
220+
@SuppressWarnings("unchecked")
221+
private void assertValidationError(Object response, String expectedFieldInError) {
222+
assertNotNull(response, "Response should not be null");
223+
Map<String, Object> responseMap;
224+
if (response instanceof String) {
225+
responseMap = new Gson().fromJson((String) response, Map.class);
226+
} else {
227+
responseMap = (Map<String, Object>) response;
228+
}
229+
230+
assertTrue(responseMap.containsKey("errors"), "Response should contain 'errors' key");
231+
232+
List<Map<String, Object>> errors = (List<Map<String, Object>>) responseMap.get("errors");
233+
assertNotNull(errors, "Errors list should not be null");
234+
assertTrue(!errors.isEmpty(), "Errors list should not be empty");
235+
236+
boolean foundExpectedError = errors.stream().anyMatch(error -> {
237+
String parameterName = (String) error.get("parameterName");
238+
String userMessageGlobalisationCode = (String) error.get("userMessageGlobalisationCode");
239+
return (parameterName != null && parameterName.contains(expectedFieldInError))
240+
|| (userMessageGlobalisationCode != null && userMessageGlobalisationCode.contains(expectedFieldInError));
241+
});
242+
243+
assertTrue(foundExpectedError, String.format("Expected validation error for field '%s' but got: %s", expectedFieldInError, errors));
244+
log.info("Received expected validation error for field '{}': {}", expectedFieldInError, errors);
245+
}
246+
}

integration-tests/src/test/java/org/apache/fineract/integrationtests/common/CreditBureauConfigurationHelper.java

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -214,4 +214,34 @@ public static String updateCreditBureauConfigurationAsJson(final String configKe
214214
return new Gson().toJson(map);
215215
}
216216

217+
// TODO: Rewrite to use fineract-client instead!
218+
@Deprecated(forRemoval = true)
219+
public static Object createCreditBureauConfigurationWithResponse(final RequestSpecification requestSpec,
220+
final ResponseSpecification responseSpec, final Long creditBureauId, final String jsonBody) {
221+
final String url = "/fineract-provider/api/v1/CreditBureauConfiguration/configuration/" + creditBureauId + "?"
222+
+ Utils.TENANT_IDENTIFIER;
223+
LOG.info("URL: {} - Body: {}", url, jsonBody);
224+
return Utils.performServerPost(requestSpec, responseSpec, url, jsonBody, null);
225+
}
226+
227+
// TODO: Rewrite to use fineract-client instead!
228+
@Deprecated(forRemoval = true)
229+
public static Object addOrganisationCreditBureauWithResponse(final RequestSpecification requestSpec,
230+
final ResponseSpecification responseSpec, final Long creditBureauId, final String jsonBody) {
231+
final String url = "/fineract-provider/api/v1/CreditBureauConfiguration/organisationCreditBureau/" + creditBureauId + "?"
232+
+ Utils.TENANT_IDENTIFIER;
233+
LOG.info("URL: {} - Body: {}", url, jsonBody);
234+
return Utils.performServerPost(requestSpec, responseSpec, url, jsonBody, null);
235+
}
236+
237+
// TODO: Rewrite to use fineract-client instead!
238+
@Deprecated(forRemoval = true)
239+
public static Object createLoanProductMappingWithResponse(final RequestSpecification requestSpec,
240+
final ResponseSpecification responseSpec, final Long organisationCreditBureauId, final String jsonBody) {
241+
final String url = "/fineract-provider/api/v1/CreditBureauConfiguration/mappings/" + organisationCreditBureauId + "?"
242+
+ Utils.TENANT_IDENTIFIER;
243+
LOG.info("URL: {} - Body: {}", url, jsonBody);
244+
return Utils.performServerPost(requestSpec, responseSpec, url, jsonBody, null);
245+
}
246+
217247
}

0 commit comments

Comments
 (0)