aboutsummaryrefslogtreecommitdiff
path: root/src/dict2rest/vendor/github.com/stretchr/graceful
diff options
context:
space:
mode:
authorFelix Hanley <felix@userspace.com.au>2016-05-11 07:43:19 +0000
committerFelix Hanley <felix@userspace.com.au>2016-05-11 07:43:19 +0000
commit01d4169b551675aa04e9075915113d2e94fdb72d (patch)
tree0eaad50b248928795ba6c5c24873b7b84b0bca09 /src/dict2rest/vendor/github.com/stretchr/graceful
parenta5be2d0a2f450dd2e2c699e45773016528d43876 (diff)
downloadgo-dict2rest-01d4169b551675aa04e9075915113d2e94fdb72d.tar.gz
go-dict2rest-01d4169b551675aa04e9075915113d2e94fdb72d.tar.bz2
Use Golang 1.6 vendor structure
Diffstat (limited to 'src/dict2rest/vendor/github.com/stretchr/graceful')
-rw-r--r--src/dict2rest/vendor/github.com/stretchr/graceful/.gitignore23
-rw-r--r--src/dict2rest/vendor/github.com/stretchr/graceful/LICENSE21
-rw-r--r--src/dict2rest/vendor/github.com/stretchr/graceful/README.md137
-rw-r--r--src/dict2rest/vendor/github.com/stretchr/graceful/graceful.go359
-rw-r--r--src/dict2rest/vendor/github.com/stretchr/graceful/graceful_test.go439
-rw-r--r--src/dict2rest/vendor/github.com/stretchr/graceful/tests/main.go40
6 files changed, 1019 insertions, 0 deletions
diff --git a/src/dict2rest/vendor/github.com/stretchr/graceful/.gitignore b/src/dict2rest/vendor/github.com/stretchr/graceful/.gitignore
new file mode 100644
index 0000000..8365624
--- /dev/null
+++ b/src/dict2rest/vendor/github.com/stretchr/graceful/.gitignore
@@ -0,0 +1,23 @@
+# Compiled Object files, Static and Dynamic libs (Shared Objects)
+*.o
+*.a
+*.so
+
+# Folders
+_obj
+_test
+
+# Architecture specific extensions/prefixes
+*.[568vq]
+[568vq].out
+
+*.cgo1.go
+*.cgo2.c
+_cgo_defun.c
+_cgo_gotypes.go
+_cgo_export.*
+
+_testmain.go
+
+*.exe
+*.test
diff --git a/src/dict2rest/vendor/github.com/stretchr/graceful/LICENSE b/src/dict2rest/vendor/github.com/stretchr/graceful/LICENSE
new file mode 100644
index 0000000..a4f2f28
--- /dev/null
+++ b/src/dict2rest/vendor/github.com/stretchr/graceful/LICENSE
@@ -0,0 +1,21 @@
+The MIT License (MIT)
+
+Copyright (c) 2014 Tyler Bunnell
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
diff --git a/src/dict2rest/vendor/github.com/stretchr/graceful/README.md b/src/dict2rest/vendor/github.com/stretchr/graceful/README.md
new file mode 100644
index 0000000..531249a
--- /dev/null
+++ b/src/dict2rest/vendor/github.com/stretchr/graceful/README.md
@@ -0,0 +1,137 @@
+graceful [![GoDoc](https://godoc.org/github.com/tylerb/graceful?status.png)](http://godoc.org/github.com/tylerb/graceful) [![Build Status](https://drone.io/github.com/tylerb/graceful/status.png)](https://drone.io/github.com/tylerb/graceful/latest) [![Coverage Status](https://coveralls.io/repos/tylerb/graceful/badge.svg?branch=dronedebug)](https://coveralls.io/r/tylerb/graceful?branch=dronedebug) [![Gitter](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/tylerb/graceful?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge)
+========
+
+Graceful is a Go 1.3+ package enabling graceful shutdown of http.Handler servers.
+
+## Installation
+
+To install, simply execute:
+
+```
+go get gopkg.in/tylerb/graceful.v1
+```
+
+I am using [gopkg.in](http://labix.org/gopkg.in) to control releases.
+
+## Usage
+
+Using Graceful is easy. Simply create your http.Handler and pass it to the `Run` function:
+
+```go
+package main
+
+import (
+ "gopkg.in/tylerb/graceful.v1"
+ "net/http"
+ "fmt"
+ "time"
+)
+
+func main() {
+ mux := http.NewServeMux()
+ mux.HandleFunc("/", func(w http.ResponseWriter, req *http.Request) {
+ fmt.Fprintf(w, "Welcome to the home page!")
+ })
+
+ graceful.Run(":3001",10*time.Second,mux)
+}
+```
+
+Another example, using [Negroni](https://github.com/codegangsta/negroni), functions in much the same manner:
+
+```go
+package main
+
+import (
+ "github.com/codegangsta/negroni"
+ "gopkg.in/tylerb/graceful.v1"
+ "net/http"
+ "fmt"
+ "time"
+)
+
+func main() {
+ mux := http.NewServeMux()
+ mux.HandleFunc("/", func(w http.ResponseWriter, req *http.Request) {
+ fmt.Fprintf(w, "Welcome to the home page!")
+ })
+
+ n := negroni.Classic()
+ n.UseHandler(mux)
+ //n.Run(":3000")
+ graceful.Run(":3001",10*time.Second,n)
+}
+```
+
+In addition to Run there are the http.Server counterparts ListenAndServe, ListenAndServeTLS and Serve, which allow you to configure HTTPS, custom timeouts and error handling.
+Graceful may also be used by instantiating its Server type directly, which embeds an http.Server:
+
+```go
+mux := // ...
+
+srv := &graceful.Server{
+ Timeout: 10 * time.Second,
+
+ Server: &http.Server{
+ Addr: ":1234",
+ Handler: mux,
+ },
+}
+
+srv.ListenAndServe()
+```
+
+This form allows you to set the ConnState callback, which works in the same way as in http.Server:
+
+```go
+mux := // ...
+
+srv := &graceful.Server{
+ Timeout: 10 * time.Second,
+
+ ConnState: func(conn net.Conn, state http.ConnState) {
+ // conn has a new state
+ },
+
+ Server: &http.Server{
+ Addr: ":1234",
+ Handler: mux,
+ },
+}
+
+srv.ListenAndServe()
+```
+
+## Behaviour
+
+When Graceful is sent a SIGINT or SIGTERM (possibly from ^C or a kill command), it:
+
+1. Disables keepalive connections.
+2. Closes the listening socket, allowing another process to listen on that port immediately.
+3. Starts a timer of `timeout` duration to give active requests a chance to finish.
+4. When timeout expires, closes all active connections.
+5. Closes the `stopChan`, waking up any blocking goroutines.
+6. Returns from the function, allowing the server to terminate.
+
+## Notes
+
+If the `timeout` argument to `Run` is 0, the server never times out, allowing all active requests to complete.
+
+If you wish to stop the server in some way other than an OS signal, you may call the `Stop()` function.
+This function stops the server, gracefully, using the new timeout value you provide. The `StopChan()` function
+returns a channel on which you can block while waiting for the server to stop. This channel will be closed when
+the server is stopped, allowing your execution to proceed. Multiple goroutines can block on this channel at the
+same time and all will be signalled when stopping is complete.
+
+## Contributing
+
+If you would like to contribute, please:
+
+1. Create a GitHub issue regarding the contribution. Features and bugs should be discussed beforehand.
+2. Fork the repository.
+3. Create a pull request with your solution. This pull request should reference and close the issues (Fix #2).
+
+All pull requests should:
+
+1. Pass [gometalinter -t .](https://github.com/alecthomas/gometalinter) with no warnings.
+2. Be `go fmt` formatted.
diff --git a/src/dict2rest/vendor/github.com/stretchr/graceful/graceful.go b/src/dict2rest/vendor/github.com/stretchr/graceful/graceful.go
new file mode 100644
index 0000000..d3a7175
--- /dev/null
+++ b/src/dict2rest/vendor/github.com/stretchr/graceful/graceful.go
@@ -0,0 +1,359 @@
+package graceful
+
+import (
+ "crypto/tls"
+ "log"
+ "net"
+ "net/http"
+ "os"
+ "os/signal"
+ "sync"
+ "syscall"
+ "time"
+
+ "golang.org/x/net/netutil"
+)
+
+// Server wraps an http.Server with graceful connection handling.
+// It may be used directly in the same way as http.Server, or may
+// be constructed with the global functions in this package.
+//
+// Example:
+// srv := &graceful.Server{
+// Timeout: 5 * time.Second,
+// Server: &http.Server{Addr: ":1234", Handler: handler},
+// }
+// srv.ListenAndServe()
+type Server struct {
+ *http.Server
+
+ // Timeout is the duration to allow outstanding requests to survive
+ // before forcefully terminating them.
+ Timeout time.Duration
+
+ // Limit the number of outstanding requests
+ ListenLimit int
+
+ // ConnState specifies an optional callback function that is
+ // called when a client connection changes state. This is a proxy
+ // to the underlying http.Server's ConnState, and the original
+ // must not be set directly.
+ ConnState func(net.Conn, http.ConnState)
+
+ // BeforeShutdown is an optional callback function that is called
+ // before the listener is closed.
+ BeforeShutdown func()
+
+ // ShutdownInitiated is an optional callback function that is called
+ // when shutdown is initiated. It can be used to notify the client
+ // side of long lived connections (e.g. websockets) to reconnect.
+ ShutdownInitiated func()
+
+ // NoSignalHandling prevents graceful from automatically shutting down
+ // on SIGINT and SIGTERM. If set to true, you must shut down the server
+ // manually with Stop().
+ NoSignalHandling bool
+
+ // interrupt signals the listener to stop serving connections,
+ // and the server to shut down.
+ interrupt chan os.Signal
+
+ // stopLock is used to protect against concurrent calls to Stop
+ stopLock sync.Mutex
+
+ // stopChan is the channel on which callers may block while waiting for
+ // the server to stop.
+ stopChan chan struct{}
+
+ // chanLock is used to protect access to the various channel constructors.
+ chanLock sync.RWMutex
+
+ // connections holds all connections managed by graceful
+ connections map[net.Conn]struct{}
+}
+
+// Run serves the http.Handler with graceful shutdown enabled.
+//
+// timeout is the duration to wait until killing active requests and stopping the server.
+// If timeout is 0, the server never times out. It waits for all active requests to finish.
+func Run(addr string, timeout time.Duration, n http.Handler) {
+ srv := &Server{
+ Timeout: timeout,
+ Server: &http.Server{Addr: addr, Handler: n},
+ }
+
+ if err := srv.ListenAndServe(); err != nil {
+ if opErr, ok := err.(*net.OpError); !ok || (ok && opErr.Op != "accept") {
+ logger := log.New(os.Stdout, "[graceful] ", 0)
+ logger.Fatal(err)
+ }
+ }
+
+}
+
+// ListenAndServe is equivalent to http.Server.ListenAndServe with graceful shutdown enabled.
+//
+// timeout is the duration to wait until killing active requests and stopping the server.
+// If timeout is 0, the server never times out. It waits for all active requests to finish.
+func ListenAndServe(server *http.Server, timeout time.Duration) error {
+ srv := &Server{Timeout: timeout, Server: server}
+ return srv.ListenAndServe()
+}
+
+// ListenAndServe is equivalent to http.Server.ListenAndServe with graceful shutdown enabled.
+func (srv *Server) ListenAndServe() error {
+ // Create the listener so we can control their lifetime
+ addr := srv.Addr
+ if addr == "" {
+ addr = ":http"
+ }
+ l, err := net.Listen("tcp", addr)
+ if err != nil {
+ return err
+ }
+
+ return srv.Serve(l)
+}
+
+// ListenAndServeTLS is equivalent to http.Server.ListenAndServeTLS with graceful shutdown enabled.
+//
+// timeout is the duration to wait until killing active requests and stopping the server.
+// If timeout is 0, the server never times out. It waits for all active requests to finish.
+func ListenAndServeTLS(server *http.Server, certFile, keyFile string, timeout time.Duration) error {
+ srv := &Server{Timeout: timeout, Server: server}
+ return srv.ListenAndServeTLS(certFile, keyFile)
+}
+
+// ListenTLS is a convenience method that creates an https listener using the
+// provided cert and key files. Use this method if you need access to the
+// listener object directly. When ready, pass it to the Serve method.
+func (srv *Server) ListenTLS(certFile, keyFile string) (net.Listener, error) {
+ // Create the listener ourselves so we can control its lifetime
+ addr := srv.Addr
+ if addr == "" {
+ addr = ":https"
+ }
+
+ config := &tls.Config{}
+ if srv.TLSConfig != nil {
+ *config = *srv.TLSConfig
+ }
+ if config.NextProtos == nil {
+ config.NextProtos = []string{"http/1.1"}
+ }
+
+ var err error
+ config.Certificates = make([]tls.Certificate, 1)
+ config.Certificates[0], err = tls.LoadX509KeyPair(certFile, keyFile)
+ if err != nil {
+ return nil, err
+ }
+
+ conn, err := net.Listen("tcp", addr)
+ if err != nil {
+ return nil, err
+ }
+
+ tlsListener := tls.NewListener(conn, config)
+ return tlsListener, nil
+}
+
+// ListenAndServeTLS is equivalent to http.Server.ListenAndServeTLS with graceful shutdown enabled.
+func (srv *Server) ListenAndServeTLS(certFile, keyFile string) error {
+ l, err := srv.ListenTLS(certFile, keyFile)
+ if err != nil {
+ return err
+ }
+
+ return srv.Serve(l)
+}
+
+// ListenAndServeTLSConfig can be used with an existing TLS config and is equivalent to
+// http.Server.ListenAndServeTLS with graceful shutdown enabled,
+func (srv *Server) ListenAndServeTLSConfig(config *tls.Config) error {
+ addr := srv.Addr
+ if addr == "" {
+ addr = ":https"
+ }
+
+ conn, err := net.Listen("tcp", addr)
+ if err != nil {
+ return err
+ }
+
+ tlsListener := tls.NewListener(conn, config)
+ return srv.Serve(tlsListener)
+}
+
+// Serve is equivalent to http.Server.Serve with graceful shutdown enabled.
+//
+// timeout is the duration to wait until killing active requests and stopping the server.
+// If timeout is 0, the server never times out. It waits for all active requests to finish.
+func Serve(server *http.Server, l net.Listener, timeout time.Duration) error {
+ srv := &Server{Timeout: timeout, Server: server}
+ return srv.Serve(l)
+}
+
+// Serve is equivalent to http.Server.Serve with graceful shutdown enabled.
+func (srv *Server) Serve(listener net.Listener) error {
+
+ if srv.ListenLimit != 0 {
+ listener = netutil.LimitListener(listener, srv.ListenLimit)
+ }
+
+ // Track connection state
+ add := make(chan net.Conn)
+ remove := make(chan net.Conn)
+
+ srv.Server.ConnState = func(conn net.Conn, state http.ConnState) {
+ switch state {
+ case http.StateNew:
+ add <- conn
+ case http.StateClosed, http.StateHijacked:
+ remove <- conn
+ }
+ if srv.ConnState != nil {
+ srv.ConnState(conn, state)
+ }
+ }
+
+ // Manage open connections
+ shutdown := make(chan chan struct{})
+ kill := make(chan struct{})
+ go srv.manageConnections(add, remove, shutdown, kill)
+
+ interrupt := srv.interruptChan()
+ // Set up the interrupt handler
+ if !srv.NoSignalHandling {
+ signal.Notify(interrupt, syscall.SIGINT, syscall.SIGTERM)
+ }
+ quitting := make(chan struct{})
+ go srv.handleInterrupt(interrupt, quitting, listener)
+
+ // Serve with graceful listener.
+ // Execution blocks here until listener.Close() is called, above.
+ err := srv.Server.Serve(listener)
+ if err != nil {
+ // If the underlying listening is closed, Serve returns an error
+ // complaining about listening on a closed socket. This is expected, so
+ // let's ignore the error if we are the ones who explicitly closed the
+ // socket.
+ select {
+ case <-quitting:
+ err = nil
+ default:
+ }
+ }
+
+ srv.shutdown(shutdown, kill)
+
+ return err
+}
+
+// Stop instructs the type to halt operations and close
+// the stop channel when it is finished.
+//
+// timeout is grace period for which to wait before shutting
+// down the server. The timeout value passed here will override the
+// timeout given when constructing the server, as this is an explicit
+// command to stop the server.
+func (srv *Server) Stop(timeout time.Duration) {
+ srv.stopLock.Lock()
+ srv.Timeout = timeout
+ interrupt := srv.interruptChan()
+ interrupt <- syscall.SIGINT
+ srv.stopLock.Unlock()
+}
+
+// StopChan gets the stop channel which will block until
+// stopping has completed, at which point it is closed.
+// Callers should never close the stop channel.
+func (srv *Server) StopChan() <-chan struct{} {
+ srv.chanLock.Lock()
+ if srv.stopChan == nil {
+ srv.stopChan = make(chan struct{})
+ }
+ srv.chanLock.Unlock()
+ return srv.stopChan
+}
+
+func (srv *Server) manageConnections(add, remove chan net.Conn, shutdown chan chan struct{}, kill chan struct{}) {
+ var done chan struct{}
+ srv.connections = map[net.Conn]struct{}{}
+ for {
+ select {
+ case conn := <-add:
+ srv.connections[conn] = struct{}{}
+ case conn := <-remove:
+ delete(srv.connections, conn)
+ if done != nil && len(srv.connections) == 0 {
+ done <- struct{}{}
+ return
+ }
+ case done = <-shutdown:
+ if len(srv.connections) == 0 {
+ done <- struct{}{}
+ return
+ }
+ case <-kill:
+ for k := range srv.connections {
+ _ = k.Close() // nothing to do here if it errors
+ }
+ return
+ }
+ }
+}
+
+func (srv *Server) interruptChan() chan os.Signal {
+ srv.chanLock.Lock()
+ if srv.interrupt == nil {
+ srv.interrupt = make(chan os.Signal, 1)
+ }
+ srv.chanLock.Unlock()
+
+ return srv.interrupt
+}
+
+func (srv *Server) handleInterrupt(interrupt chan os.Signal, quitting chan struct{}, listener net.Listener) {
+ <-interrupt
+
+ if srv.BeforeShutdown != nil {
+ srv.BeforeShutdown()
+ }
+
+ close(quitting)
+ srv.SetKeepAlivesEnabled(false)
+ _ = listener.Close() // we are shutting down anyway. ignore error.
+
+ if srv.ShutdownInitiated != nil {
+ srv.ShutdownInitiated()
+ }
+
+ srv.stopLock.Lock()
+ signal.Stop(interrupt)
+ close(interrupt)
+ srv.interrupt = nil
+ srv.stopLock.Unlock()
+}
+
+func (srv *Server) shutdown(shutdown chan chan struct{}, kill chan struct{}) {
+ // Request done notification
+ done := make(chan struct{})
+ shutdown <- done
+
+ if srv.Timeout > 0 {
+ select {
+ case <-done:
+ case <-time.After(srv.Timeout):
+ close(kill)
+ }
+ } else {
+ <-done
+ }
+ // Close the stopChan to wake up any blocked goroutines.
+ srv.chanLock.Lock()
+ if srv.stopChan != nil {
+ close(srv.stopChan)
+ }
+ srv.chanLock.Unlock()
+}
diff --git a/src/dict2rest/vendor/github.com/stretchr/graceful/graceful_test.go b/src/dict2rest/vendor/github.com/stretchr/graceful/graceful_test.go
new file mode 100644
index 0000000..83acac3
--- /dev/null
+++ b/src/dict2rest/vendor/github.com/stretchr/graceful/graceful_test.go
@@ -0,0 +1,439 @@
+package graceful
+
+import (
+ "fmt"
+ "io"
+ "net"
+ "net/http"
+ "net/url"
+ "os"
+ "reflect"
+ "strings"
+ "sync"
+ "syscall"
+ "testing"
+ "time"
+)
+
+var (
+ killTime = 500 * time.Millisecond
+ timeoutTime = 1000 * time.Millisecond
+ waitTime = 100 * time.Millisecond
+)
+
+func runQuery(t *testing.T, expected int, shouldErr bool, wg *sync.WaitGroup, once *sync.Once) {
+ wg.Add(1)
+ defer wg.Done()
+ client := http.Client{}
+ r, err := client.Get("http://localhost:9654")
+ if shouldErr && err == nil {
+ once.Do(func() {
+ t.Fatal("Expected an error but none was encountered.")
+ })
+ } else if shouldErr && err != nil {
+ if checkErr(t, err, once) {
+ return
+ }
+ }
+ if r != nil && r.StatusCode != expected {
+ once.Do(func() {
+ t.Fatalf("Incorrect status code on response. Expected %d. Got %d", expected, r.StatusCode)
+ })
+ } else if r == nil {
+ once.Do(func() {
+ t.Fatal("No response when a response was expected.")
+ })
+ }
+}
+
+func checkErr(t *testing.T, err error, once *sync.Once) bool {
+ if err.(*url.Error).Err == io.EOF {
+ return true
+ }
+ var errno syscall.Errno
+ switch oe := err.(*url.Error).Err.(type) {
+ case *net.OpError:
+ switch e := oe.Err.(type) {
+ case syscall.Errno:
+ errno = e
+ case *os.SyscallError:
+ errno = e.Err.(syscall.Errno)
+ }
+ if errno == syscall.ECONNREFUSED {
+ return true
+ } else if err != nil {
+ once.Do(func() {
+ t.Fatal("Error on Get:", err)
+ })
+ }
+ default:
+ if strings.Contains(err.Error(), "transport closed before response was received") {
+ return true
+ }
+ fmt.Printf("unknown err: %s, %#v\n", err, err)
+ }
+ return false
+}
+
+func createListener(sleep time.Duration) (*http.Server, net.Listener, error) {
+ mux := http.NewServeMux()
+ mux.HandleFunc("/", func(rw http.ResponseWriter, r *http.Request) {
+ time.Sleep(sleep)
+ rw.WriteHeader(http.StatusOK)
+ })
+
+ time.Sleep(1 * time.Second)
+ server := &http.Server{Addr: ":9654", Handler: mux}
+ l, err := net.Listen("tcp", ":9654")
+ if err != nil {
+ }
+ return server, l, err
+}
+
+func runServer(timeout, sleep time.Duration, c chan os.Signal) error {
+ server, l, err := createListener(sleep)
+ if err != nil {
+ return err
+ }
+
+ srv := &Server{Timeout: timeout, Server: server, interrupt: c}
+ return srv.Serve(l)
+}
+
+func launchTestQueries(t *testing.T, wg *sync.WaitGroup, c chan os.Signal) {
+ var once sync.Once
+ for i := 0; i < 8; i++ {
+ go runQuery(t, http.StatusOK, false, wg, &once)
+ }
+
+ time.Sleep(waitTime)
+ c <- os.Interrupt
+ time.Sleep(waitTime)
+
+ for i := 0; i < 8; i++ {
+ go runQuery(t, 0, true, wg, &once)
+ }
+
+ wg.Done()
+}
+
+func TestGracefulRun(t *testing.T) {
+ c := make(chan os.Signal, 1)
+
+ var wg sync.WaitGroup
+ wg.Add(1)
+
+ go func() {
+ runServer(killTime, killTime/2, c)
+ wg.Done()
+ }()
+ time.Sleep(1 * time.Second)
+
+ wg.Add(1)
+ go launchTestQueries(t, &wg, c)
+ wg.Wait()
+}
+
+func TestGracefulRunTimesOut(t *testing.T) {
+ c := make(chan os.Signal, 1)
+
+ var wg sync.WaitGroup
+ wg.Add(1)
+
+ go func() {
+ runServer(killTime, killTime*10, c)
+ wg.Done()
+ }()
+ time.Sleep(2 * time.Second)
+
+ var once sync.Once
+ wg.Add(1)
+ go func() {
+ for i := 0; i < 8; i++ {
+ go runQuery(t, 0, true, &wg, &once)
+ }
+ time.Sleep(waitTime)
+ c <- os.Interrupt
+ time.Sleep(waitTime)
+ for i := 0; i < 8; i++ {
+ go runQuery(t, 0, true, &wg, &once)
+ }
+ wg.Done()
+ }()
+
+ wg.Wait()
+
+}
+
+func TestGracefulRunDoesntTimeOut(t *testing.T) {
+ c := make(chan os.Signal, 1)
+
+ var wg sync.WaitGroup
+ wg.Add(1)
+
+ go func() {
+ runServer(0, killTime*2, c)
+ wg.Done()
+ }()
+ time.Sleep(1 * time.Second)
+
+ wg.Add(1)
+ go launchTestQueries(t, &wg, c)
+ wg.Wait()
+}
+
+func TestGracefulRunNoRequests(t *testing.T) {
+ c := make(chan os.Signal, 1)
+
+ var wg sync.WaitGroup
+ wg.Add(1)
+
+ go func() {
+ runServer(0, killTime*2, c)
+ wg.Done()
+ }()
+ time.Sleep(1 * time.Second)
+
+ c <- os.Interrupt
+
+ wg.Wait()
+
+}
+
+func TestGracefulForwardsConnState(t *testing.T) {
+ c := make(chan os.Signal, 1)
+ states := make(map[http.ConnState]int)
+ var stateLock sync.Mutex
+
+ connState := func(conn net.Conn, state http.ConnState) {
+ stateLock.Lock()
+ states[state]++
+ stateLock.Unlock()
+ }
+
+ var wg sync.WaitGroup
+ wg.Add(1)
+
+ expected := map[http.ConnState]int{
+ http.StateNew: 8,
+ http.StateActive: 8,
+ http.StateClosed: 8,
+ }
+
+ go func() {
+ server, l, _ := createListener(killTime / 2)
+ srv := &Server{
+ ConnState: connState,
+ Timeout: killTime,
+ Server: server,
+ interrupt: c,
+ }
+ srv.Serve(l)
+
+ wg.Done()
+ }()
+ time.Sleep(2 * time.Second)
+
+ wg.Add(1)
+ go launchTestQueries(t, &wg, c)
+ wg.Wait()
+
+ stateLock.Lock()
+ if !reflect.DeepEqual(states, expected) {
+ t.Errorf("Incorrect connection state tracking.\n actual: %v\nexpected: %v\n", states, expected)
+ }
+ stateLock.Unlock()
+}
+
+func TestGracefulExplicitStop(t *testing.T) {
+ server, l, err := createListener(1 * time.Millisecond)
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ srv := &Server{Timeout: killTime, Server: server}
+
+ go func() {
+ go srv.Serve(l)
+ time.Sleep(waitTime)
+ srv.Stop(killTime)
+ }()
+
+ // block on the stopChan until the server has shut down
+ select {
+ case <-srv.StopChan():
+ case <-time.After(timeoutTime):
+ t.Fatal("Timed out while waiting for explicit stop to complete")
+ }
+}
+
+func TestGracefulExplicitStopOverride(t *testing.T) {
+ server, l, err := createListener(1 * time.Millisecond)
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ srv := &Server{Timeout: killTime, Server: server}
+
+ go func() {
+ go srv.Serve(l)
+ time.Sleep(waitTime)
+ srv.Stop(killTime / 2)
+ }()
+
+ // block on the stopChan until the server has shut down
+ select {
+ case <-srv.StopChan():
+ case <-time.After(killTime):
+ t.Fatal("Timed out while waiting for explicit stop to complete")
+ }
+}
+
+func TestBeforeShutdownAndShutdownInitiatedCallbacks(t *testing.T) {
+ server, l, err := createListener(1 * time.Millisecond)
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ beforeShutdownCalled := make(chan struct{})
+ cb1 := func() { close(beforeShutdownCalled) }
+ shutdownInitiatedCalled := make(chan struct{})
+ cb2 := func() { close(shutdownInitiatedCalled) }
+
+ srv := &Server{Server: server, BeforeShutdown: cb1, ShutdownInitiated: cb2}
+
+ go func() {
+ go srv.Serve(l)
+ time.Sleep(waitTime)
+ srv.Stop(killTime)
+ }()
+
+ beforeShutdown := false
+ shutdownInitiated := false
+ for i := 0; i < 2; i++ {
+ select {
+ case <-beforeShutdownCalled:
+ beforeShutdownCalled = nil
+ beforeShutdown = true
+ case <-shutdownInitiatedCalled:
+ shutdownInitiatedCalled = nil
+ shutdownInitiated = true
+ case <-time.After(killTime):
+ t.Fatal("Timed out while waiting for ShutdownInitiated callback to be called")
+ }
+ }
+
+ if !beforeShutdown {
+ t.Fatal("beforeShutdown should be true")
+ }
+ if !shutdownInitiated {
+ t.Fatal("shutdownInitiated should be true")
+ }
+}
+func hijackingListener(srv *Server) (*http.Server, net.Listener, error) {
+ mux := http.NewServeMux()
+ mux.HandleFunc("/", func(rw http.ResponseWriter, r *http.Request) {
+ conn, bufrw, err := rw.(http.Hijacker).Hijack()
+ if err != nil {
+ http.Error(rw, "webserver doesn't support hijacking", http.StatusInternalServerError)
+ return
+ }
+
+ defer conn.Close()
+
+ bufrw.WriteString("HTTP/1.1 200 OK\r\n\r\n")
+ bufrw.Flush()
+ })
+
+ server := &http.Server{Addr: ":9654", Handler: mux}
+ l, err := net.Listen("tcp", ":9654")
+ return server, l, err
+}
+
+func TestNotifyClosed(t *testing.T) {
+ c := make(chan os.Signal, 1)
+
+ var wg sync.WaitGroup
+ wg.Add(1)
+
+ srv := &Server{Timeout: killTime, interrupt: c}
+ server, l, err := hijackingListener(srv)
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ srv.Server = server
+
+ go func() {
+ srv.Serve(l)
+ wg.Done()
+ }()
+
+ var once sync.Once
+ for i := 0; i < 8; i++ {
+ runQuery(t, http.StatusOK, false, &wg, &once)
+ }
+
+ srv.Stop(0)
+
+ // block on the stopChan until the server has shut down
+ select {
+ case <-srv.StopChan():
+ case <-time.After(timeoutTime):
+ t.Fatal("Timed out while waiting for explicit stop to complete")
+ }
+
+ if len(srv.connections) > 0 {
+ t.Fatal("hijacked connections should not be managed")
+ }
+
+}
+
+func TestStopDeadlock(t *testing.T) {
+ c := make(chan struct{})
+
+ server, l, err := createListener(1 * time.Millisecond)
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ srv := &Server{Server: server, NoSignalHandling: true}
+
+ go func() {
+ time.Sleep(waitTime)
+ srv.Serve(l)
+ }()
+
+ go func() {
+ srv.Stop(0)
+ close(c)
+ }()
+
+ select {
+ case <-c:
+ l.Close()
+ case <-time.After(timeoutTime):
+ t.Fatal("Timed out while waiting for explicit stop to complete")
+ }
+}
+
+// Run with --race
+func TestStopRace(t *testing.T) {
+ server, l, err := createListener(1 * time.Millisecond)
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ srv := &Server{Timeout: killTime, Server: server}
+
+ go func() {
+ go srv.Serve(l)
+ srv.Stop(killTime)
+ }()
+ srv.Stop(0)
+ select {
+ case <-srv.StopChan():
+ case <-time.After(timeoutTime):
+ t.Fatal("Timed out while waiting for explicit stop to complete")
+ }
+}
diff --git a/src/dict2rest/vendor/github.com/stretchr/graceful/tests/main.go b/src/dict2rest/vendor/github.com/stretchr/graceful/tests/main.go
new file mode 100644
index 0000000..8c8fa20
--- /dev/null
+++ b/src/dict2rest/vendor/github.com/stretchr/graceful/tests/main.go
@@ -0,0 +1,40 @@
+package main
+
+import (
+ "fmt"
+ "sync"
+
+ "github.com/codegangsta/negroni"
+ "github.com/tylerb/graceful"
+)
+
+func main() {
+
+ var wg sync.WaitGroup
+
+ wg.Add(3)
+ go func() {
+ n := negroni.New()
+ fmt.Println("Launching server on :3000")
+ graceful.Run(":3000", 0, n)
+ fmt.Println("Terminated server on :3000")
+ wg.Done()
+ }()
+ go func() {
+ n := negroni.New()
+ fmt.Println("Launching server on :3001")
+ graceful.Run(":3001", 0, n)
+ fmt.Println("Terminated server on :3001")
+ wg.Done()
+ }()
+ go func() {
+ n := negroni.New()
+ fmt.Println("Launching server on :3002")
+ graceful.Run(":3002", 0, n)
+ fmt.Println("Terminated server on :3002")
+ wg.Done()
+ }()
+ fmt.Println("Press ctrl+c. All servers should terminate.")
+ wg.Wait()
+
+}