Skip to content

Commit

Permalink
Bump to v2.12.0
Browse files Browse the repository at this point in the history
  • Loading branch information
dim committed Aug 31, 2023
1 parent 4568708 commit 384424d
Show file tree
Hide file tree
Showing 16 changed files with 88 additions and 59 deletions.
2 changes: 1 addition & 1 deletion docs/Gemfile.lock
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ GEM
execjs
coffee-script-source (1.11.1)
colorator (1.1.0)
commonmarker (0.23.9)
commonmarker (0.23.10)
concurrent-ruby (1.2.0)
dnsruby (1.61.9)
simpleidn (~> 0.1)
Expand Down
2 changes: 1 addition & 1 deletion docs/MIGRATING_TO_V2.md
Original file line number Diff line number Diff line change
Expand Up @@ -391,7 +391,7 @@ Ginkgo can now repeat a test suite N additional times by running `ginkgo --repea
Ginkgo requires the tests to succeed during each repetition in order to consider the test run a success.
### New: --focus-file and --skip-file
You can now tell Ginkgo to only run specs that match (or don't match) a given file filter. You can filter by filename as well as file:line. See the [Filtering Specs](onsi.github.io/ginkgo/#filtering-specs) documentation for more details.
You can now tell Ginkgo to only run specs that match (or don't match) a given file filter. You can filter by filename as well as file:line. See the [Filtering Specs](https://onsi.github.io/ginkgo/#filtering-specs) documentation for more details.

### Improved: windows support for capturing stdout and stderr
In V1 Ginkgo would run windows tests in parallel with the `--stream` option. This would result in hard-to-understand interleaved output. The reason behind this design choice was that it proved challenging to intercept all stdout and stderr output on Windows. V2 implements a best-effort output interception scheme for windows that entails reassigning the global `os.Stdout` and `os.Stderr` variables. While not as bullet-proof as the Unix `syscall.Dup2` based implementation, this is likely good enough for most usecases and allows Ginkgo support on Windows to come into parity with unix.
Expand Down
8 changes: 3 additions & 5 deletions docs/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -2597,8 +2597,8 @@ These mechanisms can all be used in concert. They combine with the following ru

- `Pending` specs are always pending and can never be coerced to run by another filtering mechanism.
- Specs that invoke `Skip()` will always be skipped regardless of other filtering mechanisms.
- The CLI based filters (`--label-filter`, `--focus-file/--skip-file`, `--focus/--skip`) **always** override any programmatic focus.
- When multiple CLI filters are provided they are all ANDed together. The spec must satisfy the label filter query **and** any location-based filters **and** any description based filters.
- Programmatic filters always apply and result in a non-zero exit code. Any additional CLI filters only apply to the subset of specs selected by the programmatic filters.
- When multiple CLI filters (`--label-filter`, `--focus-file/--skip-file`, `--focus/--skip`) are provided they are all ANDed together. The spec must satisfy the label filter query **and** any location-based filters **and** any description based filters.

### Repeating Spec Runs and Managing Flaky Specs

Expand Down Expand Up @@ -4387,7 +4387,7 @@ Eventually(func(g Gomega, ctx SpecContext) []string { //note: g Gomega must go f
for _, message := range messages {
subjects = append(subjects, message.Subject)
}
return subjects, nil
return subjects
}).WithContext(ctx).Should(ContainElement(fmt.Sprintf(`"%s" is available for pickup`, book.Title)))
```

Expand All @@ -4402,7 +4402,6 @@ Eventually(func(g Gomega, ctx SpecContext) {
subjects = append(subjects, message.Subject)
}
g.Expect(subjects).To(ContainElement(fmt.Sprintf(`"%s" is available for pickup`, book.Title)))
return subjects, nil
}).WithContext(ctx).Should(Succeed())
```

Expand All @@ -4419,7 +4418,6 @@ Eventually(func(g Gomega, ctx SpecContext) {
expectedSubject := fmt.Sprintf(`"%s" is available for pickup`, book.Title)
subjectGetter := func(m gmail.Message) string { return m.Subject }
g.Expect(messages).To(ContainElement(WithTransform(subjectGetter, Equal(expectedSubject))))
return messages, nil
}).WithContext(ctx).Should(Succeed())
```

Expand Down
6 changes: 4 additions & 2 deletions ginkgo/generators/generate_templates.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package generators

