package com.ruoyi.order.service.impl;
|
|
import com.baomidou.mybatisplus.core.MybatisConfiguration;
|
import com.baomidou.mybatisplus.core.metadata.TableInfoHelper;
|
import com.ruoyi.chargingPile.api.feignClient.ChargingGunClient;
|
import com.ruoyi.chargingPile.api.model.TChargingGun;
|
import com.ruoyi.common.core.domain.R;
|
import com.ruoyi.common.redis.service.RedisService;
|
import com.ruoyi.order.api.model.TChargingOrder;
|
import com.ruoyi.order.api.vo.SecurityDetectionVO;
|
import com.ruoyi.order.dto.PreChargeCheck;
|
import com.ruoyi.order.mapper.TChargingOrderMapper;
|
import org.apache.ibatis.builder.MapperBuilderAssistant;
|
import org.junit.jupiter.api.BeforeAll;
|
import org.junit.jupiter.api.BeforeEach;
|
import org.junit.jupiter.api.Test;
|
import org.mockito.ArgumentCaptor;
|
import org.springframework.test.util.ReflectionTestUtils;
|
|
import java.time.LocalDateTime;
|
import java.util.Collections;
|
import java.util.concurrent.TimeUnit;
|
|
import static org.junit.jupiter.api.Assertions.assertEquals;
|
import static org.junit.jupiter.api.Assertions.assertNotNull;
|
import static org.mockito.ArgumentMatchers.any;
|
import static org.mockito.ArgumentMatchers.anyLong;
|
import static org.mockito.ArgumentMatchers.anyString;
|
import static org.mockito.ArgumentMatchers.eq;
|
import static org.mockito.Mockito.doNothing;
|
import static org.mockito.Mockito.mock;
|
import static org.mockito.Mockito.never;
|
import static org.mockito.Mockito.spy;
|
import static org.mockito.Mockito.verify;
|
import static org.mockito.Mockito.when;
|
|
/**
|
* 启动等待链路单测:安全检测上报缓存自愈重建、启动超时订单兜底取消
|
*/
|
class TChargingOrderStartupTimeoutTest {
|
|
private static final Integer GUN_ID = 1967;
|
private static final String ORDER_CODE = "CD3720261014104949469";
|
|
/**
|
* 纯单测无 Spring 容器,MyBatis-Plus 的 lambda 列缓存需手工初始化
|
*/
|
@BeforeAll
|
static void initMybatisPlusTableInfo() {
|
MapperBuilderAssistant assistant = new MapperBuilderAssistant(new MybatisConfiguration(), "");
|
TableInfoHelper.initTableInfo(assistant, TChargingOrder.class);
|
}
|
|
private TChargingOrderServiceImpl service;
|
private TChargingOrderMapper mapper;
|
private RedisService redisService;
|
private ChargingGunClient chargingGunClient;
|
|
@BeforeEach
|
void setUp() {
|
service = spy(new TChargingOrderServiceImpl());
|
mapper = mock(TChargingOrderMapper.class);
|
redisService = mock(RedisService.class);
|
chargingGunClient = mock(ChargingGunClient.class);
|
ReflectionTestUtils.setField(service, "baseMapper", mapper);
|
ReflectionTestUtils.setField(service, "redisService", redisService);
|
ReflectionTestUtils.setField(service, "chargingGunClient", chargingGunClient);
|
}
|
|
/**
|
* 缓存缺失时按待启动订单重建,保证设备安全检测上报仍能推进启动
|
*/
|
@Test
|
void securityDetectionRebuildsCacheWhenCacheMissing() {
|
when(chargingGunClient.getChargingGunByCode(any())).thenReturn(R.ok(chargingGun()));
|
when(redisService.getCacheObject("AQJC_" + GUN_ID)).thenReturn(null);
|
when(mapper.selectOne(any())).thenReturn(pendingOrder());
|
|
// 绝缘检测未通过(1=不安全)时仅更新缓存,不进入启动下发
|
service.securityDetection(securityDetectionVO(1, 1, 1));
|
|
ArgumentCaptor<PreChargeCheck> captor = ArgumentCaptor.forClass(PreChargeCheck.class);
|
verify(redisService).setCacheObject(eq("AQJC_" + GUN_ID), captor.capture(), eq(24L), eq(TimeUnit.HOURS));
|
PreChargeCheck saved = captor.getValue();
|
assertEquals(Integer.valueOf(1), saved.getStartupSuccess(), "重建后应回到等待启动状态");
|
assertEquals(Boolean.TRUE, saved.getElectronicLockLock());
|
assertEquals(Boolean.FALSE, saved.getInsulationTesting());
|
assertNotNull(saved.getAddTime(), "重建后应刷新等待基准时间");
|
}
|
|
/**
|
* 缓存缺失且无待启动订单时忽略上报,不产生脏缓存
|
*/
|
@Test
|
void securityDetectionIgnoresWhenNoPendingOrder() {
|
when(chargingGunClient.getChargingGunByCode(any())).thenReturn(R.ok(chargingGun()));
|
when(redisService.getCacheObject("AQJC_" + GUN_ID)).thenReturn(null);
|
when(mapper.selectOne(any())).thenReturn(null);
|
|
service.securityDetection(securityDetectionVO(1, 0, 1));
|
|
verify(redisService, never()).setCacheObject(anyString(), any(), anyLong(), any(TimeUnit.class));
|
}
|
|
/**
|
* 等待安全检测超时的订单自动取消:退款、推进为已结束并清理缓存
|
*/
|
@Test
|
void startupTimeoutOrderIsCancelled() {
|
when(mapper.selectList(any())).thenReturn(Collections.singletonList(pendingOrder()));
|
when(redisService.getCacheObject("AQJC_" + GUN_ID)).thenReturn(null);
|
doNothing().when(service).refund(ORDER_CODE);
|
|
service.cancelStartupTimeoutOrders();
|
|
ArgumentCaptor<TChargingOrder> captor = ArgumentCaptor.forClass(TChargingOrder.class);
|
verify(mapper).updateById(captor.capture());
|
TChargingOrder finished = captor.getValue();
|
assertEquals(Integer.valueOf(5), finished.getStatus());
|
assertEquals(Integer.valueOf(0), finished.getEndMode());
|
assertNotNull(finished.getEndTime());
|
verify(service).refund(ORDER_CODE);
|
verify(redisService).deleteObject("AQJC_" + GUN_ID);
|
}
|
|
/**
|
* 已下发启动指令的订单交给启动结果检测处理,兜底任务不得误取消
|
*/
|
@Test
|
void startupTimeoutOrderWithCommandSentIsSkipped() {
|
when(mapper.selectList(any())).thenReturn(Collections.singletonList(pendingOrder()));
|
PreChargeCheck check = new PreChargeCheck();
|
check.setStartCommandSent(true);
|
when(redisService.getCacheObject("AQJC_" + GUN_ID)).thenReturn(check);
|
|
service.cancelStartupTimeoutOrders();
|
|
verify(service, never()).refund(anyString());
|
verify(mapper, never()).updateById(any());
|
verify(redisService, never()).deleteObject(anyString());
|
}
|
|
/**
|
* 初始化安全检测等待对象:预约订单以预约时间为等待基准
|
*/
|
@Test
|
void newPreChargeCheckUsesReservationTimeAsWaitBase() {
|
LocalDateTime reservationTime = LocalDateTime.now().plusMinutes(5);
|
TChargingOrder order = pendingOrder();
|
order.setReservationTime(reservationTime);
|
|
PreChargeCheck check = ReflectionTestUtils.invokeMethod(service, "newPreChargeCheck", order);
|
|
assertNotNull(check);
|
assertEquals(reservationTime, check.getAddTime());
|
assertEquals(Integer.valueOf(1), check.getStartupSuccess());
|
assertEquals(Boolean.FALSE, check.getStartCommandSent());
|
}
|
|
private static TChargingGun chargingGun() {
|
TChargingGun gun = new TChargingGun();
|
gun.setId(GUN_ID);
|
return gun;
|
}
|
|
private static TChargingOrder pendingOrder() {
|
TChargingOrder order = new TChargingOrder();
|
order.setId(2110201381176229890L);
|
order.setCode(ORDER_CODE);
|
order.setChargingGunId(GUN_ID);
|
order.setStatus(2);
|
order.setRechargePaymentStatus(2);
|
order.setDelFlag(false);
|
order.setPayTime(LocalDateTime.now().minusMinutes(10));
|
return order;
|
}
|
|
private static SecurityDetectionVO securityDetectionVO(Integer electronicLock, Integer insulation, Integer secureConnection) {
|
SecurityDetectionVO vo = new SecurityDetectionVO();
|
vo.setCharging_pile_code("8832010600495288");
|
vo.setCharging_gun_code("02");
|
vo.setElectronic_lock_lock(electronicLock);
|
vo.setNsulation_detection(insulation);
|
vo.setSecure_connection(secureConnection);
|
return vo;
|
}
|
}
|