1package leafnodes_test
2
3import (
4	"sync"
5
6	. "github.com/onsi/ginkgo"
7	. "github.com/onsi/ginkgo/internal/leafnodes"
8	"github.com/onsi/ginkgo/types"
9	. "github.com/onsi/gomega"
10
11	"net/http"
12
13	"github.com/onsi/gomega/ghttp"
14
15	"time"
16
17	"github.com/onsi/ginkgo/internal/codelocation"
18	Failer "github.com/onsi/ginkgo/internal/failer"
19)
20
21var _ = Describe("SynchronizedAfterSuiteNode", func() {
22	var failer *Failer.Failer
23	var node SuiteNode
24	var codeLocation types.CodeLocation
25	var innerCodeLocation types.CodeLocation
26	var outcome bool
27	var server *ghttp.Server
28	var things []string
29	var lock *sync.Mutex
30
31	BeforeEach(func() {
32		things = []string{}
33		server = ghttp.NewServer()
34		codeLocation = codelocation.New(0)
35		innerCodeLocation = codelocation.New(0)
36		failer = Failer.New()
37		lock = &sync.Mutex{}
38	})
39
40	AfterEach(func() {
41		server.Close()
42	})
43
44	newNode := func(bodyA interface{}, bodyB interface{}) SuiteNode {
45		return NewSynchronizedAfterSuiteNode(bodyA, bodyB, codeLocation, time.Millisecond, failer)
46	}
47
48	ranThing := func(thing string) {
49		lock.Lock()
50		defer lock.Unlock()
51		things = append(things, thing)
52	}
53
54	thingsThatRan := func() []string {
55		lock.Lock()
56		defer lock.Unlock()
57		return things
58	}
59
60	Context("when not running in parallel", func() {
61		Context("when all is well", func() {
62			BeforeEach(func() {
63				node = newNode(func() {
64					ranThing("A")
65				}, func() {
66					ranThing("B")
67				})
68
69				outcome = node.Run(1, 1, server.URL())
70			})
71
72			It("should run A, then B", func() {
73				Ω(thingsThatRan()).Should(Equal([]string{"A", "B"}))
74			})
75
76			It("should report success", func() {
77				Ω(outcome).Should(BeTrue())
78				Ω(node.Passed()).Should(BeTrue())
79				Ω(node.Summary().State).Should(Equal(types.SpecStatePassed))
80			})
81		})
82
83		Context("when A fails", func() {
84			BeforeEach(func() {
85				node = newNode(func() {
86					ranThing("A")
87					failer.Fail("bam", innerCodeLocation)
88				}, func() {
89					ranThing("B")
90				})
91
92				outcome = node.Run(1, 1, server.URL())
93			})
94
95			It("should still run B", func() {
96				Ω(thingsThatRan()).Should(Equal([]string{"A", "B"}))
97			})
98
99			It("should report failure", func() {
100				Ω(outcome).Should(BeFalse())
101				Ω(node.Passed()).Should(BeFalse())
102				Ω(node.Summary().State).Should(Equal(types.SpecStateFailed))
103			})
104		})
105
106		Context("when B fails", func() {
107			BeforeEach(func() {
108				node = newNode(func() {
109					ranThing("A")
110				}, func() {
111					ranThing("B")
112					failer.Fail("bam", innerCodeLocation)
113				})
114
115				outcome = node.Run(1, 1, server.URL())
116			})
117
118			It("should run all the things", func() {
119				Ω(thingsThatRan()).Should(Equal([]string{"A", "B"}))
120			})
121
122			It("should report failure", func() {
123				Ω(outcome).Should(BeFalse())
124				Ω(node.Passed()).Should(BeFalse())
125				Ω(node.Summary().State).Should(Equal(types.SpecStateFailed))
126			})
127		})
128	})
129
130	Context("when running in parallel", func() {
131		Context("as the first node", func() {
132			BeforeEach(func() {
133				server.AppendHandlers(ghttp.CombineHandlers(
134					ghttp.VerifyRequest("GET", "/RemoteAfterSuiteData"),
135					func(writer http.ResponseWriter, request *http.Request) {
136						ranThing("Request1")
137					},
138					ghttp.RespondWithJSONEncoded(200, types.RemoteAfterSuiteData{CanRun: false}),
139				), ghttp.CombineHandlers(
140					ghttp.VerifyRequest("GET", "/RemoteAfterSuiteData"),
141					func(writer http.ResponseWriter, request *http.Request) {
142						ranThing("Request2")
143					},
144					ghttp.RespondWithJSONEncoded(200, types.RemoteAfterSuiteData{CanRun: false}),
145				), ghttp.CombineHandlers(
146					ghttp.VerifyRequest("GET", "/RemoteAfterSuiteData"),
147					func(writer http.ResponseWriter, request *http.Request) {
148						ranThing("Request3")
149					},
150					ghttp.RespondWithJSONEncoded(200, types.RemoteAfterSuiteData{CanRun: true}),
151				))
152
153				node = newNode(func() {
154					ranThing("A")
155				}, func() {
156					ranThing("B")
157				})
158
159				outcome = node.Run(1, 3, server.URL())
160			})
161
162			It("should run A and, when the server says its time, run B", func() {
163				Ω(thingsThatRan()).Should(Equal([]string{"A", "Request1", "Request2", "Request3", "B"}))
164			})
165
166			It("should report success", func() {
167				Ω(outcome).Should(BeTrue())
168				Ω(node.Passed()).Should(BeTrue())
169				Ω(node.Summary().State).Should(Equal(types.SpecStatePassed))
170			})
171		})
172
173		Context("as any other node", func() {
174			BeforeEach(func() {
175				node = newNode(func() {
176					ranThing("A")
177				}, func() {
178					ranThing("B")
179				})
180
181				outcome = node.Run(2, 3, server.URL())
182			})
183
184			It("should run A, and not run B", func() {
185				Ω(thingsThatRan()).Should(Equal([]string{"A"}))
186			})
187
188			It("should not talk to the server", func() {
189				Ω(server.ReceivedRequests()).Should(BeEmpty())
190			})
191
192			It("should report success", func() {
193				Ω(outcome).Should(BeTrue())
194				Ω(node.Passed()).Should(BeTrue())
195				Ω(node.Summary().State).Should(Equal(types.SpecStatePassed))
196			})
197		})
198	})
199})
200