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 }