From 20498fd65d27952c7844e0d64ecb83a51e60c0d0 Mon Sep 17 00:00:00 2001 From: Dave Chen Date: Fri, 15 Apr 2022 11:45:49 +0800 Subject: [PATCH] Generate conformance test spec with `offset` decorator `FullStackTrace` is not available in v2 if no exception found with test execution. The change is needed for conformance test's spec validation. pls see: https://github.com/onsi/ginkgo/issues/960 for details. Signed-off-by: Dave Chen --- test/conformance/walk.go | 96 +++++++++++---------------------- test/e2e/framework/framework.go | 2 +- 2 files changed, 31 insertions(+), 67 deletions(-) diff --git a/test/conformance/walk.go b/test/conformance/walk.go index 58d41336558..2b18626d234 100644 --- a/test/conformance/walk.go +++ b/test/conformance/walk.go @@ -28,7 +28,6 @@ import ( "os" "regexp" "sort" - "strconv" "strings" "text/template" @@ -70,8 +69,6 @@ var ( ) type frame struct { - Function string - // File and Line are the file name and line number of the // location in this frame. For non-leaf frames, this will be // the location of a call. These may be the empty string and @@ -97,7 +94,7 @@ func main() { dec := json.NewDecoder(f) testInfos := []*ConformanceData{} for { - var spec *types.SpecSummary + var spec *types.SpecReport if err := dec.Decode(&spec); err == io.EOF { break } else if err != nil { @@ -119,39 +116,35 @@ func main() { saveAllTestInfo(testInfos) } -func isConformance(spec *types.SpecSummary) bool { +func isConformance(spec *types.SpecReport) bool { return strings.Contains(getTestName(spec), "[Conformance]") } -func getTestInfo(spec *types.SpecSummary) *ConformanceData { +func getTestInfo(spec *types.SpecReport) *ConformanceData { var c *ConformanceData var err error // The key to this working is that we don't need to parse every file or walk - // every componentCodeLocation. The last componentCodeLocation is going to typically start - // with the ConformanceIt(...) call and the next call in that callstack will be the - // ast.Node which is attached to the comment that we want. - for i := len(spec.ComponentCodeLocations) - 1; i > 0; i-- { - fullstacktrace := spec.ComponentCodeLocations[i].FullStackTrace - c, err = getConformanceDataFromStackTrace(fullstacktrace) - if err != nil { - log.Printf("Error looking for conformance data: %v", err) - } - if c != nil { - break - } + // every types.CodeLocation. The LeafNodeLocation is going to be file:line which + // attached to the comment that we want. + leafNodeLocation := spec.LeafNodeLocation + frame := frame{ + File: leafNodeLocation.FileName, + Line: leafNodeLocation.LineNumber, + } + c, err = getConformanceData(frame) + if err != nil { + log.Printf("Error looking for conformance data: %v", err) } - if c == nil { log.Printf("Did not find test info for spec: %#v\n", getTestName(spec)) return nil } - c.CodeName = getTestName(spec) return c } -func getTestName(spec *types.SpecSummary) string { - return strings.Join(spec.ComponentTexts[1:], " ") +func getTestName(spec *types.SpecReport) string { + return strings.Join(spec.ContainerHierarchyTexts[0:], " ") + " " + spec.LeafNodeText } func saveAllTestInfo(dataSet []*ConformanceData) { @@ -185,56 +178,27 @@ func saveAllTestInfo(dataSet []*ConformanceData) { fmt.Println(string(b)) } -func getConformanceDataFromStackTrace(fullstackstrace string) (*ConformanceData, error) { - // The full stacktrace to parse from ginkgo is of the form: - // k8s.io/kubernetes/test/e2e/storage/utils.SIGDescribe(0x51f4c4f, 0xf, 0x53a0dd8, 0xc000ab6e01)\n\ttest/e2e/storage/utils/framework.go:23 +0x75\n ... ... - // So we need to split it into lines, remove whitespace, and then grab the files/lines. - stack := strings.Replace(fullstackstrace, "\t", "", -1) - calls := strings.Split(stack, "\n") - frames := []frame{} - i := 0 - for i < len(calls) { - fileLine := strings.Split(calls[i+1], " ") - lineinfo := strings.Split(fileLine[0], ":") - line, err := strconv.Atoi(lineinfo[1]) - if err != nil { - panic(err) - } - frames = append(frames, frame{ - Function: calls[i], - File: lineinfo[0], - Line: line, - }) - i += 2 - } - +func getConformanceData(targetFrame frame) (*ConformanceData, error) { // filenames are in one of two special GOPATHs depending on if they were // built dockerized or with the host go // we want to trim this prefix to produce portable relative paths k8sSRC := *k8sPath + "/_output/local/go/src/k8s.io/kubernetes/" - for i := range frames { - trimmedFile := strings.TrimPrefix(frames[i].File, k8sSRC) - trimmedFile = strings.TrimPrefix(trimmedFile, "/go/src/k8s.io/kubernetes/_output/dockerized/go/src/k8s.io/kubernetes/") - frames[i].File = trimmedFile + trimmedFile := strings.TrimPrefix(targetFrame.File, k8sSRC) + trimmedFile = strings.TrimPrefix(trimmedFile, "/go/src/k8s.io/kubernetes/_output/dockerized/go/src/k8s.io/kubernetes/") + targetFrame.File = trimmedFile + + freader, err := os.Open(targetFrame.File) + if err != nil { + return nil, err } + defer freader.Close() - for _, curFrame := range frames { - if _, seen := seenLines[fmt.Sprintf("%v:%v", curFrame.File, curFrame.Line)]; seen { - continue - } - - freader, err := os.Open(curFrame.File) - if err != nil { - return nil, err - } - defer freader.Close() - cd, err := scanFileForFrame(curFrame.File, freader, curFrame) - if err != nil { - return nil, err - } - if cd != nil { - return cd, nil - } + cd, err := scanFileForFrame(targetFrame.File, freader, targetFrame) + if err != nil { + return nil, err + } + if cd != nil { + return cd, nil } return nil, nil diff --git a/test/e2e/framework/framework.go b/test/e2e/framework/framework.go index 50d84d8cc33..559f384b2d5 100644 --- a/test/e2e/framework/framework.go +++ b/test/e2e/framework/framework.go @@ -644,7 +644,7 @@ func (kc *KubeConfig) FindCluster(name string) *KubeCluster { // ConformanceIt is wrapper function for ginkgo It. Adds "[Conformance]" tag and makes static analysis easier. func ConformanceIt(text string, body interface{}) bool { - return ginkgo.It(text+" [Conformance]", body) + return ginkgo.It(text+" [Conformance]", ginkgo.Offset(1), body) } // PodStateVerification represents a verification of pod state.