Commit 7c165fb1f6f2602b1929648b87fb40e1f61357e0
1 parent
3a1694de
1. 完善 PayNotifyServiceImpl 的单元测试
Showing
5 changed files
with
193 additions
and
9 deletions
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 = '支付通知日志'; |