github.com/blueinnovationsgroup/can-go@v0.0.0-20230518195432-d0567cda0028/pkg/socketcan/dialraw_linux_test.go (about)

     1  //go:build linux && go1.12
     2  
     3  package socketcan
     4  
     5  import (
     6  	"context"
     7  	"fmt"
     8  	"net"
     9  	"runtime"
    10  	"testing"
    11  	"time"
    12  
    13  	"github.com/blueinnovationsgroup/can-go"
    14  	"golang.org/x/sync/errgroup"
    15  	"gotest.tools/v3/assert"
    16  	is "gotest.tools/v3/assert/cmp"
    17  )
    18  
    19  func TestDial_CANRaw(t *testing.T) {
    20  	requireVCAN0(t)
    21  	conn, err := Dial("can", "vcan0")
    22  	assert.NilError(t, err)
    23  	assert.NilError(t, conn.Close())
    24  }
    25  
    26  func TestDialContext_CANRaw(t *testing.T) {
    27  	requireVCAN0(t)
    28  	ctx, done := context.WithTimeout(context.Background(), time.Second)
    29  	defer done()
    30  	conn, err := DialContext(ctx, "can", "vcan0")
    31  	assert.NilError(t, err)
    32  	assert.NilError(t, conn.Close())
    33  }
    34  
    35  func TestConn_DialFail(t *testing.T) {
    36  	t.Run("bad file name", func(t *testing.T) {
    37  		_, err := Dial("can", "badFileName#")
    38  		assert.ErrorContains(t, err, "dial")
    39  	})
    40  	t.Run("timeout", func(t *testing.T) {
    41  		ctx, cancel := context.WithCancel(context.Background())
    42  		cancel()
    43  		_, err := DialContext(ctx, "can", "vcan0")
    44  		assert.ErrorContains(t, err, "context canceled")
    45  	})
    46  }
    47  
    48  func TestConn_Addr(t *testing.T) {
    49  	requireVCAN0(t)
    50  	conn, err := Dial("can", "vcan0")
    51  	assert.NilError(t, err)
    52  	assert.Assert(t, is.Nil(conn.LocalAddr())) // SocketCAN connections don't have a local connection
    53  	assert.Equal(t, "can", conn.RemoteAddr().Network())
    54  	assert.Equal(t, "vcan0", conn.RemoteAddr().String())
    55  }
    56  
    57  func TestConn_SetDeadline(t *testing.T) {
    58  	requireVCAN0(t)
    59  	// Given that a vcan device exists and that I can open a connection to it
    60  	receiver, err := Dial("can", "vcan0")
    61  	assert.NilError(t, err)
    62  	// When I set the can
    63  	timeout := 20 * time.Millisecond
    64  	assert.NilError(t, receiver.SetDeadline(time.Now().Add(timeout)))
    65  	// Then I expect a read without a corresponding write to time out
    66  	data := make([]byte, lengthOfFrame)
    67  	n, err := receiver.Read(data)
    68  	assert.Equal(t, 0, n)
    69  	assert.Assert(t, is.ErrorContains(err, ""))
    70  	// When I clear the timeouts
    71  	assert.NilError(t, receiver.SetDeadline(time.Time{}))
    72  	// Then I don't expect the read to timeout anymore
    73  	errChan := make(chan error, 1)
    74  	go func() {
    75  		_, err = receiver.Read(data)
    76  		errChan <- err
    77  	}()
    78  	select {
    79  	case <-errChan:
    80  		t.Fatal("unexpected read result")
    81  	case <-time.After(timeout):
    82  		assert.NilError(t, receiver.Close())
    83  		assert.Assert(t, is.ErrorContains(<-errChan, ""))
    84  	}
    85  }
    86  
    87  func TestConn_ReadWrite(t *testing.T) {
    88  	requireVCAN0(t)
    89  	// given a reader and writer
    90  	reader, err := Dial("can", "vcan0")
    91  	assert.NilError(t, err)
    92  	writer, err := Dial("can", "vcan0")
    93  	assert.NilError(t, err)
    94  	// when the reader reads
    95  	var g errgroup.Group
    96  	var readFrame can.Frame
    97  	g.Go(func() error {
    98  		rec := NewReceiver(reader)
    99  		if !rec.Receive() {
   100  			return fmt.Errorf("receive")
   101  		}
   102  		readFrame = rec.Frame()
   103  		return reader.Close()
   104  	})
   105  	// and the writer writes
   106  	writeFrame := can.Frame{ID: 32}
   107  	tr := NewTransmitter(writer)
   108  	ctx, done := context.WithTimeout(context.Background(), time.Second)
   109  	defer done()
   110  	assert.NilError(t, tr.TransmitFrame(ctx, writeFrame))
   111  	assert.NilError(t, writer.Close())
   112  	// then the written and read frames should be identical
   113  	assert.NilError(t, g.Wait())
   114  	assert.DeepEqual(t, writeFrame, readFrame)
   115  }
   116  
   117  func TestConn_WriteOnClosedFails(t *testing.T) {
   118  	requireVCAN0(t)
   119  	conn, err := Dial("can", "vcan0")
   120  	assert.NilError(t, err)
   121  	tr := NewTransmitter(conn)
   122  	ctx, done := context.WithTimeout(context.Background(), time.Second)
   123  	defer done()
   124  	assert.NilError(t, tr.TransmitFrame(ctx, can.Frame{}))
   125  	// When I close the connection and then write to it
   126  	assert.NilError(t, conn.Close())
   127  	// Then it should fail
   128  	assert.Assert(t, is.ErrorContains(tr.TransmitFrame(ctx, can.Frame{}), ""), "WriteFrame on a closed Conn should fail")
   129  }
   130  
   131  func TestConn_ReadOnClose(t *testing.T) {
   132  	requireVCAN0(t)
   133  	t.Run("close then read", func(t *testing.T) {
   134  		conn, err := Dial("can", "vcan0")
   135  		assert.NilError(t, err)
   136  		// When I close the connection and then read from it
   137  		assert.NilError(t, conn.Close())
   138  		rec := NewReceiver(conn)
   139  		assert.Assert(t, !rec.Receive())
   140  		assert.Assert(t, is.ErrorContains(rec.Err(), ""))
   141  	})
   142  	t.Run("read then close", func(t *testing.T) {
   143  		conn, err := Dial("can", "vcan0")
   144  		assert.NilError(t, err)
   145  		// And when I read from a connection
   146  		var g errgroup.Group
   147  		var receiveErr error
   148  		g.Go(func() error {
   149  			rec := NewReceiver(conn)
   150  			if rec.Receive() {
   151  				return fmt.Errorf("receive")
   152  			}
   153  			receiveErr = rec.Err()
   154  			return nil
   155  		})
   156  		runtime.Gosched()
   157  		// And then close it
   158  		assert.NilError(t, conn.Close())
   159  		// Then the read operation should fail
   160  		assert.NilError(t, g.Wait())
   161  		assert.Assert(t, is.ErrorContains(receiveErr, ""))
   162  	})
   163  }
   164  
   165  func requireVCAN0(t *testing.T) {
   166  	t.Helper()
   167  	if _, err := net.InterfaceByName("vcan0"); err != nil {
   168  		t.Skip("device vcan0 not available")
   169  	}
   170  }