1// Copyright 2012 The Go Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style
3// license that can be found in the LICENSE file.
4
5package signal
6
7import (
8	"internal/testenv"
9	"os"
10	"path/filepath"
11	"strings"
12	"syscall"
13	"testing"
14	"time"
15)
16
17func sendCtrlBreak(t *testing.T, pid int) {
18	d, e := syscall.LoadDLL("kernel32.dll")
19	if e != nil {
20		t.Fatalf("LoadDLL: %v\n", e)
21	}
22	p, e := d.FindProc("GenerateConsoleCtrlEvent")
23	if e != nil {
24		t.Fatalf("FindProc: %v\n", e)
25	}
26	r, _, e := p.Call(syscall.CTRL_BREAK_EVENT, uintptr(pid))
27	if r == 0 {
28		t.Fatalf("GenerateConsoleCtrlEvent: %v\n", e)
29	}
30}
31
32func TestCtrlBreak(t *testing.T) {
33	// create source file
34	const source = `
35package main
36
37import (
38	"log"
39	"os"
40	"os/signal"
41	"time"
42)
43
44
45func main() {
46	c := make(chan os.Signal, 10)
47	signal.Notify(c)
48	select {
49	case s := <-c:
50		if s != os.Interrupt {
51			log.Fatalf("Wrong signal received: got %q, want %q\n", s, os.Interrupt)
52		}
53	case <-time.After(3 * time.Second):
54		log.Fatalf("Timeout waiting for Ctrl+Break\n")
55	}
56}
57`
58	tmp := t.TempDir()
59
60	// write ctrlbreak.go
61	name := filepath.Join(tmp, "ctlbreak")
62	src := name + ".go"
63	f, err := os.Create(src)
64	if err != nil {
65		t.Fatalf("Failed to create %v: %v", src, err)
66	}
67	defer f.Close()
68	f.Write([]byte(source))
69
70	// compile it
71	exe := name + ".exe"
72	defer os.Remove(exe)
73	o, err := testenv.Command(t, testenv.GoToolPath(t), "build", "-o", exe, src).CombinedOutput()
74	if err != nil {
75		t.Fatalf("Failed to compile: %v\n%v", err, string(o))
76	}
77
78	// run it
79	cmd := testenv.Command(t, exe)
80	var buf strings.Builder
81	cmd.Stdout = &buf
82	cmd.Stderr = &buf
83	cmd.SysProcAttr = &syscall.SysProcAttr{
84		CreationFlags: syscall.CREATE_NEW_PROCESS_GROUP,
85	}
86	err = cmd.Start()
87	if err != nil {
88		t.Fatalf("Start failed: %v", err)
89	}
90	go func() {
91		time.Sleep(1 * time.Second)
92		sendCtrlBreak(t, cmd.Process.Pid)
93	}()
94	err = cmd.Wait()
95	if err != nil {
96		t.Fatalf("Program exited with error: %v\n%v", err, buf.String())
97	}
98}
99