浇水bug修改
This commit is contained in:
134
docs/superpowers/plans/2026-07-13-device-status-lwt-mac.md
Normal file
134
docs/superpowers/plans/2026-07-13-device-status-lwt-mac.md
Normal file
@@ -0,0 +1,134 @@
|
||||
# Device Status LWT MAC Resolution Implementation Plan
|
||||
|
||||
> **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking.
|
||||
|
||||
**Goal:** Verify and document that `/MAC/publish/status` last-will messages resolve the MAC address to `deviceNo` before updating device status.
|
||||
|
||||
**Architecture:** Keep `DeviceStatusHandler` focused on status parsing and delegate Topic identity resolution to the existing `DeviceIdentityResolver`. Add a focused integration-style unit test using the real resolver and a mocked mapper so the complete MAC-to-device-number path is covered without duplicating database access in the handler.
|
||||
|
||||
**Tech Stack:** Java 17, Spring Boot, JUnit 5, Mockito, AssertJ, MyBatis-Plus
|
||||
|
||||
## Global Constraints
|
||||
|
||||
- Only `/MAC/publish/status` may use a MAC address for this change.
|
||||
- Other MQTT communication continues to use `deviceNo`.
|
||||
- A missing MAC mapping must not update device status.
|
||||
- Preserve all existing uncommitted workspace changes.
|
||||
|
||||
---
|
||||
|
||||
### Task 1: Cover MAC Last-Will Resolution
|
||||
|
||||
**Files:**
|
||||
- Modify: `water-modules/water-app/src/test/java/org/dromara/app/handler/DeviceStatusHandlerTest.java`
|
||||
|
||||
**Interfaces:**
|
||||
- Consumes: `DeviceIdentityResolver(AppDeviceMapper)` and `DeviceStatusHandler.handle(String, String, boolean)`
|
||||
- Produces: Regression coverage proving a Topic MAC is converted to `AppDevice.deviceNo`
|
||||
|
||||
- [ ] **Step 1: Add the mapper mock and MAC last-will test**
|
||||
|
||||
Add imports and a mapper mock:
|
||||
|
||||
```java
|
||||
import org.dromara.app.domain.AppDevice;
|
||||
import org.dromara.app.mapper.AppDeviceMapper;
|
||||
|
||||
@Mock
|
||||
private AppDeviceMapper appDeviceMapper;
|
||||
```
|
||||
|
||||
Add this test:
|
||||
|
||||
```java
|
||||
@Test
|
||||
void handleResolvesLastWillTopicMacToDeviceNo() {
|
||||
String macAddress = "DC:DA:0C:FA:29:5E";
|
||||
AppDevice device = new AppDevice();
|
||||
device.setDeviceNo("D01");
|
||||
when(appDeviceMapper.selectById(macAddress)).thenReturn(null);
|
||||
when(appDeviceMapper.selectByMac("dc:da:0c:fa:29:5e")).thenReturn(device);
|
||||
DeviceIdentityResolver resolver = new DeviceIdentityResolver(appDeviceMapper);
|
||||
DeviceStatusHandler handler = new DeviceStatusHandler(resolver, deviceStatusService, new ObjectMapper());
|
||||
|
||||
handler.handle(macAddress, "{\"status\":\"offline\"}", false);
|
||||
|
||||
verify(appDeviceMapper).selectByMac("dc:da:0c:fa:29:5e");
|
||||
verify(deviceStatusService).markOffline("D01", "设备 MQTT 状态离线");
|
||||
verify(deviceStatusService, never()).markOffline(macAddress, "设备 MQTT 状态离线");
|
||||
}
|
||||
```
|
||||
|
||||
Add the missing-device guard test:
|
||||
|
||||
```java
|
||||
@Test
|
||||
void handleDoesNotUpdateStatusWhenLastWillMacIsUnknown() {
|
||||
String macAddress = "DC:DA:0C:FA:29:5E";
|
||||
when(appDeviceMapper.selectById(macAddress)).thenReturn(null);
|
||||
when(appDeviceMapper.selectByMac("dc:da:0c:fa:29:5e")).thenReturn(null);
|
||||
DeviceIdentityResolver resolver = new DeviceIdentityResolver(appDeviceMapper);
|
||||
DeviceStatusHandler handler = new DeviceStatusHandler(resolver, deviceStatusService, new ObjectMapper());
|
||||
|
||||
handler.handle(macAddress, "{\"status\":\"offline\"}", false);
|
||||
|
||||
verify(deviceStatusService, never()).markOffline(anyString(), anyString());
|
||||
verify(deviceStatusService, never()).markOnline(anyString());
|
||||
}
|
||||
```
|
||||
|
||||
- [ ] **Step 2: Run the focused test**
|
||||
|
||||
Run:
|
||||
|
||||
```powershell
|
||||
mvn -pl water-modules/water-app -am "-DskipTests=false" "-Dmaven.test.skip=false" "-Dprofiles.active=dev" "-Dtest=DeviceStatusHandlerTest#handleResolvesLastWillTopicMacToDeviceNo+handleDoesNotUpdateStatusWhenLastWillMacIsUnknown" "-Dsurefire.failIfNoSpecifiedTests=false" test
|
||||
```
|
||||
|
||||
Expected: both tests PASS. The requested production path already exists in `DeviceIdentityResolver`; these characterization tests make that behavior explicit and prevent regression.
|
||||
|
||||
### Task 2: Clarify Device Status Topic Identity
|
||||
|
||||
**Files:**
|
||||
- Modify: `water-modules/water-app/src/main/java/org/dromara/app/handler/DeviceStatusHandler.java:15-19`
|
||||
|
||||
**Interfaces:**
|
||||
- Consumes: Existing `DeviceIdentityResolver.resolveDeviceNo(String)` behavior
|
||||
- Produces: Javadoc that accurately documents device-number and MAC Topic identities
|
||||
|
||||
- [ ] **Step 1: Update handler Javadoc**
|
||||
|
||||
Replace the class description with:
|
||||
|
||||
```java
|
||||
/**
|
||||
* 设备在线/离线状态处理器,匹配 /{deviceIdentity}/publish/status。
|
||||
* <p>
|
||||
* deviceIdentity 支持设备编号;设备遗嘱消息允许使用 MAC 地址,处理前统一解析为设备编号。
|
||||
* 设备通过 status=online 标记上线,通过 LWT status=offline 标记异常离线。
|
||||
*/
|
||||
```
|
||||
|
||||
- [ ] **Step 2: Run all handler tests**
|
||||
|
||||
Run:
|
||||
|
||||
```powershell
|
||||
mvn -pl water-modules/water-app -am "-DskipTests=false" "-Dmaven.test.skip=false" "-Dprofiles.active=dev" "-Dtest=DeviceStatusHandlerTest" "-Dsurefire.failIfNoSpecifiedTests=false" test
|
||||
```
|
||||
|
||||
Expected: all `DeviceStatusHandlerTest` tests PASS with zero failures and errors.
|
||||
|
||||
- [ ] **Step 3: Check the final diff**
|
||||
|
||||
Run:
|
||||
|
||||
```powershell
|
||||
git diff --check -- water-modules/water-app/src/main/java/org/dromara/app/handler/DeviceStatusHandler.java water-modules/water-app/src/test/java/org/dromara/app/handler/DeviceStatusHandlerTest.java
|
||||
```
|
||||
|
||||
Expected: exit code 0 and no whitespace errors.
|
||||
|
||||
- [ ] **Step 4: Leave implementation changes uncommitted for review**
|
||||
|
||||
Both implementation files already contain user changes. Do not create a commit that would mix those changes with this task.
|
||||
Reference in New Issue
Block a user