summaryrefslogtreecommitdiff
path: root/libgo/go/os/signal/signal_test.go
diff options
context:
space:
mode:
Diffstat (limited to 'libgo/go/os/signal/signal_test.go')
-rw-r--r--libgo/go/os/signal/signal_test.go102
1 files changed, 60 insertions, 42 deletions
diff --git a/libgo/go/os/signal/signal_test.go b/libgo/go/os/signal/signal_test.go
index 66b83271130..db947568dca 100644
--- a/libgo/go/os/signal/signal_test.go
+++ b/libgo/go/os/signal/signal_test.go
@@ -675,22 +675,68 @@ func TestTime(t *testing.T) {
<-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)
- }
+var (
+ checkNotifyContext = flag.Bool("check_notify_ctx", false, "if true, TestNotifyContext will fail if SIGINT is not received.")
+ ctxNotifyTimes = flag.Int("ctx_notify_times", 1, "number of times a SIGINT signal should be received")
+)
- 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)
+func TestNotifyContextNotifications(t *testing.T) {
+ if *checkNotifyContext {
+ ctx, _ := NotifyContext(context.Background(), syscall.SIGINT)
+ // We want to make sure not to be calling Stop() internally on NotifyContext() when processing a received signal.
+ // Being able to wait for a number of received system signals allows us to do so.
+ var wg sync.WaitGroup
+ n := *ctxNotifyTimes
+ wg.Add(n)
+ for i := 0; i < n; i++ {
+ go func() {
+ syscall.Kill(syscall.Getpid(), syscall.SIGINT)
+ wg.Done()
+ }()
}
- case <-time.After(time.Second):
- t.Errorf("timed out waiting for context to be done after SIGINT")
+ wg.Wait()
+ <-ctx.Done()
+ fmt.Print("received SIGINT")
+ // Sleep to give time to simultaneous signals to reach the process.
+ // These signals must be ignored given stop() is not called on this code.
+ // We want to guarantee a SIGINT doesn't cause a premature termination of the program.
+ time.Sleep(settleTime)
+ return
+ }
+
+ t.Parallel()
+ testCases := []struct {
+ name string
+ n int // number of times a SIGINT should be notified.
+ }{
+ {"once", 1},
+ {"multiple", 10},
+ }
+ for _, tc := range testCases {
+ t.Run(tc.name, func(t *testing.T) {
+ var subTimeout time.Duration
+ if deadline, ok := t.Deadline(); ok {
+ subTimeout := time.Until(deadline)
+ subTimeout -= subTimeout / 10 // Leave 10% headroom for cleaning up subprocess.
+ }
+
+ args := []string{
+ "-test.v",
+ "-test.run=TestNotifyContextNotifications$",
+ "-check_notify_ctx",
+ fmt.Sprintf("-ctx_notify_times=%d", tc.n),
+ }
+ if subTimeout != 0 {
+ args = append(args, fmt.Sprintf("-test.timeout=%v", subTimeout))
+ }
+ out, err := exec.Command(os.Args[0], args...).CombinedOutput()
+ if err != nil {
+ t.Errorf("ran test with -check_notify_ctx_notification and it failed with %v.\nOutput:\n%s", err, out)
+ }
+ if want := []byte("received SIGINT"); !bytes.Contains(out, want) {
+ t.Errorf("got %q, wanted %q", out, want)
+ }
+ })
}
}
@@ -768,34 +814,6 @@ func TestNotifyContextPrematureCancelParent(t *testing.T) {
}
}
-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()