github.com/MerlinKodo/quic-go@v0.39.2/integrationtests/self/deadline_test.go (about) 1 package self_test 2 3 import ( 4 "context" 5 "fmt" 6 "io" 7 "net" 8 "time" 9 10 "github.com/MerlinKodo/quic-go" 11 12 . "github.com/onsi/ginkgo/v2" 13 . "github.com/onsi/gomega" 14 ) 15 16 var _ = Describe("Stream deadline tests", func() { 17 setup := func() (*quic.Listener, quic.Stream, quic.Stream) { 18 server, err := quic.ListenAddr("localhost:0", getTLSConfig(), getQuicConfig(nil)) 19 Expect(err).ToNot(HaveOccurred()) 20 strChan := make(chan quic.SendStream) 21 go func() { 22 defer GinkgoRecover() 23 conn, err := server.Accept(context.Background()) 24 Expect(err).ToNot(HaveOccurred()) 25 str, err := conn.AcceptStream(context.Background()) 26 Expect(err).ToNot(HaveOccurred()) 27 _, err = str.Read([]byte{0}) 28 Expect(err).ToNot(HaveOccurred()) 29 strChan <- str 30 }() 31 32 conn, err := quic.DialAddr( 33 context.Background(), 34 fmt.Sprintf("localhost:%d", server.Addr().(*net.UDPAddr).Port), 35 getTLSClientConfig(), 36 getQuicConfig(nil), 37 ) 38 Expect(err).ToNot(HaveOccurred()) 39 clientStr, err := conn.OpenStream() 40 Expect(err).ToNot(HaveOccurred()) 41 _, err = clientStr.Write([]byte{0}) // need to write one byte so the server learns about the stream 42 Expect(err).ToNot(HaveOccurred()) 43 var serverStr quic.Stream 44 Eventually(strChan).Should(Receive(&serverStr)) 45 return server, serverStr, clientStr 46 } 47 48 Context("read deadlines", func() { 49 It("completes a transfer when the deadline is set", func() { 50 server, serverStr, clientStr := setup() 51 defer server.Close() 52 53 const timeout = time.Millisecond 54 done := make(chan struct{}) 55 go func() { 56 defer GinkgoRecover() 57 _, err := serverStr.Write(PRDataLong) 58 Expect(err).ToNot(HaveOccurred()) 59 close(done) 60 }() 61 62 var bytesRead int 63 var timeoutCounter int 64 buf := make([]byte, 1<<10) 65 data := make([]byte, len(PRDataLong)) 66 clientStr.SetReadDeadline(time.Now().Add(timeout)) 67 for bytesRead < len(PRDataLong) { 68 n, err := clientStr.Read(buf) 69 if nerr, ok := err.(net.Error); ok && nerr.Timeout() { 70 timeoutCounter++ 71 clientStr.SetReadDeadline(time.Now().Add(timeout)) 72 } else { 73 Expect(err).ToNot(HaveOccurred()) 74 } 75 copy(data[bytesRead:], buf[:n]) 76 bytesRead += n 77 } 78 Expect(data).To(Equal(PRDataLong)) 79 // make sure the test actually worked and Read actually ran into the deadline a few times 80 Expect(timeoutCounter).To(BeNumerically(">=", 10)) 81 Eventually(done).Should(BeClosed()) 82 }) 83 84 It("completes a transfer when the deadline is set concurrently", func() { 85 server, serverStr, clientStr := setup() 86 defer server.Close() 87 88 const timeout = time.Millisecond 89 go func() { 90 defer GinkgoRecover() 91 _, err := serverStr.Write(PRDataLong) 92 Expect(err).ToNot(HaveOccurred()) 93 }() 94 95 var bytesRead int 96 var timeoutCounter int 97 buf := make([]byte, 1<<10) 98 data := make([]byte, len(PRDataLong)) 99 clientStr.SetReadDeadline(time.Now().Add(timeout)) 100 deadlineDone := make(chan struct{}) 101 received := make(chan struct{}) 102 go func() { 103 defer close(deadlineDone) 104 for { 105 select { 106 case <-received: 107 return 108 default: 109 time.Sleep(timeout) 110 } 111 clientStr.SetReadDeadline(time.Now().Add(timeout)) 112 } 113 }() 114 115 for bytesRead < len(PRDataLong) { 116 n, err := clientStr.Read(buf) 117 if nerr, ok := err.(net.Error); ok && nerr.Timeout() { 118 timeoutCounter++ 119 } else { 120 Expect(err).ToNot(HaveOccurred()) 121 } 122 copy(data[bytesRead:], buf[:n]) 123 bytesRead += n 124 } 125 close(received) 126 Expect(data).To(Equal(PRDataLong)) 127 // make sure the test actually worked an Read actually ran into the deadline a few times 128 Expect(timeoutCounter).To(BeNumerically(">=", 10)) 129 Eventually(deadlineDone).Should(BeClosed()) 130 }) 131 }) 132 133 Context("write deadlines", func() { 134 It("completes a transfer when the deadline is set", func() { 135 server, serverStr, clientStr := setup() 136 defer server.Close() 137 138 const timeout = time.Millisecond 139 done := make(chan struct{}) 140 go func() { 141 defer GinkgoRecover() 142 data, err := io.ReadAll(serverStr) 143 Expect(err).ToNot(HaveOccurred()) 144 Expect(data).To(Equal(PRDataLong)) 145 close(done) 146 }() 147 148 var bytesWritten int 149 var timeoutCounter int 150 clientStr.SetWriteDeadline(time.Now().Add(timeout)) 151 for bytesWritten < len(PRDataLong) { 152 n, err := clientStr.Write(PRDataLong[bytesWritten:]) 153 if nerr, ok := err.(net.Error); ok && nerr.Timeout() { 154 timeoutCounter++ 155 clientStr.SetWriteDeadline(time.Now().Add(timeout)) 156 } else { 157 Expect(err).ToNot(HaveOccurred()) 158 } 159 bytesWritten += n 160 } 161 clientStr.Close() 162 // make sure the test actually worked an Read actually ran into the deadline a few times 163 Expect(timeoutCounter).To(BeNumerically(">=", 10)) 164 Eventually(done).Should(BeClosed()) 165 }) 166 167 It("completes a transfer when the deadline is set concurrently", func() { 168 server, serverStr, clientStr := setup() 169 defer server.Close() 170 171 const timeout = time.Millisecond 172 readDone := make(chan struct{}) 173 go func() { 174 defer GinkgoRecover() 175 data, err := io.ReadAll(serverStr) 176 Expect(err).ToNot(HaveOccurred()) 177 Expect(data).To(Equal(PRDataLong)) 178 close(readDone) 179 }() 180 181 clientStr.SetWriteDeadline(time.Now().Add(timeout)) 182 deadlineDone := make(chan struct{}) 183 go func() { 184 defer close(deadlineDone) 185 for { 186 select { 187 case <-readDone: 188 return 189 default: 190 time.Sleep(timeout) 191 } 192 clientStr.SetWriteDeadline(time.Now().Add(timeout)) 193 } 194 }() 195 196 var bytesWritten int 197 var timeoutCounter int 198 clientStr.SetWriteDeadline(time.Now().Add(timeout)) 199 for bytesWritten < len(PRDataLong) { 200 n, err := clientStr.Write(PRDataLong[bytesWritten:]) 201 if nerr, ok := err.(net.Error); ok && nerr.Timeout() { 202 timeoutCounter++ 203 } else { 204 Expect(err).ToNot(HaveOccurred()) 205 } 206 bytesWritten += n 207 } 208 clientStr.Close() 209 // make sure the test actually worked an Read actually ran into the deadline a few times 210 Expect(timeoutCounter).To(BeNumerically(">=", 10)) 211 Eventually(readDone).Should(BeClosed()) 212 Eventually(deadlineDone).Should(BeClosed()) 213 }) 214 }) 215 })