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  }