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