292 lines
10 KiB
Java
292 lines
10 KiB
Java
package com.tuoheng.old;
|
||
|
||
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.*;
|
||
import lombok.extern.slf4j.Slf4j;
|
||
import org.junit.jupiter.api.BeforeEach;
|
||
import org.junit.jupiter.api.MethodOrderer;
|
||
import org.junit.jupiter.api.Test;
|
||
import org.junit.jupiter.api.TestMethodOrder;
|
||
import org.springframework.beans.factory.annotation.Autowired;
|
||
import org.springframework.boot.test.context.SpringBootTest;
|
||
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
|
||
@Slf4j
|
||
@TestMethodOrder(MethodOrderer.OrderAnnotation.class)
|
||
public class DrcStateMachineTest {
|
||
|
||
|
||
@Autowired
|
||
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");
|
||
}
|
||
|
||
@Test
|
||
@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());
|
||
}
|
||
|
||
@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());
|
||
}
|
||
|
||
/**
|
||
* 测试开仓命令 - 场景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("=== 测试通过:设备不在调试模式,先开启调试模式再开仓成功 ===");
|
||
}
|
||
}
|