Skip to content

Commit f9e7b15

Browse files
committed
ktesting: add Run
This is useful in Go unit tests because it directly replaces the corresponding testing.T/B.Run.
1 parent c2ad724 commit f9e7b15

File tree

5 files changed

+76
-0
lines changed

5 files changed

+76
-0
lines changed

test/utils/ktesting/clientcontext.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,10 @@ func (cCtx clientContext) ExpectNoError(err error, explain ...interface{}) {
8686
expectNoError(cCtx, err, explain...)
8787
}
8888

89+
func (cCtx clientContext) Run(name string, cb func(tCtx TContext)) bool {
90+
return run(cCtx, name, cb)
91+
}
92+
8993
func (cCtx clientContext) Logger() klog.Logger {
9094
return klog.FromContext(cCtx)
9195
}

test/utils/ktesting/errorcontext.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -149,6 +149,10 @@ func (eCtx *errorContext) ExpectNoError(err error, explain ...interface{}) {
149149
expectNoError(eCtx, err, explain...)
150150
}
151151

152+
func (cCtx *errorContext) Run(name string, cb func(tCtx TContext)) bool {
153+
return run(cCtx, name, cb)
154+
}
155+
152156
func (eCtx *errorContext) Logger() klog.Logger {
153157
return klog.FromContext(eCtx)
154158
}

test/utils/ktesting/tcontext.go

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ import (
2121
"flag"
2222
"fmt"
2323
"strings"
24+
"testing"
2425
"time"
2526

2627
"github.com/onsi/gomega"
@@ -84,6 +85,13 @@ type TContext interface {
8485
// a single test never run in parallel with each other.
8586
Parallel()
8687

88+
// Run runs f as a subtest of t called name. It blocks until f returns or
89+
// calls t.Parallel to become a parallel test.
90+
//
91+
// Only supported in Go unit tests or benchmarks. It fails the current
92+
// test when called elsewhere.
93+
Run(name string, f func(tCtx TContext)) bool
94+
8795
// Cancel can be invoked to cancel the context before the test is completed.
8896
// Tests which use the context to control goroutines and then wait for
8997
// termination of those goroutines must call Cancel to avoid a deadlock.
@@ -174,6 +182,7 @@ type TContext interface {
174182
// - CleanupCtx
175183
// - Expect
176184
// - ExpectNoError
185+
// - Run
177186
// - Logger
178187
//
179188
// Usually these methods would be stand-alone functions with a TContext
@@ -337,6 +346,9 @@ func InitCtx(ctx context.Context, tb TB, _ ...InitOption) TContext {
337346
// })
338347
//
339348
// WithTB sets up cancellation for the sub-test.
349+
//
350+
// A simpler API is to use TContext.Run as replacement
351+
// for [testing.T.Run].
340352
func WithTB(parentCtx TContext, tb TB) TContext {
341353
tCtx := InitCtx(parentCtx, tb)
342354
tCtx = WithCancel(tCtx)
@@ -350,6 +362,27 @@ func WithTB(parentCtx TContext, tb TB) TContext {
350362
return tCtx
351363
}
352364

365+
// run implements the different Run methods. It's not an exported
366+
// method because tCtx.Run is more discoverable (same usage as
367+
// with normal Go).
368+
func run(tCtx TContext, name string, cb func(tCtx TContext)) bool {
369+
tCtx.Helper()
370+
switch tb := tCtx.TB().(type) {
371+
case interface {
372+
Run(string, func(t *testing.T)) bool
373+
}:
374+
return tb.Run(name, func(t *testing.T) { cb(WithTB(tCtx, t)) })
375+
case interface {
376+
Run(string, func(t *testing.B)) bool
377+
}:
378+
return tb.Run(name, func(b *testing.B) { cb(WithTB(tCtx, b)) })
379+
default:
380+
tCtx.Fatalf("Run not implemented, underlying %T does not support it", tCtx.TB())
381+
}
382+
383+
return false
384+
}
385+
353386
// WithContext constructs a new TContext with a different Context instance.
354387
// This can be used in callbacks which receive a Context, for example
355388
// from Gomega:
@@ -439,6 +472,10 @@ func cleanupCtx(tCtx TContext, cb func(TContext)) {
439472
})
440473
}
441474

475+
func (cCtx tContext) Run(name string, cb func(tCtx TContext)) bool {
476+
return run(cCtx, name, cb)
477+
}
478+
442479
func (tCtx tContext) Logger() klog.Logger {
443480
return klog.FromContext(tCtx)
444481
}

test/utils/ktesting/tcontext_test.go

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -123,6 +123,33 @@ func TestWithTB(t *testing.T) {
123123
assert.Equal(t, apiextensions, tCtx.APIExtensions(), "APIExtensions")
124124

125125
tCtx.Cancel("test is complete")
126+
<-tCtx.Done()
127+
})
128+
129+
if err := tCtx.Err(); err != nil {
130+
t.Errorf("parent TContext should not have been cancelled: %v", err)
131+
}
132+
}
133+
134+
func TestRun(t *testing.T) {
135+
tCtx := ktesting.Init(t)
136+
137+
cfg := new(rest.Config)
138+
mapper := new(restmapper.DeferredDiscoveryRESTMapper)
139+
client := clientset.New(nil)
140+
dynamic := dynamic.New(nil)
141+
apiextensions := apiextensions.New(nil)
142+
tCtx = ktesting.WithClients(tCtx, cfg, mapper, client, dynamic, apiextensions)
143+
144+
tCtx.Run("sub", func(tCtx ktesting.TContext) {
145+
assert.Equal(t, cfg, tCtx.RESTConfig(), "RESTConfig")
146+
assert.Equal(t, mapper, tCtx.RESTMapper(), "RESTMapper")
147+
assert.Equal(t, client, tCtx.Client(), "Client")
148+
assert.Equal(t, dynamic, tCtx.Dynamic(), "Dynamic")
149+
assert.Equal(t, apiextensions, tCtx.APIExtensions(), "APIExtensions")
150+
151+
tCtx.Cancel("test is complete")
152+
<-tCtx.Done()
126153
})
127154

128155
if err := tCtx.Err(); err != nil {

test/utils/ktesting/withcontext.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -102,6 +102,10 @@ func (wCtx withContext) ExpectNoError(err error, explain ...interface{}) {
102102
expectNoError(wCtx, err, explain...)
103103
}
104104

105+
func (cCtx withContext) Run(name string, cb func(tCtx TContext)) bool {
106+
return run(cCtx, name, cb)
107+
}
108+
105109
func (wCtx withContext) Logger() klog.Logger {
106110
return klog.FromContext(wCtx)
107111
}

0 commit comments

Comments
 (0)