Use Go 1.5 vendoring instead of Godeps

Change made by:

- running "gvt fetch" on each of the packages mentioned in
  Godeps/Godeps.json
- `rm -rf Godeps`
- tweaking the build scripts to not mention Godeps
- tweaking the build scripts to test `./lib/...`, `./cmd/...` explicitly
  (to avoid testing vendor)
- tweaking the build scripts to not juggle GOPATH for Godeps and instead
  set GO15VENDOREXPERIMENT.

This also results in some updated packages at the same time I bet.

Building with Go 1.3 and 1.4 still *works* but won't use our vendored
dependencies - the user needs to have the actual packages in their
GOPATH then, which they'll get with a normal "go get". Building with Go
1.6+ will get our vendored dependencies by default even when not using
our build script, which is nice.

By doing this we gain some freedom in that we can pick and choose
manually what to include in vendor, as it's not based on just dependency
analysis of our own code. This is also a risk as we might pick up
dependencies we are unaware of, as the build may work locally with those
packages present in GOPATH. On the other hand the build server will
detect this as it has no packages in it's GOPATH beyond what is included
in the repo.

Recommended tool to manage dependencies is github.com/FiloSottile/gvt.
This commit is contained in:
Jakob Borg
2016-03-05 21:01:58 +01:00
parent 9259425a9a
commit 65aaa607ab
694 changed files with 65763 additions and 3541 deletions

View File

@@ -0,0 +1,83 @@
/*
Ginkgo's Default Reporter
A number of command line flags are available to tweak Ginkgo's default output.
These are documented [here](http://onsi.github.io/ginkgo/#running_tests)
*/
package reporters
import (
"github.com/onsi/ginkgo/config"
"github.com/onsi/ginkgo/reporters/stenographer"
"github.com/onsi/ginkgo/types"
)
type DefaultReporter struct {
config config.DefaultReporterConfigType
stenographer stenographer.Stenographer
specSummaries []*types.SpecSummary
}
func NewDefaultReporter(config config.DefaultReporterConfigType, stenographer stenographer.Stenographer) *DefaultReporter {
return &DefaultReporter{
config: config,
stenographer: stenographer,
}
}
func (reporter *DefaultReporter) SpecSuiteWillBegin(config config.GinkgoConfigType, summary *types.SuiteSummary) {
reporter.stenographer.AnnounceSuite(summary.SuiteDescription, config.RandomSeed, config.RandomizeAllSpecs, reporter.config.Succinct)
if config.ParallelTotal > 1 {
reporter.stenographer.AnnounceParallelRun(config.ParallelNode, config.ParallelTotal, summary.NumberOfTotalSpecs, summary.NumberOfSpecsBeforeParallelization, reporter.config.Succinct)
}
reporter.stenographer.AnnounceNumberOfSpecs(summary.NumberOfSpecsThatWillBeRun, summary.NumberOfTotalSpecs, reporter.config.Succinct)
}
func (reporter *DefaultReporter) BeforeSuiteDidRun(setupSummary *types.SetupSummary) {
if setupSummary.State != types.SpecStatePassed {
reporter.stenographer.AnnounceBeforeSuiteFailure(setupSummary, reporter.config.Succinct, reporter.config.FullTrace)
}
}
func (reporter *DefaultReporter) AfterSuiteDidRun(setupSummary *types.SetupSummary) {
if setupSummary.State != types.SpecStatePassed {
reporter.stenographer.AnnounceAfterSuiteFailure(setupSummary, reporter.config.Succinct, reporter.config.FullTrace)
}
}
func (reporter *DefaultReporter) SpecWillRun(specSummary *types.SpecSummary) {
if reporter.config.Verbose && !reporter.config.Succinct && specSummary.State != types.SpecStatePending && specSummary.State != types.SpecStateSkipped {
reporter.stenographer.AnnounceSpecWillRun(specSummary)
}
}
func (reporter *DefaultReporter) SpecDidComplete(specSummary *types.SpecSummary) {
switch specSummary.State {
case types.SpecStatePassed:
if specSummary.IsMeasurement {
reporter.stenographer.AnnounceSuccesfulMeasurement(specSummary, reporter.config.Succinct)
} else if specSummary.RunTime.Seconds() >= reporter.config.SlowSpecThreshold {
reporter.stenographer.AnnounceSuccesfulSlowSpec(specSummary, reporter.config.Succinct)
} else {
reporter.stenographer.AnnounceSuccesfulSpec(specSummary)
}
case types.SpecStatePending:
reporter.stenographer.AnnouncePendingSpec(specSummary, reporter.config.NoisyPendings && !reporter.config.Succinct)
case types.SpecStateSkipped:
reporter.stenographer.AnnounceSkippedSpec(specSummary, reporter.config.Succinct, reporter.config.FullTrace)
case types.SpecStateTimedOut:
reporter.stenographer.AnnounceSpecTimedOut(specSummary, reporter.config.Succinct, reporter.config.FullTrace)
case types.SpecStatePanicked:
reporter.stenographer.AnnounceSpecPanicked(specSummary, reporter.config.Succinct, reporter.config.FullTrace)
case types.SpecStateFailed:
reporter.stenographer.AnnounceSpecFailed(specSummary, reporter.config.Succinct, reporter.config.FullTrace)
}
reporter.specSummaries = append(reporter.specSummaries, specSummary)
}
func (reporter *DefaultReporter) SpecSuiteDidEnd(summary *types.SuiteSummary) {
reporter.stenographer.SummarizeFailures(reporter.specSummaries)
reporter.stenographer.AnnounceSpecRunCompletion(summary, reporter.config.Succinct)
}

View File

