| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146 |
- //go:build !darwin
- // +build !darwin
- package watch
- import (
- "fmt"
- "os"
- "os/exec"
- "path/filepath"
- "runtime"
- "strconv"
- "strings"
- "testing"
- "github.com/stretchr/testify/require"
- )
- func TestDontWatchEachFile(t *testing.T) {
- if runtime.GOOS != "linux" {
- t.Skip("This test uses linux-specific inotify checks")
- }
- // fsnotify is not recursive, so we need to watch each directory
- // you can watch individual files with fsnotify, but that is more prone to exhaust resources
- // this test uses a Linux way to get the number of watches to make sure we're watching
- // per-directory, not per-file
- f := newNotifyFixture(t)
- watched := f.TempDir("watched")
- // there are a few different cases we want to test for because the code paths are slightly
- // different:
- // 1) initial: data there before we ever call watch
- // 2) inplace: data we create while the watch is happening
- // 3) staged: data we create in another directory and then atomically move into place
- // initial
- f.WriteFile(f.JoinPath(watched, "initial.txt"), "initial data")
- initialDir := f.JoinPath(watched, "initial_dir")
- if err := os.Mkdir(initialDir, 0777); err != nil {
- t.Fatal(err)
- }
- for i := 0; i < 100; i++ {
- f.WriteFile(f.JoinPath(initialDir, fmt.Sprintf("%d", i)), "initial data")
- }
- f.watch(watched)
- f.fsync()
- if len(f.events) != 0 {
- t.Fatalf("expected 0 initial events; got %d events: %v", len(f.events), f.events)
- }
- f.events = nil
- // inplace
- inplace := f.JoinPath(watched, "inplace")
- if err := os.Mkdir(inplace, 0777); err != nil {
- t.Fatal(err)
- }
- f.WriteFile(f.JoinPath(inplace, "inplace.txt"), "inplace data")
- inplaceDir := f.JoinPath(inplace, "inplace_dir")
- if err := os.Mkdir(inplaceDir, 0777); err != nil {
- t.Fatal(err)
- }
- for i := 0; i < 100; i++ {
- f.WriteFile(f.JoinPath(inplaceDir, fmt.Sprintf("%d", i)), "inplace data")
- }
- f.fsync()
- if len(f.events) < 100 {
- t.Fatalf("expected >100 inplace events; got %d events: %v", len(f.events), f.events)
- }
- f.events = nil
- // staged
- staged := f.TempDir("staged")
- f.WriteFile(f.JoinPath(staged, "staged.txt"), "staged data")
- stagedDir := f.JoinPath(staged, "staged_dir")
- if err := os.Mkdir(stagedDir, 0777); err != nil {
- t.Fatal(err)
- }
- for i := 0; i < 100; i++ {
- f.WriteFile(f.JoinPath(stagedDir, fmt.Sprintf("%d", i)), "staged data")
- }
- if err := os.Rename(staged, f.JoinPath(watched, "staged")); err != nil {
- t.Fatal(err)
- }
- f.fsync()
- if len(f.events) < 100 {
- t.Fatalf("expected >100 staged events; got %d events: %v", len(f.events), f.events)
- }
- f.events = nil
- n, err := inotifyNodes()
- require.NoError(t, err)
- if n > 10 {
- t.Fatalf("watching more than 10 files: %d", n)
- }
- }
- func inotifyNodes() (int, error) {
- pid := os.Getpid()
- output, err := exec.Command("bash", "-c", fmt.Sprintf(
- "find /proc/%d/fd -lname anon_inode:inotify -printf '%%hinfo/%%f\n' | xargs cat | grep -c '^inotify'", pid)).Output()
- if err != nil {
- return 0, fmt.Errorf("error running command to determine number of watched files: %v", err)
- }
- n, err := strconv.Atoi(strings.TrimSpace(string(output)))
- if err != nil {
- return 0, fmt.Errorf("couldn't parse number of watched files: %v", err)
- }
- return n, nil
- }
- func TestDontRecurseWhenWatchingParentsOfNonExistentFiles(t *testing.T) {
- if runtime.GOOS != "linux" {
- t.Skip("This test uses linux-specific inotify checks")
- }
- f := newNotifyFixture(t)
- watched := f.TempDir("watched")
- f.watch(filepath.Join(watched, ".tiltignore"))
- excludedDir := f.JoinPath(watched, "excluded")
- for i := 0; i < 10; i++ {
- f.WriteFile(f.JoinPath(excludedDir, fmt.Sprintf("%d", i), "data.txt"), "initial data")
- }
- f.fsync()
- n, err := inotifyNodes()
- require.NoError(t, err)
- if n > 5 {
- t.Fatalf("watching more than 5 files: %d", n)
- }
- }
|