|
|
@@ -5,8 +5,11 @@ import ch.qos.logback.classic.spi.ILoggingEvent;
|
|
|
import ch.qos.logback.core.read.ListAppender;
|
|
|
import com.ruoyi.app.order.OrderLifecycleService;
|
|
|
import com.ruoyi.app.pay.dto.OmgCallbackRequest;
|
|
|
+import com.ruoyi.app.pay.dto.OmgOrderRequest;
|
|
|
import com.ruoyi.app.pay.dto.OmgRefundOutcome;
|
|
|
import com.ruoyi.app.utils.omg.OmgPay;
|
|
|
+import com.ruoyi.common.core.domain.AjaxResult;
|
|
|
+import com.ruoyi.common.utils.MessageUtils;
|
|
|
import com.ruoyi.system.domain.PosOrder;
|
|
|
import com.ruoyi.system.domain.PosOrderOmgPayment;
|
|
|
import com.ruoyi.system.domain.PosOrderOmgRefund;
|
|
|
@@ -21,6 +24,9 @@ import org.slf4j.LoggerFactory;
|
|
|
import org.springframework.beans.MutablePropertyValues;
|
|
|
import org.springframework.test.util.ReflectionTestUtils;
|
|
|
import org.springframework.validation.DataBinder;
|
|
|
+import org.springframework.web.bind.annotation.ModelAttribute;
|
|
|
+import org.springframework.web.bind.annotation.PathVariable;
|
|
|
+import org.springframework.web.bind.annotation.RequestBody;
|
|
|
import org.springframework.web.bind.annotation.RequestHeader;
|
|
|
import org.springframework.web.bind.annotation.RequestParam;
|
|
|
|
|
|
@@ -38,6 +44,7 @@ import static org.mockito.ArgumentMatchers.any;
|
|
|
import static org.mockito.ArgumentMatchers.anyInt;
|
|
|
import static org.mockito.ArgumentMatchers.anyString;
|
|
|
import static org.mockito.Mockito.mock;
|
|
|
+import static org.mockito.Mockito.mockStatic;
|
|
|
import static org.mockito.Mockito.never;
|
|
|
import static org.mockito.Mockito.verify;
|
|
|
import static org.mockito.Mockito.when;
|
|
|
@@ -75,6 +82,32 @@ class OmgPayControllerTest {
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+ @Test
|
|
|
+ void orderCommandEndpointsUseRequestBodyWithoutAutomaticBeanValidation() {
|
|
|
+ for (String methodName : List.of("create", "refund", "query")) {
|
|
|
+ Parameter request = Arrays.stream(method(methodName).getParameters())
|
|
|
+ .filter(parameter -> parameter.getType() == OmgOrderRequest.class)
|
|
|
+ .findFirst()
|
|
|
+ .orElseThrow();
|
|
|
+
|
|
|
+ RequestBody requestBody = request.getAnnotation(RequestBody.class);
|
|
|
+ assertTrue(requestBody != null, methodName + " should bind its DTO with @RequestBody");
|
|
|
+ assertFalse(requestBody.required(), methodName + " should let business validation handle an empty body");
|
|
|
+ assertFalse(request.isAnnotationPresent(ModelAttribute.class));
|
|
|
+ assertFalse(Arrays.stream(request.getAnnotations())
|
|
|
+ .anyMatch(annotation -> annotation.annotationType().getPackageName()
|
|
|
+ .startsWith("jakarta.validation")));
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ @Test
|
|
|
+ void orderRequestDtoDoesNotContainBeanValidationAnnotations() {
|
|
|
+ assertFalse(Arrays.stream(OmgOrderRequest.class.getDeclaredFields())
|
|
|
+ .flatMap(field -> Arrays.stream(field.getAnnotations()))
|
|
|
+ .anyMatch(annotation -> annotation.annotationType().getPackageName()
|
|
|
+ .startsWith("jakarta.validation")));
|
|
|
+ }
|
|
|
+
|
|
|
@Test
|
|
|
void omgCallbacksReceiveTypedDto() {
|
|
|
for (String methodName : List.of("notify", "returnCallback", "paymentInfoCallback")) {
|
|
|
@@ -83,6 +116,60 @@ class OmgPayControllerTest {
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+ @Test
|
|
|
+ void omgFormCallbacksUseModelAttributeInsteadOfRequestBody() {
|
|
|
+ for (String methodName : List.of("notify", "returnCallback", "paymentInfoCallback")) {
|
|
|
+ Parameter callback = Arrays.stream(method(methodName).getParameters())
|
|
|
+ .filter(parameter -> parameter.getType() == OmgCallbackRequest.class)
|
|
|
+ .findFirst()
|
|
|
+ .orElseThrow();
|
|
|
+
|
|
|
+ assertTrue(callback.isAnnotationPresent(ModelAttribute.class));
|
|
|
+ assertFalse(callback.isAnnotationPresent(RequestBody.class));
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ @Test
|
|
|
+ void paymentInfoOrderIdRemainsAPathVariable() {
|
|
|
+ Parameter orderId = Arrays.stream(method("getPaymentInfo").getParameters())
|
|
|
+ .filter(parameter -> "orderid".equals(parameter.getName()))
|
|
|
+ .findFirst()
|
|
|
+ .orElseThrow();
|
|
|
+
|
|
|
+ assertTrue(orderId.isAnnotationPresent(PathVariable.class));
|
|
|
+ assertFalse(orderId.isAnnotationPresent(RequestParam.class));
|
|
|
+ }
|
|
|
+
|
|
|
+ @Test
|
|
|
+ void invalidOrderRequestsReturnInternationalizedBusinessError() {
|
|
|
+ OmgPayController controller = new OmgPayController();
|
|
|
+ OmgOrderRequest blank = new OmgOrderRequest();
|
|
|
+ OmgOrderRequest whitespace = new OmgOrderRequest();
|
|
|
+ whitespace.setOrderid(" ");
|
|
|
+
|
|
|
+ try (var messages = mockStatic(MessageUtils.class)) {
|
|
|
+ messages.when(() -> MessageUtils.message("no.order.id.error")).thenReturn("localized order error");
|
|
|
+
|
|
|
+ for (AjaxResult result : List.of(
|
|
|
+ controller.create("token", null),
|
|
|
+ controller.refund("token", blank),
|
|
|
+ controller.query("token", whitespace))) {
|
|
|
+ assertEquals("localized order error", result.get(AjaxResult.MSG_TAG));
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ @Test
|
|
|
+ void orderRequestValidationDoesNotImposeALengthLimit() {
|
|
|
+ OmgOrderRequest request = new OmgOrderRequest();
|
|
|
+ request.setOrderid("x".repeat(1000));
|
|
|
+
|
|
|
+ Boolean invalid = ReflectionTestUtils.invokeMethod(
|
|
|
+ new OmgPayController(), "invalidOrderRequest", request);
|
|
|
+
|
|
|
+ assertFalse(Boolean.TRUE.equals(invalid));
|
|
|
+ }
|
|
|
+
|
|
|
@Test
|
|
|
void callbackDtoRetainsOriginalOmgParameterNames() {
|
|
|
OmgCallbackRequest request = new OmgCallbackRequest();
|