diff options
author | Valery Piashchynski <[email protected]> | 2020-02-27 16:40:36 +0300 |
---|---|---|
committer | Valery Piashchynski <[email protected]> | 2020-02-27 16:40:36 +0300 |
commit | eaab15a7a9089b6c660b313f0f4cd3ed4ca93a1d (patch) | |
tree | d47bc55d1e80c760de5b1fe428bc05587fe9bfa0 | |
parent | 53859e193b89082c83d7a190baa97892075d259c (diff) | |
parent | 9960aff462c985f89e1e9387e0b87bab24504d0e (diff) |
Merge remote-tracking branch 'remotes/origin/master' into address_already_in_use_error
-rwxr-xr-x | build.sh | 85 | ||||
-rw-r--r-- | service/reload/config.go | 6 | ||||
-rw-r--r-- | service/reload/config_test.go | 16 | ||||
-rw-r--r-- | service/reload/watcher_test.go | 305 |
4 files changed, 342 insertions, 70 deletions
@@ -11,40 +11,61 @@ LDFLAGS="$LDFLAGS -X github.com/spiral/roadrunner/cmd/rr/cmd.BuildTime=$(date +% # remove debug info from binary as well as string and symbol tables LDFLAGS="$LDFLAGS -s" -build(){ - echo Packaging "$1" Build - bdir=roadrunner-${RR_VERSION}-$2-$3 - rm -rf builds/"$bdir" && mkdir -p builds/"$bdir" - GOOS=$2 GOARCH=$3 ./build.sh - - if [ "$2" == "windows" ]; then - mv rr builds/"$bdir"/rr.exe - else - mv rr builds/"$bdir" - fi - - cp README.md builds/"$bdir" - cp CHANGELOG.md builds/"$bdir" - cp LICENSE builds/"$bdir" - cd builds - - if [ "$2" == "linux" ]; then - tar -zcf "$bdir".tar.gz "$bdir" - else - zip -r -q "$bdir".zip "$bdir" - fi - - rm -rf "$bdir" - cd .. +build() { + echo Packaging "$1" Build + bdir=roadrunner-${RR_VERSION}-$2-$3 + rm -rf builds/"$bdir" && mkdir -p builds/"$bdir" + GOOS=$2 GOARCH=$3 ./build.sh + + if [ "$2" == "windows" ]; then + mv rr builds/"$bdir"/rr.exe + else + mv rr builds/"$bdir" + fi + + cp README.md builds/"$bdir" + cp CHANGELOG.md builds/"$bdir" + cp LICENSE builds/"$bdir" + cd builds + + if [ "$2" == "linux" ]; then + tar -zcf "$bdir".tar.gz "$bdir" + else + zip -r -q "$bdir".zip "$bdir" + fi + + rm -rf "$bdir" + cd .. +} + +# For musl build you should have musl-gcc installed. If not, please, use: +# go build -a -ldflags "-linkmode external -extldflags '-static' -s" +build_musl() { + echo Packaging "$2" Build + bdir=roadrunner-${RR_VERSION}-$1-$2-$3 + rm -rf builds/"$bdir" && mkdir -p builds/"$bdir" + CC=musl-gcc GOARCH=amd64 go build -ldflags "$LDFLAGS" -o "$OD/rr" cmd/rr/main.go + + mv rr builds/"$bdir" + + cp README.md builds/"$bdir" + cp CHANGELOG.md builds/"$bdir" + cp LICENSE builds/"$bdir" + cd builds + zip -r -q "$bdir".zip "$bdir" + + rm -rf "$bdir" + cd .. } if [ "$1" == "all" ]; then - rm -rf builds/ - build "Windows" "windows" "amd64" - build "Mac" "darwin" "amd64" - build "Linux" "linux" "amd64" - build "FreeBSD" "freebsd" "amd64" - exit + rm -rf builds/ + build "Windows" "windows" "amd64" + build "Mac" "darwin" "amd64" + build "Linux" "linux" "amd64" + build "FreeBSD" "freebsd" "amd64" + build_musl "unknown" "musl" "amd64" + exit fi -go build -ldflags "$LDFLAGS" -o "$OD/rr" cmd/rr/main.go +CGO_ENABLED=0 go build -ldflags "$LDFLAGS" -o "$OD/rr" cmd/rr/main.go diff --git a/service/reload/config.go b/service/reload/config.go index f33b5081..efc71972 100644 --- a/service/reload/config.go +++ b/service/reload/config.go @@ -62,5 +62,11 @@ func (c *Config) Valid() error { return errors.New("too short interval") } + if c.Services == nil { + return errors.New("should add at least 1 service") + } else if len(c.Services) == 0 { + return errors.New("service initialized, however, no config added") + } + return nil } diff --git a/service/reload/config_test.go b/service/reload/config_test.go index cefb6544..600975d3 100644 --- a/service/reload/config_test.go +++ b/service/reload/config_test.go @@ -36,8 +36,17 @@ func Test_Fake_ServiceConfig(t *testing.T) { func Test_Interval(t *testing.T) { services := make(map[string]ServiceConfig) + services["test"] = ServiceConfig{ + Enabled: false, + Recursive: false, + Patterns: nil, + Dirs: nil, + Ignore: nil, + service: nil, + } + cfg := &Config{ - Interval: time.Millisecond, + Interval: time.Millisecond, // should crash here Patterns: nil, Services: services, } @@ -45,11 +54,10 @@ func Test_Interval(t *testing.T) { } func Test_NoServiceConfig(t *testing.T) { - services := make(map[string]ServiceConfig) cfg := &Config{ - Interval: time.Millisecond, + Interval: time.Second, Patterns: nil, - Services: services, + Services: nil, } assert.Error(t, cfg.Valid()) } diff --git a/service/reload/watcher_test.go b/service/reload/watcher_test.go index 449a21df..f5a5db01 100644 --- a/service/reload/watcher_test.go +++ b/service/reload/watcher_test.go @@ -2,9 +2,11 @@ package reload import ( "fmt" + "io" "io/ioutil" "os" "path/filepath" + "runtime" "strings" "testing" "time" @@ -57,12 +59,15 @@ 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(".", "") - defer func() { - err = freeResources(tempDir) + c := make(chan struct{}) + defer func(name string) { + err = freeResources(name) if err != nil { + c <- struct{}{} t.Fatal(err) } - }() + c <- struct{}{} + }(tempDir) if err != nil { t.Fatal(err) @@ -92,7 +97,7 @@ func Test_Get_FileEvent(t *testing.T) { filterHooks: nil, files: make(map[string]os.FileInfo), ignored: nil, - filePatterns: nil, + filePatterns: []string{"aaa", "txt"}, } w, err := NewWatcher([]WatcherConfig{wc}) @@ -105,20 +110,26 @@ func Test_Get_FileEvent(t *testing.T) { t.Fatal("incorrect directories len") } + go limitTime(time.Second * 10, t.Name(), c) + go func() { - // time sleep is used here because StartPolling is blocking operation - time.Sleep(time.Second * 5) - err = ioutil.WriteFile(filepath.Join(tempDir, "file2.txt"), - []byte{1, 1, 1}, 0755) - if err != nil { - panic(err) - } + go func() { + time.Sleep(time.Second) + err2 := ioutil.WriteFile(filepath.Join(tempDir, "file2.txt"), + []byte{1, 1, 1}, 0755) + if err2 != nil { + panic(err2) + } + runtime.Goexit() + }() + go func() { for e := range w.Event { if e.path != "file2.txt" { panic("didn't handle event when write file2") } w.Stop() + return } }() }() @@ -135,12 +146,15 @@ 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(".", "") - defer func() { - err = freeResources(tempDir) + c := make(chan struct{}) + defer func(name string) { + err = freeResources(name) if err != nil { + c <- struct{}{} t.Fatal(err) } - }() + c <- struct{}{} + }(tempDir) if err != nil { t.Fatal(err) @@ -190,22 +204,27 @@ 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() { - err = ioutil.WriteFile(filepath.Join(tempDir, "file3.txt"), - []byte{1, 1, 1}, 0755) - if err != nil { - panic(err) - } + go func() { + err2 := ioutil.WriteFile(filepath.Join(tempDir, "file3.txt"), + []byte{1, 1, 1}, 0755) + if err2 != nil { + panic(err2) + } + + runtime.Goexit() + }() + go func() { for e := range w.Event { fmt.Println(e.info.Name()) panic("handled event from filtered file") } }() - - // time sleep is used here because StartPolling is blocking operation - time.Sleep(time.Second * 5) w.Stop() + return }() err = w.StartPolling(time.Second) @@ -338,12 +357,17 @@ func Test_Wrong_Dir(t *testing.T) { func Test_Filter_Directory(t *testing.T) { tempDir, err := ioutil.TempDir(".", "") - defer func() { - err = freeResources(tempDir) + c := make(chan struct{}) + defer func(name string) { + err = freeResources(name) if err != nil { + c <- struct{}{} t.Fatal(err) } - }() + c <- struct{}{} + }(tempDir) + + go limitTime(time.Second*10, t.Name(), c) nestedDir, err := ioutil.TempDir(tempDir, "/nested") if err != nil { @@ -406,16 +430,17 @@ func Test_Filter_Directory(t *testing.T) { } go func() { - // 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) - } go func() { - for range w.Event { + err2 := ioutil.WriteFile(filepath.Join(nestedDir, "file4.aaa"), + []byte{1, 1, 1}, 0755) + if err2 != nil { + panic(err2) + } + }() + + go func() { + for e := range w.Event { + fmt.Println("file: " + e.info.Name()) panic("handled event from watcher in nested dir") } }() @@ -432,6 +457,218 @@ func Test_Filter_Directory(t *testing.T) { } } +// copy files from nested dir to not ignored +// 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{}{} + }() + + nestedDir, err := ioutil.TempDir(tempDir, "/nested") + if err != nil { + t.Fatal(err) + } + + err = ioutil.WriteFile(filepath.Join(tempDir, "file1.aaa"), + []byte{}, 0755) + if err != nil { + t.Fatal(err) + } + + err = ioutil.WriteFile(filepath.Join(tempDir, "file2.bbb"), + []byte{}, 0755) + if err != nil { + t.Fatal(err) + } + + err = ioutil.WriteFile(filepath.Join(nestedDir, "file3.txt"), + []byte{}, 0755) + if err != nil { + t.Fatal(err) + } + err = ioutil.WriteFile(filepath.Join(nestedDir, "file4.aaa"), + []byte{}, 0755) + if err != nil { + t.Fatal(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 { + for i := 0; i < len(patterns); i++ { + if strings.Contains(filename, patterns[i]) { + return nil + } + } + return ErrorSkip + }, + files: make(map[string]os.FileInfo), + ignored: ignored, + filePatterns: []string{"aaa", "bbb", "txt"}, + } + + w, err := NewWatcher([]WatcherConfig{wc}) + if err != nil { + t.Fatal(err) + } + + dirLen := len(w.GetAllFiles(testServiceName)) + // should be 2 files (2 from root dir), filtered other + if dirLen != 2 { + 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() + }() + + go func() { + for range w.Event { + // here should be event, otherwise we won't stop + w.Stop() + } + }() + }() + + 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 + } + } + }() +} + +func copyFile(src, dst string) (err error) { + in, err := os.Open(src) + if err != nil { + return + } + defer in.Close() + + out, err := os.Create(dst) + if err != nil { + return + } + defer func() { + if e := out.Close(); e != nil { + err = e + } + }() + + _, err = io.Copy(out, in) + if err != nil { + return + } + + err = out.Sync() + if err != nil { + return + } + + si, err := os.Stat(src) + if err != nil { + return + } + err = os.Chmod(dst, si.Mode()) + if err != nil { + return + } + + return +} + +func copyDir(src string, dst string) (err error) { + src = filepath.Clean(src) + dst = filepath.Clean(dst) + + si, err := os.Stat(src) + if err != nil { + return err + } + if !si.IsDir() { + return fmt.Errorf("source is not a directory") + } + + _, err = os.Stat(dst) + if err != nil && !os.IsNotExist(err) { + return + } + if err == nil { + return fmt.Errorf("destination already exists") + } + + err = os.MkdirAll(dst, si.Mode()) + if err != nil { + return + } + + entries, err := ioutil.ReadDir(src) + if err != nil { + return + } + + for _, entry := range entries { + srcPath := filepath.Join(src, entry.Name()) + dstPath := filepath.Join(dst, entry.Name()) + + if entry.IsDir() { + err = copyDir(srcPath, dstPath) + if err != nil { + return + } + } else { + // Skip symlinks. + if entry.Mode()&os.ModeSymlink != 0 { + continue + } + + err = copyFile(srcPath, dstPath) + if err != nil { + return + } + } + } + + return +} + func freeResources(path string) error { return os.RemoveAll(path) } |