type Disruption … type Test … type Interface … type Chaosmonkey … // New creates and returns a Chaosmonkey, with which the caller should register Tests and call Do. // See Do for more information. func New(disruption Disruption) *Chaosmonkey { … } // Register registers the given Test with the Chaosmonkey, so that the test will run over the // Disruption. func (cm *Chaosmonkey) Register(test Test) { … } // RegisterInterface registers the given Interface with the Chaosmonkey, so the Chaosmonkey will // call Setup, Test, and Teardown properly. Test can tell that the Disruption is finished when // stopCh is closed. func (cm *Chaosmonkey) RegisterInterface(in Interface) { … } // Do performs the Disruption while testing the registered Tests. Once the caller has registered // all Tests with the Chaosmonkey, they call Do. Do starts each registered test asynchronously and // waits for each test to signal that it is ready by calling sem.Ready(). Do will then do the // Disruption, and when it's complete, close sem.StopCh to signal to the registered Tests that the // Disruption is over, and wait for all Tests to return. func (cm *Chaosmonkey) Do(ctx context.Context) { … } type Semaphore … func newSemaphore(stopCh <-chan struct{ … } // Ready is called by the Test to signal that the Test is ready for the disruption to start. func (sem *Semaphore) Ready() { … } // done is an internal method for Go to defer, both to wait for all tests to return, but also to // sense if a test panicked before calling Ready. See waitForReadyOrDone. func (sem *Semaphore) done() { … } // We would like to just check if all tests are ready, but if they fail (which Ginkgo implements as // a panic), they may not have called Ready(). We check done as well to see if the function has // already returned; if it has, we don't care if it's ready, and just continue. func (sem *Semaphore) waitForReadyOrDone() { … } // waitForDone is an internal method for Go to wait on all Tests returning. func (sem *Semaphore) waitForDone() { … }