Skip to content

ktesting: abort entire test suite on SIGINT + /dev/tty #128606

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions test/utils/ktesting/ktesting.go
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ func SetDefaultVerbosity(v int) {
// NewTestContext is a replacement for ktesting.NewTestContext
// which returns a more versatile context.
func NewTestContext(tb testing.TB) (klog.Logger, TContext) {
tb.Helper()
tCtx := Init(tb)
return tCtx.Logger(), tCtx
}
18 changes: 14 additions & 4 deletions test/utils/ktesting/signals.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ package ktesting
import (
"context"
"errors"
"fmt"
"io"
"os"
"os/signal"
Expand All @@ -40,18 +41,29 @@ type ginkgoReporter interface {
}

func init() {
// os.Stderr gets redirected by "go test". "go test -v" has to be
// used to see the output while a test runs. Opening /dev/tty avoids
// the redirection, but isn't always possible.
console, err := os.OpenFile("/dev/tty", os.O_RDWR|os.O_APPEND, 0)
if err != nil {
console = os.Stderr
fmt.Fprintf(console, "Cannot use /dev/tty: %v", err)
}

// 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.
signalCtx, _ := signal.NotifyContext(context.Background(), os.Interrupt)
cancelCtx, cancel := context.WithCancelCause(context.Background())
go func() {
<-signalCtx.Done()
fmt.Fprintf(console, "\n\nINFO: canceling test context(s): received interrupt signal\n\n")
cancel(errors.New("received interrupt signal"))
}()

// This reimplements the contract between Ginkgo and Gomega for progress reporting.
// When using Ginkgo contexts, Ginkgo will implement it. This here is for "go test".
// When using Ginkgo contexts, Ginkgo will implement it. This here is for "go test"
// in combination with Gomega.
//
// nolint:staticcheck // It complains about using a plain string. This can only be fixed
// by Ginkgo and Gomega formalizing this interface and define a type (somewhere...
Expand All @@ -64,9 +76,7 @@ func init() {
signal.Notify(defaultSignalChannel, progressSignals...)
}

// os.Stderr gets redirected by "go test". "go test -v" has to be
// used to see the output while a test runs.
defaultProgressReporter.setOutput(os.Stderr)
defaultProgressReporter.setOutput(console)
go defaultProgressReporter.run(interruptCtx, defaultSignalChannel)
}

Expand Down
7 changes: 7 additions & 0 deletions test/utils/ktesting/tcontext.go
Original file line number Diff line number Diff line change
Expand Up @@ -239,7 +239,14 @@ func Init(tb TB, opts ...InitOption) TContext {
Deadline() (time.Time, bool)
})

// If testing has been interrupted, immediately fail all new tests.
// Giving them a canceled context also works, but only if the tests
// actually check it.
ctx := interruptCtx
if ctx.Err() != nil {
tb.Fatalf("testing has been interrupted: %v", context.Cause(ctx))
}

if c.PerTestOutput {
config := ktesting.NewConfig(
ktesting.AnyToString(func(v interface{}) string {
Expand Down