Skip to content

Commit 41e774a

Browse files
committed
FINERACT-2832: move e2e tests
1 parent d5702a3 commit 41e774a

27 files changed

Lines changed: 675 additions & 583 deletions

fineract-client-feign/src/main/java/org/apache/fineract/client/feign/FineractFeignClient.java

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -96,10 +96,13 @@
9696
import org.apache.fineract.client.feign.services.LoanCollateralApi;
9797
import org.apache.fineract.client.feign.services.LoanCollateralManagementApi;
9898
import org.apache.fineract.client.feign.services.LoanDisbursementDetailsApi;
99+
import org.apache.fineract.client.feign.services.LoanDisbursementDetailsApiExtension;
99100
import org.apache.fineract.client.feign.services.LoanInterestPauseApi;
100101
import org.apache.fineract.client.feign.services.LoanProductsApi;
102+
import org.apache.fineract.client.feign.services.LoanProductsApiExtension;
101103
import org.apache.fineract.client.feign.services.LoanReschedulingApi;
102104
import org.apache.fineract.client.feign.services.LoanTransactionsApi;
105+
import org.apache.fineract.client.feign.services.LoanTransactionsApiExtension;
103106
import org.apache.fineract.client.feign.services.LoansApi;
104107
import org.apache.fineract.client.feign.services.LoansPointInTimeApi;
105108
import org.apache.fineract.client.feign.services.MakerCheckerOr4EyeFunctionalityApi;
@@ -533,6 +536,10 @@ public LoanDisbursementDetailsApi loanDisbursementDetails() {
533536
return create(LoanDisbursementDetailsApi.class);
534537
}
535538

539+
public LoanDisbursementDetailsApiExtension loanDisbursementDetailsExtension() {
540+
return create(LoanDisbursementDetailsApiExtension.class);
541+
}
542+
536543
public LoanInterestPauseApi loanInterestPause() {
537544
return create(LoanInterestPauseApi.class);
538545
}
@@ -541,6 +548,10 @@ public LoanProductsApi loanProducts() {
541548
return create(LoanProductsApi.class);
542549
}
543550

551+
public LoanProductsApiExtension loanProductsExtension() {
552+
return create(LoanProductsApiExtension.class);
553+
}
554+
544555
public LoanReschedulingApi loanRescheduling() {
545556
return create(LoanReschedulingApi.class);
546557
}
@@ -549,6 +560,10 @@ public LoanTransactionsApi loanTransactions() {
549560
return create(LoanTransactionsApi.class);
550561
}
551562