@@ -0,0 +1,415 @@
package reporters_test
import (
"time"
. "github.com/onsi/ginkgo"
"github.com/onsi/ginkgo/config"
"github.com/onsi/ginkgo/reporters"
st "github.com/onsi/ginkgo/reporters/stenographer"
"github.com/onsi/ginkgo/types"
. "github.com/onsi/gomega"
)
var _ = Describe("DefaultReporter", func() {
var (
reporter *reporters.DefaultReporter
reporterConfig config.DefaultReporterConfigType
stenographer *st.FakeStenographer
ginkgoConfig config.GinkgoConfigType
suite *types.SuiteSummary
spec *types.SpecSummary
)
BeforeEach(func() {
stenographer = st.NewFakeStenographer()
reporterConfig = config.DefaultReporterConfigType{
NoColor: false,
SlowSpecThreshold: 0.1,
NoisyPendings: false,
Verbose: true,
FullTrace: true,
}
reporter = reporters.NewDefaultReporter(reporterConfig, stenographer)
})
call := func(method string, args ...interface{}) st.FakeStenographerCall {
return st.NewFakeStenographerCall(method, args...)
}
Describe("SpecSuiteWillBegin", func() {
BeforeEach(func() {
suite = &types.SuiteSummary{
SuiteDescription: "A Sweet Suite",
NumberOfTotalSpecs: 10,
NumberOfSpecsThatWillBeRun: 8,
}
ginkgoConfig = config.GinkgoConfigType{
RandomSeed: 1138,
RandomizeAllSpecs: true,
}
})
Context("when a serial (non-parallel) suite begins", func() {
BeforeEach(func() {
ginkgoConfig.ParallelTotal = 1
reporter.SpecSuiteWillBegin(ginkgoConfig, suite)
})
It("should announce the suite, then announce the number of specs", func() {
Ω(stenographer.Calls()).Should(HaveLen(2))
Ω(stenographer.Calls()[0]).Should(Equal(call("AnnounceSuite", "A Sweet Suite", ginkgoConfig.RandomSeed, true, false)))
Ω(stenographer.Calls()[1]).Should(Equal(call("AnnounceNumberOfSpecs", 8, 10, false)))
})
})
Context("when a parallel suite begins", func() {
BeforeEach(func() {
ginkgoConfig.ParallelTotal = 2
ginkgoConfig.ParallelNode = 1
suite.NumberOfSpecsBeforeParallelization = 20
reporter.SpecSuiteWillBegin(ginkgoConfig, suite)
})
It("should announce the suite, announce that it's a parallel run, then announce the number of specs", func() {
Ω(stenographer.Calls()).Should(HaveLen(3))
Ω(stenographer.Calls()[0]).Should(Equal(call("AnnounceSuite", "A Sweet Suite", ginkgoConfig.RandomSeed, true, false)))
Ω(stenographer.Calls()[1]).Should(Equal(call("AnnounceParallelRun", 1, 2, 10, 20, false)))
Ω(stenographer.Calls()[2]).Should(Equal(call("AnnounceNumberOfSpecs", 8, 10, false)))
})
})
})
Describe("BeforeSuiteDidRun", func() {
Context("when the BeforeSuite passes", func() {
It("should announce nothing", func() {
reporter.BeforeSuiteDidRun(&types.SetupSummary{
State: types.SpecStatePassed,
})
Ω(stenographer.Calls()).Should(BeEmpty())
})
})
Context("when the BeforeSuite fails", func() {
It("should announce the failure", func() {
summary := &types.SetupSummary{
State: types.SpecStateFailed,
}
reporter.BeforeSuiteDidRun(summary)
Ω(stenographer.Calls()).Should(HaveLen(1))
Ω(stenographer.Calls()[0]).Should(Equal(call("AnnounceBeforeSuiteFailure", summary, false, true)))
})
})
})
Describe("AfterSuiteDidRun", func() {
Context("when the AfterSuite passes", func() {
It("should announce nothing", func() {
reporter.AfterSuiteDidRun(&types.SetupSummary{
State: types.SpecStatePassed,
})
Ω(stenographer.Calls()).Should(BeEmpty())
})
})
Context("when the AfterSuite fails", func() {
It("should announce the failure", func() {
summary := &types.SetupSummary{
State: types.SpecStateFailed,
}
reporter.AfterSuiteDidRun(summary)
Ω(stenographer.Calls()).Should(HaveLen(1))
Ω(stenographer.Calls()[0]).Should(Equal(call("AnnounceAfterSuiteFailure", summary, false, true)))
})
})
})
Describe("SpecWillRun", func() {
Context("When running in verbose mode", func() {
Context("and the spec will run", func() {
BeforeEach(func() {
spec = &types.SpecSummary{}
reporter.SpecWillRun(spec)
})
It("should announce that the spec will run", func() {
Ω(stenographer.Calls()).Should(HaveLen(1))
Ω(stenographer.Calls()[0]).Should(Equal(call("AnnounceSpecWillRun", spec)))
})
})
Context("and the spec will not run", func() {
Context("because it is pending", func() {
BeforeEach(func() {
spec = &types.SpecSummary{
State: types.SpecStatePending,
}
reporter.SpecWillRun(spec)
})
It("should announce nothing", func() {
Ω(stenographer.Calls()).Should(BeEmpty())
})
})
Context("because it is skipped", func() {
BeforeEach(func() {
spec = &types.SpecSummary{
State: types.SpecStateSkipped,
}
reporter.SpecWillRun(spec)
})
It("should announce nothing", func() {
Ω(stenographer.Calls()).Should(BeEmpty())
})
})
})
})
Context("When running in verbose & succinct mode", func() {
BeforeEach(func() {
reporterConfig.Succinct = true
reporter = reporters.NewDefaultReporter(reporterConfig, stenographer)
spec = &types.SpecSummary{}
reporter.SpecWillRun(spec)
})
It("should announce nothing", func() {
Ω(stenographer.Calls()).Should(BeEmpty())
})
})
Context("When not running in verbose mode", func() {
BeforeEach(func() {
reporterConfig.Verbose = false
reporter = reporters.NewDefaultReporter(reporterConfig, stenographer)
spec = &types.SpecSummary{}
reporter.SpecWillRun(spec)
})
It("should announce nothing", func() {
Ω(stenographer.Calls()).Should(BeEmpty())
})
})
})
Describe("SpecDidComplete", func() {
JustBeforeEach(func() {
reporter.SpecDidComplete(spec)
})
BeforeEach(func() {
spec = &types.SpecSummary{}
})
Context("When the spec passed", func() {
BeforeEach(func() {
spec.State = types.SpecStatePassed
})
Context("When the spec was a measurement", func() {
BeforeEach(func() {
spec.IsMeasurement = true
})
It("should announce the measurement", func() {
Ω(stenographer.Calls()[0]).Should(Equal(call("AnnounceSuccesfulMeasurement", spec, false)))
})
})
Context("When the spec is slow", func() {
BeforeEach(func() {
spec.RunTime = time.Second
})
It("should announce that it was slow", func() {
Ω(stenographer.Calls()[0]).Should(Equal(call("AnnounceSuccesfulSlowSpec", spec, false)))
})
})
Context("Otherwise", func() {
It("should announce the succesful spec", func() {
Ω(stenographer.Calls()[0]).Should(Equal(call("AnnounceSuccesfulSpec", spec)))
})
})
})
Context("When the spec is pending", func() {
BeforeEach(func() {
spec.State = types.SpecStatePending
})
It("should announce the pending spec, succinctly", func() {
Ω(stenographer.Calls()[0]).Should(Equal(call("AnnouncePendingSpec", spec, false)))
})
})
Context("When the spec is skipped", func() {
BeforeEach(func() {
spec.State = types.SpecStateSkipped
})
It("should announce the skipped spec", func() {
Ω(stenographer.Calls()[0]).Should(Equal(call("AnnounceSkippedSpec", spec, false, true)))
})
})
Context("When the spec timed out", func() {
BeforeEach(func() {
spec.State = types.SpecStateTimedOut
})
It("should announce the timedout spec", func() {
Ω(stenographer.Calls()[0]).Should(Equal(call("AnnounceSpecTimedOut", spec, false, true)))
})
})
Context("When the spec panicked", func() {
BeforeEach(func() {
spec.State = types.SpecStatePanicked
})
It("should announce the panicked spec", func() {
Ω(stenographer.Calls()[0]).Should(Equal(call("AnnounceSpecPanicked", spec, false, true)))
})
})
Context("When the spec failed", func() {
BeforeEach(func() {
spec.State = types.SpecStateFailed
})
It("should announce the failed spec", func() {
Ω(stenographer.Calls()[0]).Should(Equal(call("AnnounceSpecFailed", spec, false, true)))
})
})
Context("in noisy pendings mode", func() {
BeforeEach(func() {
reporterConfig.Succinct = false
reporterConfig.NoisyPendings = true
reporter = reporters.NewDefaultReporter(reporterConfig, stenographer)
})
Context("When the spec is pending", func() {
BeforeEach(func() {
spec.State = types.SpecStatePending
})
It("should announce the pending spec, noisily", func() {
Ω(stenographer.Calls()[0]).Should(Equal(call("AnnouncePendingSpec", spec, true)))
})
})
})
Context("in succinct mode", func() {
BeforeEach(func() {
reporterConfig.Succinct = true
reporter = reporters.NewDefaultReporter(reporterConfig, stenographer)
})
Context("When the spec passed", func() {
BeforeEach(func() {
spec.State = types.SpecStatePassed
})
Context("When the spec was a measurement", func() {
BeforeEach(func() {
spec.IsMeasurement = true
})
It("should announce the measurement", func() {
Ω(stenographer.Calls()[0]).Should(Equal(call("AnnounceSuccesfulMeasurement", spec, true)))
})
})
Context("When the spec is slow", func() {
BeforeEach(func() {
spec.RunTime = time.Second
})
It("should announce that it was slow", func() {
Ω(stenographer.Calls()[0]).Should(Equal(call("AnnounceSuccesfulSlowSpec", spec, true)))
})
})
Context("Otherwise", func() {
It("should announce the succesful spec", func() {
Ω(stenographer.Calls()[0]).Should(Equal(call("AnnounceSuccesfulSpec", spec)))
})
})
})
Context("When the spec is pending", func() {
BeforeEach(func() {
spec.State = types.SpecStatePending
})
It("should announce the pending spec, succinctly", func() {
Ω(stenographer.Calls()[0]).Should(Equal(call("AnnouncePendingSpec", spec, false)))
})
})
Context("When the spec is skipped", func() {
BeforeEach(func() {
spec.State = types.SpecStateSkipped
})
It("should announce the skipped spec", func() {
Ω(stenographer.Calls()[0]).Should(Equal(call("AnnounceSkippedSpec", spec, true, true)))
})
})
Context("When the spec timed out", func() {
BeforeEach(func() {
spec.State = types.SpecStateTimedOut
})
It("should announce the timedout spec", func() {
Ω(stenographer.Calls()[0]).Should(Equal(call("AnnounceSpecTimedOut", spec, true, true)))
})
})
Context("When the spec panicked", func() {
BeforeEach(func() {
spec.State = types.SpecStatePanicked
})
It("should announce the panicked spec", func() {
Ω(stenographer.Calls()[0]).Should(Equal(call("AnnounceSpecPanicked", spec, true, true)))
})
})
Context("When the spec failed", func() {
BeforeEach(func() {
spec.State = types.SpecStateFailed
})
It("should announce the failed spec", func() {
Ω(stenographer.Calls()[0]).Should(Equal(call("AnnounceSpecFailed", spec, true, true)))
})
})
})
})
Describe("SpecSuiteDidEnd", func() {
BeforeEach(func() {
suite = &types.SuiteSummary{}
reporter.SpecSuiteDidEnd(suite)
})
It("should announce the spec run's completion", func() {
Ω(stenographer.Calls()[1]).Should(Equal(call("AnnounceSpecRunCompletion", suite, false)))
})
})
})

View File

