You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

247 lines
6.7 KiB

  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 _, justAfterEach := range container.SetupNodesOfType(types.SpecComponentTypeJustAfterEach) {
  133. spec.announceSetupNode(writer, "JustAfterEach", container, justAfterEach)
  134. justAfterEachState, justAfterEachFailure := justAfterEach.Run()
  135. if justAfterEachState != types.SpecStatePassed && spec.state == types.SpecStatePassed {
  136. spec.state = justAfterEachState
  137. spec.failure = justAfterEachFailure
  138. }
  139. }
  140. }
  141. for i := innerMostContainerIndexToUnwind; i >= 0; i-- {
  142. container := spec.containers[i]
  143. for _, afterEach := range container.SetupNodesOfType(types.SpecComponentTypeAfterEach) {
  144. spec.announceSetupNode(writer, "AfterEach", container, afterEach)
  145. afterEachState, afterEachFailure := afterEach.Run()
  146. if afterEachState != types.SpecStatePassed && spec.getState() == types.SpecStatePassed {
  147. spec.setState(afterEachState)
  148. spec.failure = afterEachFailure
  149. }
  150. }
  151. }
  152. }()
  153. for i, container := range spec.containers {
  154. innerMostContainerIndexToUnwind = i
  155. for _, beforeEach := range container.SetupNodesOfType(types.SpecComponentTypeBeforeEach) {
  156. spec.announceSetupNode(writer, "BeforeEach", container, beforeEach)
  157. s, f := beforeEach.Run()
  158. spec.failure = f
  159. spec.setState(s)
  160. if spec.getState() != types.SpecStatePassed {
  161. return
  162. }
  163. }
  164. }
  165. for _, container := range spec.containers {
  166. for _, justBeforeEach := range container.SetupNodesOfType(types.SpecComponentTypeJustBeforeEach) {
  167. spec.announceSetupNode(writer, "JustBeforeEach", container, justBeforeEach)
  168. s, f := justBeforeEach.Run()
  169. spec.failure = f
  170. spec.setState(s)
  171. if spec.getState() != types.SpecStatePassed {
  172. return
  173. }
  174. }
  175. }
  176. spec.announceSubject(writer, spec.subject)
  177. s, f := spec.subject.Run()
  178. spec.failure = f
  179. spec.setState(s)
  180. }
  181. func (spec *Spec) announceSetupNode(writer io.Writer, nodeType string, container *containernode.ContainerNode, setupNode leafnodes.BasicNode) {
  182. if spec.announceProgress {
  183. s := fmt.Sprintf("[%s] %s\n %s\n", nodeType, container.Text(), setupNode.CodeLocation().String())
  184. writer.Write([]byte(s))
  185. }
  186. }
  187. func (spec *Spec) announceSubject(writer io.Writer, subject leafnodes.SubjectNode) {
  188. if spec.announceProgress {
  189. nodeType := ""
  190. switch subject.Type() {
  191. case types.SpecComponentTypeIt:
  192. nodeType = "It"
  193. case types.SpecComponentTypeMeasure:
  194. nodeType = "Measure"
  195. }
  196. s := fmt.Sprintf("[%s] %s\n %s\n", nodeType, subject.Text(), subject.CodeLocation().String())
  197. writer.Write([]byte(s))
  198. }
  199. }
  200. func (spec *Spec) measurementsReport() map[string]*types.SpecMeasurement {
  201. if !spec.IsMeasurement() || spec.Failed() {
  202. return map[string]*types.SpecMeasurement{}
  203. }
  204. return spec.subject.(*leafnodes.MeasureNode).MeasurementsReport()
  205. }