Change:
Detected by
Create a Pod as follows: Name: jenkins Using image: jenkins In a new Kubenetes namespace named website-frontend kubectl create ns website-frontend apiVersion: v1 kind: Pod metadata: name: jenkins namespace: website-frontend spec: containers: name: jenkins image: jenkins kubectl create -f

Discussion:
fakeEtcd := util.MakeFakeEtcdClient(t) manager := MakeReplicationManager(fakeEtcd, nil) var testControllerSpec api.ReplicationController <del> receivedCount := 0 </del> <ins> received := make(chan bool) </ins> manager.syncHandler = func(controllerSpec api.ReplicationController) error { if !reflect.DeepEqual(controllerSpec, testControllerSpec) { t.Errorf("Expected %#v, but got %#v", testControllerSpec, controllerSpec) } <del> receivedCount++ </del> <ins> close(received) </ins> return nil } go manager.watchControllers() <del> time.Sleep(10 * time.Millisecond) </del> <ins> fakeEtcd.WaitForWatchCompletion() </ins> // Test normal case testControllerSpec.ID = "foo"

}, } <del> time.Sleep(10 * time.Millisecond) if receivedCount != 1 { t.Errorf("Expected 1 call but got %v", receivedCount) </del> <ins> select { case <-received: case <-time.After(10 * time.Millisecond): t.Errorf("Expected 1 call but got 0") </ins> } // Test error case fakeEtcd.WatchInjectError <- fmt.Errorf("Injected error") <del> time.Sleep(10 * time.Millisecond) </del> // Did everything shut down? if _, open := <-fakeEtcd.WatchResponse; open {

// Test purposeful shutdown go manager.watchControllers() <del> time.Sleep(10 * time.Millisecond) </del> <ins> fakeEtcd.WaitForWatchCompletion() </ins> fakeEtcd.WatchStop <- true <del> time.Sleep(10 * time.Millisecond) </del> // Did everything shut down? if _, open := <-fakeEtcd.WatchResponse; open {

import ( "fmt" <ins> "sync" </ins> "testing" "github.com/coreos/go-etcd/etcd"

} type FakeEtcdClient struct { <ins> condWatchCompleted *sync.Cond condLock           sync.Mutex </ins> Data        map[string]EtcdResponseWithError DeletedKeys []string Err         error

} func MakeFakeEtcdClient(t *testing.T) *FakeEtcdClient { <del> return &FakeEtcdClient{ </del> <ins> ret := &FakeEtcdClient{ </ins> t:    t, Data: map[string]EtcdResponseWithError{}, } <ins> // There are three publicly accessible channels in FakeEtcdClient: //  - WatchResponse //  - WatchInjectError //  - WatchStop // They are only available when Watch() is called.  If users of // FakeEtcdClient want to use any of these channels, they have to call // WaitForWatchCompletion before any operation on these channels. // Internally, FakeEtcdClient use condWatchCompleted to indicate if the // Watch() method has been called. WaitForWatchCompletion() will wait // on condWatchCompleted. By the end of the Watch() method, it will // call Broadcast() on condWatchCompleted, which will awake any // goroutine waiting on this condition. ret.condWatchCompleted = sync.NewCond(&ret.condLock) return ret </ins> } func (f *FakeEtcdClient) AddChild(key, data string, ttl uint64) (*etcd.Response, error) {

return &etcd.Response{}, f.Err } <ins> func (f *FakeEtcdClient) WaitForWatchCompletion() { f.condLock.Lock() defer f.condLock.Unlock() f.condWatchCompleted.Wait() } </ins> func (f *FakeEtcdClient) Watch(prefix string, waitIndex uint64, recursive bool, receiver chan *etcd.Response, stop chan bool) (*etcd.Response, error) { f.WatchResponse = receiver f.WatchStop = stop injectedError := make(chan error) defer close(injectedError) f.WatchInjectError = injectedError <ins> f.condWatchCompleted.Broadcast() </ins> select { case <-stop: return nil, etcd.ErrWatchStoppedByUser