@@ -0,0 +1,59 @@
package reporters
import (
"github.com/onsi/ginkgo/config"
"github.com/onsi/ginkgo/types"
)
//FakeReporter is useful for testing purposes
type FakeReporter struct {
Config config.GinkgoConfigType
BeginSummary *types.SuiteSummary
BeforeSuiteSummary *types.SetupSummary
SpecWillRunSummaries []*types.SpecSummary
SpecSummaries []*types.SpecSummary
AfterSuiteSummary *types.SetupSummary
EndSummary *types.SuiteSummary
SpecWillRunStub func(specSummary *types.SpecSummary)
SpecDidCompleteStub func(specSummary *types.SpecSummary)
}
func NewFakeReporter() *FakeReporter {
return &FakeReporter{
SpecWillRunSummaries: make([]*types.SpecSummary, 0),
SpecSummaries: make([]*types.SpecSummary, 0),
}
}
func (fakeR *FakeReporter) SpecSuiteWillBegin(config config.GinkgoConfigType, summary *types.SuiteSummary) {
fakeR.Config = config
fakeR.BeginSummary = summary
}
func (fakeR *FakeReporter) BeforeSuiteDidRun(setupSummary *types.SetupSummary) {
fakeR.BeforeSuiteSummary = setupSummary
}
func (fakeR *FakeReporter) SpecWillRun(specSummary *types.SpecSummary) {
if fakeR.SpecWillRunStub != nil {
fakeR.SpecWillRunStub(specSummary)
}
fakeR.SpecWillRunSummaries = append(fakeR.SpecWillRunSummaries, specSummary)
}
func (fakeR *FakeReporter) SpecDidComplete(specSummary *types.SpecSummary) {
if fakeR.SpecDidCompleteStub != nil {
fakeR.SpecDidCompleteStub(specSummary)
}
fakeR.SpecSummaries = append(fakeR.SpecSummaries, specSummary)
}
func (fakeR *FakeReporter) AfterSuiteDidRun(setupSummary *types.SetupSummary) {
fakeR.AfterSuiteSummary = setupSummary
}
func (fakeR *FakeReporter) SpecSuiteDidEnd(summary *types.SuiteSummary) {
fakeR.EndSummary = summary
}

View File

@@ -0,0 +1,139 @@
/*
JUnit XML Reporter for Ginkgo
For usage instructions: http://onsi.github.io/ginkgo/#generating_junit_xml_output
*/
package reporters
import (
"encoding/xml"
"fmt"
"github.com/onsi/ginkgo/config"
"github.com/onsi/ginkgo/types"
"os"
"strings"
)
type JUnitTestSuite struct {
XMLName xml.Name `xml:"testsuite"`
TestCases []JUnitTestCase `xml:"testcase"`
Tests int `xml:"tests,attr"`
Failures int `xml:"failures,attr"`
Time float64 `xml:"time,attr"`
}
type JUnitTestCase struct {
Name string `xml:"name,attr"`
ClassName string `xml:"classname,attr"`
FailureMessage *JUnitFailureMessage `xml:"failure,omitempty"`
Skipped *JUnitSkipped `xml:"skipped,omitempty"`
Time float64 `xml:"time,attr"`
}
type JUnitFailureMessage struct {
Type string `xml:"type,attr"`
Message string `xml:",chardata"`
}
type JUnitSkipped struct {
XMLName xml.Name `xml:"skipped"`
}
type JUnitReporter struct {
suite JUnitTestSuite
filename string
testSuiteName string
}
//NewJUnitReporter creates a new JUnit XML reporter. The XML will be stored in the passed in filename.
func NewJUnitReporter(filename string) *JUnitReporter {
return &JUnitReporter{
filename: filename,
}
}
func (reporter *JUnitReporter) SpecSuiteWillBegin(config config.GinkgoConfigType, summary *types.SuiteSummary) {
reporter.suite = JUnitTestSuite{
Tests: summary.NumberOfSpecsThatWillBeRun,
TestCases: []JUnitTestCase{},
}
reporter.testSuiteName = summary.SuiteDescription
}
func (reporter *JUnitReporter) SpecWillRun(specSummary *types.SpecSummary) {
}
func (reporter *JUnitReporter) BeforeSuiteDidRun(setupSummary *types.SetupSummary) {
reporter.handleSetupSummary("BeforeSuite", setupSummary)
}
func (reporter *JUnitReporter) AfterSuiteDidRun(setupSummary *types.SetupSummary) {
reporter.handleSetupSummary("AfterSuite", setupSummary)
}
func (reporter *JUnitReporter) handleSetupSummary(name string, setupSummary *types.SetupSummary) {
if setupSummary.State != types.SpecStatePassed {
testCase := JUnitTestCase{
Name: name,
ClassName: reporter.testSuiteName,
}
testCase.FailureMessage = &JUnitFailureMessage{
Type: reporter.failureTypeForState(setupSummary.State),
Message: fmt.Sprintf("%s\n%s", setupSummary.Failure.ComponentCodeLocation.String(), setupSummary.Failure.Message),
}
testCase.Time = setupSummary.RunTime.Seconds()
reporter.suite.TestCases = append(reporter.suite.TestCases, testCase)
}
}
func (reporter *JUnitReporter) SpecDidComplete(specSummary *types.SpecSummary) {
testCase := JUnitTestCase{
Name: strings.Join(specSummary.ComponentTexts[1:], " "),
ClassName: reporter.testSuiteName,
}
if specSummary.State == types.SpecStateFailed || specSummary.State == types.SpecStateTimedOut || specSummary.State == types.SpecStatePanicked {
testCase.FailureMessage = &JUnitFailureMessage{
Type: reporter.failureTypeForState(specSummary.State),
Message: fmt.Sprintf("%s\n%s", specSummary.Failure.ComponentCodeLocation.String(), specSummary.Failure.Message),
}
}
if specSummary.State == types.SpecStateSkipped || specSummary.State == types.SpecStatePending {
testCase.Skipped = &JUnitSkipped{}
}
testCase.Time = specSummary.RunTime.Seconds()
reporter.suite.TestCases = append(reporter.suite.TestCases, testCase)
}
func (reporter *JUnitReporter) SpecSuiteDidEnd(summary *types.SuiteSummary) {
reporter.suite.Time = summary.RunTime.Seconds()
reporter.suite.Failures = summary.NumberOfFailedSpecs
file, err := os.Create(reporter.filename)
if err != nil {
fmt.Printf("Failed to create JUnit report file: %s\n\t%s", reporter.filename, err.Error())
}
defer file.Close()
file.WriteString(xml.Header)
encoder := xml.NewEncoder(file)
encoder.Indent(" ", " ")
err = encoder.Encode(reporter.suite)
if err != nil {
fmt.Printf("Failed to generate JUnit report\n\t%s", err.Error())
}
}
func (reporter *JUnitReporter) failureTypeForState(state types.SpecState) string {
switch state {
case types.SpecStateFailed:
return "Failure"
case types.SpecStateTimedOut:
return "Timeout"
case types.SpecStatePanicked:
return "Panic"
default:
return ""
}
}

View File

