Merge pull request #3609 from hashicorp/f-freeport-testing
Make freeport testing friendly
This commit is contained in:
commit
98863b9694
|
@ -3,10 +3,13 @@
|
||||||
package freeport
|
package freeport
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"fmt"
|
||||||
"math/rand"
|
"math/rand"
|
||||||
"net"
|
"net"
|
||||||
"sync"
|
"sync"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/mitchellh/go-testing-interface"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
|
@ -72,16 +75,37 @@ func tcpAddr(ip string, port int) *net.TCPAddr {
|
||||||
return &net.TCPAddr{IP: net.ParseIP(ip), Port: port}
|
return &net.TCPAddr{IP: net.ParseIP(ip), Port: port}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get returns a list of free ports from the allocated port block. It is safe
|
// Get wraps the Free function and panics on any failure retrieving ports.
|
||||||
|
func Get(n int) (ports []int) {
|
||||||
|
ports, err := Free(n)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return ports
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetT is suitable for use when retrieving unused ports in tests. If there is
|
||||||
|
// an error retrieving free ports, the test will be failed.
|
||||||
|
func GetT(t testing.T, n int) (ports []int) {
|
||||||
|
ports, err := Free(n)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("Failed retrieving free port: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return ports
|
||||||
|
}
|
||||||
|
|
||||||
|
// Free returns a list of free ports from the allocated port block. It is safe
|
||||||
// to call this method concurrently. Ports have been tested to be available on
|
// to call this method concurrently. Ports have been tested to be available on
|
||||||
// 127.0.0.1 TCP but there is no guarantee that they will remain free in the
|
// 127.0.0.1 TCP but there is no guarantee that they will remain free in the
|
||||||
// future.
|
// future.
|
||||||
func Get(n int) (ports []int) {
|
func Free(n int) (ports []int, err error) {
|
||||||
mu.Lock()
|
mu.Lock()
|
||||||
defer mu.Unlock()
|
defer mu.Unlock()
|
||||||
|
|
||||||
if n > blockSize-1 {
|
if n > blockSize-1 {
|
||||||
panic("freeport: block size too small")
|
return nil, fmt.Errorf("freeport: block size too small")
|
||||||
}
|
}
|
||||||
|
|
||||||
for len(ports) < n {
|
for len(ports) < n {
|
||||||
|
@ -103,5 +127,5 @@ func Get(n int) (ports []int) {
|
||||||
ports = append(ports, port)
|
ports = append(ports, port)
|
||||||
}
|
}
|
||||||
// log.Println("[DEBUG] freeport: free ports:", ports)
|
// log.Println("[DEBUG] freeport: free ports:", ports)
|
||||||
return ports
|
return ports, nil
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,21 @@
|
||||||
|
The MIT License (MIT)
|
||||||
|
|
||||||
|
Copyright (c) 2016 Mitchell Hashimoto
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
in the Software without restriction, including without limitation the rights
|
||||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
copies of the Software, and to permit persons to whom the Software is
|
||||||
|
furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in
|
||||||
|
all copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
|
THE SOFTWARE.
|
|
@ -0,0 +1,52 @@
|
||||||
|
# go-testing-interface
|
||||||
|
|
||||||
|
go-testing-interface is a Go library that exports an interface that
|
||||||
|
`*testing.T` implements as well as a runtime version you can use in its
|
||||||
|
place.
|
||||||
|
|
||||||
|
The purpose of this library is so that you can export test helpers as a
|
||||||
|
public API without depending on the "testing" package, since you can't
|
||||||
|
create a `*testing.T` struct manually. This lets you, for example, use the
|
||||||
|
public testing APIs to generate mock data at runtime, rather than just at
|
||||||
|
test time.
|
||||||
|
|
||||||
|
## Usage & Example
|
||||||
|
|
||||||
|
For usage and examples see the [Godoc](http://godoc.org/github.com/mitchellh/go-testing-interface).
|
||||||
|
|
||||||
|
Given a test helper written using `go-testing-interface` like this:
|
||||||
|
|
||||||
|
import "github.com/mitchellh/go-testing-interface"
|
||||||
|
|
||||||
|
func TestHelper(t testing.T) {
|
||||||
|
t.Fatal("I failed")
|
||||||
|
}
|
||||||
|
|
||||||
|
You can call the test helper in a real test easily:
|
||||||
|
|
||||||
|
import "testing"
|
||||||
|
|
||||||
|
func TestThing(t *testing.T) {
|
||||||
|
TestHelper(t)
|
||||||
|
}
|
||||||
|
|
||||||
|
You can also call the test helper at runtime if needed:
|
||||||
|
|
||||||
|
import "github.com/mitchellh/go-testing-interface"
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
TestHelper(&testing.RuntimeT{})
|
||||||
|
}
|
||||||
|
|
||||||
|
## Why?!
|
||||||
|
|
||||||
|
**Why would I call a test helper that takes a *testing.T at runtime?**
|
||||||
|
|
||||||
|
You probably shouldn't. The only use case I've seen (and I've had) for this
|
||||||
|
is to implement a "dev mode" for a service where the test helpers are used
|
||||||
|
to populate mock data, create a mock DB, perhaps run service dependencies
|
||||||
|
in-memory, etc.
|
||||||
|
|
||||||
|
Outside of a "dev mode", I've never seen a use case for this and I think
|
||||||
|
there shouldn't be one since the point of the `testing.T` interface is that
|
||||||
|
you can fail immediately.
|
|
@ -0,0 +1,84 @@
|
||||||
|
// +build !go1.9
|
||||||
|
|
||||||
|
package testing
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"log"
|
||||||
|
)
|
||||||
|
|
||||||
|
// T is the interface that mimics the standard library *testing.T.
|
||||||
|
//
|
||||||
|
// In unit tests you can just pass a *testing.T struct. At runtime, outside
|
||||||
|
// of tests, you can pass in a RuntimeT struct from this package.
|
||||||
|
type T interface {
|
||||||
|
Error(args ...interface{})
|
||||||
|
Errorf(format string, args ...interface{})
|
||||||
|
Fail()
|
||||||
|
FailNow()
|
||||||
|
Failed() bool
|
||||||
|
Fatal(args ...interface{})
|
||||||
|
Fatalf(format string, args ...interface{})
|
||||||
|
Log(args ...interface{})
|
||||||
|
Logf(format string, args ...interface{})
|
||||||
|
Name() string
|
||||||
|
Skip(args ...interface{})
|
||||||
|
SkipNow()
|
||||||
|
Skipf(format string, args ...interface{})
|
||||||
|
Skipped() bool
|
||||||
|
}
|
||||||
|
|
||||||
|
// RuntimeT implements T and can be instantiated and run at runtime to
|
||||||
|
// mimic *testing.T behavior. Unlike *testing.T, this will simply panic
|
||||||
|
// for calls to Fatal. For calls to Error, you'll have to check the errors
|
||||||
|
// list to determine whether to exit yourself. Name and Skip methods are
|
||||||
|
// unimplemented noops.
|
||||||
|
type RuntimeT struct {
|
||||||
|
failed bool
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *RuntimeT) Error(args ...interface{}) {
|
||||||
|
log.Println(fmt.Sprintln(args...))
|
||||||
|
t.Fail()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *RuntimeT) Errorf(format string, args ...interface{}) {
|
||||||
|
log.Println(fmt.Sprintf(format, args...))
|
||||||
|
t.Fail()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *RuntimeT) Fatal(args ...interface{}) {
|
||||||
|
log.Println(fmt.Sprintln(args...))
|
||||||
|
t.FailNow()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *RuntimeT) Fatalf(format string, args ...interface{}) {
|
||||||
|
log.Println(fmt.Sprintf(format, args...))
|
||||||
|
t.FailNow()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *RuntimeT) Fail() {
|
||||||
|
t.failed = true
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *RuntimeT) FailNow() {
|
||||||
|
panic("testing.T failed, see logs for output (if any)")
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *RuntimeT) Failed() bool {
|
||||||
|
return t.failed
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *RuntimeT) Log(args ...interface{}) {
|
||||||
|
log.Println(fmt.Sprintln(args...))
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *RuntimeT) Logf(format string, args ...interface{}) {
|
||||||
|
log.Println(fmt.Sprintf(format, args...))
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *RuntimeT) Name() string { return "" }
|
||||||
|
func (t *RuntimeT) Skip(args ...interface{}) {}
|
||||||
|
func (t *RuntimeT) SkipNow() {}
|
||||||
|
func (t *RuntimeT) Skipf(format string, args ...interface{}) {}
|
||||||
|
func (t *RuntimeT) Skipped() bool { return false }
|
|
@ -0,0 +1,108 @@
|
||||||
|
// +build go1.9
|
||||||
|
|
||||||
|
// NOTE: This is a temporary copy of testing.go for Go 1.9 with the addition
|
||||||
|
// of "Helper" to the T interface. Go 1.9 at the time of typing is in RC
|
||||||
|
// and is set for release shortly. We'll support this on master as the default
|
||||||
|
// as soon as 1.9 is released.
|
||||||
|
|
||||||
|
package testing
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"log"
|
||||||
|
)
|
||||||
|
|
||||||
|
// T is the interface that mimics the standard library *testing.T.
|
||||||
|
//
|
||||||
|
// In unit tests you can just pass a *testing.T struct. At runtime, outside
|
||||||
|
// of tests, you can pass in a RuntimeT struct from this package.
|
||||||
|
type T interface {
|
||||||
|
Error(args ...interface{})
|
||||||
|
Errorf(format string, args ...interface{})
|
||||||
|
Fail()
|
||||||
|
FailNow()
|
||||||
|
Failed() bool
|
||||||
|
Fatal(args ...interface{})
|
||||||
|
Fatalf(format string, args ...interface{})
|
||||||
|
Log(args ...interface{})
|
||||||
|
Logf(format string, args ...interface{})
|
||||||
|
Name() string
|
||||||
|
Skip(args ...interface{})
|
||||||
|
SkipNow()
|
||||||
|
Skipf(format string, args ...interface{})
|
||||||
|
Skipped() bool
|
||||||
|
Helper()
|
||||||
|
}
|
||||||
|
|
||||||
|
// RuntimeT implements T and can be instantiated and run at runtime to
|
||||||
|
// mimic *testing.T behavior. Unlike *testing.T, this will simply panic
|
||||||
|
// for calls to Fatal. For calls to Error, you'll have to check the errors
|
||||||
|
// list to determine whether to exit yourself.
|
||||||
|
type RuntimeT struct {
|
||||||
|
skipped bool
|
||||||
|
failed bool
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *RuntimeT) Error(args ...interface{}) {
|
||||||
|
log.Println(fmt.Sprintln(args...))
|
||||||
|
t.Fail()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *RuntimeT) Errorf(format string, args ...interface{}) {
|
||||||
|
log.Printf(format, args...)
|
||||||
|
t.Fail()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *RuntimeT) Fail() {
|
||||||
|
t.failed = true
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *RuntimeT) FailNow() {
|
||||||
|
panic("testing.T failed, see logs for output (if any)")
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *RuntimeT) Failed() bool {
|
||||||
|
return t.failed
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *RuntimeT) Fatal(args ...interface{}) {
|
||||||
|
log.Print(args...)
|
||||||
|
t.FailNow()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *RuntimeT) Fatalf(format string, args ...interface{}) {
|
||||||
|
log.Printf(format, args...)
|
||||||
|
t.FailNow()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *RuntimeT) Log(args ...interface{}) {
|
||||||
|
log.Println(fmt.Sprintln(args...))
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *RuntimeT) Logf(format string, args ...interface{}) {
|
||||||
|
log.Println(fmt.Sprintf(format, args...))
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *RuntimeT) Name() string {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *RuntimeT) Skip(args ...interface{}) {
|
||||||
|
log.Print(args...)
|
||||||
|
t.SkipNow()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *RuntimeT) SkipNow() {
|
||||||
|
t.skipped = true
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *RuntimeT) Skipf(format string, args ...interface{}) {
|
||||||
|
log.Printf(format, args...)
|
||||||
|
t.SkipNow()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *RuntimeT) Skipped() bool {
|
||||||
|
return t.skipped
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *RuntimeT) Helper() {}
|
|
@ -67,6 +67,7 @@
|
||||||
{"path":"github.com/mitchellh/cli","checksumSHA1":"GzfpPGtV2UJH9hFsKwzGjKrhp/A=","revision":"dff723fff508858a44c1f4bd0911f00d73b0202f","revisionTime":"2017-09-05T22:10:09Z"},
|
{"path":"github.com/mitchellh/cli","checksumSHA1":"GzfpPGtV2UJH9hFsKwzGjKrhp/A=","revision":"dff723fff508858a44c1f4bd0911f00d73b0202f","revisionTime":"2017-09-05T22:10:09Z"},
|
||||||
{"path":"github.com/mitchellh/copystructure","checksumSHA1":"86nE93o1VIND0Doe8PuhCXnhUx0=","revision":"cdac8253d00f2ecf0a0b19fbff173a9a72de4f82","revisionTime":"2016-08-04T03:23:30Z"},
|
{"path":"github.com/mitchellh/copystructure","checksumSHA1":"86nE93o1VIND0Doe8PuhCXnhUx0=","revision":"cdac8253d00f2ecf0a0b19fbff173a9a72de4f82","revisionTime":"2016-08-04T03:23:30Z"},
|
||||||
{"path":"github.com/mitchellh/go-homedir","checksumSHA1":"V/quM7+em2ByJbWBLOsEwnY3j/Q=","revision":"b8bc1bf767474819792c23f32d8286a45736f1c6","revisionTime":"2016-12-03T19:45:07Z"},
|
{"path":"github.com/mitchellh/go-homedir","checksumSHA1":"V/quM7+em2ByJbWBLOsEwnY3j/Q=","revision":"b8bc1bf767474819792c23f32d8286a45736f1c6","revisionTime":"2016-12-03T19:45:07Z"},
|
||||||
|
{"path":"github.com/mitchellh/go-testing-interface","checksumSHA1":"bDdhmDk8q6utWrccBhEOa6IoGkE=","revision":"a61a99592b77c9ba629d254a693acffaeb4b7e28","revisionTime":"2017-10-04T22:19:16Z"},
|
||||||
{"path":"github.com/mitchellh/mapstructure","checksumSHA1":"gILp4IL+xwXLH6tJtRLrnZ56F24=","revision":"06020f85339e21b2478f756a78e295255ffa4d6a","revisionTime":"2017-10-17T17:18:08Z"},
|
{"path":"github.com/mitchellh/mapstructure","checksumSHA1":"gILp4IL+xwXLH6tJtRLrnZ56F24=","revision":"06020f85339e21b2478f756a78e295255ffa4d6a","revisionTime":"2017-10-17T17:18:08Z"},
|
||||||
{"path":"github.com/mitchellh/reflectwalk","checksumSHA1":"mrqMlK6gqe//WsJSrJ1HgkPM0lM=","revision":"eecf4c70c626c7cfbb95c90195bc34d386c74ac6","revisionTime":"2015-05-27T15:31:53Z"},
|
{"path":"github.com/mitchellh/reflectwalk","checksumSHA1":"mrqMlK6gqe//WsJSrJ1HgkPM0lM=","revision":"eecf4c70c626c7cfbb95c90195bc34d386c74ac6","revisionTime":"2015-05-27T15:31:53Z"},
|
||||||
{"path":"github.com/pascaldekloe/goe/verify","checksumSHA1":"5h+ERzHw3Rl2G0kFPxoJzxiA9s0=","revision":"07ebd1e2481f616a278ab431cf04cc5cf5ab3ebe","revisionTime":"2017-03-28T18:37:59Z"},
|
{"path":"github.com/pascaldekloe/goe/verify","checksumSHA1":"5h+ERzHw3Rl2G0kFPxoJzxiA9s0=","revision":"07ebd1e2481f616a278ab431cf04cc5cf5ab3ebe","revisionTime":"2017-03-28T18:37:59Z"},
|
||||||
|
|
Loading…
Reference in New Issue