watcher_naive_test.go 2.9 KB

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