@@ -0,0 +1,241 @@
package reporters_test
import (
"encoding/xml"
"io/ioutil"
"os"
"time"
. "github.com/onsi/ginkgo"
"github.com/onsi/ginkgo/config"
"github.com/onsi/ginkgo/internal/codelocation"
"github.com/onsi/ginkgo/reporters"
"github.com/onsi/ginkgo/types"
. "github.com/onsi/gomega"
)
var _ = Describe("JUnit Reporter", func() {
var (
outputFile string
reporter Reporter
)
readOutputFile := func() reporters.JUnitTestSuite {
bytes, err := ioutil.ReadFile(outputFile)
Ω(err).ShouldNot(HaveOccurred())
var suite reporters.JUnitTestSuite
err = xml.Unmarshal(bytes, &suite)
Ω(err).ShouldNot(HaveOccurred())
return suite
}
BeforeEach(func() {
f, err := ioutil.TempFile("", "output")
Ω(err).ShouldNot(HaveOccurred())
f.Close()
outputFile = f.Name()
reporter = reporters.NewJUnitReporter(outputFile)
reporter.SpecSuiteWillBegin(config.GinkgoConfigType{}, &types.SuiteSummary{
SuiteDescription: "My test suite",
NumberOfSpecsThatWillBeRun: 1,
})
})
AfterEach(func() {
os.RemoveAll(outputFile)
})
Describe("a passing test", func() {
BeforeEach(func() {
beforeSuite := &types.SetupSummary{
State: types.SpecStatePassed,
}
reporter.BeforeSuiteDidRun(beforeSuite)
afterSuite := &types.SetupSummary{
State: types.SpecStatePassed,
}
reporter.AfterSuiteDidRun(afterSuite)
spec := &types.SpecSummary{
ComponentTexts: []string{"[Top Level]", "A", "B", "C"},
State: types.SpecStatePassed,
RunTime: 5 * time.Second,
}
reporter.SpecWillRun(spec)
reporter.SpecDidComplete(spec)
reporter.SpecSuiteDidEnd(&types.SuiteSummary{
NumberOfSpecsThatWillBeRun: 1,
NumberOfFailedSpecs: 0,
RunTime: 10 * time.Second,
})
})
It("should record the test as passing", func() {
output := readOutputFile()
Ω(output.Tests).Should(Equal(1))
Ω(output.Failures).Should(Equal(0))
Ω(output.Time).Should(Equal(10.0))
Ω(output.TestCases).Should(HaveLen(1))
Ω(output.TestCases[0].Name).Should(Equal("A B C"))
Ω(output.TestCases[0].ClassName).Should(Equal("My test suite"))
Ω(output.TestCases[0].FailureMessage).Should(BeNil())
Ω(output.TestCases[0].Skipped).Should(BeNil())
Ω(output.TestCases[0].Time).Should(Equal(5.0))
})
})
Describe("when the BeforeSuite fails", func() {
var beforeSuite *types.SetupSummary
BeforeEach(func() {
beforeSuite = &types.SetupSummary{
State: types.SpecStateFailed,
RunTime: 3 * time.Second,
Failure: types.SpecFailure{
Message: "failed to setup",
ComponentCodeLocation: codelocation.New(0),
},
}
reporter.BeforeSuiteDidRun(beforeSuite)
reporter.SpecSuiteDidEnd(&types.SuiteSummary{
NumberOfSpecsThatWillBeRun: 1,
NumberOfFailedSpecs: 1,
RunTime: 10 * time.Second,
})
})
It("should record the test as having failed", func() {
output := readOutputFile()
Ω(output.Tests).Should(Equal(1))
Ω(output.Failures).Should(Equal(1))
Ω(output.Time).Should(Equal(10.0))
Ω(output.TestCases[0].Name).Should(Equal("BeforeSuite"))
Ω(output.TestCases[0].Time).Should(Equal(3.0))
Ω(output.TestCases[0].ClassName).Should(Equal("My test suite"))
Ω(output.TestCases[0].FailureMessage.Type).Should(Equal("Failure"))
Ω(output.TestCases[0].FailureMessage.Message).Should(ContainSubstring("failed to setup"))
Ω(output.TestCases[0].FailureMessage.Message).Should(ContainSubstring(beforeSuite.Failure.ComponentCodeLocation.String()))
Ω(output.TestCases[0].Skipped).Should(BeNil())
})
})
Describe("when the AfterSuite fails", func() {
var afterSuite *types.SetupSummary
BeforeEach(func() {
afterSuite = &types.SetupSummary{
State: types.SpecStateFailed,
RunTime: 3 * time.Second,
Failure: types.SpecFailure{
Message: "failed to setup",
ComponentCodeLocation: codelocation.New(0),
},
}
reporter.AfterSuiteDidRun(afterSuite)
reporter.SpecSuiteDidEnd(&types.SuiteSummary{
NumberOfSpecsThatWillBeRun: 1,
NumberOfFailedSpecs: 1,
RunTime: 10 * time.Second,
})
})
It("should record the test as having failed", func() {
output := readOutputFile()
Ω(output.Tests).Should(Equal(1))
Ω(output.Failures).Should(Equal(1))
Ω(output.Time).Should(Equal(10.0))
Ω(output.TestCases[0].Name).Should(Equal("AfterSuite"))
Ω(output.TestCases[0].Time).Should(Equal(3.0))
Ω(output.TestCases[0].ClassName).Should(Equal("My test suite"))
Ω(output.TestCases[0].FailureMessage.Type).Should(Equal("Failure"))
Ω(output.TestCases[0].FailureMessage.Message).Should(ContainSubstring("failed to setup"))
Ω(output.TestCases[0].FailureMessage.Message).Should(ContainSubstring(afterSuite.Failure.ComponentCodeLocation.String()))
Ω(output.TestCases[0].Skipped).Should(BeNil())
})
})
specStateCases := []struct {
state types.SpecState
message string
}{
{types.SpecStateFailed, "Failure"},
{types.SpecStateTimedOut, "Timeout"},
{types.SpecStatePanicked, "Panic"},
}
for _, specStateCase := range specStateCases {
specStateCase := specStateCase
Describe("a failing test", func() {
var spec *types.SpecSummary
BeforeEach(func() {
spec = &types.SpecSummary{
ComponentTexts: []string{"[Top Level]", "A", "B", "C"},
State: specStateCase.state,
RunTime: 5 * time.Second,
Failure: types.SpecFailure{
ComponentCodeLocation: codelocation.New(0),
Message: "I failed",
},
}
reporter.SpecWillRun(spec)
reporter.SpecDidComplete(spec)
reporter.SpecSuiteDidEnd(&types.SuiteSummary{
NumberOfSpecsThatWillBeRun: 1,
NumberOfFailedSpecs: 1,
RunTime: 10 * time.Second,
})
})
It("should record test as failing", func() {
output := readOutputFile()
Ω(output.Tests).Should(Equal(1))
Ω(output.Failures).Should(Equal(1))
Ω(output.Time).Should(Equal(10.0))
Ω(output.TestCases[0].Name).Should(Equal("A B C"))
Ω(output.TestCases[0].ClassName).Should(Equal("My test suite"))
Ω(output.TestCases[0].FailureMessage.Type).Should(Equal(specStateCase.message))
Ω(output.TestCases[0].FailureMessage.Message).Should(ContainSubstring("I failed"))
Ω(output.TestCases[0].FailureMessage.Message).Should(ContainSubstring(spec.Failure.ComponentCodeLocation.String()))
Ω(output.TestCases[0].Skipped).Should(BeNil())
})
})
}
for _, specStateCase := range []types.SpecState{types.SpecStatePending, types.SpecStateSkipped} {
specStateCase := specStateCase
Describe("a skipped test", func() {
var spec *types.SpecSummary
BeforeEach(func() {
spec = &types.SpecSummary{
ComponentTexts: []string{"[Top Level]", "A", "B", "C"},
State: specStateCase,
RunTime: 5 * time.Second,
}
reporter.SpecWillRun(spec)
reporter.SpecDidComplete(spec)
reporter.SpecSuiteDidEnd(&types.SuiteSummary{
NumberOfSpecsThatWillBeRun: 1,
NumberOfFailedSpecs: 0,
RunTime: 10 * time.Second,
})
})
It("should record test as failing", func() {
output := readOutputFile()
Ω(output.Tests).Should(Equal(1))
Ω(output.Failures).Should(Equal(0))
Ω(output.Time).Should(Equal(10.0))
Ω(output.TestCases[0].Name).Should(Equal("A B C"))
Ω(output.TestCases[0].Skipped).ShouldNot(BeNil())
})
})
}
})

15
vendor/github.com/onsi/ginkgo/reporters/reporter.go generated vendored Normal file
View File

@@ -0,0 +1,15 @@
package reporters
import (
"github.com/onsi/ginkgo/config"
"github.com/onsi/ginkgo/types"
)
type Reporter interface {
SpecSuiteWillBegin(config config.GinkgoConfigType, summary *types.SuiteSummary)
BeforeSuiteDidRun(setupSummary *types.SetupSummary)
SpecWillRun(specSummary *types.SpecSummary)
SpecDidComplete(specSummary *types.SpecSummary)
AfterSuiteDidRun(setupSummary *types.SetupSummary)
SpecSuiteDidEnd(summary *types.SuiteSummary)
}

View File

@@ -0,0 +1,13 @@
package reporters_test
import (
. "github.com/onsi/ginkgo"
. "github.com/onsi/gomega"
"testing"
)
func TestReporters(t *testing.T) {
RegisterFailHandler(Fail)
RunSpecs(t, "Reporters Suite")
}

View File

@@ -0,0 +1,64 @@
package stenographer
import (
"fmt"
"strings"
)
func (s *consoleStenographer) colorize(colorCode string, format string, args ...interface{}) string {
var out string
if len(args) > 0 {
out = fmt.Sprintf(format, args...)
} else {
out = format
}
if s.color {
return fmt.Sprintf("%s%s%s", colorCode, out, defaultStyle)
} else {
return out
}
}
func (s *consoleStenographer) printBanner(text string, bannerCharacter string) {
fmt.Println(text)
fmt.Println(strings.Repeat(bannerCharacter, len(text)))
}
func (s *consoleStenographer) printNewLine() {
fmt.Println("")
}
func (s *consoleStenographer) printDelimiter() {
fmt.Println(s.colorize(grayColor, "%s", strings.Repeat("-", 30)))
}
func (s *consoleStenographer) print(indentation int, format string, args ...interface{}) {
fmt.Print(s.indent(indentation, format, args...))
}
func (s *consoleStenographer) println(indentation int, format string, args ...interface{}) {
fmt.Println(s.indent(indentation, format, args...))
}
func (s *consoleStenographer) indent(indentation int, format string, args ...interface{}) string {
var text string
if len(args) > 0 {
text = fmt.Sprintf(format, args...)
} else {
text = format
}
stringArray := strings.Split(text, "\n")
padding := ""
if indentation >= 0 {
padding = strings.Repeat(" ", indentation)
}
for i, s := range stringArray {
stringArray[i] = fmt.Sprintf("%s%s", padding, s)
}
return strings.Join(stringArray, "\n")
}

View File