563+
public LoanTransactionsApiExtension loanTransactionsExtension() {
564+
return create(LoanTransactionsApiExtension.class);
565+
}
566+
552567
public LoansApi loans() {
553568
return create(LoansApi.class);
554569
}
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
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.client.feign.services;
20+
21+
import feign.Headers;
22+
import feign.Param;
23+
import feign.QueryMap;
24+
import feign.RequestLine;
25+
import java.util.Map;
26+
import org.apache.fineract.client.models.ExternalAssetOwnerRequest;
27+
import org.apache.fineract.client.models.PostInitiateTransferResponse;
28+
29+
public interface ExternalAssetOwnersApiExtension {
30+
31+
@RequestLine("POST /v1/external-asset-owners/transfers/{id}")
32+
@Headers("Content-Type: application/json")
33+
PostInitiateTransferResponse transferRequestWithIdWithBody(@Param("id") Long id, ExternalAssetOwnerRequest body,
34+
@QueryMap Map<String, Object> queryParams);
35+
36+
@RequestLine("POST /v1/external-asset-owners/transfers/external-id/{externalId}")
37+
@Headers("Content-Type: application/json")
38+
PostInitiateTransferResponse transferRequestWithId1WithBody(@Param("externalId") String externalId, ExternalAssetOwnerRequest body,
39+
@QueryMap Map<String, Object> queryParams);
40+
}
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
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.client.feign.services;
20+
21+
import feign.Param;
22+
import feign.RequestLine;
23+
import org.apache.fineract.client.models.PostAddAndDeleteDisbursementDetailRequest;
24+
25+
public interface LoanDisbursementDetailsApiExtension {
26+
27+
@RequestLine("PUT /v1/loans/{loanId}/disbursements/editDisbursements")
28+
PostAddAndDeleteDisbursementDetailRequest addAndDeleteDisbursementDetail(@Param("loanId") Long loanId,
29+
PostAddAndDeleteDisbursementDetailRequest postAddAndDeleteDisbursementDetailRequest);
30+
31+
}
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
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.client.feign.services;
20+
21+
import feign.Param;
22+
import feign.QueryMap;
23+
import feign.RequestLine;
24+
import java.util.Map;
25+
import org.apache.fineract.client.models.GetLoanProductsProductIdResponse;
26+
27+
public interface LoanProductsApiExtension {
28+
29+
/**
30+
* Retrieve Loan Product Details with query parameters
31+
*
32+
* @param productId
33+
* Loan Product ID
34+
* @param queryParams
35+
* Query parameters (e.g., template=true)
36+
* @return GetLoanProductsProductIdResponse
37+
*/
38+
@RequestLine("GET /v1/loanproducts/{productId}")
39+
GetLoanProductsProductIdResponse retrieveLoanProductDetails(@Param("productId") Long productId,
40+
@QueryMap Map<String, Object> queryParams);
41+
}
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
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.client.feign.services;
20+
21+
import feign.HeaderMap;
22+
import feign.Param;
23+
import feign.QueryMap;
24+
import feign.RequestLine;
25+
import java.util.Map;
26+
import org.apache.fineract.client.models.PostLoansLoanIdTransactionsRequest;
27+
import org.apache.fineract.client.models.PostLoansLoanIdTransactionsResponse;
28+
29+
public interface LoanTransactionsApiExtension {
30+
31+
@RequestLine("POST /v1/loans/{loanId}/transactions")
32+
PostLoansLoanIdTransactionsResponse executeLoanTransaction(@Param("loanId") Long loanId,
33+
PostLoansLoanIdTransactionsRequest postLoansLoanIdTransactionsRequest, @QueryMap Map<String, Object> queryParams,
34+
@HeaderMap Map<String, String> headers);
35+
36+
@RequestLine("POST /v1/loans/external-id/{loanExternalId}/transactions")
37+
PostLoansLoanIdTransactionsResponse executeLoanTransaction1(@Param("loanExternalId") String loanExternalId,
38+
PostLoansLoanIdTransactionsRequest postLoansLoanIdTransactionsRequest, @QueryMap Map<String, Object> queryParams,
39+
@HeaderMap Map<String, String> headers);
40+
41+
}

fineract-client-feign/src/main/java/org/apache/fineract/client/feign/util/CallFailedRuntimeException.java

Lines changed: 5 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -18,13 +18,9 @@
1818
*/
1919
package org.apache.fineract.client.feign.util;
2020

21-
import com.fasterxml.jackson.databind.JsonNode;
22-
import com.fasterxml.jackson.databind.ObjectMapper;
23-
import feign.FeignException;
24-
import java.io.IOException;
25-
import java.nio.charset.StandardCharsets;
2621
import lombok.Getter;
2722
import lombok.extern.slf4j.Slf4j;
23+
import org.apache.fineract.client.feign.FeignException;
2824

