complement/helpers/waiter.go
kegsay 5ecb086412
refactor: make logging test agnostic and colourful (#703)
- The entire Complement API now no longer uses `t *testing.T`, instead
  opting for `ct.TestLike` which is an interface. In practice, this changes
  nothing. However, this enables Complement to be used in many more places
  where you do not have a `t *testing.T` object to use e.g benchmarks, scripts.
  This is of particular use for Complement-Crypto which has to run parts of the
  test as a standalone binary, and therefore has no `t *testing.T` to use.
- The entire Complement API now uses `ct.Fatalf` and `ct.Errorf` for highlighting
  test failures in red. This should make it significantly easier to skim for the
  test failure message.
- Add `Deployment.ContainerID(TestLike, hsName) string` to allow tests to interact
  with the container beyond the abilities of the Complement API e.g log extraction,
  memory use, CPU use.
2024-01-17 12:41:04 +00:00

61 lines
1.7 KiB
Go

package helpers
import (
"fmt"
"sync"
"time"
"github.com/matrix-org/complement/ct"
)
// Waiter is a simple primitive to wait for a signal asynchronously. It is preferred
// over other sync primitives due to having more sensible defaults such as built-in timeouts
// if the signal does not appear and ability to signal more than once without panicking.
type Waiter struct {
mu sync.Mutex
ch chan bool
closed bool
}
// NewWaiter returns a generic struct which can be waited on until `Waiter.Finish` is called.
// A Waiter is similar to a `sync.WaitGroup` of size 1, but without the ability to underflow and
// with built-in timeouts.
func NewWaiter() *Waiter {
return &Waiter{
ch: make(chan bool),
mu: sync.Mutex{},
}
}
// Wait blocks until Finish() is called or until the timeout is reached.
// If the timeout is reached, the test is failed.
func (w *Waiter) Wait(t ct.TestLike, timeout time.Duration) {
t.Helper()
w.Waitf(t, timeout, "Wait")
}
// Waitf blocks until Finish() is called or until the timeout is reached.
// If the timeout is reached, the test is failed with the given error message.
func (w *Waiter) Waitf(t ct.TestLike, timeout time.Duration, errFormat string, args ...interface{}) {
t.Helper()
select {
case <-w.ch:
return
case <-time.After(timeout):
errmsg := fmt.Sprintf(errFormat, args...)
ct.Fatalf(t, "%s: timed out after %f seconds.", errmsg, timeout.Seconds())
}
}
// Finish will cause all goroutines waiting via Wait to stop waiting and return.
// Once this function has been called, subsequent calls to Wait will return immediately.
// To begin waiting again, make a new Waiter.
func (w *Waiter) Finish() {
w.mu.Lock()
defer w.mu.Unlock()
if w.closed {
return
}
w.closed = true
close(w.ch)
}