Overview
Refactor the I2C device interface to use traits instead of concrete types, enabling comprehensive integration testing without hardware dependencies.
Current Problem
The daemon architecture tightly couples to the concrete HalpiDevice type:
AppState directly contains HalpiDevice
- All HTTP handlers depend on
AppState with real I2C hardware
- No dependency injection mechanism for mocking
- Integration tests cannot run without actual HALPI2 hardware
- Cannot test error paths systematically
Proposed Solution
1. Define I2C Device Trait
pub trait I2CDeviceInterface: Send {
fn get_measurements(&mut self) -> Result<Measurements, I2cError>;
fn get_power_state(&mut self) -> Result<PowerState, I2cError>;
fn feed_watchdog(&mut self) -> Result<(), I2cError>;
fn get_usb_port_state(&mut self) -> Result<u8, I2cError>;
fn set_usb_port_state(&mut self, port_bits: u8) -> Result<(), I2cError>;
fn request_shutdown(&mut self) -> Result<(), I2cError>;
fn request_standby(&mut self) -> Result<(), I2cError>;
fn firmware_version(&mut self) -> Result<&str, I2cError>;
fn get_hardware_version(&mut self) -> Result<Version, I2cError>;
fn get_firmware_version(&mut self) -> Result<Version, I2cError>;
fn get_device_id(&mut self) -> Result<String, I2cError>;
// ... other methods
}
2. Make AppState Generic
pub struct AppState<D: I2CDeviceInterface> {
pub device: Arc<Mutex<D>>,
pub config: Arc<RwLock<Config>>,
pub version: &'static str,
}
3. Implement Trait for HalpiDevice
impl I2CDeviceInterface for HalpiDevice {
// Existing method implementations
}
4. Create Mock Implementation
pub struct MockI2CDevice {
measurements: Measurements,
power_state: PowerState,
usb_ports: u8,
// ... configurable test data
}
impl I2CDeviceInterface for MockI2CDevice {
fn get_measurements(&mut self) -> Result<Measurements, I2cError> {
Ok(self.measurements.clone())
}
// ... predetermined responses for testing
}
5. Update All Handlers
Update all HTTP handler functions to use generic type parameters or trait objects.
Benefits
- ✅ Integration tests can run without hardware
- ✅ Fast, deterministic test execution in CI
- ✅ Can test error paths systematically
- ✅ Can control I2C device state for testing
- ✅ Better separation of concerns
- ✅ More maintainable architecture
Implementation Plan
- Define
I2CDeviceInterface trait in halpid/src/i2c/mod.rs
- Implement trait for
HalpiDevice
- Create
MockI2CDevice in test utilities
- Refactor
AppState to be generic
- Update all handler functions
- Update
main.rs to use concrete type
- Add comprehensive integration tests using mock
- Verify all existing tests still pass
Acceptance Criteria
Dependencies
- None (can be implemented independently)
Estimated Effort
Medium - Requires changes across multiple modules but is mostly mechanical refactoring.
Related Issues
Overview
Refactor the I2C device interface to use traits instead of concrete types, enabling comprehensive integration testing without hardware dependencies.
Current Problem
The daemon architecture tightly couples to the concrete
HalpiDevicetype:AppStatedirectly containsHalpiDeviceAppStatewith real I2C hardwareProposed Solution
1. Define I2C Device Trait
2. Make AppState Generic
3. Implement Trait for HalpiDevice
4. Create Mock Implementation
5. Update All Handlers
Update all HTTP handler functions to use generic type parameters or trait objects.
Benefits
Implementation Plan
I2CDeviceInterfacetrait inhalpid/src/i2c/mod.rsHalpiDeviceMockI2CDevicein test utilitiesAppStateto be genericmain.rsto use concrete typeAcceptance Criteria
I2CDeviceInterfacetrait defined with all necessary methodsHalpiDeviceimplements the traitMockI2CDevicetest implementation createdAppStateis generic over device typeDependencies
Estimated Effort
Medium - Requires changes across multiple modules but is mostly mechanical refactoring.
Related Issues