Skip to content
File

Blob: util/bufconn/bufconn_test.go

go68 lines
1package bufconn_test
2 
3import (
4 "net"
5 "sync"
6 "testing"
7 "time"
8 
9 "go.miragespace.co/specter/util/bufconn"
10)
11 
12func TestClearedDeadlineDoesNotTimeoutLaterIO(t *testing.T) {
13 for _, direction := range []string{"read", "write"} {
14 t.Run(direction, func(t *testing.T) {
15 failures := make(chan error, 32)
16 var workers sync.WaitGroup
17 for range 32 {
18 workers.Go(func() {
19 for range 256 {
20 if err := exerciseDeadlineReset(direction); err != nil {
21 failures <- err
22 return
23 }
24 }
25 })
26 }
27 workers.Wait()
28 close(failures)
29 for err := range failures {
30 t.Errorf("I/O after clearing deadline: %v", err)
31 }
32 })
33 }
34}
35 
36func exerciseDeadlineReset(direction string) error {
37 conn, peer := bufconn.BufferedPipe(1)
38 setDeadline := conn.SetReadDeadline
39 if direction == "write" {
40 _, _ = conn.Write([]byte{0}) // Fill the pipe so the next write waits.
41 setDeadline = conn.SetWriteDeadline
42 }
43 // Expiry can already be running when the deadline is cleared. It must not
44 // time out an operation that starts after SetDeadline returns.
45 _ = setDeadline(time.Now())
46 _ = setDeadline(time.Time{})
47 
48 peerDone := make(chan struct{})
49 go func() {
50 defer close(peerDone)
51 time.Sleep(50 * time.Microsecond)
52 _, _ = transferByte(peer, direction != "write")
53 }()
54 _, err := transferByte(conn, direction == "write")
55 _ = conn.Close()
56 _ = peer.Close()
57 <-peerDone
58 return err
59}
60 
61func transferByte(conn net.Conn, write bool) (int, error) {
62 data := [1]byte{1}
63 if write {
64 return conn.Write(data[:])
65 }
66 return conn.Read(data[:])
67}