Skip to content

Commit a0e52ff

Browse files
committed
make it clearer that you need to pass a filename to the various profile flags, not an absolute directory
1 parent b799d8d commit a0e52ff

File tree

4 files changed

+37
-4
lines changed

4 files changed

+37
-4
lines changed

docs/index.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3745,7 +3745,7 @@ You can also specify the `--covermode` to be one of `set` ("was this code called
37453745

37463746
When run with `--cover`, Ginkgo will generate a single `coverprofile.out` file that captures the coverage statistics of all the suites that ran. You can change the name of this file by specifying `-coverprofile=filename`. If you would like to keep separate coverprofiles for each suite use the `--keep-separate-coverprofiles` option.
37473747

3748-
Ginkgo also honors the `--output-dir` flag when generating coverprofiles. If you specify `--output-dir` the generated coverprofile will be placed in the requested directory. If you also specify `--keep-separate-coverprofiles` individual package coverprofiles will be placed in the requested directory and namespaced with a prefix that contains the name of the package in question.
3748+
Note that `-coverprofile` only takes a filename, not a path. To place the coverprofile in a particular path you should specify `--output-dir` the generated coverprofile will be placed in the requested directory. If you also specify `--keep-separate-coverprofiles` individual package coverprofiles will be placed in the requested directory and namespaced with a prefix that contains the name of the package in question.
37493749

37503750
Finally, when running a suite that has [programmatically focused specs](#focused-specs) (i.e. specs with the `Focus` decorator or with nodes prefixed with an `F`) Ginkgo exits the suite early with a non-zero exit code. This interferes with `go test`'s profiling code and prevents profiles from being generated. Ginkgo will tell you this has happened. If you want to profile just a subset of your suite you'll need to use a different [mechanism](#filtering-specs) to filter your specs.
37513751

integration/profiling_test.go

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -141,6 +141,12 @@ var _ = Describe("Profiling Specs", func() {
141141
Ω(fm.PathTo("coverage", "myprofile.out")).Should(BeAnExistingFile())
142142
Ω(fm.PathTo("coverage", "coverprofile.out")).ShouldNot(BeAnExistingFile())
143143
})
144+
145+
It("fails if the cover profile is not just a filename", func() {
146+
session := startGinkgo(fm.PathTo("coverage"), "--no-color", "-coverprofile=/path/to/profile.out")
147+
Eventually(session).Should(gexec.Exit(1))
148+
Ω(session.Err).Should(gbytes.Say(`--coverprofile expects a filename but was given a path: /path/to/profile.out`))
149+
})
144150
})
145151

