utils/testutil/testutil.go (73 lines of code) (raw):
// Copyright (c) 2016-2019 Uber Technologies, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package testutil
import (
"fmt"
"io/ioutil"
"net"
"net/http"
"os"
"time"
)
// PollUntilTrue calls f until f returns true. Returns error if true is not received
// within timeout.
func PollUntilTrue(timeout time.Duration, f func() bool) error {
timer := time.NewTimer(timeout)
for {
result := make(chan bool, 1)
go func() {
result <- f()
}()
select {
case ok := <-result:
if ok {
return nil
}
time.Sleep(100 * time.Millisecond)
case <-timer.C:
return fmt.Errorf("timed out after %.2f seconds", timeout.Seconds())
}
}
}
// Cleanup contains a list of function that are called to cleanup a fixture
type Cleanup struct {
funcs []func()
}
// Add adds function to funcs list
func (c *Cleanup) Add(f ...func()) {
c.funcs = append(c.funcs, f...)
}
// AppendFront append funcs from another cleanup in front of the funcs list
func (c *Cleanup) AppendFront(c1 *Cleanup) {
c.funcs = append(c1.funcs, c.funcs...)
}
// Recover runs cleanup functions after test exit with exception
func (c *Cleanup) Recover() {
if err := recover(); err != nil {
c.run()
panic(err)
}
}
// Run runs cleanup functions when a test finishes running
func (c *Cleanup) Run() {
c.run()
}
func (c *Cleanup) run() {
for _, f := range c.funcs {
f()
}
}
// StartServer starts an HTTP server with h. Returns address the server is
// listening on, and a closure for stopping the server.
func StartServer(h http.Handler) (addr string, stop func()) {
l, err := net.Listen("tcp", "localhost:0")
if err != nil {
panic(err)
}
s := &http.Server{Handler: h}
go s.Serve(l)
return l.Addr().String(), func() { s.Close() }
}
// TempFile creates a temporary file. Returns its name and cleanup function.
func TempFile(data []byte) (string, func()) {
var cleanup Cleanup
defer cleanup.Recover()
f, err := ioutil.TempFile(".", "")
if err != nil {
panic(err)
}
cleanup.Add(func() { os.Remove(f.Name()) })
defer f.Close()
if _, err := f.Write(data); err != nil {
panic(err)
}
return f.Name(), cleanup.Run
}