diff options
author | Valery Piashchynski <[email protected]> | 2020-12-19 18:28:33 +0300 |
---|---|---|
committer | GitHub <[email protected]> | 2020-12-19 18:28:33 +0300 |
commit | b8a889168094a03d13a734625b59a31459a0b963 (patch) | |
tree | 1f34d18fb3de24f7940b87e62ea1f342eb7ac414 | |
parent | 73d3f968b690b0e34e571580243e5fdd0d42199c (diff) | |
parent | 52ac2c31107b396433042c1e46de2ddb07546bec (diff) |
Merge pull request #455 from spiral/fix_reload_plugin
plugin/reload fixes
-rw-r--r-- | .github/workflows/build.yml | 6 | ||||
-rw-r--r-- | codecov.yml | 12 | ||||
-rw-r--r-- | pipe_factory.go | 7 | ||||
-rw-r--r-- | service/reload/samefile.go | 9 | ||||
-rw-r--r-- | service/reload/samefile_windows.go | 12 | ||||
-rw-r--r-- | service/reload/service.go | 35 | ||||
-rw-r--r-- | service/reload/service_test.go | 1 | ||||
-rw-r--r-- | service/reload/watcher.go | 150 | ||||
-rw-r--r-- | service/reload/watcher_test.go | 400 |
9 files changed, 255 insertions, 377 deletions
diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 92b55666..242ad184 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -3,6 +3,12 @@ name: build on: push: pull_request: + branches: + # Branches from forks have the form 'user:branch-name' so we only run + # this job on pull_request events for branches that look like fork + # branches. Without this we would end up running this job twice for non + # forked PRs, once for the push and then once for opening the PR. + - '**:**' jobs: php: diff --git a/codecov.yml b/codecov.yml new file mode 100644 index 00000000..672717e3 --- /dev/null +++ b/codecov.yml @@ -0,0 +1,12 @@ +coverage: + status: + project: + default: + target: auto + threshold: 0% + informational: true + patch: + default: + target: auto + threshold: 0% + informational: true diff --git a/pipe_factory.go b/pipe_factory.go index 9696a474..e9e750c4 100644 --- a/pipe_factory.go +++ b/pipe_factory.go @@ -2,10 +2,11 @@ package roadrunner import ( "fmt" - "github.com/pkg/errors" - "github.com/spiral/goridge/v2" "io" "os/exec" + + "github.com/pkg/errors" + "github.com/spiral/goridge/v2" ) // PipeFactory connects to workers using standard @@ -50,7 +51,7 @@ func (f *PipeFactory) SpawnWorker(cmd *exec.Cmd) (w *Worker, err error) { err := w.Kill() if err != nil { // there is no logger here, how to handle error in goroutines ? - fmt.Println(fmt.Sprintf("error killing the worker with PID number %d, Created: %s", w.Pid, w.Created)) + fmt.Printf("error killing the worker with PID number %d, Created: %s", w.Pid, w.Created) } }(w) diff --git a/service/reload/samefile.go b/service/reload/samefile.go deleted file mode 100644 index 80df0431..00000000 --- a/service/reload/samefile.go +++ /dev/null @@ -1,9 +0,0 @@ -// +build !windows - -package reload - -import "os" - -func sameFile(fi1, fi2 os.FileInfo) bool { - return os.SameFile(fi1, fi2) -} diff --git a/service/reload/samefile_windows.go b/service/reload/samefile_windows.go deleted file mode 100644 index 5f70d327..00000000 --- a/service/reload/samefile_windows.go +++ /dev/null @@ -1,12 +0,0 @@ -// +build windows - -package reload - -import "os" - -func sameFile(fi1, fi2 os.FileInfo) bool { - return fi1.ModTime() == fi2.ModTime() && - fi1.Size() == fi2.Size() && - fi1.Mode() == fi2.Mode() && - fi1.IsDir() == fi2.IsDir() -} diff --git a/service/reload/service.go b/service/reload/service.go index 9c615e0b..c065d95d 100644 --- a/service/reload/service.go +++ b/service/reload/service.go @@ -2,12 +2,13 @@ package reload import ( "errors" - "github.com/sirupsen/logrus" - "github.com/spiral/roadrunner" - "github.com/spiral/roadrunner/service" "os" "strings" "time" + + "github.com/sirupsen/logrus" + "github.com/spiral/roadrunner" + "github.com/spiral/roadrunner/service" ) // ID contains default service name. @@ -51,10 +52,10 @@ func (s *Service) Init(cfg *Config, log *logrus.Logger, c service.Container) (bo return false, err } configs = append(configs, WatcherConfig{ - serviceName: serviceName, - recursive: config.Recursive, - directories: config.Dirs, - filterHooks: func(filename string, patterns []string) error { + ServiceName: serviceName, + Recursive: config.Recursive, + Directories: config.Dirs, + FilterHooks: func(filename string, patterns []string) error { for i := 0; i < len(patterns); i++ { if strings.Contains(filename, patterns[i]) { return nil @@ -62,9 +63,9 @@ func (s *Service) Init(cfg *Config, log *logrus.Logger, c service.Container) (bo } return ErrorSkip }, - files: make(map[string]os.FileInfo), - ignored: ignored, - filePatterns: append(config.Patterns, cfg.Patterns...), + Files: make(map[string]os.FileInfo), + Ignored: ignored, + FilePatterns: append(config.Patterns, cfg.Patterns...), }) } @@ -91,7 +92,7 @@ func (s *Service) Serve() error { }, 100) // use the same interval - ticker := time.NewTicker(s.cfg.Interval) + timer := time.NewTimer(s.cfg.Interval) // drain channel in case of leaved messages defer func() { @@ -120,15 +121,15 @@ func (s *Service) Serve() error { case config := <-treshholdc: // replace previous value in map by more recent without adding new one updated[config.service] = config.serviceConfig - // stop ticker - ticker.Stop() + // stop timer + timer.Stop() // restart // logic is following: // if we getting a lot of events, we should't restart particular service on each of it (user doing bug move or very fast typing) - // instead, we are resetting the ticker and wait for Interval time + // instead, we are resetting the timer and wait for Interval time // If there is no more events, we restart service only once - ticker = time.NewTicker(s.cfg.Interval) - case <-ticker.C: + timer.Reset(s.cfg.Interval) + case <-timer.C: if len(updated) > 0 { for k, v := range updated { sv := *v.service @@ -142,7 +143,7 @@ func (s *Service) Serve() error { updated = make(map[string]ServiceConfig, 100) } case <-s.stopc: - ticker.Stop() + timer.Stop() return } } diff --git a/service/reload/service_test.go b/service/reload/service_test.go deleted file mode 100644 index 7cad4a5d..00000000 --- a/service/reload/service_test.go +++ /dev/null @@ -1 +0,0 @@ -package reload diff --git a/service/reload/watcher.go b/service/reload/watcher.go index 721495c3..1397dfa5 100644 --- a/service/reload/watcher.go +++ b/service/reload/watcher.go @@ -19,33 +19,33 @@ type SimpleHook func(filename string, pattern []string) error // changes occur. It includes the os.FileInfo of the changed file or // directory and the type of event that's occurred and the full path of the file. type Event struct { - path string - info os.FileInfo + Path string + Info os.FileInfo service string // type of service, http, grpc, etc... } type WatcherConfig struct { // service name - serviceName string + ServiceName string - // recursive or just add by singe directory - recursive bool + // Recursive or just add by singe directory + Recursive bool - // directories used per-service - directories []string + // Directories used per-service + Directories []string // simple hook, just CONTAINS - filterHooks func(filename string, pattern []string) error + FilterHooks func(filename string, pattern []string) error - // path to file with files - files map[string]os.FileInfo + // path to file with Files + Files map[string]os.FileInfo - // ignored directories, used map for O(1) amortized get - ignored map[string]struct{} + // Ignored Directories, used map for O(1) amortized get + Ignored map[string]struct{} - // filePatterns to ignore - filePatterns []string + // FilePatterns to ignore + FilePatterns []string } type Watcher struct { @@ -53,7 +53,7 @@ type Watcher struct { Event chan Event close chan struct{} - //============================= + // ============================= mu *sync.Mutex // indicates is walker started or not @@ -73,7 +73,7 @@ func NewWatcher(configs []WatcherConfig, options ...Options) (*Watcher, error) { Event: make(chan Event), mu: &sync.Mutex{}, - close: make(chan struct{}), + close: make(chan struct{}, 1), //workingDir: workDir, watcherConfigs: make(map[string]WatcherConfig), @@ -81,7 +81,7 @@ func NewWatcher(configs []WatcherConfig, options ...Options) (*Watcher, error) { // add watcherConfigs by service names for _, v := range configs { - w.watcherConfigs[v.serviceName] = v + w.watcherConfigs[v.ServiceName] = v } // apply options @@ -105,7 +105,7 @@ func (w *Watcher) initFs() error { } // workaround. in golang you can't assign to map in struct field tmp := w.watcherConfigs[srvName] - tmp.files = fileList + tmp.Files = fileList w.watcherConfigs[srvName] = tmp } return nil @@ -127,14 +127,13 @@ func ConvertIgnored(ignored []string) (map[string]struct{}, error) { } return ign, nil - } // GetAllFiles returns all files initialized for particular company func (w *Watcher) GetAllFiles(serviceName string) []os.FileInfo { var ret []os.FileInfo - for _, v := range w.watcherConfigs[serviceName].files { + for _, v := range w.watcherConfigs[serviceName].Files { ret = append(ret, v) } @@ -146,12 +145,12 @@ func (w *Watcher) GetAllFiles(serviceName string) []os.FileInfo { // In case of file watch errors, this value can be increased system-wide // For linux: set --> fs.inotify.max_user_watches = 600000 (under /etc/<choose_name_here>.conf) // Add apply: sudo sysctl -p --system -//func SetMaxFileEvents(events int) Options { +// func SetMaxFileEvents(events int) Options { // return func(watcher *Watcher) { // watcher.maxFileWatchEvents = events // } // -//} +// } // pass map from outside func (w *Watcher) retrieveFilesSingle(serviceName, path string) (map[string]os.FileInfo, error) { @@ -178,13 +177,13 @@ func (w *Watcher) retrieveFilesSingle(serviceName, path string) (map[string]os.F outer: for i := 0; i < len(fileInfoList); i++ { // if file in ignored --> continue - if _, ignored := w.watcherConfigs[serviceName].ignored[path]; ignored { + if _, ignored := w.watcherConfigs[serviceName].Ignored[path]; ignored { continue } // if filename does not contain pattern --> ignore that file - if w.watcherConfigs[serviceName].filePatterns != nil && w.watcherConfigs[serviceName].filterHooks != nil { - err = w.watcherConfigs[serviceName].filterHooks(fileInfoList[i].Name(), w.watcherConfigs[serviceName].filePatterns) + if w.watcherConfigs[serviceName].FilePatterns != nil && w.watcherConfigs[serviceName].FilterHooks != nil { + err = w.watcherConfigs[serviceName].FilterHooks(fileInfoList[i].Name(), w.watcherConfigs[serviceName].FilePatterns) if err == ErrorSkip { continue outer } @@ -223,27 +222,23 @@ func (w *Watcher) waitEvent(d time.Duration) error { // this is not very effective way // because we have to wait on Lock // better is to listen files in parallel, but, since that would be used in debug... TODO - for serviceName, config := range w.watcherConfigs { - go func(sn string, c WatcherConfig) { - fileList, _ := w.retrieveFileList(sn, c) - w.pollEvents(c.serviceName, fileList) - }(serviceName, config) + for serviceName := range w.watcherConfigs { + // TODO sync approach + fileList, _ := w.retrieveFileList(serviceName, w.watcherConfigs[serviceName]) + w.pollEvents(w.watcherConfigs[serviceName].ServiceName, fileList) } } } - } // retrieveFileList get file list for service func (w *Watcher) retrieveFileList(serviceName string, config WatcherConfig) (map[string]os.FileInfo, error) { - w.mu.Lock() - defer w.mu.Unlock() fileList := make(map[string]os.FileInfo) - if config.recursive { + if config.Recursive { // walk through directories recursively - for _, dir := range config.directories { + for i := 0; i < len(config.Directories); i++ { // full path is workdir/relative_path - fullPath, err := filepath.Abs(dir) + fullPath, err := filepath.Abs(config.Directories[i]) if err != nil { return nil, err } @@ -252,16 +247,16 @@ func (w *Watcher) retrieveFileList(serviceName string, config WatcherConfig) (ma return nil, err } - for k, v := range list { - fileList[k] = v + for k := range list { + fileList[k] = list[k] } } return fileList, nil } - for _, dir := range config.directories { + for i := 0; i < len(config.Directories); i++ { // full path is workdir/relative_path - fullPath, err := filepath.Abs(dir) + fullPath, err := filepath.Abs(config.Directories[i]) if err != nil { return nil, err } @@ -290,7 +285,7 @@ func (w *Watcher) retrieveFilesRecursive(serviceName, root string) (map[string]o // If path is ignored and it's a directory, skip the directory. If it's // ignored and it's a single file, skip the file. - _, ignored := w.watcherConfigs[serviceName].ignored[path] + _, ignored := w.watcherConfigs[serviceName].Ignored[path] if ignored { if info.IsDir() { // if it's dir, ignore whole @@ -300,7 +295,7 @@ func (w *Watcher) retrieveFilesRecursive(serviceName, root string) (map[string]o } // if filename does not contain pattern --> ignore that file - err = w.watcherConfigs[serviceName].filterHooks(info.Name(), w.watcherConfigs[serviceName].filePatterns) + err = w.watcherConfigs[serviceName].FilterHooks(info.Name(), w.watcherConfigs[serviceName].FilePatterns) if err == ErrorSkip { return nil } @@ -320,76 +315,53 @@ func (w *Watcher) pollEvents(serviceName string, files map[string]os.FileInfo) { removes := make(map[string]os.FileInfo) // Check for removed files. - for pth, info := range w.watcherConfigs[serviceName].files { + for pth := range w.watcherConfigs[serviceName].Files { if _, found := files[pth]; !found { - removes[pth] = info + removes[pth] = w.watcherConfigs[serviceName].Files[pth] } } // Check for created files, writes and chmods. - for pth, info := range files { - if info.IsDir() { + for pth := range files { + if files[pth].IsDir() { continue } - oldInfo, found := w.watcherConfigs[serviceName].files[pth] + oldInfo, found := w.watcherConfigs[serviceName].Files[pth] if !found { // A file was created. - creates[pth] = info + creates[pth] = files[pth] continue } - if oldInfo.ModTime() != info.ModTime() { - w.watcherConfigs[serviceName].files[pth] = info - w.Event <- Event{ - path: pth, - info: info, - service: serviceName, - } - } - if oldInfo.Mode() != info.Mode() { - w.watcherConfigs[serviceName].files[pth] = info + + if oldInfo.ModTime() != files[pth].ModTime() || oldInfo.Mode() != files[pth].Mode() { + w.watcherConfigs[serviceName].Files[pth] = files[pth] w.Event <- Event{ - path: pth, - info: info, + Path: pth, + Info: files[pth], service: serviceName, } } } - //Check for renames and moves. - for path1, info1 := range removes { - for path2, info2 := range creates { - if sameFile(info1, info2) { - e := Event{ - path: path2, - info: info2, - service: serviceName, - } + // Send all the remaining create and remove events. + for pth := range creates { + // add file to the plugin watch files + w.watcherConfigs[serviceName].Files[pth] = creates[pth] - // remove initial path - delete(w.watcherConfigs[serviceName].files, path1) - // update with new - w.watcherConfigs[serviceName].files[path2] = info2 - - - w.Event <- e - } - } - } - - //Send all the remaining create and remove events. - for pth, info := range creates { - w.watcherConfigs[serviceName].files[pth] = info w.Event <- Event{ - path: pth, - info: info, + Path: pth, + Info: creates[pth], service: serviceName, } } - for pth, info := range removes { - delete(w.watcherConfigs[serviceName].files, pth) + + for pth := range removes { + // delete path from the config + delete(w.watcherConfigs[serviceName].Files, pth) + w.Event <- Event{ - path: pth, - info: info, + Path: pth, + Info: removes[pth], service: serviceName, } } diff --git a/service/reload/watcher_test.go b/service/reload/watcher_test.go index 9683d2de..ac5d3740 100644 --- a/service/reload/watcher_test.go +++ b/service/reload/watcher_test.go @@ -6,10 +6,11 @@ import ( "io/ioutil" "os" "path/filepath" - "runtime" "strings" "testing" "time" + + "github.com/stretchr/testify/assert" ) var testServiceName = "test" @@ -34,13 +35,13 @@ func Test_Correct_Watcher_Init(t *testing.T) { } wc := WatcherConfig{ - serviceName: testServiceName, - recursive: false, - directories: []string{tempDir}, - filterHooks: nil, - files: make(map[string]os.FileInfo), - ignored: nil, - filePatterns: nil, + ServiceName: testServiceName, + Recursive: false, + Directories: []string{tempDir}, + FilterHooks: nil, + Files: make(map[string]os.FileInfo), + Ignored: nil, + FilePatterns: nil, } w, err := NewWatcher([]WatcherConfig{wc}) @@ -59,84 +60,69 @@ func Test_Correct_Watcher_Init(t *testing.T) { // change file and see, if event had come to handler func Test_Get_FileEvent(t *testing.T) { tempDir, err := ioutil.TempDir(".", "") - c := make(chan struct{}) defer func(name string) { err = freeResources(name) - if err != nil { - c <- struct{}{} - t.Fatal(err) - } - c <- struct{}{} + assert.NoError(t, err) }(tempDir) - - if err != nil { - t.Fatal(err) - } + assert.NoError(t, err) err = ioutil.WriteFile(filepath.Join(tempDir, "file1.txt"), []byte{}, 0755) - if err != nil { - t.Fatal(err) - } - + assert.NoError(t, err) err = ioutil.WriteFile(filepath.Join(tempDir, "file2.txt"), []byte{}, 0755) - if err != nil { - t.Fatal(err) - } + assert.NoError(t, err) err = ioutil.WriteFile(filepath.Join(tempDir, "file3.txt"), []byte{}, 0755) - if err != nil { - t.Fatal(err) - } + assert.NoError(t, err) wc := WatcherConfig{ - serviceName: testServiceName, - recursive: false, - directories: []string{tempDir}, - filterHooks: nil, - files: make(map[string]os.FileInfo), - ignored: nil, - filePatterns: []string{"aaa", "txt"}, + ServiceName: testServiceName, + Recursive: false, + Directories: []string{tempDir}, + FilterHooks: nil, + Files: make(map[string]os.FileInfo), + Ignored: nil, + FilePatterns: []string{"aaa", "txt"}, } w, err := NewWatcher([]WatcherConfig{wc}) - if err != nil { - t.Fatal(err) - } + assert.NoError(t, err) // should be 3 files and directory if len(w.GetAllFiles(testServiceName)) != 4 { t.Fatal("incorrect directories len") } - go limitTime(time.Second * 10, t.Name(), c) - go func() { + stop := make(chan struct{}, 1) go func() { - time.Sleep(time.Second) - err2 := ioutil.WriteFile(filepath.Join(tempDir, "file2.txt"), + time.Sleep(time.Second * 2) + err := ioutil.WriteFile(filepath.Join(tempDir, "file2.txt"), []byte{1, 1, 1}, 0755) - if err2 != nil { - panic(err2) - } - runtime.Goexit() + assert.NoError(t, err) + time.Sleep(time.Second) + stop <- struct{}{} }() go func() { - for e := range w.Event { - if e.path != "file2.txt" { - panic("didn't handle event when write file2") + for { + select { + case e := <-w.Event: + if e.Path != "file2.txt" { + assert.Fail(t, "didn't handle event when write file2") + } + w.Stop() + case <-stop: + return } - w.Stop() } + }() }() err = w.StartPolling(time.Second) - if err != nil { - t.Fatal(err) - } + assert.NoError(t, err) } // scenario @@ -145,41 +131,29 @@ func Test_Get_FileEvent(t *testing.T) { // change file with txt extension, and see, if event had not come to handler because it was filtered func Test_FileExtensionFilter(t *testing.T) { tempDir, err := ioutil.TempDir(".", "") - c := make(chan struct{}) + assert.NoError(t, err) + defer func(name string) { err = freeResources(name) - if err != nil { - c <- struct{}{} - t.Fatal(err) - } - c <- struct{}{} + assert.NoError(t, err) }(tempDir) - if err != nil { - t.Fatal(err) - } err = ioutil.WriteFile(filepath.Join(tempDir, "file1.aaa"), []byte{}, 0755) - if err != nil { - t.Fatal(err) - } + assert.NoError(t, err) err = ioutil.WriteFile(filepath.Join(tempDir, "file2.bbb"), []byte{}, 0755) - if err != nil { - t.Fatal(err) - } + assert.NoError(t, err) err = ioutil.WriteFile(filepath.Join(tempDir, "file3.txt"), []byte{}, 0755) - if err != nil { - t.Fatal(err) - } + assert.NoError(t, err) wc := WatcherConfig{ - serviceName: testServiceName, - recursive: false, - directories: []string{tempDir}, - filterHooks: func(filename string, patterns []string) error { + ServiceName: testServiceName, + Recursive: false, + Directories: []string{tempDir}, + FilterHooks: func(filename string, patterns []string) error { for i := 0; i < len(patterns); i++ { if strings.Contains(filename, patterns[i]) { return nil @@ -187,15 +161,13 @@ func Test_FileExtensionFilter(t *testing.T) { } return ErrorSkip }, - files: make(map[string]os.FileInfo), - ignored: nil, - filePatterns: []string{"aaa", "bbb"}, + Files: make(map[string]os.FileInfo), + Ignored: nil, + FilePatterns: []string{"aaa", "bbb"}, } w, err := NewWatcher([]WatcherConfig{wc}) - if err != nil { - t.Fatal(err) - } + assert.NoError(t, err) dirLen := len(w.GetAllFiles(testServiceName)) // should be 2 files (one filtered) and directory @@ -203,33 +175,32 @@ func Test_FileExtensionFilter(t *testing.T) { t.Fatalf("incorrect directories len, len is: %d", dirLen) } - go limitTime(time.Second * 5, t.Name(), c) - go func() { + stop := make(chan struct{}, 1) + go func() { - err2 := ioutil.WriteFile(filepath.Join(tempDir, "file3.txt"), + time.Sleep(time.Second) + err := ioutil.WriteFile(filepath.Join(tempDir, "file3.txt"), []byte{1, 1, 1}, 0755) - if err2 != nil { - panic(err2) - } - - runtime.Goexit() + assert.NoError(t, err) + stop <- struct{}{} }() go func() { - for e := range w.Event { - fmt.Println(e.info.Name()) - panic("handled event from filtered file") + time.Sleep(time.Second) + select { + case <-w.Event: + assert.Fail(t, "handled event from filtered file") + case <-stop: + return } }() + time.Sleep(time.Second) w.Stop() - runtime.Goexit() }() err = w.StartPolling(time.Second) - if err != nil { - t.Fatal(err) - } + assert.NoError(t, err) } // nested @@ -241,44 +212,32 @@ func Test_Recursive_Support(t *testing.T) { tempDir, err := ioutil.TempDir(".", "") defer func() { err = freeResources(tempDir) - if err != nil { - t.Fatal(err) - } + assert.NoError(t, err) }() nestedDir, err := ioutil.TempDir(tempDir, "nested") - if err != nil { - t.Fatal(err) - } + assert.NoError(t, err) err = ioutil.WriteFile(filepath.Join(tempDir, "file1.aaa"), []byte{}, 0755) - if err != nil { - t.Fatal(err) - } + assert.NoError(t, err) err = ioutil.WriteFile(filepath.Join(tempDir, "file2.bbb"), []byte{}, 0755) - if err != nil { - t.Fatal(err) - } + assert.NoError(t, err) err = ioutil.WriteFile(filepath.Join(nestedDir, "file3.txt"), []byte{}, 0755) - if err != nil { - t.Fatal(err) - } + assert.NoError(t, err) err = ioutil.WriteFile(filepath.Join(nestedDir, "file4.aaa"), []byte{}, 0755) - if err != nil { - t.Fatal(err) - } + assert.NoError(t, err) wc := WatcherConfig{ - serviceName: testServiceName, - recursive: true, - directories: []string{tempDir}, - filterHooks: func(filename string, patterns []string) error { + ServiceName: testServiceName, + Recursive: true, + Directories: []string{tempDir}, + FilterHooks: func(filename string, patterns []string) error { for i := 0; i < len(patterns); i++ { if strings.Contains(filename, patterns[i]) { return nil @@ -286,15 +245,13 @@ func Test_Recursive_Support(t *testing.T) { } return ErrorSkip }, - files: make(map[string]os.FileInfo), - ignored: nil, - filePatterns: []string{"aaa", "bbb"}, + Files: make(map[string]os.FileInfo), + Ignored: nil, + FilePatterns: []string{"aaa", "bbb"}, } w, err := NewWatcher([]WatcherConfig{wc}) - if err != nil { - t.Fatal(err) - } + assert.NoError(t, err) dirLen := len(w.GetAllFiles(testServiceName)) // should be 3 files (2 from root dir, and 1 from nested), filtered txt @@ -303,28 +260,35 @@ func Test_Recursive_Support(t *testing.T) { } go func() { + stop := make(chan struct{}, 1) // time sleep is used here because StartPolling is blocking operation time.Sleep(time.Second * 5) // change file in nested directory err = ioutil.WriteFile(filepath.Join(nestedDir, "file4.aaa"), []byte{1, 1, 1}, 0755) - if err != nil { - panic(err) - } + assert.NoError(t, err) + go func() { - for e := range w.Event { - if e.info.Name() != "file4.aaa" { - panic("wrong handled event from watcher in nested dir") + time.Sleep(time.Second) + for { + select { + case e := <-w.Event: + if e.Info.Name() != "file4.aaa" { + assert.Fail(t, "wrong handled event from watcher in nested dir") + } + case <-stop: + w.Stop() + return } - w.Stop() } }() + + time.Sleep(time.Second) + stop <- struct{}{} }() err = w.StartPolling(time.Second) - if err != nil { - t.Fatal(err) - } + assert.NoError(t, err) } func Test_Wrong_Dir(t *testing.T) { @@ -332,10 +296,10 @@ func Test_Wrong_Dir(t *testing.T) { wrongDir := "askdjfhaksdlfksdf" wc := WatcherConfig{ - serviceName: testServiceName, - recursive: true, - directories: []string{wrongDir}, - filterHooks: func(filename string, patterns []string) error { + ServiceName: testServiceName, + Recursive: true, + Directories: []string{wrongDir}, + FilterHooks: func(filename string, patterns []string) error { for i := 0; i < len(patterns); i++ { if strings.Contains(filename, patterns[i]) { return nil @@ -343,68 +307,49 @@ func Test_Wrong_Dir(t *testing.T) { } return ErrorSkip }, - files: make(map[string]os.FileInfo), - ignored: nil, - filePatterns: []string{"aaa", "bbb"}, + Files: make(map[string]os.FileInfo), + Ignored: nil, + FilePatterns: []string{"aaa", "bbb"}, } _, err := NewWatcher([]WatcherConfig{wc}) - if err == nil { - t.Fatal(err) - } + assert.Error(t, err) } func Test_Filter_Directory(t *testing.T) { tempDir, err := ioutil.TempDir(".", "") - c := make(chan struct{}) defer func(name string) { err = freeResources(name) - if err != nil { - c <- struct{}{} - t.Fatal(err) - } - c <- struct{}{} + assert.NoError(t, err) }(tempDir) - go limitTime(time.Second*10, t.Name(), c) - nestedDir, err := ioutil.TempDir(tempDir, "nested") - if err != nil { - t.Fatal(err) - } + assert.NoError(t, err) err = ioutil.WriteFile(filepath.Join(tempDir, "file1.aaa"), []byte{}, 0755) - if err != nil { - t.Fatal(err) - } + assert.NoError(t, err) err = ioutil.WriteFile(filepath.Join(tempDir, "file2.bbb"), []byte{}, 0755) - if err != nil { - t.Fatal(err) - } + assert.NoError(t, err) err = ioutil.WriteFile(filepath.Join(nestedDir, "file3.txt"), []byte{}, 0755) - if err != nil { - t.Fatal(err) - } + assert.NoError(t, err) err = ioutil.WriteFile(filepath.Join(nestedDir, "file4.aaa"), []byte{}, 0755) - if err != nil { - t.Fatal(err) - } + assert.NoError(t, err) ignored, err := ConvertIgnored([]string{nestedDir}) if err != nil { t.Fatal(err) } wc := WatcherConfig{ - serviceName: testServiceName, - recursive: true, - directories: []string{tempDir}, - filterHooks: func(filename string, patterns []string) error { + ServiceName: testServiceName, + Recursive: true, + Directories: []string{tempDir}, + FilterHooks: func(filename string, patterns []string) error { for i := 0; i < len(patterns); i++ { if strings.Contains(filename, patterns[i]) { return nil @@ -412,9 +357,9 @@ func Test_Filter_Directory(t *testing.T) { } return ErrorSkip }, - files: make(map[string]os.FileInfo), - ignored: ignored, - filePatterns: []string{"aaa", "bbb", "txt"}, + Files: make(map[string]os.FileInfo), + Ignored: ignored, + FilePatterns: []string{"aaa", "bbb", "txt"}, } w, err := NewWatcher([]WatcherConfig{wc}) @@ -429,25 +374,28 @@ func Test_Filter_Directory(t *testing.T) { } go func() { + stop := make(chan struct{}, 1) go func() { - err2 := ioutil.WriteFile(filepath.Join(nestedDir, "file4.aaa"), + time.Sleep(time.Second) + err := ioutil.WriteFile(filepath.Join(nestedDir, "file4.aaa"), []byte{1, 1, 1}, 0755) - if err2 != nil { - panic(err2) - } + assert.NoError(t, err) }() go func() { - for e := range w.Event { - fmt.Println("file: " + e.info.Name()) - panic("handled event from watcher in nested dir") + select { + case e := <-w.Event: + fmt.Println("file: " + e.Info.Name()) + assert.Fail(t, "handled event from watcher in nested dir") + case <-stop: + w.Stop() + return } }() // time sleep is used here because StartPolling is blocking operation time.Sleep(time.Second * 5) - w.Stop() - + stop <- struct{}{} }() err = w.StartPolling(time.Second) @@ -460,54 +408,38 @@ func Test_Filter_Directory(t *testing.T) { // should fire an event func Test_Copy_Directory(t *testing.T) { tempDir, err := ioutil.TempDir(".", "") - c := make(chan struct{}) + defer func() { err = freeResources(tempDir) - if err != nil { - c <- struct{}{} - t.Fatal(err) - } - c <- struct{}{} + assert.NoError(t, err) }() nestedDir, err := ioutil.TempDir(tempDir, "nested") - if err != nil { - t.Fatal(err) - } + assert.NoError(t, err) err = ioutil.WriteFile(filepath.Join(tempDir, "file1.aaa"), []byte{}, 0755) - if err != nil { - t.Fatal(err) - } + assert.NoError(t, err) err = ioutil.WriteFile(filepath.Join(tempDir, "file2.bbb"), []byte{}, 0755) - if err != nil { - t.Fatal(err) - } + assert.NoError(t, err) err = ioutil.WriteFile(filepath.Join(nestedDir, "file3.txt"), []byte{}, 0755) - if err != nil { - t.Fatal(err) - } + assert.NoError(t, err) err = ioutil.WriteFile(filepath.Join(nestedDir, "file4.aaa"), []byte{}, 0755) - if err != nil { - t.Fatal(err) - } + assert.NoError(t, err) ignored, err := ConvertIgnored([]string{nestedDir}) - if err != nil { - t.Fatal(err) - } + assert.NoError(t, err) wc := WatcherConfig{ - serviceName: testServiceName, - recursive: true, - directories: []string{tempDir}, - filterHooks: func(filename string, patterns []string) error { + ServiceName: testServiceName, + Recursive: true, + Directories: []string{tempDir}, + FilterHooks: func(filename string, patterns []string) error { for i := 0; i < len(patterns); i++ { if strings.Contains(filename, patterns[i]) { return nil @@ -515,15 +447,13 @@ func Test_Copy_Directory(t *testing.T) { } return ErrorSkip }, - files: make(map[string]os.FileInfo), - ignored: ignored, - filePatterns: []string{"aaa", "bbb", "txt"}, + Files: make(map[string]os.FileInfo), + Ignored: ignored, + FilePatterns: []string{"aaa", "bbb", "txt"}, } w, err := NewWatcher([]WatcherConfig{wc}) - if err != nil { - t.Fatal(err) - } + assert.NoError(t, err) dirLen := len(w.GetAllFiles(testServiceName)) // should be 2 files (2 from root dir), filtered other @@ -531,17 +461,11 @@ func Test_Copy_Directory(t *testing.T) { t.Fatalf("incorrect directories len, len is: %d", dirLen) } - go limitTime(time.Second*10, t.Name(), c) - go func() { go func() { - err2 := copyDir(nestedDir, filepath.Join(tempDir, "copyTo")) - if err2 != nil { - panic(err2) - } - - // exit from current goroutine - runtime.Goexit() + time.Sleep(time.Second * 2) + err := copyDir(nestedDir, filepath.Join(tempDir, "copyTo")) + assert.NoError(t, err) }() go func() { @@ -553,25 +477,7 @@ func Test_Copy_Directory(t *testing.T) { }() err = w.StartPolling(time.Second) - if err != nil { - t.Fatal(err) - } -} - -func limitTime(d time.Duration, name string, free chan struct{}) { - go func() { - ticket := time.NewTicker(d) - for { - select { - case <-ticket.C: - ticket.Stop() - panic("timeout exceed, test: " + name) - case <-free: - ticket.Stop() - return - } - } - }() + assert.NoError(t, err) } func copyFile(src, dst string) (err error) { @@ -579,7 +485,9 @@ func copyFile(src, dst string) (err error) { if err != nil { return } - defer in.Close() + defer func() { + _ = in.Close() + }() out, err := os.Create(dst) if err != nil { |