homelabby/internal/tester/mock_drivers.go
Mikkel Georgsen 11aea60aee feat(05-01): TesterDriver interface, 4 mock drivers, KnownDevices tester entries
- TesterDriver interface: Connect/Read/Disconnect
- StreamingTesterDriver interface: embeds TesterDriver, adds Stream()
- TestResult struct: CableType, versions, speed, power, continuity, eMarker, resistance
- LiveReading struct: Voltage, CurrentAmps, PowerWatts, PDProtocol, Timestamp
- MockUSBDriver: deterministic USB 3.2 Gen 2 result, ErrNotConnected guard
- MockDPDriver: deterministic DP 1.4 result
- MockHDMIDriver: deterministic HDMI 2.1 result
- MockFNB58Driver: 3 LiveReading samples at 100ms, context-cancelled via Disconnect()
- KnownDevices: 4 RoleCableTester placeholder entries (dead0:0001-0004)
2026-04-10 07:07:27 +00:00

175 lines
4 KiB
Go

package tester
import (
"context"
"time"
)
// MockUSBDriver simulates a Treedix USB cable tester.
// Returns deterministic USB 3.2 Gen 2 test results.
// All fields are exported so test code can construct zero values directly.
type MockUSBDriver struct {
connected bool
}
// Compile-time interface assertion.
var _ TesterDriver = (*MockUSBDriver)(nil)
func (d *MockUSBDriver) Connect() error {
d.connected = true
return nil
}
func (d *MockUSBDriver) Read() (TestResult, error) {
if !d.connected {
return TestResult{}, ErrNotConnected
}
return TestResult{
CableType: CableTypeUSB,
USBVersion: "USB 3.2 Gen 2",
SpeedGbps: 10.0,
MaxWatts: 100,
PinContinuity: true,
HasEMarker: true,
ResistanceOhm: 0.12,
}, nil
}
func (d *MockUSBDriver) Disconnect() error {
d.connected = false
return nil
}
// MockDPDriver simulates a Treedix DisplayPort cable tester.
// Returns deterministic DP 1.4 test results.
type MockDPDriver struct {
connected bool
}
// Compile-time interface assertion.
var _ TesterDriver = (*MockDPDriver)(nil)
func (d *MockDPDriver) Connect() error {
d.connected = true
return nil
}
func (d *MockDPDriver) Read() (TestResult, error) {
if !d.connected {
return TestResult{}, ErrNotConnected
}
return TestResult{
CableType: CableTypeDP,
DPVersion: "1.4",
PinContinuity: true,
}, nil
}
func (d *MockDPDriver) Disconnect() error {
d.connected = false
return nil
}
// MockHDMIDriver simulates a Treedix HDMI cable tester.
// Returns deterministic HDMI 2.1 test results.
type MockHDMIDriver struct {
connected bool
}
// Compile-time interface assertion.
var _ TesterDriver = (*MockHDMIDriver)(nil)
func (d *MockHDMIDriver) Connect() error {
d.connected = true
return nil
}
func (d *MockHDMIDriver) Read() (TestResult, error) {
if !d.connected {
return TestResult{}, ErrNotConnected
}
return TestResult{
CableType: CableTypeHDMI,
HDMIVersion: "2.1",
PinContinuity: true,
}, nil
}
func (d *MockHDMIDriver) Disconnect() error {
d.connected = false
return nil
}
// MockFNB58Driver simulates an FNIRSI FNB58 USB power meter.
// Stream() emits 3 deterministic LiveReading samples at 100ms intervals,
// then closes the channel. Disconnect() cancels the goroutine early.
type MockFNB58Driver struct {
connected bool
streamCh chan LiveReading
cancelFunc context.CancelFunc
}
// Compile-time interface assertion.
var _ StreamingTesterDriver = (*MockFNB58Driver)(nil)
func (d *MockFNB58Driver) Connect() error {
d.connected = true
d.streamCh = make(chan LiveReading, 8)
ctx, cancel := context.WithCancel(context.Background())
d.cancelFunc = cancel
go d.runStream(ctx)
return nil
}
func (d *MockFNB58Driver) runStream(ctx context.Context) {
defer close(d.streamCh)
samples := []LiveReading{
{Voltage: 5.1, CurrentAmps: 3.0, PowerWatts: 15.3, PDProtocol: "PD3.0", Timestamp: time.Now()},
{Voltage: 5.1, CurrentAmps: 3.0, PowerWatts: 15.3, PDProtocol: "PD3.0", Timestamp: time.Now()},
{Voltage: 5.1, CurrentAmps: 3.0, PowerWatts: 15.3, PDProtocol: "PD3.0", Timestamp: time.Now()},
}
for _, s := range samples {
select {
case <-ctx.Done():
return
case <-time.After(100 * time.Millisecond):
s.Timestamp = time.Now()
select {
case d.streamCh <- s:
case <-ctx.Done():
return
}
}
}
}
func (d *MockFNB58Driver) Read() (TestResult, error) {
if !d.connected {
return TestResult{}, ErrNotConnected
}
// FNB58 is a streaming device; discrete Read returns a snapshot.
return TestResult{
CableType: CableTypeUSB,
MaxWatts: 100,
}, nil
}
func (d *MockFNB58Driver) Disconnect() error {
if d.cancelFunc != nil {
d.cancelFunc()
d.cancelFunc = nil
}
d.connected = false
return nil
}
// Stream returns the live reading channel. If called before Connect(),
// returns a pre-closed channel (never nil, never blocking).
func (d *MockFNB58Driver) Stream() <-chan LiveReading {
if !d.connected || d.streamCh == nil {
closed := make(chan LiveReading)
close(closed)
return closed
}
return d.streamCh
}