diff --git a/go/gorm/server.go b/go/gorm/server.go index f959b89..9f58ea7 100644 --- a/go/gorm/server.go +++ b/go/gorm/server.go @@ -45,7 +45,7 @@ func (s *Server) RegisterRouter(router *httprouter.Router) { } func (s *Server) ping(w http.ResponseWriter, r *http.Request, _ httprouter.Params) { - writeTextResult(w, "pong") + writeTextResult(w, "go/gorm") } func (s *Server) getCustomers(w http.ResponseWriter, r *http.Request, _ httprouter.Params) { diff --git a/java/hibernate/Makefile b/java/hibernate/Makefile index 6e96e8c..ce4df1b 100644 --- a/java/hibernate/Makefile +++ b/java/hibernate/Makefile @@ -30,4 +30,4 @@ start: .PHONY: deps deps: - $(GRADLE) assemble + $(GRADLE) assemble --stacktrace diff --git a/java/hibernate/src/main/java/com/cockroachlabs/services/PingService.java b/java/hibernate/src/main/java/com/cockroachlabs/services/PingService.java index fedaad9..9df849d 100644 --- a/java/hibernate/src/main/java/com/cockroachlabs/services/PingService.java +++ b/java/hibernate/src/main/java/com/cockroachlabs/services/PingService.java @@ -10,7 +10,7 @@ public class PingService { @GET @Produces("text/plain") public String ping() { - return "pong"; + return "java/hibernate"; } } diff --git a/testing/api_handler.go b/testing/api_handler.go index 7c4df9e..7f0edca 100644 --- a/testing/api_handler.go +++ b/testing/api_handler.go @@ -4,7 +4,9 @@ import ( "bytes" "encoding/json" "io/ioutil" + "net" "net/http" + "strings" "github.com/pkg/errors" @@ -12,12 +14,13 @@ import ( ) const ( - applicationAddr = "http://localhost:6543" + applicationAddr = "localhost:6543" + applicationURL = "http://" + applicationAddr - pingPath = applicationAddr + "/ping" - customersPath = applicationAddr + "/customer" - ordersPath = applicationAddr + "/order" - productsPath = applicationAddr + "/product" + pingPath = applicationURL + "/ping" + customersPath = applicationURL + "/customer" + ordersPath = applicationURL + "/order" + productsPath = applicationURL + "/product" jsonContentType = "application/json" ) @@ -27,8 +30,28 @@ const ( // across all ORMs. type apiHandler struct{} -func (apiHandler) ping() error { - _, err := http.Get(pingPath) +func (apiHandler) canDial() bool { + conn, err := net.Dial("tcp", applicationAddr) + if err != nil { + return false + } + conn.Close() + return true +} + +func (apiHandler) ping(expected string) error { + resp, err := http.Get(pingPath) + if err != nil { + return err + } + defer resp.Body.Close() + if resp.StatusCode != http.StatusOK { + return errors.Errorf("HTTP error %s", resp.Status) + } + b, err := ioutil.ReadAll(resp.Body) + if body := strings.TrimSpace(string(b)); body != expected { + return errors.Errorf("ping response %s != expected %s", body, expected) + } return err } diff --git a/testing/main_test.go b/testing/main_test.go index 55e006c..0d523e9 100644 --- a/testing/main_test.go +++ b/testing/main_test.go @@ -4,8 +4,10 @@ import ( "bytes" "database/sql" "fmt" + "io" "log" "net/url" + "os" "os/exec" "strings" "syscall" @@ -25,8 +27,12 @@ type application struct { orm string } +func (app application) name() string { + return fmt.Sprintf("%s/%s", app.language, app.orm) +} + func (app application) dir() string { - return fmt.Sprintf("../%s/%s", app.language, app.orm) + return fmt.Sprintf("../%s", app.name()) } func (app application) dbName() string { @@ -85,20 +91,19 @@ func initORMApp(t *testing.T, app application, dbURL *url.URL) (killFunc, restar cmd := exec.Command(args[0], args[1:]...) - // Set up stderr so we can later verify that it's clean. + // Set up stderr to display to console and store in a buffer, so we can later + // verify that it's clean. stderr := new(bytes.Buffer) - cmd.Stderr = stderr + cmd.Stderr = io.MultiWriter(stderr, os.Stderr) // make will launch the application in a child process, and this is the most // straightforward way to kill all ancestors. cmd.SysProcAttr = &syscall.SysProcAttr{Setpgid: true} killed := false killCmd := func() { - if s := stderr.String(); len(s) > 0 { - log.Print("app error:", s) - } if !killed { syscall.Kill(-cmd.Process.Pid, syscall.SIGKILL) + waitForAppExit() } killed = true } @@ -111,13 +116,12 @@ func initORMApp(t *testing.T, app application, dbURL *url.URL) (killFunc, restar log.Printf("process %d started: %s", cmd.Process.Pid, strings.Join(args, " ")) } - if err := waitForInit(); err != nil { + if err := waitForInit(app); err != nil { killCmd() t.Fatalf("error waiting for http server initialization: %v stderr=%s", err, stderr.String()) } if s := stderr.String(); len(s) > 0 { killCmd() - t.Fatalf("stderr=%s", s) } restartCmd := func() (killFunc, restartFunc) { @@ -129,7 +133,7 @@ func initORMApp(t *testing.T, app application, dbURL *url.URL) (killFunc, restar } // waitForInit retries until a connection is successfully established. -func waitForInit() error { +func waitForInit(app application) error { const maxWait = 3 * time.Minute const waitDelay = 250 * time.Millisecond const maxWaitLoops = int(maxWait / waitDelay) @@ -137,7 +141,7 @@ func waitForInit() error { var err error var api apiHandler for i := 0; i < maxWaitLoops; i++ { - if err = api.ping(); err == nil { + if err = api.ping(app.name()); err == nil { return err } log.Printf("waitForInit: %v", err) @@ -146,6 +150,20 @@ func waitForInit() error { return err } +// waitForExit waits indefinitely for the HTTP port of the ORM to stop +// listening. +func waitForAppExit() { + const waitDelay = time.Second + var api apiHandler + for { + if !api.canDial() { + break + } + log.Print("waiting for app to exit") + time.Sleep(waitDelay) + } +} + func testORM(t *testing.T, language, orm string) { app := application{ language: language,