thingsboard-client-demo/src/test/java/com/tuoheng/old/DrcStateMachineTest.java

292 lines
10 KiB
Java
Raw Normal View History

2025-12-17 10:23:45 +08:00
package com.tuoheng.old;
2025-12-18 13:22:34 +08:00
import com.tuoheng.machine.MachineCommandManager;
import com.tuoheng.machine.command.CommandResult;
import com.tuoheng.machine.command.CommandType;
import com.tuoheng.machine.mqtt.MqttCallbackRegistry;
import com.tuoheng.machine.state.*;
2025-12-16 16:00:14 +08:00
import lombok.extern.slf4j.Slf4j;
2025-12-18 13:22:34 +08:00
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.MethodOrderer;
import org.junit.jupiter.api.Test;
2025-12-18 13:22:34 +08:00
import org.junit.jupiter.api.TestMethodOrder;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
2025-12-18 13:22:34 +08:00
import org.junit.jupiter.api.*;
import org.springframework.util.Assert;
import java.util.HashMap;
import java.util.concurrent.*;
import static org.junit.jupiter.api.Assertions.*;
/**
* DRC状态机测试
* 测试DRC模式的完整状态转换流程
*/
@SpringBootTest
2025-12-16 16:00:14 +08:00
@Slf4j
2025-12-18 13:22:34 +08:00
@TestMethodOrder(MethodOrderer.OrderAnnotation.class)
public class DrcStateMachineTest {
@Autowired
2025-12-18 13:22:34 +08:00
MachineCommandManager machineCommandManager;
@Autowired
MqttCallbackRegistry mqttCallbackRegistry;
private static final ScheduledExecutorService scheduler =
Executors.newScheduledThreadPool(2);
private Boolean initState = false;
private static final String SN = "SN9527";
@BeforeEach
public void init(){
if(initState){
return;
}
initState = true;
machineCommandManager.bindMachine(SN,"DJI");
}
2025-12-16 17:40:31 +08:00
@Test
2025-12-18 13:22:34 +08:00
@Order(1)
public void checkInitState(){
MachineStates machineStates = machineCommandManager.getMachineStates(SN);
assertNotNull(machineStates);
assertEquals(AirportState.UNKNOWN, machineStates.getAirportState());
assertEquals(DrcState.UNKNOWN, machineStates.getDrcState());
assertEquals(CoverState.UNKNOWN, machineStates.getCoverState());
assertEquals(DroneState.UNKNOWN, machineStates.getDroneState());
assertEquals(StopState.UNKNOWN, machineStates.getStopState());
}
/**
* 非在线状态下不可起飞
* @throws ExecutionException
* @throws InterruptedException
*/
@Test
@Order(2)
public void checkTakeOffCommand() throws ExecutionException, InterruptedException {
CompletableFuture<CommandResult> future =
machineCommandManager.executeCommand(SN, CommandType.TAKE_OFF,new HashMap<>());
assertFalse(future.get().isSuccess());
}
2025-12-18 13:22:34 +08:00
@Test
@Order(3)
public void setState() {
MachineStates machineStates = new MachineStates();
machineStates.setAirportState(AirportState.ONLINE);
machineStates.setDroneState(DroneState.ONLINE);
machineCommandManager.updateMachineStates(SN, machineStates);
machineStates = machineCommandManager.getMachineStates(SN);
assertNotNull(machineStates);
assertEquals(AirportState.ONLINE, machineStates.getAirportState());
assertEquals(DroneState.ONLINE, machineStates.getDroneState());
assertEquals(DrcState.UNKNOWN, machineStates.getDrcState());
assertEquals(CoverState.UNKNOWN, machineStates.getCoverState());
assertEquals(StopState.UNKNOWN, machineStates.getStopState());
}
// @Test
// @Order(4)
// public void checkTakeOffOverTime1() throws ExecutionException, InterruptedException, TimeoutException {
// /**
// * 指令执行超时;因为缺乏指令成功的回调
// */
// CompletableFuture<CommandResult> future =
// machineCommandManager.executeCommand(SN, CommandType.TAKE_OFF,new HashMap<>());
// assertFalse(future.get().isSuccess());
//
// }
/**
* 指令执行成功,因为mqttCallbackRegistry模拟了发送回调
* 需要将 DjiTakeOffInstruction getStateCallbackConfig 中直接返回null
*/
// @Test
// @Order(5)
// public void checkTakeOffOverTime2() throws ExecutionException, InterruptedException, TimeoutException {
//
// CompletableFuture<CommandResult> future =
// machineCommandManager.executeCommand(SN, CommandType.TAKE_OFF,new HashMap<>());
//
// scheduler.schedule(new Runnable() {
// @Override
// public void run() {
// String response = "{\"data\":{\"result\":\"takeoff\"}}";
// mqttCallbackRegistry.handleMessage("dji/SN9527/response",response);
// }
// },100,TimeUnit.MILLISECONDS);
//
// assertTrue(future.get().isSuccess());
//
// }
/**
* 指令执行失败
* 需要将 DjiTakeOffInstruction getStateCallbackConfig 中的注释放开
*/
// @Test
// @Order(5)
// public void checkTakeOffOverTime2() throws ExecutionException, InterruptedException, TimeoutException {
//
// CompletableFuture<CommandResult> future =
// machineCommandManager.executeCommand(SN, CommandType.TAKE_OFF,new HashMap<>());
//
// scheduler.schedule(new Runnable() {
// @Override
// public void run() {
// String response = "{\"data\":{\"result\":\"takeoff\"}}";
// mqttCallbackRegistry.handleMessage("dji/SN9527/response",response);
// }
// },100,TimeUnit.MILLISECONDS);
//
// assertFalse(future.get().isSuccess());
// }
/**
* 需要将 DjiTakeOffInstruction getStateCallbackConfig 中的注释放开
* @throws ExecutionException
* @throws InterruptedException
* @throws TimeoutException
*/
@Test
@Order(5)
public void checkTakeOffOverTime2() throws ExecutionException, InterruptedException, TimeoutException {
CompletableFuture<CommandResult> future =
machineCommandManager.executeCommand(SN, CommandType.TAKE_OFF,new HashMap<>());
scheduler.schedule(new Runnable() {
@Override
public void run() {
String response = "{\"data\":{\"result\":\"takeoff\"}}";
mqttCallbackRegistry.handleMessage("dji/SN9527/response",response);
// 添加延迟,等待状态回调监听器注册
try {
Thread.sleep(50); // 等待50ms
} catch (InterruptedException e) {
e.printStackTrace();
}
response = "{\"droneState\":\"FLYING\"}";
mqttCallbackRegistry.handleMessage("dji/SN9527/state",response);
}
},100,TimeUnit.MILLISECONDS);
assertTrue(future.get().isSuccess());
}
2025-12-18 14:06:35 +08:00
/**
* 测试开仓命令 - 场景1设备已在调试模式直接开仓成功
* 流程
* 1. 检查调试模式成功
* 2. 执行开仓命令
* 3. 收到开仓命令ACK
* 4. 收到舱门状态变为OPENED
*/
@Test
@Order(6)
public void testOpenCoverWithDebugModeEnabled() throws ExecutionException, InterruptedException {
log.info("=== 测试开仓命令 - 场景1设备已在调试模式 ===");
CompletableFuture<CommandResult> future =
machineCommandManager.executeCommand(SN, CommandType.OPEN_COVER, new HashMap<>());
scheduler.schedule(() -> {
try {
// 1. 模拟设备已在调试模式的状态回调100ms后
String response = "{\"debugMode\":\"ENABLED\"}";
mqttCallbackRegistry.handleMessage("dji/SN9527/state", response);
log.info("发送调试模式状态: {}", response);
Thread.sleep(50);
// 2. 模拟开仓命令的ACK响应
response = "{\"cmd\":\"openCover\"}";
mqttCallbackRegistry.handleMessage("dji/SN9527/response", response);
log.info("发送开仓命令ACK: {}", response);
Thread.sleep(50);
// 3. 模拟舱门状态变为OPENED
response = "{\"coverState\":\"OPENED\"}";
mqttCallbackRegistry.handleMessage("dji/SN9527/state", response);
log.info("发送舱门状态: {}", response);
} catch (InterruptedException e) {
e.printStackTrace();
}
}, 100, TimeUnit.MILLISECONDS);
CommandResult result = future.get();
assertTrue(result.isSuccess(), "开仓命令应该执行成功");
log.info("=== 测试通过:设备已在调试模式,开仓成功 ===");
}
/**
* 测试开仓命令 - 场景2设备不在调试模式先开启调试模式再开仓
* 流程
* 1. 检查调试模式失败/超时
* 2. 开启调试模式
* 3. 收到开启调试模式ACK
* 4. 执行开仓命令
* 5. 收到开仓命令ACK
* 6. 收到舱门状态变为OPENED
*/
@Test
@Order(7)
public void testOpenCoverWithDebugModeDisabled() throws ExecutionException, InterruptedException {
log.info("=== 测试开仓命令 - 场景2设备不在调试模式 ===");
CompletableFuture<CommandResult> future =
machineCommandManager.executeCommand(SN, CommandType.OPEN_COVER, new HashMap<>());
scheduler.schedule(() -> {
try {
// 1. 不发送调试模式状态让检查调试模式超时等待3秒超时
log.info("等待检查调试模式超时...");
Thread.sleep(3500); // 等待超过3秒让检查调试模式超时
// 2. 模拟开启调试模式命令的ACK响应
String response = "{\"cmd\":\"enableDebugMode\"}";
mqttCallbackRegistry.handleMessage("dji/SN9527/response", response);
log.info("发送开启调试模式ACK: {}", response);
Thread.sleep(50);
// 3. 模拟开仓命令的ACK响应
response = "{\"cmd\":\"openCover\"}";
mqttCallbackRegistry.handleMessage("dji/SN9527/response", response);
log.info("发送开仓命令ACK: {}", response);
Thread.sleep(50);
// 4. 模拟舱门状态变为OPENED
response = "{\"coverState\":\"OPENED\"}";
mqttCallbackRegistry.handleMessage("dji/SN9527/state", response);
log.info("发送舱门状态: {}", response);
} catch (InterruptedException e) {
e.printStackTrace();
}
}, 100, TimeUnit.MILLISECONDS);
CommandResult result = future.get();
assertTrue(result.isSuccess(), "开仓命令应该执行成功(先开启调试模式再开仓)");
log.info("=== 测试通过:设备不在调试模式,先开启调试模式再开仓成功 ===");
}
}