Skip to content

Commit

Permalink
Handle -outputdir flag (#364)
Browse files Browse the repository at this point in the history
* Handle -coverprofile flag

Fixes #346

* Add tool for easier contribution

* Cast byte[], otherwise failure will be displayed as array of bytes, not very useful

* Fix combine not finding files if coverProfile was set

* Add test for recursive coverage

* Fix test imports to point to correct subpackages

* Refactor casts to be semantic functions

* Add test for cover profile in parallel mode

* Add failing test for outputdir case

* Implement outputdir

* Add test for moving files to output dir
  • Loading branch information
Alexey Soshin authored and onsi committed Jul 21, 2017
1 parent 43392d5 commit 228e3a8
Show file tree
Hide file tree
Showing 3 changed files with 174 additions and 17 deletions.
75 changes: 75 additions & 0 deletions ginkgo/run_command.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@ import (
"github.com/onsi/ginkgo/ginkgo/interrupthandler"
"github.com/onsi/ginkgo/ginkgo/testrunner"
"github.com/onsi/ginkgo/types"
"io/ioutil"
"path/filepath"
)

func BuildRunCommand() *Command {
Expand Down Expand Up @@ -100,6 +102,18 @@ func (r *SpecRunner) RunSpecs(args []string, additionalArgs []string) {
runResult, numSuites = r.suiteRunner.RunSuites(randomizedRunners, r.commandFlags.NumCompilers, r.commandFlags.KeepGoing, nil)
}

if r.isInCoverageMode() {
if r.getOutputDir() != "" {
// If coverprofile is set, combine coverages
if r.getCoverprofile() != "" {
r.combineCoverprofiles(runners)
} else {
// Just move them
r.moveCoverprofiles(runners)
}
}
}

for _, runner := range runners {
runner.CleanUp()
}
Expand All @@ -121,6 +135,67 @@ func (r *SpecRunner) RunSpecs(args []string, additionalArgs []string) {
}
}

// Moves all generated profiles to specified directory
func (r *SpecRunner) moveCoverprofiles(runners []*testrunner.TestRunner) {
for _, runner := range runners {
_, filename := filepath.Split(runner.CoverageFile)
err := os.Rename(runner.CoverageFile, filepath.Join(r.getOutputDir(), filename))

if err != nil {
fmt.Printf("Unable to move coverprofile %s, %v\n", runner.CoverageFile, err)
return
}
}
}

// Combines all generated profiles in the specified directory
func (r *SpecRunner) combineCoverprofiles(runners []*testrunner.TestRunner) {

path, _ := filepath.Abs(r.getOutputDir())

fmt.Println("path is " + path)
os.MkdirAll(path, os.ModePerm)

combined, err := os.OpenFile(filepath.Join(path, r.getCoverprofile()),
os.O_APPEND|os.O_WRONLY|os.O_CREATE, 0666)

if err != nil {
fmt.Printf("Unable to create combined profile, %v\n", err)
return
}

for _, runner := range runners {
contents, err := ioutil.ReadFile(runner.CoverageFile)

if err != nil {
fmt.Printf("Unable to read coverage file %s to combine, %v\n", runner.CoverageFile, err)
return
}

_, err = combined.Write(contents)

if err != nil {
fmt.Printf("Unable to append to coverprofile, %v\n", err)
return
}
}

fmt.Println("All profiles combined")
}

func (r *SpecRunner) isInCoverageMode() bool {
opts := r.commandFlags.GoOpts
return *opts["cover"].(*bool) || *opts["coverpkg"].(*string) != "" || *opts["covermode"].(*string) != ""
}

func (r *SpecRunner) getCoverprofile() string {
return *r.commandFlags.GoOpts["coverprofile"].(*string)
}

func (r *SpecRunner) getOutputDir() string {
return *r.commandFlags.GoOpts["outputdir"].(*string)
}

func (r *SpecRunner) ComputeSuccinctMode(numSuites int) {
if config.DefaultReporterConfig.Verbose {
config.DefaultReporterConfig.Succinct = false
Expand Down
63 changes: 47 additions & 16 deletions ginkgo/testrunner/test_runner.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,8 @@ type TestRunner struct {
goOpts map[string]interface{}
additionalArgs []string
stderr *bytes.Buffer

CoverageFile string
}

func New(suite testsuite.TestSuite, numCPU int, parallelStream bool, timeout time.Duration, goOpts map[string]interface{}, additionalArgs []string) *TestRunner {
Expand Down Expand Up @@ -63,10 +65,10 @@ func (t *TestRunner) Compile() error {
func (t *TestRunner) BuildArgs(path string) []string {
args := []string{"test", "-c", "-i", "-o", path, t.Suite.Path}

if *t.goOpts["covermode"].(*string) != "" {
args = append(args, "-cover", fmt.Sprintf("-covermode=%s", *t.goOpts["covermode"].(*string)))
if t.getCoverMode() != "" {
args = append(args, "-cover", fmt.Sprintf("-covermode=%s", t.getCoverMode()))
} else {
if *t.goOpts["cover"].(*bool) || *t.goOpts["coverpkg"].(*string) != "" {
if t.shouldCover() || t.getCoverPackage() != "" {
args = append(args, "-cover", "-covermode=atomic")
}
}
Expand Down Expand Up @@ -298,7 +300,7 @@ func (t *TestRunner) runAndStreamParallelGinkgoSuite() RunResult {

os.Stdout.Sync()

if *t.goOpts["cover"].(*bool) || *t.goOpts["coverpkg"].(*string) != "" || *t.goOpts["covermode"].(*string) != "" {
if t.shouldCombineCoverprofiles() {
t.combineCoverprofiles()
}

Expand Down Expand Up @@ -380,7 +382,7 @@ func (t *TestRunner) runParallelGinkgoSuite() RunResult {
os.Stdout.Sync()
}

if *t.goOpts["cover"].(*bool) || *t.goOpts["coverpkg"].(*string) != "" || *t.goOpts["covermode"].(*string) != "" {
if t.shouldCombineCoverprofiles() {
t.combineCoverprofiles()
}

Expand All @@ -392,21 +394,24 @@ const CoverProfileSuffix = ".coverprofile"
func (t *TestRunner) cmd(ginkgoArgs []string, stream io.Writer, node int) *exec.Cmd {
args := []string{"--test.timeout=" + t.timeout.String()}

coverMode := *t.goOpts["covermode"].(*string)
coverPackage := *t.goOpts["coverpkg"].(*string)
cover := *t.goOpts["cover"].(*bool)
coverProfile := *t.goOpts["coverprofile"].(*string)
coverProfile := t.getCoverProfile()

if t.shouldCombineCoverprofiles() {

if cover || coverPackage != "" || coverMode != "" {
testCoverProfile := "--test.coverprofile="

coverageFile := ""
// Set default name for coverage results
if coverProfile == "" {
testCoverProfile += t.Suite.PackageName + CoverProfileSuffix
coverageFile = t.Suite.PackageName + CoverProfileSuffix
} else {
testCoverProfile += coverProfile
coverageFile = coverProfile
}

testCoverProfile += coverageFile

t.CoverageFile = filepath.Join(t.Suite.Path, coverageFile)

if t.numCPU > 1 {
testCoverProfile = fmt.Sprintf("%s.%d", testCoverProfile, node)
}
Expand All @@ -430,6 +435,30 @@ func (t *TestRunner) cmd(ginkgoArgs []string, stream io.Writer, node int) *exec.
return cmd
}

func (t *TestRunner) shouldCover() bool {
return *t.goOpts["cover"].(*bool)
}

func (t *TestRunner) shouldRequireSuite() bool {
return *t.goOpts["requireSuite"].(*bool)
}

func (t *TestRunner) getCoverProfile() string {
return *t.goOpts["coverprofile"].(*string)
}

func (t *TestRunner) getCoverPackage() string {
return *t.goOpts["coverpkg"].(*string)
}

func (t *TestRunner) getCoverMode() string {
return *t.goOpts["covermode"].(*string)
}

func (t *TestRunner) shouldCombineCoverprofiles() bool {
return t.shouldCover() || t.getCoverPackage() != "" || t.getCoverMode() != ""
}

func (t *TestRunner) run(cmd *exec.Cmd, completions chan RunResult) RunResult {
var res RunResult

Expand All @@ -452,7 +481,7 @@ func (t *TestRunner) run(cmd *exec.Cmd, completions chan RunResult) RunResult {
res.HasProgrammaticFocus = (exitStatus == types.GINKGO_FOCUS_EXIT_CODE)

if strings.Contains(t.stderr.String(), "warning: no tests to run") {
if *t.goOpts["requireSuite"].(*bool) {
if t.shouldRequireSuite() {
res.Passed = false
}
fmt.Fprintf(os.Stderr, `Found no test suites, did you forget to run "ginkgo bootstrap"?`)
Expand All @@ -464,7 +493,7 @@ func (t *TestRunner) run(cmd *exec.Cmd, completions chan RunResult) RunResult {
func (t *TestRunner) combineCoverprofiles() {
profiles := []string{}

coverProfile := *t.goOpts["coverprofile"].(*string)
coverProfile := t.getCoverProfile()

for cpu := 1; cpu <= t.numCPU; cpu++ {
var coverFile string
Expand Down Expand Up @@ -518,6 +547,8 @@ func (t *TestRunner) combineCoverprofiles() {
finalFilename = fmt.Sprintf("%s%s", t.Suite.PackageName, CoverProfileSuffix)
}

ioutil.WriteFile(filepath.Join(t.Suite.Path, finalFilename),
[]byte(finalOutput), 0666)
coverageFilepath := filepath.Join(t.Suite.Path, finalFilename)
ioutil.WriteFile(coverageFilepath, []byte(finalOutput), 0666)

t.CoverageFile = coverageFilepath
}
53 changes: 52 additions & 1 deletion integration/coverage_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,10 @@ import (
"os"
"os/exec"

"fmt"
. "github.com/onsi/ginkgo"
. "github.com/onsi/gomega"
"github.com/onsi/gomega/gexec"
"fmt"
)

var _ = Describe("Coverage Specs", func() {
Expand Down Expand Up @@ -97,4 +97,55 @@ var _ = Describe("Coverage Specs", func() {
// Cleanup
os.RemoveAll(coverFile)
})

It("Appends coverages if output dir and coverprofile were set", func() {
session := startGinkgo("./_fixtures/combined_coverage_fixture", "-outputdir=./", "-r", "-cover", "-coverprofile=coverage.txt")

Eventually(session).Should(gexec.Exit(0))

_, err := os.Stat("./_fixtures/combined_coverage_fixture/coverage.txt")

Ω(err).ShouldNot(HaveOccurred())

// Cleanup
os.RemoveAll("./_fixtures/combined_coverage_fixture/coverage.txt")
})

It("Creates directories in path if they don't exist", func() {
session := startGinkgo("./_fixtures/combined_coverage_fixture", "-outputdir=./all/profiles/here", "-r", "-cover", "-coverprofile=coverage.txt")

defer os.RemoveAll("./_fixtures/combined_coverage_fixture/all")
defer os.RemoveAll("./_fixtures/combined_coverage_fixture/coverage.txt")

Eventually(session).Should(gexec.Exit(0))

_, err := os.Stat("./_fixtures/combined_coverage_fixture/all/profiles/here/coverage.txt")

Ω(err).ShouldNot(HaveOccurred())
})

It("Moves coverages if only output dir was set", func() {
session := startGinkgo("./_fixtures/combined_coverage_fixture", "-outputdir=./", "-r", "-cover")

Eventually(session).Should(gexec.Exit(0))

packages := []string{"first_package", "second_package"}

for _, p := range packages {
coverFile := fmt.Sprintf("./_fixtures/combined_coverage_fixture/%s.coverprofile", p)

// Cleanup
defer func (f string) {
os.RemoveAll(f)
} (coverFile)

defer func (f string) {
os.RemoveAll(fmt.Sprintf("./_fixtures/combined_coverage_fixture/%s/coverage.txt", f))
} (p)

_, err := os.Stat(coverFile)

Ω(err).ShouldNot(HaveOccurred())
}
})
})

0 comments on commit 228e3a8

Please sign in to comment.