Skip to content

Commit d80eebe

Browse files
grosseronsi
authored andcommittedMay 21, 2024·
fail when no tests were run and --fail-on-empty was set
1 parent fcf1fd7 commit d80eebe

File tree

5 files changed

+23
-8
lines changed

5 files changed

+23
-8
lines changed
 

‎CONTRIBUTING.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -10,4 +10,4 @@ Your contributions to Ginkgo are essential for its long-term maintenance and imp
1010
- Vet your changes via `go vet ./...`
1111
- 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.
1212

13-
Thanks for supporting Ginkgo!
13+
Thanks for supporting Ginkgo!

‎docs/index.md

+12-6
Original file line numberDiff line numberDiff line change
@@ -2697,6 +2697,12 @@ These mechanisms can all be used in concert. They combine with the following ru
26972697
- 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.
26982698
- 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.
26992699

2700+
#### Avoiding filtering out all tests
2701+
2702+
Especially for CI it is useful to fail when all tests were filtered out by accident (either via skip or typo in label filter).
2703+
2704+
`ginkgo --fail-on-empty --label-filter mytypo ./...` will fail since no test was run.
2705+
27002706
### Repeating Spec Runs and Managing Flaky Specs
27012707

27022708
Ginkgo wants to help you write reliable, deterministic, tests. Flaky specs - i.e. specs that fail _sometimes_ in non-deterministic or difficult to reason about ways - can be incredibly frustrating to debug and can erode faith in the value of a spec suite.
@@ -3098,8 +3104,8 @@ SynchronizedBeforeSuite(func(ctx SpecContext) []byte {
30983104
```
30993105
are all valid interruptible signatures. Of course you can specify `context.Context` instead and can mix-and-match interruptibility between the two functions.
31003106

3101-
**Reporting** nodes `ReportAfterEach`, `ReportBeforeEach`, `ReportBeforeSuite` `ReportAfterSuite` can be made interruptible,
3102-
to do this you need to provide it a node function which accepts both `SpecContext` and `SpecReport` for `*Each` nodes and `Report` for `*Suite` nodes.
3107+
**Reporting** nodes `ReportAfterEach`, `ReportBeforeEach`, `ReportBeforeSuite` `ReportAfterSuite` can be made interruptible,
3108+
to do this you need to provide it a node function which accepts both `SpecContext` and `SpecReport` for `*Each` nodes and `Report` for `*Suite` nodes.
31033109

31043110
As for **Container** nodes, since these run during the Tree Construction Phase they cannot be made interruptible and so do not accept functions that expect a context. And since the `By` annotation is simply syntactic sugar enabling more detailed spec documentation, any callbacks passed to `By` cannot be independently marked as interruptible (you should, instead, use the `context` passed into the node that you're calling `By` from).
31053111

@@ -3502,7 +3508,7 @@ Ginkgo's reporting infrastructure provides an alternative solution for this use
35023508

35033509
Ginkgo provides four reporting-focused nodes `ReportAfterEach`, `ReportBeforeEach` `ReportBeforeSuite`, and `ReportAfterSuite`.
35043510

3505-
`ReportAfterEach` behaves similarly to a standard `AfterEach` node and can be declared anywhere an `AfterEach` node can be declared.
3511+
`ReportAfterEach` behaves similarly to a standard `AfterEach` node and can be declared anywhere an `AfterEach` node can be declared.
35063512
`ReportAfterEach` can take either a closure that accepts a single [`SpecReport`](https://pkg.go.dev/github.com/onsi/ginkgo/v2/types#SpecReport) argument or both `SpecContext` and `SpecReport`
35073513
For example, we could implement a top-level ReportAfterEach that emits information about every spec to a remote server:
35083514

@@ -3511,7 +3517,7 @@ ReportAfterEach(func(report SpecReport) {
35113517
customFormat := fmt.Sprintf("%s | %s", report.State, report.FullText())
35123518
client.SendReport(customFormat)
35133519
})
3514-
// interruptible ReportAfterEach node
3520+
// interruptible ReportAfterEach node
35153521
ReportAfterEach(func(ctx SpecContext, report SpecReport) {
35163522
customFormat := fmt.Sprintf("%s | %s", report.State, report.FullText())
35173523
client.SendReport(customFormat)
@@ -3522,7 +3528,7 @@ ReportAfterEach(func(ctx SpecContext, report SpecReport) {
35223528

35233529
In addition, `ReportAfterEach` closures are called after a spec completes. i.e. _after_ all `AfterEach` closures have run. This gives them access to the complete final state of the spec. Note that if a failure occurs in a `ReportAfterEach` your the spec will be marked as failed. Subsequent `ReportAfterEach` closures will see the failed state, but not the closure in which the failure occurred.
35243530

3525-
`ReportAfterEach` is useful if you need to stream or emit up-to-date information about the suite as it runs. Ginkgo also provides `ReportBeforeEach` which is called before the test runs and
3531+
`ReportAfterEach` is useful if you need to stream or emit up-to-date information about the suite as it runs. Ginkgo also provides `ReportBeforeEach` which is called before the test runs and
35263532
receives a preliminary `types.SpecReport` ( or both `SpecContext` and `types.SpecReport` for interruptible behaviour) - the state of this report will indicate whether the test will be skipped or is marked pending.
35273533

35283534
You should be aware that when running in parallel, each parallel process will be running specs and their `ReportAfterEach`es. This means that multiple `ReportAfterEach` blocks can be running concurrently on independent processes. Given that, code like this won't work:
@@ -3542,7 +3548,7 @@ ReportAfterEach(func(report SpecReport) {
35423548
you'll end up with multiple processes writing to the same file and the output will be a mess. There is a better approach for this usecase...
35433549

35443550
#### Reporting Nodes - ReportBeforeSuite and ReportAfterSuite
3545-
`ReportBeforeSuite` and `ReportAfterSuite` nodes behave similarly to `BeforeSuite` and `AfterSuite` and can be placed at the top-level of your suite (typically in the suite bootstrap file).
3551+
`ReportBeforeSuite` and `ReportAfterSuite` nodes behave similarly to `BeforeSuite` and `AfterSuite` and can be placed at the top-level of your suite (typically in the suite bootstrap file).
35463552
`ReportBeforeSuite` node take a closure that accepts either [`Report`]((https://pkg.go.dev/github.com/onsi/ginkgo/v2/types#Report)) or, both `SpecContext` and `Report` converting the node to an interruptible node.
35473553

35483554
```go

‎internal/suite.go

+6-1
Original file line numberDiff line numberDiff line change
@@ -489,10 +489,15 @@ func (suite *Suite) runSpecs(description string, suiteLabels Labels, suitePath s
489489
newGroup(suite).run(specs.AtIndices(groupedSpecIndices[groupedSpecIdx]))
490490
}
491491

492-
if specs.HasAnySpecsMarkedPending() && suite.config.FailOnPending {
492+
if suite.config.FailOnPending && specs.HasAnySpecsMarkedPending() {
493493
suite.report.SpecialSuiteFailureReasons = append(suite.report.SpecialSuiteFailureReasons, "Detected pending specs and --fail-on-pending is set")
494494
suite.report.SuiteSucceeded = false
495495
}
496+
497+
if suite.config.FailOnEmpty && specs.CountWithoutSkip() == 0 {
498+
suite.report.SpecialSuiteFailureReasons = append(suite.report.SpecialSuiteFailureReasons, "Detected no specs ran and --fail-on-empty is set")
499+
suite.report.SuiteSucceeded = false
500+
}
496501
}
497502

498503
if ranBeforeSuite {

‎reporters/junit_report.go

+1
Original file line numberDiff line numberDiff line change
@@ -177,6 +177,7 @@ func GenerateJUnitReportWithConfig(report types.Report, dst string, config Junit
177177
{"FocusFiles", strings.Join(report.SuiteConfig.FocusFiles, ";")},
178178
{"SkipFiles", strings.Join(report.SuiteConfig.SkipFiles, ";")},
179179
{"FailOnPending", fmt.Sprintf("%t", report.SuiteConfig.FailOnPending)},
180+
{"FailOnEmpty", fmt.Sprintf("%t", report.SuiteConfig.FailOnEmpty)},
180181
{"FailFast", fmt.Sprintf("%t", report.SuiteConfig.FailFast)},
181182
{"FlakeAttempts", fmt.Sprintf("%d", report.SuiteConfig.FlakeAttempts)},
182183
{"DryRun", fmt.Sprintf("%t", report.SuiteConfig.DryRun)},

‎types/config.go

+3
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ type SuiteConfig struct {
2525
SkipFiles []string
2626
LabelFilter string
2727
FailOnPending bool
28+
FailOnEmpty bool
2829
FailFast bool
2930
FlakeAttempts int
3031
MustPassRepeatedly int
@@ -275,6 +276,8 @@ var SuiteConfigFlags = GinkgoFlags{
275276
Usage: "If set, ginkgo will stop running a test suite after a failure occurs."},
276277
{KeyPath: "S.FlakeAttempts", Name: "flake-attempts", SectionKey: "failure", UsageDefaultValue: "0 - failed tests are not retried", DeprecatedName: "flakeAttempts", DeprecatedDocLink: "changed-command-line-flags",
277278
Usage: "Make up to this many attempts to run each spec. If any of the attempts succeed, the suite will not be failed."},
279+
{KeyPath: "S.FailOnEmpty", Name: "fail-on-empty", SectionKey: "failure",
280+
Usage: "If set, ginkgo will mark the test suite as failed if no specs are run."},
278281

279282
{KeyPath: "S.DryRun", Name: "dry-run", SectionKey: "debug", DeprecatedName: "dryRun", DeprecatedDocLink: "changed-command-line-flags",
280283
Usage: "If set, ginkgo will walk the test hierarchy without actually running anything. Best paired with -v."},

0 commit comments

Comments
 (0)
Please sign in to comment.