Files
virtual-kubelet/internal/test/suite/suite.go
Ernest Wong f10a16aed7 Importable End-To-End Test Suite (#758)
* Rename VK to chewong for development purpose

* Rename basic_test.go to basic.go

* Add e2e.go and suite.go

* Disable tests in node.go

* End to end tests are now importable as a testing suite

* Remove 'test' from test files

* Add documentations

* Rename chewong back to virtual-kubelet

* Change 'Testing Suite' to 'Test Suite'

* Add the ability to skip certain testss

* Add unit tests for suite.go

* Add README.md for importable e2e test suite

* VK implementation has to be based on VK v1.0.0

* Stricter checks on validating test functions

* Move certain files back to internal folder

* Add WatchTimeout as a config field

* Add slight modifications
2019-09-04 22:25:43 +01:00

86 lines
2.2 KiB
Go

package suite
import (
"reflect"
"runtime/debug"
"strings"
"testing"
)
// TestFunc defines the test function in a test case
type TestFunc func(*testing.T)
// SetUpFunc sets up provider-specific resource in the test suite
type SetUpFunc func() error
// TeardownFunc tears down provider-specific resources from the test suite
type TeardownFunc func() error
// ShouldSkipTestFunc determines whether the test suite should skip certain tests
type ShouldSkipTestFunc func(string) bool
// TestSuite contains methods that defines the lifecycle of a test suite
type TestSuite interface {
Setup()
Teardown()
}
// TestSkipper allows providers to skip certain tests
type TestSkipper interface {
ShouldSkipTest(string) bool
}
type testCase struct {
name string
f TestFunc
}
// Run runs tests registered in the test suite
func Run(t *testing.T, ts TestSuite) {
defer failOnPanic(t)
ts.Setup()
defer ts.Teardown()
// The implementation below is based on https://github.com/stretchr/testify
testFinder := reflect.TypeOf(ts)
tests := []testCase{}
for i := 0; i < testFinder.NumMethod(); i++ {
method := testFinder.Method(i)
if !isValidTestFunc(method) {
continue
}
test := testCase{
name: method.Name,
f: func(t *testing.T) {
defer failOnPanic(t)
if tSkipper, ok := ts.(TestSkipper); ok && tSkipper.ShouldSkipTest(method.Name) {
t.Skipf("Skipped due to shouldSkipTest()")
}
method.Func.Call([]reflect.Value{reflect.ValueOf(ts), reflect.ValueOf(t)})
},
}
tests = append(tests, test)
}
for _, test := range tests {
t.Run(test.name, test.f)
}
}
// failOnPanic recovers panic occurred in the test suite and marks the test / test suite as failed
func failOnPanic(t *testing.T) {
if r := recover(); r != nil {
t.Fatalf("%v\n%s", r, debug.Stack())
}
}
// isValidTestFunc determines whether or not a given method is a valid test function
func isValidTestFunc(method reflect.Method) bool {
return strings.HasPrefix(method.Name, "Test") && // Test function name must start with "Test",
method.Type.NumIn() == 2 && // the number of function input should be 2 (*TestSuite ts and t *testing.T),
method.Type.In(1) == reflect.TypeOf(&testing.T{}) &&
method.Type.NumOut() == 0 // and the number of function output should be 0
}