mirror of
https://github.com/featurebasedb/featurebase.git
synced 2026-08-28 02:44:59 +00:00
126 lines
3.6 KiB
Go
126 lines
3.6 KiB
Go
// Copyright 2021 Molecula Corp. All rights reserved.
|
|
package test
|
|
|
|
import (
|
|
"log"
|
|
"os"
|
|
"sync"
|
|
"testing"
|
|
|
|
"github.com/featurebasedb/featurebase/v3/testhook"
|
|
)
|
|
|
|
// glue lets us make a thing which isn't a testing.TB, but can be passed
|
|
// around to the functions that take testing.TB.
|
|
|
|
// DirCleaner represents the subset of the testing.TB interface
|
|
// we care about, allowing us to take objects which behave like
|
|
// that without importing all of testing to get them.
|
|
type DirCleaner interface {
|
|
Helper()
|
|
Errorf(string, ...interface{})
|
|
Fatalf(string, ...interface{})
|
|
Fatal(...interface{})
|
|
Logf(string, ...interface{})
|
|
Name() string
|
|
TempDir() string
|
|
Cleanup(func())
|
|
Skip(...interface{})
|
|
}
|
|
|
|
// Verify that a TB is a DirCleaner
|
|
var _ DirCleaner = testing.TB(nil)
|
|
var _ DirCleaner = &wholeTestRunWrapper{}
|
|
|
|
// wholeTestRun is a thing that's shaped a bit like testing.TB,
|
|
// but it can be used across all the tests, running its cleanup functions
|
|
// at the very end of the testing process. this lets us create clusters
|
|
// using the same code and logic we would for per-test things, except
|
|
// substituting this, and then have a single global post-test-hook run
|
|
// their cleanup.
|
|
type wholeTestRun struct {
|
|
setup sync.Once
|
|
mu sync.Mutex
|
|
tempDirs []string
|
|
cleanupFuncs []func()
|
|
}
|
|
|
|
// wholeTestRunWrapper is a test-specific thing that can refer to the
|
|
// global shared state, but also forwards everything *except* TempDir,
|
|
// Cleanup, and Logf to the tb it's created with.
|
|
type wholeTestRunWrapper struct {
|
|
testing.TB
|
|
}
|
|
|
|
// globalT is a system-wide wholeTestRun. the first time it's used, for any
|
|
// reason, it registers a cleanup with testhook, which will run at the end
|
|
// of the TestMain stuff, but before any previously-registered cleanup
|
|
// functions (such as the auditor stuff) so it can ensure that everything's
|
|
// been deleted. Basically this exists to let us call `tb.TempDir` on
|
|
// things and get a directory which outlives the current test.
|
|
var globalT wholeTestRun
|
|
|
|
// NewWholeTestRun produces a wholeTestRunWrapper around TB, which overrides
|
|
// a couple of the TB's methods to get whole-test-friendly behaviors.
|
|
func NewWholeTestRun(tb testing.TB) *wholeTestRunWrapper {
|
|
return &wholeTestRunWrapper{TB: tb}
|
|
}
|
|
|
|
func (w *wholeTestRun) Teardown() {
|
|
w.mu.Lock()
|
|
defer w.mu.Unlock()
|
|
for _, fn := range w.cleanupFuncs {
|
|
fn()
|
|
}
|
|
for _, path := range w.tempDirs {
|
|
// disregard errors because we don't care that much about them;
|
|
// we assume RemoveAll probably works unless something's wrong.
|
|
// see the comments on the testing package's internal removeAll,
|
|
// which suggests the errors only happen on Windows, which we
|
|
// don't support.
|
|
_ = os.RemoveAll(path)
|
|
}
|
|
}
|
|
|
|
func (w *wholeTestRun) Setup() {
|
|
w.setup.Do(func() {
|
|
testhook.RegisterPostTestHook(func() error {
|
|
w.Teardown()
|
|
return nil
|
|
})
|
|
})
|
|
}
|
|
|
|
// We provide a Logf here because the wholeTestRunWrapper could
|
|
// be set as a tb-replacement for something which lasts past the
|
|
// test that created it. That shouldn't happen, probably.
|
|
func (w *wholeTestRunWrapper) Logf(msg string, args ...interface{}) {
|
|
log.Printf(msg, args...)
|
|
}
|
|
|
|
func (w *wholeTestRun) TempDir(tb DirCleaner) string {
|
|
w.Setup()
|
|
w.mu.Lock()
|
|
defer w.mu.Unlock()
|
|
path, err := os.MkdirTemp("", "test-temp-")
|
|
if err != nil {
|
|
tb.Fatalf("creating temp dir: %v", err)
|
|
}
|
|
globalT.tempDirs = append(globalT.tempDirs, path)
|
|
return path
|
|
}
|
|
|
|
func (w *wholeTestRun) Cleanup(fn func()) {
|
|
w.Setup()
|
|
w.mu.Lock()
|
|
defer w.mu.Unlock()
|
|
w.cleanupFuncs = append(w.cleanupFuncs, fn)
|
|
}
|
|
|
|
func (w *wholeTestRunWrapper) TempDir() string {
|
|
return globalT.TempDir(w.TB)
|
|
}
|
|
|
|
func (w *wholeTestRunWrapper) Cleanup(fn func()) {
|
|
globalT.Cleanup(fn)
|
|
}
|