
The e2e core framework and subpackages of e2e framework are defined. The subpackages can import the core framework, but the core framework should not import the subpackages. We've defined this dependency rule after circular depencency issue happened. This adds TODOs to understand what we should in this rule.
107 lines
3.6 KiB
Go
107 lines
3.6 KiB
Go
/*
|
|
Copyright 2019 The Kubernetes Authors.
|
|
|
|
Licensed under the Apache License, Version 2.0 (the "License");
|
|
you may not use this file except in compliance with the License.
|
|
You may obtain a copy of the License at
|
|
|
|
http://www.apache.org/licenses/LICENSE-2.0
|
|
|
|
Unless required by applicable law or agreed to in writing, software
|
|
distributed under the License is distributed on an "AS IS" BASIS,
|
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
See the License for the specific language governing permissions and
|
|
limitations under the License.
|
|
*/
|
|
|
|
package framework
|
|
|
|
import (
|
|
"fmt"
|
|
"regexp"
|
|
"runtime/debug"
|
|
"strings"
|
|
"time"
|
|
|
|
"github.com/onsi/ginkgo"
|
|
|
|
// TODO: Remove the following imports (ref: https://github.com/kubernetes/kubernetes/issues/81245)
|
|
"k8s.io/kubernetes/test/e2e/framework/ginkgowrapper"
|
|
)
|
|
|
|
func nowStamp() string {
|
|
return time.Now().Format(time.StampMilli)
|
|
}
|
|
|
|
func log(level string, format string, args ...interface{}) {
|
|
fmt.Fprintf(ginkgo.GinkgoWriter, nowStamp()+": "+level+": "+format+"\n", args...)
|
|
}
|
|
|
|
// Logf logs the info.
|
|
func Logf(format string, args ...interface{}) {
|
|
log("INFO", format, args...)
|
|
}
|
|
|
|
// Failf logs the fail info, including a stack trace.
|
|
func Failf(format string, args ...interface{}) {
|
|
FailfWithOffset(1, format, args...)
|
|
}
|
|
|
|
// FailfWithOffset calls "Fail" and logs the error with a stack trace that starts at "offset" levels above its caller
|
|
// (for example, for call chain f -> g -> FailfWithOffset(1, ...) error would be logged for "f").
|
|
func FailfWithOffset(offset int, format string, args ...interface{}) {
|
|
msg := fmt.Sprintf(format, args...)
|
|
skip := offset + 1
|
|
log("FAIL", "%s\n\nFull Stack Trace\n%s", msg, PrunedStack(skip))
|
|
ginkgowrapper.Fail(nowStamp()+": "+msg, skip)
|
|
}
|
|
|
|
// Fail is a replacement for ginkgo.Fail which logs the problem as it occurs
|
|
// together with a stack trace and then calls ginkgowrapper.Fail.
|
|
func Fail(msg string, callerSkip ...int) {
|
|
skip := 1
|
|
if len(callerSkip) > 0 {
|
|
skip += callerSkip[0]
|
|
}
|
|
log("FAIL", "%s\n\nFull Stack Trace\n%s", msg, PrunedStack(skip))
|
|
ginkgowrapper.Fail(nowStamp()+": "+msg, skip)
|
|
}
|
|
|
|
var codeFilterRE = regexp.MustCompile(`/github.com/onsi/ginkgo/`)
|
|
|
|
// PrunedStack is a wrapper around debug.Stack() that removes information
|
|
// about the current goroutine and optionally skips some of the initial stack entries.
|
|
// With skip == 0, the returned stack will start with the caller of PruneStack.
|
|
// From the remaining entries it automatically filters out useless ones like
|
|
// entries coming from Ginkgo.
|
|
//
|
|
// This is a modified copy of PruneStack in https://github.com/onsi/ginkgo/blob/f90f37d87fa6b1dd9625e2b1e83c23ffae3de228/internal/codelocation/code_location.go#L25:
|
|
// - simplified API and thus renamed (calls debug.Stack() instead of taking a parameter)
|
|
// - source code filtering updated to be specific to Kubernetes
|
|
func PrunedStack(skip int) string {
|
|
fullStackTrace := string(debug.Stack())
|
|
stack := strings.Split(fullStackTrace, "\n")
|
|
// Ensure that the even entries are the method names and the
|
|
// the odd entries the source code information.
|
|
if len(stack) > 0 && strings.HasPrefix(stack[0], "goroutine ") {
|
|
// Ignore "goroutine 29 [running]:" line.
|
|
stack = stack[1:]
|
|
}
|
|
// The "+2" is for skipping over:
|
|
// - runtime/debug.Stack()
|
|
// - PrunedStack()
|
|
skip += 2
|
|
if len(stack) > 2*skip {
|
|
stack = stack[2*skip:]
|
|
}
|
|
prunedStack := []string{}
|
|
for i := 0; i < len(stack)/2; i++ {
|
|
// We filter out based on the source code file name.
|
|
if !codeFilterRE.Match([]byte(stack[i*2+1])) {
|
|
prunedStack = append(prunedStack, stack[i*2])
|
|
prunedStack = append(prunedStack, stack[i*2+1])
|
|
}
|
|
}
|
|
return strings.Join(prunedStack, "\n")
|
|
}
|