Skip to content

Commit 338fe7a

Browse files
committed
e2e framework: validate test definitions
This checks that the With* label functions are used instead of the previous inline tags. To catch strings passed to Ginkgo directly instead of the framework wrapper functions, the final test specs are checked.
1 parent f2cfbf4 commit 338fe7a

File tree

2 files changed

+79
-0
lines changed

2 files changed

+79
-0
lines changed

test/e2e/framework/ginkgowrapper.go

Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -246,6 +246,84 @@ func registerInSuite(ginkgoCall func(string, ...interface{}) bool, args []interf
246246
return ginkgoCall(text, ginkgoArgs...)
247247
}
248248

249+
var (
250+
tagRe = regexp.MustCompile(`\[.*?\]`)
251+
deprecatedTags = sets.New("Conformance", "NodeConformance", "Disruptive", "Serial", "Slow")
252+
deprecatedTagPrefixes = sets.New("Environment", "Feature", "NodeFeature", "FeatureGate")
253+
deprecatedStability = sets.New("Alpha", "Beta")
254+
)
255+
256+
// validateSpecs checks that the test specs were registered as intended.
257+
func validateSpecs(specs types.SpecReports) {
258+
checked := sets.New[call]()
259+
260+
for _, spec := range specs {
261+
for i, text := range spec.ContainerHierarchyTexts {
262+
c := call{
263+
text: text,
264+
location: spec.ContainerHierarchyLocations[i],
265+
}
266+
if checked.Has(c) {
267+
// No need to check the same container more than once.
268+
continue
269+
}
270+
checked.Insert(c)
271+
validateText(c.location, text, spec.ContainerHierarchyLabels[i])
272+
}
273+
c := call{
274+
text: spec.LeafNodeText,
275+
location: spec.LeafNodeLocation,
276+
}
277+
if !checked.Has(c) {
278+
validateText(spec.LeafNodeLocation, spec.LeafNodeText, spec.LeafNodeLabels)
279+
checked.Insert(c)
280+
}
281+
}
282+
}
283+
284+
// call acts as (mostly) unique identifier for a container node call like
285+
// Describe or Context. It's not perfect because theoretically a line might
286+
// have multiple calls with the same text, but that isn't a problem in
287+
// practice.
288+
type call struct {
289+
text string
290+
location types.CodeLocation
291+
}
292+
293+
// validateText checks for some known tags that should not be added through the
294+
// plain text strings anymore. Eventually, all such tags should get replaced
295+
// with the new APIs.
296+
func validateText(location types.CodeLocation, text string, labels []string) {
297+
for _, tag := range tagRe.FindAllString(text, -1) {
298+
if tag == "[]" {
299+
recordTextBug(location, "[] in plain text is invalid")
300+
continue
301+
}
302+
// Strip square brackets.
303+
tag = tag[1 : len(tag)-1]
304+
if slices.Contains(labels, tag) {
305+
// Okay, was also set as label.
306+
continue
307+
}
308+
if deprecatedTags.Has(tag) {
309+
recordTextBug(location, fmt.Sprintf("[%s] in plain text is deprecated and must be added through With%s instead", tag, tag))
310+
}
311+
if deprecatedStability.Has(tag) {
312+
recordTextBug(location, fmt.Sprintf("[%s] in plain text is deprecated and must be added by defining the feature gate through WithFeatureGate instead", tag))
313+
}
314+
if index := strings.Index(tag, ":"); index > 0 {
315+
prefix := tag[:index]
316+
if deprecatedTagPrefixes.Has(prefix) {
317+
recordTextBug(location, fmt.Sprintf("[%s] in plain text is deprecated and must be added through With%s(%s) instead", tag, prefix, tag[index+1:]))
318+
}
319+
}
320+
}
321+
}
322+
323+
func recordTextBug(location types.CodeLocation, message string) {
324+
RecordBug(Bug{FileName: location.FileName, LineNumber: location.LineNumber, Message: message})
325+
}
326+
249327
// WithEnvironment specifies that a certain test or group of tests only works
250328
// with a feature available. The return value must be passed as additional
251329
// argument to [framework.It], [framework.Describe], [framework.Context].

test/e2e/framework/test_context.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -517,6 +517,7 @@ func AfterReadingAllFlags(t *TestContextType) {
517517

518518
// ginkgo.PreviewSpecs will expand all nodes and thus may find new bugs.
519519
report := ginkgo.PreviewSpecs("Kubernetes e2e test statistics")
520+
validateSpecs(report.SpecReports)
520521
if err := FormatBugs(); CheckForBugs && err != nil {
521522
// Refuse to do anything if the E2E suite is buggy.
522523
fmt.Fprint(Output, "ERROR: E2E suite initialization was faulty, these errors must be fixed:")

0 commit comments

Comments
 (0)