mirror of
https://github.com/autc04/Retro68.git
synced 2024-07-31 10:29:19 +00:00
241 lines
6.4 KiB
Go
241 lines
6.4 KiB
Go
// Copyright 2012 The Go Authors. All rights reserved.
|
|
// Use of this source code is governed by a BSD-style
|
|
// license that can be found in the LICENSE file.
|
|
|
|
package httptest
|
|
|
|
import (
|
|
"bufio"
|
|
"io"
|
|
"net"
|
|
"net/http"
|
|
"testing"
|
|
)
|
|
|
|
type newServerFunc func(http.Handler) *Server
|
|
|
|
var newServers = map[string]newServerFunc{
|
|
"NewServer": NewServer,
|
|
"NewTLSServer": NewTLSServer,
|
|
|
|
// The manual variants of newServer create a Server manually by only filling
|
|
// in the exported fields of Server.
|
|
"NewServerManual": func(h http.Handler) *Server {
|
|
ts := &Server{Listener: newLocalListener(), Config: &http.Server{Handler: h}}
|
|
ts.Start()
|
|
return ts
|
|
},
|
|
"NewTLSServerManual": func(h http.Handler) *Server {
|
|
ts := &Server{Listener: newLocalListener(), Config: &http.Server{Handler: h}}
|
|
ts.StartTLS()
|
|
return ts
|
|
},
|
|
}
|
|
|
|
func TestServer(t *testing.T) {
|
|
for _, name := range []string{"NewServer", "NewServerManual"} {
|
|
t.Run(name, func(t *testing.T) {
|
|
newServer := newServers[name]
|
|
t.Run("Server", func(t *testing.T) { testServer(t, newServer) })
|
|
t.Run("GetAfterClose", func(t *testing.T) { testGetAfterClose(t, newServer) })
|
|
t.Run("ServerCloseBlocking", func(t *testing.T) { testServerCloseBlocking(t, newServer) })
|
|
t.Run("ServerCloseClientConnections", func(t *testing.T) { testServerCloseClientConnections(t, newServer) })
|
|
t.Run("ServerClientTransportType", func(t *testing.T) { testServerClientTransportType(t, newServer) })
|
|
})
|
|
}
|
|
for _, name := range []string{"NewTLSServer", "NewTLSServerManual"} {
|
|
t.Run(name, func(t *testing.T) {
|
|
newServer := newServers[name]
|
|
t.Run("ServerClient", func(t *testing.T) { testServerClient(t, newServer) })
|
|
t.Run("TLSServerClientTransportType", func(t *testing.T) { testTLSServerClientTransportType(t, newServer) })
|
|
})
|
|
}
|
|
}
|
|
|
|
func testServer(t *testing.T, newServer newServerFunc) {
|
|
ts := newServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
|
w.Write([]byte("hello"))
|
|
}))
|
|
defer ts.Close()
|
|
res, err := http.Get(ts.URL)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
got, err := io.ReadAll(res.Body)
|
|
res.Body.Close()
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if string(got) != "hello" {
|
|
t.Errorf("got %q, want hello", string(got))
|
|
}
|
|
}
|
|
|
|
// Issue 12781
|
|
func testGetAfterClose(t *testing.T, newServer newServerFunc) {
|
|
ts := newServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
|
w.Write([]byte("hello"))
|
|
}))
|
|
|
|
res, err := http.Get(ts.URL)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
got, err := io.ReadAll(res.Body)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if string(got) != "hello" {
|
|
t.Fatalf("got %q, want hello", string(got))
|
|
}
|
|
|
|
ts.Close()
|
|
|
|
res, err = http.Get(ts.URL)
|
|
if err == nil {
|
|
body, _ := io.ReadAll(res.Body)
|
|
t.Fatalf("Unexpected response after close: %v, %v, %s", res.Status, res.Header, body)
|
|
}
|
|
}
|
|
|
|
func testServerCloseBlocking(t *testing.T, newServer newServerFunc) {
|
|
ts := newServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
|
w.Write([]byte("hello"))
|
|
}))
|
|
dial := func() net.Conn {
|
|
c, err := net.Dial("tcp", ts.Listener.Addr().String())
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
return c
|
|
}
|
|
|
|
// Keep one connection in StateNew (connected, but not sending anything)
|
|
cnew := dial()
|
|
defer cnew.Close()
|
|
|
|
// Keep one connection in StateIdle (idle after a request)
|
|
cidle := dial()
|
|
defer cidle.Close()
|
|
cidle.Write([]byte("HEAD / HTTP/1.1\r\nHost: foo\r\n\r\n"))
|
|
_, err := http.ReadResponse(bufio.NewReader(cidle), nil)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
ts.Close() // test we don't hang here forever.
|
|
}
|
|
|
|
// Issue 14290
|
|
func testServerCloseClientConnections(t *testing.T, newServer newServerFunc) {
|
|
var s *Server
|
|
s = newServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
|
s.CloseClientConnections()
|
|
}))
|
|
defer s.Close()
|
|
res, err := http.Get(s.URL)
|
|
if err == nil {
|
|
res.Body.Close()
|
|
t.Fatalf("Unexpected response: %#v", res)
|
|
}
|
|
}
|
|
|
|
// Tests that the Server.Client method works and returns an http.Client that can hit
|
|
// NewTLSServer without cert warnings.
|
|
func testServerClient(t *testing.T, newTLSServer newServerFunc) {
|
|
ts := newTLSServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
|
w.Write([]byte("hello"))
|
|
}))
|
|
defer ts.Close()
|
|
client := ts.Client()
|
|
res, err := client.Get(ts.URL)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
got, err := io.ReadAll(res.Body)
|
|
res.Body.Close()
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if string(got) != "hello" {
|
|
t.Errorf("got %q, want hello", string(got))
|
|
}
|
|
}
|
|
|
|
// Tests that the Server.Client.Transport interface is implemented
|
|
// by a *http.Transport.
|
|
func testServerClientTransportType(t *testing.T, newServer newServerFunc) {
|
|
ts := newServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
|
}))
|
|
defer ts.Close()
|
|
client := ts.Client()
|
|
if _, ok := client.Transport.(*http.Transport); !ok {
|
|
t.Errorf("got %T, want *http.Transport", client.Transport)
|
|
}
|
|
}
|
|
|
|
// Tests that the TLS Server.Client.Transport interface is implemented
|
|
// by a *http.Transport.
|
|
func testTLSServerClientTransportType(t *testing.T, newTLSServer newServerFunc) {
|
|
ts := newTLSServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
|
}))
|
|
defer ts.Close()
|
|
client := ts.Client()
|
|
if _, ok := client.Transport.(*http.Transport); !ok {
|
|
t.Errorf("got %T, want *http.Transport", client.Transport)
|
|
}
|
|
}
|
|
|
|
type onlyCloseListener struct {
|
|
net.Listener
|
|
}
|
|
|
|
func (onlyCloseListener) Close() error { return nil }
|
|
|
|
// Issue 19729: panic in Server.Close for values created directly
|
|
// without a constructor (so the unexported client field is nil).
|
|
func TestServerZeroValueClose(t *testing.T) {
|
|
ts := &Server{
|
|
Listener: onlyCloseListener{},
|
|
Config: &http.Server{},
|
|
}
|
|
|
|
ts.Close() // tests that it doesn't panic
|
|
}
|
|
|
|
func TestTLSServerWithHTTP2(t *testing.T) {
|
|
modes := []struct {
|
|
name string
|
|
wantProto string
|
|
}{
|
|
{"http1", "HTTP/1.1"},
|
|
{"http2", "HTTP/2.0"},
|
|
}
|
|
|
|
for _, tt := range modes {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
cst := NewUnstartedServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
|
w.Header().Set("X-Proto", r.Proto)
|
|
}))
|
|
|
|
switch tt.name {
|
|
case "http2":
|
|
cst.EnableHTTP2 = true
|
|
cst.StartTLS()
|
|
default:
|
|
cst.Start()
|
|
}
|
|
|
|
defer cst.Close()
|
|
|
|
res, err := cst.Client().Get(cst.URL)
|
|
if err != nil {
|
|
t.Fatalf("Failed to make request: %v", err)
|
|
}
|
|
if g, w := res.Header.Get("X-Proto"), tt.wantProto; g != w {
|
|
t.Fatalf("X-Proto header mismatch:\n\tgot: %q\n\twant: %q", g, w)
|
|
}
|
|
})
|
|
}
|
|
}
|