1
0

udp_linux_writebatch_concurrent_test.go 1.5 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061
  1. //go:build linux && !android && !e2e_testing
  2. package udp
  3. import (
  4. "net/netip"
  5. "runtime"
  6. "sync"
  7. "testing"
  8. "github.com/stretchr/testify/require"
  9. )
  10. // The TUN reader and relay forwarding share a socket. Exercise their concurrent
  11. // batches against the actual GSO planner and scratch, without relying on a NIC.
  12. func TestWriteBatchConcurrent(t *testing.T) {
  13. const batches = 64
  14. w := newRewindTestWriter()
  15. sent := make(chan [][]byte, 2*batches)
  16. w.sendFn = func(start, n int) (int, error) {
  17. runtime.Gosched()
  18. sent <- capturePrepared(w, start, n)
  19. return n, nil
  20. }
  21. conn := &StdConn{bw: w}
  22. remote := netip.MustParseAddrPort("192.0.2.1:4242")
  23. var wg sync.WaitGroup
  24. start := make(chan struct{})
  25. for producer := range 2 {
  26. wg.Go(func() {
  27. <-start
  28. for i := range batches {
  29. var bufs [][]byte
  30. var addrs []netip.AddrPort
  31. for j := range 4 {
  32. bufs = append(bufs, []byte{byte(producer), byte(i), byte(j), 0})
  33. addrs = append(addrs, remote)
  34. }
  35. n, err := conn.WriteBatch(bufs, addrs)
  36. if err != nil || n != len(bufs) {
  37. t.Errorf("WriteBatch = %d, %v; want %d, nil", n, err, len(bufs))
  38. return
  39. }
  40. }
  41. })
  42. }
  43. close(start)
  44. wg.Wait()
  45. close(sent)
  46. var counts [2]int
  47. for packets := range sent {
  48. require.Len(t, packets, 4)
  49. producer := packets[0][0]
  50. require.Less(t, int(producer), len(counts))
  51. for j, packet := range packets {
  52. require.Equal(t, []byte{producer, byte(counts[producer]), byte(j), 0}, packet)
  53. }
  54. counts[producer]++
  55. }
  56. require.Equal(t, [2]int{batches, batches}, counts)
  57. }