watcher_naive_test.go 2.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114
  1. // +build !darwin
  2. package watch
  3. import (
  4. "fmt"
  5. "os"
  6. "os/exec"
  7. "runtime"
  8. "strconv"
  9. "strings"
  10. "testing"
  11. )
  12. func TestDontWatchEachFile(t *testing.T) {
  13. // fsnotify is not recursive, so we need to watch each directory
  14. // you can watch individual files with fsnotify, but that is more prone to exhaust resources
  15. // this test uses a Linux way to get the number of watches to make sure we're watching
  16. // per-directory, not per-file
  17. f := newNotifyFixture(t)
  18. defer f.tearDown()
  19. watched := f.TempDir("watched")
  20. // there are a few different cases we want to test for because the code paths are slightly
  21. // different:
  22. // 1) initial: data there before we ever call watch
  23. // 2) inplace: data we create while the watch is happening
  24. // 3) staged: data we create in another directory and then atomically move into place
  25. // initial
  26. f.WriteFile(f.JoinPath(watched, "initial.txt"), "initial data")
  27. initialDir := f.JoinPath(watched, "initial_dir")
  28. if err := os.Mkdir(initialDir, 0777); err != nil {
  29. t.Fatal(err)
  30. }
  31. for i := 0; i < 100; i++ {
  32. f.WriteFile(f.JoinPath(initialDir, fmt.Sprintf("%d", i)), "initial data")
  33. }
  34. f.watch(watched)
  35. f.fsync()
  36. if len(f.events) != 0 {
  37. t.Fatalf("expected 0 initial events; got %d events: %v", len(f.events), f.events)
  38. }
  39. f.events = nil
  40. // inplace
  41. inplace := f.JoinPath(watched, "inplace")
  42. if err := os.Mkdir(inplace, 0777); err != nil {
  43. t.Fatal(err)
  44. }
  45. f.WriteFile(f.JoinPath(inplace, "inplace.txt"), "inplace data")
  46. inplaceDir := f.JoinPath(inplace, "inplace_dir")
  47. if err := os.Mkdir(inplaceDir, 0777); err != nil {
  48. t.Fatal(err)
  49. }
  50. for i := 0; i < 100; i++ {
  51. f.WriteFile(f.JoinPath(inplaceDir, fmt.Sprintf("%d", i)), "inplace data")
  52. }
  53. f.fsync()
  54. if len(f.events) < 100 {
  55. t.Fatalf("expected >100 inplace events; got %d events: %v", len(f.events), f.events)
  56. }
  57. f.events = nil
  58. // staged
  59. staged := f.TempDir("staged")
  60. f.WriteFile(f.JoinPath(staged, "staged.txt"), "staged data")
  61. stagedDir := f.JoinPath(staged, "staged_dir")
  62. if err := os.Mkdir(stagedDir, 0777); err != nil {
  63. t.Fatal(err)
  64. }
  65. for i := 0; i < 100; i++ {
  66. f.WriteFile(f.JoinPath(stagedDir, fmt.Sprintf("%d", i)), "staged data")
  67. }
  68. if err := os.Rename(staged, f.JoinPath(watched, "staged")); err != nil {
  69. t.Fatal(err)
  70. }
  71. f.fsync()
  72. if len(f.events) < 100 {
  73. t.Fatalf("expected >100 staged events; got %d events: %v", len(f.events), f.events)
  74. }
  75. f.events = nil
  76. pid := os.Getpid()
  77. if runtime.GOOS == "windows" {
  78. return // skip the inotify count
  79. }
  80. output, err := exec.Command("bash", "-c", fmt.Sprintf(
  81. "find /proc/%d/fd -lname anon_inode:inotify -printf '%%hinfo/%%f\n' | xargs cat | grep -c '^inotify'", pid)).Output()
  82. if err != nil {
  83. t.Fatalf("error running command to determine number of watched files: %v", err)
  84. }
  85. n, err := strconv.Atoi(strings.TrimSpace(string(output)))
  86. if err != nil {
  87. t.Fatalf("couldn't parse number of watched files: %v", err)
  88. }
  89. if n > 10 {
  90. t.Fatalf("watching more than 10 files: %d", n)
  91. }
  92. }