Given a small HTTP server, how can you write a unit test to make sure the interrupt is dealt with correctly?
package main
import (
"context"
"fmt"
"net"
"net/http"
"os"
"os/signal"
"syscall"
"time"
)
func SimpleServer() {
ctx := context.Background()
server := http.Server{
Addr: ":8080",
BaseContext: func(net.Listener) context.Context { return ctx },
}
http.HandleFunc("/ping", func(w http.ResponseWriter, r *http.Request) {
fmt.Fprint(w, "pong at ", time.Now().String())
})
go server.ListenAndServe()
exitChannel := make(chan os.Signal, 1) // reserve with buffer size 1 so the notifiers aren't blocked
defer close(exitChannel)
signal.Notify(exitChannel, os.Interrupt, syscall.SIGTERM) // Docker and Kubernetes will signal with syscall.SIGTERM
<-exitChannel
fmt.Print("\n")
fmt.Println("shutting down server...")
err := server.Shutdown(ctx)
fmt.Println(err)
}
I'm wondering how to pass in this:
exitChannel <- syscall.SIGINT
or:
syscall.Kill(syscall.Getpid(), syscall.SIGINT)
..and then somehow be notified that the server shut down.
Update:
Following Burak's answer below, here's a working solution:
func exampleCaller() {
exitChannel, serverDownChannel := HTTPServer()
fmt.Println("sending kill signal in...")
for i := 3; i > 0; i-- {
fmt.Println(i)
time.Sleep(1 * time.Second)
}
exitChannel <- syscall.SIGINT
fmt.Println("kill signal sent")
<-serverDownChannel
fmt.Println("server is down!")
}
func HTTPServer() (chan os.Signal, chan struct{}) {
responseDelay := 1000 // millisecond delay before sending a response message
ctx := context.Background()
server := http.Server{
Addr: ":8080",
BaseContext: func(net.Listener) context.Context { return ctx },
}
http.HandleFunc("/ping", func(w http.ResponseWriter, r *http.Request) {
time.Sleep(time.Duration(responseDelay) * time.Millisecond)
fmt.Fprint(w, "pong at ", time.Now().String())
})
fmt.Println("creating channels...")
exitChannel := make(chan os.Signal, 1) // reserve with buffer size 1 so the notifiers aren't blocked
serverDownChannel := make(chan struct{}) // NOTE: we're not passing any data into this channel
signal.Notify(exitChannel, os.Interrupt, syscall.SIGTERM) // Docker and Kubernetes will signal with syscall.SIGTERM
go func() {
<-exitChannel // wait for the signal interrupt
fmt.Print("\n")
fmt.Println("shutting down server...")
err := server.Shutdown(ctx)
fmt.Println(err)
}()
go func() {
server.ListenAndServe() // start the HTTP server
close(serverDownChannel)
}()
return exitChannel, serverDownChannel
}