Thanks to visit codestin.com
Credit goes to Github.com

Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 13 additions & 6 deletions core_dsl.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import (
"io"
"os"
"path/filepath"
"slices"
"strings"

"github.com/go-logr/logr"
Expand Down Expand Up @@ -268,7 +269,7 @@ func RunSpecs(t GinkgoTestingT, description string, args ...any) bool {
}
defer global.PopClone()

suiteLabels, suiteSemVerConstraints, suiteAroundNodes := extractSuiteConfiguration(args)
suiteLabels, suiteSemVerConstraints, suiteComponentSemVerConstraints, suiteAroundNodes := extractSuiteConfiguration(args)

var reporter reporters.Reporter
if suiteConfig.ParallelTotal == 1 {
Expand Down Expand Up @@ -311,7 +312,7 @@ func RunSpecs(t GinkgoTestingT, description string, args ...any) bool {
suitePath, err = filepath.Abs(suitePath)
exitIfErr(err)

passed, hasFocusedTests := global.Suite.Run(description, suiteLabels, suiteSemVerConstraints, suiteAroundNodes, suitePath, global.Failer, reporter, writer, outputInterceptor, interrupt_handler.NewInterruptHandler(client), client, internal.RegisterForProgressSignal, suiteConfig)
passed, hasFocusedTests := global.Suite.Run(description, suiteLabels, suiteSemVerConstraints, suiteComponentSemVerConstraints, suiteAroundNodes, suitePath, global.Failer, reporter, writer, outputInterceptor, interrupt_handler.NewInterruptHandler(client), client, internal.RegisterForProgressSignal, suiteConfig)
outputInterceptor.Shutdown()

flagSet.ValidateDeprecations(deprecationTracker)
Expand All @@ -330,9 +331,10 @@ func RunSpecs(t GinkgoTestingT, description string, args ...any) bool {
return passed
}

func extractSuiteConfiguration(args []any) (Labels, SemVerConstraints, types.AroundNodes) {
func extractSuiteConfiguration(args []any) (Labels, SemVerConstraints, ComponentSemVerConstraints, types.AroundNodes) {
suiteLabels := Labels{}
suiteSemVerConstraints := SemVerConstraints{}
suiteComponentSemVerConstraints := ComponentSemVerConstraints{}
aroundNodes := types.AroundNodes{}
configErrors := []error{}
for _, arg := range args {
Expand All @@ -345,6 +347,11 @@ func extractSuiteConfiguration(args []any) (Labels, SemVerConstraints, types.Aro
suiteLabels = append(suiteLabels, arg...)
case SemVerConstraints:
suiteSemVerConstraints = append(suiteSemVerConstraints, arg...)
case ComponentSemVerConstraints:
for component, constraints := range arg {
suiteComponentSemVerConstraints[component] = append(suiteComponentSemVerConstraints[component], constraints...)
suiteComponentSemVerConstraints[component] = slices.Compact(suiteComponentSemVerConstraints[component])
}
case types.AroundNodeDecorator:
aroundNodes = append(aroundNodes, arg)
default:
Expand All @@ -362,7 +369,7 @@ func extractSuiteConfiguration(args []any) (Labels, SemVerConstraints, types.Aro
os.Exit(1)
}

return suiteLabels, suiteSemVerConstraints, aroundNodes
return suiteLabels, suiteSemVerConstraints, suiteComponentSemVerConstraints, aroundNodes
}

func getwd() (string, error) {
Expand All @@ -385,7 +392,7 @@ func PreviewSpecs(description string, args ...any) Report {
}
defer global.PopClone()

suiteLabels, suiteSemVerConstraints, suiteAroundNodes := extractSuiteConfiguration(args)
suiteLabels, suiteSemVerConstraints, suiteComponentSemVerConstraints, suiteAroundNodes := extractSuiteConfiguration(args)
priorDryRun, priorParallelTotal, priorParallelProcess := suiteConfig.DryRun, suiteConfig.ParallelTotal, suiteConfig.ParallelProcess
suiteConfig.DryRun, suiteConfig.ParallelTotal, suiteConfig.ParallelProcess = true, 1, 1
defer func() {
Expand All @@ -403,7 +410,7 @@ func PreviewSpecs(description string, args ...any) Report {
suitePath, err = filepath.Abs(suitePath)
exitIfErr(err)

global.Suite.Run(description, suiteLabels, suiteSemVerConstraints, suiteAroundNodes, suitePath, global.Failer, reporter, writer, outputInterceptor, interrupt_handler.NewInterruptHandler(client), client, internal.RegisterForProgressSignal, suiteConfig)
global.Suite.Run(description, suiteLabels, suiteSemVerConstraints, suiteComponentSemVerConstraints, suiteAroundNodes, suitePath, global.Failer, reporter, writer, outputInterceptor, interrupt_handler.NewInterruptHandler(client), client, internal.RegisterForProgressSignal, suiteConfig)

return global.Suite.GetPreviewReport()
}
Expand Down
21 changes: 21 additions & 0 deletions decorator_dsl.go
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,27 @@ You can learn more here: https://onsi.github.io/ginkgo/#spec-semantic-version-fi
*/
type SemVerConstraints = internal.SemVerConstraints

/*
ComponentSemVerConstraint decorates specs with ComponentSemVerConstraints. Multiple components semantic version constraints can be passed to ComponentSemVerConstraint and the component can't be empy, also the version strings must follow the semantic version constraint rules.
ComponentSemVerConstraints can be applied to container and subject nodes, but not setup nodes. You can provide multiple ComponentSemVerConstraints to a given node and a spec's component semantic version constraints is the union of all component semantic version constraints in its node hierarchy.
You can learn more here: https://onsi.github.io/ginkgo/#spec-semantic-version-filtering
You can learn more about decorators here: https://onsi.github.io/ginkgo/#decorator-reference
*/
func ComponentSemVerConstraint(component string, semVerConstraints ...string) ComponentSemVerConstraints {
componentSemVerConstraints := ComponentSemVerConstraints{
component: semVerConstraints,
}

return componentSemVerConstraints
}

/*
ComponentSemVerConstraints are the type for spec ComponentSemVerConstraint decorators. Use ComponentSemVerConstraint(...) to construct ComponentSemVerConstraints.
You can learn more here: https://onsi.github.io/ginkgo/#spec-semantic-version-filtering
*/
type ComponentSemVerConstraints = internal.ComponentSemVerConstraints

/*
PollProgressAfter allows you to override the configured value for --poll-progress-after for a particular node.
Expand Down
21 changes: 19 additions & 2 deletions docs/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -2930,13 +2930,17 @@ Describe("Feature with version requirements", func() {
It("should work in a specific version range (1.0.0, 2.0.0)", SemVerConstraint("> 1.0.0", "< 2.0.0"), func() {
// This test will only run when version is between 1.0.0 (exclusive) and 2.0.0 (exclusive)
})

It("should work in a specific version range (1.0.0, 2.0.0) and third-party dependency redis in [8.0.0, ~)", SemVerConstraint(">= 3.2.0"), ComponentSemVerConstraint("redis", ">= 8.0.0") func() {
// This test will only run when version is between 1.0.0 (exclusive) and 2.0.0 (exclusive) and redis version is >= 8.0.0
})
})
```

You can then filter specs by providing a semantic version via the `--sem-ver-filter` flag:

```bash
ginkgo --sem-ver-filter="2.1.1"
ginkgo --sem-ver-filter="2.1.1, redis=8.2.0"
```

This will only run specs whose semantic version constraints are satisfied by the provided version.
Expand All @@ -2963,14 +2967,27 @@ Describe("Feature with version requirements", SemVerConstraint(">= 2.0.0, < 2.3.
It("should only run in a narrower range", SemVerConstraint(">= 2.1.0, <= 2.2.0"), func() {
// Effective constraint: >= 2.1.0, <= 2.2.0 (intersection with parent)
})

Context("should work in the base version range and third-party dependency", ComponentSemVerConstraint("redis", ">= 6.0.0"), func() {
It("should run when both constraints are satisfied", func() {
// Effective constraint: >= 2.0.0, < 2.3.0 and redis version >= 6.0.0
})

It("should run in a narrower range with third-party dependency", ComponentSemVerConstraint("redis", ">= 7.0.0", "< 8.0.0"), func() {
// Effective constraint: >= 2.0.0, < 2.3.0 and redis version >= 7.0.0, < 8.0.0
})
})
})
```

In this example, the second spec will only run when the version satisfies both the parent constraint (`>= 2.0.0, < 2.3.0`) and its own constraint (`>= 2.1.0, <= 2.2.0`), resulting in an effective constraint of `>= 2.1.0, <= 2.2.0`.
Additionally, the specs within the `Context` will only run when both the parent constraint and the third-party dependency constraint are satisfied.

Note that while using `ComponentSemVerConstraint` decorator, the component name can not be empty.

##### Unconstrained Specs

Specs that don't have a `SemVerConstraint` decorator are considered unconstrained and will always run when the `--sem-ver-filter` flag is provided. This allows you to have a mix of version-specific and version-agnostic tests in the same suite.
Specs that don't have `SemVerConstraint` or `ComponentSemVerConstraint` decorator are considered unconstrained and will always run when the `--sem-ver-filter` flag is provided. This allows you to have a mix of version-specific and version-agnostic tests in the same suite.

#### Location-Based Filtering

Expand Down
2 changes: 2 additions & 0 deletions dsl/decorators/decorators_dsl.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ type FlakeAttempts = ginkgo.FlakeAttempts
type MustPassRepeatedly = ginkgo.MustPassRepeatedly
type Labels = ginkgo.Labels
type SemVerConstraints = ginkgo.SemVerConstraints
type ComponentSemVerConstraints = ginkgo.ComponentSemVerConstraints
type PollProgressAfter = ginkgo.PollProgressAfter
type PollProgressInterval = ginkgo.PollProgressInterval
type NodeTimeout = ginkgo.NodeTimeout
Expand All @@ -39,6 +40,7 @@ const SuppressProgressReporting = ginkgo.SuppressProgressReporting

var Label = ginkgo.Label
var SemVerConstraint = ginkgo.SemVerConstraint
var ComponentSemVerConstraint = ginkgo.ComponentSemVerConstraint

func AroundNode[F types.AroundNodeAllowedFuncs](f F) types.AroundNodeDecorator {
return types.AroundNode(f, types.NewCodeLocation(1))
Expand Down
38 changes: 38 additions & 0 deletions integration/_fixtures/semver_fixture/semver_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,21 @@ var _ = Describe("Semantic Version Filtering", func() {

It("should run with version in range [2.0.0, 5.0.0)", SemVerConstraint(">= 2.0.0"), SemVerConstraint("< 5.0.0"), func() {})

It("should run with ComponentA in range [2.0.0, ~)", ComponentSemVerConstraint("ComponentA", ">= 2.0.0"), func() {})

It("should run with ComponentA in range [2.0.0, 3.0.0)", ComponentSemVerConstraint("ComponentA", ">= 2.0.0, < 3.0.0"), func() {})

It("should run with ComponentA in range [2.0.0, 4.0.0)", ComponentSemVerConstraint("ComponentA", ">= 2.0.0", "< 4.0.0"), func() {})

It("should run with ComponentA in range [2.0.0, 5.0.0)", ComponentSemVerConstraint("ComponentA", ">= 2.0.0"), ComponentSemVerConstraint("ComponentA", "< 5.0.0"), func() {})

It("should run with a mixed of component-specific and non-component constraints", SemVerConstraint(">= 2.0.0"), ComponentSemVerConstraint("ComponentA", ">= 2.0.0"), func() {})

It("shouldn't run with version in a conflict range", SemVerConstraint("2.0.0 - 6.0.0"), SemVerConstraint("<= 1.0.0"), func() {})

It("shouldn't run with ComponentA in a conflict range", ComponentSemVerConstraint("ComponentA", "2.0.0 - 6.0.0"), ComponentSemVerConstraint("ComponentA", "<= 1.0.0"), func() {})

It("shouldn't run with a mixed of component-specific and non-component conflict constraints", SemVerConstraint(">= 2.0.0"), ComponentSemVerConstraint("ComponentA", "<= 1.0.0"), func() {})
})

var _ = Describe("Hierarchy Semantic Version Filtering", func() {
Expand All @@ -35,6 +49,27 @@ var _ = Describe("Hierarchy Semantic Version Filtering", func() {
// So, this test case would be skipped.
})
})

Context("with container component-specific constraints", ComponentSemVerConstraint("ComponentA", ">= 2.0.0", "< 3.0.0"), func() {
It("should inherit container component-specific constraint", func() {})

It("should narrow down the component-specific constraint", ComponentSemVerConstraint("ComponentA", ">= 2.1.0, < 2.8.0"), func() {})

It("shouldn't expand the component-specific constraint", ComponentSemVerConstraint("ComponentA", "< 4.0.0"), func() {
// If you pass '--sem-ver-filter=3.5.0', then the whole Context would be skipped since it doesn't match the top level ComponentSemVerConstraints.
// But if you pass '--sem-ver-filter=2.5.0', this test case would keep running since it matches the combined constraint '>= 2.0.0, < 3.0.0, < 4.0.0'
})

It("shouldn't combine with a component-specific conflict constraint", ComponentSemVerConstraint("ComponentA", "< 1.0.0"), func() {
// The new combined constraint is '>= 2.0.0, < 3.0.0, <1.0.0', there's no such a version can match this constraint.
// So, this test case would be skipped.
})
})

Context("with mixed container constraints", SemVerConstraint(">= 2.0.0", "< 3.0.0"),
ComponentSemVerConstraint("ComponentA", ">= 2.0.0", "< 3.0.0"), func() {
It("should inherit container constraints and a new component-specific constraint", ComponentSemVerConstraint("ComponentB", ">= 0.1.0"), func() {})
})
})

var _ = DescribeTable("Semantic Version Filtering in table-driven spec", func() {
Expand All @@ -43,4 +78,7 @@ var _ = DescribeTable("Semantic Version Filtering in table-driven spec", func()
Entry("should run without constraints by table driven"),
Entry("should run with version in range [2.0.0, ~) by table driven", SemVerConstraint(">= 2.0.0")),
Entry("shouldn't run with version in a conflict range by table driven", SemVerConstraint(">= 2.0.0"), SemVerConstraint("~1.2.3")),
Entry("should run with ComponentA in range [2.0.0, ~) by table driven", ComponentSemVerConstraint("ComponentA", ">= 2.0.0")),
Entry("shouldn't run with ComponentA in a conflict range by table driven", ComponentSemVerConstraint("ComponentA", ">= 2.0.0"), ComponentSemVerConstraint("ComponentA", "~1.2.3")),
Entry("should run with mixed constraints by table driven", SemVerConstraint(">= 2.0.0"), ComponentSemVerConstraint("ComponentA", ">= 2.0.0")),
)
Original file line number Diff line number Diff line change
Expand Up @@ -16,4 +16,6 @@ var _ = Describe("Spec Hierarchy Semantic Version Filtering", func() {
It("should inherit spec constraint", func() {})

It("should narrow down spec constraint", SemVerConstraint(">= 3.0.0, < 4.0.0"), func() {})

It("should integrate with component constraint", ComponentSemVerConstraint("compA", ">= 12.0.0"), func() {})
})
26 changes: 21 additions & 5 deletions integration/filter_test.go
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
package integration_test

import (
"path/filepath"
"path/filepath"

. "github.com/onsi/ginkgo/v2"
. "github.com/onsi/gomega"
Expand Down Expand Up @@ -113,7 +113,7 @@ var _ = Describe("Filter", func() {

It("filters specs based on semantic version constraints", func() {
session := startGinkgo(filepath.Join(fm.TmpDir, "semver"),
"--sem-ver-filter=2.2.0",
"--sem-ver-filter=2.2.0, ComponentA=2.5.0",
"--json-report=report.json",
)
Eventually(session).Should(gexec.Exit(0))
Expand All @@ -124,35 +124,51 @@ var _ = Describe("Filter", func() {
"should run with version in range [2.0.0, 3.0.0)",
"should run with version in range [2.0.0, 4.0.0)",
"should run with version in range [2.0.0, 5.0.0)",
"should run with ComponentA in range [2.0.0, ~)",
"should run with ComponentA in range [2.0.0, 3.0.0)",
"should run with ComponentA in range [2.0.0, 4.0.0)",
"should run with ComponentA in range [2.0.0, 5.0.0)",
"should run with a mixed of component-specific and non-component constraints",
"should inherit container constraint",
"should narrow down the constraint",
"shouldn't expand the constraint",
"should inherit container component-specific constraint",
"should narrow down the component-specific constraint",
"shouldn't expand the component-specific constraint",
"should inherit container constraints and a new component-specific constraint",
"should run without constraints by table driven",
"should run with version in range [2.0.0, ~) by table driven",
"should run with ComponentA in range [2.0.0, ~) by table driven",
"should run with mixed constraints by table driven",
}
skippedSpecs := []string{
"shouldn't run with version in a conflict range",
"shouldn't run with ComponentA in a conflict range",
"shouldn't run with a mixed of component-specific and non-component conflict constraints",
"shouldn't combine with a conflict constraint",
"shouldn't combine with a component-specific conflict constraint",
"shouldn't run with version in a conflict range by table driven",
"shouldn't run with ComponentA in a conflict range by table driven",
}
Ω(specs).Should(HaveLen(len(passedSpecs) + len(skippedSpecs)))
for _, passed := range passedSpecs {
Ω(specs.Find(passed)).Should(HavePassed())
Ω(specs.Find(passed)).Should(HavePassed(), passed)
}
for _, skipped := range skippedSpecs {
Ω(specs.Find(skipped)).Should(HaveBeenSkipped())
Ω(specs.Find(skipped)).Should(HaveBeenSkipped(), skipped)
}
})

It("filters specs with hierarchy based on semantic version constraints", func() {
session := startGinkgo(filepath.Join(fm.TmpDir, "semver", "spechierarchy"),
"--sem-ver-filter=2.2.0",
"--sem-ver-filter=2.2.0, compA=12.0.0",
"--json-report=report.json",
)
Eventually(session).Should(gexec.Exit(0))
specs := Reports(fm.LoadJSONReports(filepath.Join("semver", "spechierarchy"), "report.json")[0].SpecReports)
passedSpecs := []string{
"should inherit spec constraint",
"should integrate with component constraint",
}
skippedSpecs := []string{
"should narrow down spec constraint",
Expand Down
21 changes: 19 additions & 2 deletions internal/focus.go
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ This function sets the `Skip` property on specs by applying Ginkgo's focus polic

*Note:* specs with pending nodes are Skipped when created by NewSpec.
*/
func ApplyFocusToSpecs(specs Specs, description string, suiteLabels Labels, suiteSemVerConstraints SemVerConstraints, suiteConfig types.SuiteConfig) (Specs, bool) {
func ApplyFocusToSpecs(specs Specs, description string, suiteLabels Labels, suiteSemVerConstraints SemVerConstraints, suiteComponentSemVerConstraints ComponentSemVerConstraints, suiteConfig types.SuiteConfig) (Specs, bool) {
focusString := strings.Join(suiteConfig.FocusStrings, "|")
skipString := strings.Join(suiteConfig.SkipStrings, "|")

Expand Down Expand Up @@ -87,7 +87,24 @@ func ApplyFocusToSpecs(specs Specs, description string, suiteLabels Labels, suit
if suiteConfig.SemVerFilter != "" {
semVerFilter, _ := types.ParseSemVerFilter(suiteConfig.SemVerFilter)
skipChecks = append(skipChecks, func(spec Spec) bool {
return !semVerFilter(UnionOfSemVerConstraints(suiteSemVerConstraints, spec.Nodes.UnionOfSemVerConstraints()))
noRun := false

// non-component-specific constraints
constraints := UnionOfSemVerConstraints(suiteSemVerConstraints, spec.Nodes.UnionOfSemVerConstraints())
if len(constraints) != 0 && semVerFilter("", constraints) == false {
noRun = true
}

// component-specific constraints
componentConstraints := UnionOfComponentSemVerConstraints(suiteComponentSemVerConstraints, spec.Nodes.UnionOfComponentSemVerConstraints())
for component, constraints := range componentConstraints {
if semVerFilter(component, constraints) == false {
noRun = true
break
}
}

return noRun
})
}

Expand Down
Loading
Loading