@@ -0,0 +1,138 @@
package stenographer
import (
"sync"
"github.com/onsi/ginkgo/types"
)
func NewFakeStenographerCall(method string, args ...interface{}) FakeStenographerCall {
return FakeStenographerCall{
Method: method,
Args: args,
}
}
type FakeStenographer struct {
calls []FakeStenographerCall
lock *sync.Mutex
}
type FakeStenographerCall struct {
Method string
Args []interface{}
}
func NewFakeStenographer() *FakeStenographer {
stenographer := &FakeStenographer{
lock: &sync.Mutex{},
}
stenographer.Reset()
return stenographer
}
func (stenographer *FakeStenographer) Calls() []FakeStenographerCall {
stenographer.lock.Lock()
defer stenographer.lock.Unlock()
return stenographer.calls
}
func (stenographer *FakeStenographer) Reset() {
stenographer.lock.Lock()
defer stenographer.lock.Unlock()
stenographer.calls = make([]FakeStenographerCall, 0)
}
func (stenographer *FakeStenographer) CallsTo(method string) []FakeStenographerCall {
stenographer.lock.Lock()
defer stenographer.lock.Unlock()
results := make([]FakeStenographerCall, 0)
for _, call := range stenographer.calls {
if call.Method == method {
results = append(results, call)
}
}
return results
}
func (stenographer *FakeStenographer) registerCall(method string, args ...interface{}) {
stenographer.lock.Lock()
defer stenographer.lock.Unlock()
stenographer.calls = append(stenographer.calls, NewFakeStenographerCall(method, args...))
}
func (stenographer *FakeStenographer) AnnounceSuite(description string, randomSeed int64, randomizingAll bool, succinct bool) {
stenographer.registerCall("AnnounceSuite", description, randomSeed, randomizingAll, succinct)
}
func (stenographer *FakeStenographer) AnnounceAggregatedParallelRun(nodes int, succinct bool) {
stenographer.registerCall("AnnounceAggregatedParallelRun", nodes, succinct)
}
func (stenographer *FakeStenographer) AnnounceParallelRun(node int, nodes int, specsToRun int, totalSpecs int, succinct bool) {
stenographer.registerCall("AnnounceParallelRun", node, nodes, specsToRun, totalSpecs, succinct)
}
func (stenographer *FakeStenographer) AnnounceNumberOfSpecs(specsToRun int, total int, succinct bool) {
stenographer.registerCall("AnnounceNumberOfSpecs", specsToRun, total, succinct)
}
func (stenographer *FakeStenographer) AnnounceSpecRunCompletion(summary *types.SuiteSummary, succinct bool) {
stenographer.registerCall("AnnounceSpecRunCompletion", summary, succinct)
}
func (stenographer *FakeStenographer) AnnounceSpecWillRun(spec *types.SpecSummary) {
stenographer.registerCall("AnnounceSpecWillRun", spec)
}
func (stenographer *FakeStenographer) AnnounceBeforeSuiteFailure(summary *types.SetupSummary, succinct bool, fullTrace bool) {
stenographer.registerCall("AnnounceBeforeSuiteFailure", summary, succinct, fullTrace)
}
func (stenographer *FakeStenographer) AnnounceAfterSuiteFailure(summary *types.SetupSummary, succinct bool, fullTrace bool) {
stenographer.registerCall("AnnounceAfterSuiteFailure", summary, succinct, fullTrace)
}
func (stenographer *FakeStenographer) AnnounceCapturedOutput(output string) {
stenographer.registerCall("AnnounceCapturedOutput", output)
}
func (stenographer *FakeStenographer) AnnounceSuccesfulSpec(spec *types.SpecSummary) {
stenographer.registerCall("AnnounceSuccesfulSpec", spec)
}
func (stenographer *FakeStenographer) AnnounceSuccesfulSlowSpec(spec *types.SpecSummary, succinct bool) {
stenographer.registerCall("AnnounceSuccesfulSlowSpec", spec, succinct)
}
func (stenographer *FakeStenographer) AnnounceSuccesfulMeasurement(spec *types.SpecSummary, succinct bool) {
stenographer.registerCall("AnnounceSuccesfulMeasurement", spec, succinct)
}
func (stenographer *FakeStenographer) AnnouncePendingSpec(spec *types.SpecSummary, noisy bool) {
stenographer.registerCall("AnnouncePendingSpec", spec, noisy)
}
func (stenographer *FakeStenographer) AnnounceSkippedSpec(spec *types.SpecSummary, succinct bool, fullTrace bool) {
stenographer.registerCall("AnnounceSkippedSpec", spec, succinct, fullTrace)
}
func (stenographer *FakeStenographer) AnnounceSpecTimedOut(spec *types.SpecSummary, succinct bool, fullTrace bool) {
stenographer.registerCall("AnnounceSpecTimedOut", spec, succinct, fullTrace)
}
func (stenographer *FakeStenographer) AnnounceSpecPanicked(spec *types.SpecSummary, succinct bool, fullTrace bool) {
stenographer.registerCall("AnnounceSpecPanicked", spec, succinct, fullTrace)
}
func (stenographer *FakeStenographer) AnnounceSpecFailed(spec *types.SpecSummary, succinct bool, fullTrace bool) {
stenographer.registerCall("AnnounceSpecFailed", spec, succinct, fullTrace)
}
func (stenographer *FakeStenographer) SummarizeFailures(summaries []*types.SpecSummary) {
stenographer.registerCall("SummarizeFailures", summaries)
}

View File