2925
/**
3026
* Exception thrown by {@link FeignCalls} utility when Feign calls fail.
@@ -49,7 +45,7 @@ private static String createMessage(FeignException e) {
4945
sb.append(", request=").append(e.request().url());
5046
}
5147

52-
String contentString = e.contentUTF8();
48+
String contentString = e.responseBodyAsString();
5349
if (contentString != null && !contentString.isEmpty()) {
5450
sb.append(", errorBody=").append(contentString);
5551
}
@@ -58,34 +54,9 @@ private static String createMessage(FeignException e) {
5854
}
5955

6056
private static String extractDeveloperMessage(FeignException e) {
61-
try {
62-
byte[] content = e.content();
63-
if (content == null || content.length == 0) {
64-
return e.getMessage();
65-
}
66-
67-
String contentString = new String(content, StandardCharsets.UTF_8);
68-
ObjectMapper mapper = new ObjectMapper();
69-
JsonNode root = mapper.readTree(contentString);
70-
71-
if (root.has("developerMessage")) {
72-
return root.get("developerMessage").asText();
73-
}
74-
75-
if (root.has("errors")) {
76-
JsonNode errors = root.get("errors");
77-
if (errors.isArray() && errors.size() > 0) {
78-
JsonNode firstError = errors.get(0);
79-
if (firstError.has("developerMessage")) {
80-
return firstError.get("developerMessage").asText();
81-
}
82-
}
83-
}
84-
85-
return contentString;
86-
} catch (IOException ex) {
87-
log.warn("Failed to extract developer message from error response", ex);
88-
return e.getMessage();
57+
if (e.getDeveloperMessage() != null) {
58+
return e.getDeveloperMessage();
8959
}
60+
return e.getMessage();
9061
}
9162
}

fineract-client-feign/src/main/java/org/apache/fineract/client/feign/util/FeignCalls.java

Lines changed: 38 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,8 +18,8 @@
1818
*/
1919
package org.apache.fineract.client.feign.util;
2020

21-
import feign.FeignException;
2221
import java.util.function.Supplier;
22+
import org.apache.fineract.client.feign.FeignException;
2323

2424
/**
2525
* Extension methods for Feign calls. This class is recommended to be statically imported.
@@ -77,4 +77,41 @@ public static void executeVoid(Runnable feignCall) throws CallFailedRuntimeExcep
7777
public static <T> T execute(Supplier<T> feignCall) throws FeignException {
7878
return feignCall.get();
7979
}
80+
81+
/**
82+
* Execute a Feign call expecting failure (for negative tests). Returns the exception with error details.
83+
*
84+
* @param feignCall
85+
* the Feign call to execute
86+
* @return CallFailedRuntimeException containing status code and error message
87+
* @throws AssertionError
88+
* if the call succeeds when failure was expected
89+
*/
90+
public static CallFailedRuntimeException fail(Supplier<?> feignCall) {
91+
try {
92+
Object result = feignCall.get();
93+
throw new AssertionError("Expected call to fail, but it succeeded with result: " + result);
94+
} catch (FeignException e) {
95+
return new CallFailedRuntimeException(e);
96+
}
97+
}
98+
99+
/**
100+
* Execute a Feign call expecting failure with void return (for negative tests). Returns the exception with error
101+
* details.
102+
*
103+
* @param feignCall
104+
* the Feign call to execute
105+
* @return CallFailedRuntimeException containing status code and error message
106+
* @throws AssertionError
107+
* if the call succeeds when failure was expected
108+
*/
109+
public static CallFailedRuntimeException failVoid(Runnable feignCall) {
110+
try {
111+
feignCall.run();
112+
throw new AssertionError("Expected call to fail, but it succeeded");
113+
} catch (FeignException e) {
114+
return new CallFailedRuntimeException(e);
115+
}
116+
}
80117
}

fineract-e2e-tests-core/src/test/java/org/apache/fineract/test/api/FineractClientConfiguration.java

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -55,12 +55,15 @@ public FineractFeignClient fineractFeignClient() {
5555
String tenantId = apiProperties.getTenantId();
5656
long readTimeout = apiProperties.getReadTimeout();
5757
String apiBaseUrl = baseUrl + "/fineract-provider/api/";
58-
log.info("Creating FineractFeignClient: url={}, tenant={}, user={}", apiBaseUrl, tenantId, username);
58+
59+
boolean debugEnabled = Boolean.parseBoolean(System.getProperty("fineract.feign.debug", "false"));
60+
log.info("Creating FineractFeignClient: url={}, tenant={}, user={}, debug={}", apiBaseUrl, tenantId, username, debugEnabled);
5961

6062
FineractFeignClient client = FineractFeignClient.builder().baseUrl(apiBaseUrl).credentials(username, password).tenantId(tenantId)
61-
.disableSslVerification(true).connectTimeout(60, TimeUnit.SECONDS).readTimeout((int) readTimeout, TimeUnit.SECONDS).build();
63+
.disableSslVerification(true).debug(debugEnabled).connectTimeout(60, TimeUnit.SECONDS)
64+
.readTimeout((int) readTimeout, TimeUnit.SECONDS).build();
6265

63-
log.info("FineractFeignClient created successfully");
66+
log.info("FineractFeignClient created successfully with debug={}", debugEnabled);
6467
return client;
6568
}
6669
}

