psnotify_test.go 5.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286
  1. // Copyright (c) 2012 VMware, Inc.
  2. // +build darwin freebsd netbsd openbsd linux
  3. package psnotify
  4. import (
  5. "fmt"
  6. "os"
  7. "os/exec"
  8. "runtime"
  9. "syscall"
  10. "testing"
  11. "time"
  12. )
  13. type anyEvent struct {
  14. exits []int
  15. forks []int
  16. execs []int
  17. errors []error
  18. done chan bool
  19. }
  20. type testWatcher struct {
  21. t *testing.T
  22. watcher *Watcher
  23. events *anyEvent
  24. }
  25. // General purpose Watcher wrapper for all tests
  26. func newTestWatcher(t *testing.T) *testWatcher {
  27. watcher, err := NewWatcher()
  28. if err != nil {
  29. t.Fatal(err)
  30. }
  31. events := &anyEvent{
  32. done: make(chan bool, 1),
  33. }
  34. tw := &testWatcher{
  35. t: t,
  36. watcher: watcher,
  37. events: events,
  38. }
  39. go func() {
  40. for {
  41. select {
  42. case <-events.done:
  43. return
  44. case ev := <-watcher.Fork:
  45. events.forks = append(events.forks, ev.ParentPid)
  46. case ev := <-watcher.Exec:
  47. events.execs = append(events.execs, ev.Pid)
  48. case ev := <-watcher.Exit:
  49. events.exits = append(events.exits, ev.Pid)
  50. case err := <-watcher.Error:
  51. events.errors = append(events.errors, err)
  52. }
  53. }
  54. }()
  55. return tw
  56. }
  57. func (tw *testWatcher) close() {
  58. pause := 100 * time.Millisecond
  59. time.Sleep(pause)
  60. tw.events.done <- true
  61. tw.watcher.Close()
  62. time.Sleep(pause)
  63. }
  64. func skipTest(t *testing.T) bool {
  65. if runtime.GOOS == "linux" && os.Getuid() != 0 {
  66. fmt.Println("SKIP: test must be run as root on linux")
  67. return true
  68. }
  69. return false
  70. }
  71. func startSleepCommand(t *testing.T) *exec.Cmd {
  72. cmd := exec.Command("sh", "-c", "sleep 100")
  73. if err := cmd.Start(); err != nil {
  74. t.Error(err)
  75. }
  76. return cmd
  77. }
  78. func runCommand(t *testing.T, name string) *exec.Cmd {
  79. cmd := exec.Command(name)
  80. if err := cmd.Run(); err != nil {
  81. t.Error(err)
  82. }
  83. return cmd
  84. }
  85. func expectEvents(t *testing.T, num int, name string, pids []int) bool {
  86. if len(pids) != num {
  87. t.Errorf("Expected %d %s events, got=%v", num, name, pids)
  88. return false
  89. }
  90. return true
  91. }
  92. func expectEventPid(t *testing.T, name string, expect int, pid int) bool {
  93. if expect != pid {
  94. t.Errorf("Expected %s pid=%d, received=%d", name, expect, pid)
  95. return false
  96. }
  97. return true
  98. }
  99. func TestWatchFork(t *testing.T) {
  100. if skipTest(t) {
  101. return
  102. }
  103. pid := os.Getpid()
  104. tw := newTestWatcher(t)
  105. // no watches added yet, so this fork event will no be captured
  106. runCommand(t, "date")
  107. // watch fork events for this process
  108. if err := tw.watcher.Watch(pid, PROC_EVENT_FORK); err != nil {
  109. t.Error(err)
  110. }
  111. // this fork event will be captured,
  112. // the exec and exit events will not be captured
  113. runCommand(t, "cal")
  114. tw.close()
  115. if expectEvents(t, 1, "forks", tw.events.forks) {
  116. expectEventPid(t, "fork", pid, tw.events.forks[0])
  117. }
  118. expectEvents(t, 0, "execs", tw.events.execs)
  119. expectEvents(t, 0, "exits", tw.events.exits)
  120. }
  121. func TestWatchExit(t *testing.T) {
  122. if skipTest(t) {
  123. return
  124. }
  125. tw := newTestWatcher(t)
  126. cmd := startSleepCommand(t)
  127. childPid := cmd.Process.Pid
  128. // watch for exit event of our child process
  129. if err := tw.watcher.Watch(childPid, PROC_EVENT_EXIT); err != nil {
  130. t.Error(err)
  131. }
  132. // kill our child process, triggers exit event
  133. syscall.Kill(childPid, syscall.SIGTERM)
  134. cmd.Wait()
  135. tw.close()
  136. expectEvents(t, 0, "forks", tw.events.forks)
  137. expectEvents(t, 0, "execs", tw.events.execs)
  138. if expectEvents(t, 1, "exits", tw.events.exits) {
  139. expectEventPid(t, "exit", childPid, tw.events.exits[0])
  140. }
  141. }
  142. // combined version of TestWatchFork() and TestWatchExit()
  143. func TestWatchForkAndExit(t *testing.T) {
  144. if skipTest(t) {
  145. return
  146. }
  147. pid := os.Getpid()
  148. tw := newTestWatcher(t)
  149. if err := tw.watcher.Watch(pid, PROC_EVENT_FORK); err != nil {
  150. t.Error(err)
  151. }
  152. cmd := startSleepCommand(t)
  153. childPid := cmd.Process.Pid
  154. if err := tw.watcher.Watch(childPid, PROC_EVENT_EXIT); err != nil {
  155. t.Error(err)
  156. }
  157. syscall.Kill(childPid, syscall.SIGTERM)
  158. cmd.Wait()
  159. tw.close()
  160. if expectEvents(t, 1, "forks", tw.events.forks) {
  161. expectEventPid(t, "fork", pid, tw.events.forks[0])
  162. }
  163. expectEvents(t, 0, "execs", tw.events.execs)
  164. if expectEvents(t, 1, "exits", tw.events.exits) {
  165. expectEventPid(t, "exit", childPid, tw.events.exits[0])
  166. }
  167. }
  168. func TestWatchFollowFork(t *testing.T) {
  169. if skipTest(t) {
  170. return
  171. }
  172. // Darwin is not able to follow forks, as the kqueue fork event
  173. // does not provide the child pid.
  174. if runtime.GOOS != "linux" {
  175. fmt.Println("SKIP: test follow forks is linux only")
  176. return
  177. }
  178. pid := os.Getpid()
  179. tw := newTestWatcher(t)
  180. // watch for all process events related to this process
  181. if err := tw.watcher.Watch(pid, PROC_EVENT_ALL); err != nil {
  182. t.Error(err)
  183. }
  184. commands := []string{"date", "cal"}
  185. childPids := make([]int, len(commands))
  186. // triggers fork/exec/exit events for each command
  187. for i, name := range commands {
  188. cmd := runCommand(t, name)
  189. childPids[i] = cmd.Process.Pid
  190. }
  191. // remove watch for this process
  192. tw.watcher.RemoveWatch(pid)
  193. // run commands again to make sure we don't receive any unwanted events
  194. for _, name := range commands {
  195. runCommand(t, name)
  196. }
  197. tw.close()
  198. // run commands again to make sure nothing panics after
  199. // closing the watcher
  200. for _, name := range commands {
  201. runCommand(t, name)
  202. }
  203. num := len(commands)
  204. if expectEvents(t, num, "forks", tw.events.forks) {
  205. for _, epid := range tw.events.forks {
  206. expectEventPid(t, "fork", pid, epid)
  207. }
  208. }
  209. if expectEvents(t, num, "execs", tw.events.execs) {
  210. for i, epid := range tw.events.execs {
  211. expectEventPid(t, "exec", childPids[i], epid)
  212. }
  213. }
  214. if expectEvents(t, num, "exits", tw.events.exits) {
  215. for i, epid := range tw.events.exits {
  216. expectEventPid(t, "exit", childPids[i], epid)
  217. }
  218. }
  219. }