浏览代码

internal/test/suite

Signed-off-by: Tibor Vass <tibor@docker.com>
Tibor Vass 6 年之前
父节点
当前提交
fd0ed80ff2
共有 3 个文件被更改,包括 150 次插入0 次删除
  1. 33 0
      internal/test/suite/interfaces.go
  2. 96 0
      internal/test/suite/suite.go
  3. 21 0
      internal/test/suite/testify.LICENSE

+ 33 - 0
internal/test/suite/interfaces.go

@@ -0,0 +1,33 @@
+package suite
+
+import "testing"
+
+// SetupAllSuite has a SetupSuite method, which will run before the
+// tests in the suite are run.
+type SetupAllSuite interface {
+	SetUpSuite(t *testing.T)
+}
+
+// SetupTestSuite has a SetupTest method, which will run before each
+// test in the suite.
+type SetupTestSuite interface {
+	SetUpTest(t *testing.T)
+}
+
+// TearDownAllSuite has a TearDownSuite method, which will run after
+// all the tests in the suite have been run.
+type TearDownAllSuite interface {
+	TearDownSuite(t *testing.T)
+}
+
+// TearDownTestSuite has a TearDownTest method, which will run after
+// each test in the suite.
+type TearDownTestSuite interface {
+	TearDownTest(t *testing.T)
+}
+
+// TimeoutTestSuite has a OnTimeout method, which will run after
+// a single test times out after a period specified by -timeout flag.
+type TimeoutTestSuite interface {
+	OnTimeout()
+}

+ 96 - 0
internal/test/suite/suite.go

@@ -0,0 +1,96 @@
+// Package suite is a simplified version of testify's suite package which has unnecessary dependencies.
+// Please remove this package whenever possible.
+package suite
+
+import (
+	"flag"
+	"fmt"
+	"reflect"
+	"runtime/debug"
+	"strings"
+	"testing"
+	"time"
+)
+
+// TimeoutFlag is the flag to set a per-test timeout when running tests. Defaults to `-timeout`.
+var TimeoutFlag = flag.Duration("timeout", 0, "per-test panic after duration `d` (default 0, timeout disabled)")
+
+var typTestingT = reflect.TypeOf(new(testing.T))
+
+// Run takes a testing suite and runs all of the tests attached to it.
+func Run(t *testing.T, suite interface{}) {
+	defer failOnPanic(t)
+
+	suiteSetupDone := false
+
+	methodFinder := reflect.TypeOf(suite)
+	suiteName := methodFinder.Elem().Name()
+	for index := 0; index < methodFinder.NumMethod(); index++ {
+		method := methodFinder.Method(index)
+		if !methodFilter(method.Name, method.Type) {
+			continue
+		}
+		if !suiteSetupDone {
+			if setupAllSuite, ok := suite.(SetupAllSuite); ok {
+				setupAllSuite.SetUpSuite(t)
+			}
+			defer func() {
+				if tearDownAllSuite, ok := suite.(TearDownAllSuite); ok {
+					tearDownAllSuite.TearDownSuite(t)
+				}
+			}()
+			suiteSetupDone = true
+		}
+		t.Run(suiteName+"/"+method.Name, func(t *testing.T) {
+			defer failOnPanic(t)
+
+			if setupTestSuite, ok := suite.(SetupTestSuite); ok {
+				setupTestSuite.SetUpTest(t)
+			}
+			defer func() {
+				if tearDownTestSuite, ok := suite.(TearDownTestSuite); ok {
+					tearDownTestSuite.TearDownTest(t)
+				}
+			}()
+
+			var timeout <-chan time.Time
+			if *TimeoutFlag > 0 {
+				timeout = time.After(*TimeoutFlag)
+			}
+			panicCh := make(chan error)
+			go func() {
+				defer func() {
+					if r := recover(); r != nil {
+						panicCh <- fmt.Errorf("test panicked: %v\n%s", r, debug.Stack())
+					} else {
+						close(panicCh)
+					}
+				}()
+				method.Func.Call([]reflect.Value{reflect.ValueOf(suite), reflect.ValueOf(t)})
+			}()
+			select {
+			case err := <-panicCh:
+				if err != nil {
+					t.Fatal(err.Error())
+				}
+			case <-timeout:
+				if timeoutSuite, ok := suite.(TimeoutTestSuite); ok {
+					timeoutSuite.OnTimeout()
+				}
+				t.Fatalf("timeout: test timed out after %s since start of test", *TimeoutFlag)
+			}
+		})
+	}
+}
+
+func failOnPanic(t *testing.T) {
+	r := recover()
+	if r != nil {
+		t.Errorf("test suite panicked: %v\n%s", r, debug.Stack())
+		t.FailNow()
+	}
+}
+
+func methodFilter(name string, typ reflect.Type) bool {
+	return strings.HasPrefix(name, "Test") && typ.NumIn() == 2 && typ.In(1) == typTestingT // 2 params: method receiver and *testing.T
+}

+ 21 - 0
internal/test/suite/testify.LICENSE

@@ -0,0 +1,21 @@
+MIT License
+
+Copyright (c) 2012-2018 Mat Ryer and Tyler Bunnell
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.