grace/gracehttp/http_test.go

286 lines
6.8 KiB
Go
Raw Normal View History

2012-06-05 06:21:10 +08:00
package gracehttp_test
import (
"bufio"
2013-08-21 02:29:40 +08:00
"crypto/tls"
2012-06-05 06:21:10 +08:00
"encoding/json"
"flag"
2012-06-05 06:21:10 +08:00
"fmt"
2013-10-07 01:38:28 +08:00
"io"
"net"
2012-06-05 06:21:10 +08:00
"net/http"
"os"
"os/exec"
"sync"
"syscall"
"testing"
"time"
2013-08-21 02:29:40 +08:00
2014-04-03 02:52:43 +08:00
"github.com/facebookgo/freeport"
"github.com/facebookgo/tool"
2012-06-05 06:21:10 +08:00
)
2013-10-16 02:54:28 +08:00
var (
// Debug logging.
debugLog = flag.Bool("debug", false, "enable debug logging")
testserverCommand = &tool.CommandBuild{
2014-04-03 02:52:43 +08:00
ImportPath: "github.com/facebookgo/grace/gracehttp/testserver",
2013-10-16 02:54:28 +08:00
}
)
func debug(format string, a ...interface{}) {
if *debugLog {
println(fmt.Sprintf(format, a...))
}
}
2013-10-07 00:58:50 +08:00
var (
buildOut string
buildErr error
buildOnce sync.Once
)
2012-06-05 06:21:10 +08:00
// The response from the test server.
type response struct {
Sleep time.Duration
Pid int
2013-08-21 02:29:40 +08:00
Error string
2012-06-05 06:21:10 +08:00
}
// State for the test run.
type harness struct {
T *testing.T // The test instance.
2013-08-21 02:29:40 +08:00
httpAddr string // The address for the http server.
httpsAddr string // The address for the https server.
Process []*os.Process // The server commands, oldest to newest.
ProcessMutex sync.Mutex // The mutex to guard Process manipulation.
RequestWaitGroup sync.WaitGroup // The wait group for the HTTP requests.
2013-08-21 02:29:40 +08:00
newProcess chan bool // A bool is sent on start/restart.
requestCount int
requestCountMutex sync.Mutex
2012-06-05 06:21:10 +08:00
}
// Find 3 free ports and setup addresses.
2013-10-07 01:38:28 +08:00
func (h *harness) setupAddr() {
2013-08-21 02:29:40 +08:00
port, err := freeport.Get()
if err != nil {
h.T.Fatalf("Failed to find a free port: %s", err)
2012-06-05 06:21:10 +08:00
}
2013-08-21 02:29:40 +08:00
h.httpAddr = fmt.Sprintf("127.0.0.1:%d", port)
2012-06-05 06:21:10 +08:00
2013-08-21 02:29:40 +08:00
port, err = freeport.Get()
if err != nil {
h.T.Fatalf("Failed to find a free port: %s", err)
2012-06-05 06:21:10 +08:00
}
2013-08-21 02:29:40 +08:00
h.httpsAddr = fmt.Sprintf("127.0.0.1:%d", port)
2013-10-07 01:38:28 +08:00
debug("Addresses %s & %s", h.httpAddr, h.httpsAddr)
2012-06-05 06:21:10 +08:00
}
// Start a fresh server and wait for pid updates on restart.
func (h *harness) Start() {
2013-10-16 02:54:28 +08:00
bin, err := testserverCommand.Build()
if err != nil {
h.T.Fatalf("build error: %s", err)
}
2013-10-07 01:38:28 +08:00
h.setupAddr()
2013-10-16 02:54:28 +08:00
cmd := exec.Command(bin, "-http", h.httpAddr, "-https", h.httpsAddr)
2012-06-05 06:21:10 +08:00
stderr, err := cmd.StderrPipe()
2013-10-07 01:38:28 +08:00
if err != nil {
h.T.Fatal(err)
}
2012-06-05 06:21:10 +08:00
go func() {
reader := bufio.NewReader(stderr)
for {
line, isPrefix, err := reader.ReadLine()
2013-10-07 01:38:28 +08:00
if err == io.EOF {
return
}
2012-06-05 06:21:10 +08:00
if err != nil {
2013-10-16 02:54:28 +08:00
println(fmt.Sprintf("Failed to read line from server process: %s", err))
2012-06-05 06:21:10 +08:00
}
if isPrefix {
2013-10-16 02:54:28 +08:00
println(fmt.Sprintf("Deal with isPrefix for line: %s", line))
2012-06-05 06:21:10 +08:00
}
res := &response{}
err = json.Unmarshal([]byte(line), res)
if err != nil {
2013-10-16 02:54:28 +08:00
println(fmt.Sprintf("Could not parse json from stderr %s: %s", line, err))
2013-08-21 02:29:40 +08:00
}
if res.Error != "" {
println(fmt.Sprintf("Got error from process: %v", res))
2012-06-05 06:21:10 +08:00
}
process, err := os.FindProcess(res.Pid)
if err != nil {
2013-10-16 02:54:28 +08:00
println(fmt.Sprintf("Could not find process with pid: %d", res.Pid))
2012-06-05 06:21:10 +08:00
}
h.ProcessMutex.Lock()
2012-06-05 06:21:10 +08:00
h.Process = append(h.Process, process)
h.ProcessMutex.Unlock()
2012-06-05 06:21:10 +08:00
h.newProcess <- true
}
}()
err = cmd.Start()
if err != nil {
h.T.Fatalf("Failed to start command: %s", err)
}
<-h.newProcess
}
// Restart the most recent server.
func (h *harness) Restart() {
err := h.MostRecentProcess().Signal(syscall.SIGUSR2)
if err != nil {
h.T.Fatalf("Failed to send SIGUSR2 and restart process: %s", err)
}
<-h.newProcess
}
// Graceful termination of the most recent server.
func (h *harness) Stop() {
err := h.MostRecentProcess().Signal(syscall.SIGTERM)
if err != nil {
h.T.Fatalf("Failed to send SIGTERM and stop process: %s", err)
}
}
// Returns the most recent server process.
func (h *harness) MostRecentProcess() *os.Process {
h.ProcessMutex.Lock()
defer h.ProcessMutex.Unlock()
2012-06-05 06:21:10 +08:00
l := len(h.Process)
if l == 0 {
h.T.Fatalf("Most recent command requested before command was created.")
}
return h.Process[l-1]
}
2013-08-21 02:29:40 +08:00
// Get the global request count and increment it.
func (h *harness) RequestCount() int {
h.requestCountMutex.Lock()
defer h.requestCountMutex.Unlock()
c := h.requestCount
h.requestCount++
return c
}
2012-06-05 06:21:10 +08:00
// Helper for sending a single request.
2013-08-21 02:29:40 +08:00
func (h *harness) SendOne(dialgroup *sync.WaitGroup, url string, pid int) {
defer h.RequestWaitGroup.Done()
count := h.RequestCount()
2013-08-21 02:29:40 +08:00
debug("Send %02d pid=%d url=%s", count, pid, url)
2012-06-05 06:21:10 +08:00
client := &http.Client{
Transport: &http.Transport{
DisableKeepAlives: true,
Dial: func(network, addr string) (net.Conn, error) {
defer func() {
time.Sleep(50 * time.Millisecond)
dialgroup.Done()
}()
return net.Dial(network, addr)
},
2013-08-21 02:29:40 +08:00
TLSClientConfig: &tls.Config{
InsecureSkipVerify: true,
},
},
2012-06-05 06:21:10 +08:00
}
r, err := client.Get(url)
if err != nil {
2013-08-21 02:29:40 +08:00
h.T.Fatalf("Failed request %02d to %s pid=%d: %s", count, url, pid, err)
2012-06-05 06:21:10 +08:00
}
2013-08-21 02:29:40 +08:00
debug("Body %02d pid=%d url=%s", count, pid, url)
2012-06-05 06:21:10 +08:00
defer r.Body.Close()
res := &response{}
err = json.NewDecoder(r.Body).Decode(res)
if err != nil {
2013-08-21 02:29:40 +08:00
h.T.Fatalf("Failed to ready decode json response body pid=%d: %s", pid, err)
2012-06-05 06:21:10 +08:00
}
if pid != res.Pid {
for _, old := range h.Process[0 : len(h.Process)-1] {
if res.Pid == old.Pid {
h.T.Logf("Found old pid %d, ignoring the discrepancy", res.Pid)
return
}
}
2012-06-05 06:21:10 +08:00
h.T.Fatalf("Didn't get expected pid %d instead got %d", pid, res.Pid)
}
2013-08-21 02:29:40 +08:00
debug("Done %02d pid=%d url=%s", count, pid, url)
2012-06-05 06:21:10 +08:00
}
// Send test HTTP request.
func (h *harness) SendRequest() {
pid := h.MostRecentProcess().Pid
2013-08-21 02:29:40 +08:00
httpFastUrl := fmt.Sprintf("http://%s/sleep/?duration=0", h.httpAddr)
httpSlowUrl := fmt.Sprintf("http://%s/sleep/?duration=2s", h.httpAddr)
httpsFastUrl := fmt.Sprintf("https://%s/sleep/?duration=0", h.httpsAddr)
httpsSlowUrl := fmt.Sprintf("https://%s/sleep/?duration=2s", h.httpsAddr)
var dialgroup sync.WaitGroup
2013-08-21 02:29:40 +08:00
h.RequestWaitGroup.Add(4)
dialgroup.Add(4)
go h.SendOne(&dialgroup, httpFastUrl, pid)
go h.SendOne(&dialgroup, httpSlowUrl, pid)
go h.SendOne(&dialgroup, httpsFastUrl, pid)
go h.SendOne(&dialgroup, httpsSlowUrl, pid)
debug("Added Requests pid=%d", pid)
dialgroup.Wait()
2013-08-21 02:29:40 +08:00
debug("Dialed Requests pid=%d", pid)
2012-06-05 06:21:10 +08:00
}
// Wait for everything.
func (h *harness) Wait() {
h.RequestWaitGroup.Wait()
}
2013-10-07 01:38:28 +08:00
func newHarness(t *testing.T) *harness {
return &harness{
T: t,
newProcess: make(chan bool),
}
}
2012-06-05 06:21:10 +08:00
// The main test case.
func TestComplex(t *testing.T) {
2013-10-07 00:58:50 +08:00
t.Parallel()
debug("Started TestComplex")
2013-10-07 01:38:28 +08:00
h := newHarness(t)
debug("Initial Start")
h.Start()
debug("Send Request 1")
h.SendRequest()
debug("Restart 1")
h.Restart()
debug("Send Request 2")
h.SendRequest()
debug("Restart 2")
h.Restart()
debug("Send Request 3")
h.SendRequest()
debug("Stopping")
h.Stop()
debug("Waiting")
h.Wait()
}
func TestComplexAgain(t *testing.T) {
t.Parallel()
debug("Started TestComplex")
h := newHarness(t)
debug("Initial Start")
2012-06-05 06:21:10 +08:00
h.Start()
debug("Send Request 1")
2012-06-05 06:21:10 +08:00
h.SendRequest()
debug("Restart 1")
2012-06-05 06:21:10 +08:00
h.Restart()
debug("Send Request 2")
2012-06-05 06:21:10 +08:00
h.SendRequest()
debug("Restart 2")
2012-06-05 06:21:10 +08:00
h.Restart()
debug("Send Request 3")
2012-06-05 06:21:10 +08:00
h.SendRequest()
debug("Stopping")
h.Stop()
2013-10-07 01:01:17 +08:00
debug("Waiting")
h.Wait()
2012-06-05 06:21:10 +08:00
}