From 36dc864314ba0a9d5c71afef15c0cd9cf3aac678 Mon Sep 17 00:00:00 2001 From: Yuedong Wu Date: Wed, 21 Aug 2024 18:26:38 +0800 Subject: [PATCH 1/2] bump ginkgo/v2 to v2.19.0 Signed-off-by: Yuedong Wu --- go.mod | 2 +- go.sum | 4 +- vendor/github.com/onsi/ginkgo/v2/CHANGELOG.md | 25 ++ .../github.com/onsi/ginkgo/v2/CONTRIBUTING.md | 10 +- vendor/github.com/onsi/ginkgo/v2/Makefile | 11 + .../ginkgo/v2/ginkgo/watch/package_hash.go | 9 + .../onsi/ginkgo/v2/internal/suite.go | 7 +- .../ginkgo/v2/reporters/default_reporter.go | 10 +- .../onsi/ginkgo/v2/reporters/junit_report.go | 1 + vendor/github.com/onsi/ginkgo/v2/table_dsl.go | 8 +- .../github.com/onsi/ginkgo/v2/types/config.go | 9 + .../onsi/ginkgo/v2/types/label_filter.go | 229 +++++++++++++++++- .../onsi/ginkgo/v2/types/version.go | 2 +- vendor/modules.txt | 2 +- 14 files changed, 314 insertions(+), 15 deletions(-) create mode 100644 vendor/github.com/onsi/ginkgo/v2/Makefile diff --git a/go.mod b/go.mod index fd40eeed9..cabf7113d 100644 --- a/go.mod +++ b/go.mod @@ -11,7 +11,7 @@ require ( github.com/google/go-cmp v0.6.0 github.com/google/go-jsonnet v0.17.0 github.com/mogensen/kubernetes-split-yaml v0.3.0 - github.com/onsi/ginkgo/v2 v2.17.2 + github.com/onsi/ginkgo/v2 v2.19.0 github.com/onsi/gomega v1.33.1 github.com/openshift/api v0.0.0-20240812094746-86145edb40cf github.com/openshift/build-machinery-go v0.0.0-20240419090851-af9c868bcf52 diff --git a/go.sum b/go.sum index dcd3e053d..722e997b1 100644 --- a/go.sum +++ b/go.sum @@ -500,8 +500,8 @@ github.com/olekukonko/tablewriter v0.0.5 h1:P2Ga83D34wi1o9J6Wh1mRuqd4mF/x/lgBS7N github.com/olekukonko/tablewriter v0.0.5/go.mod h1:hPp6KlRPjbx+hW8ykQs1w3UBbZlj6HuIJcUGPhkA7kY= github.com/onsi/ginkgo v1.16.5 h1:8xi0RTUf59SOSfEtZMvwTvXYMzG4gV23XVHOZiXNtnE= github.com/onsi/ginkgo v1.16.5/go.mod h1:+E8gABHa3K6zRBolWtd+ROzc/U5bkGt0FwiG042wbpU= -github.com/onsi/ginkgo/v2 v2.17.2 h1:7eMhcy3GimbsA3hEnVKdw/PQM9XN9krpKVXsZdph0/g= -github.com/onsi/ginkgo/v2 v2.17.2/go.mod h1:nP2DPOQoNsQmsVyv5rDA8JkXQoCs6goXIvr/PRJ1eCc= +github.com/onsi/ginkgo/v2 v2.19.0 h1:9Cnnf7UHo57Hy3k6/m5k3dRfGTMXGvxhHFvkDTCTpvA= +github.com/onsi/ginkgo/v2 v2.19.0/go.mod h1:rlwLi9PilAFJ8jCg9UE1QP6VBpd6/xj3SRC0d6TU0To= github.com/onsi/gomega v1.33.1 h1:dsYjIxxSR755MDmKVsaFQTE22ChNBcuuTWgkUDSubOk= github.com/onsi/gomega v1.33.1/go.mod h1:U4R44UsT+9eLIaYRB2a5qajjtQYn0hauxvRm16AVYg0= github.com/openshift/api v0.0.0-20240812094746-86145edb40cf h1:MB0TCPkvxj80Ucj7w6xArL4StOrQBMN7AvGYtsP5t2M= diff --git a/vendor/github.com/onsi/ginkgo/v2/CHANGELOG.md b/vendor/github.com/onsi/ginkgo/v2/CHANGELOG.md index 0a8949799..76577dc78 100644 --- a/vendor/github.com/onsi/ginkgo/v2/CHANGELOG.md +++ b/vendor/github.com/onsi/ginkgo/v2/CHANGELOG.md @@ -1,3 +1,28 @@ +## 2.19.0 + +### Features + +[Label Sets](https://onsi.github.io/ginkgo/#label-sets) allow for more expressive and flexible label filtering. + +## 2.18.0 + +### Features +- Add --slience-skips and --force-newlines [f010b65] +- fail when no tests were run and --fail-on-empty was set [d80eebe] + +### Fixes +- Fix table entry context edge case [42013d6] + +### Maintenance +- Bump golang.org/x/tools from 0.20.0 to 0.21.0 (#1406) [fcf1fd7] +- Bump github.com/onsi/gomega from 1.33.0 to 1.33.1 (#1399) [8bb14fd] +- Bump golang.org/x/net from 0.24.0 to 0.25.0 (#1407) [04bfad7] + +## 2.17.3 + +### Fixes +`ginkgo watch` now ignores hidden files [bde6e00] + ## 2.17.2 ### Fixes diff --git a/vendor/github.com/onsi/ginkgo/v2/CONTRIBUTING.md b/vendor/github.com/onsi/ginkgo/v2/CONTRIBUTING.md index 1da92fe7e..80de566a5 100644 --- a/vendor/github.com/onsi/ginkgo/v2/CONTRIBUTING.md +++ b/vendor/github.com/onsi/ginkgo/v2/CONTRIBUTING.md @@ -6,8 +6,10 @@ Your contributions to Ginkgo are essential for its long-term maintenance and imp - Ensure adequate test coverage: - When adding to the Ginkgo library, add unit and/or integration tests (under the `integration` folder). - When adding to the Ginkgo CLI, note that there are very few unit tests. Please add an integration test. -- Make sure all the tests succeed via `ginkgo -r -p` -- Vet your changes via `go vet ./...` -- Update the documentation. Ginkgo uses `godoc` comments and documentation in `docs/index.md`. You can run `bundle exec jekyll serve` in the `docs` directory to preview your changes. +- Run `make` or: + - Install ginkgo locally via `go install ./...` + - Make sure all the tests succeed via `ginkgo -r -p` + - Vet your changes via `go vet ./...` +- Update the documentation. Ginkgo uses `godoc` comments and documentation in `docs/index.md`. You can run `bundle && bundle exec jekyll serve` in the `docs` directory to preview your changes. -Thanks for supporting Ginkgo! \ No newline at end of file +Thanks for supporting Ginkgo! diff --git a/vendor/github.com/onsi/ginkgo/v2/Makefile b/vendor/github.com/onsi/ginkgo/v2/Makefile new file mode 100644 index 000000000..cb099aff9 --- /dev/null +++ b/vendor/github.com/onsi/ginkgo/v2/Makefile @@ -0,0 +1,11 @@ +# default task since it's first +.PHONY: all +all: vet test + +.PHONY: test +test: + go run github.com/onsi/ginkgo/v2/ginkgo -r -p + +.PHONY: vet +vet: + go vet ./... diff --git a/vendor/github.com/onsi/ginkgo/v2/ginkgo/watch/package_hash.go b/vendor/github.com/onsi/ginkgo/v2/ginkgo/watch/package_hash.go index 17d052bdc..0e6ae1f29 100644 --- a/vendor/github.com/onsi/ginkgo/v2/ginkgo/watch/package_hash.go +++ b/vendor/github.com/onsi/ginkgo/v2/ginkgo/watch/package_hash.go @@ -4,6 +4,7 @@ import ( "fmt" "os" "regexp" + "strings" "time" ) @@ -79,6 +80,10 @@ func (p *PackageHash) computeHashes() (codeHash string, codeModifiedTime time.Ti continue } + if isHiddenFile(info) { + continue + } + if goTestRegExp.MatchString(info.Name()) { testHash += p.hashForFileInfo(info) if info.ModTime().After(testModifiedTime) { @@ -103,6 +108,10 @@ func (p *PackageHash) computeHashes() (codeHash string, codeModifiedTime time.Ti return } +func isHiddenFile(info os.FileInfo) bool { + return strings.HasPrefix(info.Name(), ".") || strings.HasPrefix(info.Name(), "_") +} + func (p *PackageHash) hashForFileInfo(info os.FileInfo) string { return fmt.Sprintf("%s_%d_%d", info.Name(), info.Size(), info.ModTime().UnixNano()) } diff --git a/vendor/github.com/onsi/ginkgo/v2/internal/suite.go b/vendor/github.com/onsi/ginkgo/v2/internal/suite.go index a994ee3d6..a3c9e6bf1 100644 --- a/vendor/github.com/onsi/ginkgo/v2/internal/suite.go +++ b/vendor/github.com/onsi/ginkgo/v2/internal/suite.go @@ -489,10 +489,15 @@ func (suite *Suite) runSpecs(description string, suiteLabels Labels, suitePath s newGroup(suite).run(specs.AtIndices(groupedSpecIndices[groupedSpecIdx])) } - if specs.HasAnySpecsMarkedPending() && suite.config.FailOnPending { + if suite.config.FailOnPending && specs.HasAnySpecsMarkedPending() { suite.report.SpecialSuiteFailureReasons = append(suite.report.SpecialSuiteFailureReasons, "Detected pending specs and --fail-on-pending is set") suite.report.SuiteSucceeded = false } + + if suite.config.FailOnEmpty && specs.CountWithoutSkip() == 0 { + suite.report.SpecialSuiteFailureReasons = append(suite.report.SpecialSuiteFailureReasons, "Detected no specs ran and --fail-on-empty is set") + suite.report.SuiteSucceeded = false + } } if ranBeforeSuite { diff --git a/vendor/github.com/onsi/ginkgo/v2/reporters/default_reporter.go b/vendor/github.com/onsi/ginkgo/v2/reporters/default_reporter.go index 980973370..480730486 100644 --- a/vendor/github.com/onsi/ginkgo/v2/reporters/default_reporter.go +++ b/vendor/github.com/onsi/ginkgo/v2/reporters/default_reporter.go @@ -202,6 +202,11 @@ func (r *DefaultReporter) DidRun(report types.SpecReport) { v := r.conf.Verbosity() inParallel := report.RunningInParallel + //should we completely omit this spec? + if report.State.Is(types.SpecStateSkipped) && r.conf.SilenceSkips { + return + } + header := r.specDenoter if report.LeafNodeType.Is(types.NodeTypesForSuiteLevelNodes) { header = fmt.Sprintf("[%s]", report.LeafNodeType) @@ -278,9 +283,12 @@ func (r *DefaultReporter) DidRun(report types.SpecReport) { } } - // If we have no content to show, jsut emit the header and return + // If we have no content to show, just emit the header and return if !reportHasContent { r.emit(r.f(highlightColor + header + "{{/}}")) + if r.conf.ForceNewlines { + r.emit("\n") + } return } diff --git a/vendor/github.com/onsi/ginkgo/v2/reporters/junit_report.go b/vendor/github.com/onsi/ginkgo/v2/reporters/junit_report.go index 2a3215b51..562e0f62b 100644 --- a/vendor/github.com/onsi/ginkgo/v2/reporters/junit_report.go +++ b/vendor/github.com/onsi/ginkgo/v2/reporters/junit_report.go @@ -177,6 +177,7 @@ func GenerateJUnitReportWithConfig(report types.Report, dst string, config Junit {"FocusFiles", strings.Join(report.SuiteConfig.FocusFiles, ";")}, {"SkipFiles", strings.Join(report.SuiteConfig.SkipFiles, ";")}, {"FailOnPending", fmt.Sprintf("%t", report.SuiteConfig.FailOnPending)}, + {"FailOnEmpty", fmt.Sprintf("%t", report.SuiteConfig.FailOnEmpty)}, {"FailFast", fmt.Sprintf("%t", report.SuiteConfig.FailFast)}, {"FlakeAttempts", fmt.Sprintf("%d", report.SuiteConfig.FlakeAttempts)}, {"DryRun", fmt.Sprintf("%t", report.SuiteConfig.DryRun)}, diff --git a/vendor/github.com/onsi/ginkgo/v2/table_dsl.go b/vendor/github.com/onsi/ginkgo/v2/table_dsl.go index a3aef821b..c7de7a8be 100644 --- a/vendor/github.com/onsi/ginkgo/v2/table_dsl.go +++ b/vendor/github.com/onsi/ginkgo/v2/table_dsl.go @@ -269,11 +269,15 @@ func generateTable(description string, isSubtree bool, args ...interface{}) { internalNodeArgs = append(internalNodeArgs, entry.decorations...) hasContext := false - if internalBodyType.NumIn() > 0. { + if internalBodyType.NumIn() > 0 { if internalBodyType.In(0).Implements(specContextType) { hasContext = true - } else if internalBodyType.In(0).Implements(contextType) && (len(entry.parameters) == 0 || !reflect.TypeOf(entry.parameters[0]).Implements(contextType)) { + } else if internalBodyType.In(0).Implements(contextType) { hasContext = true + if len(entry.parameters) > 0 && reflect.TypeOf(entry.parameters[0]) != nil && reflect.TypeOf(entry.parameters[0]).Implements(contextType) { + // we allow you to pass in a non-nil context + hasContext = false + } } } diff --git a/vendor/github.com/onsi/ginkgo/v2/types/config.go b/vendor/github.com/onsi/ginkgo/v2/types/config.go index cef273ee1..66463cf5e 100644 --- a/vendor/github.com/onsi/ginkgo/v2/types/config.go +++ b/vendor/github.com/onsi/ginkgo/v2/types/config.go @@ -25,6 +25,7 @@ type SuiteConfig struct { SkipFiles []string LabelFilter string FailOnPending bool + FailOnEmpty bool FailFast bool FlakeAttempts int MustPassRepeatedly int @@ -90,6 +91,8 @@ type ReporterConfig struct { FullTrace bool ShowNodeEvents bool GithubOutput bool + SilenceSkips bool + ForceNewlines bool JSONReport string JUnitReport string @@ -275,6 +278,8 @@ var SuiteConfigFlags = GinkgoFlags{ Usage: "If set, ginkgo will stop running a test suite after a failure occurs."}, {KeyPath: "S.FlakeAttempts", Name: "flake-attempts", SectionKey: "failure", UsageDefaultValue: "0 - failed tests are not retried", DeprecatedName: "flakeAttempts", DeprecatedDocLink: "changed-command-line-flags", Usage: "Make up to this many attempts to run each spec. If any of the attempts succeed, the suite will not be failed."}, + {KeyPath: "S.FailOnEmpty", Name: "fail-on-empty", SectionKey: "failure", + Usage: "If set, ginkgo will mark the test suite as failed if no specs are run."}, {KeyPath: "S.DryRun", Name: "dry-run", SectionKey: "debug", DeprecatedName: "dryRun", DeprecatedDocLink: "changed-command-line-flags", Usage: "If set, ginkgo will walk the test hierarchy without actually running anything. Best paired with -v."}, @@ -334,6 +339,10 @@ var ReporterConfigFlags = GinkgoFlags{ Usage: "If set, default reporter prints node > Enter and < Exit events when specs fail"}, {KeyPath: "R.GithubOutput", Name: "github-output", SectionKey: "output", Usage: "If set, default reporter prints easier to manage output in Github Actions."}, + {KeyPath: "R.SilenceSkips", Name: "silence-skips", SectionKey: "output", + Usage: "If set, default reporter will not print out skipped tests."}, + {KeyPath: "R.ForceNewlines", Name: "force-newlines", SectionKey: "output", + Usage: "If set, default reporter will ensure a newline appears after each test."}, {KeyPath: "R.JSONReport", Name: "json-report", UsageArgument: "filename.json", SectionKey: "output", Usage: "If set, Ginkgo will generate a JSON-formatted test report at the specified location."}, diff --git a/vendor/github.com/onsi/ginkgo/v2/types/label_filter.go b/vendor/github.com/onsi/ginkgo/v2/types/label_filter.go index b0d3b651e..7fdc8aa23 100644 --- a/vendor/github.com/onsi/ginkgo/v2/types/label_filter.go +++ b/vendor/github.com/onsi/ginkgo/v2/types/label_filter.go @@ -45,6 +45,83 @@ func orAction(a, b LabelFilter) LabelFilter { return func(labels []string) bool { return a(labels) || b(labels) } } +func labelSetFor(key string, labels []string) map[string]bool { + key = strings.ToLower(strings.TrimSpace(key)) + out := map[string]bool{} + for _, label := range labels { + components := strings.SplitN(label, ":", 2) + if len(components) < 2 { + continue + } + if key == strings.ToLower(strings.TrimSpace(components[0])) { + out[strings.ToLower(strings.TrimSpace(components[1]))] = true + } + } + + return out +} + +func isEmptyLabelSetAction(key string) LabelFilter { + return func(labels []string) bool { + return len(labelSetFor(key, labels)) == 0 + } +} + +func containsAnyLabelSetAction(key string, expectedValues []string) LabelFilter { + return func(labels []string) bool { + set := labelSetFor(key, labels) + for _, value := range expectedValues { + if set[value] { + return true + } + } + return false + } +} + +func containsAllLabelSetAction(key string, expectedValues []string) LabelFilter { + return func(labels []string) bool { + set := labelSetFor(key, labels) + for _, value := range expectedValues { + if !set[value] { + return false + } + } + return true + } +} + +func consistsOfLabelSetAction(key string, expectedValues []string) LabelFilter { + return func(labels []string) bool { + set := labelSetFor(key, labels) + if len(set) != len(expectedValues) { + return false + } + for _, value := range expectedValues { + if !set[value] { + return false + } + } + return true + } +} + +func isSubsetOfLabelSetAction(key string, expectedValues []string) LabelFilter { + expectedSet := map[string]bool{} + for _, value := range expectedValues { + expectedSet[value] = true + } + return func(labels []string) bool { + set := labelSetFor(key, labels) + for value := range set { + if !expectedSet[value] { + return false + } + } + return true + } +} + type lfToken uint const ( @@ -58,6 +135,9 @@ const ( lfTokenOr lfTokenRegexp lfTokenLabel + lfTokenSetKey + lfTokenSetOperation + lfTokenSetArgument lfTokenEOF ) @@ -71,6 +151,8 @@ func (l lfToken) Precedence() int { return 2 case lfTokenNot: return 3 + case lfTokenSetOperation: + return 4 } return -1 } @@ -93,6 +175,12 @@ func (l lfToken) String() string { return "/regexp/" case lfTokenLabel: return "label" + case lfTokenSetKey: + return "set_key" + case lfTokenSetOperation: + return "set_operation" + case lfTokenSetArgument: + return "set_argument" case lfTokenEOF: return "EOF" } @@ -148,6 +236,35 @@ func (tn *treeNode) constructLabelFilter(input string) (LabelFilter, error) { return nil, GinkgoErrors.SyntaxErrorParsingLabelFilter(input, tn.location, fmt.Sprintf("RegExp compilation error: %s", err)) } return matchLabelRegexAction(re), nil + case lfTokenSetOperation: + tokenSetOperation := strings.ToLower(tn.value) + if tokenSetOperation == "isempty" { + return isEmptyLabelSetAction(tn.leftNode.value), nil + } + if tn.rightNode == nil { + return nil, GinkgoErrors.SyntaxErrorParsingLabelFilter(input, tn.location, fmt.Sprintf("Set operation '%s' is missing an argument.", tn.value)) + } + + rawValues := strings.Split(tn.rightNode.value, ",") + values := make([]string, len(rawValues)) + for i := range rawValues { + values[i] = strings.ToLower(strings.TrimSpace(rawValues[i])) + if strings.ContainsAny(values[i], "&|!,()/") { + return nil, GinkgoErrors.SyntaxErrorParsingLabelFilter(input, tn.rightNode.location, fmt.Sprintf("Invalid label value '%s' in set operation argument.", values[i])) + } else if values[i] == "" { + return nil, GinkgoErrors.SyntaxErrorParsingLabelFilter(input, tn.rightNode.location, "Empty label value in set operation argument.") + } + } + switch tokenSetOperation { + case "containsany": + return containsAnyLabelSetAction(tn.leftNode.value, values), nil + case "containsall": + return containsAllLabelSetAction(tn.leftNode.value, values), nil + case "consistsof": + return consistsOfLabelSetAction(tn.leftNode.value, values), nil + case "issubsetof": + return isSubsetOfLabelSetAction(tn.leftNode.value, values), nil + } } if tn.rightNode == nil { @@ -203,7 +320,17 @@ func (tn *treeNode) toString(indent int) string { return out } +var validSetOperations = map[string]string{ + "containsany": "containsAny", + "containsall": "containsAll", + "consistsof": "consistsOf", + "issubsetof": "isSubsetOf", + "isempty": "isEmpty", +} + func tokenize(input string) func() (*treeNode, error) { + lastToken := lfTokenInvalid + lastValue := "" runes, i := []rune(input), 0 peekIs := func(r rune) bool { @@ -233,6 +360,53 @@ func tokenize(input string) func() (*treeNode, error) { } node := &treeNode{location: i} + defer func() { + lastToken = node.token + lastValue = node.value + }() + + if lastToken == lfTokenSetKey { + //we should get a valid set operation next + value, n := consumeUntil(" )") + if validSetOperations[strings.ToLower(value)] == "" { + return &treeNode{}, GinkgoErrors.SyntaxErrorParsingLabelFilter(input, i, fmt.Sprintf("Invalid set operation '%s'.", value)) + } + i += n + node.token, node.value = lfTokenSetOperation, value + return node, nil + } + if lastToken == lfTokenSetOperation { + //we should get an argument next, if we aren't isempty + var arg = "" + origI := i + if runes[i] == '{' { + i += 1 + value, n := consumeUntil("}") + if i+n >= len(runes) { + return &treeNode{}, GinkgoErrors.SyntaxErrorParsingLabelFilter(input, i-1, "Missing closing '}' in set operation argument?") + } + i += n + 1 + arg = value + } else { + value, n := consumeUntil("&|!,()/") + i += n + arg = strings.TrimSpace(value) + } + if strings.ToLower(lastValue) == "isempty" && arg != "" { + return &treeNode{}, GinkgoErrors.SyntaxErrorParsingLabelFilter(input, origI, fmt.Sprintf("isEmpty does not take arguments, was passed '%s'.", arg)) + } + if arg == "" && strings.ToLower(lastValue) != "isempty" { + if i < len(runes) && runes[i] == '/' { + return &treeNode{}, GinkgoErrors.SyntaxErrorParsingLabelFilter(input, origI, "Set operations do not support regular expressions.") + } else { + return &treeNode{}, GinkgoErrors.SyntaxErrorParsingLabelFilter(input, origI, fmt.Sprintf("Set operation '%s' requires an argument.", lastValue)) + } + } + // note that we sent an empty SetArgument token if we are isempty + node.token, node.value = lfTokenSetArgument, arg + return node, nil + } + switch runes[i] { case '&': if !peekIs('&') { @@ -264,8 +438,38 @@ func tokenize(input string) func() (*treeNode, error) { i += n + 1 node.token, node.value = lfTokenRegexp, value default: - value, n := consumeUntil("&|!,()/") + value, n := consumeUntil("&|!,()/:") i += n + value = strings.TrimSpace(value) + + //are we the beginning of a set operation? + if i < len(runes) && runes[i] == ':' { + if peekIs(' ') { + if value == "" { + return &treeNode{}, GinkgoErrors.SyntaxErrorParsingLabelFilter(input, i, "Missing set key.") + } + i += 1 + //we are the beginning of a set operation + node.token, node.value = lfTokenSetKey, value + return node, nil + } + additionalValue, n := consumeUntil("&|!,()/") + additionalValue = strings.TrimSpace(additionalValue) + if additionalValue == ":" { + return &treeNode{}, GinkgoErrors.SyntaxErrorParsingLabelFilter(input, i, "Missing set operation.") + } + i += n + value += additionalValue + } + + valueToCheckForSetOperation := strings.ToLower(value) + for setOperation := range validSetOperations { + idx := strings.Index(valueToCheckForSetOperation, " "+setOperation) + if idx > 0 { + return &treeNode{}, GinkgoErrors.SyntaxErrorParsingLabelFilter(input, i-n+idx+1, fmt.Sprintf("Looks like you are using the set operator '%s' but did not provide a set key. Did you forget the ':'?", validSetOperations[setOperation])) + } + } + node.token, node.value = lfTokenLabel, strings.TrimSpace(value) } return node, nil @@ -307,7 +511,7 @@ LOOP: switch node.token { case lfTokenEOF: break LOOP - case lfTokenLabel, lfTokenRegexp: + case lfTokenLabel, lfTokenRegexp, lfTokenSetKey: if current.rightNode != nil { return nil, GinkgoErrors.SyntaxErrorParsingLabelFilter(input, node.location, "Found two adjacent labels. You need an operator between them.") } @@ -326,6 +530,18 @@ LOOP: node.setLeftNode(nodeToStealFrom.rightNode) nodeToStealFrom.setRightNode(node) current = node + case lfTokenSetOperation: + if current.rightNode == nil { + return nil, GinkgoErrors.SyntaxErrorParsingLabelFilter(input, node.location, fmt.Sprintf("Set operation '%s' missing left hand operand.", node.value)) + } + node.setLeftNode(current.rightNode) + current.setRightNode(node) + current = node + case lfTokenSetArgument: + if current.rightNode != nil { + return nil, GinkgoErrors.SyntaxErrorParsingLabelFilter(input, node.location, fmt.Sprintf("Unexpected set argument '%s'.", node.token)) + } + current.setRightNode(node) case lfTokenCloseGroup: firstUnmatchedOpenNode := current.firstUnmatchedOpenNode() if firstUnmatchedOpenNode == nil { @@ -354,5 +570,14 @@ func ValidateAndCleanupLabel(label string, cl CodeLocation) (string, error) { if strings.ContainsAny(out, "&|!,()/") { return "", GinkgoErrors.InvalidLabel(label, cl) } + if out[0] == ':' { + return "", GinkgoErrors.InvalidLabel(label, cl) + } + if strings.Contains(out, ":") { + components := strings.SplitN(out, ":", 2) + if len(components) < 2 || components[1] == "" { + return "", GinkgoErrors.InvalidLabel(label, cl) + } + } return out, nil } diff --git a/vendor/github.com/onsi/ginkgo/v2/types/version.go b/vendor/github.com/onsi/ginkgo/v2/types/version.go index 5dd0140cd..acab03492 100644 --- a/vendor/github.com/onsi/ginkgo/v2/types/version.go +++ b/vendor/github.com/onsi/ginkgo/v2/types/version.go @@ -1,3 +1,3 @@ package types -const VERSION = "2.17.2" +const VERSION = "2.19.0" diff --git a/vendor/modules.txt b/vendor/modules.txt index 3c720ef7b..53e361eda 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -599,7 +599,7 @@ github.com/nishanths/predeclared/passes/predeclared # github.com/olekukonko/tablewriter v0.0.5 ## explicit; go 1.12 github.com/olekukonko/tablewriter -# github.com/onsi/ginkgo/v2 v2.17.2 +# github.com/onsi/ginkgo/v2 v2.19.0 ## explicit; go 1.20 github.com/onsi/ginkgo/v2 github.com/onsi/ginkgo/v2/config From 59a1ba79f4b5dcefdb210de9b3654dcf92626c65 Mon Sep 17 00:00:00 2001 From: Yuedong Wu Date: Wed, 21 Aug 2024 18:27:21 +0800 Subject: [PATCH 2/2] apply ginkgo label filter to differentiate cloud platforms Signed-off-by: Yuedong Wu --- Makefile | 6 +- test/e2e/certificates_test.go | 158 ++++++++++++++++------------------ 2 files changed, 77 insertions(+), 87 deletions(-) diff --git a/Makefile b/Makefile index 2693501e9..93609a490 100644 --- a/Makefile +++ b/Makefile @@ -102,6 +102,9 @@ SHORTCOMMIT ?= $(shell git rev-parse --short HEAD) GOBUILD_VERSION_ARGS = -ldflags "-X $(PACKAGE)/pkg/version.SHORTCOMMIT=$(SHORTCOMMIT) -X $(PACKAGE)/pkg/version.COMMIT=$(COMMIT)" E2E_TIMEOUT ?= 1h +# E2E_GINKGO_LABEL_FILTER is ginkgo label query for selecting tests. See +# https://onsi.github.io/ginkgo/#spec-labels. The default is to run tests on the AWS platform. +E2E_GINKGO_LABEL_FILTER ?= "Platform: isSubsetOf {AWS}" MANIFEST_SOURCE = https://github.com/cert-manager/cert-manager/releases/download/v1.15.2/cert-manager.yaml @@ -246,7 +249,8 @@ test-e2e: test-e2e-wait-for-stable-state -p 1 \ -tags e2e \ -run "$(TEST)" \ - ./test/e2e + ./test/e2e \ + -ginkgo.label-filter=$(E2E_GINKGO_LABEL_FILTER) test-e2e-wait-for-stable-state: @echo "---- Waiting for stable state ----" diff --git a/test/e2e/certificates_test.go b/test/e2e/certificates_test.go index 9b584a883..ebd2b59ad 100644 --- a/test/e2e/certificates_test.go +++ b/test/e2e/certificates_test.go @@ -19,7 +19,6 @@ import ( v1 "github.com/cert-manager/cert-manager/pkg/apis/acme/v1" certmanagerv1 "github.com/cert-manager/cert-manager/pkg/apis/certmanager/v1" certmanagermetav1 "github.com/cert-manager/cert-manager/pkg/apis/meta/v1" - configv1 "github.com/openshift/api/config/v1" . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" @@ -74,11 +73,8 @@ var _ = Describe("ACME Certificate", Ordered, func() { Expect(err).NotTo(HaveOccurred(), "Operator is expected to be available") }) - Context("dns-01 challenge using explicit credentials", func() { - It("should obtain a valid LetsEncrypt certificate", func() { - if _, ok := os.LookupEnv(targetPlatformEnvironmentVar); ok { - Skip("skipping, using ibmcloud cis webhook") - } + Context("dns-01 challenge with AWS Route53", Label("Platform:AWS"), func() { + It("should obtain a valid LetsEncrypt certificate using explicit credentials", func() { By("creating a test namespace") ns, err := loader.CreateTestingNS("e2e-acme-explicit-dns01") @@ -187,66 +183,7 @@ var _ = Describe("ACME Certificate", Ordered, func() { Expect(err).NotTo(HaveOccurred()) }) - // This test uses IBM Cloud Internet Services (CIS) for the DNS-01 test cases. - // These tests work with both UPI / IPI installations by passing in the CRN of your CIS instance on IBM Cloud. - It("should obtain a valid LetsEncrypt certificate on ibm cloud CIS", func() { - cisCRN, isCisCRN := os.LookupEnv(cisCRNEnvironmentVar) - if targetPlatform, ok := os.LookupEnv(targetPlatformEnvironmentVar); ok && targetPlatform == "ibmcloud-upi" { - if !isCisCRN || cisCRN == "" { - Fail("cisCRN is required for IBM Cloud platform") - } - } else { - Skip("skipping as the cluster does not use IBM Cloud CIS") - } - - By("creating a test namespace") - ns, err := loader.CreateTestingNS("e2e-acme-explicit-dns01-ibmcloud") - Expect(err).NotTo(HaveOccurred()) - defer loader.DeleteTestingNS(ns.Name) - - By("creating new certificate ClusterIssuer with IBM Cloud CIS webhook solver") - randomString := randomStr(3) - clusterIssuerName := "letsencrypt-dns01-explicit-ic" - replaceStrMap := map[string]string{ - "CIS_CRN": cisCRN, - } - loadFileAndReplaceStr := func(fileName string) ([]byte, error) { - fileContentsStr, err := replaceStrInFile(replaceStrMap, fileName) - return []byte(fileContentsStr), err - } - loader.CreateFromFile(loadFileAndReplaceStr, filepath.Join("testdata", "acme", "clusterissuer_ibmcis.yaml"), "") - defer certmanagerClient.CertmanagerV1().ClusterIssuers().Delete(ctx, clusterIssuerName, metav1.DeleteOptions{}) - - By("creating new certificate") - // The name is defined by the testdata YAML file certificate_ibmcis.yaml - certDomain := "adwie." + appsDomain // acronym for "ACME dns-01 ibmcloud Webhook Explicit", short naming to pass dns name validation - certName := "letsencrypt-cert-ic" - replaceStrMap = map[string]string{ - "RANDOM_STR": randomString, - "DNS_NAME": certDomain, - } - loadFileAndReplaceStr = func(fileName string) ([]byte, error) { - fileContentsStr, err := replaceStrInFile(replaceStrMap, fileName) - return []byte(fileContentsStr), err - } - loader.CreateFromFile(loadFileAndReplaceStr, filepath.Join("testdata", "acme", "certificate_ibmcis.yaml"), ns.Name) - - By("Waiting for certificate to get ready") - err = waitForCertificateReadiness(ctx, certName, ns.Name) - Expect(err).NotTo(HaveOccurred()) - - By("checking for certificate validity from secret contents") - err = verifyCertificate(ctx, certName, ns.Name, randomString+"."+certDomain) - Expect(err).NotTo(HaveOccurred()) - }) - - }) - - Context("dns-01 challenge using ambient credentials", func() { - It("should obtain a valid LetsEncrypt certificate using ClusterIssuer on AWS mint/passthrough cluster", func() { - if _, ok := os.LookupEnv(targetPlatformEnvironmentVar); ok { - Skip("skipping, using ibmcloud cis webhook") - } + It("should obtain a valid LetsEncrypt certificate using ambient credentials with ClusterIssuer", func() { By("creating a test namespace") ns, err := loader.CreateTestingNS("e2e-acme-ambient-dns01") @@ -343,7 +280,7 @@ var _ = Describe("ACME Certificate", Ordered, func() { Expect(err).NotTo(HaveOccurred()) }) - It("should obtain a valid LetsEncrypt certificate using Issuer on AWS mint/passthrough cluster", func() { + It("should obtain a valid LetsEncrypt certificate using ambient credentials with Issuer", func() { By("creating a test namespace") ns, err := loader.CreateTestingNS("e2e-acme-issuer-ambient-dns01-aws") @@ -441,21 +378,15 @@ var _ = Describe("ACME Certificate", Ordered, func() { err = verifyCertificate(ctx, certName, ns.Name, certDomain) Expect(err).NotTo(HaveOccurred()) }) + }) - It("should obtain a valid LetsEncrypt certificate using ClusterIssuer on GCP mint/passthrough cluster", func() { + Context("dns-01 challenge with Google CloudDNS", Label("Platform:GCP"), func() { + It("should obtain a valid LetsEncrypt certificate using ambient credentials with ClusterIssuer", func() { - By("Getting Infrastructure object") - infra, err := configClient.Infrastructures().Get(ctx, "cluster", metav1.GetOptions{}) + By("Creating a test namespace") + ns, err := loader.CreateTestingNS("e2e-acme-ambient-dns01") Expect(err).NotTo(HaveOccurred()) - if infra.Status.PlatformStatus.Type != configv1.GCPPlatformType { - Skip("Skip this case for current plaform, it's not gcp.") - } - - By("Check cloud credential in cluster") - _, err = loader.KubeClient.CoreV1().Secrets("kube-system").Get(ctx, "gcp-credentials", metav1.GetOptions{}) - if err != nil { - Skip("Skipping for the cluster without credential in cluster") - } + defer loader.DeleteTestingNS(ns.Name) By("Creating CredentialsRequest object") loader.CreateFromFile(testassets.ReadFile, filepath.Join("testdata", "credentials", "credentialsrequest_gcp.yaml"), "") @@ -476,11 +407,16 @@ var _ = Describe("ACME Certificate", Ordered, func() { err = patchSubscriptionWithCloudCredential(ctx, loader, credentialSecret) Expect(err).NotTo(HaveOccurred()) + By("Getting GCP project ID from Infrastructure object") + infra, err := configClient.Infrastructures().Get(ctx, "cluster", metav1.GetOptions{}) + Expect(err).NotTo(HaveOccurred()) + + gcpProjectId := infra.Status.PlatformStatus.GCP.ProjectID + Expect(gcpProjectId).NotTo(Equal("")) + By("Creating new certificate ClusterIssuer") // The name is defined by the testdata YAML file clusterissuer_gcp.yaml clusterIssuerName := "acme-dns01-clouddns-ambient" - gcpProjectId := infra.Status.PlatformStatus.GCP.ProjectID - Expect(gcpProjectId).NotTo(Equal("")) replaceStrMap := map[string]string{ "PROJECT_ID": gcpProjectId, } @@ -491,11 +427,6 @@ var _ = Describe("ACME Certificate", Ordered, func() { loader.CreateFromFile(loadFileAndReplaceStr, filepath.Join("testdata", "acme", "clusterissuer_gcp.yaml"), "") defer certmanagerClient.CertmanagerV1().ClusterIssuers().Delete(ctx, clusterIssuerName, metav1.DeleteOptions{}) - By("Creating a test namespace") - ns, err := loader.CreateTestingNS("e2e-acme-ambient-dns01-65035") - Expect(err).NotTo(HaveOccurred()) - defer loader.DeleteTestingNS(ns.Name) - By("Creating new certificate") randomString := randomStr(3) replaceStrMap = map[string]string{ @@ -521,6 +452,61 @@ var _ = Describe("ACME Certificate", Ordered, func() { }) }) + Context("dns-01 challenge with IBM Cloud Internet Service Webhook", Label("Platform:IBM"), func() { + // This test uses IBM Cloud Internet Services (CIS) for the DNS-01 challenge. + // It works with both UPI / IPI installations by passing in the CRN of your CIS instance on IBM Cloud. + It("should obtain a valid LetsEncrypt certificate using explicit credentials", func() { + cisCRN, isCisCRN := os.LookupEnv(cisCRNEnvironmentVar) + if targetPlatform, ok := os.LookupEnv(targetPlatformEnvironmentVar); ok && targetPlatform == "ibmcloud-upi" { + if !isCisCRN || cisCRN == "" { + Fail("cisCRN is required for IBM Cloud platform") + } + } else { + Skip("skipping as the cluster does not use IBM Cloud CIS") + } + + By("creating a test namespace") + ns, err := loader.CreateTestingNS("e2e-acme-explicit-dns01-ibmcloud") + Expect(err).NotTo(HaveOccurred()) + defer loader.DeleteTestingNS(ns.Name) + + By("creating new certificate ClusterIssuer with IBM Cloud CIS webhook solver") + randomString := randomStr(3) + clusterIssuerName := "letsencrypt-dns01-explicit-ic" + replaceStrMap := map[string]string{ + "CIS_CRN": cisCRN, + } + loadFileAndReplaceStr := func(fileName string) ([]byte, error) { + fileContentsStr, err := replaceStrInFile(replaceStrMap, fileName) + return []byte(fileContentsStr), err + } + loader.CreateFromFile(loadFileAndReplaceStr, filepath.Join("testdata", "acme", "clusterissuer_ibmcis.yaml"), "") + defer certmanagerClient.CertmanagerV1().ClusterIssuers().Delete(ctx, clusterIssuerName, metav1.DeleteOptions{}) + + By("creating new certificate") + // The name is defined by the testdata YAML file certificate_ibmcis.yaml + certDomain := "adwie." + appsDomain // acronym for "ACME dns-01 ibmcloud Webhook Explicit", short naming to pass dns name validation + certName := "letsencrypt-cert-ic" + replaceStrMap = map[string]string{ + "RANDOM_STR": randomString, + "DNS_NAME": certDomain, + } + loadFileAndReplaceStr = func(fileName string) ([]byte, error) { + fileContentsStr, err := replaceStrInFile(replaceStrMap, fileName) + return []byte(fileContentsStr), err + } + loader.CreateFromFile(loadFileAndReplaceStr, filepath.Join("testdata", "acme", "certificate_ibmcis.yaml"), ns.Name) + + By("waiting for certificate to get ready") + err = waitForCertificateReadiness(ctx, certName, ns.Name) + Expect(err).NotTo(HaveOccurred()) + + By("checking for certificate validity from secret contents") + err = verifyCertificate(ctx, certName, ns.Name, randomString+"."+certDomain) + Expect(err).NotTo(HaveOccurred()) + }) + }) + Context("http-01 challenge using ingress", func() { It("should obtain a valid LetsEncrypt certificate", func() {