package internal import ( "context" "errors" "testing" "time" "github.com/fsnotify/fsnotify" "github.com/sirupsen/logrus" "github.com/stretchr/testify/require" ) var logger *logrus.Logger type testErrorNotifier struct { *fsnotify.Watcher } func (n *testErrorNotifier) NewWatcher() (*fsnotify.Watcher, error) { return nil, errIntentional } var ( errNotifier = &testErrorNotifier{} okNotifier = &Notifier{} ) var ( mockDeploy ExecFunc mockErrorDeploy ExecFunc errIntentional = errors.New("intentional error") binaryPath = "" scriptPath = "" executionMaxTimeout = time.Second * 2 events = []fsnotify.Event{ { Name: "test event", Op: fsnotify.Create, }, { Name: "Write", Op: fsnotify.Write, }, } ) func TestMain(m *testing.M) { logger = logrus.New() logger.SetLevel(logrus.DebugLevel) mockDeploy = func(executableFilePath string, args ...string) error { return nil } mockErrorDeploy = func(executableFilePath string, args ...string) error { return errIntentional } } func sendTestEvents(w *Watcher) { for _, event := range events { w.fswatcher.Events <- event } } func newWatcher() (*Watcher, error) { return NewWatcher(logger, okNotifier, mockDeploy) } func newWatcherWithDeployError() (*Watcher, error) { return NewWatcher(logger, okNotifier, mockErrorDeploy) } func newWatcherWithCtorError() (*Watcher, error) { return NewWatcher(logger, errNotifier, mockDeploy) } func Test_NewNotifier(t *testing.T) { require.NotNil(t, NewNotifier()) } func Test_NewWatcher(t *testing.T) { w, err := newWatcher() require.NoError(t, err) require.NotNil(t, w) } func Test_ErrorNewWatcher(t *testing.T) { w, err := newWatcherWithCtorError() require.NoError(t, err) require.NotNil(t, w) } func Test_Close(t *testing.T) { w, err := newWatcher() require.NoError(t, err) require.NotNil(t, w) require.NoError(t, w.Close()) } func Test_Monitor(t *testing.T) { w, err := newWatcher() require.NoError(t, err) require.NoError(t, w.Monitor("testdata/file-to-watch.txt")) } func Test_ListenSuccess(t *testing.T) { w, err := newWatcher() require.NoError(t, err) ctx, errors := listenWithSendEvents(w) for { select { case <-ctx.Done(): return case err := <-errors: require.NoError(t, err) return } } } func Test_ListenError(t *testing.T) { w, err := newWatcherWithDeployError() require.NoError(t, err) ctx, errors := listenWithSendEvents(w) for { select { case <-ctx.Done(): return case err := <-errors: require.Error(t, err) require.EqualError(t, err, errIntentional.Error()) return } } } func Test_ListenErrorChanClose(t *testing.T) { w, err := newWatcher() require.NoError(t, err) ctx, errors := listenWithSendEvents(w) close(w.fswatcher.Events) for { select { case <-ctx.Done(): return case err := <-errors: require.Error(t, err) require.EqualError(t, err, errEventsClosedChan.Error()) return } } } func listenWithSendEvents(w *Watcher) (context.Context, chan error) { ctx, cancel := context.WithTimeout(context.Background(), executionMaxTimeout) errChan := make(chan error) go w.Listen(ctx, errChan, scriptPath) go func(cancel context.CancelFunc) { time.Sleep(executionMaxTimeout) cancel() }(cancel) sendTestEvents(w) return ctx, errChan }