const testDeviceID = "01ARZ3NDEKTSV4RRFFQ69G5FAV"
type fakeClient struct {
- mu sync.Mutex
- inputs []bool
- coils []bool
- analog []uint16
- registers map[uint16]uint16
- writes []coilWrite
- registerWrites []uint16
- attempts []time.Time
- closes int
- coilReads int
- connectErrors []error
- inputErr error
- readErr error
- writeErr error
- registerErr error
- closeErr error
- wrongConfig bool
- shortRead bool
- mismatch int
- writeDelay time.Duration
- inputDelay time.Duration
+ registerReadErr error
+ wrongRegister uint16
+ failAfterWrites int
+ mu sync.Mutex
+ inputs []bool
+ coils []bool
+ analog []uint16
+ registers map[uint16]uint16
+ writes []coilWrite
+ registerWrites []uint16
+ attempts []time.Time
+ closes int
+ coilReads int
+ connectErrors []error
+ inputErr error
+ readErr error
+ writeErr error
+ registerErr error
+ closeErr error
+ wrongConfig bool
+ shortRead bool
+ mismatch int
+ writeDelay time.Duration
+ inputDelay time.Duration
}
func (c *fakeClient) Connect(ctx context.Context, _ string, _ byte) error {
c.mu.Lock()
defer c.mu.Unlock()
- if c.registerErr != nil || ctx.Err() != nil {
- return nil, errors.Join(c.registerErr, ctx.Err())
+ if c.registerErr != nil || c.registerReadErr != nil || ctx.Err() != nil {
+ return nil, errors.Join(c.registerErr, c.registerReadErr, ctx.Err())
}
if address >= pulseWidthBase {
value := c.registers[address]
- if c.wrongConfig {
+ if c.wrongConfig || address == c.wrongRegister {
value++
}
time.Sleep(c.writeDelay)
- if c.writeErr != nil || ctx.Err() != nil {
+ if c.writeErr != nil && len(c.writes) >= c.failAfterWrites || ctx.Err() != nil {
return errors.Join(c.writeErr, ctx.Err())
}
return slices.Clone(f.messages)
}
-func testAssembly(t *testing.T) (*Driver, *fakeClient, *fakeTransport) {
+func testAssembly(t *testing.T) (*Driver, *fakeClient, *fakeTransport, *driver.Router) {
t.Helper()
transport := &fakeTransport{}
publisher := driver.NewPublisher(transport)
+ router, err := driver.NewRouter([]string{testDeviceID})
+ require.NoError(t, err)
+
client := &fakeClient{
inputs: make([]bool, 16),
coils: make([]bool, 32),
{Model: MixedModel},
},
}
- d, err := New(settings, publisher, client)
+ d, err := New(settings, publisher, router, client)
require.NoError(t, err)
- return d, client, transport
+ return d, client, transport, router
+}
+
+func testCommand(t *testing.T, capability string, value string) driver.Command {
+ t.Helper()
+
+ id, err := protocol.NewID(time.Now())
+ require.NoError(t, err)
+
+ expires := time.Now().UTC().Add(time.Minute)
+
+ return driver.Command{
+ DeviceID: testDeviceID,
+ Capability: capability,
+ Metadata: protocol.Metadata{
+ MessageID: id,
+ ExpiresAt: &expires,
+ },
+ Payload: protocol.ValuePayload{Value: []byte(value)},
+ }
}
func testConnection(t *testing.T) (*connection, *fakeClient, *fakeTransport) {
t.Helper()
- d, client, transport := testAssembly(t)
+ d, client, transport, _ := testAssembly(t)
connection := &connection{owner: d}
require.NoError(t, connection.start(t.Context()))
return connection, client, transport
}
+
+func queueCommands(t *testing.T, router *driver.Router, commands []driver.Command) {
+ t.Helper()
+
+ var (
+ publication protocol.Publication
+ err error
+ )
+
+ if len(commands) == 1 {
+ command := commands[0]
+ publication, err = protocol.BuildCommand(command.DeviceID, command.Capability, command.Metadata, command.Payload)
+ } else {
+ members := make([]protocol.BatchCommand, len(commands))
+
+ for index, command := range commands {
+ members[index] = protocol.BatchCommand{
+ Capability: command.Capability,
+ Metadata: command.Metadata,
+ Payload: command.Payload,
+ }
+ }
+
+ publication, err = protocol.BuildCommandBatch(testDeviceID, commands[0].Metadata, protocol.BatchPayload{Commands: members})
+ }
+
+ require.NoError(t, err)
+ require.NoError(t, router.Handle(t.Context(), publication.Topic, publication.Data, false))
+}