github.com/cilium/ebpf@v0.16.0/internal/epoll/poller_test.go (about) 1 package epoll 2 3 import ( 4 "errors" 5 "math" 6 "os" 7 "testing" 8 "time" 9 10 "github.com/cilium/ebpf/internal/unix" 11 "github.com/go-quicktest/qt" 12 ) 13 14 func TestPoller(t *testing.T) { 15 t.Parallel() 16 17 event, poller := mustNewPoller(t) 18 19 done := make(chan struct{}, 1) 20 read := func() { 21 defer func() { 22 done <- struct{}{} 23 }() 24 25 events := make([]unix.EpollEvent, 1) 26 27 n, err := poller.Wait(events, time.Time{}) 28 if errors.Is(err, os.ErrClosed) { 29 return 30 } 31 32 if err != nil { 33 t.Error("Error from wait:", err) 34 return 35 } 36 37 if n != 1 { 38 t.Errorf("Got %d instead of 1 events", n) 39 } 40 41 if e := events[0]; e.Pad != 42 { 42 t.Errorf("Incorrect value in EpollEvent.Pad: %d != 42", e.Pad) 43 } 44 } 45 46 if err := event.add(1); err != nil { 47 t.Fatal(err) 48 } 49 50 go read() 51 select { 52 case <-done: 53 case <-time.After(time.Second): 54 t.Fatal("Timed out") 55 } 56 57 if _, err := event.read(); err != nil { 58 t.Fatal(err) 59 } 60 61 go read() 62 select { 63 case <-done: 64 t.Fatal("Wait doesn't block") 65 case <-time.After(time.Second): 66 } 67 68 if err := poller.Close(); err != nil { 69 t.Fatal("Close returns an error:", err) 70 } 71 72 select { 73 case <-done: 74 case <-time.After(time.Second): 75 t.Fatal("Close doesn't unblock Wait") 76 } 77 78 if err := poller.Close(); !errors.Is(err, os.ErrClosed) { 79 t.Fatal("Closing a second time doesn't return ErrClosed:", err) 80 } 81 } 82 83 func TestPollerDeadline(t *testing.T) { 84 t.Parallel() 85 86 _, poller := mustNewPoller(t) 87 events := make([]unix.EpollEvent, 1) 88 89 _, err := poller.Wait(events, time.Now().Add(-time.Second)) 90 if !errors.Is(err, os.ErrDeadlineExceeded) { 91 t.Fatal("Expected os.ErrDeadlineExceeded on deadline in the past, got", err) 92 } 93 94 done := make(chan struct{}) 95 go func() { 96 defer close(done) 97 98 _, err := poller.Wait(events, time.Now().Add(math.MaxInt64)) 99 if !errors.Is(err, os.ErrClosed) { 100 t.Error("Expected os.ErrClosed when interrupting deadline, got", err) 101 } 102 }() 103 104 // Wait for the goroutine to enter the syscall. 105 time.Sleep(500 * time.Microsecond) 106 107 poller.Close() 108 <-done 109 } 110 111 func TestPollerFlush(t *testing.T) { 112 t.Parallel() 113 114 _, poller := mustNewPoller(t) 115 events := make([]unix.EpollEvent, 1) 116 117 done := make(chan struct{}) 118 go func() { 119 defer close(done) 120 121 _, err := poller.Wait(events, time.Time{}) 122 qt.Check(t, qt.ErrorIs(err, ErrFlushed)) 123 }() 124 125 // Wait for the goroutine to enter the syscall. 126 time.Sleep(500 * time.Microsecond) 127 128 poller.Flush() 129 <-done 130 } 131 132 func mustNewPoller(t *testing.T) (*eventFd, *Poller) { 133 t.Helper() 134 135 event, err := newEventFd() 136 if err != nil { 137 t.Fatal(err) 138 } 139 t.Cleanup(func() { event.close() }) 140 141 poller, err := New() 142 if err != nil { 143 t.Fatal(err) 144 } 145 t.Cleanup(func() { poller.Close() }) 146 147 if err := poller.Add(event.raw, 42); err != nil { 148 t.Fatal("Can't add fd:", err) 149 } 150 151 return event, poller 152 }