116 lines
2.8 KiB
Go
116 lines
2.8 KiB
Go
|
|
package starnet
|
|||
|
|
|
|||
|
|
import (
|
|||
|
|
"io"
|
|||
|
|
"net"
|
|||
|
|
"net/http"
|
|||
|
|
"net/http/httptest"
|
|||
|
|
"testing"
|
|||
|
|
"time"
|
|||
|
|
)
|
|||
|
|
|
|||
|
|
func TestRequestTimeoutDoesNotMutateClientTimeout(t *testing.T) {
|
|||
|
|
s := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
|||
|
|
time.Sleep(200 * time.Millisecond)
|
|||
|
|
w.WriteHeader(http.StatusOK)
|
|||
|
|
}))
|
|||
|
|
defer s.Close()
|
|||
|
|
|
|||
|
|
client := NewClientNoErr()
|
|||
|
|
baseTimeout := client.HTTPClient().Timeout
|
|||
|
|
|
|||
|
|
_, err := client.Get(s.URL, WithTimeout(80*time.Millisecond))
|
|||
|
|
if err == nil {
|
|||
|
|
t.Fatal("expected request timeout error")
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
if client.HTTPClient().Timeout != baseTimeout {
|
|||
|
|
t.Fatalf("client timeout mutated: got=%v want=%v", client.HTTPClient().Timeout, baseTimeout)
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
resp, err := client.Get(s.URL, WithTimeout(400*time.Millisecond))
|
|||
|
|
if err != nil {
|
|||
|
|
t.Fatalf("second request should succeed with larger timeout: %v", err)
|
|||
|
|
}
|
|||
|
|
defer resp.Close()
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
func TestRequestTimeoutNoLingeringConnDeadline(t *testing.T) {
|
|||
|
|
s := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
|||
|
|
_, _ = io.Copy(io.Discard, r.Body)
|
|||
|
|
w.WriteHeader(http.StatusOK)
|
|||
|
|
_, _ = w.Write([]byte("ok"))
|
|||
|
|
}))
|
|||
|
|
defer s.Close()
|
|||
|
|
|
|||
|
|
client := NewClientNoErr()
|
|||
|
|
|
|||
|
|
resp1, err := client.Post(s.URL, WithBodyString("first"), WithTimeout(120*time.Millisecond))
|
|||
|
|
if err != nil {
|
|||
|
|
t.Fatalf("first request should succeed: %v", err)
|
|||
|
|
}
|
|||
|
|
_ = resp1.Close()
|
|||
|
|
|
|||
|
|
// 如果请求超时依赖连接级绝对 deadline,经过该等待后复用连接会出现误超时。
|
|||
|
|
time.Sleep(220 * time.Millisecond)
|
|||
|
|
|
|||
|
|
resp2, err := client.Post(s.URL, WithBodyString("second"), WithTimeout(1*time.Second))
|
|||
|
|
if err != nil {
|
|||
|
|
t.Fatalf("second request should not be affected by previous timeout window: %v", err)
|
|||
|
|
}
|
|||
|
|
_ = resp2.Close()
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
func TestConnReadDeadlineTimeoutAndRecover(t *testing.T) {
|
|||
|
|
ln, err := net.Listen("tcp", "127.0.0.1:0")
|
|||
|
|
if err != nil {
|
|||
|
|
t.Fatalf("listen error: %v", err)
|
|||
|
|
}
|
|||
|
|
defer ln.Close()
|
|||
|
|
|
|||
|
|
done := make(chan struct{})
|
|||
|
|
go func() {
|
|||
|
|
defer close(done)
|
|||
|
|
conn, err := ln.Accept()
|
|||
|
|
if err != nil {
|
|||
|
|
return
|
|||
|
|
}
|
|||
|
|
defer conn.Close()
|
|||
|
|
|
|||
|
|
time.Sleep(180 * time.Millisecond)
|
|||
|
|
_, _ = conn.Write([]byte("x"))
|
|||
|
|
}()
|
|||
|
|
|
|||
|
|
c, err := Dial("tcp", ln.Addr().String())
|
|||
|
|
if err != nil {
|
|||
|
|
t.Fatalf("dial error: %v", err)
|
|||
|
|
}
|
|||
|
|
defer c.Close()
|
|||
|
|
|
|||
|
|
if err := c.SetReadDeadline(time.Now().Add(60 * time.Millisecond)); err != nil {
|
|||
|
|
t.Fatalf("set read deadline error: %v", err)
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
buf := make([]byte, 1)
|
|||
|
|
_, err = c.Read(buf)
|
|||
|
|
if err == nil {
|
|||
|
|
t.Fatal("expected read timeout error")
|
|||
|
|
}
|
|||
|
|
if ne, ok := err.(net.Error); !ok || !ne.Timeout() {
|
|||
|
|
t.Fatalf("expected net timeout error, got: %v", err)
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
if err := c.SetReadDeadline(time.Time{}); err != nil {
|
|||
|
|
t.Fatalf("clear read deadline error: %v", err)
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
if _, err := io.ReadFull(c, buf); err != nil {
|
|||
|
|
t.Fatalf("read after clearing deadline should succeed: %v", err)
|
|||
|
|
}
|
|||
|
|
if string(buf) != "x" {
|
|||
|
|
t.Fatalf("unexpected payload: %q", string(buf))
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
<-done
|
|||
|
|
}
|