arnaucube
arnaucube/mirror-to-giteaPublic Self-hosted repository
mirror-to-gitea/vendor/github.com/onsi/ginkgo/internal/remote/server.go
vendor/github.com/onsi/ginkgo/internal/remote/server.goRaw
  1/*
  2
  3The remote package provides the pieces to allow Ginkgo test suites to report to remote listeners.
  4This is used, primarily, to enable streaming parallel test output but has, in principal, broader applications (e.g. streaming test output to a browser).
  5
  6*/
  7
  8package remote
  9
 10import (
 11	"encoding/json"
 12	"io/ioutil"
 13	"net"
 14	"net/http"
 15	"sync"
 16
 17	"github.com/onsi/ginkgo/internal/spec_iterator"
 18
 19	"github.com/onsi/ginkgo/config"
 20	"github.com/onsi/ginkgo/reporters"
 21	"github.com/onsi/ginkgo/types"
 22)
 23
 24/*
 25Server spins up on an automatically selected port and listens for communication from the forwarding reporter.
 26It then forwards that communication to attached reporters.
 27*/
 28type Server struct {
 29	listener        net.Listener
 30	reporters       []reporters.Reporter
 31	alives          []func() bool
 32	lock            *sync.Mutex
 33	beforeSuiteData types.RemoteBeforeSuiteData
 34	parallelTotal   int
 35	counter         int
 36}
 37
 38//Create a new server, automatically selecting a port
 39func NewServer(parallelTotal int) (*Server, error) {
 40	listener, err := net.Listen("tcp", "127.0.0.1:0")
 41	if err != nil {
 42		return nil, err
 43	}
 44	return &Server{
 45		listener:        listener,
 46		lock:            &sync.Mutex{},
 47		alives:          make([]func() bool, parallelTotal),
 48		beforeSuiteData: types.RemoteBeforeSuiteData{Data: nil, State: types.RemoteBeforeSuiteStatePending},
 49		parallelTotal:   parallelTotal,
 50	}, nil
 51}
 52
 53//Start the server.  You don't need to `go s.Start()`, just `s.Start()`
 54func (server *Server) Start() {
 55	httpServer := &http.Server{}
 56	mux := http.NewServeMux()
 57	httpServer.Handler = mux
 58
 59	//streaming endpoints
 60	mux.HandleFunc("/SpecSuiteWillBegin", server.specSuiteWillBegin)
 61	mux.HandleFunc("/BeforeSuiteDidRun", server.beforeSuiteDidRun)
 62	mux.HandleFunc("/AfterSuiteDidRun", server.afterSuiteDidRun)
 63	mux.HandleFunc("/SpecWillRun", server.specWillRun)
 64	mux.HandleFunc("/SpecDidComplete", server.specDidComplete)
 65	mux.HandleFunc("/SpecSuiteDidEnd", server.specSuiteDidEnd)
 66
 67	//synchronization endpoints
 68	mux.HandleFunc("/BeforeSuiteState", server.handleBeforeSuiteState)
 69	mux.HandleFunc("/RemoteAfterSuiteData", server.handleRemoteAfterSuiteData)
 70	mux.HandleFunc("/counter", server.handleCounter)
 71	mux.HandleFunc("/has-counter", server.handleHasCounter) //for backward compatibility
 72
 73	go httpServer.Serve(server.listener)
 74}
 75
 76//Stop the server
 77func (server *Server) Close() {
 78	server.listener.Close()
 79}
 80
 81//The address the server can be reached it.  Pass this into the `ForwardingReporter`.
 82func (server *Server) Address() string {
 83	return "http://" + server.listener.Addr().String()
 84}
 85
 86//
 87// Streaming Endpoints
 88//
 89
 90//The server will forward all received messages to Ginkgo reporters registered with `RegisterReporters`
 91func (server *Server) readAll(request *http.Request) []byte {
 92	defer request.Body.Close()
 93	body, _ := ioutil.ReadAll(request.Body)
 94	return body
 95}
 96
 97func (server *Server) RegisterReporters(reporters ...reporters.Reporter) {
 98	server.reporters = reporters
 99}
