github.com/jshiv/can-go@v0.2.1-0.20210224011015-069e90e90bdf/pkg/socketcan/dialraw_linux_test.go (about)

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