github.com/onsi/ginkgo@v1.16.6-0.20211118180735-4e1925ba4c95/internal/parallel_support/server_handler.go (about) 1 package parallel_support 2 3 import ( 4 "io" 5 "os" 6 "sync" 7 8 "github.com/onsi/ginkgo/reporters" 9 "github.com/onsi/ginkgo/types" 10 ) 11 12 type Void struct{} 13 14 var voidReceiver *Void = &Void{} 15 var voidSender Void 16 17 // ServerHandler is an RPC-compatible handler that is shared between the http server and the rpc server. 18 // It handles all the business logic to avoid duplication between the two servers 19 20 type ServerHandler struct { 21 done chan interface{} 22 outputDestination io.Writer 23 reporter reporters.Reporter 24 alives []func() bool 25 lock *sync.Mutex 26 beforeSuiteState BeforeSuiteState 27 parallelTotal int 28 counter int 29 counterLock *sync.Mutex 30 shouldAbort bool 31 32 numSuiteDidBegins int 33 numSuiteDidEnds int 34 aggregatedReport types.Report 35 reportHoldingArea []types.SpecReport 36 } 37 38 func newServerHandler(parallelTotal int, reporter reporters.Reporter) *ServerHandler { 39 return &ServerHandler{ 40 reporter: reporter, 41 lock: &sync.Mutex{}, 42 counterLock: &sync.Mutex{}, 43 alives: make([]func() bool, parallelTotal), 44 beforeSuiteState: BeforeSuiteState{Data: nil, State: types.SpecStateInvalid}, 45 parallelTotal: parallelTotal, 46 outputDestination: os.Stdout, 47 done: make(chan interface{}), 48 } 49 } 50 51 func (handler *ServerHandler) SpecSuiteWillBegin(report types.Report, _ *Void) error { 52 handler.lock.Lock() 53 defer handler.lock.Unlock() 54 55 handler.numSuiteDidBegins += 1 56 57 // all summaries are identical, so it's fine to simply emit the last one of these 58 if handler.numSuiteDidBegins == handler.parallelTotal { 59 handler.reporter.SuiteWillBegin(report) 60 61 for _, summary := range handler.reportHoldingArea { 62 handler.reporter.WillRun(summary) 63 handler.reporter.DidRun(summary) 64 } 65 66 handler.reportHoldingArea = nil 67 } 68 69 return nil 70 } 71 72 func (handler *ServerHandler) DidRun(report types.SpecReport, _ *Void) error { 73 handler.lock.Lock() 74 defer handler.lock.Unlock() 75 76 if handler.numSuiteDidBegins == handler.parallelTotal { 77 handler.reporter.WillRun(report) 78 handler.reporter.DidRun(report) 79 } else { 80 handler.reportHoldingArea = append(handler.reportHoldingArea, report) 81 } 82 83 return nil 84 } 85 86 func (handler *ServerHandler) SpecSuiteDidEnd(report types.Report, _ *Void) error { 87 handler.lock.Lock() 88 defer handler.lock.Unlock() 89 90 handler.numSuiteDidEnds += 1 91 if handler.numSuiteDidEnds == 1 { 92 handler.aggregatedReport = report 93 } else { 94 handler.aggregatedReport = handler.aggregatedReport.Add(report) 95 } 96 97 if handler.numSuiteDidEnds == handler.parallelTotal { 98 handler.reporter.SuiteDidEnd(handler.aggregatedReport) 99 close(handler.done) 100 } 101 102 return nil 103 } 104 105 func (handler *ServerHandler) EmitOutput(output []byte, n *int) error { 106 var err error 107 *n, err = handler.outputDestination.Write(output) 108 return err 109 } 110 111 func (handler *ServerHandler) registerAlive(proc int, alive func() bool) { 112 handler.lock.Lock() 113 defer handler.lock.Unlock() 114 handler.alives[proc-1] = alive 115 } 116 117 func (handler *ServerHandler) procIsAlive(proc int) bool { 118 handler.lock.Lock() 119 defer handler.lock.Unlock() 120 alive := handler.alives[proc-1] 121 if alive == nil { 122 return true 123 } 124 return alive() 125 } 126 127 func (handler *ServerHandler) haveNonprimaryProcsFinished() bool { 128 for i := 2; i <= handler.parallelTotal; i++ { 129 if handler.procIsAlive(i) { 130 return false 131 } 132 } 133 return true 134 } 135 136 func (handler *ServerHandler) BeforeSuiteCompleted(beforeSuiteState BeforeSuiteState, _ *Void) error { 137 handler.lock.Lock() 138 defer handler.lock.Unlock() 139 handler.beforeSuiteState = beforeSuiteState 140 141 return nil 142 } 143 144 func (handler *ServerHandler) BeforeSuiteState(_ Void, beforeSuiteState *BeforeSuiteState) error { 145 proc1IsAlive := handler.procIsAlive(1) 146 handler.lock.Lock() 147 defer handler.lock.Unlock() 148 if handler.beforeSuiteState.State == types.SpecStateInvalid { 149 if proc1IsAlive { 150 return ErrorEarly 151 } else { 152 return ErrorGone 153 } 154 } 155 *beforeSuiteState = handler.beforeSuiteState 156 return nil 157 } 158 159 func (handler *ServerHandler) HaveNonprimaryProcsFinished(_ Void, _ *Void) error { 160 if handler.haveNonprimaryProcsFinished() { 161 return nil 162 } else { 163 return ErrorEarly 164 } 165 } 166 167 func (handler *ServerHandler) AggregatedNonprimaryProcsReport(_ Void, report *types.Report) error { 168 if handler.haveNonprimaryProcsFinished() { 169 handler.lock.Lock() 170 defer handler.lock.Unlock() 171 if handler.numSuiteDidEnds == handler.parallelTotal-1 { 172 *report = handler.aggregatedReport 173 return nil 174 } else { 175 return ErrorGone 176 } 177 } else { 178 return ErrorEarly 179 } 180 } 181 182 func (handler *ServerHandler) Counter(_ Void, counter *int) error { 183 handler.counterLock.Lock() 184 defer handler.counterLock.Unlock() 185 *counter = handler.counter 186 handler.counter++ 187 return nil 188 } 189 190 func (handler *ServerHandler) Abort(_ Void, _ *Void) error { 191 handler.lock.Lock() 192 defer handler.lock.Unlock() 193 handler.shouldAbort = true 194 return nil 195 } 196 197 func (handler *ServerHandler) ShouldAbort(_ Void, shouldAbort *bool) error { 198 handler.lock.Lock() 199 defer handler.lock.Unlock() 200 *shouldAbort = handler.shouldAbort 201 return nil 202 }