Moving to glide
Этот коммит содержится в:
119
vendor/github.com/braintree/manners/helpers_test.go
сгенерированный
поставляемый
Обычный файл
119
vendor/github.com/braintree/manners/helpers_test.go
сгенерированный
поставляемый
Обычный файл
@@ -0,0 +1,119 @@
|
||||
package manners
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"crypto/tls"
|
||||
"io/ioutil"
|
||||
"net"
|
||||
"net/http"
|
||||
"testing"
|
||||
)
|
||||
|
||||
// a simple step-controllable http client
|
||||
type client struct {
|
||||
tls bool
|
||||
addr net.Addr
|
||||
connected chan error
|
||||
sendrequest chan bool
|
||||
response chan *rawResponse
|
||||
closed chan bool
|
||||
}
|
||||
|
||||
type rawResponse struct {
|
||||
body []string
|
||||
err error
|
||||
}
|
||||
|
||||
func (c *client) Run() {
|
||||
go func() {
|
||||
var err error
|
||||
conn, err := net.Dial(c.addr.Network(), c.addr.String())
|
||||
if err != nil {
|
||||
c.connected <- err
|
||||
return
|
||||
}
|
||||
if c.tls {
|
||||
conn = tls.Client(conn, &tls.Config{InsecureSkipVerify: true})
|
||||
}
|
||||
c.connected <- nil
|
||||
for <-c.sendrequest {
|
||||
_, err = conn.Write([]byte("GET / HTTP/1.1\nHost: localhost:8000\n\n"))
|
||||
if err != nil {
|
||||
c.response <- &rawResponse{err: err}
|
||||
}
|
||||
// Read response; no content
|
||||
scanner := bufio.NewScanner(conn)
|
||||
var lines []string
|
||||
for scanner.Scan() {
|
||||
// our null handler doesn't send a body, so we know the request is
|
||||
// done when we reach the blank line after the headers
|
||||
line := scanner.Text()
|
||||
if line == "" {
|
||||
break
|
||||
}
|
||||
lines = append(lines, line)
|
||||
}
|
||||
c.response <- &rawResponse{lines, scanner.Err()}
|
||||
}
|
||||
conn.Close()
|
||||
ioutil.ReadAll(conn)
|
||||
c.closed <- true
|
||||
}()
|
||||
}
|
||||
|
||||
func newClient(addr net.Addr, tls bool) *client {
|
||||
return &client{
|
||||
addr: addr,
|
||||
tls: tls,
|
||||
connected: make(chan error),
|
||||
sendrequest: make(chan bool),
|
||||
response: make(chan *rawResponse),
|
||||
closed: make(chan bool),
|
||||
}
|
||||
}
|
||||
|
||||
// a handler that returns 200 ok with no body
|
||||
var nullHandler = http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {})
|
||||
|
||||
func startGenericServer(t *testing.T, server *GracefulServer, statechanged chan http.ConnState, runner func() error) (l net.Listener, errc chan error) {
|
||||
server.Addr = "localhost:0"
|
||||
server.Handler = nullHandler
|
||||
if statechanged != nil {
|
||||
// Wrap the ConnState handler with something that will notify
|
||||
// the statechanged channel when a state change happens
|
||||
server.ConnState = func(conn net.Conn, newState http.ConnState) {
|
||||
statechanged <- newState
|
||||
}
|
||||
}
|
||||
|
||||
server.up = make(chan net.Listener)
|
||||
exitchan := make(chan error)
|
||||
|
||||
go func() {
|
||||
exitchan <- runner()
|
||||
}()
|
||||
|
||||
// wait for server socket to be bound
|
||||
select {
|
||||
case l = <-server.up:
|
||||
// all good
|
||||
|
||||
case err := <-exitchan:
|
||||
// all bad
|
||||
t.Fatal("Server failed to start", err)
|
||||
}
|
||||
return l, exitchan
|
||||
}
|
||||
|
||||
func startServer(t *testing.T, server *GracefulServer, statechanged chan http.ConnState) (
|
||||
l net.Listener, errc chan error) {
|
||||
return startGenericServer(t, server, statechanged, server.ListenAndServe)
|
||||
}
|
||||
|
||||
func startTLSServer(t *testing.T, server *GracefulServer, certFile, keyFile string, statechanged chan http.ConnState) (l net.Listener, errc chan error) {
|
||||
runner := func() error {
|
||||
return server.ListenAndServeTLS(certFile, keyFile)
|
||||
}
|
||||
|
||||
return startGenericServer(t, server, statechanged, runner)
|
||||
}
|
||||
289
vendor/github.com/braintree/manners/server_test.go
сгенерированный
поставляемый
Обычный файл
289
vendor/github.com/braintree/manners/server_test.go
сгенерированный
поставляемый
Обычный файл
@@ -0,0 +1,289 @@
|
||||
package manners
|
||||
|
||||
import (
|
||||
"net"
|
||||
"net/http"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
helpers "github.com/braintree/manners/test_helpers"
|
||||
)
|
||||
|
||||
type httpInterface interface {
|
||||
ListenAndServe() error
|
||||
ListenAndServeTLS(certFile, keyFile string) error
|
||||
Serve(listener net.Listener) error
|
||||
}
|
||||
|
||||
// Test that the method signatures of the methods we override from net/http/Server match those of the original.
|
||||
func TestInterface(t *testing.T) {
|
||||
var original, ours interface{}
|
||||
original = &http.Server{}
|
||||
ours = &GracefulServer{}
|
||||
if _, ok := original.(httpInterface); !ok {
|
||||
t.Errorf("httpInterface definition does not match the canonical server!")
|
||||
}
|
||||
if _, ok := ours.(httpInterface); !ok {
|
||||
t.Errorf("GracefulServer does not implement httpInterface")
|
||||
}
|
||||
}
|
||||
|
||||
// Tests that the server allows in-flight requests to complete
|
||||
// before shutting down.
|
||||
func TestGracefulness(t *testing.T) {
|
||||
server := NewServer()
|
||||
wg := helpers.NewWaitGroup()
|
||||
server.wg = wg
|
||||
statechanged := make(chan http.ConnState)
|
||||
listener, exitchan := startServer(t, server, statechanged)
|
||||
|
||||
client := newClient(listener.Addr(), false)
|
||||
client.Run()
|
||||
|
||||
// wait for client to connect, but don't let it send the request yet
|
||||
if err := <-client.connected; err != nil {
|
||||
t.Fatal("Client failed to connect to server", err)
|
||||
}
|
||||
// Even though the client is connected, the server ConnState handler may
|
||||
// not know about that yet. So wait until it is called.
|
||||
waitForState(t, statechanged, http.StateNew, "Request not received")
|
||||
|
||||
server.Close()
|
||||
|
||||
waiting := <-wg.WaitCalled
|
||||
if waiting < 1 {
|
||||
t.Errorf("Expected the waitgroup to equal 1 at shutdown; actually %d", waiting)
|
||||
}
|
||||
|
||||
// allow the client to finish sending the request and make sure the server exits after
|
||||
// (client will be in connected but idle state at that point)
|
||||
client.sendrequest <- true
|
||||
close(client.sendrequest)
|
||||
if err := <-exitchan; err != nil {
|
||||
t.Error("Unexpected error during shutdown", err)
|
||||
}
|
||||
}
|
||||
|
||||
// Tests that starting the server and closing in 2 new, separate goroutines doesnot
|
||||
// get flagged by the race detector (need to run 'go test' w/the -race flag)
|
||||
func TestRacyClose(t *testing.T) {
|
||||
go func() {
|
||||
ListenAndServe(":9000", nil)
|
||||
}()
|
||||
|
||||
go func() {
|
||||
Close()
|
||||
}()
|
||||
}
|
||||
|
||||
// Tests that the server begins to shut down when told to and does not accept
|
||||
// new requests once shutdown has begun
|
||||
func TestShutdown(t *testing.T) {
|
||||
server := NewServer()
|
||||
wg := helpers.NewWaitGroup()
|
||||
server.wg = wg
|
||||
statechanged := make(chan http.ConnState)
|
||||
listener, exitchan := startServer(t, server, statechanged)
|
||||
|
||||
client1 := newClient(listener.Addr(), false)
|
||||
client1.Run()
|
||||
|
||||
// wait for client1 to connect
|
||||
if err := <-client1.connected; err != nil {
|
||||
t.Fatal("Client failed to connect to server", err)
|
||||
}
|
||||
// Even though the client is connected, the server ConnState handler may
|
||||
// not know about that yet. So wait until it is called.
|
||||
waitForState(t, statechanged, http.StateNew, "Request not received")
|
||||
|
||||
// start the shutdown; once it hits waitgroup.Wait()
|
||||
// the listener should of been closed, though client1 is still connected
|
||||
if server.Close() != true {
|
||||
t.Fatal("first call to Close returned false")
|
||||
}
|
||||
if server.Close() != false {
|
||||
t.Fatal("second call to Close returned true")
|
||||
}
|
||||
|
||||
waiting := <-wg.WaitCalled
|
||||
if waiting != 1 {
|
||||
t.Errorf("Waitcount should be one, got %d", waiting)
|
||||
}
|
||||
|
||||
// should get connection refused at this point
|
||||
client2 := newClient(listener.Addr(), false)
|
||||
client2.Run()
|
||||
|
||||
if err := <-client2.connected; err == nil {
|
||||
t.Fatal("client2 connected when it should of received connection refused")
|
||||
}
|
||||
|
||||
// let client1 finish so the server can exit
|
||||
close(client1.sendrequest) // don't bother sending an actual request
|
||||
|
||||
<-exitchan
|
||||
}
|
||||
|
||||
// If a request is sent to a closed server via a kept alive connection then
|
||||
// the server closes the connection upon receiving the request.
|
||||
func TestRequestAfterClose(t *testing.T) {
|
||||
// Given
|
||||
server := NewServer()
|
||||
srvStateChangedCh := make(chan http.ConnState, 100)
|
||||
listener, srvClosedCh := startServer(t, server, srvStateChangedCh)
|
||||
|
||||
client := newClient(listener.Addr(), false)
|
||||
client.Run()
|
||||
<-client.connected
|
||||
client.sendrequest <- true
|
||||
<-client.response
|
||||
|
||||
server.Close()
|
||||
if err := <-srvClosedCh; err != nil {
|
||||
t.Error("Unexpected error during shutdown", err)
|
||||
}
|
||||
|
||||
// When
|
||||
client.sendrequest <- true
|
||||
rr := <-client.response
|
||||
|
||||
// Then
|
||||
if rr.body != nil || rr.err != nil {
|
||||
t.Errorf("Request should be rejected, body=%v, err=%v", rr.body, rr.err)
|
||||
}
|
||||
}
|
||||
|
||||
func waitForState(t *testing.T, waiter chan http.ConnState, state http.ConnState, errmsg string) {
|
||||
for {
|
||||
select {
|
||||
case ns := <-waiter:
|
||||
if ns == state {
|
||||
return
|
||||
}
|
||||
case <-time.After(time.Second):
|
||||
t.Fatal(errmsg)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Test that a request moving from active->idle->active using an actual
|
||||
// network connection still results in a corect shutdown
|
||||
func TestStateTransitionActiveIdleActive(t *testing.T) {
|
||||
server := NewServer()
|
||||
wg := helpers.NewWaitGroup()
|
||||
statechanged := make(chan http.ConnState)
|
||||
server.wg = wg
|
||||
listener, exitchan := startServer(t, server, statechanged)
|
||||
|
||||
client := newClient(listener.Addr(), false)
|
||||
client.Run()
|
||||
|
||||
// wait for client to connect, but don't let it send the request
|
||||
if err := <-client.connected; err != nil {
|
||||
t.Fatal("Client failed to connect to server", err)
|
||||
}
|
||||
|
||||
for i := 0; i < 2; i++ {
|
||||
client.sendrequest <- true
|
||||
waitForState(t, statechanged, http.StateActive, "Client failed to reach active state")
|
||||
<-client.response
|
||||
waitForState(t, statechanged, http.StateIdle, "Client failed to reach idle state")
|
||||
}
|
||||
|
||||
// client is now in an idle state
|
||||
|
||||
server.Close()
|
||||
waiting := <-wg.WaitCalled
|
||||
if waiting != 0 {
|
||||
t.Errorf("Waitcount should be zero, got %d", waiting)
|
||||
}
|
||||
|
||||
if err := <-exitchan; err != nil {
|
||||
t.Error("Unexpected error during shutdown", err)
|
||||
}
|
||||
}
|
||||
|
||||
// Test state transitions from new->active->-idle->closed using an actual
|
||||
// network connection and make sure the waitgroup count is correct at the end.
|
||||
func TestStateTransitionActiveIdleClosed(t *testing.T) {
|
||||
var (
|
||||
listener net.Listener
|
||||
exitchan chan error
|
||||
)
|
||||
|
||||
keyFile, err1 := helpers.NewTempFile(helpers.Key)
|
||||
certFile, err2 := helpers.NewTempFile(helpers.Cert)
|
||||
defer keyFile.Unlink()
|
||||
defer certFile.Unlink()
|
||||
|
||||
if err1 != nil || err2 != nil {
|
||||
t.Fatal("Failed to create temporary files", err1, err2)
|
||||
}
|
||||
|
||||
for _, withTLS := range []bool{false, true} {
|
||||
server := NewServer()
|
||||
wg := helpers.NewWaitGroup()
|
||||
statechanged := make(chan http.ConnState)
|
||||
server.wg = wg
|
||||
if withTLS {
|
||||
listener, exitchan = startTLSServer(t, server, certFile.Name(), keyFile.Name(), statechanged)
|
||||
} else {
|
||||
listener, exitchan = startServer(t, server, statechanged)
|
||||
}
|
||||
|
||||
client := newClient(listener.Addr(), withTLS)
|
||||
client.Run()
|
||||
|
||||
// wait for client to connect, but don't let it send the request
|
||||
if err := <-client.connected; err != nil {
|
||||
t.Fatal("Client failed to connect to server", err)
|
||||
}
|
||||
|
||||
client.sendrequest <- true
|
||||
waitForState(t, statechanged, http.StateActive, "Client failed to reach active state")
|
||||
|
||||
rr := <-client.response
|
||||
if rr.err != nil {
|
||||
t.Fatalf("tls=%t unexpected error from client %s", withTLS, rr.err)
|
||||
}
|
||||
|
||||
waitForState(t, statechanged, http.StateIdle, "Client failed to reach idle state")
|
||||
|
||||
// client is now in an idle state
|
||||
close(client.sendrequest)
|
||||
<-client.closed
|
||||
waitForState(t, statechanged, http.StateClosed, "Client failed to reach closed state")
|
||||
|
||||
server.Close()
|
||||
waiting := <-wg.WaitCalled
|
||||
if waiting != 0 {
|
||||
t.Errorf("Waitcount should be zero, got %d", waiting)
|
||||
}
|
||||
|
||||
if err := <-exitchan; err != nil {
|
||||
t.Error("Unexpected error during shutdown", err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestRoutinesCount(t *testing.T) {
|
||||
var count int
|
||||
server := NewServer()
|
||||
|
||||
count = server.RoutinesCount()
|
||||
if count != 0 {
|
||||
t.Errorf("Expected the routines count to equal 0; actually %d", count)
|
||||
}
|
||||
|
||||
server.StartRoutine()
|
||||
count = server.RoutinesCount()
|
||||
if count != 1 {
|
||||
t.Errorf("Expected the routines count to equal 1; actually %d", count)
|
||||
}
|
||||
|
||||
server.FinishRoutine()
|
||||
count = server.RoutinesCount()
|
||||
if count != 0 {
|
||||
t.Errorf("Expected the routines count to equal 0; actually %d", count)
|
||||
}
|
||||
}
|
||||
29
vendor/github.com/braintree/manners/test_helpers/certs.go
сгенерированный
поставляемый
Обычный файл
29
vendor/github.com/braintree/manners/test_helpers/certs.go
сгенерированный
поставляемый
Обычный файл
@@ -0,0 +1,29 @@
|
||||
package test_helpers
|
||||
|
||||
// A PEM-encoded TLS cert with SAN IPs "127.0.0.1" and "[::1]", expiring at the
|
||||
// last second of 2049 (the end of ASN.1 time).
|
||||
|
||||
// generated from src/pkg/crypto/tls:
|
||||
// go run generate_cert.go --rsa-bits 512 --host 127.0.0.1,::1,example.com --ca --start-date "Jan 1 00:00:00 1970" --duration=1000000h
|
||||
var (
|
||||
Cert = []byte(`-----BEGIN CERTIFICATE-----
|
||||
MIIBdzCCASOgAwIBAgIBADALBgkqhkiG9w0BAQUwEjEQMA4GA1UEChMHQWNtZSBD
|
||||
bzAeFw03MDAxMDEwMDAwMDBaFw00OTEyMzEyMzU5NTlaMBIxEDAOBgNVBAoTB0Fj
|
||||
bWUgQ28wWjALBgkqhkiG9w0BAQEDSwAwSAJBAN55NcYKZeInyTuhcCwFMhDHCmwa
|
||||
IUSdtXdcbItRB/yfXGBhiex00IaLXQnSU+QZPRZWYqeTEbFSgihqi1PUDy8CAwEA
|
||||
AaNoMGYwDgYDVR0PAQH/BAQDAgCkMBMGA1UdJQQMMAoGCCsGAQUFBwMBMA8GA1Ud
|
||||
EwEB/wQFMAMBAf8wLgYDVR0RBCcwJYILZXhhbXBsZS5jb22HBH8AAAGHEAAAAAAA
|
||||
AAAAAAAAAAAAAAEwCwYJKoZIhvcNAQEFA0EAAoQn/ytgqpiLcZu9XKbCJsJcvkgk
|
||||
Se6AbGXgSlq+ZCEVo0qIwSgeBqmsJxUu7NCSOwVJLYNEBO2DtIxoYVk+MA==
|
||||
-----END CERTIFICATE-----`)
|
||||
|
||||
Key = []byte(`-----BEGIN RSA PRIVATE KEY-----
|
||||
MIIBPAIBAAJBAN55NcYKZeInyTuhcCwFMhDHCmwaIUSdtXdcbItRB/yfXGBhiex0
|
||||
0IaLXQnSU+QZPRZWYqeTEbFSgihqi1PUDy8CAwEAAQJBAQdUx66rfh8sYsgfdcvV
|
||||
NoafYpnEcB5s4m/vSVe6SU7dCK6eYec9f9wpT353ljhDUHq3EbmE4foNzJngh35d
|
||||
AekCIQDhRQG5Li0Wj8TM4obOnnXUXf1jRv0UkzE9AHWLG5q3AwIhAPzSjpYUDjVW
|
||||
MCUXgckTpKCuGwbJk7424Nb8bLzf3kllAiA5mUBgjfr/WtFSJdWcPQ4Zt9KTMNKD
|
||||
EUO0ukpTwEIl6wIhAMbGqZK3zAAFdq8DD2jPx+UJXnh0rnOkZBzDtJ6/iN69AiEA
|
||||
1Aq8MJgTaYsDQWyU/hDq5YkDJc9e9DSCvUIzqxQWMQE=
|
||||
-----END RSA PRIVATE KEY-----`)
|
||||
)
|
||||
13
vendor/github.com/braintree/manners/test_helpers/conn.go
сгенерированный
поставляемый
Обычный файл
13
vendor/github.com/braintree/manners/test_helpers/conn.go
сгенерированный
поставляемый
Обычный файл
@@ -0,0 +1,13 @@
|
||||
package test_helpers
|
||||
|
||||
import "net"
|
||||
|
||||
type Conn struct {
|
||||
net.Conn
|
||||
CloseCalled bool
|
||||
}
|
||||
|
||||
func (c *Conn) Close() error {
|
||||
c.CloseCalled = true
|
||||
return nil
|
||||
}
|
||||
34
vendor/github.com/braintree/manners/test_helpers/listener.go
сгенерированный
поставляемый
Обычный файл
34
vendor/github.com/braintree/manners/test_helpers/listener.go
сгенерированный
поставляемый
Обычный файл
@@ -0,0 +1,34 @@
|
||||
package test_helpers
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"net"
|
||||
)
|
||||
|
||||
type Listener struct {
|
||||
AcceptRelease chan bool
|
||||
CloseCalled chan bool
|
||||
}
|
||||
|
||||
func NewListener() *Listener {
|
||||
return &Listener{
|
||||
make(chan bool, 1),
|
||||
make(chan bool, 1),
|
||||
}
|
||||
}
|
||||
|
||||
func (l *Listener) Addr() net.Addr {
|
||||
addr, _ := net.ResolveTCPAddr("tcp", "127.0.0.1:8080")
|
||||
return addr
|
||||
}
|
||||
|
||||
func (l *Listener) Close() error {
|
||||
l.CloseCalled <- true
|
||||
l.AcceptRelease <- true
|
||||
return nil
|
||||
}
|
||||
|
||||
func (l *Listener) Accept() (net.Conn, error) {
|
||||
<-l.AcceptRelease
|
||||
return nil, errors.New("connection closed")
|
||||
}
|
||||
27
vendor/github.com/braintree/manners/test_helpers/temp_file.go
сгенерированный
поставляемый
Обычный файл
27
vendor/github.com/braintree/manners/test_helpers/temp_file.go
сгенерированный
поставляемый
Обычный файл
@@ -0,0 +1,27 @@
|
||||
package test_helpers
|
||||
|
||||
import (
|
||||
"io/ioutil"
|
||||
"os"
|
||||
)
|
||||
|
||||
type TempFile struct {
|
||||
*os.File
|
||||
}
|
||||
|
||||
func NewTempFile(content []byte) (*TempFile, error) {
|
||||
f, err := ioutil.TempFile("", "graceful-test")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
f.Write(content)
|
||||
return &TempFile{f}, nil
|
||||
}
|
||||
|
||||
func (tf *TempFile) Unlink() {
|
||||
if tf.File != nil {
|
||||
os.Remove(tf.Name())
|
||||
tf.File = nil
|
||||
}
|
||||
}
|
||||
33
vendor/github.com/braintree/manners/test_helpers/wait_group.go
сгенерированный
поставляемый
Обычный файл
33
vendor/github.com/braintree/manners/test_helpers/wait_group.go
сгенерированный
поставляемый
Обычный файл
@@ -0,0 +1,33 @@
|
||||
package test_helpers
|
||||
|
||||
import "sync"
|
||||
|
||||
type WaitGroup struct {
|
||||
sync.Mutex
|
||||
Count int
|
||||
WaitCalled chan int
|
||||
}
|
||||
|
||||
func NewWaitGroup() *WaitGroup {
|
||||
return &WaitGroup{
|
||||
WaitCalled: make(chan int, 1),
|
||||
}
|
||||
}
|
||||
|
||||
func (wg *WaitGroup) Add(delta int) {
|
||||
wg.Lock()
|
||||
wg.Count++
|
||||
wg.Unlock()
|
||||
}
|
||||
|
||||
func (wg *WaitGroup) Done() {
|
||||
wg.Lock()
|
||||
wg.Count--
|
||||
wg.Unlock()
|
||||
}
|
||||
|
||||
func (wg *WaitGroup) Wait() {
|
||||
wg.Lock()
|
||||
wg.WaitCalled <- wg.Count
|
||||
wg.Unlock()
|
||||
}
|
||||
54
vendor/github.com/braintree/manners/transition_test.go
сгенерированный
поставляемый
Обычный файл
54
vendor/github.com/braintree/manners/transition_test.go
сгенерированный
поставляемый
Обычный файл
@@ -0,0 +1,54 @@
|
||||
package manners
|
||||
|
||||
import (
|
||||
helpers "github.com/braintree/manners/test_helpers"
|
||||
"net/http"
|
||||
"strings"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestStateTransitions(t *testing.T) {
|
||||
tests := []transitionTest{
|
||||
transitionTest{[]http.ConnState{http.StateNew, http.StateActive}, 1},
|
||||
transitionTest{[]http.ConnState{http.StateNew, http.StateClosed}, 0},
|
||||
transitionTest{[]http.ConnState{http.StateNew, http.StateActive, http.StateClosed}, 0},
|
||||
transitionTest{[]http.ConnState{http.StateNew, http.StateActive, http.StateHijacked}, 0},
|
||||
transitionTest{[]http.ConnState{http.StateNew, http.StateActive, http.StateIdle}, 0},
|
||||
transitionTest{[]http.ConnState{http.StateNew, http.StateActive, http.StateIdle, http.StateActive}, 1},
|
||||
transitionTest{[]http.ConnState{http.StateNew, http.StateActive, http.StateIdle, http.StateActive, http.StateIdle}, 0},
|
||||
transitionTest{[]http.ConnState{http.StateNew, http.StateActive, http.StateIdle, http.StateActive, http.StateClosed}, 0},
|
||||
transitionTest{[]http.ConnState{http.StateNew, http.StateActive, http.StateIdle, http.StateActive, http.StateIdle, http.StateClosed}, 0},
|
||||
}
|
||||
|
||||
for _, test := range tests {
|
||||
testStateTransition(t, test)
|
||||
}
|
||||
}
|
||||
|
||||
type transitionTest struct {
|
||||
states []http.ConnState
|
||||
expectedWgCount int
|
||||
}
|
||||
|
||||
func testStateTransition(t *testing.T, test transitionTest) {
|
||||
server := NewServer()
|
||||
wg := helpers.NewWaitGroup()
|
||||
server.wg = wg
|
||||
startServer(t, server, nil)
|
||||
|
||||
conn := &helpers.Conn{}
|
||||
for _, newState := range test.states {
|
||||
server.ConnState(conn, newState)
|
||||
}
|
||||
|
||||
server.Close()
|
||||
waiting := <-wg.WaitCalled
|
||||
if waiting != test.expectedWgCount {
|
||||
names := make([]string, len(test.states))
|
||||
for i, s := range test.states {
|
||||
names[i] = s.String()
|
||||
}
|
||||
transitions := strings.Join(names, " -> ")
|
||||
t.Errorf("%s - Waitcount should be %d, got %d", transitions, test.expectedWgCount, waiting)
|
||||
}
|
||||
}
|
||||
Ссылка в новой задаче
Block a user