feat(application): HealthMonitor service and hardware integration test
Add HealthMonitor service for tracking system health status with comprehensive state transition logic and thread-safe operations. Includes 16 unit tests covering all functionality including concurrent access scenarios. Add optional Modbus hardware integration tests with 7 test cases for real device testing. Tests are marked as ignored and can be run with Ref: T034, T039, T040 (specs/001-modbus-relay-control/tasks.org)
This commit is contained in:
@@ -331,13 +331,13 @@
|
||||
|
||||
--------------
|
||||
|
||||
*** STARTED T025: ModbusRelayController Implementation (DECOMPOSED) [9/13]
|
||||
*** STARTED T025: ModbusRelayController Implementation (DECOMPOSED) [12/13]
|
||||
- Complexity :: High → Broken into 6 sub-tasks
|
||||
- Uncertainty :: High
|
||||
- Rationale :: Nested Result handling, =Arc<Mutex>= synchronization, timeout wrapping
|
||||
- Protocol :: Native Modbus TCP (MBAP header, no CRC16 validation)
|
||||
|
||||
- [X] *T025a* [US1] [TDD] Implement =ModbusRelayController= connection setup
|
||||
- [X] *T025a* [US1] [TDD] Implement =ModbusRelayController= connection setup [3/3]
|
||||
|
||||
- Struct: =ModbusRelayController { ctx: Arc<Mutex<Context>>, timeout_duration: Duration }=
|
||||
- Constructor: =new(host, port, slave_id, timeout_secs) → Result<Self, ControllerError>=
|
||||
@@ -382,7 +382,7 @@
|
||||
- [X] Test: =new()= with invalid host returns =ConnectionError=
|
||||
- [X] Test: =new()= stores correct timeout_duration
|
||||
|
||||
- [X] *T025b* [US1] [TDD] Implement timeout-wrapped =read_coils= helper
|
||||
- [X] *T025b* [US1] [TDD] Implement timeout-wrapped =read_coils= helper [4/4]
|
||||
|
||||
- Private method: =read_coils_with_timeout(addr: u16, count: u16) → Result<Vec<bool>, ControllerError>=
|
||||
- Wrap =ctx.read_coils()= with =tokio::time::timeout()=
|
||||
@@ -421,7 +421,7 @@
|
||||
- [X] Test: =read_coils_with_timeout()= returns =ConnectionError= on =io::Error=
|
||||
- [X] Test: =read_coils_with_timeout()= returns =ModbusException= on protocol error
|
||||
|
||||
- [X] *T025c* [US1] [TDD] Implement timeout-wrapped =write_single_coil= helper
|
||||
- [X] *T025c* [US1] [TDD] Implement timeout-wrapped =write_single_coil= helper [3/3]
|
||||
|
||||
- Private method: =write_single_coil_with_timeout(addr: u16, value: bool) → Result<(), ControllerError>=
|
||||
- Similar nested Result handling as T025b
|
||||
@@ -454,7 +454,7 @@
|
||||
- [X] Test: =write_single_coil_with_timeout()= returns Timeout on slow device
|
||||
- [X] Test: =write_single_coil_with_timeout()= returns appropriate error on failure
|
||||
|
||||
- [X] *T025d* [US1] [TDD] Implement =RelayController::read_state()= using helpers
|
||||
- [X] *T025d* [US1] [TDD] Implement =RelayController::read_state()= using helpers [3/3]
|
||||
|
||||
- Convert =RelayId= → =ModbusAddress= (0-based)
|
||||
- Call =read_coils_with_timeout(addr, 1)=
|
||||
@@ -482,7 +482,7 @@
|
||||
- [X] Test: =read_state(RelayId(1))= returns =Off= when coil is false
|
||||
- [X] Test: =read_state()= propagates =ControllerError= from helper
|
||||
|
||||
- [X] *T025e* [US1] [TDD] Implement =RelayController::write_state()= using helpers
|
||||
- [X] *T025e* [US1] [TDD] Implement =RelayController::write_state()= using helpers [2/2]
|
||||
|
||||
- Convert =RelayId= → =ModbusAddress=
|
||||
- Convert =RelayState= → bool (On=true, Off=false)
|
||||
@@ -505,7 +505,7 @@
|
||||
- [X] Test: =write_state(RelayId(1), RelayState::On)= writes true to coil
|
||||
- [X] Test: =write_state(RelayId(1), RelayState::Off)= writes false to coil
|
||||
|
||||
- [X] *T025f* [US1] [TDD] Implement =RelayController::read_all()= and =write_all()=
|
||||
- [X] *T025f* [US1] [TDD] Implement =RelayController::read_all()= and =write_all()= [3/3]
|
||||
|
||||
- =read_all()=: Call =read_coils_with_timeout(0, 8)=, map to =Vec<(RelayId, RelayState)>=
|
||||
- =write_all()=: Loop over RelayId 1-8, call =write_state()= for each
|
||||
@@ -545,7 +545,7 @@
|
||||
|
||||
--------------
|
||||
|
||||
- [ ] *T034* [US1] [TDD] Integration test with real hardware (optional)
|
||||
- [X] *T034* [US1] [TDD] Integration test with real hardware (optional)
|
||||
- *REQUIRES PHYSICAL DEVICE*: Test against actual Modbus relay at configured IP
|
||||
- Skip if device unavailable, rely on =MockRelayController= for CI
|
||||
- *File*: =tests/integration/modbus_hardware_test.rs=
|
||||
@@ -570,12 +570,12 @@
|
||||
- HashMap-based implementation
|
||||
- *File*: =src/infrastructure/persistence/mock_label_repository.rs=
|
||||
- *Complexity*: Low | *Uncertainty*: Low
|
||||
- [ ] *T039* [US3] [TDD] Write tests for =HealthMonitor= service
|
||||
- [X] *T039* [US3] [TDD] Write tests for =HealthMonitor= service
|
||||
- Test: =track_success()= transitions =Degraded= → =Healthy=
|
||||
- Test: =track_failure()= transitions =Healthy= → =Degraded= → =Unhealthy=
|
||||
- *File*: =src/application/health_monitor.rs=
|
||||
- *Complexity*: Medium | *Uncertainty*: Low
|
||||
- [ ] *T040* [US3] [TDD] Implement =HealthMonitor= service
|
||||
- [X] *T040* [US3] [TDD] Implement =HealthMonitor= service
|
||||
- Track consecutive errors, transition states per FR-020, FR-021
|
||||
- *File*: =src/application/health_monitor.rs=
|
||||
- *Complexity*: Medium | *Uncertainty*: Low
|
||||
|
||||
Reference in New Issue
Block a user