ktesting: install signal handler on demand

The ktesting package is meant to be usable in E2E suites and then must not
affect signal handling in Ginkgo.
This commit is contained in:
Patrick Ohly
2026-01-10 15:44:31 +01:00
parent 81383b249f
commit 7421eea877
3 changed files with 21 additions and 5 deletions

View File

@@ -29,6 +29,10 @@ func TestMain(m *testing.M) {
// Bail out early when -help was given as parameter.
flag.Parse()
// The unit tests assume that they run as a unit test, with progress reporting enabled.
// This leaks a goroutine, so we have to do it before IgnoreCurrent.
initSignals()
// Must be called *before* creating new goroutines.
goleakOpts := []goleak.Option{
goleak.IgnoreCurrent(),

View File

@@ -27,7 +27,7 @@ import (
)
var (
interruptCtx context.Context
interruptCtx = context.Background()
defaultProgressReporter = new(progressReporter)
defaultSignalChannel chan os.Signal
@@ -39,10 +39,11 @@ type ginkgoReporter interface {
AttachProgressReporter(reporter func() string) func()
}
func init() {
// Setting up signals is intentionally done in an init function because
// then importing ktesting in a unit or integration test is sufficient
// to activate the signal behavior.
// initSignals is invoked once when ktesting is used for a `go test` unit test.
// It implements support for triggering a progress report in
// a running test when sending it a USR1 signal, similar to the corresponding
// Ginkgo feature.
func initSignals() {
signalCtx, _ := signal.NotifyContext(context.Background(), os.Interrupt)
cancelCtx, cancel := context.WithCancelCause(context.Background())
go func() {
@@ -70,6 +71,8 @@ func init() {
go defaultProgressReporter.run(interruptCtx, defaultSignalChannel)
}
var initSignalsOnce sync.Once
type progressReporter struct {
mutex sync.Mutex
reporterCounter int64

View File

@@ -162,6 +162,15 @@ func Init(tb TB, opts ...InitOption) TContext {
tCtx.Cleanup(func() {
tCtx.Cancel(cleanupErr(tCtx.Name()).Error())
})
// Only enable signal handling if we are sure that we are not
// in a Ginkgo suite. Only structs from the testing package
// can implement this interface because it contains an "internal"
// method, so this has to run under `go test`.
if _, ok := tb.(testing.TB); ok {
initSignalsOnce.Do(initSignals)
}
return tCtx
}