Skip to content

Commit

Permalink
chore: wire up tests, fix bugs discovered with tests
Browse files Browse the repository at this point in the history
  • Loading branch information
djosephsen committed Aug 6, 2024
1 parent cdd7fa4 commit 081b245
Show file tree
Hide file tree
Showing 2 changed files with 134 additions and 7 deletions.
11 changes: 6 additions & 5 deletions core/pkg/sync/file/fileinfo_watcher.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,8 +30,8 @@ type fileInfoWatcher struct {
// NewFsNotifyWatcher returns a new fsNotifyWatcher
func NewFileInfoWatcher(ctx context.Context, logger *logger.Logger) Watcher {
fiw := &fileInfoWatcher{
evChan: make(chan fsnotify.Event),
erChan: make(chan error),
evChan: make(chan fsnotify.Event, 256),
erChan: make(chan error, 256),
logger: logger,
}
// TODO: wire in configs
Expand Down Expand Up @@ -84,7 +84,7 @@ func (f *fileInfoWatcher) Remove(name string) error {
// Watchlist calls watchlist on the underlying fsnotify.Watcher
func (f *fileInfoWatcher) WatchList() []string {
f.mu.RLock()
defer f.mu.Unlock()
defer f.mu.RUnlock()
out := []string{}
for name := range f.watches {
n := name
Expand Down Expand Up @@ -131,7 +131,7 @@ func (f *fileInfoWatcher) update() error {
defer f.mu.Unlock()

for path, info := range f.watches {
newInfo, err := getFileInfo(path)
newInfo, err := f.statFunc(path)
if err != nil {
// if the file isn't there, it must have been removed
// fire off a remove event and remove it from the watches
Expand All @@ -141,6 +141,7 @@ func (f *fileInfoWatcher) update() error {
Op: fsnotify.Remove,
}
delete(f.watches, path)
continue
}
return err
}
Expand All @@ -162,7 +163,7 @@ func (f *fileInfoWatcher) update() error {
}

// generateEvent figures out what changed and generates an fsnotify.Event for it. (if we care)
// file removal events are handled above in the update() method
// file removal are handled above in the update() method
func (f *fileInfoWatcher) generateEvent(path string, newInfo fs.FileInfo) (*fsnotify.Event, error) {

Check failure on line 167 in core/pkg/sync/file/fileinfo_watcher.go

View workflow job for this annotation

GitHub Actions / lint

(*fileInfoWatcher).generateEvent - result 1 (error) is always nil (unparam)
info := f.watches[path]
switch {
Expand Down
130 changes: 128 additions & 2 deletions core/pkg/sync/file/fileinfo_watcher_test.go
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
package file

import (
"errors"
"fmt"
"io/fs"
"os"
"testing"
"time"

Expand Down Expand Up @@ -68,13 +71,136 @@ func Test_fileInfoWatcher_Add(t *testing.T) {
}
}

func Test_fileInfoWatcher_Remove(t *testing.T) {
tests := []struct {
name string
watcher *fileInfoWatcher
removeThis string
want []string
}{{
name: "remove foo",
watcher: makeTestWatcher(t, map[string]fs.FileInfo{"foo": &mockFileInfo{}, "bar": &mockFileInfo{}}),
removeThis: "foo",
want: []string{"bar"},
}}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
err := tt.watcher.Remove(tt.removeThis)
if err != nil {
t.Errorf("fileInfoWatcher.Remove() error = %v", err)
}
if !cmp.Equal(tt.watcher.WatchList(), tt.want) {
t.Errorf("fileInfoWatcher.Add(): want-, got+: %v ", cmp.Diff(tt.want, tt.watcher.WatchList()))
}
})
}
}

func Test_fileInfoWatcher_update(t *testing.T) {
tests := []struct {
name string
watcher *fileInfoWatcher
statFunc func(string) (fs.FileInfo, error)
wantErr bool
want *fsnotify.Event
}{
{
name: "chmod",
watcher: makeTestWatcher(t,
map[string]fs.FileInfo{
"foo": &mockFileInfo{
name: "foo",
mode: 0,
},
},
),
statFunc: func(path string) (fs.FileInfo, error) {
return &mockFileInfo{
name: "foo",
mode: 1,
}, nil
},
want: &fsnotify.Event{Name: "foo", Op: fsnotify.Chmod},
},
{
name: "write",
watcher: makeTestWatcher(t,
map[string]fs.FileInfo{
"foo": &mockFileInfo{
name: "foo",
modTime: time.Now().Local(),
},
},
),
statFunc: func(path string) (fs.FileInfo, error) {
return &mockFileInfo{
name: "foo",
modTime: (time.Now().Local().Add(5 * time.Minute)),
}, nil
},
want: &fsnotify.Event{Name: "foo", Op: fsnotify.Write},
},
{
name: "remove",
watcher: makeTestWatcher(t,
map[string]fs.FileInfo{
"foo": &mockFileInfo{
name: "foo",
},
},
),
statFunc: func(path string) (fs.FileInfo, error) {
return nil, fmt.Errorf("mock file-no-existy error: %w", os.ErrNotExist)
},
want: &fsnotify.Event{Name: "foo", Op: fsnotify.Remove},
},
{
name: "unknown error",
watcher: makeTestWatcher(t,
map[string]fs.FileInfo{
"foo": &mockFileInfo{
name: "foo",
},
},
),
statFunc: func(path string) (fs.FileInfo, error) {
return nil, errors.New("unhandled error")
},
wantErr: true,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
// set the statFunc
tt.watcher.statFunc = tt.statFunc
// run an update
// this also flexes fileinfowatcher.generateEvent()
err := tt.watcher.update()
if err != nil {
if tt.wantErr {
return
} else {

Check failure on line 182 in core/pkg/sync/file/fileinfo_watcher_test.go

View workflow job for this annotation

GitHub Actions / lint

indent-error-flow: if block ends with a return statement, so drop this else and outdent its block (revive)
t.Errorf("fileInfoWatcher.update() unexpected error = %v, wantErr %v", err, tt.wantErr)
}
}
// slurp an event off the event chan
out := <-tt.watcher.Events()
if out != *tt.want {
t.Errorf("fileInfoWatcher.update() wanted %v, got %v", tt.want, out)
}
})
}
}

// Helpers

// makeTestWatcher returns a pointer to a fileInfoWatcher suitable for testing
func makeTestWatcher(t *testing.T, watches map[string]fs.FileInfo) *fileInfoWatcher {
t.Helper()

return &fileInfoWatcher{
evChan: make(chan fsnotify.Event),
erChan: make(chan error),
evChan: make(chan fsnotify.Event, 512),
erChan: make(chan error, 512),
watches: watches,
}
}
Expand Down

0 comments on commit 081b245

Please sign in to comment.