diff --git a/Readme.md b/Readme.md index 9a407cbb..dcf4e025 100644 --- a/Readme.md +++ b/Readme.md @@ -77,6 +77,8 @@ mount your stub file in `/mystubs` folder then mount it to docker like `docker run -p 4770:4770 -p 4771:4771 -v /mypath:/proto -v /mystubs:/stub tkpd/gripmock --stub=/stub /proto/hello.proto` Please note that Gripmock still serves http stubbing to modify stored stubs on the fly. + +You may pass `--stub-watch` option to watch changes in the stub directory. When you edit a file in the directory, it will clean the stubs and load all files in the directory again to make your changes available. ## Input Matching Stub will respond with the expected response only if the request matches any rule. Stub service will serve `/find` endpoint with format: diff --git a/go.mod b/go.mod index 973d64b4..4666cb77 100644 --- a/go.mod +++ b/go.mod @@ -3,6 +3,7 @@ module github.com/tokopedia/gripmock go 1.15 require ( + github.com/fsnotify/fsnotify v1.4.9 github.com/go-chi/chi v4.1.2+incompatible github.com/gobuffalo/here v0.6.2 // indirect github.com/golang/protobuf v1.4.3 diff --git a/gripmock.go b/gripmock.go index d3570a03..bcc044de 100644 --- a/gripmock.go +++ b/gripmock.go @@ -20,6 +20,7 @@ func main() { adminport := flag.String("admin-port", "4771", "Port of stub admin server") adminBindAddr := flag.String("admin-listen", "", "Adress the admin server will bind to. Default to localhost, set to 0.0.0.0 to use from another machine") stubPath := flag.String("stub", "", "Path where the stub files are (Optional)") + stubWatch := flag.Bool("stub-watch", false, "watch the stub directory for change") imports := flag.String("imports", "/protobuf", "comma separated imports path. default path /protobuf is where gripmock Dockerfile install WKT protos") // for backwards compatibility if os.Args[1] == "gripmock" { @@ -45,9 +46,10 @@ func main() { // run admin stub server stub.RunStubServer(stub.Options{ - StubPath: *stubPath, - Port: *adminport, - BindAddr: *adminBindAddr, + StubPath: *stubPath, + StubWatch: *stubWatch, + Port: *adminport, + BindAddr: *adminBindAddr, }) // parse proto files diff --git a/stub/storage.go b/stub/storage.go index 2f20e2ad..3ddc98a8 100644 --- a/stub/storage.go +++ b/stub/storage.go @@ -9,6 +9,7 @@ import ( "regexp" "sync" + "github.com/fsnotify/fsnotify" "github.com/lithammer/fuzzysearch/fuzzy" ) @@ -285,3 +286,39 @@ func readStubFromFile(path string) { storeStub(stub) } } + +func watchStubDir(path string) { + watcher, err := fsnotify.NewWatcher() + if err != nil { + log.Printf("Error when watching the stub directory. %v.", err) + return + } + defer watcher.Close() + + done := make(chan bool) + go func() { + for { + select { + case event, ok := <-watcher.Events: + if !ok { + return + } + if event.Op&fsnotify.Write == fsnotify.Write { + clearStorage() + readStubFromFile(path) + } + case err, ok := <-watcher.Errors: + if !ok { + return + } + log.Printf("Error when watching the stub directory. %v.", err) + } + } + }() + + err = watcher.Add(path) + if err != nil { + log.Printf("Error when watching the stub directory %s. %v.", path, err) + } + <-done +} diff --git a/stub/stub.go b/stub/stub.go index 819b317f..f4a4ed13 100644 --- a/stub/stub.go +++ b/stub/stub.go @@ -7,14 +7,15 @@ import ( "log" "net/http" "strings" - + "github.com/go-chi/chi" ) type Options struct { - Port string - BindAddr string - StubPath string + Port string + BindAddr string + StubPath string + StubWatch bool } const DEFAULT_PORT = "4771" @@ -32,6 +33,13 @@ func RunStubServer(opt Options) { if opt.StubPath != "" { readStubFromFile(opt.StubPath) + + if opt.StubWatch { + fmt.Println("Watching for changes in " + opt.StubPath) + go func() { + watchStubDir(opt.StubPath) + }() + } } fmt.Println("Serving stub admin on http://" + addr)