func WaitContext(ctx context.Context, f func()) bool {
	done := make(chan struct{})
	wg := &sync.WaitGroup{}
	wg.Add(1)
	go func() {
		wg.Done()
		f()
		close(done)
	}()
	wg.Wait()
	select {
	case <-ctx.Done():
		return false
	case <-done:
		return true
	}
}
WaitContext returns true if f returns before <-ctx.Done() or false otherwise.
An example of a f, for which this is useful would be Wait method of sync.WaitGroup.
Note, this function leaks a goroutine if f never returns.
package test
import (
	"context"
	"fmt"
	"os"
	"strconv"
	"strings"
	"sync"
	"time"
	"go.thethings.network/lorawan-stack/v3/pkg/errors"
)
func FormatError(err error) string {
	if err == nil {
		return "nil"
	}
	var s string
	for i, err := range errors.Stack(err) {
		s += fmt.Sprintf(`
%s-> %s (attributes: %v)`,
			strings.Repeat("-", i), err, errors.Attributes(err),
		)
	}
	return s
}
var Delay = time.Millisecond * func() time.Duration {
	env := os.Getenv("TEST_SLOWDOWN")
	if env == "" {
		return 1
	}
	v, err := strconv.Atoi(env)
	if err != nil {
		return 1
	}
	return time.Duration(v)
}()
func Must(v interface{}, err error) interface{} {
	if err != nil {
		panic(fmt.Sprintf("Must received error: %v", FormatError(err)))
	}
	return v
}
func MustMultiple(vs ...interface{}) []interface{} {
	n := len(vs)
	if n == 0 {
		panic("MustMultiple requires at least 1 argument")
	}
	err, ok := vs[n-1].(error)
	if !ok && vs[n-1] != nil {
		panic(fmt.Sprintf("MustMultiple expected last argument to be an error, got %T", vs[n-1]))
	}
	if err != nil {
		panic(fmt.Sprintf("MustMultiple received error: %s", FormatError(err)))
	}
	return vs[:n-1]
}
func WaitTimeout(d time.Duration, f func()) bool {
	done := make(chan struct{})
	wg := &sync.WaitGroup{}
	wg.Add(1)
	go func() {
		wg.Done()
		f()
		close(done)
	}()
	wg.Wait()
	select {
	case <-time.After(d):
		return false
	case <-done:
		return true
	}
}
func WaitDeadline(t time.Time, f func()) bool {
	return WaitTimeout(time.Until(t), f)
}