var specText = `package {{.Package}}
var specText = `{{.BuildTags}}
package {{.Package}}
import (
{{.GinkgoImport}}
Expand All @@ -14,7 +15,8 @@ var _ = {{.GinkgoPackage}}Describe("{{.Subject}}", func() {
})
`

var agoutiSpecText = `package {{.Package}}
var agoutiSpecText = `{{.BuildTags}}
package {{.Package}}
import (
{{.GinkgoImport}}
Expand Down
12 changes: 12 additions & 0 deletions ginkgo/generators/generators_common.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package generators

import (
"fmt"
"go/build"
"os"
"path/filepath"
Expand All @@ -14,6 +15,7 @@ type GeneratorsConfig struct {
Agouti, NoDot, Internal bool
CustomTemplate string
CustomTemplateData string
Tags string
}

func getPackageAndFormattedName() (string, string, string) {
Expand Down Expand Up @@ -62,3 +64,13 @@ func determinePackageName(name string, internal bool) string {

return name + "_test"
}

// getBuildTags returns the resultant string to be added.
// If the input string is not empty, then returns a `//go:build {}` string,
// otherwise returns an empty string.
func getBuildTags(tags string) string {
if tags != "" {
return fmt.Sprintf("//go:build %s\n", tags)
}
return ""
}
71 changes: 34 additions & 37 deletions internal/focus.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,22 +8,22 @@ import (
)

/*
If a container marked as focus has a descendant that is also marked as focus, Ginkgo's policy is to
unmark the container's focus. This gives developers a more intuitive experience when debugging specs.
It is common to focus a container to just run a subset of specs, then identify the specific specs within the container to focus -
this policy allows the developer to simply focus those specific specs and not need to go back and turn the focus off of the container:
As a common example, consider:
FDescribe("something to debug", function() {
It("works", function() {...})
It("works", function() {...})
FIt("doesn't work", function() {...})
It("works", function() {...})
})
here the developer's intent is to focus in on the `"doesn't work"` spec and not to run the adjacent specs in the focused `"something to debug"` container.
The nested policy applied by this function enables this behavior.
If a container marked as focus has a descendant that is also marked as focus, Ginkgo's policy is to
unmark the container's focus. This gives developers a more intuitive experience when debugging specs.
It is common to focus a container to just run a subset of specs, then identify the specific specs within the container to focus -
this policy allows the developer to simply focus those specific specs and not need to go back and turn the focus off of the container:
As a common example, consider:
FDescribe("something to debug", function() {
It("works", function() {...})
It("works", function() {...})
FIt("doesn't work", function() {...})
It("works", function() {...})
})
here the developer's intent is to focus in on the `"doesn't work"` spec and not to run the adjacent specs in the focused `"something to debug"` container.
The nested policy applied by this function enables this behavior.
*/
func ApplyNestedFocusPolicyToTree(tree *TreeNode) {
var walkTree func(tree *TreeNode) bool
Expand All @@ -44,46 +44,43 @@ func ApplyNestedFocusPolicyToTree(tree *TreeNode) {
}

/*
Ginkgo supports focussing specs using `FIt`, `FDescribe`, etc. - this is called "programmatic focus"
It also supports focussing specs using regular expressions on the command line (`-focus=`, `-skip=`) that match against spec text
and file filters (`-focus-files=`, `-skip-files=`) that match against code locations for nodes in specs.
Ginkgo supports focussing specs using `FIt`, `FDescribe`, etc. - this is called "programmatic focus"
It also supports focussing specs using regular expressions on the command line (`-focus=`, `-skip=`) that match against spec text and file filters (`-focus-files=`, `-skip-files=`) that match against code locations for nodes in specs.
If any of the CLI flags are provided they take precedence. The file filters run first followed by the regex filters.
When both programmatic and file filters are provided their results are ANDed together. If multiple kinds of filters are provided, the file filters run first followed by the regex filters.
This function sets the `Skip` property on specs by applying Ginkgo's focus policy:
- If there are no CLI arguments and no programmatic focus, do nothing.
- If there are no CLI arguments but a spec somewhere has programmatic focus, skip any specs that have no programmatic focus.
- If there are CLI arguments parse them and skip any specs that either don't match the focus filters or do match the skip filters.
This function sets the `Skip` property on specs by applying Ginkgo's focus policy:
- If there are no CLI arguments and no programmatic focus, do nothing.
- If a spec somewhere has programmatic focus skip any specs that have no programmatic focus.
- If there are CLI arguments parse them and skip any specs that either don't match the focus filters or do match the skip filters.
*Note:* specs with pending nodes are Skipped when created by NewSpec.
*Note:* specs with pending nodes are Skipped when created by NewSpec.
*/
func ApplyFocusToSpecs(specs Specs, description string, suiteLabels Labels, suiteConfig types.SuiteConfig) (Specs, bool) {
focusString := strings.Join(suiteConfig.FocusStrings, "|")
skipString := strings.Join(suiteConfig.SkipStrings, "|")

hasFocusCLIFlags := focusString != "" || skipString != "" || len(suiteConfig.SkipFiles) > 0 || len(suiteConfig.FocusFiles) > 0 || suiteConfig.LabelFilter != ""

type SkipCheck func(spec Spec) bool

// by default, skip any specs marked pending
skipChecks := []SkipCheck{func(spec Spec) bool { return spec.Nodes.HasNodeMarkedPending() }}
hasProgrammaticFocus := false

if !hasFocusCLIFlags {
// check for programmatic focus
for _, spec := range specs {
if spec.Nodes.HasNodeMarkedFocus() && !spec.Nodes.HasNodeMarkedPending() {
skipChecks = append(skipChecks, func(spec Spec) bool { return !spec.Nodes.HasNodeMarkedFocus() })
hasProgrammaticFocus = true
break
}
for _, spec := range specs {
if spec.Nodes.HasNodeMarkedFocus() && !spec.Nodes.HasNodeMarkedPending() {
hasProgrammaticFocus = true
break
}
}

if hasProgrammaticFocus {
skipChecks = append(skipChecks, func(spec Spec) bool { return !spec.Nodes.HasNodeMarkedFocus() })
}

if suiteConfig.LabelFilter != "" {
labelFilter, _ := types.ParseLabelFilter(suiteConfig.LabelFilter)
skipChecks = append(skipChecks, func(spec Spec) bool {
return !labelFilter(UnionOfLabels(suiteLabels, spec.Nodes.UnionOfLabels()))
skipChecks = append(skipChecks, func(spec Spec) bool {
return !labelFilter(UnionOfLabels(suiteLabels, spec.Nodes.UnionOfLabels()))
})
}

Expand Down
5 changes: 4 additions & 1 deletion internal/group.go
Original file line number Diff line number Diff line change
Expand Up @@ -321,7 +321,10 @@ func (g *group) run(specs Specs) {
if !skip {
var maxAttempts = 1

if g.suite.currentSpecReport.MaxMustPassRepeatedly > 0 {
if g.suite.config.MustPassRepeatedly > 0 {
maxAttempts = g.suite.config.MustPassRepeatedly
g.suite.currentSpecReport.MaxMustPassRepeatedly = maxAttempts
} else if g.suite.currentSpecReport.MaxMustPassRepeatedly > 0 {
maxAttempts = max(1, spec.MustPassRepeatedly())
} else if g.suite.config.FlakeAttempts > 0 {
maxAttempts = g.suite.config.FlakeAttempts
Expand Down
4 changes: 1 addition & 3 deletions internal/node.go
Original file line number Diff line number Diff line change
Expand Up @@ -600,9 +600,7 @@ type Nodes []Node
func (n Nodes) CopyAppend(nodes ...Node) Nodes {
numN := len(n)
out := make(Nodes, numN+len(nodes))
for i, node := range n {
out[i] = node
}
copy(out, n)
for j, node := range nodes {
out[numN+j] = node
}
Expand Down
2 changes: 2 additions & 0 deletions internal/suite.go
Original file line number Diff line number Diff line change
Expand Up @@ -245,7 +245,9 @@ func (suite *Suite) pushCleanupNode(node Node) error {

node.NodeIDWhereCleanupWasGenerated = suite.currentNode.ID
node.NestingLevel = suite.currentNode.NestingLevel
suite.selectiveLock.Lock()
suite.cleanupNodes = append(suite.cleanupNodes, node)
suite.selectiveLock.Unlock()

return nil
}
Expand Down
13 changes: 10 additions & 3 deletions reporters/json_report.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,16 @@ import (
"encoding/json"
"fmt"
"os"
"path"

"github.com/bsm/ginkgo/v2/types"
)

//GenerateJSONReport produces a JSON-formatted report at the passed in destination
// GenerateJSONReport produces a JSON-formatted report at the passed in destination
func GenerateJSONReport(report types.Report, destination string) error {
if err := os.MkdirAll(path.Dir(destination), 0770); err != nil {
return err
}
f, err := os.Create(destination)
if err != nil {
return err
Expand All @@ -25,8 +29,8 @@ func GenerateJSONReport(report types.Report, destination string) error {
return f.Close()
}

//MergeJSONReports produces a single JSON-formatted report at the passed in destination by merging the JSON-formatted reports provided in sources
//It skips over reports that fail to decode but reports on them via the returned messages []string
// MergeJSONReports produces a single JSON-formatted report at the passed in destination by merging the JSON-formatted reports provided in sources
// It skips over reports that fail to decode but reports on them via the returned messages []string
func MergeAndCleanupJSONReports(sources []string, destination string) ([]string, error) {
messages := []string{}
allReports := []types.Report{}
Expand All @@ -46,6 +50,9 @@ func MergeAndCleanupJSONReports(sources []string, destination string) ([]string,
allReports = append(allReports, reports...)
}

if err := os.MkdirAll(path.Dir(destination), 0770); err != nil {
return messages, err
}
f, err := os.Create(destination)
if err != nil {
return messages, err
Expand Down
7 changes: 7 additions & 0 deletions reporters/junit_report.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import (
"encoding/xml"
"fmt"
"os"
"path"
"strings"

"github.com/bsm/ginkgo/v2/config"
Expand Down Expand Up @@ -285,6 +286,9 @@ func GenerateJUnitReportWithConfig(report types.Report, dst string, config Junit
TestSuites: []JUnitTestSuite{suite},
}

if err := os.MkdirAll(path.Dir(dst), 0770); err != nil {
return err
}
f, err := os.Create(dst)
if err != nil {
return err
Expand Down Expand Up @@ -322,6 +326,9 @@ func MergeAndCleanupJUnitReports(sources []string, dst string) ([]string, error)
mergedReport.TestSuites = append(mergedReport.TestSuites, report.TestSuites...)
}

if err := os.MkdirAll(path.Dir(dst), 0770); err != nil {
return messages, err
}
f, err := os.Create(dst)
if err != nil {
return messages, err
Expand Down
4 changes: 4 additions & 0 deletions reporters/teamcity_report.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ package reporters
import (
"fmt"
"os"
"path"
"strings"

"github.com/bsm/ginkgo/v2/types"
Expand All @@ -27,6 +28,9 @@ func tcEscape(s string) string {
}

func GenerateTeamcityReport(report types.Report, dst string) error {
if err := os.MkdirAll(path.Dir(dst), 0770); err != nil {
return err
}
f, err := os.Create(dst)
if err != nil {
return err
Expand Down
1 change: 1 addition & 0 deletions types/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ type SuiteConfig struct {
FailOnPending bool
FailFast bool
FlakeAttempts int
MustPassRepeatedly int
DryRun bool
PollProgressAfter time.Duration
PollProgressInterval time.Duration
Expand Down
4 changes: 2 additions & 2 deletions types/errors.go
Original file line number Diff line number Diff line change
Expand Up @@ -453,8 +453,8 @@ func (g ginkgoErrors) InvalidEntryDescription(cl CodeLocation) error {

func (g ginkgoErrors) MissingParametersForTableFunction(cl CodeLocation) error {
return GinkgoError{
Heading: fmt.Sprintf("No parameters have been passed to the Table Function"),
Message: fmt.Sprintf("The Table Function expected at least 1 parameter"),
Heading: "No parameters have been passed to the Table Function",
Message: "The Table Function expected at least 1 parameter",
CodeLocation: cl,
DocLink: "table-specs",
}
Expand Down
4 changes: 1 addition & 3 deletions types/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -97,9 +97,7 @@ func (report Report) Add(other Report) Report {
report.RunTime = report.EndTime.Sub(report.StartTime)

reports := make(SpecReports, len(report.SpecReports)+len(other.SpecReports))
for i := range report.SpecReports {
reports[i] = report.SpecReports[i]
}
copy(reports, report.SpecReports)
offset := len(report.SpecReports)
for i := range other.SpecReports {
reports[i+offset] = other.SpecReports[i]
Expand Down
2 changes: 1 addition & 1 deletion types/version.go
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
package types

const VERSION = "2.9.5"
const VERSION = "2.12.0"

0 comments on commit 384424d

Please sign in to comment.