github.com/blueinnovationsgroup/can-go@v0.0.0-20230518195432-d0567cda0028/pkg/socketcan/emulator_test.go (about) 1 package socketcan 2 3 import ( 4 "context" 5 "fmt" 6 "log" 7 "testing" 8 "time" 9 10 "github.com/blueinnovationsgroup/can-go" 11 "golang.org/x/sync/errgroup" 12 "gotest.tools/v3/assert" 13 is "gotest.tools/v3/assert/cmp" 14 ) 15 16 func TestEmulate_Close(t *testing.T) { 17 // Given: an emulator 18 e, err := NewEmulator() 19 assert.NilError(t, err) 20 ctx, cancel := context.WithTimeout(context.Background(), 500*time.Millisecond) 21 defer cancel() 22 // When: I start the emulator 23 g, ctx := errgroup.WithContext(ctx) 24 g.Go(func() error { 25 return e.Run(ctx) 26 }) 27 // Then: I should be able to close it 28 assert.NilError(t, g.Wait()) 29 } 30 31 func TestEmulate_SendToAll(t *testing.T) { 32 for _, tt := range []struct { 33 receivers int 34 }{ 35 {receivers: 1}, 36 {receivers: 5}, 37 {receivers: 100}, 38 } { 39 tt := tt 40 t.Run(fmt.Sprintf("receivers:%v", tt.receivers), func(t *testing.T) { 41 // Given: A listener with an Emulator 42 ctx, cancel := context.WithCancel(context.Background()) 43 eg, eCtx := errgroup.WithContext(ctx) 44 e, err := NewEmulator() 45 assert.NilError(t, err) 46 eg.Go(func() error { 47 return e.Run(eCtx) 48 }) 49 // When: I start multiple receivers connected to the Emulator 50 g := errgroup.Group{} 51 for i := 0; i < tt.receivers; i++ { 52 r, err := e.Receiver() 53 assert.NilError(t, err) 54 g.Go(func() error { 55 if ok := r.Receive(); !ok { 56 return fmt.Errorf("failed to receive CAN frame: %w", r.Err()) 57 } 58 if r.HasErrorFrame() { 59 return fmt.Errorf("received error frame: %v", r.ErrorFrame()) 60 } 61 return r.Err() 62 }) 63 } 64 // And then the emulator transmits a CAN frame 65 txFrame := can.Frame{ID: 42, Length: 4, Data: can.Data{1, 2, 3, 4}} 66 err = e.TransmitFrame(context.Background(), txFrame) 67 assert.NilError(t, err) 68 // Then: Every receiver should receive the frame and not return an error 69 assert.NilError(t, g.Wait()) 70 cancel() 71 assert.NilError(t, eg.Wait()) 72 }) 73 } 74 } 75 76 func TestEmulate_ConnectMany(t *testing.T) { 77 // TODO: Fix raciness or remove this test. 78 t.Skip("racy") 79 for _, tt := range []struct { 80 noTransmitters int 81 canFrames []can.Frame 82 }{ 83 { 84 noTransmitters: 1, 85 canFrames: []can.Frame{ 86 {ID: 42}, 87 {ID: 43, Length: 4, Data: can.Data{1, 2, 3, 4}}, 88 }, 89 }, 90 { 91 noTransmitters: 10, 92 canFrames: []can.Frame{ 93 {ID: 42}, 94 {ID: 43, Length: 4, Data: can.Data{1, 2, 3, 4}}, 95 {ID: 44, IsRemote: true}, 96 }, 97 }, 98 { 99 noTransmitters: 50, 100 canFrames: []can.Frame{ 101 {ID: 42}, 102 {ID: 43, Length: 4, Data: can.Data{1, 2, 3, 4}}, 103 {ID: 44, IsRemote: true}, 104 {ID: 45, Length: 7, Data: can.Data{1, 2, 3, 4, 5, 6, 7}}, 105 {ID: 46, IsExtended: false}, 106 {ID: 47, Length: 1, Data: can.Data{1}}, 107 {ID: 48, IsRemote: false}, 108 }, 109 }, 110 } { 111 tt := tt 112 name := fmt.Sprintf("transmitters:%v,frames:%v", tt.noTransmitters, len(tt.canFrames)) 113 t.Run(name, func(t *testing.T) { 114 // Given: A listener with an Emulator 115 e, err := NewEmulator(NoLogger) 116 assert.NilError(t, err) 117 ctx, cancel := context.WithCancel(context.Background()) 118 eg, eCtx := errgroup.WithContext(ctx) 119 eg.Go(func() error { 120 return e.Run(eCtx) 121 }) 122 r, err := e.Receiver() 123 assert.NilError(t, err) 124 receiver := errgroup.Group{} 125 receiver.Go(func() error { 126 for i := 0; i < len(tt.canFrames)*tt.noTransmitters; i++ { 127 i := i 128 if ok := r.Receive(); !ok { 129 cancel() 130 assert.NilError(t, eg.Wait()) 131 t.Fatal("Not all CAN frames were received", i, r.Err()) 132 } 133 assert.Assert(t, is.Contains(tt.canFrames, r.Frame())) 134 } 135 return nil 136 }) 137 // When: I connect multiple transmitters and transmit CAN frame on every transmitter 138 transmits, txCtx := errgroup.WithContext(ctx) 139 for i := 0; i < tt.noTransmitters; i++ { 140 transmits.Go(func() error { 141 conn, err := DialContext(txCtx, e.Addr().Network(), e.Addr().String()) 142 if err != nil { 143 return err 144 } 145 tx := NewTransmitter(conn) 146 for _, frame := range tt.canFrames { 147 if err := tx.TransmitFrame(txCtx, frame); err != nil { 148 log.Printf("failed to transmit frame: %+v\n", err) 149 return err 150 } 151 } 152 return conn.Close() 153 }) 154 } 155 assert.NilError(t, transmits.Wait()) 156 // Then: Every CAN frame should have been delivered to the emulator 157 assert.NilError(t, receiver.Wait()) 158 cancel() 159 assert.NilError(t, eg.Wait()) 160 }) 161 } 162 } 163 164 func TestEmulate_SendReceive(t *testing.T) { 165 for _, tt := range []struct { 166 transmitters int 167 receivers int 168 }{ 169 { 170 transmitters: 1, 171 receivers: 2, 172 }, 173 { 174 transmitters: 10, 175 receivers: 50, 176 }, 177 { 178 transmitters: 50, 179 receivers: 50, 180 }, 181 } { 182 tt := tt 183 name := fmt.Sprintf("transmitters: %v,receivers: %v", tt.transmitters, tt.receivers) 184 t.Run(name, func(t *testing.T) { 185 // Given: A listener and an emulator 186 e, err := NewEmulator() 187 assert.NilError(t, err) 188 ctx, cancel := context.WithCancel(context.Background()) 189 eg, eCtx := errgroup.WithContext(ctx) 190 eg.Go(func() error { 191 return e.Run(eCtx) 192 }) 193 canFrames := make(map[uint32]can.Frame) 194 canFrames[42] = can.Frame{ID: 42} 195 canFrames[43] = can.Frame{ID: 43, IsRemote: true} 196 canFrames[44] = can.Frame{ID: 44, IsExtended: true} 197 // When: I start a number of receivers 198 rx := errgroup.Group{} 199 for i := 0; i < tt.receivers; i++ { 200 r, err := e.Receiver() 201 assert.NilError(t, err) 202 rx.Go(func() error { 203 for i := 0; i < tt.transmitters*len(canFrames); i++ { 204 if ok := r.Receive(); !ok { 205 return fmt.Errorf("receive frames: %w", r.Err()) 206 } 207 if r.HasErrorFrame() { 208 return fmt.Errorf("received error frame: %v", r.ErrorFrame()) 209 } 210 if _, ok := canFrames[r.Frame().ID]; !ok { 211 return fmt.Errorf("received unexpected frame: %v", r.Frame()) 212 } 213 } 214 return nil 215 }) 216 } 217 // And then start a number of transmitters that will transmit a number of CAN frames 218 tx, txCtx := errgroup.WithContext(ctx) 219 for i := 0; i < tt.transmitters; i++ { 220 conn, err := DialContext(txCtx, e.Addr().Network(), e.Addr().String()) 221 assert.NilError(t, err) 222 tx.Go(func() (err error) { 223 t := NewTransmitter(conn) 224 for _, f := range canFrames { 225 if err := t.TransmitFrame(txCtx, f); err != nil { 226 return fmt.Errorf("transmit frame: %w", err) 227 } 228 } 229 if err := conn.Close(); err != nil { 230 return fmt.Errorf("close transmitter: %w", err) 231 } 232 return nil 233 }) 234 } 235 // Then: The transmissions should not fail 236 assert.NilError(t, tx.Wait()) 237 // And every receiver should receive every CAN frame 238 assert.NilError(t, rx.Wait()) 239 cancel() 240 assert.NilError(t, eg.Wait()) 241 }) 242 } 243 } 244 245 func TestEmulator_Isolation(t *testing.T) { 246 // Given 5 separate emulators 247 const nEmulators = 5 248 emulators := make([]*Emulator, nEmulators) 249 ctx, cancel := context.WithCancel(context.Background()) 250 eg, eCtx := errgroup.WithContext(ctx) 251 for i := 0; i < nEmulators; i++ { 252 e, err := NewEmulator() 253 assert.NilError(t, err) 254 emulators[i] = e 255 eg.Go(func() error { 256 return e.Run(eCtx) 257 }) 258 } 259 // When starting one transmitter/receiver pair per emulator sending 10 frames 260 const nFrames = 10 261 rx := errgroup.Group{} 262 tx := errgroup.Group{} 263 for i := 0; i < nEmulators; i++ { 264 i := i 265 r, err := emulators[i].Receiver() 266 assert.NilError(t, err) 267 rx.Go(func() error { 268 for j := 0; j < nFrames; j++ { 269 if ok := r.Receive(); !ok { 270 return fmt.Errorf("receive frame: %w", r.Err()) 271 } 272 if r.HasErrorFrame() { 273 return fmt.Errorf("received error frame: %v", r.ErrorFrame()) 274 } 275 if r.Frame().ID != uint32(i) { 276 return fmt.Errorf("receiver(%v) received unexpected frame: %v", i, r.Frame()) 277 } 278 } 279 return nil 280 }) 281 for j := 0; j < nFrames; j++ { 282 frame := can.Frame{ID: uint32(i)} 283 tx.Go(func() error { 284 return emulators[i].TransmitFrame(context.Background(), frame) 285 }) 286 } 287 } 288 // Then all transmitted frames should be received by correct receiver 289 assert.NilError(t, rx.Wait()) 290 assert.NilError(t, tx.Wait()) 291 cancel() 292 assert.NilError(t, eg.Wait()) 293 } 294 295 func TestEmulator_WaitForSenders(t *testing.T) { 296 // Given a started emulator 297 ctx, cancel := context.WithCancel(context.Background()) 298 eg, eCtx := errgroup.WithContext(ctx) 299 e, err := NewEmulator() 300 assert.NilError(t, err) 301 eg.Go(func() error { 302 return e.Run(eCtx) 303 }) 304 // When one transmitter is transmitting a frame 305 txg := errgroup.Group{} 306 txg.Go(func() error { 307 return e.TransmitFrame(context.Background(), can.Frame{ID: 1234}) 308 }) 309 // Then WaitForSenders should return without an error 310 err = e.WaitForSenders(1, time.Second) 311 assert.NilError(t, err) 312 assert.NilError(t, txg.Wait()) 313 cancel() 314 assert.NilError(t, eg.Wait()) 315 } 316 317 func TestEmulator_WaitForSenders_Multiple(t *testing.T) { 318 // Given a started emulator 319 ctx, cancel := context.WithCancel(context.Background()) 320 eg, eCtx := errgroup.WithContext(ctx) 321 e, err := NewEmulator() 322 assert.NilError(t, err) 323 eg.Go(func() error { 324 return e.Run(eCtx) 325 }) 326 // When one transmitter is transmitting a frame 327 txg := errgroup.Group{} 328 txg.Go(func() error { 329 return e.TransmitFrame(context.Background(), can.Frame{ID: 1234}) 330 }) 331 txg.Go(func() error { 332 return e.TransmitFrame(context.Background(), can.Frame{ID: 4321}) 333 }) 334 // Then WaitForSenders should return without an error 335 err = e.WaitForSenders(2, time.Second) 336 assert.NilError(t, err) 337 assert.NilError(t, txg.Wait()) 338 cancel() 339 assert.NilError(t, eg.Wait()) 340 } 341 342 func TestEmulator_WaitForSenders_Timeout(t *testing.T) { 343 // Given a started emulator 344 ctx, cancel := context.WithCancel(context.Background()) 345 eg, eCtx := errgroup.WithContext(ctx) 346 e, err := NewEmulator() 347 assert.NilError(t, err) 348 eg.Go(func() error { 349 return e.Run(eCtx) 350 }) 351 // When no transmitters have connected and transmitted frames 352 // Then WaitForSenders should timeout 353 err = e.WaitForSenders(1, 100*time.Millisecond) 354 assert.ErrorContains(t, err, "timeout") 355 cancel() 356 assert.NilError(t, eg.Wait()) 357 }