From a8ad6eea383853007a191c4a15283770b952a837 Mon Sep 17 00:00:00 2001 From: Marten Seemann Date: Tue, 18 Dec 2018 22:08:05 +0630 Subject: [PATCH] add integration tests for setting read and write deadlines --- integrationtests/self/deadline_test.go | 213 +++++++++++++++++++++++++ 1 file changed, 213 insertions(+) create mode 100644 integrationtests/self/deadline_test.go diff --git a/integrationtests/self/deadline_test.go b/integrationtests/self/deadline_test.go new file mode 100644 index 00000000..e65d0b3a --- /dev/null +++ b/integrationtests/self/deadline_test.go @@ -0,0 +1,213 @@ +package self + +import ( + "crypto/tls" + "fmt" + "io/ioutil" + "net" + "time" + + quic "github.com/lucas-clemente/quic-go" + "github.com/lucas-clemente/quic-go/integrationtests/tools/testserver" + "github.com/lucas-clemente/quic-go/internal/testdata" + + . "github.com/onsi/ginkgo" + . "github.com/onsi/gomega" +) + +var _ = Describe("Stream deadline tests", func() { + var ( + server quic.Listener + serverStr quic.Stream + clientStr quic.Stream + ) + + BeforeEach(func() { + var err error + server, err = quic.ListenAddr("localhost:0", testdata.GetTLSConfig(), nil) + Expect(err).ToNot(HaveOccurred()) + acceptedStream := make(chan struct{}) + go func() { + defer GinkgoRecover() + sess, err := server.Accept() + Expect(err).ToNot(HaveOccurred()) + serverStr, err = sess.AcceptStream() + Expect(err).ToNot(HaveOccurred()) + _, err = serverStr.Read([]byte{0}) + Expect(err).ToNot(HaveOccurred()) + close(acceptedStream) + }() + + sess, err := quic.DialAddr( + fmt.Sprintf("localhost:%d", server.Addr().(*net.UDPAddr).Port), + &tls.Config{RootCAs: testdata.GetRootCA()}, + nil, + ) + Expect(err).ToNot(HaveOccurred()) + clientStr, err = sess.OpenStream() + Expect(err).ToNot(HaveOccurred()) + _, err = clientStr.Write([]byte{0}) // need to write one byte so the server learns about the stream + Expect(err).ToNot(HaveOccurred()) + Eventually(acceptedStream).Should(BeClosed()) + }) + + AfterEach(func() { + Expect(server.Close()).To(Succeed()) + }) + + Context("read deadlines", func() { + It("completes a transfer when the deadline is set", func() { + const timeout = 20 * time.Millisecond + done := make(chan struct{}) + go func() { + defer GinkgoRecover() + _, err := serverStr.Write(testserver.PRDataLong) + Expect(err).ToNot(HaveOccurred()) + close(done) + }() + + var bytesRead int + var timeoutCounter int + buf := make([]byte, 1<<10) + data := make([]byte, len(testserver.PRDataLong)) + clientStr.SetReadDeadline(time.Now().Add(timeout)) + for bytesRead < len(testserver.PRDataLong) { + n, err := clientStr.Read(buf) + if nerr, ok := err.(net.Error); ok && nerr.Timeout() { + timeoutCounter++ + clientStr.SetReadDeadline(time.Now().Add(timeout)) + } else { + Expect(err).ToNot(HaveOccurred()) + } + copy(data[bytesRead:], buf[:n]) + bytesRead += n + } + Expect(data).To(Equal(testserver.PRDataLong)) + // make sure the test actually worked an Read actually ran into the deadline a few times + Expect(timeoutCounter).To(BeNumerically(">=", 10)) + Eventually(done).Should(BeClosed()) + }) + + It("completes a transfer when the deadline is set concurrently", func() { + const timeout = 20 * time.Millisecond + go func() { + defer GinkgoRecover() + _, err := serverStr.Write(testserver.PRDataLong) + Expect(err).ToNot(HaveOccurred()) + }() + + var bytesRead int + var timeoutCounter int + buf := make([]byte, 1<<10) + data := make([]byte, len(testserver.PRDataLong)) + clientStr.SetReadDeadline(time.Now().Add(timeout)) + deadlineDone := make(chan struct{}) + received := make(chan struct{}) + go func() { + defer close(deadlineDone) + for { + select { + case <-received: + return + default: + time.Sleep(timeout) + } + clientStr.SetReadDeadline(time.Now().Add(timeout)) + } + }() + + for bytesRead < len(testserver.PRDataLong) { + n, err := clientStr.Read(buf) + if nerr, ok := err.(net.Error); ok && nerr.Timeout() { + timeoutCounter++ + } else { + Expect(err).ToNot(HaveOccurred()) + } + copy(data[bytesRead:], buf[:n]) + bytesRead += n + } + close(received) + Expect(data).To(Equal(testserver.PRDataLong)) + // make sure the test actually worked an Read actually ran into the deadline a few times + Expect(timeoutCounter).To(BeNumerically(">=", 10)) + Eventually(deadlineDone).Should(BeClosed()) + }) + }) + + Context("write deadlines", func() { + It("completes a transfer when the deadline is set", func() { + const timeout = 20 * time.Millisecond + done := make(chan struct{}) + go func() { + defer GinkgoRecover() + data, err := ioutil.ReadAll(serverStr) + Expect(err).ToNot(HaveOccurred()) + Expect(data).To(Equal(testserver.PRDataLong)) + close(done) + }() + + var bytesWritten int + var timeoutCounter int + clientStr.SetWriteDeadline(time.Now().Add(timeout)) + for bytesWritten < len(testserver.PRDataLong) { + n, err := clientStr.Write(testserver.PRDataLong[bytesWritten:]) + if nerr, ok := err.(net.Error); ok && nerr.Timeout() { + timeoutCounter++ + clientStr.SetWriteDeadline(time.Now().Add(timeout)) + } else { + Expect(err).ToNot(HaveOccurred()) + } + bytesWritten += n + } + clientStr.Close() + // make sure the test actually worked an Read actually ran into the deadline a few times + Expect(timeoutCounter).To(BeNumerically(">=", 10)) + Eventually(done).Should(BeClosed()) + }) + + It("completes a transfer when the deadline is set concurrently", func() { + const timeout = 20 * time.Millisecond + readDone := make(chan struct{}) + go func() { + defer GinkgoRecover() + data, err := ioutil.ReadAll(serverStr) + Expect(err).ToNot(HaveOccurred()) + Expect(data).To(Equal(testserver.PRDataLong)) + close(readDone) + }() + + clientStr.SetWriteDeadline(time.Now().Add(timeout)) + deadlineDone := make(chan struct{}) + go func() { + defer close(deadlineDone) + for { + select { + case <-readDone: + return + default: + time.Sleep(timeout) + } + clientStr.SetWriteDeadline(time.Now().Add(timeout)) + } + }() + + var bytesWritten int + var timeoutCounter int + clientStr.SetWriteDeadline(time.Now().Add(timeout)) + for bytesWritten < len(testserver.PRDataLong) { + n, err := clientStr.Write(testserver.PRDataLong[bytesWritten:]) + if nerr, ok := err.(net.Error); ok && nerr.Timeout() { + timeoutCounter++ + } else { + Expect(err).ToNot(HaveOccurred()) + } + bytesWritten += n + } + clientStr.Close() + // make sure the test actually worked an Read actually ran into the deadline a few times + Expect(timeoutCounter).To(BeNumerically(">=", 10)) + Eventually(readDone).Should(BeClosed()) + Eventually(deadlineDone).Should(BeClosed()) + }) + }) +})