diff --git a/contrib/mesos/pkg/election/etcd_master_test.go b/contrib/mesos/pkg/election/etcd_master_test.go index 5378d2a7725..efd98d4d775 100644 --- a/contrib/mesos/pkg/election/etcd_master_test.go +++ b/contrib/mesos/pkg/election/etcd_master_test.go @@ -17,18 +17,24 @@ limitations under the License. package election import ( + "reflect" "testing" "github.com/coreos/go-etcd/etcd" + etcdtesting "k8s.io/kubernetes/pkg/storage/etcd/testing" "k8s.io/kubernetes/pkg/tools" "k8s.io/kubernetes/pkg/watch" ) func TestEtcdMasterOther(t *testing.T) { + server := etcdtesting.NewEtcdTestClientServer(t) + defer server.Terminate(t) + path := "foo" - etcd := tools.NewFakeEtcdClient(t) - etcd.Set(path, "baz", 0) - master := NewEtcdMasterElector(etcd) + if _, err := server.Client.Set(path, "baz", 0); err != nil { + t.Errorf("unexpected error: %v", err) + } + master := NewEtcdMasterElector(server.Client) w := master.Elect(path, "bar") result := <-w.ResultChan() if result.Type != watch.Modified || result.Object.(Master) != "baz" { @@ -38,18 +44,11 @@ func TestEtcdMasterOther(t *testing.T) { } func TestEtcdMasterNoOther(t *testing.T) { + server := etcdtesting.NewEtcdTestClientServer(t) + defer server.Terminate(t) + path := "foo" - e := tools.NewFakeEtcdClient(t) - e.TestIndex = true - e.Data["foo"] = tools.EtcdResponseWithError{ - R: &etcd.Response{ - Node: nil, - }, - E: &etcd.EtcdError{ - ErrorCode: tools.EtcdErrorCodeNotFound, - }, - } - master := NewEtcdMasterElector(e) + master := NewEtcdMasterElector(server.Client) w := master.Elect(path, "bar") result := <-w.ResultChan() if result.Type != watch.Modified || result.Object.(Master) != "bar" { @@ -58,41 +57,77 @@ func TestEtcdMasterNoOther(t *testing.T) { w.Stop() } +// MockClient is wrapper aroung tools.EtcdClient. +type MockClient struct { + client tools.EtcdClient + t *testing.T + // afterGetFunc is called after each Get() call. + afterGetFunc func() + calls []string +} + +func (m *MockClient) GetCluster() []string { + return m.client.GetCluster() +} + +func (m *MockClient) Get(key string, sort, recursive bool) (*etcd.Response, error) { + m.calls = append(m.calls, "get") + defer m.afterGetFunc() + response, err := m.client.Get(key, sort, recursive) + return response, err +} + +func (m *MockClient) Set(key, value string, ttl uint64) (*etcd.Response, error) { + return m.client.Set(key, value, ttl) +} + +func (m *MockClient) Create(key, value string, ttl uint64) (*etcd.Response, error) { + m.calls = append(m.calls, "create") + return m.client.Create(key, value, ttl) +} + +func (m *MockClient) CompareAndSwap(key, value string, ttl uint64, prevValue string, prevIndex uint64) (*etcd.Response, error) { + return m.client.CompareAndSwap(key, value, ttl, prevValue, prevIndex) +} + +func (m *MockClient) Delete(key string, recursive bool) (*etcd.Response, error) { + return m.client.Delete(key, recursive) +} + +func (m *MockClient) Watch(prefix string, waitIndex uint64, recursive bool, receiver chan *etcd.Response, stop chan bool) (*etcd.Response, error) { + return m.client.Watch(prefix, waitIndex, recursive, receiver, stop) +} + func TestEtcdMasterNoOtherThenConflict(t *testing.T) { + server := etcdtesting.NewEtcdTestClientServer(t) + defer server.Terminate(t) + + // We set up the following scenario: + // - after each Get() call, we write "baz" to a path + // - this is simulating someone else writing a data + // - the value written by someone else is the new value path := "foo" - e := tools.NewFakeEtcdClient(t) - e.TestIndex = true - // Ok, so we set up a chain of responses from etcd: - // 1) Nothing there - // 2) conflict (someone else wrote) - // 3) new value (the data they wrote) - empty := tools.EtcdResponseWithError{ - R: &etcd.Response{ - Node: nil, - }, - E: &etcd.EtcdError{ - ErrorCode: tools.EtcdErrorCodeNotFound, + client := &MockClient{ + client: server.Client, + t: t, + afterGetFunc: func() { + if _, err := server.Client.Set(path, "baz", 0); err != nil { + t.Errorf("unexpected error: %v", err) + } }, + calls: make([]string, 0), } - empty.N = &tools.EtcdResponseWithError{ - R: &etcd.Response{}, - E: &etcd.EtcdError{ - ErrorCode: tools.EtcdErrorCodeNodeExist, - }, - } - empty.N.N = &tools.EtcdResponseWithError{ - R: &etcd.Response{ - Node: &etcd.Node{ - Value: "baz", - }, - }, - } - e.Data["foo"] = empty - master := NewEtcdMasterElector(e) + + master := NewEtcdMasterElector(client) w := master.Elect(path, "bar") result := <-w.ResultChan() - if result.Type != watch.Modified || result.Object.(Master) != "bar" { + if result.Type != watch.Modified || result.Object.(Master) != "baz" { t.Errorf("unexpected event: %#v", result) } w.Stop() + + expectedCalls := []string{"get", "create", "get"} + if !reflect.DeepEqual(client.calls, expectedCalls) { + t.Errorf("unexpected calls: %#v", client.calls) + } }