mirror of
https://github.com/golang/go.git
synced 2025-12-08 06:10:04 +00:00
os/signal: add NotifyContext to cancel context using system signals
Fixes #37255 Change-Id: Ic0fde3498afefed6e4447f8476e4da7c1faa7145 Reviewed-on: https://go-review.googlesource.com/c/go/+/219640 Run-TryBot: Ian Lance Taylor <iant@golang.org> TryBot-Result: Go Bot <gobot@golang.org> Trust: Giovanni Bajo <rasky@develer.com> Reviewed-by: Ian Lance Taylor <iant@golang.org>
This commit is contained in:
parent
8248b5791c
commit
b6dbaef68f
3 changed files with 284 additions and 0 deletions
|
|
@ -8,6 +8,7 @@ package signal
|
|||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"flag"
|
||||
"fmt"
|
||||
"internal/testenv"
|
||||
|
|
@ -674,3 +675,164 @@ func TestTime(t *testing.T) {
|
|||
close(stop)
|
||||
<-done
|
||||
}
|
||||
|
||||
func TestNotifyContext(t *testing.T) {
|
||||
c, stop := NotifyContext(context.Background(), syscall.SIGINT)
|
||||
defer stop()
|
||||
|
||||
if want, got := "signal.NotifyContext(context.Background, [interrupt])", fmt.Sprint(c); want != got {
|
||||
t.Errorf("c.String() = %q, want %q", got, want)
|
||||
}
|
||||
|
||||
syscall.Kill(syscall.Getpid(), syscall.SIGINT)
|
||||
select {
|
||||
case <-c.Done():
|
||||
if got := c.Err(); got != context.Canceled {
|
||||
t.Errorf("c.Err() = %q, want %q", got, context.Canceled)
|
||||
}
|
||||
case <-time.After(time.Second):
|
||||
t.Errorf("timed out waiting for context to be done after SIGINT")
|
||||
}
|
||||
}
|
||||
|
||||
func TestNotifyContextStop(t *testing.T) {
|
||||
Ignore(syscall.SIGHUP)
|
||||
if !Ignored(syscall.SIGHUP) {
|
||||
t.Errorf("expected SIGHUP to be ignored when explicitly ignoring it.")
|
||||
}
|
||||
|
||||
parent, cancelParent := context.WithCancel(context.Background())
|
||||
defer cancelParent()
|
||||
c, stop := NotifyContext(parent, syscall.SIGHUP)
|
||||
defer stop()
|
||||
|
||||
// If we're being notified, then the signal should not be ignored.
|
||||
if Ignored(syscall.SIGHUP) {
|
||||
t.Errorf("expected SIGHUP to not be ignored.")
|
||||
}
|
||||
|
||||
if want, got := "signal.NotifyContext(context.Background.WithCancel, [hangup])", fmt.Sprint(c); want != got {
|
||||
t.Errorf("c.String() = %q, wanted %q", got, want)
|
||||
}
|
||||
|
||||
stop()
|
||||
select {
|
||||
case <-c.Done():
|
||||
if got := c.Err(); got != context.Canceled {
|
||||
t.Errorf("c.Err() = %q, want %q", got, context.Canceled)
|
||||
}
|
||||
case <-time.After(time.Second):
|
||||
t.Errorf("timed out waiting for context to be done after calling stop")
|
||||
}
|
||||
}
|
||||
|
||||
func TestNotifyContextCancelParent(t *testing.T) {
|
||||
parent, cancelParent := context.WithCancel(context.Background())
|
||||
defer cancelParent()
|
||||
c, stop := NotifyContext(parent, syscall.SIGINT)
|
||||
defer stop()
|
||||
|
||||
if want, got := "signal.NotifyContext(context.Background.WithCancel, [interrupt])", fmt.Sprint(c); want != got {
|
||||
t.Errorf("c.String() = %q, want %q", got, want)
|
||||
}
|
||||
|
||||
cancelParent()
|
||||
select {
|
||||
case <-c.Done():
|
||||
if got := c.Err(); got != context.Canceled {
|
||||
t.Errorf("c.Err() = %q, want %q", got, context.Canceled)
|
||||
}
|
||||
case <-time.After(time.Second):
|
||||
t.Errorf("timed out waiting for parent context to be canceled")
|
||||
}
|
||||
}
|
||||
|
||||
func TestNotifyContextPrematureCancelParent(t *testing.T) {
|
||||
parent, cancelParent := context.WithCancel(context.Background())
|
||||
defer cancelParent()
|
||||
|
||||
cancelParent() // Prematurely cancel context before calling NotifyContext.
|
||||
c, stop := NotifyContext(parent, syscall.SIGINT)
|
||||
defer stop()
|
||||
|
||||
if want, got := "signal.NotifyContext(context.Background.WithCancel, [interrupt])", fmt.Sprint(c); want != got {
|
||||
t.Errorf("c.String() = %q, want %q", got, want)
|
||||
}
|
||||
|
||||
select {
|
||||
case <-c.Done():
|
||||
if got := c.Err(); got != context.Canceled {
|
||||
t.Errorf("c.Err() = %q, want %q", got, context.Canceled)
|
||||
}
|
||||
case <-time.After(time.Second):
|
||||
t.Errorf("timed out waiting for parent context to be canceled")
|
||||
}
|
||||
}
|
||||
|
||||
func TestNotifyContextSimultaneousNotifications(t *testing.T) {
|
||||
c, stop := NotifyContext(context.Background(), syscall.SIGINT)
|
||||
defer stop()
|
||||
|
||||
if want, got := "signal.NotifyContext(context.Background, [interrupt])", fmt.Sprint(c); want != got {
|
||||
t.Errorf("c.String() = %q, want %q", got, want)
|
||||
}
|
||||
|
||||
var wg sync.WaitGroup
|
||||
n := 10
|
||||
wg.Add(n)
|
||||
for i := 0; i < n; i++ {
|
||||
go func() {
|
||||
syscall.Kill(syscall.Getpid(), syscall.SIGINT)
|
||||
wg.Done()
|
||||
}()
|
||||
}
|
||||
wg.Wait()
|
||||
select {
|
||||
case <-c.Done():
|
||||
if got := c.Err(); got != context.Canceled {
|
||||
t.Errorf("c.Err() = %q, want %q", got, context.Canceled)
|
||||
}
|
||||
case <-time.After(time.Second):
|
||||
t.Errorf("expected context to be canceled")
|
||||
}
|
||||
}
|
||||
|
||||
func TestNotifyContextSimultaneousStop(t *testing.T) {
|
||||
c, stop := NotifyContext(context.Background(), syscall.SIGINT)
|
||||
defer stop()
|
||||
|
||||
if want, got := "signal.NotifyContext(context.Background, [interrupt])", fmt.Sprint(c); want != got {
|
||||
t.Errorf("c.String() = %q, want %q", got, want)
|
||||
}
|
||||
|
||||
var wg sync.WaitGroup
|
||||
n := 10
|
||||
wg.Add(n)
|
||||
for i := 0; i < n; i++ {
|
||||
go func() {
|
||||
stop()
|
||||
wg.Done()
|
||||
}()
|
||||
}
|
||||
wg.Wait()
|
||||
select {
|
||||
case <-c.Done():
|
||||
if got := c.Err(); got != context.Canceled {
|
||||
t.Errorf("c.Err() = %q, want %q", got, context.Canceled)
|
||||
}
|
||||
case <-time.After(time.Second):
|
||||
t.Errorf("expected context to be canceled")
|
||||
}
|
||||
}
|
||||
|
||||
func TestNotifyContextStringer(t *testing.T) {
|
||||
parent, cancelParent := context.WithCancel(context.Background())
|
||||
defer cancelParent()
|
||||
c, stop := NotifyContext(parent, syscall.SIGHUP, syscall.SIGINT, syscall.SIGTERM)
|
||||
defer stop()
|
||||
|
||||
want := `signal.NotifyContext(context.Background.WithCancel, [hangup interrupt terminated])`
|
||||
if got := fmt.Sprint(c); got != want {
|
||||
t.Errorf("c.String() = %q, want %q", got, want)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue