package library import ( "context" "os" "path/filepath" "testing" "time" "github.com/fsnotify/fsnotify" ) func expectCall(t *testing.T, ch <-chan struct{}, what string) { t.Helper() select { case <-ch: case <-time.After(3 * time.Second): t.Fatalf("no onChange after %s", what) } } func TestWatchDebouncesAndFollowsNewDirs(t *testing.T) { root := writeTree(t, map[string]string{"tokyo/a.jpg": "x"}) ctx, cancel := context.WithCancel(context.Background()) defer cancel() calls := make(chan struct{}, 10) if err := Watch(ctx, root, 100*time.Millisecond, func() { calls <- struct{}{} }); err != nil { t.Fatal(err) } for _, n := range []string{"b.jpg", "c.jpg", "d.jpg"} { os.WriteFile(filepath.Join(root, "tokyo", n), []byte("x"), 0o644) } expectCall(t, calls, "writes in existing album") select { case <-calls: t.Fatal("burst of writes produced more than one call") case <-time.After(300 * time.Millisecond): } os.Mkdir(filepath.Join(root, "iceland"), 0o755) expectCall(t, calls, "new album dir") time.Sleep(150 * time.Millisecond) // let the watcher add the new dir os.WriteFile(filepath.Join(root, "iceland", "a.jpg"), []byte("x"), 0o644) expectCall(t, calls, "write in new album") } func TestWatchLoopOverflowTriggersRescan(t *testing.T) { ctx, cancel := context.WithCancel(context.Background()) defer cancel() events := make(chan fsnotify.Event) errs := make(chan error) calls := make(chan struct{}, 1) go watchLoop(ctx, events, errs, func(string) error { return nil }, 50*time.Millisecond, func() { calls <- struct{}{} }) errs <- fsnotify.ErrEventOverflow expectCall(t, calls, "event overflow") }