|
@@ -17,6 +17,7 @@ import com.payment.platform.module.payment.leshouying.enums.LsyRefundStatus;
|
|
|
import com.payment.platform.module.payment.leshouying.mapper.LsyOrderMapper;
|
|
import com.payment.platform.module.payment.leshouying.mapper.LsyOrderMapper;
|
|
|
import com.payment.platform.module.payment.leshouying.mapper.LsyRefundMapper;
|
|
import com.payment.platform.module.payment.leshouying.mapper.LsyRefundMapper;
|
|
|
import com.payment.platform.module.payment.leshouying.service.*;
|
|
import com.payment.platform.module.payment.leshouying.service.*;
|
|
|
|
|
+import com.payment.platform.module.payment.stream.OrderEventPublisher;
|
|
|
import org.apache.ibatis.builder.MapperBuilderAssistant;
|
|
import org.apache.ibatis.builder.MapperBuilderAssistant;
|
|
|
import org.junit.jupiter.api.BeforeEach;
|
|
import org.junit.jupiter.api.BeforeEach;
|
|
|
import org.junit.jupiter.api.Test;
|
|
import org.junit.jupiter.api.Test;
|
|
@@ -55,6 +56,10 @@ class LsySchedulerTest {
|
|
|
@Mock private LsyCallbackService callbackService;
|
|
@Mock private LsyCallbackService callbackService;
|
|
|
@Mock private LsyOrderService orderService;
|
|
@Mock private LsyOrderService orderService;
|
|
|
@Mock private LsyRefundService refundService;
|
|
@Mock private LsyRefundService refundService;
|
|
|
|
|
+ @Mock private OrderEventPublisher publisher;
|
|
|
|
|
+
|
|
|
|
|
+ /** 行上的租户 —— 信号按它分桶(只发给该租户的连接 + 超管那条)。 */
|
|
|
|
|
+ private static final Long TENANT = 7L;
|
|
|
|
|
|
|
|
private LeshouyingProperties props;
|
|
private LeshouyingProperties props;
|
|
|
|
|
|
|
@@ -82,6 +87,8 @@ class LsySchedulerTest {
|
|
|
o.setStatus("PAYING");
|
|
o.setStatus("PAYING");
|
|
|
o.setQueryCount(queryCount);
|
|
o.setQueryCount(queryCount);
|
|
|
o.setMchNo("Y52211090004");
|
|
o.setMchNo("Y52211090004");
|
|
|
|
|
+ // 租户:发布断言要钉的就是这个值(真实行必然带它,hand-built 夹具得自己补)
|
|
|
|
|
+ o.setTenantId(TENANT);
|
|
|
return o;
|
|
return o;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
@@ -103,7 +110,8 @@ class LsySchedulerTest {
|
|
|
when(orderService.settleFromQuery(eq(o2), any())).thenReturn("SUCCESS");
|
|
when(orderService.settleFromQuery(eq(o2), any())).thenReturn("SUCCESS");
|
|
|
|
|
|
|
|
LsyOrderPollScheduler scheduler = new LsyOrderPollScheduler(
|
|
LsyOrderPollScheduler scheduler = new LsyOrderPollScheduler(
|
|
|
- orderMapper, queryService, cancelService, callbackService, orderService, props);
|
|
|
|
|
|
|
+ orderMapper, queryService, cancelService, callbackService,
|
|
|
|
|
+ orderService, props, publisher);
|
|
|
|
|
|
|
|
assertDoesNotThrow(scheduler::pollBarcodeOrders);
|
|
assertDoesNotThrow(scheduler::pollBarcodeOrders);
|
|
|
verify(queryService).queryOrder(o2);
|
|
verify(queryService).queryOrder(o2);
|
|
@@ -117,7 +125,7 @@ class LsySchedulerTest {
|
|
|
when(orderService.settleFromQuery(eq(o), any())).thenReturn("SUCCESS");
|
|
when(orderService.settleFromQuery(eq(o), any())).thenReturn("SUCCESS");
|
|
|
|
|
|
|
|
new LsyOrderPollScheduler(orderMapper, queryService, cancelService,
|
|
new LsyOrderPollScheduler(orderMapper, queryService, cancelService,
|
|
|
- callbackService, orderService, props)
|
|
|
|
|
|
|
+ callbackService, orderService, props, publisher)
|
|
|
.pollBarcodeOrders();
|
|
.pollBarcodeOrders();
|
|
|
|
|
|
|
|
verify(callbackService).notifyOrder(o);
|
|
verify(callbackService).notifyOrder(o);
|
|
@@ -131,7 +139,7 @@ class LsySchedulerTest {
|
|
|
when(orderService.settleFromQuery(eq(o), any())).thenReturn(null); // 未流转
|
|
when(orderService.settleFromQuery(eq(o), any())).thenReturn(null); // 未流转
|
|
|
|
|
|
|
|
new LsyOrderPollScheduler(orderMapper, queryService, cancelService,
|
|
new LsyOrderPollScheduler(orderMapper, queryService, cancelService,
|
|
|
- callbackService, orderService, props)
|
|
|
|
|
|
|
+ callbackService, orderService, props, publisher)
|
|
|
.pollBarcodeOrders();
|
|
.pollBarcodeOrders();
|
|
|
|
|
|
|
|
verify(callbackService, never()).notifyOrder(any());
|
|
verify(callbackService, never()).notifyOrder(any());
|
|
@@ -160,7 +168,7 @@ class LsySchedulerTest {
|
|
|
when(orderMapper.update(any(), any())).thenReturn(1); // 条件更新命中 1 行
|
|
when(orderMapper.update(any(), any())).thenReturn(1); // 条件更新命中 1 行
|
|
|
|
|
|
|
|
new LsyOrderPollScheduler(orderMapper, queryService, cancelService,
|
|
new LsyOrderPollScheduler(orderMapper, queryService, cancelService,
|
|
|
- callbackService, orderService, props)
|
|
|
|
|
|
|
+ callbackService, orderService, props, publisher)
|
|
|
.pollBarcodeOrders();
|
|
.pollBarcodeOrders();
|
|
|
|
|
|
|
|
var captor = org.mockito.ArgumentCaptor.forClass(UpdateWrapper.class);
|
|
var captor = org.mockito.ArgumentCaptor.forClass(UpdateWrapper.class);
|
|
@@ -171,6 +179,8 @@ class LsySchedulerTest {
|
|
|
verify(orderMapper, never()).updateById(any());
|
|
verify(orderMapper, never()).updateById(any());
|
|
|
verify(cancelService).closeOrder(o);
|
|
verify(cancelService).closeOrder(o);
|
|
|
verify(callbackService).notifyOrder(o);
|
|
verify(callbackService).notifyOrder(o);
|
|
|
|
|
+ // 真的改了这一行才发信号(命中 1 行)
|
|
|
|
|
+ verify(publisher).changed(OrderEventPublisher.CHANNEL_LSY_ORDER, TENANT);
|
|
|
assertEquals("CANCELED", o.getStatus());
|
|
assertEquals("CANCELED", o.getStatus());
|
|
|
}
|
|
}
|
|
|
|
|
|
|
@@ -192,7 +202,7 @@ class LsySchedulerTest {
|
|
|
when(orderMapper.update(any(), any())).thenReturn(0); // 往返期间已被回调写成终态
|
|
when(orderMapper.update(any(), any())).thenReturn(0); // 往返期间已被回调写成终态
|
|
|
|
|
|
|
|
new LsyOrderPollScheduler(orderMapper, queryService, cancelService,
|
|
new LsyOrderPollScheduler(orderMapper, queryService, cancelService,
|
|
|
- callbackService, orderService, props)
|
|
|
|
|
|
|
+ callbackService, orderService, props, publisher)
|
|
|
.pollBarcodeOrders();
|
|
.pollBarcodeOrders();
|
|
|
|
|
|
|
|
var captor = org.mockito.ArgumentCaptor.forClass(UpdateWrapper.class);
|
|
var captor = org.mockito.ArgumentCaptor.forClass(UpdateWrapper.class);
|
|
@@ -203,6 +213,7 @@ class LsySchedulerTest {
|
|
|
|
|
|
|
|
verify(orderMapper, never()).updateById(any());
|
|
verify(orderMapper, never()).updateById(any());
|
|
|
verify(callbackService, never()).notifyOrder(any());
|
|
verify(callbackService, never()).notifyOrder(any());
|
|
|
|
|
+ verifyNoInteractions(publisher); // 一行都没改,发了就是让页面白拉
|
|
|
assertEquals("PAYING", o.getStatus(), "0 行时内存对象也不得被改写成 CANCELED");
|
|
assertEquals("PAYING", o.getStatus(), "0 行时内存对象也不得被改写成 CANCELED");
|
|
|
}
|
|
}
|
|
|
|
|
|
|
@@ -219,7 +230,7 @@ class LsySchedulerTest {
|
|
|
when(orderMapper.selectById(1L)).thenReturn(won);
|
|
when(orderMapper.selectById(1L)).thenReturn(won);
|
|
|
|
|
|
|
|
new LsyOrderPollScheduler(orderMapper, queryService, cancelService,
|
|
new LsyOrderPollScheduler(orderMapper, queryService, cancelService,
|
|
|
- callbackService, orderService, props)
|
|
|
|
|
|
|
+ callbackService, orderService, props, publisher)
|
|
|
.pollBarcodeOrders();
|
|
.pollBarcodeOrders();
|
|
|
|
|
|
|
|
verify(cancelService, never()).closeOrder(any());
|
|
verify(cancelService, never()).closeOrder(any());
|
|
@@ -231,7 +242,8 @@ class LsySchedulerTest {
|
|
|
when(orderMapper.selectList(any())).thenReturn(List.of());
|
|
when(orderMapper.selectList(any())).thenReturn(List.of());
|
|
|
|
|
|
|
|
LsyOrderPollScheduler scheduler = new LsyOrderPollScheduler(
|
|
LsyOrderPollScheduler scheduler = new LsyOrderPollScheduler(
|
|
|
- orderMapper, queryService, cancelService, callbackService, orderService, props);
|
|
|
|
|
|
|
+ orderMapper, queryService, cancelService, callbackService,
|
|
|
|
|
+ orderService, props, publisher);
|
|
|
scheduler.pollBarcodeOrders();
|
|
scheduler.pollBarcodeOrders();
|
|
|
|
|
|
|
|
verify(queryService, never()).queryOrder(any());
|
|
verify(queryService, never()).queryOrder(any());
|
|
@@ -246,7 +258,7 @@ class LsySchedulerTest {
|
|
|
|
|
|
|
|
LsyReconcileScheduler scheduler = new LsyReconcileScheduler(
|
|
LsyReconcileScheduler scheduler = new LsyReconcileScheduler(
|
|
|
orderMapper, refundMapper, queryService, cancelService, callbackService,
|
|
orderMapper, refundMapper, queryService, cancelService, callbackService,
|
|
|
- orderService, refundService, props);
|
|
|
|
|
|
|
+ orderService, refundService, props, publisher);
|
|
|
|
|
|
|
|
assertDoesNotThrow(() -> scheduler.applyCloseResult(o));
|
|
assertDoesNotThrow(() -> scheduler.applyCloseResult(o));
|
|
|
verify(orderMapper, never()).updateById(any());
|
|
verify(orderMapper, never()).updateById(any());
|
|
@@ -262,7 +274,7 @@ class LsySchedulerTest {
|
|
|
|
|
|
|
|
LsyReconcileScheduler scheduler = new LsyReconcileScheduler(
|
|
LsyReconcileScheduler scheduler = new LsyReconcileScheduler(
|
|
|
orderMapper, refundMapper, queryService, cancelService, callbackService,
|
|
orderMapper, refundMapper, queryService, cancelService, callbackService,
|
|
|
- orderService, refundService, props);
|
|
|
|
|
|
|
+ orderService, refundService, props, publisher);
|
|
|
scheduler.reconcilePendingOrders();
|
|
scheduler.reconcilePendingOrders();
|
|
|
|
|
|
|
|
verify(callbackService).notifyOrder(o);
|
|
verify(callbackService).notifyOrder(o);
|
|
@@ -295,7 +307,7 @@ class LsySchedulerTest {
|
|
|
|
|
|
|
|
LsyReconcileScheduler scheduler = new LsyReconcileScheduler(
|
|
LsyReconcileScheduler scheduler = new LsyReconcileScheduler(
|
|
|
orderMapper, refundMapper, queryService, cancelService, callbackService,
|
|
orderMapper, refundMapper, queryService, cancelService, callbackService,
|
|
|
- orderService, refundService, props);
|
|
|
|
|
|
|
+ orderService, refundService, props, publisher);
|
|
|
assertDoesNotThrow(scheduler::expireStaleOrders);
|
|
assertDoesNotThrow(scheduler::expireStaleOrders);
|
|
|
|
|
|
|
|
var captor = org.mockito.ArgumentCaptor.forClass(UpdateWrapper.class);
|
|
var captor = org.mockito.ArgumentCaptor.forClass(UpdateWrapper.class);
|
|
@@ -325,6 +337,7 @@ class LsySchedulerTest {
|
|
|
// 守卫不许落在返回值上 ⇒ 这条写入路径不得再出现无条件的 updateById
|
|
// 守卫不许落在返回值上 ⇒ 这条写入路径不得再出现无条件的 updateById
|
|
|
verify(orderMapper, never()).updateById(any());
|
|
verify(orderMapper, never()).updateById(any());
|
|
|
verify(callbackService, never()).notifyOrder(any());
|
|
verify(callbackService, never()).notifyOrder(any());
|
|
|
|
|
+ verifyNoInteractions(publisher); // 0 行 ⇒ 页面没什么可刷的
|
|
|
assertEquals("PAYING", o.getStatus(), "0 行时内存对象也不得被改写成 EXPIRED");
|
|
assertEquals("PAYING", o.getStatus(), "0 行时内存对象也不得被改写成 EXPIRED");
|
|
|
}
|
|
}
|
|
|
|
|
|
|
@@ -345,10 +358,11 @@ class LsySchedulerTest {
|
|
|
when(orderMapper.update(any(), any())).thenReturn(1);
|
|
when(orderMapper.update(any(), any())).thenReturn(1);
|
|
|
|
|
|
|
|
new LsyReconcileScheduler(orderMapper, refundMapper, queryService, cancelService,
|
|
new LsyReconcileScheduler(orderMapper, refundMapper, queryService, cancelService,
|
|
|
- callbackService, orderService, refundService, props)
|
|
|
|
|
|
|
+ callbackService, orderService, refundService, props, publisher)
|
|
|
.expireStaleOrders();
|
|
.expireStaleOrders();
|
|
|
|
|
|
|
|
verify(callbackService).notifyOrder(o);
|
|
verify(callbackService).notifyOrder(o);
|
|
|
|
|
+ verify(publisher).changed(OrderEventPublisher.CHANNEL_LSY_ORDER, TENANT);
|
|
|
assertEquals("EXPIRED", o.getStatus());
|
|
assertEquals("EXPIRED", o.getStatus());
|
|
|
}
|
|
}
|
|
|
|
|
|
|
@@ -372,7 +386,7 @@ class LsySchedulerTest {
|
|
|
when(orderMapper.update(any(), any())).thenReturn(0);
|
|
when(orderMapper.update(any(), any())).thenReturn(0);
|
|
|
|
|
|
|
|
new LsyReconcileScheduler(orderMapper, refundMapper, queryService, cancelService,
|
|
new LsyReconcileScheduler(orderMapper, refundMapper, queryService, cancelService,
|
|
|
- callbackService, orderService, refundService, props).applyCloseResult(o);
|
|
|
|
|
|
|
+ callbackService, orderService, refundService, props, publisher).applyCloseResult(o);
|
|
|
|
|
|
|
|
var captor = org.mockito.ArgumentCaptor.forClass(UpdateWrapper.class);
|
|
var captor = org.mockito.ArgumentCaptor.forClass(UpdateWrapper.class);
|
|
|
verify(orderMapper, atLeastOnce()).update(any(), captor.capture());
|
|
verify(orderMapper, atLeastOnce()).update(any(), captor.capture());
|
|
@@ -385,6 +399,7 @@ class LsySchedulerTest {
|
|
|
|
|
|
|
|
verify(orderMapper, never()).updateById(any());
|
|
verify(orderMapper, never()).updateById(any());
|
|
|
verify(callbackService, never()).notifyOrder(any());
|
|
verify(callbackService, never()).notifyOrder(any());
|
|
|
|
|
+ verifyNoInteractions(publisher); // 0 行 ⇒ 页面没什么可刷的
|
|
|
assertEquals("PAYING", o.getStatus(), "0 行时内存对象也不得被改写成 CLOSED");
|
|
assertEquals("PAYING", o.getStatus(), "0 行时内存对象也不得被改写成 CLOSED");
|
|
|
}
|
|
}
|
|
|
|
|
|
|
@@ -401,10 +416,11 @@ class LsySchedulerTest {
|
|
|
when(orderMapper.update(any(), any())).thenReturn(1);
|
|
when(orderMapper.update(any(), any())).thenReturn(1);
|
|
|
|
|
|
|
|
new LsyReconcileScheduler(orderMapper, refundMapper, queryService, cancelService,
|
|
new LsyReconcileScheduler(orderMapper, refundMapper, queryService, cancelService,
|
|
|
- callbackService, orderService, refundService, props).applyCloseResult(o);
|
|
|
|
|
|
|
+ callbackService, orderService, refundService, props, publisher).applyCloseResult(o);
|
|
|
|
|
|
|
|
assertEquals("CLOSED", o.getStatus());
|
|
assertEquals("CLOSED", o.getStatus());
|
|
|
verify(callbackService).notifyOrder(o);
|
|
verify(callbackService).notifyOrder(o);
|
|
|
|
|
+ verify(publisher).changed(OrderEventPublisher.CHANNEL_LSY_ORDER, TENANT);
|
|
|
verify(orderMapper, never()).updateById(any());
|
|
verify(orderMapper, never()).updateById(any());
|
|
|
}
|
|
}
|
|
|
|
|
|
|
@@ -518,7 +534,7 @@ class LsySchedulerTest {
|
|
|
|
|
|
|
|
private LsyReconcileScheduler scheduler() {
|
|
private LsyReconcileScheduler scheduler() {
|
|
|
return new LsyReconcileScheduler(orderMapper, refundMapper, queryService, cancelService,
|
|
return new LsyReconcileScheduler(orderMapper, refundMapper, queryService, cancelService,
|
|
|
- callbackService, orderService, refundService, props);
|
|
|
|
|
|
|
+ callbackService, orderService, refundService, props, publisher);
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
private LsyRefundEntity pendingRefund() {
|
|
private LsyRefundEntity pendingRefund() {
|