如何为HTTP服务器的中断信号(Ctrl+C)编写单元测试?
为HTTP服务器中断信号处理逻辑编写单元测试的方案
给定如下小型HTTP服务器实现,需要验证其中断信号处理逻辑的正确性:通过exitChannel <- syscall.SIGINT或syscall.Kill(syscall.Getpid(), syscall.SIGINT)传递中断信号,并确认服务器已完成关闭。
初始服务器实现代码
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) // 缓冲大小设为1,避免通知器阻塞 defer close(exitChannel) signal.Notify(exitChannel, os.Interrupt, syscall.SIGTERM) // Docker和Kubernetes通常用SIGTERM发送终止信号 <-exitChannel fmt.Print("\n") fmt.Println("shutting down server...") err := server.Shutdown(ctx) fmt.Println(err) }
可行解决方案代码
通过重构服务器代码,暴露信号触发通道并新增服务器关闭状态监听通道,即可实现测试需求:
func exampleCaller() { exitChannel, serverDownChannel := HTTPServer() fmt.Println("3秒后发送终止信号...") for i := 3; i > 0; i-- { fmt.Println(i) time.Sleep(1 * time.Second) } exitChannel <- syscall.SIGINT fmt.Println("终止信号已发送") <-serverDownChannel fmt.Println("服务器已完全关闭!") } func HTTPServer() (chan os.Signal, chan struct{}) { responseDelay := 1000 // 响应前的延迟毫秒数 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("创建通道...") exitChannel := make(chan os.Signal, 1) // 缓冲大小设为1,避免通知器阻塞 serverDownChannel := make(chan struct{}) // 用于通知服务器已关闭的信号通道 signal.Notify(exitChannel, os.Interrupt, syscall.SIGTERM) // 监听中断和终止信号 go func() { <-exitChannel // 等待中断信号 fmt.Print("\n") fmt.Println("正在关闭服务器...") err := server.Shutdown(ctx) fmt.Println(err) }() go func() { server.ListenAndServe() // 启动HTTP服务器 close(serverDownChannel) // 服务器停止后关闭通道,通知外部 }() return exitChannel, serverDownChannel }
方案说明
- 重构后的
HTTPServer函数返回两个核心通道:exitChannel用于手动发送中断信号,serverDownChannel用于监听服务器是否完全关闭。 - 在测试逻辑中,通过向
exitChannel发送syscall.SIGINT触发服务器关闭流程,随后阻塞等待serverDownChannel关闭,即可确认服务器已完成Shutdown操作。 - 若使用
syscall.Kill(syscall.Getpid(), syscall.SIGINT)替代通道发送信号,signal.Notify会自动捕捉该信号并传递给exitChannel,同样能触发完整的关闭流程。
内容的提问来源于stack exchange,提问作者Ryan Loggerythm
相关产品推荐
相关产品推荐

