]> git.giacomolli.uk - onehouse/blobdiff - driver/m31/tcp_client_test.go
Preserve separate Modbus phase timeouts
[onehouse] / driver / m31 / tcp_client_test.go
index 6e4979b80ac81d443505bda5f0ca41f5bb2c2e1a..0067566b070cf21907b8b465479db9123d1e432a 100644 (file)
@@ -311,6 +311,59 @@ func TestTCPClientUsesCallerDeadlineAndStartsClosed(t *testing.T) {
        })
 }
 
        })
 }
 
+func TestTCPClientReadTimeoutStartsAfterRequestWrite(t *testing.T) {
+       synctest.Test(t, func(t *testing.T) {
+               conn, peer := net.Pipe()
+               c := &tcpClient{conn: conn, unit: 1}
+               t.Cleanup(func() {
+                       require.NoError(t, c.Close())
+                       require.NoError(t, peer.Close())
+               })
+
+               done := make(chan error, 1)
+               go func() {
+                       time.Sleep(500 * time.Millisecond)
+
+                       var request [12]byte
+
+                       _, err := io.ReadFull(peer, request[:])
+                       done <- err
+               }()
+
+               started := time.Now()
+               _, err := c.ReadCoils(t.Context(), 1)
+               require.Error(t, err)
+               require.NoError(t, <-done)
+               require.Equal(t, 2500*time.Millisecond, time.Since(started))
+       })
+}
+
+func TestTCPClientStopsAfterCancelledRequestWrite(t *testing.T) {
+       synctest.Test(t, func(t *testing.T) {
+               conn, peer := net.Pipe()
+               t.Cleanup(func() {
+                       require.NoError(t, peer.Close())
+               })
+
+               ctx, cancel := context.WithCancel(t.Context())
+               defer cancel()
+
+               transport := &interruptConn{
+                       Conn:        conn,
+                       cancel:      cancel,
+                       interrupted: make(chan struct{}),
+               }
+               c := &tcpClient{conn: transport, unit: 1}
+               t.Cleanup(func() {
+                       require.NoError(t, c.Close())
+               })
+
+               _, err := c.ReadCoils(ctx, 1)
+               require.ErrorIs(t, err, context.Canceled)
+               require.NotErrorIs(t, err, os.ErrDeadlineExceeded)
+       })
+}
+
 func TestTCPClientCancellationPreservesIndependentFailure(t *testing.T) {
        synctest.Test(t, func(t *testing.T) {
                conn, peer := net.Pipe()
 func TestTCPClientCancellationPreservesIndependentFailure(t *testing.T) {
        synctest.Test(t, func(t *testing.T) {
                conn, peer := net.Pipe()
@@ -363,11 +416,15 @@ type interruptConn struct {
        interrupted chan struct{}
 }
 
        interrupted chan struct{}
 }
 
-func (c *interruptConn) Write([]byte) (int, error) {
+func (c *interruptConn) Write(data []byte) (int, error) {
        c.cancel()
        <-c.interrupted
 
        c.cancel()
        <-c.interrupted
 
-       return 0, c.failure
+       if c.failure != nil {
+               return 0, c.failure
+       }
+
+       return len(data), nil
 }
 
 func (c *interruptConn) SetDeadline(deadline time.Time) error {
 }
 
 func (c *interruptConn) SetDeadline(deadline time.Time) error {