Commit 73e1158836c53ab7155ac329939b4f100e42dcf3
1 parent
00e1c30f
by gateway:
1. notify 部分单元测试
Showing
14 changed files
with
238 additions
and
66 deletions
yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/dal/dataobject/notify/PayNotifyTaskDO.java
| @@ -7,6 +7,7 @@ import cn.iocoder.yudao.module.pay.dal.dataobject.refund.PayRefundDO; | @@ -7,6 +7,7 @@ import cn.iocoder.yudao.module.pay.dal.dataobject.refund.PayRefundDO; | ||
| 7 | import cn.iocoder.yudao.module.pay.enums.notify.PayNotifyStatusEnum; | 7 | import cn.iocoder.yudao.module.pay.enums.notify.PayNotifyStatusEnum; |
| 8 | import cn.iocoder.yudao.module.pay.enums.notify.PayNotifyTypeEnum; | 8 | import cn.iocoder.yudao.module.pay.enums.notify.PayNotifyTypeEnum; |
| 9 | import com.baomidou.mybatisplus.annotation.KeySequence; | 9 | import com.baomidou.mybatisplus.annotation.KeySequence; |
| 10 | +import com.baomidou.mybatisplus.annotation.TableId; | ||
| 10 | import com.baomidou.mybatisplus.annotation.TableName; | 11 | import com.baomidou.mybatisplus.annotation.TableName; |
| 11 | import lombok.Data; | 12 | import lombok.Data; |
| 12 | import lombok.EqualsAndHashCode; | 13 | import lombok.EqualsAndHashCode; |
| @@ -40,6 +41,7 @@ public class PayNotifyTaskDO extends TenantBaseDO { | @@ -40,6 +41,7 @@ public class PayNotifyTaskDO extends TenantBaseDO { | ||
| 40 | /** | 41 | /** |
| 41 | * 编号,自增 | 42 | * 编号,自增 |
| 42 | */ | 43 | */ |
| 44 | + @TableId | ||
| 43 | private Long id; | 45 | private Long id; |
| 44 | /** | 46 | /** |
| 45 | * 应用编号 | 47 | * 应用编号 |
yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/dal/redis/RedisKeyConstants.java
| @@ -11,7 +11,7 @@ import org.redisson.api.RLock; | @@ -11,7 +11,7 @@ import org.redisson.api.RLock; | ||
| 11 | public interface RedisKeyConstants { | 11 | public interface RedisKeyConstants { |
| 12 | 12 | ||
| 13 | RedisKeyDefine PAY_NOTIFY_LOCK = new RedisKeyDefine("通知任务的分布式锁", | 13 | RedisKeyDefine PAY_NOTIFY_LOCK = new RedisKeyDefine("通知任务的分布式锁", |
| 14 | - "pay_notify:lock:", // 参数来自 DefaultLockKeyBuilder 类 | 14 | + "pay_notify:lock:%d", // 参数来自 DefaultLockKeyBuilder 类 |
| 15 | RedisKeyDefine.KeyTypeEnum.HASH, RLock.class, RedisKeyDefine.TimeoutTypeEnum.DYNAMIC); // Redisson 的 Lock 锁,使用 Hash 数据结构 | 15 | RedisKeyDefine.KeyTypeEnum.HASH, RLock.class, RedisKeyDefine.TimeoutTypeEnum.DYNAMIC); // Redisson 的 Lock 锁,使用 Hash 数据结构 |
| 16 | 16 | ||
| 17 | /** | 17 | /** |
yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/service/notify/PayNotifyService.java
| @@ -4,9 +4,7 @@ import cn.iocoder.yudao.framework.common.pojo.PageResult; | @@ -4,9 +4,7 @@ import cn.iocoder.yudao.framework.common.pojo.PageResult; | ||
| 4 | import cn.iocoder.yudao.module.pay.controller.admin.notify.vo.PayNotifyTaskPageReqVO; | 4 | import cn.iocoder.yudao.module.pay.controller.admin.notify.vo.PayNotifyTaskPageReqVO; |
| 5 | import cn.iocoder.yudao.module.pay.dal.dataobject.notify.PayNotifyLogDO; | 5 | import cn.iocoder.yudao.module.pay.dal.dataobject.notify.PayNotifyLogDO; |
| 6 | import cn.iocoder.yudao.module.pay.dal.dataobject.notify.PayNotifyTaskDO; | 6 | import cn.iocoder.yudao.module.pay.dal.dataobject.notify.PayNotifyTaskDO; |
| 7 | -import cn.iocoder.yudao.module.pay.service.notify.dto.PayNotifyTaskCreateReqDTO; | ||
| 8 | 7 | ||
| 9 | -import javax.validation.Valid; | ||
| 10 | import java.util.List; | 8 | import java.util.List; |
| 11 | 9 | ||
| 12 | /** | 10 | /** |
| @@ -19,9 +17,10 @@ public interface PayNotifyService { | @@ -19,9 +17,10 @@ public interface PayNotifyService { | ||
| 19 | /** | 17 | /** |
| 20 | * 创建回调通知任务 | 18 | * 创建回调通知任务 |
| 21 | * | 19 | * |
| 22 | - * @param reqDTO 任务信息 | 20 | + * @param type 类型 |
| 21 | + * @param dataId 数据编号 | ||
| 23 | */ | 22 | */ |
| 24 | - void createPayNotifyTask(@Valid PayNotifyTaskCreateReqDTO reqDTO); | 23 | + void createPayNotifyTask(Integer type, Long dataId); |
| 25 | 24 | ||
| 26 | /** | 25 | /** |
| 27 | * 执行回调通知 | 26 | * 执行回调通知 |
yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/service/notify/PayNotifyServiceImpl.java
| @@ -3,6 +3,7 @@ package cn.iocoder.yudao.module.pay.service.notify; | @@ -3,6 +3,7 @@ package cn.iocoder.yudao.module.pay.service.notify; | ||
| 3 | import cn.hutool.core.collection.CollUtil; | 3 | import cn.hutool.core.collection.CollUtil; |
| 4 | import cn.hutool.core.exceptions.ExceptionUtil; | 4 | import cn.hutool.core.exceptions.ExceptionUtil; |
| 5 | import cn.hutool.core.util.ObjectUtil; | 5 | import cn.hutool.core.util.ObjectUtil; |
| 6 | +import cn.hutool.extra.spring.SpringUtil; | ||
| 6 | import cn.hutool.http.HttpResponse; | 7 | import cn.hutool.http.HttpResponse; |
| 7 | import cn.hutool.http.HttpUtil; | 8 | import cn.hutool.http.HttpUtil; |
| 8 | import cn.iocoder.yudao.framework.common.pojo.CommonResult; | 9 | import cn.iocoder.yudao.framework.common.pojo.CommonResult; |
| @@ -22,7 +23,6 @@ import cn.iocoder.yudao.module.pay.dal.mysql.notify.PayNotifyTaskMapper; | @@ -22,7 +23,6 @@ import cn.iocoder.yudao.module.pay.dal.mysql.notify.PayNotifyTaskMapper; | ||
| 22 | import cn.iocoder.yudao.module.pay.dal.redis.notify.PayNotifyLockRedisDAO; | 23 | import cn.iocoder.yudao.module.pay.dal.redis.notify.PayNotifyLockRedisDAO; |
| 23 | import cn.iocoder.yudao.module.pay.enums.notify.PayNotifyStatusEnum; | 24 | import cn.iocoder.yudao.module.pay.enums.notify.PayNotifyStatusEnum; |
| 24 | import cn.iocoder.yudao.module.pay.enums.notify.PayNotifyTypeEnum; | 25 | import cn.iocoder.yudao.module.pay.enums.notify.PayNotifyTypeEnum; |
| 25 | -import cn.iocoder.yudao.module.pay.service.notify.dto.PayNotifyTaskCreateReqDTO; | ||
| 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 lombok.extern.slf4j.Slf4j; | 28 | import lombok.extern.slf4j.Slf4j; |
| @@ -84,15 +84,10 @@ public class PayNotifyServiceImpl implements PayNotifyService { | @@ -84,15 +84,10 @@ public class PayNotifyServiceImpl implements PayNotifyService { | ||
| 84 | @Resource | 84 | @Resource |
| 85 | private PayNotifyLockRedisDAO notifyLockCoreRedisDAO; | 85 | private PayNotifyLockRedisDAO notifyLockCoreRedisDAO; |
| 86 | 86 | ||
| 87 | - @Resource | ||
| 88 | - @Lazy // 循环依赖(自己依赖自己),避免报错 | ||
| 89 | - private PayNotifyServiceImpl self; | ||
| 90 | - | ||
| 91 | @Override | 87 | @Override |
| 92 | @Transactional(rollbackFor = Exception.class) | 88 | @Transactional(rollbackFor = Exception.class) |
| 93 | - public void createPayNotifyTask(PayNotifyTaskCreateReqDTO reqDTO) { | ||
| 94 | - PayNotifyTaskDO task = new PayNotifyTaskDO(); | ||
| 95 | - task.setType(reqDTO.getType()).setDataId(reqDTO.getDataId()); | 89 | + public void createPayNotifyTask(Integer type, Long dataId) { |
| 90 | + PayNotifyTaskDO task = new PayNotifyTaskDO().setType(type).setDataId(dataId); | ||
| 96 | task.setStatus(PayNotifyStatusEnum.WAITING.getStatus()).setNextNotifyTime(LocalDateTime.now()) | 91 | task.setStatus(PayNotifyStatusEnum.WAITING.getStatus()).setNextNotifyTime(LocalDateTime.now()) |
| 97 | .setNotifyTimes(0).setMaxNotifyTimes(PayNotifyTaskDO.NOTIFY_FREQUENCY.length + 1); | 92 | .setNotifyTimes(0).setMaxNotifyTimes(PayNotifyTaskDO.NOTIFY_FREQUENCY.length + 1); |
| 98 | // 补充 appId + notifyUrl 字段 | 93 | // 补充 appId + notifyUrl 字段 |
| @@ -178,7 +173,7 @@ public class PayNotifyServiceImpl implements PayNotifyService { | @@ -178,7 +173,7 @@ public class PayNotifyServiceImpl implements PayNotifyService { | ||
| 178 | } | 173 | } |
| 179 | 174 | ||
| 180 | // 执行通知 | 175 | // 执行通知 |
| 181 | - self.executeNotify0(dbTask); | 176 | + getSelf().executeNotify0(dbTask); |
| 182 | }); | 177 | }); |
| 183 | } | 178 | } |
| 184 | 179 | ||
| @@ -285,4 +280,13 @@ public class PayNotifyServiceImpl implements PayNotifyService { | @@ -285,4 +280,13 @@ public class PayNotifyServiceImpl implements PayNotifyService { | ||
| 285 | return notifyLogMapper.selectListByTaskId(taskId); | 280 | return notifyLogMapper.selectListByTaskId(taskId); |
| 286 | } | 281 | } |
| 287 | 282 | ||
| 283 | + /** | ||
| 284 | + * 获得自身的代理对象,解决 AOP 生效问题 | ||
| 285 | + * | ||
| 286 | + * @return 自己 | ||
| 287 | + */ | ||
| 288 | + private PayNotifyServiceImpl getSelf() { | ||
| 289 | + return SpringUtil.getBean(getClass()); | ||
| 290 | + } | ||
| 291 | + | ||
| 288 | } | 292 | } |
yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/service/notify/dto/PayNotifyTaskCreateReqDTO.java deleted
| 1 | -package cn.iocoder.yudao.module.pay.service.notify.dto; | ||
| 2 | - | ||
| 3 | -import lombok.AllArgsConstructor; | ||
| 4 | -import lombok.Builder; | ||
| 5 | -import lombok.Data; | ||
| 6 | -import lombok.NoArgsConstructor; | ||
| 7 | - | ||
| 8 | -import javax.validation.constraints.NotNull; | ||
| 9 | - | ||
| 10 | -/** | ||
| 11 | - * 支付通知创建 DTO | ||
| 12 | - * | ||
| 13 | - * @author 芋道源码 | ||
| 14 | - */ | ||
| 15 | -@Data | ||
| 16 | -@Builder | ||
| 17 | -@NoArgsConstructor | ||
| 18 | -@AllArgsConstructor | ||
| 19 | -public class PayNotifyTaskCreateReqDTO { | ||
| 20 | - | ||
| 21 | - /** | ||
| 22 | - * 类型 | ||
| 23 | - */ | ||
| 24 | - @NotNull(message = "类型不能为空") | ||
| 25 | - private Integer type; | ||
| 26 | - /** | ||
| 27 | - * 数据编号 | ||
| 28 | - */ | ||
| 29 | - @NotNull(message = "数据编号不能为空") | ||
| 30 | - private Long dataId; | ||
| 31 | - | ||
| 32 | -} |
yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/service/notify/vo/PayNotifyOrderReqVO.java deleted
yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/service/notify/vo/PayRefundOrderReqVO.java deleted
yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/service/order/PayOrderServiceImpl.java
| @@ -31,7 +31,6 @@ import cn.iocoder.yudao.module.pay.framework.pay.config.PayProperties; | @@ -31,7 +31,6 @@ import cn.iocoder.yudao.module.pay.framework.pay.config.PayProperties; | ||
| 31 | import cn.iocoder.yudao.module.pay.service.app.PayAppService; | 31 | import cn.iocoder.yudao.module.pay.service.app.PayAppService; |
| 32 | import cn.iocoder.yudao.module.pay.service.channel.PayChannelService; | 32 | import cn.iocoder.yudao.module.pay.service.channel.PayChannelService; |
| 33 | import cn.iocoder.yudao.module.pay.service.notify.PayNotifyService; | 33 | import cn.iocoder.yudao.module.pay.service.notify.PayNotifyService; |
| 34 | -import cn.iocoder.yudao.module.pay.service.notify.dto.PayNotifyTaskCreateReqDTO; | ||
| 35 | import cn.iocoder.yudao.module.pay.util.MoneyUtils; | 34 | import cn.iocoder.yudao.module.pay.util.MoneyUtils; |
| 36 | import com.google.common.annotations.VisibleForTesting; | 35 | import com.google.common.annotations.VisibleForTesting; |
| 37 | import lombok.extern.slf4j.Slf4j; | 36 | import lombok.extern.slf4j.Slf4j; |
| @@ -282,8 +281,8 @@ public class PayOrderServiceImpl implements PayOrderService { | @@ -282,8 +281,8 @@ public class PayOrderServiceImpl implements PayOrderService { | ||
| 282 | } | 281 | } |
| 283 | 282 | ||
| 284 | // 3. 插入支付通知记录 | 283 | // 3. 插入支付通知记录 |
| 285 | - notifyService.createPayNotifyTask(PayNotifyTaskCreateReqDTO.builder() | ||
| 286 | - .type(PayNotifyTypeEnum.ORDER.getType()).dataId(orderExtension.getOrderId()).build()); | 284 | + notifyService.createPayNotifyTask(PayNotifyTypeEnum.ORDER.getType(), |
| 285 | + orderExtension.getOrderId()); | ||
| 287 | } | 286 | } |
| 288 | 287 | ||
| 289 | /** | 288 | /** |
yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/service/refund/PayRefundServiceImpl.java
| @@ -26,7 +26,6 @@ import cn.iocoder.yudao.module.pay.framework.pay.config.PayProperties; | @@ -26,7 +26,6 @@ import cn.iocoder.yudao.module.pay.framework.pay.config.PayProperties; | ||
| 26 | import cn.iocoder.yudao.module.pay.service.app.PayAppService; | 26 | import cn.iocoder.yudao.module.pay.service.app.PayAppService; |
| 27 | import cn.iocoder.yudao.module.pay.service.channel.PayChannelService; | 27 | import cn.iocoder.yudao.module.pay.service.channel.PayChannelService; |
| 28 | import cn.iocoder.yudao.module.pay.service.notify.PayNotifyService; | 28 | import cn.iocoder.yudao.module.pay.service.notify.PayNotifyService; |
| 29 | -import cn.iocoder.yudao.module.pay.service.notify.dto.PayNotifyTaskCreateReqDTO; | ||
| 30 | import cn.iocoder.yudao.module.pay.service.order.PayOrderService; | 29 | import cn.iocoder.yudao.module.pay.service.order.PayOrderService; |
| 31 | import lombok.extern.slf4j.Slf4j; | 30 | import lombok.extern.slf4j.Slf4j; |
| 32 | import org.springframework.stereotype.Service; | 31 | import org.springframework.stereotype.Service; |
| @@ -242,8 +241,8 @@ public class PayRefundServiceImpl implements PayRefundService { | @@ -242,8 +241,8 @@ public class PayRefundServiceImpl implements PayRefundService { | ||
| 242 | orderService.updateOrderRefundPrice(refund.getOrderId(), refund.getRefundPrice()); | 241 | orderService.updateOrderRefundPrice(refund.getOrderId(), refund.getRefundPrice()); |
| 243 | 242 | ||
| 244 | // 3. 插入退款通知记录 | 243 | // 3. 插入退款通知记录 |
| 245 | - notifyService.createPayNotifyTask(PayNotifyTaskCreateReqDTO.builder() | ||
| 246 | - .type(PayNotifyTypeEnum.REFUND.getType()).dataId(refund.getId()).build()); | 244 | + notifyService.createPayNotifyTask(PayNotifyTypeEnum.REFUND.getType(), |
| 245 | + refund.getId()); | ||
| 247 | } | 246 | } |
| 248 | 247 | ||
| 249 | private void notifyRefundFailure(PayChannelDO channel, PayRefundRespDTO notify) { | 248 | private void notifyRefundFailure(PayChannelDO channel, PayRefundRespDTO notify) { |
| @@ -273,8 +272,8 @@ public class PayRefundServiceImpl implements PayRefundService { | @@ -273,8 +272,8 @@ public class PayRefundServiceImpl implements PayRefundService { | ||
| 273 | log.info("[notifyRefundFailure][退款订单({}) 更新为退款失败]", refund.getId()); | 272 | log.info("[notifyRefundFailure][退款订单({}) 更新为退款失败]", refund.getId()); |
| 274 | 273 | ||
| 275 | // 2. 插入退款通知记录 | 274 | // 2. 插入退款通知记录 |
| 276 | - notifyService.createPayNotifyTask(PayNotifyTaskCreateReqDTO.builder() | ||
| 277 | - .type(PayNotifyTypeEnum.REFUND.getType()).dataId(refund.getId()).build()); | 275 | + notifyService.createPayNotifyTask(PayNotifyTypeEnum.REFUND.getType(), |
| 276 | + refund.getId()); | ||
| 278 | } | 277 | } |
| 279 | 278 | ||
| 280 | @Override | 279 | @Override |
yudao-module-pay/yudao-module-pay-biz/src/test/java/cn/iocoder/yudao/module/pay/service/notify/PayNotifyServiceTest.java
0 → 100644
| 1 | +package cn.iocoder.yudao.module.pay.service.notify; | ||
| 2 | + | ||
| 3 | +import cn.hutool.extra.spring.SpringUtil; | ||
| 4 | +import cn.iocoder.yudao.framework.test.core.ut.BaseDbUnitTest; | ||
| 5 | +import cn.iocoder.yudao.module.pay.dal.dataobject.notify.PayNotifyTaskDO; | ||
| 6 | +import cn.iocoder.yudao.module.pay.dal.dataobject.order.PayOrderDO; | ||
| 7 | +import cn.iocoder.yudao.module.pay.dal.dataobject.refund.PayRefundDO; | ||
| 8 | +import cn.iocoder.yudao.module.pay.dal.mysql.notify.PayNotifyLogMapper; | ||
| 9 | +import cn.iocoder.yudao.module.pay.dal.mysql.notify.PayNotifyTaskMapper; | ||
| 10 | +import cn.iocoder.yudao.module.pay.dal.redis.notify.PayNotifyLockRedisDAO; | ||
| 11 | +import cn.iocoder.yudao.module.pay.enums.notify.PayNotifyStatusEnum; | ||
| 12 | +import cn.iocoder.yudao.module.pay.enums.notify.PayNotifyTypeEnum; | ||
| 13 | +import cn.iocoder.yudao.module.pay.framework.job.config.PayJobConfiguration; | ||
| 14 | +import cn.iocoder.yudao.module.pay.service.order.PayOrderService; | ||
| 15 | +import cn.iocoder.yudao.module.pay.service.refund.PayRefundService; | ||
| 16 | +import cn.iocoder.yudao.module.pay.service.refund.PayRefundServiceImpl; | ||
| 17 | +import org.junit.jupiter.api.Test; | ||
| 18 | +import org.mockito.MockedStatic; | ||
| 19 | +import org.redisson.api.RLock; | ||
| 20 | +import org.redisson.api.RedissonClient; | ||
| 21 | +import org.springframework.boot.test.mock.mockito.MockBean; | ||
| 22 | +import org.springframework.context.annotation.Import; | ||
| 23 | +import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor; | ||
| 24 | + | ||
| 25 | +import javax.annotation.Resource; | ||
| 26 | + | ||
| 27 | +import java.time.Duration; | ||
| 28 | + | ||
| 29 | +import static cn.iocoder.yudao.framework.common.util.date.LocalDateTimeUtils.addTime; | ||
| 30 | +import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.randomPojo; | ||
| 31 | +import static org.assertj.core.api.Assertions.assertThat; | ||
| 32 | +import static org.junit.jupiter.api.Assertions.*; | ||
| 33 | +import static org.mockito.ArgumentMatchers.anyString; | ||
| 34 | +import static org.mockito.ArgumentMatchers.eq; | ||
| 35 | +import static org.mockito.Mockito.*; | ||
| 36 | + | ||
| 37 | +/** | ||
| 38 | + * {@link PayRefundServiceImpl} 的单元测试类 | ||
| 39 | + * | ||
| 40 | + * @author 芋艿 | ||
| 41 | + */ | ||
| 42 | +@Import({PayJobConfiguration.class, PayNotifyServiceImpl.class, PayNotifyLockRedisDAO.class}) | ||
| 43 | +public class PayNotifyServiceTest extends BaseDbUnitTest { | ||
| 44 | + | ||
| 45 | + @Resource | ||
| 46 | + private PayNotifyServiceImpl notifyService; | ||
| 47 | + | ||
| 48 | + @MockBean | ||
| 49 | + private PayOrderService orderService; | ||
| 50 | + @MockBean | ||
| 51 | + private PayRefundService refundService; | ||
| 52 | + | ||
| 53 | + @Resource | ||
| 54 | + private PayNotifyTaskMapper notifyTaskMapper; | ||
| 55 | + @Resource | ||
| 56 | + private PayNotifyLogMapper notifyLogMapper; | ||
| 57 | + | ||
| 58 | + @MockBean | ||
| 59 | + private RedissonClient redissonClient; | ||
| 60 | + | ||
| 61 | + @Test | ||
| 62 | + public void testCreatePayNotifyTask_order() { | ||
| 63 | + PayNotifyServiceImpl payNotifyService = mock(PayNotifyServiceImpl.class); | ||
| 64 | + try (MockedStatic<SpringUtil> springUtilMockedStatic = mockStatic(SpringUtil.class)) { | ||
| 65 | + springUtilMockedStatic.when(() -> SpringUtil.getBean(eq(PayNotifyServiceImpl.class))) | ||
| 66 | + .thenReturn(payNotifyService); | ||
| 67 | + | ||
| 68 | + // 准备参数 | ||
| 69 | + Integer type = PayNotifyTypeEnum.ORDER.getType(); | ||
| 70 | + Long dataId = 1L; | ||
| 71 | + // mock 方法(order) | ||
| 72 | + PayOrderDO order = randomPojo(PayOrderDO.class); | ||
| 73 | + when(orderService.getOrder(eq(1L))).thenReturn(order); | ||
| 74 | + // mock 方法(lock) | ||
| 75 | + mockLock(null); // null 的原因,是咱没办法拿到 taskId 新增 | ||
| 76 | + | ||
| 77 | + // 调用 | ||
| 78 | + notifyService.createPayNotifyTask(type, dataId); | ||
| 79 | + // 断言,task | ||
| 80 | + PayNotifyTaskDO dbTask = notifyTaskMapper.selectOne(null); | ||
| 81 | + assertNotNull(dbTask.getNextNotifyTime()); | ||
| 82 | + assertThat(dbTask) | ||
| 83 | + .extracting("type", "dataId", "status", "notifyTimes", "maxNotifyTimes", | ||
| 84 | + "appId", "merchantOrderId", "notifyUrl") | ||
| 85 | + .containsExactly(type, dataId, PayNotifyStatusEnum.WAITING.getStatus(), 0, 9, | ||
| 86 | + order.getAppId(), order.getMerchantOrderId(), order.getNotifyUrl()); | ||
| 87 | + // 断言,调用 | ||
| 88 | + verify(payNotifyService).executeNotify0(eq(dbTask)); | ||
| 89 | + } | ||
| 90 | + } | ||
| 91 | + | ||
| 92 | + @Test | ||
| 93 | + public void testCreatePayNotifyTask_refund() { | ||
| 94 | + PayNotifyServiceImpl payNotifyService = mock(PayNotifyServiceImpl.class); | ||
| 95 | + try (MockedStatic<SpringUtil> springUtilMockedStatic = mockStatic(SpringUtil.class)) { | ||
| 96 | + springUtilMockedStatic.when(() -> SpringUtil.getBean(eq(PayNotifyServiceImpl.class))) | ||
| 97 | + .thenReturn(payNotifyService); | ||
| 98 | + | ||
| 99 | + // 准备参数 | ||
| 100 | + Integer type = PayNotifyTypeEnum.REFUND.getType(); | ||
| 101 | + Long dataId = 1L; | ||
| 102 | + // mock 方法(refund) | ||
| 103 | + PayRefundDO refund = randomPojo(PayRefundDO.class); | ||
| 104 | + when(refundService.getRefund(eq(1L))).thenReturn(refund); | ||
| 105 | + // mock 方法(lock) | ||
| 106 | + mockLock(null); // null 的原因,是咱没办法拿到 taskId 新增 | ||
| 107 | + | ||
| 108 | + // 调用 | ||
| 109 | + notifyService.createPayNotifyTask(type, dataId); | ||
| 110 | + // 断言,task | ||
| 111 | + PayNotifyTaskDO dbTask = notifyTaskMapper.selectOne(null); | ||
| 112 | + assertNotNull(dbTask.getNextNotifyTime()); | ||
| 113 | + assertThat(dbTask) | ||
| 114 | + .extracting("type", "dataId", "status", "notifyTimes", "maxNotifyTimes", | ||
| 115 | + "appId", "merchantOrderId", "notifyUrl") | ||
| 116 | + .containsExactly(type, dataId, PayNotifyStatusEnum.WAITING.getStatus(), 0, 9, | ||
| 117 | + refund.getAppId(), refund.getMerchantOrderId(), refund.getNotifyUrl()); | ||
| 118 | + // 断言,调用 | ||
| 119 | + verify(payNotifyService).executeNotify0(eq(dbTask)); | ||
| 120 | + } | ||
| 121 | + } | ||
| 122 | + | ||
| 123 | + @Test | ||
| 124 | + public void testExecuteNotify() throws InterruptedException { | ||
| 125 | + // mock 数据(notify) | ||
| 126 | + PayNotifyTaskDO dbTask01 = randomPojo(PayNotifyTaskDO.class, | ||
| 127 | + o -> o.setStatus(PayNotifyStatusEnum.WAITING.getStatus()) | ||
| 128 | + .setNextNotifyTime(addTime(Duration.ofMinutes(-1)))); | ||
| 129 | + notifyTaskMapper.insert(dbTask01); | ||
| 130 | + PayNotifyTaskDO dbTask02 = randomPojo(PayNotifyTaskDO.class, | ||
| 131 | + o -> o.setStatus(PayNotifyStatusEnum.REQUEST_SUCCESS.getStatus()) | ||
| 132 | + .setNextNotifyTime(addTime(Duration.ofMinutes(-1)))); | ||
| 133 | + notifyTaskMapper.insert(dbTask02); | ||
| 134 | + PayNotifyTaskDO dbTask03 = randomPojo(PayNotifyTaskDO.class, | ||
| 135 | + o -> o.setStatus(PayNotifyStatusEnum.REQUEST_FAILURE.getStatus()) | ||
| 136 | + .setNextNotifyTime(addTime(Duration.ofMinutes(-1)))); | ||
| 137 | + notifyTaskMapper.insert(dbTask03); | ||
| 138 | + PayNotifyTaskDO dbTask04 = randomPojo(PayNotifyTaskDO.class, // 不满足状态 | ||
| 139 | + o -> o.setStatus(PayNotifyStatusEnum.FAILURE.getStatus()) | ||
| 140 | + .setNextNotifyTime(addTime(Duration.ofMinutes(-1)))); | ||
| 141 | + notifyTaskMapper.insert(dbTask04); | ||
| 142 | + PayNotifyTaskDO dbTask05 = randomPojo(PayNotifyTaskDO.class, // 不满足状态 | ||
| 143 | + o -> o.setStatus(PayNotifyStatusEnum.SUCCESS.getStatus()) | ||
| 144 | + .setNextNotifyTime(addTime(Duration.ofMinutes(-1)))); | ||
| 145 | + notifyTaskMapper.insert(dbTask05); | ||
| 146 | + PayNotifyTaskDO dbTask06 = randomPojo(PayNotifyTaskDO.class, // 不满足时间 | ||
| 147 | + o -> o.setStatus(PayNotifyStatusEnum.SUCCESS.getStatus()) | ||
| 148 | + .setNextNotifyTime(addTime(Duration.ofMinutes(1)))); | ||
| 149 | + notifyTaskMapper.insert(dbTask06); | ||
| 150 | + // mock 方法(lock) | ||
| 151 | + mockLock(dbTask01.getId()); | ||
| 152 | + mockLock(dbTask02.getId()); | ||
| 153 | + mockLock(dbTask03.getId()); | ||
| 154 | + | ||
| 155 | + // 调用 | ||
| 156 | + int count = notifyService.executeNotify(); | ||
| 157 | + // 断言,数量 | ||
| 158 | + assertEquals(count, 3); | ||
| 159 | + } | ||
| 160 | + | ||
| 161 | + @Test // 由于 HttpUtil 不好 mock,所以只测试异常的情况 | ||
| 162 | + public void testExecuteNotify0_exception() { | ||
| 163 | + // mock 数据(task) | ||
| 164 | + PayNotifyTaskDO task = randomPojo(PayNotifyTaskDO.class, o -> o.setType(-1) | ||
| 165 | + .setNotifyTimes(0).setMaxNotifyTimes(9)); | ||
| 166 | + notifyTaskMapper.insert(task); | ||
| 167 | + | ||
| 168 | + // 调用 | ||
| 169 | + notifyService.executeNotify0(task); | ||
| 170 | + | ||
| 171 | + } | ||
| 172 | + | ||
| 173 | + private void mockLock(Long id) { | ||
| 174 | + RLock lock = mock(RLock.class); | ||
| 175 | + if (id == null) { | ||
| 176 | + when(redissonClient.getLock(anyString())) | ||
| 177 | + .thenReturn(lock); | ||
| 178 | + } else { | ||
| 179 | + when(redissonClient.getLock(eq("pay_notify:lock:" + id))) | ||
| 180 | + .thenReturn(lock); | ||
| 181 | + } | ||
| 182 | + } | ||
| 183 | + | ||
| 184 | +} |
yudao-module-pay/yudao-module-pay-biz/src/test/java/cn/iocoder/yudao/module/pay/service/order/PayOrderServiceTest.java
| @@ -27,7 +27,6 @@ import cn.iocoder.yudao.module.pay.framework.pay.config.PayProperties; | @@ -27,7 +27,6 @@ import cn.iocoder.yudao.module.pay.framework.pay.config.PayProperties; | ||
| 27 | import cn.iocoder.yudao.module.pay.service.app.PayAppService; | 27 | import cn.iocoder.yudao.module.pay.service.app.PayAppService; |
| 28 | import cn.iocoder.yudao.module.pay.service.channel.PayChannelService; | 28 | import cn.iocoder.yudao.module.pay.service.channel.PayChannelService; |
| 29 | import cn.iocoder.yudao.module.pay.service.notify.PayNotifyService; | 29 | import cn.iocoder.yudao.module.pay.service.notify.PayNotifyService; |
| 30 | -import cn.iocoder.yudao.module.pay.service.notify.dto.PayNotifyTaskCreateReqDTO; | ||
| 31 | import org.junit.jupiter.api.BeforeEach; | 30 | import org.junit.jupiter.api.BeforeEach; |
| 32 | import org.junit.jupiter.api.Test; | 31 | import org.junit.jupiter.api.Test; |
| 33 | import org.mockito.MockedStatic; | 32 | import org.mockito.MockedStatic; |
| @@ -622,7 +621,7 @@ public class PayOrderServiceTest extends BaseDbAndRedisUnitTest { | @@ -622,7 +621,7 @@ public class PayOrderServiceTest extends BaseDbAndRedisUnitTest { | ||
| 622 | // 断言 PayOrderDO :数据未更新,因为它是 SUCCESS | 621 | // 断言 PayOrderDO :数据未更新,因为它是 SUCCESS |
| 623 | assertPojoEquals(order, orderMapper.selectOne(null)); | 622 | assertPojoEquals(order, orderMapper.selectOne(null)); |
| 624 | // 断言,调用 | 623 | // 断言,调用 |
| 625 | - verify(notifyService, never()).createPayNotifyTask(any(PayNotifyTaskCreateReqDTO.class)); | 624 | + verify(notifyService, never()).createPayNotifyTask(anyInt(), anyLong()); |
| 626 | } | 625 | } |
| 627 | 626 | ||
| 628 | @Test | 627 | @Test |
| @@ -661,11 +660,8 @@ public class PayOrderServiceTest extends BaseDbAndRedisUnitTest { | @@ -661,11 +660,8 @@ public class PayOrderServiceTest extends BaseDbAndRedisUnitTest { | ||
| 661 | assertPojoEquals(order, orderMapper.selectOne(null), | 660 | assertPojoEquals(order, orderMapper.selectOne(null), |
| 662 | "updateTime", "updater"); | 661 | "updateTime", "updater"); |
| 663 | // 断言,调用 | 662 | // 断言,调用 |
| 664 | - verify(notifyService).createPayNotifyTask(argThat(reqDTO -> { | ||
| 665 | - assertEquals(reqDTO.getType(), PayNotifyTypeEnum.ORDER.getType()); | ||
| 666 | - assertEquals(reqDTO.getDataId(), orderExtension.getOrderId()); | ||
| 667 | - return true; | ||
| 668 | - })); | 663 | + verify(notifyService).createPayNotifyTask(eq(PayNotifyTypeEnum.ORDER.getType()), |
| 664 | + eq(orderExtension.getOrderId())); | ||
| 669 | } | 665 | } |
| 670 | 666 | ||
| 671 | @Test | 667 | @Test |
yudao-module-pay/yudao-module-pay-biz/src/test/java/cn/iocoder/yudao/module/pay/service/refund/PayRefundServiceTest.java
| @@ -25,7 +25,6 @@ import cn.iocoder.yudao.module.pay.framework.pay.config.PayProperties; | @@ -25,7 +25,6 @@ import cn.iocoder.yudao.module.pay.framework.pay.config.PayProperties; | ||
| 25 | import cn.iocoder.yudao.module.pay.service.app.PayAppService; | 25 | import cn.iocoder.yudao.module.pay.service.app.PayAppService; |
| 26 | import cn.iocoder.yudao.module.pay.service.channel.PayChannelService; | 26 | import cn.iocoder.yudao.module.pay.service.channel.PayChannelService; |
| 27 | import cn.iocoder.yudao.module.pay.service.notify.PayNotifyService; | 27 | import cn.iocoder.yudao.module.pay.service.notify.PayNotifyService; |
| 28 | -import cn.iocoder.yudao.module.pay.service.notify.dto.PayNotifyTaskCreateReqDTO; | ||
| 29 | import cn.iocoder.yudao.module.pay.service.order.PayOrderService; | 28 | import cn.iocoder.yudao.module.pay.service.order.PayOrderService; |
| 30 | import org.junit.jupiter.api.BeforeEach; | 29 | import org.junit.jupiter.api.BeforeEach; |
| 31 | import org.junit.jupiter.api.Test; | 30 | import org.junit.jupiter.api.Test; |
| @@ -552,8 +551,8 @@ public class PayRefundServiceTest extends BaseDbAndRedisUnitTest { | @@ -552,8 +551,8 @@ public class PayRefundServiceTest extends BaseDbAndRedisUnitTest { | ||
| 552 | "updateTime", "updater"); | 551 | "updateTime", "updater"); |
| 553 | // 断言,调用 | 552 | // 断言,调用 |
| 554 | verify(orderService).updateOrderRefundPrice(eq(100L), eq(23)); | 553 | verify(orderService).updateOrderRefundPrice(eq(100L), eq(23)); |
| 555 | - verify(notifyService).createPayNotifyTask(eq(PayNotifyTaskCreateReqDTO.builder() | ||
| 556 | - .type(PayNotifyTypeEnum.REFUND.getType()).dataId(refund.getId()).build())); | 554 | + verify(notifyService).createPayNotifyTask(eq(PayNotifyTypeEnum.REFUND.getType()), |
| 555 | + eq(refund.getId())); | ||
| 557 | } | 556 | } |
| 558 | 557 | ||
| 559 | @Test | 558 | @Test |
| @@ -624,8 +623,8 @@ public class PayRefundServiceTest extends BaseDbAndRedisUnitTest { | @@ -624,8 +623,8 @@ public class PayRefundServiceTest extends BaseDbAndRedisUnitTest { | ||
| 624 | assertPojoEquals(refund, refundMapper.selectById(refund.getId()), | 623 | assertPojoEquals(refund, refundMapper.selectById(refund.getId()), |
| 625 | "updateTime", "updater"); | 624 | "updateTime", "updater"); |
| 626 | // 断言,调用 | 625 | // 断言,调用 |
| 627 | - verify(notifyService).createPayNotifyTask(eq(PayNotifyTaskCreateReqDTO.builder() | ||
| 628 | - .type(PayNotifyTypeEnum.REFUND.getType()).dataId(refund.getId()).build())); | 626 | + verify(notifyService).createPayNotifyTask(eq(PayNotifyTypeEnum.REFUND.getType()), |
| 627 | + eq(refund.getId())); | ||
| 629 | } | 628 | } |
| 630 | 629 | ||
| 631 | @Test | 630 | @Test |
yudao-module-pay/yudao-module-pay-biz/src/test/resources/sql/clean.sql
| @@ -3,3 +3,4 @@ DELETE FROM pay_channel; | @@ -3,3 +3,4 @@ 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; | ||
| 6 | \ No newline at end of file | 7 | \ No newline at end of file |
yudao-module-pay/yudao-module-pay-biz/src/test/resources/sql/create_tables.sql
| @@ -109,3 +109,24 @@ CREATE TABLE IF NOT EXISTS `pay_refund` ( | @@ -109,3 +109,24 @@ CREATE TABLE IF NOT EXISTS `pay_refund` ( | ||
| 109 | `deleted` bit(1) NOT NULL DEFAULT FALSE, | 109 | `deleted` bit(1) NOT NULL DEFAULT FALSE, |
| 110 | PRIMARY KEY ("id") | 110 | PRIMARY KEY ("id") |
| 111 | ) COMMENT = '退款订单'; | 111 | ) COMMENT = '退款订单'; |
| 112 | + | ||
| 113 | +CREATE TABLE IF NOT EXISTS `pay_notify_task` ( | ||
| 114 | + "id" number NOT NULL GENERATED BY DEFAULT AS IDENTITY, | ||
| 115 | + `app_id` bigint(20) NOT NULL, | ||
| 116 | + `type` tinyint(4) NOT NULL, | ||
| 117 | + `data_id` bigint(20) NOT NULL, | ||
| 118 | + `merchant_order_id` varchar(64) NOT NULL, | ||
| 119 | + `status` tinyint(4) NOT NULL, | ||
| 120 | + `next_notify_time` datetime(0) NULL DEFAULT NULL, | ||
| 121 | + `last_execute_time` datetime(0) NULL DEFAULT NULL, | ||
| 122 | + `notify_times` int NOT NULL, | ||
| 123 | + `max_notify_times` int NOT NULL, | ||
| 124 | + `notify_url` varchar(1024) NOT NULL, | ||
| 125 | + `creator` varchar(64) NULL DEFAULT '', | ||
| 126 | + `create_time` datetime(0) NOT NULL DEFAULT CURRENT_TIMESTAMP, | ||
| 127 | + `updater` varchar(64) NULL DEFAULT '', | ||
| 128 | + `update_time` datetime(0) NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, | ||
| 129 | + `deleted` bit(1) NOT NULL DEFAULT FALSE, | ||
| 130 | + `tenant_id` bigint(20) NOT NULL DEFAULT 0, | ||
| 131 | + PRIMARY KEY ("id") | ||
| 132 | +) COMMENT = '支付通知'; |