Commit 7c165fb1f6f2602b1929648b87fb40e1f61357e0

Authored by YunaiV
1 parent 3a1694de

1. 完善 PayNotifyServiceImpl 的单元测试

yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/controller/admin/notify/vo/PayNotifyTaskPageReqVO.java
@@ -21,13 +21,13 @@ public class PayNotifyTaskPageReqVO extends PageParam { @@ -21,13 +21,13 @@ public class PayNotifyTaskPageReqVO extends PageParam {
21 private Long appId; 21 private Long appId;
22 22
23 @Schema(description = "通知类型", example = "2") 23 @Schema(description = "通知类型", example = "2")
24 - private Byte type; 24 + private Integer type;
25 25
26 @Schema(description = "数据编号", example = "6722") 26 @Schema(description = "数据编号", example = "6722")
27 private Long dataId; 27 private Long dataId;
28 28
29 @Schema(description = "通知状态", example = "1") 29 @Schema(description = "通知状态", example = "1")
30 - private Byte status; 30 + private Integer status;
31 31
32 @Schema(description = "商户订单编号", example = "26697") 32 @Schema(description = "商户订单编号", example = "26697")
33 private String merchantOrderId; 33 private String merchantOrderId;
yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/service/notify/PayNotifyServiceImpl.java
@@ -25,6 +25,7 @@ import cn.iocoder.yudao.module.pay.enums.notify.PayNotifyStatusEnum; @@ -25,6 +25,7 @@ import cn.iocoder.yudao.module.pay.enums.notify.PayNotifyStatusEnum;
25 import cn.iocoder.yudao.module.pay.enums.notify.PayNotifyTypeEnum; 25 import cn.iocoder.yudao.module.pay.enums.notify.PayNotifyTypeEnum;
26 import cn.iocoder.yudao.module.pay.service.order.PayOrderService; 26 import cn.iocoder.yudao.module.pay.service.order.PayOrderService;
27 import cn.iocoder.yudao.module.pay.service.refund.PayRefundService; 27 import cn.iocoder.yudao.module.pay.service.refund.PayRefundService;
  28 +import com.google.common.annotations.VisibleForTesting;
28 import lombok.extern.slf4j.Slf4j; 29 import lombok.extern.slf4j.Slf4j;
29 import org.springframework.context.annotation.Lazy; 30 import org.springframework.context.annotation.Lazy;
30 import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor; 31 import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
@@ -177,7 +178,7 @@ public class PayNotifyServiceImpl implements PayNotifyService { @@ -177,7 +178,7 @@ public class PayNotifyServiceImpl implements PayNotifyService {
177 }); 178 });
178 } 179 }
179 180
180 - @Transactional 181 + @Transactional(rollbackFor = Exception.class)
181 public void executeNotify0(PayNotifyTaskDO task) { 182 public void executeNotify0(PayNotifyTaskDO task) {
182 // 发起回调 183 // 发起回调
183 CommonResult<?> invokeResult = null; 184 CommonResult<?> invokeResult = null;
@@ -237,7 +238,8 @@ public class PayNotifyServiceImpl implements PayNotifyService { @@ -237,7 +238,8 @@ public class PayNotifyServiceImpl implements PayNotifyService {
237 * @param invokeException 通知异常 238 * @param invokeException 通知异常
238 * @return 最终任务的状态 239 * @return 最终任务的状态
239 */ 240 */
240 - private Integer processNotifyResult(PayNotifyTaskDO task, CommonResult<?> invokeResult, Throwable invokeException) { 241 + @VisibleForTesting
  242 + Integer processNotifyResult(PayNotifyTaskDO task, CommonResult<?> invokeResult, Throwable invokeException) {
241 // 设置通用的更新 PayNotifyTaskDO 的字段 243 // 设置通用的更新 PayNotifyTaskDO 的字段
242 PayNotifyTaskDO updateTask = new PayNotifyTaskDO() 244 PayNotifyTaskDO updateTask = new PayNotifyTaskDO()
243 .setId(task.getId()) 245 .setId(task.getId())
yudao-module-pay/yudao-module-pay-biz/src/test/java/cn/iocoder/yudao/module/pay/service/notify/PayNotifyServiceTest.java
1 package cn.iocoder.yudao.module.pay.service.notify; 1 package cn.iocoder.yudao.module.pay.service.notify;
2 2
3 import cn.hutool.extra.spring.SpringUtil; 3 import cn.hutool.extra.spring.SpringUtil;
  4 +import cn.iocoder.yudao.framework.common.pojo.CommonResult;
  5 +import cn.iocoder.yudao.framework.common.pojo.PageResult;
4 import cn.iocoder.yudao.framework.test.core.ut.BaseDbUnitTest; 6 import cn.iocoder.yudao.framework.test.core.ut.BaseDbUnitTest;
  7 +import cn.iocoder.yudao.module.pay.controller.admin.notify.vo.PayNotifyTaskPageReqVO;
  8 +import cn.iocoder.yudao.module.pay.dal.dataobject.notify.PayNotifyLogDO;
5 import cn.iocoder.yudao.module.pay.dal.dataobject.notify.PayNotifyTaskDO; 9 import cn.iocoder.yudao.module.pay.dal.dataobject.notify.PayNotifyTaskDO;
6 import cn.iocoder.yudao.module.pay.dal.dataobject.order.PayOrderDO; 10 import cn.iocoder.yudao.module.pay.dal.dataobject.order.PayOrderDO;
7 import cn.iocoder.yudao.module.pay.dal.dataobject.refund.PayRefundDO; 11 import cn.iocoder.yudao.module.pay.dal.dataobject.refund.PayRefundDO;
@@ -20,14 +24,17 @@ import org.redisson.api.RLock; @@ -20,14 +24,17 @@ import org.redisson.api.RLock;
20 import org.redisson.api.RedissonClient; 24 import org.redisson.api.RedissonClient;
21 import org.springframework.boot.test.mock.mockito.MockBean; 25 import org.springframework.boot.test.mock.mockito.MockBean;
22 import org.springframework.context.annotation.Import; 26 import org.springframework.context.annotation.Import;
23 -import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;  
24 27
25 import javax.annotation.Resource; 28 import javax.annotation.Resource;
26 -  
27 import java.time.Duration; 29 import java.time.Duration;
  30 +import java.util.List;
28 31
29 -import static cn.iocoder.yudao.framework.common.util.date.LocalDateTimeUtils.addTime; 32 +import static cn.iocoder.yudao.framework.common.exception.enums.GlobalErrorCodeConstants.BAD_REQUEST;
  33 +import static cn.iocoder.yudao.framework.common.util.date.LocalDateTimeUtils.*;
  34 +import static cn.iocoder.yudao.framework.common.util.object.ObjectUtils.cloneIgnoreId;
  35 +import static cn.iocoder.yudao.framework.test.core.util.AssertUtils.assertPojoEquals;
30 import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.randomPojo; 36 import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.randomPojo;
  37 +import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.randomString;
31 import static org.assertj.core.api.Assertions.assertThat; 38 import static org.assertj.core.api.Assertions.assertThat;
32 import static org.junit.jupiter.api.Assertions.*; 39 import static org.junit.jupiter.api.Assertions.*;
33 import static org.mockito.ArgumentMatchers.anyString; 40 import static org.mockito.ArgumentMatchers.anyString;
@@ -167,7 +174,167 @@ public class PayNotifyServiceTest extends BaseDbUnitTest { @@ -167,7 +174,167 @@ public class PayNotifyServiceTest extends BaseDbUnitTest {
167 174
168 // 调用 175 // 调用
169 notifyService.executeNotify0(task); 176 notifyService.executeNotify0(task);
  177 + // 断言,task
  178 + PayNotifyTaskDO dbTask = notifyTaskMapper.selectById(task.getId());
  179 + assertNotEquals(task.getNextNotifyTime(), dbTask.getNextNotifyTime());
  180 + assertNotEquals(task.getLastExecuteTime(), dbTask.getNextNotifyTime());
  181 + assertEquals(dbTask.getNotifyTimes(), 1);
  182 + assertEquals(dbTask.getStatus(), PayNotifyStatusEnum.REQUEST_FAILURE.getStatus());
  183 + // 断言,log
  184 + PayNotifyLogDO dbLog = notifyLogMapper.selectOne(null);
  185 + assertEquals(dbLog.getTaskId(), task.getId());
  186 + assertEquals(dbLog.getNotifyTimes(), 1);
  187 + assertTrue(dbLog.getResponse().contains("未知的通知任务类型:"));
  188 + assertEquals(dbLog.getStatus(), PayNotifyStatusEnum.REQUEST_FAILURE.getStatus());
  189 + }
  190 +
  191 + @Test
  192 + public void testProcessNotifyResult_success() {
  193 + // mock 数据(task)
  194 + PayNotifyTaskDO task = randomPojo(PayNotifyTaskDO.class,
  195 + o -> o.setNotifyTimes(0).setMaxNotifyTimes(9));
  196 + notifyTaskMapper.insert(task);
  197 + // 准备参数
  198 + CommonResult<?> invokeResult = CommonResult.success(randomString());
  199 +
  200 + // 调用
  201 + notifyService.processNotifyResult(task, invokeResult, null);
  202 + // 断言
  203 + PayNotifyTaskDO dbTask = notifyTaskMapper.selectById(task.getId());
  204 + assertEquals(task.getNextNotifyTime(), dbTask.getNextNotifyTime());
  205 + assertNotEquals(task.getLastExecuteTime(), dbTask.getNextNotifyTime());
  206 + assertEquals(dbTask.getNotifyTimes(), 1);
  207 + assertEquals(dbTask.getStatus(), PayNotifyStatusEnum.SUCCESS.getStatus());
  208 + }
  209 +
  210 + @Test
  211 + public void testProcessNotifyResult_failure() {
  212 + // mock 数据(task)
  213 + PayNotifyTaskDO task = randomPojo(PayNotifyTaskDO.class,
  214 + o -> o.setNotifyTimes(8).setMaxNotifyTimes(9));
  215 + notifyTaskMapper.insert(task);
  216 + // 准备参数
  217 + CommonResult<?> invokeResult = CommonResult.error(BAD_REQUEST);
  218 +
  219 + // 调用
  220 + notifyService.processNotifyResult(task, invokeResult, null);
  221 + // 断言
  222 + PayNotifyTaskDO dbTask = notifyTaskMapper.selectById(task.getId());
  223 + assertEquals(task.getNextNotifyTime(), dbTask.getNextNotifyTime());
  224 + assertNotEquals(task.getLastExecuteTime(), dbTask.getNextNotifyTime());
  225 + assertEquals(dbTask.getNotifyTimes(), 9);
  226 + assertEquals(dbTask.getStatus(), PayNotifyStatusEnum.FAILURE.getStatus());
  227 + }
  228 +
  229 + @Test
  230 + public void testProcessNotifyResult_requestFailure() {
  231 + // mock 数据(task)
  232 + PayNotifyTaskDO task = randomPojo(PayNotifyTaskDO.class,
  233 + o -> o.setNotifyTimes(0).setMaxNotifyTimes(9));
  234 + notifyTaskMapper.insert(task);
  235 + // 准备参数
  236 + CommonResult<?> invokeResult = CommonResult.error(BAD_REQUEST);
  237 +
  238 + // 调用
  239 + notifyService.processNotifyResult(task, invokeResult, null);
  240 + // 断言
  241 + PayNotifyTaskDO dbTask = notifyTaskMapper.selectById(task.getId());
  242 + assertNotEquals(task.getNextNotifyTime(), dbTask.getNextNotifyTime());
  243 + assertNotEquals(task.getLastExecuteTime(), dbTask.getNextNotifyTime());
  244 + assertEquals(dbTask.getNotifyTimes(), 1);
  245 + assertEquals(dbTask.getStatus(), PayNotifyStatusEnum.REQUEST_SUCCESS.getStatus());
  246 + }
170 247
  248 + @Test
  249 + public void testProcessNotifyResult_requestSuccess() {
  250 + // mock 数据(task)
  251 + PayNotifyTaskDO task = randomPojo(PayNotifyTaskDO.class,
  252 + o -> o.setNotifyTimes(0).setMaxNotifyTimes(9));
  253 + notifyTaskMapper.insert(task);
  254 + // 准备参数
  255 + CommonResult<?> invokeResult = CommonResult.error(BAD_REQUEST);
  256 + RuntimeException invokeException = new RuntimeException();
  257 +
  258 + // 调用
  259 + notifyService.processNotifyResult(task, invokeResult, invokeException);
  260 + // 断言
  261 + PayNotifyTaskDO dbTask = notifyTaskMapper.selectById(task.getId());
  262 + assertNotEquals(task.getNextNotifyTime(), dbTask.getNextNotifyTime());
  263 + assertNotEquals(task.getLastExecuteTime(), dbTask.getNextNotifyTime());
  264 + assertEquals(dbTask.getNotifyTimes(), 1);
  265 + assertEquals(dbTask.getStatus(), PayNotifyStatusEnum.REQUEST_FAILURE.getStatus());
  266 + }
  267 +
  268 + @Test
  269 + public void testGetNotifyTask() {
  270 + // mock 数据(task)
  271 + PayNotifyTaskDO task = randomPojo(PayNotifyTaskDO.class);
  272 + notifyTaskMapper.insert(task);
  273 + // 准备参数
  274 + Long id = task.getId();
  275 +
  276 + // 调用
  277 + PayNotifyTaskDO dbTask = notifyService.getNotifyTask(id);
  278 + // 断言
  279 + assertPojoEquals(dbTask, task);
  280 + }
  281 +
  282 + @Test
  283 + public void testGetNotifyTaskPage() {
  284 + // mock 数据
  285 + PayNotifyTaskDO dbTask = randomPojo(PayNotifyTaskDO.class, o -> { // 等会查询到
  286 + o.setAppId(1L);
  287 + o.setType(PayNotifyTypeEnum.REFUND.getType());
  288 + o.setDataId(100L);
  289 + o.setStatus(PayNotifyStatusEnum.SUCCESS.getStatus());
  290 + o.setMerchantOrderId("P110");
  291 + o.setCreateTime(buildTime(2023, 2, 3));
  292 + });
  293 + notifyTaskMapper.insert(dbTask);
  294 + // 测试 appId 不匹配
  295 + notifyTaskMapper.insert(cloneIgnoreId(dbTask, o -> o.setAppId(2L)));
  296 + // 测试 type 不匹配
  297 + notifyTaskMapper.insert(cloneIgnoreId(dbTask, o -> o.setType(PayNotifyTypeEnum.ORDER.getType())));
  298 + // 测试 dataId 不匹配
  299 + notifyTaskMapper.insert(cloneIgnoreId(dbTask, o -> o.setDataId(200L)));
  300 + // 测试 status 不匹配
  301 + notifyTaskMapper.insert(cloneIgnoreId(dbTask, o -> o.setStatus(PayNotifyStatusEnum.FAILURE.getStatus())));
  302 + // 测试 merchantOrderId 不匹配
  303 + notifyTaskMapper.insert(cloneIgnoreId(dbTask, o -> o.setMerchantOrderId(randomString())));
  304 + // 测试 createTime 不匹配
  305 + notifyTaskMapper.insert(cloneIgnoreId(dbTask, o -> o.setCreateTime(buildTime(2023, 1, 1))));
  306 + // 准备参数
  307 + PayNotifyTaskPageReqVO reqVO = new PayNotifyTaskPageReqVO();
  308 + reqVO.setAppId(1L);
  309 + reqVO.setType(PayNotifyTypeEnum.REFUND.getType());
  310 + reqVO.setDataId(100L);
  311 + reqVO.setStatus(PayNotifyStatusEnum.SUCCESS.getStatus());
  312 + reqVO.setMerchantOrderId("P110");
  313 + reqVO.setCreateTime(buildBetweenTime(2023, 2, 1, 2023, 2, 28));
  314 +
  315 + // 调用
  316 + PageResult<PayNotifyTaskDO> pageResult = notifyService.getNotifyTaskPage(reqVO);
  317 + // 断言
  318 + assertEquals(1, pageResult.getTotal());
  319 + assertEquals(1, pageResult.getList().size());
  320 + assertPojoEquals(dbTask, pageResult.getList().get(0));
  321 + }
  322 +
  323 + @Test
  324 + public void testGetNotifyLogList() {
  325 + // mock 数据
  326 + PayNotifyLogDO dbLog = randomPojo(PayNotifyLogDO.class);
  327 + notifyLogMapper.insert(dbLog);
  328 + PayNotifyLogDO dbLog02 = randomPojo(PayNotifyLogDO.class);
  329 + notifyLogMapper.insert(dbLog02);
  330 + // 准备参数
  331 + Long taskId = dbLog.getTaskId();
  332 +
  333 + // 调用
  334 + List<PayNotifyLogDO> logList = notifyService.getNotifyLogList(taskId);
  335 + // 断言
  336 + assertEquals(logList.size(), 1);
  337 + assertPojoEquals(dbLog, logList.get(0));
171 } 338 }
172 339
173 private void mockLock(Long id) { 340 private void mockLock(Long id) {
yudao-module-pay/yudao-module-pay-biz/src/test/resources/sql/clean.sql
@@ -3,4 +3,5 @@ DELETE FROM pay_channel; @@ -3,4 +3,5 @@ DELETE FROM pay_channel;
3 DELETE FROM pay_order; 3 DELETE FROM pay_order;
4 DELETE FROM pay_order_extension; 4 DELETE FROM pay_order_extension;
5 DELETE FROM pay_refund; 5 DELETE FROM pay_refund;
6 -DELETE FROM pay_notify_task;  
7 \ No newline at end of file 6 \ No newline at end of file
  7 +DELETE FROM pay_notify_task;
  8 +DELETE FROM pay_notify_log;
yudao-module-pay/yudao-module-pay-biz/src/test/resources/sql/create_tables.sql
@@ -129,4 +129,18 @@ CREATE TABLE IF NOT EXISTS `pay_notify_task` ( @@ -129,4 +129,18 @@ CREATE TABLE IF NOT EXISTS `pay_notify_task` (
129 `deleted` bit(1) NOT NULL DEFAULT FALSE, 129 `deleted` bit(1) NOT NULL DEFAULT FALSE,
130 `tenant_id` bigint(20) NOT NULL DEFAULT 0, 130 `tenant_id` bigint(20) NOT NULL DEFAULT 0,
131 PRIMARY KEY ("id") 131 PRIMARY KEY ("id")
132 -) COMMENT = '支付通知'; 132 +) COMMENT = '支付通知任务';
  133 +
  134 +CREATE TABLE IF NOT EXISTS `pay_notify_log` (
  135 + "id" number NOT NULL GENERATED BY DEFAULT AS IDENTITY,
  136 + `task_id` bigint(20) NOT NULL,
  137 + `notify_times` int NOT NULL,
  138 + `response` varchar(1024) NOT NULL,
  139 + `status` tinyint(4) NOT NULL,
  140 + `creator` varchar(64) NULL DEFAULT '',
  141 + `create_time` datetime(0) NOT NULL DEFAULT CURRENT_TIMESTAMP,
  142 + `updater` varchar(64) NULL DEFAULT '',
  143 + `update_time` datetime(0) NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
  144 + `deleted` bit(1) NOT NULL DEFAULT FALSE,
  145 + PRIMARY KEY ("id")
  146 +) COMMENT = '支付通知日志';