@@ -0,0 +1,549 @@
/*
The stenographer is used by Ginkgo's reporters to generate output.
Move along, nothing to see here.
*/
package stenographer
import (
"fmt"
"runtime"
"strings"
"github.com/onsi/ginkgo/types"
)
const defaultStyle = "\x1b[0m"
const boldStyle = "\x1b[1m"
const redColor = "\x1b[91m"
const greenColor = "\x1b[32m"
const yellowColor = "\x1b[33m"
const cyanColor = "\x1b[36m"
const grayColor = "\x1b[90m"
const lightGrayColor = "\x1b[37m"
type cursorStateType int
const (
cursorStateTop cursorStateType = iota
cursorStateStreaming
cursorStateMidBlock
cursorStateEndBlock
)
type Stenographer interface {
AnnounceSuite(description string, randomSeed int64, randomizingAll bool, succinct bool)
AnnounceAggregatedParallelRun(nodes int, succinct bool)
AnnounceParallelRun(node int, nodes int, specsToRun int, totalSpecs int, succinct bool)
AnnounceNumberOfSpecs(specsToRun int, total int, succinct bool)
AnnounceSpecRunCompletion(summary *types.SuiteSummary, succinct bool)
AnnounceSpecWillRun(spec *types.SpecSummary)
AnnounceBeforeSuiteFailure(summary *types.SetupSummary, succinct bool, fullTrace bool)
AnnounceAfterSuiteFailure(summary *types.SetupSummary, succinct bool, fullTrace bool)
AnnounceCapturedOutput(output string)
AnnounceSuccesfulSpec(spec *types.SpecSummary)
AnnounceSuccesfulSlowSpec(spec *types.SpecSummary, succinct bool)
AnnounceSuccesfulMeasurement(spec *types.SpecSummary, succinct bool)
AnnouncePendingSpec(spec *types.SpecSummary, noisy bool)
AnnounceSkippedSpec(spec *types.SpecSummary, succinct bool, fullTrace bool)
AnnounceSpecTimedOut(spec *types.SpecSummary, succinct bool, fullTrace bool)
AnnounceSpecPanicked(spec *types.SpecSummary, succinct bool, fullTrace bool)
AnnounceSpecFailed(spec *types.SpecSummary, succinct bool, fullTrace bool)
SummarizeFailures(summaries []*types.SpecSummary)
}
func New(color bool) Stenographer {
denoter := "•"
if runtime.GOOS == "windows" {
denoter = "+"
}
return &consoleStenographer{
color: color,
denoter: denoter,
cursorState: cursorStateTop,
}
}
type consoleStenographer struct {
color bool
denoter string
cursorState cursorStateType
}
var alternatingColors = []string{defaultStyle, grayColor}
func (s *consoleStenographer) AnnounceSuite(description string, randomSeed int64, randomizingAll bool, succinct bool) {
if succinct {
s.print(0, "[%d] %s ", randomSeed, s.colorize(boldStyle, description))
return
}
s.printBanner(fmt.Sprintf("Running Suite: %s", description), "=")
s.print(0, "Random Seed: %s", s.colorize(boldStyle, "%d", randomSeed))
if randomizingAll {
s.print(0, " - Will randomize all specs")
}
s.printNewLine()
}
func (s *consoleStenographer) AnnounceParallelRun(node int, nodes int, specsToRun int, totalSpecs int, succinct bool) {
if succinct {
s.print(0, "- node #%d ", node)
return
}
s.println(0,
"Parallel test node %s/%s. Assigned %s of %s specs.",
s.colorize(boldStyle, "%d", node),
s.colorize(boldStyle, "%d", nodes),
s.colorize(boldStyle, "%d", specsToRun),
s.colorize(boldStyle, "%d", totalSpecs),
)
s.printNewLine()
}
func (s *consoleStenographer) AnnounceAggregatedParallelRun(nodes int, succinct bool) {
if succinct {
s.print(0, "- %d nodes ", nodes)
return
}
s.println(0,
"Running in parallel across %s nodes",
s.colorize(boldStyle, "%d", nodes),
)
s.printNewLine()
}
func (s *consoleStenographer) AnnounceNumberOfSpecs(specsToRun int, total int, succinct bool) {
if succinct {
s.print(0, "- %d/%d specs ", specsToRun, total)
s.stream()
return
}
s.println(0,
"Will run %s of %s specs",
s.colorize(boldStyle, "%d", specsToRun),
s.colorize(boldStyle, "%d", total),
)
s.printNewLine()
}
func (s *consoleStenographer) AnnounceSpecRunCompletion(summary *types.SuiteSummary, succinct bool) {
if succinct && summary.SuiteSucceeded {
s.print(0, " %s %s ", s.colorize(greenColor, "SUCCESS!"), summary.RunTime)
return
}
s.printNewLine()
color := greenColor
if !summary.SuiteSucceeded {
color = redColor
}
s.println(0, s.colorize(boldStyle+color, "Ran %d of %d Specs in %.3f seconds", summary.NumberOfSpecsThatWillBeRun, summary.NumberOfTotalSpecs, summary.RunTime.Seconds()))
status := ""
if summary.SuiteSucceeded {
status = s.colorize(boldStyle+greenColor, "SUCCESS!")
} else {
status = s.colorize(boldStyle+redColor, "FAIL!")
}
s.print(0,
"%s -- %s | %s | %s | %s ",
status,
s.colorize(greenColor+boldStyle, "%d Passed", summary.NumberOfPassedSpecs),
s.colorize(redColor+boldStyle, "%d Failed", summary.NumberOfFailedSpecs),
s.colorize(yellowColor+boldStyle, "%d Pending", summary.NumberOfPendingSpecs),
s.colorize(cyanColor+boldStyle, "%d Skipped", summary.NumberOfSkippedSpecs),
)
}
func (s *consoleStenographer) AnnounceSpecWillRun(spec *types.SpecSummary) {
s.startBlock()
for i, text := range spec.ComponentTexts[1 : len(spec.ComponentTexts)-1] {
s.print(0, s.colorize(alternatingColors[i%2], text)+" ")
}
indentation := 0
if len(spec.ComponentTexts) > 2 {
indentation = 1
s.printNewLine()
}
index := len(spec.ComponentTexts) - 1
s.print(indentation, s.colorize(boldStyle, spec.ComponentTexts[index]))
s.printNewLine()
s.print(indentation, s.colorize(lightGrayColor, spec.ComponentCodeLocations[index].String()))
s.printNewLine()
s.midBlock()
}
func (s *consoleStenographer) AnnounceBeforeSuiteFailure(summary *types.SetupSummary, succinct bool, fullTrace bool) {
s.announceSetupFailure("BeforeSuite", summary, succinct, fullTrace)
}
func (s *consoleStenographer) AnnounceAfterSuiteFailure(summary *types.SetupSummary, succinct bool, fullTrace bool) {
s.announceSetupFailure("AfterSuite", summary, succinct, fullTrace)
}
func (s *consoleStenographer) announceSetupFailure(name string, summary *types.SetupSummary, succinct bool, fullTrace bool) {
s.startBlock()
var message string
switch summary.State {
case types.SpecStateFailed:
message = "Failure"
case types.SpecStatePanicked:
message = "Panic"
case types.SpecStateTimedOut:
message = "Timeout"
}
s.println(0, s.colorize(redColor+boldStyle, "%s [%.3f seconds]", message, summary.RunTime.Seconds()))
indentation := s.printCodeLocationBlock([]string{name}, []types.CodeLocation{summary.CodeLocation}, summary.ComponentType, 0, summary.State, true)
s.printNewLine()
s.printFailure(indentation, summary.State, summary.Failure, fullTrace)
s.endBlock()
}
func (s *consoleStenographer) AnnounceCapturedOutput(output string) {
if output == "" {
return
}
s.startBlock()
s.println(0, output)
s.midBlock()
}
func (s *consoleStenographer) AnnounceSuccesfulSpec(spec *types.SpecSummary) {
s.print(0, s.colorize(greenColor, s.denoter))
s.stream()
}
func (s *consoleStenographer) AnnounceSuccesfulSlowSpec(spec *types.SpecSummary, succinct bool) {
s.printBlockWithMessage(
s.colorize(greenColor, "%s [SLOW TEST:%.3f seconds]", s.denoter, spec.RunTime.Seconds()),
"",
spec,
succinct,
)
}
func (s *consoleStenographer) AnnounceSuccesfulMeasurement(spec *types.SpecSummary, succinct bool) {
s.printBlockWithMessage(
s.colorize(greenColor, "%s [MEASUREMENT]", s.denoter),
s.measurementReport(spec, succinct),
spec,
succinct,
)
}
func (s *consoleStenographer) AnnouncePendingSpec(spec *types.SpecSummary, noisy bool) {
if noisy {
s.printBlockWithMessage(
s.colorize(yellowColor, "P [PENDING]"),
"",
spec,
false,
)
} else {
s.print(0, s.colorize(yellowColor, "P"))
s.stream()
}
}
func (s *consoleStenographer) AnnounceSkippedSpec(spec *types.SpecSummary, succinct bool, fullTrace bool) {
// Skips at runtime will have a non-empty spec.Failure. All others should be succinct.
if succinct || spec.Failure == (types.SpecFailure{}) {
s.print(0, s.colorize(cyanColor, "S"))
s.stream()
} else {
s.startBlock()
s.println(0, s.colorize(cyanColor+boldStyle, "S [SKIPPING]%s [%.3f seconds]", s.failureContext(spec.Failure.ComponentType), spec.RunTime.Seconds()))
indentation := s.printCodeLocationBlock(spec.ComponentTexts, spec.ComponentCodeLocations, spec.Failure.ComponentType, spec.Failure.ComponentIndex, spec.State, succinct)
s.printNewLine()
s.printSkip(indentation, spec.Failure)
s.endBlock()
}
}
func (s *consoleStenographer) AnnounceSpecTimedOut(spec *types.SpecSummary, succinct bool, fullTrace bool) {
s.printSpecFailure(fmt.Sprintf("%s... Timeout", s.denoter), spec, succinct, fullTrace)
}
func (s *consoleStenographer) AnnounceSpecPanicked(spec *types.SpecSummary, succinct bool, fullTrace bool) {
s.printSpecFailure(fmt.Sprintf("%s! Panic", s.denoter), spec, succinct, fullTrace)
}
func (s *consoleStenographer) AnnounceSpecFailed(spec *types.SpecSummary, succinct bool, fullTrace bool) {
s.printSpecFailure(fmt.Sprintf("%s Failure", s.denoter), spec, succinct, fullTrace)
}
func (s *consoleStenographer) SummarizeFailures(summaries []*types.SpecSummary) {
failingSpecs := []*types.SpecSummary{}
for _, summary := range summaries {
if summary.HasFailureState() {
failingSpecs = append(failingSpecs, summary)
}
}
if len(failingSpecs) == 0 {
return
}
s.printNewLine()
s.printNewLine()
plural := "s"
if len(failingSpecs) == 1 {
plural = ""
}
s.println(0, s.colorize(redColor+boldStyle, "Summarizing %d Failure%s:", len(failingSpecs), plural))
for _, summary := range failingSpecs {
s.printNewLine()
if summary.HasFailureState() {
if summary.TimedOut() {
s.print(0, s.colorize(redColor+boldStyle, "[Timeout...] "))
} else if summary.Panicked() {
s.print(0, s.colorize(redColor+boldStyle, "[Panic!] "))
} else if summary.Failed() {
s.print(0, s.colorize(redColor+boldStyle, "[Fail] "))
}
s.printSpecContext(summary.ComponentTexts, summary.ComponentCodeLocations, summary.Failure.ComponentType, summary.Failure.ComponentIndex, summary.State, true)
s.printNewLine()
s.println(0, s.colorize(lightGrayColor, summary.Failure.Location.String()))
}
}
}
func (s *consoleStenographer) startBlock() {
if s.cursorState == cursorStateStreaming {
s.printNewLine()
s.printDelimiter()
} else if s.cursorState == cursorStateMidBlock {
s.printNewLine()
}
}
func (s *consoleStenographer) midBlock() {
s.cursorState = cursorStateMidBlock
}
func (s *consoleStenographer) endBlock() {
s.printDelimiter()
s.cursorState = cursorStateEndBlock
}
func (s *consoleStenographer) stream() {
s.cursorState = cursorStateStreaming
}
func (s *consoleStenographer) printBlockWithMessage(header string, message string, spec *types.SpecSummary, succinct bool) {
s.startBlock()
s.println(0, header)
indentation := s.printCodeLocationBlock(spec.ComponentTexts, spec.ComponentCodeLocations, types.SpecComponentTypeInvalid, 0, spec.State, succinct)
if message != "" {
s.printNewLine()
s.println(indentation, message)
}
s.endBlock()
}
func (s *consoleStenographer) printSpecFailure(message string, spec *types.SpecSummary, succinct bool, fullTrace bool) {
s.startBlock()
s.println(0, s.colorize(redColor+boldStyle, "%s%s [%.3f seconds]", message, s.failureContext(spec.Failure.ComponentType), spec.RunTime.Seconds()))
indentation := s.printCodeLocationBlock(spec.ComponentTexts, spec.ComponentCodeLocations, spec.Failure.ComponentType, spec.Failure.ComponentIndex, spec.State, succinct)
s.printNewLine()
s.printFailure(indentation, spec.State, spec.Failure, fullTrace)
s.endBlock()
}
func (s *consoleStenographer) failureContext(failedComponentType types.SpecComponentType) string {
switch failedComponentType {
case types.SpecComponentTypeBeforeSuite:
return " in Suite Setup (BeforeSuite)"
case types.SpecComponentTypeAfterSuite:
return " in Suite Teardown (AfterSuite)"
case types.SpecComponentTypeBeforeEach:
return " in Spec Setup (BeforeEach)"
case types.SpecComponentTypeJustBeforeEach:
return " in Spec Setup (JustBeforeEach)"
case types.SpecComponentTypeAfterEach:
return " in Spec Teardown (AfterEach)"
}
return ""
}
func (s *consoleStenographer) printSkip(indentation int, spec types.SpecFailure) {
s.println(indentation, s.colorize(cyanColor, spec.Message))
s.printNewLine()
s.println(indentation, spec.Location.String())
}
func (s *consoleStenographer) printFailure(indentation int, state types.SpecState, failure types.SpecFailure, fullTrace bool) {
if state == types.SpecStatePanicked {
s.println(indentation, s.colorize(redColor+boldStyle, failure.Message))
s.println(indentation, s.colorize(redColor, failure.ForwardedPanic))
s.println(indentation, failure.Location.String())
s.printNewLine()
s.println(indentation, s.colorize(redColor, "Full Stack Trace"))
s.println(indentation, failure.Location.FullStackTrace)
} else {
s.println(indentation, s.colorize(redColor, failure.Message))
s.printNewLine()
s.println(indentation, failure.Location.String())
if fullTrace {
s.printNewLine()
s.println(indentation, s.colorize(redColor, "Full Stack Trace"))
s.println(indentation, failure.Location.FullStackTrace)
}
}
}
func (s *consoleStenographer) printSpecContext(componentTexts []string, componentCodeLocations []types.CodeLocation, failedComponentType types.SpecComponentType, failedComponentIndex int, state types.SpecState, succinct bool) int {
startIndex := 1
indentation := 0
if len(componentTexts) == 1 {
startIndex = 0
}
for i := startIndex; i < len(componentTexts); i++ {
if (state.IsFailure() || state == types.SpecStateSkipped) && i == failedComponentIndex {
color := redColor
if state == types.SpecStateSkipped {
color = cyanColor
}
blockType := ""
switch failedComponentType {
case types.SpecComponentTypeBeforeSuite:
blockType = "BeforeSuite"
case types.SpecComponentTypeAfterSuite:
blockType = "AfterSuite"
case types.SpecComponentTypeBeforeEach:
blockType = "BeforeEach"
case types.SpecComponentTypeJustBeforeEach:
blockType = "JustBeforeEach"
case types.SpecComponentTypeAfterEach:
blockType = "AfterEach"
case types.SpecComponentTypeIt:
blockType = "It"
case types.SpecComponentTypeMeasure:
blockType = "Measurement"
}
if succinct {
s.print(0, s.colorize(color+boldStyle, "[%s] %s ", blockType, componentTexts[i]))
} else {
s.println(indentation, s.colorize(color+boldStyle, "%s [%s]", componentTexts[i], blockType))
s.println(indentation, s.colorize(grayColor, "%s", componentCodeLocations[i]))
}
} else {
if succinct {
s.print(0, s.colorize(alternatingColors[i%2], "%s ", componentTexts[i]))
} else {
s.println(indentation, componentTexts[i])
s.println(indentation, s.colorize(grayColor, "%s", componentCodeLocations[i]))
}
}
indentation++
}
return indentation
}
func (s *consoleStenographer) printCodeLocationBlock(componentTexts []string, componentCodeLocations []types.CodeLocation, failedComponentType types.SpecComponentType, failedComponentIndex int, state types.SpecState, succinct bool) int {
indentation := s.printSpecContext(componentTexts, componentCodeLocations, failedComponentType, failedComponentIndex, state, succinct)
if succinct {
if len(componentTexts) > 0 {
s.printNewLine()
s.print(0, s.colorize(lightGrayColor, "%s", componentCodeLocations[len(componentCodeLocations)-1]))
}
s.printNewLine()
indentation = 1
} else {
indentation--
}
return indentation
}
func (s *consoleStenographer) orderedMeasurementKeys(measurements map[string]*types.SpecMeasurement) []string {
orderedKeys := make([]string, len(measurements))
for key, measurement := range measurements {
orderedKeys[measurement.Order] = key
}
return orderedKeys
}
func (s *consoleStenographer) measurementReport(spec *types.SpecSummary, succinct bool) string {
if len(spec.Measurements) == 0 {
return "Found no measurements"
}
message := []string{}
orderedKeys := s.orderedMeasurementKeys(spec.Measurements)
if succinct {
message = append(message, fmt.Sprintf("%s samples:", s.colorize(boldStyle, "%d", spec.NumberOfSamples)))
for _, key := range orderedKeys {
measurement := spec.Measurements[key]
message = append(message, fmt.Sprintf(" %s - %s: %s%s, %s: %s%s ± %s%s, %s: %s%s",
s.colorize(boldStyle, "%s", measurement.Name),
measurement.SmallestLabel,
s.colorize(greenColor, "%.3f", measurement.Smallest),
measurement.Units,
measurement.AverageLabel,
s.colorize(cyanColor, "%.3f", measurement.Average),
measurement.Units,
s.colorize(cyanColor, "%.3f", measurement.StdDeviation),
measurement.Units,
measurement.LargestLabel,
s.colorize(redColor, "%.3f", measurement.Largest),
measurement.Units,
))
}
} else {
message = append(message, fmt.Sprintf("Ran %s samples:", s.colorize(boldStyle, "%d", spec.NumberOfSamples)))
for _, key := range orderedKeys {
measurement := spec.Measurements[key]
info := ""
if measurement.Info != nil {
message = append(message, fmt.Sprintf("%v", measurement.Info))
}
message = append(message, fmt.Sprintf("%s:\n%s %s: %s%s\n %s: %s%s\n %s: %s%s ± %s%s",
s.colorize(boldStyle, "%s", measurement.Name),
info,
measurement.SmallestLabel,
s.colorize(greenColor, "%.3f", measurement.Smallest),
measurement.Units,
measurement.LargestLabel,
s.colorize(redColor, "%.3f", measurement.Largest),
measurement.Units,
measurement.AverageLabel,
s.colorize(cyanColor, "%.3f", measurement.Average),
measurement.Units,
s.colorize(cyanColor, "%.3f", measurement.StdDeviation),
measurement.Units,
))
}
}
return strings.Join(message, "\n")
}

