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
|
||
}
|