github.com/mvdan/u-root-coreutils@v0.0.0-20230122170626-c2eef2898555/pkg/fdsrv/fdsrv_test.go (about)

     1  // Copyright 2022 the u-root Authors. All rights reserved
     2  // Use of this source code is governed by a BSD-style
     3  // license that can be found in the LICENSE file.
     4  
     5  package fdsrv
     6  
     7  import (
     8  	"os"
     9  	"syscall"
    10  	"testing"
    11  	"time"
    12  )
    13  
    14  // Returns an fd of the read side of a pipe that has the value 'x' written in
    15  // it.
    16  func xPipe(t *testing.T) int {
    17  	var p [2]int
    18  	if err := syscall.Pipe(p[:]); err != nil {
    19  		t.Fatal("pipe:", err)
    20  	}
    21  	if _, err := syscall.Write(p[1], []byte("x")); err != nil {
    22  		t.Fatal("write:", err)
    23  	}
    24  	if err := syscall.Close(p[1]); err != nil {
    25  		t.Fatal("close:", err)
    26  	}
    27  	return p[0]
    28  }
    29  
    30  // Returns an *Server, serving an xPipe with "some_nonce"
    31  func allocPipeFDs(t *testing.T, options ...func(*Server) error) *Server {
    32  	fd := xPipe(t)
    33  	fds, err := NewServer(fd, "some_nonce", options...)
    34  	if err != nil {
    35  		t.Fatal("alloc:", err)
    36  	}
    37  	if err := syscall.Close(fd); err != nil {
    38  		t.Fatal("close:", err)
    39  	}
    40  	return fds
    41  }
    42  
    43  // Read a string from an fd
    44  func readString(t *testing.T, fd int) string {
    45  	buf := make([]byte, 128)
    46  	n, err := syscall.Read(fd, buf)
    47  	if err != nil {
    48  		t.Fatal("read:", err)
    49  	}
    50  	return string(buf[:n])
    51  }
    52  
    53  // Gets a shared fd, makes sure we can read "x" from it
    54  func testSharedOK(t *testing.T, udspath, nonce string) {
    55  	sfd, err := GetSharedFD(udspath, nonce)
    56  	if err != nil {
    57  		t.Error("getsharedfd:", err)
    58  	}
    59  	got := readString(t, sfd)
    60  	if got != "x" {
    61  		t.Errorf("expected x, got %s", got)
    62  	}
    63  	if err := syscall.Close(sfd); err != nil {
    64  		t.Error("close:", err)
    65  	}
    66  }
    67  
    68  func TestPassFD(t *testing.T) {
    69  	fds := allocPipeFDs(t, WithServeOnce())
    70  
    71  	serveErr := make(chan error)
    72  	go func() {
    73  		serveErr <- fds.Serve()
    74  	}()
    75  
    76  	testSharedOK(t, fds.UDSPath(), "some_nonce")
    77  
    78  	fds.Close()
    79  	if err := <-serveErr; err != nil {
    80  		t.Errorf("Serve: %v", err)
    81  	}
    82  }
    83  
    84  func TestBadNonce(t *testing.T) {
    85  	fds := allocPipeFDs(t, WithServeOnce())
    86  
    87  	serveErr := make(chan error)
    88  	go func() {
    89  		serveErr <- fds.Serve()
    90  	}()
    91  
    92  	sfd, err := GetSharedFD(fds.UDSPath(), "bad_nonce")
    93  	if err == nil {
    94  		t.Errorf("should have failed, but got sfd %d", sfd)
    95  	}
    96  	fds.Close()
    97  	if err := <-serveErr; err != nil {
    98  		t.Errorf("Serve: %v", err)
    99  	}
   100  }
   101  
   102  func TestBadSubsetNonce(t *testing.T) {
   103  	fds := allocPipeFDs(t, WithServeOnce())
   104  
   105  	serveErr := make(chan error)
   106  	go func() {
   107  		serveErr <- fds.Serve()
   108  	}()
   109  
   110  	sfd, err := GetSharedFD(fds.UDSPath(), "some_non")
   111  	if err == nil {
   112  		t.Errorf("should have failed, but got sfd %d", sfd)
   113  	}
   114  	fds.Close()
   115  	if err := <-serveErr; err != nil {
   116  		t.Errorf("Serve: %v", err)
   117  	}
   118  }
   119  
   120  func TestBadEmptyNonce(t *testing.T) {
   121  	fds := allocPipeFDs(t, WithServeOnce())
   122  
   123  	serveErr := make(chan error)
   124  	go func() {
   125  		serveErr <- fds.Serve()
   126  	}()
   127  
   128  	sfd, err := GetSharedFD(fds.UDSPath(), "")
   129  	if err == nil {
   130  		t.Errorf("should have failed, but got sfd %d", sfd)
   131  	}
   132  
   133  	fds.Close()
   134  	if err := <-serveErr; err != nil {
   135  		t.Errorf("Serve: %v", err)
   136  	}
   137  }
   138  
   139  func TestEmptyNonce(t *testing.T) {
   140  	fds, err := NewServer(0, "")
   141  	if err == nil {
   142  		t.Error("should have failed to alloc")
   143  		fds.Close()
   144  	}
   145  }
   146  
   147  // Might flake, based on timing
   148  func TestTimeoutDoesntFire(t *testing.T) {
   149  	fds := allocPipeFDs(t, WithServeOnce(), WithTimeout(time.Second))
   150  
   151  	serveErr := make(chan error)
   152  	go func() {
   153  		serveErr <- fds.Serve()
   154  	}()
   155  
   156  	testSharedOK(t, fds.UDSPath(), "some_nonce")
   157  
   158  	fds.Close()
   159  	if err := <-serveErr; err != nil {
   160  		t.Errorf("Serve: %v", err)
   161  	}
   162  }
   163  
   164  // Might flake, based on timing
   165  func TestTimeoutFires(t *testing.T) {
   166  	fds := allocPipeFDs(t, WithServeOnce(), WithTimeout(100*time.Millisecond))
   167  
   168  	serveErr := make(chan error)
   169  	go func() {
   170  		serveErr <- fds.Serve()
   171  	}()
   172  
   173  	time.Sleep(time.Millisecond * 1000)
   174  
   175  	sfd, err := GetSharedFD(fds.UDSPath(), "some_nonce")
   176  	if err == nil {
   177  		t.Errorf("should have timed out, but got sfd %d", sfd)
   178  	}
   179  	fds.Close()
   180  	if err := <-serveErr; err != nil && !os.IsTimeout(err) {
   181  		t.Errorf("Serve: %v", err)
   182  	}
   183  }
   184  
   185  func TestWaitTimeout(t *testing.T) {
   186  	fds := allocPipeFDs(t, WithServeOnce(),
   187  		WithTimeout(time.Millisecond*10))
   188  
   189  	err := fds.Serve()
   190  	if err == nil || !os.IsTimeout(err) {
   191  		t.Error("expected timeout:", err)
   192  	}
   193  	fds.Close()
   194  }
   195  
   196  func TestMultiServe(t *testing.T) {
   197  	fds := allocPipeFDs(t, WithTimeout(time.Second*5))
   198  
   199  	serveErr := make(chan error)
   200  	go func() {
   201  		serveErr <- fds.Serve()
   202  	}()
   203  
   204  	testSharedOK(t, fds.UDSPath(), "some_nonce")
   205  	// The second reader won't see 'x', the pipe was already drained
   206  	sfd, err := GetSharedFD(fds.UDSPath(), "some_nonce")
   207  	if err != nil {
   208  		t.Error("getsharedfd:", err)
   209  	}
   210  	if err := syscall.Close(sfd); err != nil {
   211  		t.Error("close:", err)
   212  	}
   213  
   214  	fds.Close()
   215  	if err := <-serveErr; err != nil && !os.IsTimeout(err) {
   216  		t.Errorf("Serve: %v", err)
   217  	}
   218  }