View File

@@ -0,0 +1,92 @@
/*
TeamCity Reporter for Ginkgo
Makes use of TeamCity's support for Service Messages
http://confluence.jetbrains.com/display/TCD7/Build+Script+Interaction+with+TeamCity#BuildScriptInteractionwithTeamCity-ReportingTests
*/
package reporters
import (
"fmt"
"github.com/onsi/ginkgo/config"
"github.com/onsi/ginkgo/types"
"io"
"strings"
)
const (
messageId = "##teamcity"
)
type TeamCityReporter struct {
writer io.Writer
testSuiteName string
}
func NewTeamCityReporter(writer io.Writer) *TeamCityReporter {
return &TeamCityReporter{
writer: writer,
}
}
func (reporter *TeamCityReporter) SpecSuiteWillBegin(config config.GinkgoConfigType, summary *types.SuiteSummary) {
reporter.testSuiteName = escape(summary.SuiteDescription)
fmt.Fprintf(reporter.writer, "%s[testSuiteStarted name='%s']", messageId, reporter.testSuiteName)
}
func (reporter *TeamCityReporter) BeforeSuiteDidRun(setupSummary *types.SetupSummary) {
reporter.handleSetupSummary("BeforeSuite", setupSummary)
}
func (reporter *TeamCityReporter) AfterSuiteDidRun(setupSummary *types.SetupSummary) {
reporter.handleSetupSummary("AfterSuite", setupSummary)
}
func (reporter *TeamCityReporter) handleSetupSummary(name string, setupSummary *types.SetupSummary) {
if setupSummary.State != types.SpecStatePassed {
testName := escape(name)
fmt.Fprintf(reporter.writer, "%s[testStarted name='%s']", messageId, testName)
message := escape(setupSummary.Failure.ComponentCodeLocation.String())
details := escape(setupSummary.Failure.Message)
fmt.Fprintf(reporter.writer, "%s[testFailed name='%s' message='%s' details='%s']", messageId, testName, message, details)
durationInMilliseconds := setupSummary.RunTime.Seconds() * 1000
fmt.Fprintf(reporter.writer, "%s[testFinished name='%s' duration='%v']", messageId, testName, durationInMilliseconds)
}
}
func (reporter *TeamCityReporter) SpecWillRun(specSummary *types.SpecSummary) {
testName := escape(strings.Join(specSummary.ComponentTexts[1:], " "))
fmt.Fprintf(reporter.writer, "%s[testStarted name='%s']", messageId, testName)
}
func (reporter *TeamCityReporter) SpecDidComplete(specSummary *types.SpecSummary) {
testName := escape(strings.Join(specSummary.ComponentTexts[1:], " "))
if specSummary.State == types.SpecStateFailed || specSummary.State == types.SpecStateTimedOut || specSummary.State == types.SpecStatePanicked {
message := escape(specSummary.Failure.ComponentCodeLocation.String())
details := escape(specSummary.Failure.Message)
fmt.Fprintf(reporter.writer, "%s[testFailed name='%s' message='%s' details='%s']", messageId, testName, message, details)
}
if specSummary.State == types.SpecStateSkipped || specSummary.State == types.SpecStatePending {
fmt.Fprintf(reporter.writer, "%s[testIgnored name='%s']", messageId, testName)
}
durationInMilliseconds := specSummary.RunTime.Seconds() * 1000
fmt.Fprintf(reporter.writer, "%s[testFinished name='%s' duration='%v']", messageId, testName, durationInMilliseconds)
}
func (reporter *TeamCityReporter) SpecSuiteDidEnd(summary *types.SuiteSummary) {
fmt.Fprintf(reporter.writer, "%s[testSuiteFinished name='%s']", messageId, reporter.testSuiteName)
}
func escape(output string) string {
output = strings.Replace(output, "|", "||", -1)
output = strings.Replace(output, "'", "|'", -1)
output = strings.Replace(output, "\n", "|n", -1)
output = strings.Replace(output, "\r", "|r", -1)
output = strings.Replace(output, "[", "|[", -1)
output = strings.Replace(output, "]", "|]", -1)
return output
}

