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 }