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

292 lines
10 KiB
Java
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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("=== 测试通过:设备不在调试模式,先开启调试模式再开仓成功 ===");
}
}