kubernetes http_test 源码
kubernetes http_test 代码
文件路径:/staging/src/k8s.io/apimachinery/pkg/util/net/http_test.go
//go:build go1.8
// +build go1.8
/*
Copyright 2016 The Kubernetes Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package net
import (
"crypto/tls"
"fmt"
"io"
"net"
"net/http"
"net/url"
"os"
"reflect"
"strings"
"testing"
"github.com/stretchr/testify/assert"
netutils "k8s.io/utils/net"
)
func TestGetClientIP(t *testing.T) {
ipString := "10.0.0.1"
ip := netutils.ParseIPSloppy(ipString)
invalidIPString := "invalidIPString"
testCases := []struct {
Request http.Request
ExpectedIP net.IP
}{
{
Request: http.Request{},
},
{
Request: http.Request{
Header: map[string][]string{
"X-Real-Ip": {ipString},
},
},
ExpectedIP: ip,
},
{
Request: http.Request{
Header: map[string][]string{
"X-Real-Ip": {invalidIPString},
},
},
},
{
Request: http.Request{
Header: map[string][]string{
"X-Forwarded-For": {ipString},
},
},
ExpectedIP: ip,
},
{
Request: http.Request{
Header: map[string][]string{
"X-Forwarded-For": {invalidIPString},
},
},
},
{
Request: http.Request{
Header: map[string][]string{
"X-Forwarded-For": {invalidIPString + "," + ipString},
},
},
ExpectedIP: ip,
},
{
Request: http.Request{
// RemoteAddr is in the form host:port
RemoteAddr: ipString + ":1234",
},
ExpectedIP: ip,
},
{
Request: http.Request{
RemoteAddr: invalidIPString,
},
},
{
Request: http.Request{
Header: map[string][]string{
"X-Forwarded-For": {invalidIPString},
},
// RemoteAddr is in the form host:port
RemoteAddr: ipString,
},
ExpectedIP: ip,
},
}
for i, test := range testCases {
if a, e := GetClientIP(&test.Request), test.ExpectedIP; reflect.DeepEqual(e, a) != true {
t.Fatalf("test case %d failed. expected: %v, actual: %v", i, e, a)
}
}
}
func TestAppendForwardedForHeader(t *testing.T) {
testCases := []struct {
addr, forwarded, expected string
}{
{"1.2.3.4:8000", "", "1.2.3.4"},
{"1.2.3.4:8000", "8.8.8.8", "8.8.8.8, 1.2.3.4"},
{"1.2.3.4:8000", "8.8.8.8, 1.2.3.4", "8.8.8.8, 1.2.3.4, 1.2.3.4"},
{"1.2.3.4:8000", "foo,bar", "foo,bar, 1.2.3.4"},
}
for i, test := range testCases {
req := &http.Request{
RemoteAddr: test.addr,
Header: make(http.Header),
}
if test.forwarded != "" {
req.Header.Set("X-Forwarded-For", test.forwarded)
}
AppendForwardedForHeader(req)
actual := req.Header.Get("X-Forwarded-For")
if actual != test.expected {
t.Errorf("[%d] Expected %q, Got %q", i, test.expected, actual)
}
}
}
func TestProxierWithNoProxyCIDR(t *testing.T) {
testCases := []struct {
name string
noProxy string
url string
expectedDelegated bool
}{
{
name: "no env",
url: "https://192.168.143.1/api",
expectedDelegated: true,
},
{
name: "no cidr",
noProxy: "192.168.63.1",
url: "https://192.168.143.1/api",
expectedDelegated: true,
},
{
name: "hostname",
noProxy: "192.168.63.0/24,192.168.143.0/24",
url: "https://my-hostname/api",
expectedDelegated: true,
},
{
name: "match second cidr",
noProxy: "192.168.63.0/24,192.168.143.0/24",
url: "https://192.168.143.1/api",
expectedDelegated: false,
},
{
name: "match second cidr with host:port",
noProxy: "192.168.63.0/24,192.168.143.0/24",
url: "https://192.168.143.1:8443/api",
expectedDelegated: false,
},
{
name: "IPv6 cidr",
noProxy: "2001:db8::/48",
url: "https://[2001:db8::1]/api",
expectedDelegated: false,
},
{
name: "IPv6+port cidr",
noProxy: "2001:db8::/48",
url: "https://[2001:db8::1]:8443/api",
expectedDelegated: false,
},
{
name: "IPv6, not matching cidr",
noProxy: "2001:db8::/48",
url: "https://[2001:db8:1::1]/api",
expectedDelegated: true,
},
{
name: "IPv6+port, not matching cidr",
noProxy: "2001:db8::/48",
url: "https://[2001:db8:1::1]:8443/api",
expectedDelegated: true,
},
}
for _, test := range testCases {
os.Setenv("NO_PROXY", test.noProxy)
actualDelegated := false
proxyFunc := NewProxierWithNoProxyCIDR(func(req *http.Request) (*url.URL, error) {
actualDelegated = true
return nil, nil
})
req, err := http.NewRequest("GET", test.url, nil)
if err != nil {
t.Errorf("%s: unexpected err: %v", test.name, err)
continue
}
if _, err := proxyFunc(req); err != nil {
t.Errorf("%s: unexpected err: %v", test.name, err)
continue
}
if test.expectedDelegated != actualDelegated {
t.Errorf("%s: expected %v, got %v", test.name, test.expectedDelegated, actualDelegated)
continue
}
}
}
type fakeTLSClientConfigHolder struct {
called bool
}
func (f *fakeTLSClientConfigHolder) TLSClientConfig() *tls.Config {
f.called = true
return nil
}
func (f *fakeTLSClientConfigHolder) RoundTrip(*http.Request) (*http.Response, error) {
return nil, nil
}
func TestTLSClientConfigHolder(t *testing.T) {
rt := &fakeTLSClientConfigHolder{}
TLSClientConfig(rt)
if !rt.called {
t.Errorf("didn't find tls config")
}
}
func TestJoinPreservingTrailingSlash(t *testing.T) {
tests := []struct {
a string
b string
want string
}{
// All empty
{"", "", ""},
// Empty a
{"", "/", "/"},
{"", "foo", "foo"},
{"", "/foo", "/foo"},
{"", "/foo/", "/foo/"},
// Empty b
{"/", "", "/"},
{"foo", "", "foo"},
{"/foo", "", "/foo"},
{"/foo/", "", "/foo/"},
// Both populated
{"/", "/", "/"},
{"foo", "foo", "foo/foo"},
{"/foo", "/foo", "/foo/foo"},
{"/foo/", "/foo/", "/foo/foo/"},
}
for _, tt := range tests {
name := fmt.Sprintf("%q+%q=%q", tt.a, tt.b, tt.want)
t.Run(name, func(t *testing.T) {
if got := JoinPreservingTrailingSlash(tt.a, tt.b); got != tt.want {
t.Errorf("JoinPreservingTrailingSlash() = %v, want %v", got, tt.want)
}
})
}
}
func TestAllowsHTTP2(t *testing.T) {
testcases := []struct {
Name string
Transport *http.Transport
ExpectAllows bool
}{
{
Name: "empty",
Transport: &http.Transport{},
ExpectAllows: true,
},
{
Name: "empty tlsconfig",
Transport: &http.Transport{TLSClientConfig: &tls.Config{}},
ExpectAllows: true,
},
{
Name: "zero-length NextProtos",
Transport: &http.Transport{TLSClientConfig: &tls.Config{NextProtos: []string{}}},
ExpectAllows: true,
},
{
Name: "includes h2 in NextProtos after",
Transport: &http.Transport{TLSClientConfig: &tls.Config{NextProtos: []string{"http/1.1", "h2"}}},
ExpectAllows: true,
},
{
Name: "includes h2 in NextProtos before",
Transport: &http.Transport{TLSClientConfig: &tls.Config{NextProtos: []string{"h2", "http/1.1"}}},
ExpectAllows: true,
},
{
Name: "includes h2 in NextProtos between",
Transport: &http.Transport{TLSClientConfig: &tls.Config{NextProtos: []string{"http/1.1", "h2", "h3"}}},
ExpectAllows: true,
},
{
Name: "excludes h2 in NextProtos",
Transport: &http.Transport{TLSClientConfig: &tls.Config{NextProtos: []string{"http/1.1"}}},
ExpectAllows: false,
},
}
for _, tc := range testcases {
t.Run(tc.Name, func(t *testing.T) {
allows := allowsHTTP2(tc.Transport)
if allows != tc.ExpectAllows {
t.Errorf("expected %v, got %v", tc.ExpectAllows, allows)
}
})
}
}
func TestSourceIPs(t *testing.T) {
tests := []struct {
name string
realIP string
forwardedFor string
remoteAddr string
expected []string
}{{
name: "no headers, missing remoteAddr",
expected: []string{},
}, {
name: "no headers, just remoteAddr host:port",
remoteAddr: "1.2.3.4:555",
expected: []string{"1.2.3.4"},
}, {
name: "no headers, just remoteAddr host",
remoteAddr: "1.2.3.4",
expected: []string{"1.2.3.4"},
}, {
name: "empty forwarded-for chain",
forwardedFor: " ",
remoteAddr: "1.2.3.4",
expected: []string{"1.2.3.4"},
}, {
name: "invalid forwarded-for chain",
forwardedFor: "garbage garbage values!",
remoteAddr: "1.2.3.4",
expected: []string{"1.2.3.4"},
}, {
name: "partially invalid forwarded-for chain",
forwardedFor: "garbage garbage values!,4.5.6.7",
remoteAddr: "1.2.3.4",
expected: []string{"4.5.6.7", "1.2.3.4"},
}, {
name: "valid forwarded-for chain",
forwardedFor: "120.120.120.126,2.2.2.2,4.5.6.7",
remoteAddr: "1.2.3.4",
expected: []string{"120.120.120.126", "2.2.2.2", "4.5.6.7", "1.2.3.4"},
}, {
name: "valid forwarded-for chain with redundant remoteAddr",
forwardedFor: "2.2.2.2,1.2.3.4",
remoteAddr: "1.2.3.4",
expected: []string{"2.2.2.2", "1.2.3.4"},
}, {
name: "invalid Real-Ip",
realIP: "garbage, just garbage!",
remoteAddr: "1.2.3.4",
expected: []string{"1.2.3.4"},
}, {
name: "invalid Real-Ip with forwarded-for",
realIP: "garbage, just garbage!",
forwardedFor: "2.2.2.2",
remoteAddr: "1.2.3.4",
expected: []string{"2.2.2.2", "1.2.3.4"},
}, {
name: "valid Real-Ip",
realIP: "2.2.2.2",
remoteAddr: "1.2.3.4",
expected: []string{"2.2.2.2", "1.2.3.4"},
}, {
name: "redundant Real-Ip",
realIP: "1.2.3.4",
remoteAddr: "1.2.3.4",
expected: []string{"1.2.3.4"},
}, {
name: "valid Real-Ip with forwarded-for",
realIP: "2.2.2.2",
forwardedFor: "120.120.120.126,4.5.6.7",
remoteAddr: "1.2.3.4",
expected: []string{"120.120.120.126", "4.5.6.7", "2.2.2.2", "1.2.3.4"},
}, {
name: "redundant Real-Ip with forwarded-for",
realIP: "2.2.2.2",
forwardedFor: "120.120.120.126,2.2.2.2,4.5.6.7",
remoteAddr: "1.2.3.4",
expected: []string{"120.120.120.126", "2.2.2.2", "4.5.6.7", "1.2.3.4"},
}, {
name: "full redundancy",
realIP: "1.2.3.4",
forwardedFor: "1.2.3.4",
remoteAddr: "1.2.3.4",
expected: []string{"1.2.3.4"},
}, {
name: "full ipv6",
realIP: "abcd:ef01:2345:6789:abcd:ef01:2345:6789",
forwardedFor: "aaaa:bbbb:cccc:dddd:eeee:ffff:0:1111,0:1111:2222:3333:4444:5555:6666:7777",
remoteAddr: "aaaa:aaaa:aaaa:aaaa:aaaa:aaaa:aaaa:aaaa",
expected: []string{
"aaaa:bbbb:cccc:dddd:eeee:ffff:0:1111",
"0:1111:2222:3333:4444:5555:6666:7777",
"abcd:ef01:2345:6789:abcd:ef01:2345:6789",
"aaaa:aaaa:aaaa:aaaa:aaaa:aaaa:aaaa:aaaa",
},
}, {
name: "mixed ipv4 ipv6",
forwardedFor: "aaaa:bbbb:cccc:dddd:eeee:ffff:0:1111,1.2.3.4",
remoteAddr: "0:0:0:0:0:ffff:102:304", // ipv6 equivalent to 1.2.3.4
expected: []string{
"aaaa:bbbb:cccc:dddd:eeee:ffff:0:1111",
"1.2.3.4",
},
}}
for _, test := range tests {
t.Run(test.name, func(t *testing.T) {
req, _ := http.NewRequest("GET", "https://cluster.k8s.io/apis/foobars/v1/foo/bar", nil)
req.RemoteAddr = test.remoteAddr
if test.forwardedFor != "" {
req.Header.Set("X-Forwarded-For", test.forwardedFor)
}
if test.realIP != "" {
req.Header.Set("X-Real-Ip", test.realIP)
}
actualIPs := SourceIPs(req)
actual := make([]string, len(actualIPs))
for i, ip := range actualIPs {
actual[i] = ip.String()
}
assert.Equal(t, test.expected, actual)
})
}
}
func TestParseWarningHeader(t *testing.T) {
tests := []struct {
name string
header string
wantResult WarningHeader
wantRemainder string
wantErr string
}{
// invalid cases
{
name: "empty",
header: ``,
wantErr: "fewer than 3 segments",
},
{
name: "bad code",
header: `A B`,
wantErr: "fewer than 3 segments",
},
{
name: "short code",
header: `1 - "text"`,
wantErr: "not 3 digits",
},
{
name: "bad code",
header: `A - "text"`,
wantErr: "not 3 digits",
},
{
name: "invalid date quoting",
header: ` 299 - "text\"\\\a\b\c" "Tue, 15 Nov 1994 08:12:31 GMT `,
wantErr: "unterminated date segment",
},
{
name: "invalid post-date",
header: ` 299 - "text\"\\\a\b\c" "Tue, 15 Nov 1994 08:12:31 GMT" other`,
wantErr: "unexpected token after warn-date",
},
{
name: "agent control character",
header: " 299 agent\u0000name \"text\"",
wantErr: "invalid agent",
},
{
name: "agent non-utf8 character",
header: " 299 agent\xc5name \"text\"",
wantErr: "invalid agent",
},
{
name: "text control character",
header: " 299 - \"text\u0000\"content",
wantErr: "invalid text",
},
{
name: "text non-utf8 character",
header: " 299 - \"text\xc5\"content",
wantErr: "invalid text",
},
// valid cases
{
name: "ok",
header: `299 - "text"`,
wantResult: WarningHeader{Code: 299, Agent: `-`, Text: `text`},
},
{
name: "ok",
header: `299 - "text\"\\\a\b\c"`,
wantResult: WarningHeader{Code: 299, Agent: `-`, Text: `text"\abc`},
},
// big code
{
name: "big code",
header: `321 - "text"`,
wantResult: WarningHeader{Code: 321, Agent: "-", Text: "text"},
},
// RFC 2047 decoding
{
name: "ok, rfc 2047, iso-8859-1, q",
header: `299 - "=?iso-8859-1?q?this=20is=20some=20text?="`,
wantResult: WarningHeader{Code: 299, Agent: `-`, Text: `this is some text`},
},
{
name: "ok, rfc 2047, utf-8, b",
header: `299 - "=?UTF-8?B?VGhpcyBpcyBhIGhvcnNleTog8J+Qjg==?= And =?UTF-8?B?VGhpcyBpcyBhIGhvcnNleTog8J+Qjg==?="`,
wantResult: WarningHeader{Code: 299, Agent: `-`, Text: `This is a horsey: ? And This is a horsey: ?`},
},
{
name: "ok, rfc 2047, utf-8, q",
header: `299 - "=?UTF-8?Q?This is a \"horsey\": =F0=9F=90=8E?="`,
wantResult: WarningHeader{Code: 299, Agent: `-`, Text: `This is a "horsey": ?`},
},
{
name: "ok, rfc 2047, unknown charset",
header: `299 - "=?UTF-9?Q?This is a horsey: =F0=9F=90=8E?="`,
wantResult: WarningHeader{Code: 299, Agent: "-", Text: `=?UTF-9?Q?This is a horsey: =F0=9F=90=8E?=`},
},
{
name: "ok with spaces",
header: ` 299 - "text\"\\\a\b\c" `,
wantResult: WarningHeader{Code: 299, Agent: `-`, Text: `text"\abc`},
},
{
name: "ok with date",
header: ` 299 - "text\"\\\a\b\c" "Tue, 15 Nov 1994 08:12:31 GMT" `,
wantResult: WarningHeader{Code: 299, Agent: `-`, Text: `text"\abc`},
},
{
name: "ok with date and comma",
header: ` 299 - "text\"\\\a\b\c" "Tue, 15 Nov 1994 08:12:31 GMT" , `,
wantResult: WarningHeader{Code: 299, Agent: `-`, Text: `text"\abc`},
},
{
name: "ok with comma",
header: ` 299 - "text\"\\\a\b\c" , `,
wantResult: WarningHeader{Code: 299, Agent: `-`, Text: `text"\abc`},
},
{
name: "ok with date and comma and remainder",
header: ` 299 - "text\"\\\a\b\c" "Tue, 15 Nov 1994 08:12:31 GMT" , remainder `,
wantResult: WarningHeader{Code: 299, Agent: `-`, Text: `text"\abc`},
wantRemainder: "remainder",
},
{
name: "ok with comma and remainder",
header: ` 299 - "text\"\\\a\b\c" ,remainder text,second remainder`,
wantResult: WarningHeader{Code: 299, Agent: `-`, Text: `text"\abc`},
wantRemainder: "remainder text,second remainder",
},
{
name: "ok with utf-8 content directly in warn-text",
header: ` 299 - "Test of Iñtërnâtiônàlizætiøn,???⛔" `,
wantResult: WarningHeader{Code: 299, Agent: `-`, Text: `Test of Iñtërnâtiônàlizætiøn,???⛔`},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
gotResult, gotRemainder, err := ParseWarningHeader(tt.header)
switch {
case err == nil && len(tt.wantErr) > 0:
t.Errorf("ParseWarningHeader() no error, expected error %q", tt.wantErr)
return
case err != nil && len(tt.wantErr) == 0:
t.Errorf("ParseWarningHeader() error %q, expected no error", err)
return
case err != nil && len(tt.wantErr) > 0 && !strings.Contains(err.Error(), tt.wantErr):
t.Errorf("ParseWarningHeader() error %q, expected error %q", err, tt.wantErr)
return
}
if err != nil {
return
}
if !reflect.DeepEqual(gotResult, tt.wantResult) {
t.Errorf("ParseWarningHeader() gotResult = %#v, want %#v", gotResult, tt.wantResult)
}
if gotRemainder != tt.wantRemainder {
t.Errorf("ParseWarningHeader() gotRemainder = %v, want %v", gotRemainder, tt.wantRemainder)
}
})
}
}
func TestNewWarningHeader(t *testing.T) {
tests := []struct {
name string
code int
agent string
text string
want string
wantErr string
}{
// invalid cases
{
name: "code too low",
code: -1,
agent: `-`,
text: `example warning`,
wantErr: "between 0 and 999",
},
{
name: "code too high",
code: 1000,
agent: `-`,
text: `example warning`,
wantErr: "between 0 and 999",
},
{
name: "agent with space",
code: 299,
agent: `test agent`,
text: `example warning`,
wantErr: `agent must be valid`,
},
{
name: "agent with newline",
code: 299,
agent: "test\nagent",
text: `example warning`,
wantErr: `agent must be valid`,
},
{
name: "agent with backslash",
code: 299,
agent: `test\agent`,
text: `example warning`,
wantErr: `agent must be valid`,
},
{
name: "agent with quote",
code: 299,
agent: `test"agent"`,
text: `example warning`,
wantErr: `agent must be valid`,
},
{
name: "agent with control character",
code: 299,
agent: "test\u0000agent",
text: `example warning`,
wantErr: `agent must be valid`,
},
{
name: "agent with non-UTF8",
code: 299,
agent: "test\xc5agent",
text: `example warning`,
wantErr: `agent must be valid`,
},
{
name: "text with newline",
code: 299,
agent: `-`,
text: "Test of new\nline",
wantErr: "text must be valid",
},
{
name: "text with control character",
code: 299,
agent: `-`,
text: "Test of control\u0000character",
wantErr: "text must be valid",
},
{
name: "text with non-UTF8",
code: 299,
agent: `-`,
text: "Test of control\xc5character",
wantErr: "text must be valid",
},
{
name: "valid empty text",
code: 299,
agent: `-`,
text: ``,
want: `299 - ""`,
},
{
name: "valid empty agent",
code: 299,
agent: ``,
text: `example warning`,
want: `299 - "example warning"`,
},
{
name: "valid low code",
code: 1,
agent: `-`,
text: `example warning`,
want: `001 - "example warning"`,
},
{
name: "valid high code",
code: 999,
agent: `-`,
text: `example warning`,
want: `999 - "example warning"`,
},
{
name: "valid utf-8",
code: 299,
agent: `-`,
text: `Test of "Iñtërnâtiônàlizætiøn,???⛔"`,
want: `299 - "Test of \"Iñtërnâtiônàlizætiøn,???⛔\""`,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
got, err := NewWarningHeader(tt.code, tt.agent, tt.text)
switch {
case err == nil && len(tt.wantErr) > 0:
t.Fatalf("ParseWarningHeader() no error, expected error %q", tt.wantErr)
case err != nil && len(tt.wantErr) == 0:
t.Fatalf("ParseWarningHeader() error %q, expected no error", err)
case err != nil && len(tt.wantErr) > 0 && !strings.Contains(err.Error(), tt.wantErr):
t.Fatalf("ParseWarningHeader() error %q, expected error %q", err, tt.wantErr)
}
if err != nil {
return
}
if got != tt.want {
t.Fatalf("NewWarningHeader() = %v, want %v", got, tt.want)
}
roundTrip, remaining, err := ParseWarningHeader(got)
if err != nil {
t.Fatalf("error roundtripping: %v", err)
}
if len(remaining) > 0 {
t.Fatalf("unexpected remainder roundtripping: %s", remaining)
}
agent := tt.agent
if len(agent) == 0 {
agent = "-"
}
expect := WarningHeader{Code: tt.code, Agent: agent, Text: tt.text}
if roundTrip != expect {
t.Fatalf("after round trip, want:\n%#v\ngot\n%#v", expect, roundTrip)
}
})
}
}
func TestParseWarningHeaders(t *testing.T) {
tests := []struct {
name string
headers []string
want []WarningHeader
wantErrs []string
}{
{
name: "empty",
headers: []string{},
want: nil,
wantErrs: []string{},
},
{
name: "multi-header with error",
headers: []string{
`299 - "warning 1.1",299 - "warning 1.2"`,
`299 - "warning 2", 299 - "warning unquoted`,
` 299 - "warning 3.1" , 299 - "warning 3.2" `,
},
want: []WarningHeader{
{Code: 299, Agent: "-", Text: "warning 1.1"},
{Code: 299, Agent: "-", Text: "warning 1.2"},
{Code: 299, Agent: "-", Text: "warning 2"},
{Code: 299, Agent: "-", Text: "warning 3.1"},
{Code: 299, Agent: "-", Text: "warning 3.2"},
},
wantErrs: []string{"invalid warning header: invalid quoted string: missing closing quote"},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
got, gotErrs := ParseWarningHeaders(tt.headers)
switch {
case len(gotErrs) != len(tt.wantErrs):
t.Fatalf("ParseWarningHeader() got %v, expected %v", gotErrs, tt.wantErrs)
case len(gotErrs) == len(tt.wantErrs) && len(gotErrs) > 0:
gotErrStrings := []string{}
for _, err := range gotErrs {
gotErrStrings = append(gotErrStrings, err.Error())
}
if !reflect.DeepEqual(gotErrStrings, tt.wantErrs) {
t.Fatalf("ParseWarningHeader() got %v, expected %v", gotErrs, tt.wantErrs)
}
}
if len(gotErrs) > 0 {
return
}
if !reflect.DeepEqual(got, tt.want) {
t.Errorf("ParseWarningHeaders() got %#v, want %#v", got, tt.want)
}
})
}
}
func TestIsProbableEOF(t *testing.T) {
tests := []struct {
name string
err error
expected bool
}{
{
name: "with no error",
expected: false,
},
{
name: "with EOF error",
err: io.EOF,
expected: true,
},
{
name: "with unexpected EOF error",
err: io.ErrUnexpectedEOF,
expected: true,
},
{
name: "with broken connection error",
err: fmt.Errorf("http: can't write HTTP request on broken connection"),
expected: true,
},
{
name: "with server sent GOAWAY error",
err: fmt.Errorf("error foo - http2: server sent GOAWAY and closed the connection - error bar"),
expected: true,
},
{
name: "with connection reset by peer error",
err: fmt.Errorf("error foo - connection reset by peer - error bar"),
expected: true,
},
{
name: "with use of closed network connection error",
err: fmt.Errorf("error foo - Use of closed network connection - error bar"),
expected: true,
},
{
name: "with url error",
err: &url.Error{
Err: io.ErrUnexpectedEOF,
},
expected: true,
},
{
name: "with unrecognized error",
err: fmt.Errorf("error foo"),
expected: false,
},
}
for _, test := range tests {
t.Run(test.name, func(t *testing.T) {
actual := IsProbableEOF(test.err)
assert.Equal(t, test.expected, actual)
})
}
}
func setEnv(key, value string) func() {
originalValue := os.Getenv(key)
os.Setenv(key, value)
return func() {
os.Setenv(key, originalValue)
}
}
func TestReadIdleTimeoutSeconds(t *testing.T) {
reset := setEnv("HTTP2_READ_IDLE_TIMEOUT_SECONDS", "60")
if e, a := 60, readIdleTimeoutSeconds(); e != a {
t.Errorf("expected %d, got %d", e, a)
}
reset()
reset = setEnv("HTTP2_READ_IDLE_TIMEOUT_SECONDS", "illegal value")
if e, a := 30, readIdleTimeoutSeconds(); e != a {
t.Errorf("expected %d, got %d", e, a)
}
reset()
}
func TestPingTimeoutSeconds(t *testing.T) {
reset := setEnv("HTTP2_PING_TIMEOUT_SECONDS", "60")
if e, a := 60, pingTimeoutSeconds(); e != a {
t.Errorf("expected %d, got %d", e, a)
}
reset()
reset = setEnv("HTTP2_PING_TIMEOUT_SECONDS", "illegal value")
if e, a := 15, pingTimeoutSeconds(); e != a {
t.Errorf("expected %d, got %d", e, a)
}
reset()
}
func Benchmark_ParseQuotedString(b *testing.B) {
str := `"The quick brown" fox jumps over the lazy dog`
b.ReportAllocs()
b.ResetTimer()
for i := 0; i < b.N; i++ {
quoted, remainder, err := parseQuotedString(str)
if err != nil {
b.Errorf("Unexpected error %s", err)
}
if quoted != "The quick brown" {
b.Errorf("Unexpected quoted string %s", quoted)
}
if remainder != "fox jumps over the lazy dog" {
b.Errorf("Unexpected remainder string %s", quoted)
}
}
}
相关信息
相关文章
0
赞
热门推荐
-
2、 - 优质文章
-
3、 gate.io
-
7、 golang
-
9、 openharmony
-
10、 Vue中input框自动聚焦