fineract-e2e-tests-core/src/test/java/org/apache/fineract/test/data/loanproduct/LoanProductResolver.java

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,6 @@
2525
import lombok.extern.slf4j.Slf4j;
2626
import org.apache.fineract.client.feign.FineractFeignClient;
2727
import org.apache.fineract.client.models.GetLoanProductsResponse;
28-
import org.springframework.cache.annotation.Cacheable;
2928
import org.springframework.stereotype.Component;
3029

3130
@Component
@@ -35,12 +34,14 @@ public class LoanProductResolver {
3534

3635
private final FineractFeignClient fineractClient;
3736

38-
@Cacheable(key = "#loanProduct.getName()", value = "loanProductsByName")
3937
public long resolve(LoanProduct loanProduct) {
4038
String loanProductName = loanProduct.getName();
4139
log.debug("Resolving loan product by name [{}]", loanProductName);
4240
List<GetLoanProductsResponse> loanProductsResponses = ok(() -> fineractClient.loanProducts().retrieveAllLoanProducts());
4341

42+
log.info("Retrieved {} loan products from API", loanProductsResponses.size());
43+
log.info("Available loan products: {}", loanProductsResponses.stream().map(GetLoanProductsResponse::getName).toList());
44+
4445
GetLoanProductsResponse foundLpr = loanProductsResponses.stream().filter(lpr -> loanProductName.equals(lpr.getName())).findAny()
4546
.orElseThrow(() -> new IllegalArgumentException("Loan product [%s] not found".formatted(loanProductName)));
4647
return foundLpr.getId();

fineract-e2e-tests-core/src/test/java/org/apache/fineract/test/helper/BusinessDateHelper.java

Lines changed: 22 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -45,12 +45,30 @@ public class BusinessDateHelper {
4545
private final FineractFeignClient fineractClient;
4646

4747
public void setBusinessDate(String businessDate) {
48-
log.debug("Setting business date to: {} (using Feign)", businessDate);
48+
log.info("==========================================");
49+
log.info("SETTING BUSINESS DATE TO: {}", businessDate);
50+
log.info("==========================================");
51+
4952
BusinessDateUpdateRequest businessDateRequest = defaultBusinessDateRequest().date(businessDate);
5053

51-
BusinessDateUpdateResponse response = ok(
52-
() -> fineractClient.businessDateManagement().updateBusinessDate(businessDateRequest, Collections.emptyMap()));
53-
TestContext.INSTANCE.set(TestContextKey.BUSINESS_DATE_RESPONSE, response);
54+
try {
55+
BusinessDateUpdateResponse response = ok(
56+
() -> fineractClient.businessDateManagement().updateBusinessDate(businessDateRequest, Collections.emptyMap()));
57+
TestContext.INSTANCE.set(TestContextKey.BUSINESS_DATE_RESPONSE, response);
58+
59+
log.info("✓ Business date update response: {}", response);
60+
61+
BusinessDateResponse verify = ok(() -> fineractClient.businessDateManagement().getBusinessDate(BUSINESS_DATE));
62+
log.info("✓ Verified business date is now: {}", verify.getDate());
63+
log.info("==========================================");
64+
65+
} catch (Exception e) {
66+
log.error("==========================================");
67+
log.error("✗ BUSINESS DATE UPDATE FAILED!");
68+
log.error("✗ Error: {}", e.getMessage());
69+
log.error("==========================================", e);
70+
throw e;
71+
}
5472
}
5573

5674
public void setBusinessDateToday() {

0 commit comments

Comments
 (0)