github.com/ari-anchor/sei-tendermint@v0.0.0-20230519144642-dc826b7b56bb/privval/socket_listeners_test.go (about)

     1  package privval
     2  
     3  import (
     4  	"net"
     5  	"os"
     6  	"testing"
     7  	"time"
     8  
     9  	"github.com/stretchr/testify/require"
    10  
    11  	"github.com/ari-anchor/sei-tendermint/crypto/ed25519"
    12  )
    13  
    14  //-------------------------------------------
    15  // helper funcs
    16  
    17  func newPrivKey() ed25519.PrivKey {
    18  	return ed25519.GenPrivKey()
    19  }
    20  
    21  //-------------------------------------------
    22  // tests
    23  
    24  type listenerTestCase struct {
    25  	description string // For test reporting purposes.
    26  	listener    net.Listener
    27  	dialer      SocketDialer
    28  }
    29  
    30  // testUnixAddr will attempt to obtain a platform-independent temporary file
    31  // name for a Unix socket
    32  func testUnixAddr(t *testing.T) (string, error) {
    33  	// N.B. We can't use t.TempDir here because socket filenames have a
    34  	// restrictive length limit (~100 bytes) for silly historical reasons.
    35  	f, err := os.CreateTemp("", "tendermint-privval-test-*.sock")
    36  	if err != nil {
    37  		return "", err
    38  	}
    39  	addr := f.Name()
    40  	f.Close()
    41  	os.Remove(addr)                       // remove so the test can bind it
    42  	t.Cleanup(func() { os.Remove(addr) }) // clean up after the test
    43  	return addr, nil
    44  }
    45  
    46  func tcpListenerTestCase(t *testing.T, timeoutAccept, timeoutReadWrite time.Duration) listenerTestCase {
    47  	ln, err := net.Listen("tcp", "127.0.0.1:0")
    48  	if err != nil {
    49  		t.Fatal(err)
    50  	}
    51  
    52  	tcpLn := NewTCPListener(ln, newPrivKey())
    53  	TCPListenerTimeoutAccept(timeoutAccept)(tcpLn)
    54  	TCPListenerTimeoutReadWrite(timeoutReadWrite)(tcpLn)
    55  	return listenerTestCase{
    56  		description: "TCP",
    57  		listener:    tcpLn,
    58  		dialer:      DialTCPFn(ln.Addr().String(), testTimeoutReadWrite, newPrivKey()),
    59  	}
    60  }
    61  
    62  func unixListenerTestCase(t *testing.T, timeoutAccept, timeoutReadWrite time.Duration) listenerTestCase {
    63  	addr, err := testUnixAddr(t)
    64  	if err != nil {
    65  		t.Fatal(err)
    66  	}
    67  	ln, err := net.Listen("unix", addr)
    68  	if err != nil {
    69  		t.Fatal(err)
    70  	}
    71  
    72  	unixLn := NewUnixListener(ln)
    73  	UnixListenerTimeoutAccept(timeoutAccept)(unixLn)
    74  	UnixListenerTimeoutReadWrite(timeoutReadWrite)(unixLn)
    75  	return listenerTestCase{
    76  		description: "Unix",
    77  		listener:    unixLn,
    78  		dialer:      DialUnixFn(addr),
    79  	}
    80  }
    81  
    82  func listenerTestCases(t *testing.T, timeoutAccept, timeoutReadWrite time.Duration) []listenerTestCase {
    83  	return []listenerTestCase{
    84  		tcpListenerTestCase(t, timeoutAccept, timeoutReadWrite),
    85  		unixListenerTestCase(t, timeoutAccept, timeoutReadWrite),
    86  	}
    87  }
    88  
    89  func TestListenerTimeoutAccept(t *testing.T) {
    90  	for _, tc := range listenerTestCases(t, time.Millisecond, time.Second) {
    91  		_, err := tc.listener.Accept()
    92  		opErr, ok := err.(*net.OpError)
    93  		if !ok {
    94  			t.Fatalf("for %s listener, have %v, want *net.OpError", tc.description, err)
    95  		}
    96  
    97  		if have, want := opErr.Op, "accept"; have != want {
    98  			t.Errorf("for %s listener,  have %v, want %v", tc.description, have, want)
    99  		}
   100  	}
   101  }
   102  
   103  func TestListenerTimeoutReadWrite(t *testing.T) {
   104  	const (
   105  		// This needs to be long enough s.t. the Accept will definitely succeed:
   106  		timeoutAccept = time.Second
   107  		// This can be really short but in the TCP case, the accept can
   108  		// also trigger a timeoutReadWrite. Hence, we need to give it some time.
   109  		// Note: this controls how long this test actually runs.
   110  		timeoutReadWrite = 10 * time.Millisecond
   111  	)
   112  	for _, tc := range listenerTestCases(t, timeoutAccept, timeoutReadWrite) {
   113  		go func(dialer SocketDialer) {
   114  			_, err := dialer()
   115  			require.NoError(t, err)
   116  		}(tc.dialer)
   117  
   118  		c, err := tc.listener.Accept()
   119  		if err != nil {
   120  			t.Fatal(err)
   121  		}
   122  
   123  		// this will timeout because we don't write anything:
   124  		msg := make([]byte, 200)
   125  		_, err = c.Read(msg)
   126  		opErr, ok := err.(*net.OpError)
   127  		if !ok {
   128  			t.Fatalf("for %s listener, have %v, want *net.OpError", tc.description, err)
   129  		}
   130  
   131  		if have, want := opErr.Op, "read"; have != want {
   132  			t.Errorf("for %s listener, have %v, want %v", tc.description, have, want)
   133  		}
   134  
   135  		if !opErr.Timeout() {
   136  			t.Errorf("for %s listener, got unexpected error: have %v, want Timeout error", tc.description, opErr)
   137  		}
   138  	}
   139  }