package watcher import ( "context" "errors" "fmt" "testing" "time" "gitea.urkob.com/urko/git-webhook-ci/kit/config" "gitea.urkob.com/urko/git-webhook-ci/pkg" "github.com/fsnotify/fsnotify" "github.com/stretchr/testify/require" ) type testErrorNotifier struct { *fsnotify.Watcher } func (n *testErrorNotifier) NewWatcher() (*fsnotify.Watcher, error) { return nil, errIntentional } var ( errNotifier = &testErrorNotifier{} okNotifier = ¬ifier{} ) var ( mockDeploy pkg.DeployFunc mockErrorDeploy pkg.DeployFunc errIntentional = errors.New("intentional error") binaryPath = "" scriptPath = "" executionMaxTimeout = time.Second * 2 cfg *config.Config events = []fsnotify.Event{ { Name: "test event", Op: fsnotify.Create, }, { Name: "Write", Op: fsnotify.Write, }, } ) func TestMain(t *testing.M) { mockDeploy = func(binaryPath, scriptPath string) error { return nil } mockErrorDeploy = func(binaryPath, scriptPath string) error { return errIntentional } } func LoadConfig(t *testing.T) { t.Helper() cf, err := config.LoadConfig("testdata/config.yaml") if err != nil { panic(fmt.Errorf("Error loading config: %w", err)) } cfg = cf } func sendTestEvents(w *watcher) { for _, event := range events { w.fswatcher.Events <- event } } func newWatcher() *watcher { return NewWatcher(okNotifier, mockDeploy) } func newWatcherWithDeployError() *watcher { return NewWatcher(okNotifier, mockErrorDeploy) } func newWatcherWithCtorError() *watcher { return NewWatcher(errNotifier, mockDeploy) } func Test_NewNotifier(t *testing.T) { LoadConfig(t) require.NotNil(t, NewNotifier()) } func Test_NewWatcher(t *testing.T) { w := newWatcher() require.NotNil(t, w) } func Test_ErrorNewWatcher(t *testing.T) { w := newWatcherWithCtorError() require.Nil(t, w) } func Test_Close(t *testing.T) { w := newWatcher() err := w.Close() require.NoError(t, err) } func Test_Monitor(t *testing.T) { w := newWatcher() err := w.Monitor(cfg.FileToWatchPath) require.NoError(t, err) } func Test_ListenSuccess(t *testing.T) { w := newWatcher() 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 := newWatcherWithDeployError() 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 := newWatcher() 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) errors := make(chan error) w.Listen(binaryPath, scriptPath, errors) go func(cancel context.CancelFunc) { time.Sleep(executionMaxTimeout) cancel() }(cancel) sendTestEvents(w) return ctx, errors }