From 098d71c04d7f7f6b1b37bef60ea18dadb6bdd428 Mon Sep 17 00:00:00 2001 From: Alex Dadgar Date: Fri, 20 Oct 2017 16:46:13 -0700 Subject: [PATCH] Testutil falls back to random ports w/o porter (#3604) * Testutil falls back to random ports w/o porter This PR allows the testutil server to be used without porter. * Adds sterner-sounding fallback comments. --- test/porter/client.go | 25 +++++++++++++++++++++++-- testutil/server.go | 28 +++++++++++++++++++++++++++- 2 files changed, 50 insertions(+), 3 deletions(-) diff --git a/test/porter/client.go b/test/porter/client.go index b340b68ee..1c746e9be 100644 --- a/test/porter/client.go +++ b/test/porter/client.go @@ -9,7 +9,28 @@ import ( "strings" ) -var DefaultAddr = "127.0.0.1:7965" +var ( + // DefaultAddr is the the default bind address of a Porter server. This acts + // as the fallback address if the Porter server is not specified. + DefaultAddr = "127.0.0.1:7965" +) + +const ( + // porterErrPrefix is the string returned when displaying a porter error + porterErrPrefix = `Are you running porter? +Install with 'go install github.com/hashicorp/consul/test/porter/cmd/porter' +Then run 'porter go test ...'` +) + +// PorterExistErr is used to wrap an error that is likely from Porter not being +// run. +type PorterExistErr struct { + Wrapped error +} + +func (p *PorterExistErr) Error() string { + return fmt.Sprintf("%s:\n%s", porterErrPrefix, p.Wrapped) +} func RandomPorts(n int) ([]int, error) { addr := os.Getenv("PORTER_ADDR") @@ -25,7 +46,7 @@ func RandomPorts(n int) ([]int, error) { resp, err := http.Get(fmt.Sprintf("http://%s/%d", addr, n)) if err != nil { if strings.Contains(err.Error(), "connection refused") { - return nil, fmt.Errorf("Are you running porter?\nInstall with 'go install github.com/hashicorp/consul/test/porter/cmd/porter'\nThen run 'porter go test ...'\n%s", err) + return nil, &PorterExistErr{Wrapped: err} } return nil, err } diff --git a/testutil/server.go b/testutil/server.go index c01471271..93b734a67 100644 --- a/testutil/server.go +++ b/testutil/server.go @@ -113,7 +113,14 @@ func defaultServerConfig() *TestServerConfig { ports, err := porter.RandomPorts(6) if err != nil { - panic(err) + if _, ok := err.(*porter.PorterExistErr); ok { + // Fall back in the case that the testutil server is being used + // without porter. This should NEVER be used for Consul's own + // unit tests. See comments for getRandomPorts() for more details. + ports = getRandomPorts(6) + } else { + panic(err) + } } return &TestServerConfig{ NodeName: "node-" + nodeID, @@ -383,3 +390,22 @@ func (s *TestServer) waitForLeader() error { } return nil } + +// getRandomPorts returns a set of random port or panics on error. This +// is here to support external uses of testutil which may not have porter, +// but this has been shown not to work well with parallel tests (such as +// Consul's unit tests). This fallback should NEVER be used for Consul's +// own tests. +func getRandomPorts(n int) []int { + ports := make([]int, n) + for i := 0; i < n; i++ { + l, err := net.Listen("tcp", ":0") + if err != nil { + panic(err) + } + l.Close() + ports[i] = l.Addr().(*net.TCPAddr).Port + } + + return ports +}