spec.go 6.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236
  1. package spec
  2. import (
  3. "fmt"
  4. "io"
  5. "time"
  6. "sync"
  7. "github.com/onsi/ginkgo/internal/containernode"
  8. "github.com/onsi/ginkgo/internal/leafnodes"
  9. "github.com/onsi/ginkgo/types"
  10. )
  11. type Spec struct {
  12. subject leafnodes.SubjectNode
  13. focused bool
  14. announceProgress bool
  15. containers []*containernode.ContainerNode
  16. state types.SpecState
  17. runTime time.Duration
  18. startTime time.Time
  19. failure types.SpecFailure
  20. previousFailures bool
  21. stateMutex *sync.Mutex
  22. }
  23. func New(subject leafnodes.SubjectNode, containers []*containernode.ContainerNode, announceProgress bool) *Spec {
  24. spec := &Spec{
  25. subject: subject,
  26. containers: containers,
  27. focused: subject.Flag() == types.FlagTypeFocused,
  28. announceProgress: announceProgress,
  29. stateMutex: &sync.Mutex{},
  30. }
  31. spec.processFlag(subject.Flag())
  32. for i := len(containers) - 1; i >= 0; i-- {
  33. spec.processFlag(containers[i].Flag())
  34. }
  35. return spec
  36. }
  37. func (spec *Spec) processFlag(flag types.FlagType) {
  38. if flag == types.FlagTypeFocused {
  39. spec.focused = true
  40. } else if flag == types.FlagTypePending {
  41. spec.setState(types.SpecStatePending)
  42. }
  43. }
  44. func (spec *Spec) Skip() {
  45. spec.setState(types.SpecStateSkipped)
  46. }
  47. func (spec *Spec) Failed() bool {
  48. return spec.getState() == types.SpecStateFailed || spec.getState() == types.SpecStatePanicked || spec.getState() == types.SpecStateTimedOut
  49. }
  50. func (spec *Spec) Passed() bool {
  51. return spec.getState() == types.SpecStatePassed
  52. }
  53. func (spec *Spec) Flaked() bool {
  54. return spec.getState() == types.SpecStatePassed && spec.previousFailures
  55. }
  56. func (spec *Spec) Pending() bool {
  57. return spec.getState() == types.SpecStatePending
  58. }
  59. func (spec *Spec) Skipped() bool {
  60. return spec.getState() == types.SpecStateSkipped
  61. }
  62. func (spec *Spec) Focused() bool {
  63. return spec.focused
  64. }
  65. func (spec *Spec) IsMeasurement() bool {
  66. return spec.subject.Type() == types.SpecComponentTypeMeasure
  67. }
  68. func (spec *Spec) Summary(suiteID string) *types.SpecSummary {
  69. componentTexts := make([]string, len(spec.containers)+1)
  70. componentCodeLocations := make([]types.CodeLocation, len(spec.containers)+1)
  71. for i, container := range spec.containers {
  72. componentTexts[i] = container.Text()
  73. componentCodeLocations[i] = container.CodeLocation()
  74. }
  75. componentTexts[len(spec.containers)] = spec.subject.Text()
  76. componentCodeLocations[len(spec.containers)] = spec.subject.CodeLocation()
  77. runTime := spec.runTime
  78. if runTime == 0 && !spec.startTime.IsZero() {
  79. runTime = time.Since(spec.startTime)
  80. }
  81. return &types.SpecSummary{
  82. IsMeasurement: spec.IsMeasurement(),
  83. NumberOfSamples: spec.subject.Samples(),
  84. ComponentTexts: componentTexts,
  85. ComponentCodeLocations: componentCodeLocations,
  86. State: spec.getState(),
  87. RunTime: runTime,
  88. Failure: spec.failure,
  89. Measurements: spec.measurementsReport(),
  90. SuiteID: suiteID,
  91. }
  92. }
  93. func (spec *Spec) ConcatenatedString() string {
  94. s := ""
  95. for _, container := range spec.containers {
  96. s += container.Text() + " "
  97. }
  98. return s + spec.subject.Text()
  99. }
  100. func (spec *Spec) Run(writer io.Writer) {
  101. if spec.getState() == types.SpecStateFailed {
  102. spec.previousFailures = true
  103. }
  104. spec.startTime = time.Now()
  105. defer func() {
  106. spec.runTime = time.Since(spec.startTime)
  107. }()
  108. for sample := 0; sample < spec.subject.Samples(); sample++ {
  109. spec.runSample(sample, writer)
  110. if spec.getState() != types.SpecStatePassed {
  111. return
  112. }
  113. }
  114. }
  115. func (spec *Spec) getState() types.SpecState {
  116. spec.stateMutex.Lock()
  117. defer spec.stateMutex.Unlock()
  118. return spec.state
  119. }
  120. func (spec *Spec) setState(state types.SpecState) {
  121. spec.stateMutex.Lock()
  122. defer spec.stateMutex.Unlock()
  123. spec.state = state
  124. }
  125. func (spec *Spec) runSample(sample int, writer io.Writer) {
  126. spec.setState(types.SpecStatePassed)
  127. spec.failure = types.SpecFailure{}
  128. innerMostContainerIndexToUnwind := -1
  129. defer func() {
  130. for i := innerMostContainerIndexToUnwind; i >= 0; i-- {
  131. container := spec.containers[i]
  132. for _, afterEach := range container.SetupNodesOfType(types.SpecComponentTypeAfterEach) {
  133. spec.announceSetupNode(writer, "AfterEach", container, afterEach)
  134. afterEachState, afterEachFailure := afterEach.Run()
  135. if afterEachState != types.SpecStatePassed && spec.getState() == types.SpecStatePassed {
  136. spec.setState(afterEachState)
  137. spec.failure = afterEachFailure
  138. }
  139. }
  140. }
  141. }()
  142. for i, container := range spec.containers {
  143. innerMostContainerIndexToUnwind = i
  144. for _, beforeEach := range container.SetupNodesOfType(types.SpecComponentTypeBeforeEach) {
  145. spec.announceSetupNode(writer, "BeforeEach", container, beforeEach)
  146. s, f := beforeEach.Run()
  147. spec.failure = f
  148. spec.setState(s)
  149. if spec.getState() != types.SpecStatePassed {
  150. return
  151. }
  152. }
  153. }
  154. for _, container := range spec.containers {
  155. for _, justBeforeEach := range container.SetupNodesOfType(types.SpecComponentTypeJustBeforeEach) {
  156. spec.announceSetupNode(writer, "JustBeforeEach", container, justBeforeEach)
  157. s, f := justBeforeEach.Run()
  158. spec.failure = f
  159. spec.setState(s)
  160. if spec.getState() != types.SpecStatePassed {
  161. return
  162. }
  163. }
  164. }
  165. spec.announceSubject(writer, spec.subject)
  166. s, f := spec.subject.Run()
  167. spec.failure = f
  168. spec.setState(s)
  169. }
  170. func (spec *Spec) announceSetupNode(writer io.Writer, nodeType string, container *containernode.ContainerNode, setupNode leafnodes.BasicNode) {
  171. if spec.announceProgress {
  172. s := fmt.Sprintf("[%s] %s\n %s\n", nodeType, container.Text(), setupNode.CodeLocation().String())
  173. writer.Write([]byte(s))
  174. }
  175. }
  176. func (spec *Spec) announceSubject(writer io.Writer, subject leafnodes.SubjectNode) {
  177. if spec.announceProgress {
  178. nodeType := ""
  179. switch subject.Type() {
  180. case types.SpecComponentTypeIt:
  181. nodeType = "It"
  182. case types.SpecComponentTypeMeasure:
  183. nodeType = "Measure"
  184. }
  185. s := fmt.Sprintf("[%s] %s\n %s\n", nodeType, subject.Text(), subject.CodeLocation().String())
  186. writer.Write([]byte(s))
  187. }
  188. }
  189. func (spec *Spec) measurementsReport() map[string]*types.SpecMeasurement {
  190. if !spec.IsMeasurement() || spec.Failed() {
  191. return map[string]*types.SpecMeasurement{}
  192. }
  193. return spec.subject.(*leafnodes.MeasureNode).MeasurementsReport()
  194. }