100
101func (server *Server) specSuiteWillBegin(writer http.ResponseWriter, request *http.Request) {
102	body := server.readAll(request)
103
104	var data struct {
105		Config  config.GinkgoConfigType `json:"config"`
106		Summary *types.SuiteSummary     `json:"suite-summary"`
107	}
108
109	json.Unmarshal(body, &data)
110
111	for _, reporter := range server.reporters {
112		reporter.SpecSuiteWillBegin(data.Config, data.Summary)
113	}
114}
115
116func (server *Server) beforeSuiteDidRun(writer http.ResponseWriter, request *http.Request) {
117	body := server.readAll(request)
118	var setupSummary *types.SetupSummary
119	json.Unmarshal(body, &setupSummary)
120
121	for _, reporter := range server.reporters {
122		reporter.BeforeSuiteDidRun(setupSummary)
123	}
124}
125
126func (server *Server) afterSuiteDidRun(writer http.ResponseWriter, request *http.Request) {
127	body := server.readAll(request)
128	var setupSummary *types.SetupSummary
129	json.Unmarshal(body, &setupSummary)
130
131	for _, reporter := range server.reporters {
132		reporter.AfterSuiteDidRun(setupSummary)
133	}
134}
135
136func (server *Server) specWillRun(writer http.ResponseWriter, request *http.Request) {
137	body := server.readAll(request)
138	var specSummary *types.SpecSummary
139	json.Unmarshal(body, &specSummary)
140
141	for _, reporter := range server.reporters {
142		reporter.SpecWillRun(specSummary)
143	}
144}
145
146func (server *Server) specDidComplete(writer http.ResponseWriter, request *http.Request) {
147	body := server.readAll(request)
148	var specSummary *types.SpecSummary
149	json.Unmarshal(body, &specSummary)
150
151	for _, reporter := range server.reporters {
152		reporter.SpecDidComplete(specSummary)
153	}
154}
155
156func (server *Server) specSuiteDidEnd(writer http.ResponseWriter, request *http.Request) {
157	body := server.readAll(request)
158	var suiteSummary *types.SuiteSummary
159	json.Unmarshal(body, &suiteSummary)
160
161	for _, reporter := range server.reporters {
162		reporter.SpecSuiteDidEnd(suiteSummary)
163	}
164}
165
166//
167// Synchronization Endpoints
168//
169
170func (server *Server) RegisterAlive(node int, alive func() bool) {
171	server.lock.Lock()
172	defer server.lock.Unlock()
173	server.alives[node-1] = alive
174}
175
176func (server *Server) nodeIsAlive(node int) bool {
177	server.lock.Lock()
178	defer server.lock.Unlock()
179	alive := server.alives[node-1]
180	if alive == nil {
181		return true
182	}
183	return alive()
184}
185
186func (server *Server) handleBeforeSuiteState(writer http.ResponseWriter, request *http.Request) {
187	if request.Method == "POST" {
188		dec := json.NewDecoder(request.Body)
189		dec.Decode(&(server.beforeSuiteData))
190	} else {
191		beforeSuiteData := server.beforeSuiteData
192		if beforeSuiteData.State == types.RemoteBeforeSuiteStatePending && !server.nodeIsAlive(1) {
193			beforeSuiteData.State = types.RemoteBeforeSuiteStateDisappeared
194		}
195		enc := json.NewEncoder(writer)
196		enc.Encode(beforeSuiteData)
197	}
198}
199
200func (server *Server) handleRemoteAfterSuiteData(writer http.ResponseWriter, request *http.Request) {
201	afterSuiteData := types.RemoteAfterSuiteData{
202		CanRun: true,
203	}
204	for i := 2; i <= server.parallelTotal; i++ {
205		afterSuiteData.CanRun = afterSuiteData.CanRun && !server.nodeIsAlive(i)
206	}
207
208	enc := json.NewEncoder(writer)
209	enc.Encode(afterSuiteData)
210}
211
212func (server *Server) handleCounter(writer http.ResponseWriter, request *http.Request) {
213	c := spec_iterator.Counter{}
214	server.lock.Lock()
215	c.Index = server.counter
216	server.counter++
217	server.lock.Unlock()
218
219	json.NewEncoder(writer).Encode(c)
220}
221
222func (server *Server) handleHasCounter(writer http.ResponseWriter, request *http.Request) {
223	writer.Write([]byte(""))
224}