146152
Context("when multiple suites are tested", func() {

types/config.go

Lines changed: 23 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -257,8 +257,12 @@ var FlagSections = GinkgoFlagSections{
257257
{Key: "filter", Style: "{{cyan}}", Heading: "Filtering Tests"},
258258
{Key: "failure", Style: "{{red}}", Heading: "Failure Handling"},
259259
{Key: "output", Style: "{{magenta}}", Heading: "Controlling Output Formatting"},
260-
{Key: "code-and-coverage-analysis", Style: "{{orange}}", Heading: "Code and Coverage Analysis"},
261-
{Key: "performance-analysis", Style: "{{coral}}", Heading: "Performance Analysis"},
260+
{Key: "code-and-coverage-analysis", Style: "{{orange}}", Heading: "Code and Coverage Analysis",
261+
Description: "When generating a cover files, please pass a filename {{bold}}not{{/}} a path. To specify a different directory use {{magenta}}--output-dir{{/}}.",
262+
},
263+
{Key: "performance-analysis", Style: "{{coral}}", Heading: "Performance Analysis",
264+
Description: "When generating profile files, please pass filenames {{bold}}not{{/}} a path. Ginkgo will generate a profile file with the given name in the package's directory. To specify a different directory use {{magenta}}--output-dir{{/}}.",
265+
},
262266
{Key: "debug", Style: "{{blue}}", Heading: "Debugging Tests",
263267
Description: "In addition to these flags, Ginkgo supports a few debugging environment variables. To change the parallel server protocol set {{blue}}GINKGO_PARALLEL_PROTOCOL{{/}} to {{bold}}HTTP{{/}}. To avoid pruning callstacks set {{blue}}GINKGO_PRUNE_STACK{{/}} to {{bold}}FALSE{{/}}."},
264268
{Key: "watch", Style: "{{light-yellow}}", Heading: "Controlling Ginkgo Watch"},
@@ -572,7 +576,7 @@ var GoBuildFlags = GinkgoFlags{
572576
// GoRunFlags provides flags for the Ginkgo CLI run, and watch commands that capture go's run-time flags. These are passed to the compiled test binary by the ginkgo CLI
573577
var GoRunFlags = GinkgoFlags{
574578
{KeyPath: "Go.CoverProfile", Name: "coverprofile", UsageArgument: "file", SectionKey: "code-and-coverage-analysis",
575-
Usage: `Write a coverage profile to the file after all tests have passed. Sets -cover.`},
579+
Usage: `Write a coverage profile to the file after all tests have passed. Sets -cover. Must be passed a filename, not a path. Use output-dir to control the location of the output.`},
576580
{KeyPath: "Go.BlockProfile", Name: "blockprofile", UsageArgument: "file", SectionKey: "performance-analysis",
577581
Usage: `Write a goroutine blocking profile to the specified file when all tests are complete. Preserves test binary.`},
578582
{KeyPath: "Go.BlockProfileRate", Name: "blockprofilerate", UsageArgument: "rate", SectionKey: "performance-analysis",
@@ -600,6 +604,22 @@ func VetAndInitializeCLIAndGoConfig(cliConfig CLIConfig, goFlagsConfig GoFlagsCo
600604
errors = append(errors, GinkgoErrors.BothRepeatAndUntilItFails())
601605
}
602606

607+
if strings.ContainsRune(goFlagsConfig.CoverProfile, os.PathSeparator) {
608+
errors = append(errors, GinkgoErrors.ExpectFilenameNotPath("--coverprofile", goFlagsConfig.CoverProfile))
609+
}
610+
if strings.ContainsRune(goFlagsConfig.CPUProfile, os.PathSeparator) {
611+
errors = append(errors, GinkgoErrors.ExpectFilenameNotPath("--cpuprofile", goFlagsConfig.CPUProfile))
612+
}
613+
if strings.ContainsRune(goFlagsConfig.MemProfile, os.PathSeparator) {
614+
errors = append(errors, GinkgoErrors.ExpectFilenameNotPath("--memprofile", goFlagsConfig.MemProfile))
615+
}
616+
if strings.ContainsRune(goFlagsConfig.BlockProfile, os.PathSeparator) {
617+
errors = append(errors, GinkgoErrors.ExpectFilenameNotPath("--blockprofile", goFlagsConfig.BlockProfile))
618+
}
619+
if strings.ContainsRune(goFlagsConfig.MutexProfile, os.PathSeparator) {
620+
errors = append(errors, GinkgoErrors.ExpectFilenameNotPath("--mutexprofile", goFlagsConfig.MutexProfile))
621+
}
622+
603623
//initialize the output directory
604624
if cliConfig.OutputDir != "" {
605625
err := os.MkdirAll(cliConfig.OutputDir, 0777)

types/errors.go

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -629,6 +629,13 @@ func (g ginkgoErrors) BothRepeatAndUntilItFails() error {
629629
}
630630
}
631631

632+
func (g ginkgoErrors) ExpectFilenameNotPath(flag string, path string) error {
633+
return GinkgoError{
634+
Heading: fmt.Sprintf("%s expects a filename but was given a path: %s", flag, path),
635+
Message: fmt.Sprintf("%s takes a filename, not a path. Use --output-dir to specify a directory to collect all test outputs.", flag),
636+
}
637+
}
638+
632639
/* Stack-Trace parsing errors */
633640

634641
func (g ginkgoErrors) FailedToParseStackTrace(message string) error {

0 commit comments

Comments
 (0)