View File

@@ -0,0 +1,213 @@
package reporters_test
import (
"bytes"
"fmt"
. "github.com/onsi/ginkgo"
"github.com/onsi/ginkgo/config"
"github.com/onsi/ginkgo/internal/codelocation"
"github.com/onsi/ginkgo/reporters"
"github.com/onsi/ginkgo/types"
. "github.com/onsi/gomega"
"time"
)
var _ = Describe("TeamCity Reporter", func() {
var (
buffer bytes.Buffer
reporter Reporter
)
BeforeEach(func() {
buffer.Truncate(0)
reporter = reporters.NewTeamCityReporter(&buffer)
reporter.SpecSuiteWillBegin(config.GinkgoConfigType{}, &types.SuiteSummary{
SuiteDescription: "Foo's test suite",
NumberOfSpecsThatWillBeRun: 1,
})
})
Describe("a passing test", func() {
BeforeEach(func() {
beforeSuite := &types.SetupSummary{
State: types.SpecStatePassed,
}
reporter.BeforeSuiteDidRun(beforeSuite)
afterSuite := &types.SetupSummary{
State: types.SpecStatePassed,
}
reporter.AfterSuiteDidRun(afterSuite)
spec := &types.SpecSummary{
ComponentTexts: []string{"[Top Level]", "A", "B", "C"},
State: types.SpecStatePassed,
RunTime: 5 * time.Second,
}
reporter.SpecWillRun(spec)
reporter.SpecDidComplete(spec)
reporter.SpecSuiteDidEnd(&types.SuiteSummary{
NumberOfSpecsThatWillBeRun: 1,
NumberOfFailedSpecs: 0,
RunTime: 10 * time.Second,
})
})
It("should record the test as passing", func() {
actual := buffer.String()
expected :=
"##teamcity[testSuiteStarted name='Foo|'s test suite']" +
"##teamcity[testStarted name='A B C']" +
"##teamcity[testFinished name='A B C' duration='5000']" +
"##teamcity[testSuiteFinished name='Foo|'s test suite']"
Ω(actual).Should(Equal(expected))
})
})
Describe("when the BeforeSuite fails", func() {
var beforeSuite *types.SetupSummary
BeforeEach(func() {
beforeSuite = &types.SetupSummary{
State: types.SpecStateFailed,
RunTime: 3 * time.Second,
Failure: types.SpecFailure{
Message: "failed to setup\n",
ComponentCodeLocation: codelocation.New(0),
},
}
reporter.BeforeSuiteDidRun(beforeSuite)
reporter.SpecSuiteDidEnd(&types.SuiteSummary{
NumberOfSpecsThatWillBeRun: 1,
NumberOfFailedSpecs: 1,
RunTime: 10 * time.Second,
})
})
It("should record the test as having failed", func() {
actual := buffer.String()
expected := fmt.Sprintf(
"##teamcity[testSuiteStarted name='Foo|'s test suite']"+
"##teamcity[testStarted name='BeforeSuite']"+
"##teamcity[testFailed name='BeforeSuite' message='%s' details='failed to setup|n']"+
"##teamcity[testFinished name='BeforeSuite' duration='3000']"+
"##teamcity[testSuiteFinished name='Foo|'s test suite']", beforeSuite.Failure.ComponentCodeLocation.String(),
)
Ω(actual).Should(Equal(expected))
})
})
Describe("when the AfterSuite fails", func() {
var afterSuite *types.SetupSummary
BeforeEach(func() {
afterSuite = &types.SetupSummary{
State: types.SpecStateFailed,
RunTime: 3 * time.Second,
Failure: types.SpecFailure{
Message: "failed to setup\n",
ComponentCodeLocation: codelocation.New(0),
},
}
reporter.AfterSuiteDidRun(afterSuite)
reporter.SpecSuiteDidEnd(&types.SuiteSummary{
NumberOfSpecsThatWillBeRun: 1,
NumberOfFailedSpecs: 1,
RunTime: 10 * time.Second,
})
})
It("should record the test as having failed", func() {
actual := buffer.String()
expected := fmt.Sprintf(
"##teamcity[testSuiteStarted name='Foo|'s test suite']"+
"##teamcity[testStarted name='AfterSuite']"+
"##teamcity[testFailed name='AfterSuite' message='%s' details='failed to setup|n']"+
"##teamcity[testFinished name='AfterSuite' duration='3000']"+
"##teamcity[testSuiteFinished name='Foo|'s test suite']", afterSuite.Failure.ComponentCodeLocation.String(),
)
Ω(actual).Should(Equal(expected))
})
})
specStateCases := []struct {
state types.SpecState
message string
}{
{types.SpecStateFailed, "Failure"},
{types.SpecStateTimedOut, "Timeout"},
{types.SpecStatePanicked, "Panic"},
}
for _, specStateCase := range specStateCases {
specStateCase := specStateCase
Describe("a failing test", func() {
var spec *types.SpecSummary
BeforeEach(func() {
spec = &types.SpecSummary{
ComponentTexts: []string{"[Top Level]", "A", "B", "C"},
State: specStateCase.state,
RunTime: 5 * time.Second,
Failure: types.SpecFailure{
ComponentCodeLocation: codelocation.New(0),
Message: "I failed",
},
}
reporter.SpecWillRun(spec)
reporter.SpecDidComplete(spec)
reporter.SpecSuiteDidEnd(&types.SuiteSummary{
NumberOfSpecsThatWillBeRun: 1,
NumberOfFailedSpecs: 1,
RunTime: 10 * time.Second,
})
})
It("should record test as failing", func() {
actual := buffer.String()
expected :=
fmt.Sprintf("##teamcity[testSuiteStarted name='Foo|'s test suite']"+
"##teamcity[testStarted name='A B C']"+
"##teamcity[testFailed name='A B C' message='%s' details='I failed']"+
"##teamcity[testFinished name='A B C' duration='5000']"+
"##teamcity[testSuiteFinished name='Foo|'s test suite']", spec.Failure.ComponentCodeLocation.String())
Ω(actual).Should(Equal(expected))
})
})
}
for _, specStateCase := range []types.SpecState{types.SpecStatePending, types.SpecStateSkipped} {
specStateCase := specStateCase
Describe("a skipped test", func() {
var spec *types.SpecSummary
BeforeEach(func() {
spec = &types.SpecSummary{
ComponentTexts: []string{"[Top Level]", "A", "B", "C"},
State: specStateCase,
RunTime: 5 * time.Second,
}
reporter.SpecWillRun(spec)
reporter.SpecDidComplete(spec)
reporter.SpecSuiteDidEnd(&types.SuiteSummary{
NumberOfSpecsThatWillBeRun: 1,
NumberOfFailedSpecs: 0,
RunTime: 10 * time.Second,
})
})
It("should record test as ignored", func() {
actual := buffer.String()
expected :=
"##teamcity[testSuiteStarted name='Foo|'s test suite']" +
"##teamcity[testStarted name='A B C']" +
"##teamcity[testIgnored name='A B C']" +
"##teamcity[testFinished name='A B C' duration='5000']" +
"##teamcity[testSuiteFinished name='Foo|'s test suite']"
Ω(actual).Should(Equal(expected))
})
})
}
})