From a5b00d119cf2708655b0003205fd2d1051a2f294 Mon Sep 17 00:00:00 2001 From: Adam Ryman Date: Mon, 1 Aug 2016 15:26:03 -0700 Subject: [PATCH 1/2] Refactor truss and integration_tests truss has been refactored into main.go and generator/generator.go. Where main.go deals with working directory, GOPATH, and argument parsing and sanitation and generator.go actually exec's protoc and go build to generate and build the microservice. integration_tests were refactored to use `testing.T` to do logging rather than logrus. As well as be more readable. It can also be called with `$ go test -tags=integration -clean` in order to remove the generated test files and nothing else. Eventual goals are to unit test generator.go's functions and eventually move the integration_tests to the generator package and test by calling functions rather than execing the truss binary --- truss/generator/generator.go | 186 +++++++++++ truss/integration_tests/integration_runner.go | 312 +----------------- .../integration_runner_test.go | 229 ++++++++++++- truss/main.go | 241 +++----------- 4 files changed, 451 insertions(+), 517 deletions(-) create mode 100644 truss/generator/generator.go diff --git a/truss/generator/generator.go b/truss/generator/generator.go new file mode 100644 index 0000000..e7303fe --- /dev/null +++ b/truss/generator/generator.go @@ -0,0 +1,186 @@ +package generator + +import ( + "io/ioutil" + "os" + "os/exec" + "path/filepath" + "strings" + + log "github.com/Sirupsen/logrus" + + templates "github.com/TuneLab/gob/truss/template" +) + +func init() { + log.SetLevel(log.DebugLevel) + log.SetFormatter(&log.TextFormatter{ + ForceColors: true, + }) +} + +// GenerateMicroservice takes a golang importPath, a path to .proto definition files workingDirectory, and a slice of +// definition files DefinitionFiles and outputs a ./service direcotry in workingDirectory with a generated and built golang microservice +func GenerateMicroservice(importPath string, workingDirectory string, definitionFiles []string) { + + done := make(chan bool) + + // Stage 1 + buildDirectories(workingDirectory) + outputGoogleImport(workingDirectory) + + // Stage 2, 3, 4 + generatePbGoCmd := "--go_out=Mgoogle/api/annotations.proto=" + importPath + "/service/DONOTEDIT/third_party/googleapis/google/api,plugins=grpc:./service/DONOTEDIT/pb" + const generateDocsCmd = "--truss-doc_out=." + const generateGoKitCmd = "--truss-gokit_out=." + + go protoc(workingDirectory, definitionFiles, generatePbGoCmd, done) + go protoc(workingDirectory, definitionFiles, generateDocsCmd, done) + go protoc(workingDirectory, definitionFiles, generateGoKitCmd, done) + + <-done + <-done + <-done + + // Stage 5 + go goBuild("server", importPath+"/service/DONOTEDIT/cmd/svc/...", done) + go goBuild("cliclient", importPath+"/service/DONOTEDIT/cmd/cliclient/...", done) + + <-done + <-done +} + +// buildDirectories puts the following directories in place +// . +// └── service +// ├── bin +// └── DONOTEDIT +// ├── pb +// └── third_party +// └── googleapis +// └── google +// └── api +func buildDirectories(workingDirectory string) { + // third_party created by going through assets in template + // and creating directoires that are not there + for _, filePath := range templates.AssetNames() { + fullPath := workingDirectory + "/" + filePath + + dirPath := filepath.Dir(fullPath) + + err := os.MkdirAll(dirPath, 0777) + if err != nil { + log.WithField("DirPath", dirPath).WithError(err).Fatal("Cannot create directories") + } + } + + // Create the directory where protoc will store the compiled .pb.go files + err := os.MkdirAll(workingDirectory+"/service/DONOTEDIT/pb", 0777) + if err != nil { + log.WithField("DirPath", "service/DONOTEDIT/pb").WithError(err).Fatal("Cannot create directories") + } + + // Create the directory where go build will put the compiled binaries + err = os.MkdirAll(workingDirectory+"/service/bin", 0777) + if err != nil { + log.WithField("DirPath", "service/bin").WithError(err).Fatal("Cannot create directories") + } +} + +// outputGoogleImport places imported and required google.api.http protobuf option files +// into their required directories as part of stage one generation +func outputGoogleImport(workingDirectory string) { + // Output files that are stored in template package + for _, filePath := range templates.AssetNames() { + fileBytes, _ := templates.Asset(filePath) + fullPath := workingDirectory + "/" + filePath + + err := ioutil.WriteFile(fullPath, fileBytes, 0666) + if err != nil { + log.WithField("FilePath", fullPath).WithError(err).Fatal("Cannot create ") + } + } +} + +// goBuild calls the `$ go get ` to install dependenices +// and then calls `$ go build service/bin/$name $path` +// to put the iterating binaries in the correct place +func goBuild(name string, path string, done chan bool) { + + // $ go get + + goGetExec := exec.Command( + "go", + "get", + "-d", + "-v", + path, + ) + + goGetExec.Stderr = os.Stderr + + log.WithField("cmd", strings.Join(goGetExec.Args, " ")).Info("go get") + val, err := goGetExec.Output() + + if err != nil { + log.WithFields(log.Fields{ + "output": string(val), + "input": goGetExec.Args, + }).WithError(err).Warn("go get failed") + } + + // $ go build + + goBuildExec := exec.Command( + "go", + "build", + "-o", + "service/bin/"+name, + path, + ) + + goBuildExec.Stderr = os.Stderr + + log.WithField("cmd", strings.Join(goBuildExec.Args, " ")).Info("go build") + val, err = goBuildExec.Output() + + if err != nil { + log.WithFields(log.Fields{ + "output": string(val), + "input": goBuildExec.Args, + }).WithError(err).Fatal("go build failed") + } + + done <- true +} + +func protoc(workingDirectory string, definitionPaths []string, command string, done chan bool) { + const googleApiHttpImportPath = "/service/DONOTEDIT/third_party/googleapis" + + cmdArgs := []string{ + "-I.", + "-I" + workingDirectory + googleApiHttpImportPath, + command, + } + // Append each definition file path to the end of that command args + cmdArgs = append(cmdArgs, definitionPaths...) + + protocExec := exec.Command( + "protoc", + cmdArgs..., + ) + + protocExec.Stderr = os.Stderr + + log.WithField("cmd", strings.Join(protocExec.Args, " ")).Info("protoc") + val, err := protocExec.Output() + + if err != nil { + log.WithFields(log.Fields{ + "output": string(val), + "input": protocExec.Args, + }).WithError(err).Fatal("Protoc call failed") + } + + done <- true +} diff --git a/truss/integration_tests/integration_runner.go b/truss/integration_tests/integration_runner.go index 01a3a29..216669a 100644 --- a/truss/integration_tests/integration_runner.go +++ b/truss/integration_tests/integration_runner.go @@ -1,312 +1,2 @@ +// This file is here so that go's tooling does not complain there are no builable gofiles in this directory package integration - -import ( - "bytes" - "io/ioutil" - "net" - "path/filepath" - "strings" - "time" - - "os" - "os/exec" - "strconv" - - log "github.com/Sirupsen/logrus" -) - -// From within a folder with a truss `service` -// These are the paths to the compiled binaries -const RELATIVESERVERPATH = "/service/bin/server" -const RELATIVECLIENTPATH = "/service/bin/cliclient" - -// runReference stores data about a client-server interaction -// This data is then used to display output -type runReference struct { - path string - clientErr bool - serverErr bool - clientOutput string - serverOutput string -} - -func init() { - log.SetLevel(log.InfoLevel) - log.SetFormatter(&log.TextFormatter{ - ForceColors: true, - }) -} - -func runIntegrationTests() bool { - allPassed := true - - workingDirectory, err := os.Getwd() - if err != nil { - log.WithError(err).Fatal("Cannot get working directory") - } - workingDirectory = workingDirectory + "/test_service_definitions" - - // runRefs will be passed to all gorutines running communication tests - // and will be read to display output - runRefs := make(chan runReference) - // tasksCount is increased for every server/client call - // and decreased every time one is display, for exiting - tasksCount := 0 - - // Loop through all directories in the running path - dirs, err := ioutil.ReadDir(workingDirectory) - for _, d := range dirs { - // If this item is not a directory skip it - if !d.IsDir() { - continue - } - - // Clean up the service directories in each test - if fileExists(workingDirectory + "/" + d.Name() + "/service") { - os.RemoveAll(workingDirectory + "/" + d.Name() + "/service") - } - - // tests will be run on the fullpath to directory - testDir := workingDirectory + "/" + d.Name() - // On port relative to 8082, increasing by tasksCount - port := 8082 + tasksCount - - log.WithField("Service", d.Name()).Info("Starting integration test") - - // Running the integration tests one at a time because truss running on all files at once - // seems to slow the system more than distribute the work - communicationTestRan := runTest(testDir, port, runRefs) - - // If communication test ran, increase the running tasksCount - if communicationTestRan { - tasksCount = tasksCount + 1 - } else { - allPassed = false - } - } - - // range through the runRefs channel, display info if pass - // display warn with debug info if fail - for i := 0; i < tasksCount; i++ { - ref := <-runRefs - if ref.clientErr || ref.serverErr { - log.WithField("Service", filepath.Base(ref.path)).Warn("Communication test FAILED") - log.Warnf("Client Output\n%v", ref.clientOutput) - log.Warnf("Server Output\n%v", ref.serverOutput) - allPassed = false - } else { - log.WithField("Service", filepath.Base(ref.path)).Info("Communication test passed") - } - } - - if allPassed { - // Clean up the service directories in each test - dirs, err = ioutil.ReadDir(workingDirectory) - for _, d := range dirs { - // If this item is not a directory skip it - if !d.IsDir() { - continue - } - - if fileExists(workingDirectory + "/" + d.Name() + "/service") { - os.RemoveAll(workingDirectory + "/" + d.Name() + "/service") - } - } - } - - return allPassed -} - -// runTest generates, builds, and runs truss services -// testPath is the full path to the definition files -// portRef is a reference port to launch services on -// runRefs is a channel where references to client/server communication will be passed back -// runTest returns a bool representing whether or not the client/server communication was tested -func runTest(testPath string, portRef int, runRefs chan runReference) (communicationTestRan bool) { - // Build the full path to this directory and the path to the client and server - // binaries within it - log.WithField("Test path", testPath).Debug() - - // Generate and build service - truss(testPath) - - serverPath := testPath + RELATIVESERVERPATH - clientPath := testPath + RELATIVECLIENTPATH - - // If the server and client binary exist then run them against each other - if fileExists(serverPath) && fileExists(clientPath) { - port := portRef - debugPort := portRef + 1000 - checkPort(port) - log.WithFields(log.Fields{ - "testPath": testPath, - "port": port, - "debugPort": debugPort, - }). - Debug("LAUNCH") - go runServerAndClient(testPath, port, debugPort, runRefs) - return true - } - return false -} - -// truss calls truss on *.proto in path -// Truss logs to Stdout when generation passes or fails -func truss(path string) { - var protofiles []string - files, err := ioutil.ReadDir(path) - for _, f := range files { - if f.IsDir() { - continue - } - if strings.HasSuffix(f.Name(), ".proto") { - protofiles = append(protofiles, f.Name()) - } - } - - trussExec := exec.Command( - "truss", - protofiles..., - ) - trussExec.Dir = path - - log.WithField("Path", path).Debug("Exec Truss") - val, err := trussExec.CombinedOutput() - - if err != nil { - log.Warn(err) - log.Warn(trussExec.Args) - log.Warn(path) - log.WithField("Service", filepath.Base(path)).Warn("Truss generation FAILED") - log.Warnf("Truss Output:\n%v", string(val)) - } else { - log.WithField("Service", filepath.Base(path)).Info("Truss generation passed") - } -} - -// checkPort checks if port is being used -// TODO: Make work -func checkPort(port int) { - log.Debug("Checking Port") - ips, _ := net.LookupIP("localhost") - listener, err := net.ListenTCP("tcp", - &net.TCPAddr{ - IP: ips[0], - Port: port, - }) - _ = listener - - log.Debug("Checking Error") - if err != nil { - log.WithField("port", port).Warn("PORT MAY BE TAKEN") - } - listener.Close() - - //net.Dial("tcp", "localhost:"+strconv.Itoa(port)) - -} - -func runServerAndClient(path string, port int, debugPort int, refChan chan runReference) { - - // Output buffer for the server Stdout and Stderr - serverOut := bytes.NewBuffer(nil) - // Get the server command ready with the port - server := exec.Command( - path+RELATIVESERVERPATH, - "-grpc.addr", - ":"+strconv.Itoa(port), - "-debug.addr", - ":"+strconv.Itoa(debugPort), - ) - - // Put serverOut to be the writer of data from Stdout and Stderr - server.Stdout = serverOut - server.Stderr = serverOut - - log.Debug("Starting the server!") - // Start the server - serverErrChan := make(chan error) - go func() { - err := server.Run() - serverErrChan <- err - defer server.Process.Kill() - }() - - // We may need to wait a few miliseconds for the server to startup - retryTime := time.Millisecond * 100 - t := time.NewTimer(retryTime) - for server.Process == nil { - <-t.C - t.Reset(retryTime) - log.WithField("path", path).Debug("Timer Reset") - } - <-t.C - log.WithField("path", path).Debug("Timer Reset last") - - cOut, cErr := runClient(path, port) - - log.WithField("Client Output", string(cOut)).Debug("Client returned") - - var sErr bool - - // If the server ever stopped then it errored - // If it did not stop, kill it and see if that errors - select { - case <-serverErrChan: - sErr = true - default: - if server.Process == nil { - // This likely means the server never started - sErr = true - } else { - // If the Process is not nil, kill it, clean up our mess - err := server.Process.Kill() - if err != nil { - sErr = true - } else { - sErr = false - } - } - } - - // Construct a reference to what happened here - ref := runReference{ - path: path, - clientErr: cErr, - serverErr: sErr, - clientOutput: string(cOut), - serverOutput: serverOut.String(), - } - refChan <- ref -} - -func runClient(path string, port int) ([]byte, bool) { - client := exec.Command( - path+RELATIVECLIENTPATH, - "-grpc.addr", - ":"+strconv.Itoa(port), - ) - - log.Debug("Starting the client!") - - cOut, err := client.CombinedOutput() - - var cErr bool - if err != nil { - log.WithError(err).Warn() - cErr = true - } else { - cErr = false - } - - return cOut, cErr -} - -// fileExists checks if a file at the given path exists. Returns true if the -// file exists, and false if the file does not exist. -func fileExists(path string) bool { - if _, err := os.Stat(path); err == nil { - return true - } - return false -} diff --git a/truss/integration_tests/integration_runner_test.go b/truss/integration_tests/integration_runner_test.go index 3ff643c..1ffa1ca 100644 --- a/truss/integration_tests/integration_runner_test.go +++ b/truss/integration_tests/integration_runner_test.go @@ -3,12 +3,233 @@ package integration import ( + "bytes" + "flag" + "io/ioutil" + "os" + "os/exec" + "path/filepath" + "strconv" + "strings" + "time" + "testing" ) -func TestTruss(t *testing.T) { - allPassed := runIntegrationTests() - if !allPassed { - t.Fail() +func init() { + clean := flag.Bool("clean", false, "Remove all generated test files and do nothing else") + flag.Parse() + if *clean { + wd, _ := os.Getwd() + servicesDir := wd + "/test_service_definitions" + cleanTests(servicesDir) + os.Exit(0) + } +} + +// runReference stores data about a client-server interaction +// This data is then used to display output +type runReference struct { + name string + clientErr bool + serverErr bool + clientOutput string + serverOutput string +} + +func TestTruss(t *testing.T) { + wd, _ := os.Getwd() + servicesDir := wd + "/test_service_definitions" + + runRefs := make(chan runReference) + runCount := 0 + + dirs, _ := ioutil.ReadDir(servicesDir) + for i, d := range dirs { + // If this item is not a directory skip it + if !d.IsDir() { + continue + } + + // tests will be run on the fullpath to service directoru + sDir := servicesDir + "/" + d.Name() + + // Clean up the service directories in each test + if fileExists(sDir + "/service") { + os.RemoveAll(sDir + "/service") + } + + // On port relative to 8082 + port := 8082 + i + + // Running the integration tests one at a time because truss running on all files at once + // seems to slow the system more than distribute the work + out, err := truss(sDir) + + // If truss fails, test error and skip communication + if err != nil { + t.Errorf("Truss generation FAILED - %v\nTruss Output:\n%v", d.Name(), out) + continue + } + + go runServerAndClient(sDir, port, port+1000, runRefs) + runCount++ + } + + for i := 0; i < runCount; i++ { + ref := <-runRefs + if ref.clientErr || ref.serverErr { + t.Errorf("Communication test FAILED - %v", ref.name) + t.Logf("Client Output\n%v", ref.clientOutput) + t.Logf("Server Output\n%v", ref.serverOutput) + } + } + + // If nothing failed, delete the generated files + if !t.Failed() { + cleanTests(servicesDir) + } +} + +// truss calls truss on *.proto in path +// Truss logs to Stdout when generation passes or fails +func truss(path string) (string, error) { + var protofiles []string + files, err := ioutil.ReadDir(path) + for _, f := range files { + if f.IsDir() { + continue + } + if strings.HasSuffix(f.Name(), ".proto") { + protofiles = append(protofiles, f.Name()) + } + } + + trussExec := exec.Command( + "truss", + protofiles..., + ) + trussExec.Dir = path + + out, err := trussExec.CombinedOutput() + + return string(out), err +} + +func runServerAndClient(path string, port int, debugPort int, runRefs chan runReference) { + // From within a folder with a truss `service` + // These are the paths to the compiled binaries + const relativeServerPath = "/service/bin/server" + + // Output buffer for the server Stdout and Stderr + serverOut := bytes.NewBuffer(nil) + // Get the server command ready with the port + server := exec.Command( + path+relativeServerPath, + "-grpc.addr", + ":"+strconv.Itoa(port), + "-debug.addr", + ":"+strconv.Itoa(debugPort), + ) + + // Put serverOut to be the writer of data from Stdout and Stderr + server.Stdout = serverOut + server.Stderr = serverOut + + // Start the server + serverErrChan := make(chan error) + go func() { + err := server.Run() + serverErrChan <- err + defer server.Process.Kill() + }() + + // We may need to wait a few miliseconds for the server to startup + retryTime := time.Millisecond * 100 + t := time.NewTimer(retryTime) + for server.Process == nil { + <-t.C + t.Reset(retryTime) + } + <-t.C + + cOut, cErr := runClient(path, port) + + var sErr bool + + // If the server ever stopped then it errored + // If it did not stop, kill it and see if that errors + select { + case <-serverErrChan: + sErr = true + default: + if server.Process == nil { + // This likely means the server never started + sErr = true + } else { + // If the Process is not nil, kill it, clean up our mess + err := server.Process.Kill() + if err != nil { + sErr = true + } else { + sErr = false + } + } + } + + // Construct a reference to what happened here + ref := runReference{ + name: filepath.Base(path), + clientErr: cErr, + serverErr: sErr, + clientOutput: string(cOut), + serverOutput: serverOut.String(), + } + + runRefs <- ref +} + +func runClient(path string, port int) ([]byte, bool) { + const relativeClientPath = "/service/bin/cliclient" + + client := exec.Command( + path+relativeClientPath, + "-grpc.addr", + ":"+strconv.Itoa(port), + ) + + cOut, err := client.CombinedOutput() + + var cErr bool + if err != nil { + cErr = true + } else { + cErr = false + } + + return cOut, cErr +} + +// fileExists checks if a file at the given path exists. Returns true if the +// file exists, and false if the file does not exist. +func fileExists(path string) bool { + if _, err := os.Stat(path); err == nil { + return true + } + return false +} + +func cleanTests(servicesDir string) { + // Clean up the service directories in each test + dirs, _ := ioutil.ReadDir(servicesDir) + for _, d := range dirs { + // If this item is not a directory skip it + if !d.IsDir() { + continue + } + + if fileExists(servicesDir + "/" + d.Name() + "/service") { + os.RemoveAll(servicesDir + "/" + d.Name() + "/service") + } } } diff --git a/truss/main.go b/truss/main.go index 0c7832b..4fbc780 100644 --- a/truss/main.go +++ b/truss/main.go @@ -2,61 +2,21 @@ package main import ( "flag" - "fmt" - "io/ioutil" + //"fmt" "os" - "os/exec" - "path/filepath" + "path" "strings" - log "github.com/Sirupsen/logrus" + "github.com/TuneLab/gob/truss/generator" - templates "github.com/TuneLab/gob/truss/template" + log "github.com/Sirupsen/logrus" ) -const GENERATED_PATH = "service" -const GOOGLE_API_HTTP_IMPORT_PATH = "/service/DONOTEDIT/third_party/googleapis" - -type globalStruct struct { - workingDirectory string - genImportPath string - GOPATH string - generatePbGoCmd string - generateDocsCmd string - generateGoKitCmd string -} - -var global globalStruct - -// We build up environment knowledge here -// 1. Get working directory -// 2. Get $GOPATH -// 3. Use 1,2 to build path for golang imports for this package -// 4. Build 3 proto commands to invoke func init() { log.SetLevel(log.DebugLevel) log.SetFormatter(&log.TextFormatter{ ForceColors: true, }) - - var err error - global.workingDirectory, err = os.Getwd() - if err != nil { - log.WithError(err).Fatal("Cannot get working directory") - } - - global.GOPATH = os.Getenv("GOPATH") - - // From `$GOPATH/src/org/user/thing` get `org/user/thing` from importing in golang - global.genImportPath = strings.TrimPrefix(global.workingDirectory, global.GOPATH+"/src/") - - // Generate grpc golang code - global.generatePbGoCmd = "--go_out=Mgoogle/api/annotations.proto=" + global.genImportPath + GOOGLE_API_HTTP_IMPORT_PATH + "/google/api,plugins=grpc:./service/DONOTEDIT/pb" - // Generate documentation - global.generateDocsCmd = "--truss-doc_out=." - // Generate gokit-base service - global.generateGoKitCmd = "--truss-gokit_out=." - } // Stages are documented in README.md @@ -64,175 +24,52 @@ func main() { flag.Parse() if len(flag.Args()) == 0 { - fmt.Fprintf(os.Stderr, "usage: truss microservice.proto\n") + log.Fatal("No proto files passed") os.Exit(1) } - definitionPaths := flag.Args() + rawDefinitionPaths := flag.Args() - Stage1() + execWd, err := os.Getwd() + if err != nil { + log.WithError(err).Fatal("Cannot get working directory") + } - // Stage 2, 3, 4 - Stage234(definitionPaths) + var workingDirectory string + var definitionFiles []string - // Stage 5 - Stage5() + // Parsed passed file paths + for _, def := range rawDefinitionPaths { + // If the definition file path is not absolute, then make it absolute using trusses working directory + if !path.IsAbs(def) { + def = path.Clean(def) + def = path.Join(execWd, def) + } -} + // The working direcotry for this definition file + wd := path.Dir(def) + // Add the base name of definition file to the slice + definitionFiles = append(definitionFiles, path.Base(def)) -func Stage1() { - // Stage 1 - global.buildDirectories() - global.outputGoogleImport() -} - -func Stage234(definitionPaths []string) { - genPbGoDone := make(chan bool) - genDocsDone := make(chan bool) - genGoKitDone := make(chan bool) - go global.protoc(definitionPaths, global.generatePbGoCmd, genPbGoDone) - go global.protoc(definitionPaths, global.generateDocsCmd, genDocsDone) - go global.protoc(definitionPaths, global.generateGoKitCmd, genGoKitDone) - <-genPbGoDone - <-genDocsDone - <-genGoKitDone -} - -func Stage5() { - serverDone := make(chan bool) - clientDone := make(chan bool) - go goBuild("server", "./service/DONOTEDIT/cmd/svc/...", serverDone) - go goBuild("cliclient", "./service/DONOTEDIT/cmd/cliclient/...", clientDone) - <-serverDone - <-clientDone -} - -// buildDirectories puts the following directories in place -// . -// └── service -// ├── bin -// └── DONOTEDIT -// ├── pb -// └── third_party -// └── googleapis -// └── google -// └── api -func (g globalStruct) buildDirectories() { - // third_party created by going through assets in template - // and creating directoires that are not there - for _, filePath := range templates.AssetNames() { - fullPath := g.workingDirectory + "/" + filePath - - dirPath := filepath.Dir(fullPath) - - err := os.MkdirAll(dirPath, 0777) - if err != nil { - log.WithField("DirPath", dirPath).WithError(err).Fatal("Cannot create directories") + // If the working directory has not beenset before set it + if workingDirectory == "" { + workingDirectory = wd + } else { + // If the working directory for this definition file is different than the previous + if wd != workingDirectory { + log.Fatal("Passed protofiles reside in different directories") + } } } - // Create the directory where protoc will store the compiled .pb.go files - err := os.MkdirAll("service/DONOTEDIT/pb", 0777) - if err != nil { - log.WithField("DirPath", "service/DONOTEDIT/pb").WithError(err).Fatal("Cannot create directories") + goPath := os.Getenv("GOPATH") + + if !strings.HasPrefix(workingDirectory, goPath) { + log.Fatal("truss envoked from outside of $GOPATH") } - // Create the directory where go build will put the compiled binaries - err = os.MkdirAll("service/bin", 0777) - if err != nil { - log.WithField("DirPath", "service/bin").WithError(err).Fatal("Cannot create directories") - } -} - -// outputGoogleImport places imported and required google.api.http protobuf option files -// into their required directories as part of stage one generation -func (g globalStruct) outputGoogleImport() { - // Output files that are stored in template package - for _, filePath := range templates.AssetNames() { - fileBytes, _ := templates.Asset(filePath) - fullPath := g.workingDirectory + "/" + filePath - - err := ioutil.WriteFile(fullPath, fileBytes, 0666) - if err != nil { - log.WithField("FilePath", fullPath).WithError(err).Fatal("Cannot create ") - } - } -} - -// goBuild calls the `$ go get ` to install dependenices -// and then calls `$ go build service/bin/$name $path` -// to put the iterating binaries in the correct place -func goBuild(name string, path string, done chan bool) { - - goGetExec := exec.Command( - "go", - "get", - "-d", - "-v", - path, - ) - - goGetExec.Stderr = os.Stderr - - log.WithField("cmd", strings.Join(goGetExec.Args, " ")).Info("go get") - val, err := goGetExec.Output() - - if err != nil { - log.WithFields(log.Fields{ - "output": string(val), - "input": goGetExec.Args, - }).WithError(err).Warn("go get failed") - } - - goBuildExec := exec.Command( - "go", - "build", - "-o", - "service/bin/"+name, - path, - ) - //env := os.Environ() - //env = append(env, "CGO_ENABLED=0") - //goBuildExec.Env = env - - goBuildExec.Stderr = os.Stderr - - log.WithField("cmd", strings.Join(goBuildExec.Args, " ")).Info("go build") - val, err = goBuildExec.Output() - - if err != nil { - log.WithFields(log.Fields{ - "output": string(val), - "input": goBuildExec.Args, - }).WithError(err).Fatal("go build failed") - } - done <- true -} - -func (g globalStruct) protoc(definitionPaths []string, command string, done chan bool) { - cmdArgs := []string{ - "-I.", - "-I" + g.workingDirectory + GOOGLE_API_HTTP_IMPORT_PATH, - command, - } - // Append each definition file path to the end of that command args - cmdArgs = append(cmdArgs, definitionPaths...) - - protocExec := exec.Command( - "protoc", - cmdArgs..., - ) - - protocExec.Stderr = os.Stderr - - log.WithField("cmd", strings.Join(protocExec.Args, " ")).Info("protoc") - val, err := protocExec.Output() - - if err != nil { - log.WithFields(log.Fields{ - "output": string(val), - "input": protocExec.Args, - }).WithError(err).Fatal("Protoc call failed") - } - done <- true + // From `$GOPATH/src/org/user/thing` get `org/user/thing` for importing in golang + genImportPath := strings.TrimPrefix(workingDirectory, goPath+"/src/") + + generator.GenerateMicroservice(genImportPath, workingDirectory, definitionFiles) } From b30bbb71b19eb3ab5166e8ce0bd4c5f8e85ad880 Mon Sep 17 00:00:00 2001 From: Adam Ryman Date: Tue, 2 Aug 2016 14:10:22 -0700 Subject: [PATCH 2/2] Update Makefile with path, add logging to integration_tests --- truss/Makefile | 6 ++++-- truss/integration_tests/integration_runner_test.go | 1 + 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/truss/Makefile b/truss/Makefile index 6dc2ce0..6389dfa 100644 --- a/truss/Makefile +++ b/truss/Makefile @@ -17,7 +17,9 @@ clean: # Run truss on all proto files in all dirs in ./tests/ test: - go test -tags=integration - + go test -tags=integration -v ./integration_tests + +testclean: + go test -tags=integration ./integration_tests -clean diff --git a/truss/integration_tests/integration_runner_test.go b/truss/integration_tests/integration_runner_test.go index 1ffa1ca..56e65f7 100644 --- a/truss/integration_tests/integration_runner_test.go +++ b/truss/integration_tests/integration_runner_test.go @@ -64,6 +64,7 @@ func TestTruss(t *testing.T) { // Running the integration tests one at a time because truss running on all files at once // seems to slow the system more than distribute the work + t.Logf("Running integration test for %v...", d.Name()) out, err := truss(sDir) // If truss fails, test error and skip communication