func TestWatchEtcdError(t *testing.T) { codec := latest.Codec fakeClient := NewFakeEtcdClient(t) fakeClient.expectNotFoundGetSet["/some/key"] = struct{}{} fakeClient.WatchImmediateError = fmt.Errorf("immediate error") h := NewEtcdHelper(fakeClient, codec, etcdtest.PathPrefix()) watching, err := h.Watch("/some/key", 4, Everything) if err != nil { t.Fatalf("Unexpected error: %v", err) } defer watching.Stop() got := <-watching.ResultChan() if got.Type != watch.Error { t.Fatalf("Unexpected non-error") } status, ok := got.Object.(*api.Status) if !ok { t.Fatalf("Unexpected non-error object type") } if status.Message != "immediate error" { t.Errorf("Unexpected wrong error") } if status.Status != api.StatusFailure { t.Errorf("Unexpected wrong error status") } }
func NewTestEventEtcdRegistry(t *testing.T) (*tools.FakeEtcdClient, generic.Registry) { f := tools.NewFakeEtcdClient(t) f.TestIndex = true h := tools.NewEtcdHelper(f, testapi.Codec(), etcdtest.PathPrefix()) return f, NewEtcdRegistry(h, testTTL) }
func newStorage(t *testing.T) (*REST, *StatusREST, *tools.FakeEtcdClient, tools.EtcdHelper) { fakeEtcdClient := tools.NewFakeEtcdClient(t) fakeEtcdClient.TestIndex = true helper := tools.NewEtcdHelper(fakeEtcdClient, latest.Codec, etcdtest.PathPrefix()) storage, statusStorage := NewStorage(helper) return storage, statusStorage, fakeEtcdClient, helper }
func TestWatchFromNotFound(t *testing.T) { fakeClient := NewFakeEtcdClient(t) key := "/some/key" prefixedKey := etcdtest.AddPrefix(key) fakeClient.Data[prefixedKey] = EtcdResponseWithError{ R: &etcd.Response{ Node: nil, }, E: &etcd.EtcdError{ Index: 2, ErrorCode: 100, }, } h := NewEtcdHelper(fakeClient, codec, etcdtest.PathPrefix()) watching, err := h.Watch(key, 0, Everything) if err != nil { t.Fatalf("Unexpected error: %v", err) } fakeClient.WaitForWatchCompletion() if fakeClient.WatchIndex != 3 { t.Errorf("Expected client to wait for %d, got %#v", 3, fakeClient) } watching.Stop() }
func TestGuaranteedUpdateNoChange(t *testing.T) { fakeClient := NewFakeEtcdClient(t) fakeClient.TestIndex = true helper := NewEtcdHelper(fakeClient, codec, etcdtest.PathPrefix()) key := etcdtest.AddPrefix("/some/key") // Create a new node. fakeClient.ExpectNotFoundGet(key) obj := &TestResource{ObjectMeta: api.ObjectMeta{Name: "foo"}, Value: 1} err := helper.GuaranteedUpdate("/some/key", &TestResource{}, true, SimpleUpdate(func(in runtime.Object) (runtime.Object, error) { return obj, nil })) if err != nil { t.Errorf("Unexpected error %#v", err) } // Update an existing node with the same data callbackCalled := false objUpdate := &TestResource{ObjectMeta: api.ObjectMeta{Name: "foo"}, Value: 1} err = helper.GuaranteedUpdate("/some/key", &TestResource{}, true, SimpleUpdate(func(in runtime.Object) (runtime.Object, error) { fakeClient.Err = errors.New("should not be called") callbackCalled = true return objUpdate, nil })) if err != nil { t.Fatalf("Unexpected error %#v", err) } if !callbackCalled { t.Errorf("tryUpdate callback should have been called.") } }
func TestGuaranteedUpdateKeyNotFound(t *testing.T) { fakeClient := NewFakeEtcdClient(t) fakeClient.TestIndex = true helper := NewEtcdHelper(fakeClient, codec, etcdtest.PathPrefix()) key := etcdtest.AddPrefix("/some/key") // Create a new node. fakeClient.ExpectNotFoundGet(key) obj := &TestResource{ObjectMeta: api.ObjectMeta{Name: "foo"}, Value: 1} f := SimpleUpdate(func(in runtime.Object) (runtime.Object, error) { return obj, nil }) ignoreNotFound := false err := helper.GuaranteedUpdate("/some/key", &TestResource{}, ignoreNotFound, f) if err == nil { t.Errorf("Expected error for key not found.") } ignoreNotFound = true err = helper.GuaranteedUpdate("/some/key", &TestResource{}, ignoreNotFound, f) if err != nil { t.Errorf("Unexpected error %v.", err) } }
func TestSetObjWithoutResourceVersioner(t *testing.T) { obj := &api.Pod{ObjectMeta: api.ObjectMeta{Name: "foo"}} fakeClient := NewFakeEtcdClient(t) helper := NewEtcdHelper(fakeClient, testapi.Codec(), etcdtest.PathPrefix()) helper.Versioner = nil returnedObj := &api.Pod{} err := helper.SetObj("/some/key", obj, returnedObj, 3) key := etcdtest.AddPrefix("/some/key") if err != nil { t.Errorf("Unexpected error %#v", err) } data, err := testapi.Codec().Encode(obj) if err != nil { t.Errorf("Unexpected error %#v", err) } expect := string(data) got := fakeClient.Data[key].R.Node.Value if expect != got { t.Errorf("Wanted %v, got %v", expect, got) } if e, a := uint64(3), fakeClient.LastSetTTL; e != a { t.Errorf("Wanted %v, got %v", e, a) } if obj.ResourceVersion != returnedObj.ResourceVersion || obj.Name != returnedObj.Name { t.Errorf("If set was successful but returned object did not have correct resource version") } }
func TestWatchPurposefulShutdown(t *testing.T) { fakeClient := NewFakeEtcdClient(t) h := NewEtcdHelper(fakeClient, codec, etcdtest.PathPrefix()) key := "/some/key" prefixedKey := etcdtest.AddPrefix(key) fakeClient.expectNotFoundGetSet[prefixedKey] = struct{}{} // Test purposeful shutdown watching, err := h.Watch(key, 0, Everything) if err != nil { t.Fatalf("Unexpected error: %v", err) } fakeClient.WaitForWatchCompletion() watching.Stop() // Did everything shut down? if _, open := <-fakeClient.WatchResponse; open { t.Errorf("A stop did not cause a graceful shutdown") } if _, open := <-watching.ResultChan(); open { t.Errorf("An injected error did not cause a graceful shutdown") } }
// startMasterOrDie starts a qingyuan master and an httpserver to handle api requests func startMasterOrDie(masterConfig *master.Config) (*master.Master, *httptest.Server, *tools.EtcdHelper) { var m *master.Master s := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) { m.Handler.ServeHTTP(w, req) })) var helper tools.EtcdHelper var err error if masterConfig == nil { helper, err = master.NewEtcdHelper(NewEtcdClient(), "", etcdtest.PathPrefix()) if err != nil { glog.Fatalf("Failed to create etcd helper for master %v", err) } masterConfig = &master.Config{ EtcdHelper: helper, QingletClient: client.FakeQingletClient{}, EnableLogsSupport: false, EnableProfiling: true, EnableUISupport: false, APIPrefix: "/api", Authorizer: apiserver.NewAlwaysAllowAuthorizer(), AdmissionControl: admit.NewAlwaysAdmit(), } } else { helper = masterConfig.EtcdHelper } m = master.New(masterConfig) return m, s, &helper }
func NewTestEtcdRegistryWithPods(client tools.EtcdClient) *Registry { helper := tools.NewEtcdHelper(client, latest.Codec, etcdtest.PathPrefix()) podStorage := podetcd.NewStorage(helper, nil) endpointStorage := endpointetcd.NewStorage(helper) registry := NewRegistry(helper, pod.NewRegistry(podStorage.Pod), endpoint.NewRegistry(endpointStorage)) return registry }
func TestWatch(t *testing.T) { codec := latest.Codec fakeClient := NewFakeEtcdClient(t) key := "/some/key" prefixedKey := etcdtest.AddPrefix(key) fakeClient.expectNotFoundGetSet[prefixedKey] = struct{}{} h := NewEtcdHelper(fakeClient, codec, etcdtest.PathPrefix()) watching, err := h.Watch(key, 0, Everything) if err != nil { t.Fatalf("Unexpected error: %v", err) } fakeClient.WaitForWatchCompletion() // when server returns not found, the watch index starts at the next value (1) if fakeClient.WatchIndex != 1 { t.Errorf("Expected client to be at index %d, got %#v", 1, fakeClient) } // Test normal case pod := &api.Pod{ObjectMeta: api.ObjectMeta{Name: "foo"}} podBytes, _ := codec.Encode(pod) fakeClient.WatchResponse <- &etcd.Response{ Action: "set", Node: &etcd.Node{ Value: string(podBytes), }, } event := <-watching.ResultChan() if e, a := watch.Added, event.Type; e != a { t.Errorf("Expected %v, got %v", e, a) } if e, a := pod, event.Object; !api.Semantic.DeepDerivative(e, a) { t.Errorf("Expected %v, got %v", e, a) } // Test error case fakeClient.WatchInjectError <- fmt.Errorf("Injected error") if errEvent, ok := <-watching.ResultChan(); !ok { t.Errorf("no error result?") } else { if e, a := watch.Error, errEvent.Type; e != a { t.Errorf("Expected %v, got %v", e, a) } if e, a := "Injected error", errEvent.Object.(*api.Status).Message; e != a { t.Errorf("Expected %v, got %v", e, a) } } // Did everything shut down? if _, open := <-fakeClient.WatchResponse; open { t.Errorf("An injected error did not cause a graceful shutdown") } if _, open := <-watching.ResultChan(); open { t.Errorf("An injected error did not cause a graceful shutdown") } }
func TestCreateObjNilOutParam(t *testing.T) { obj := &api.Pod{ObjectMeta: api.ObjectMeta{Name: "foo"}} fakeClient := NewFakeEtcdClient(t) helper := NewEtcdHelper(fakeClient, testapi.Codec(), etcdtest.PathPrefix()) err := helper.CreateObj("/some/key", obj, nil, 5) if err != nil { t.Errorf("Unexpected error %#v", err) } }
func TestSetObjFailCAS(t *testing.T) { obj := &api.Pod{ObjectMeta: api.ObjectMeta{Name: "foo", ResourceVersion: "1"}} fakeClient := NewFakeEtcdClient(t) fakeClient.CasErr = fakeClient.NewError(123) helper := NewEtcdHelper(fakeClient, testapi.Codec(), etcdtest.PathPrefix()) err := helper.SetObj("/some/key", obj, nil, 5) if err == nil { t.Errorf("Expecting error.") } }
func TestGuaranteedUpdate(t *testing.T) { fakeClient := NewFakeEtcdClient(t) fakeClient.TestIndex = true helper := NewEtcdHelper(fakeClient, codec, etcdtest.PathPrefix()) key := etcdtest.AddPrefix("/some/key") // Create a new node. fakeClient.ExpectNotFoundGet(key) obj := &TestResource{ObjectMeta: api.ObjectMeta{Name: "foo"}, Value: 1} err := helper.GuaranteedUpdate("/some/key", &TestResource{}, true, SimpleUpdate(func(in runtime.Object) (runtime.Object, error) { return obj, nil })) if err != nil { t.Errorf("Unexpected error %#v", err) } data, err := codec.Encode(obj) if err != nil { t.Errorf("Unexpected error %#v", err) } expect := string(data) got := fakeClient.Data[key].R.Node.Value if expect != got { t.Errorf("Wanted %v, got %v", expect, got) } // Update an existing node. callbackCalled := false objUpdate := &TestResource{ObjectMeta: api.ObjectMeta{Name: "foo"}, Value: 2} err = helper.GuaranteedUpdate("/some/key", &TestResource{}, true, SimpleUpdate(func(in runtime.Object) (runtime.Object, error) { callbackCalled = true if in.(*TestResource).Value != 1 { t.Errorf("Callback input was not current set value") } return objUpdate, nil })) if err != nil { t.Errorf("Unexpected error %#v", err) } data, err = codec.Encode(objUpdate) if err != nil { t.Errorf("Unexpected error %#v", err) } expect = string(data) got = fakeClient.Data[key].R.Node.Value if expect != got { t.Errorf("Wanted %v, got %v", expect, got) } if !callbackCalled { t.Errorf("tryUpdate callback should have been called.") } }
func TestWatch(t *testing.T) { client := framework.NewEtcdClient() helper := tools.NewEtcdHelper(client, testapi.Codec(), etcdtest.PathPrefix()) framework.WithEtcdKey(func(key string) { key = etcdtest.AddPrefix(key) resp, err := client.Set(key, runtime.EncodeOrDie(testapi.Codec(), &api.Pod{ObjectMeta: api.ObjectMeta{Name: "foo"}}), 0) if err != nil { t.Fatalf("unexpected error: %v", err) } expectedVersion := resp.Node.ModifiedIndex // watch should load the object at the current index w, err := helper.Watch(key, 0, tools.Everything) if err != nil { t.Fatalf("Unexpected error: %v", err) } event := <-w.ResultChan() if event.Type != watch.Added || event.Object == nil { t.Fatalf("expected first value to be set to ADDED, got %#v", event) } // version should match what we set pod := event.Object.(*api.Pod) if pod.ResourceVersion != strconv.FormatUint(expectedVersion, 10) { t.Errorf("expected version %d, got %#v", expectedVersion, pod) } // should be no events in the stream select { case event, ok := <-w.ResultChan(): if !ok { t.Fatalf("channel closed unexpectedly") } t.Fatalf("unexpected object in channel: %#v", event) default: } // should return the previously deleted item in the watch, but with the latest index resp, err = client.Delete(key, false) if err != nil { t.Fatalf("unexpected error: %v", err) } expectedVersion = resp.Node.ModifiedIndex event = <-w.ResultChan() if event.Type != watch.Deleted { t.Errorf("expected deleted event %#v", event) } pod = event.Object.(*api.Pod) if pod.ResourceVersion != strconv.FormatUint(expectedVersion, 10) { t.Errorf("expected version %d, got %#v", expectedVersion, pod) } }) }
func TestGuaranteedUpdate_CreateCollision(t *testing.T) { fakeClient := NewFakeEtcdClient(t) fakeClient.TestIndex = true helper := NewEtcdHelper(fakeClient, codec, etcdtest.PathPrefix()) key := etcdtest.AddPrefix("/some/key") fakeClient.ExpectNotFoundGet(key) const concurrency = 10 var wgDone sync.WaitGroup var wgForceCollision sync.WaitGroup wgDone.Add(concurrency) wgForceCollision.Add(concurrency) for i := 0; i < concurrency; i++ { // Increment TestResource.Value by 1 go func() { defer wgDone.Done() firstCall := true err := helper.GuaranteedUpdate("/some/key", &TestResource{}, true, SimpleUpdate(func(in runtime.Object) (runtime.Object, error) { defer func() { firstCall = false }() if firstCall { // Force collision by joining all concurrent GuaranteedUpdate operations here. wgForceCollision.Done() wgForceCollision.Wait() } currValue := in.(*TestResource).Value obj := &TestResource{ObjectMeta: api.ObjectMeta{Name: "foo"}, Value: currValue + 1} return obj, nil })) if err != nil { t.Errorf("Unexpected error %#v", err) } }() } wgDone.Wait() // Check that stored TestResource has received all updates. body := fakeClient.Data[key].R.Node.Value stored := &TestResource{} if err := codec.DecodeInto([]byte(body), stored); err != nil { t.Errorf("Error decoding stored value: %v", body) } if stored.Value != concurrency { t.Errorf("Some of the writes were lost. Stored value: %d", stored.Value) } }
func TestWatchListIgnoresRootKey(t *testing.T) { codec := latest.Codec pod := &api.Pod{ObjectMeta: api.ObjectMeta{Name: "foo"}} key := "/some/key" prefixedKey := etcdtest.AddPrefix(key) fakeClient := NewFakeEtcdClient(t) h := NewEtcdHelper(fakeClient, codec, etcdtest.PathPrefix()) watching, err := h.WatchList(key, 1, Everything) if err != nil { t.Fatalf("Unexpected error: %v", err) } fakeClient.WaitForWatchCompletion() // This is the root directory of the watch, which happens to have a value encoded fakeClient.WatchResponse <- &etcd.Response{ Action: "delete", PrevNode: &etcd.Node{ Key: prefixedKey, Value: runtime.EncodeOrDie(codec, pod), CreatedIndex: 1, ModifiedIndex: 1, }, } // Delete of the parent directory of a key is an event that a list watch would receive, // but will have no value so the decode will fail. fakeClient.WatchResponse <- &etcd.Response{ Action: "delete", PrevNode: &etcd.Node{ Key: prefixedKey, Value: "", CreatedIndex: 1, ModifiedIndex: 1, }, } close(fakeClient.WatchStop) // the existing node is detected and the index set _, open := <-watching.ResultChan() if open { t.Fatalf("unexpected channel open") } watching.Stop() }
func TestPrefixEtcdKey(t *testing.T) { fakeClient := NewFakeEtcdClient(t) prefix := path.Join("/", etcdtest.PathPrefix()) helper := NewEtcdHelper(fakeClient, testapi.Codec(), prefix) baseKey := "/some/key" // Verify prefix is added keyBefore := baseKey keyAfter := helper.PrefixEtcdKey(keyBefore) assert.Equal(t, keyAfter, path.Join(prefix, baseKey), "Prefix incorrectly added by EtcdHelper") // Verify prefix is not added keyBefore = path.Join(prefix, baseKey) keyAfter = helper.PrefixEtcdKey(keyBefore) assert.Equal(t, keyBefore, keyAfter, "Prefix incorrectly added by EtcdHelper") }
func TestExtractObjNotFoundErr(t *testing.T) { fakeClient := NewFakeEtcdClient(t) helper := NewEtcdHelper(fakeClient, testapi.Codec(), etcdtest.PathPrefix()) key1 := etcdtest.AddPrefix("/some/key") fakeClient.Data[key1] = EtcdResponseWithError{ R: &etcd.Response{ Node: nil, }, E: &etcd.EtcdError{ ErrorCode: 100, }, } key2 := etcdtest.AddPrefix("/some/key2") fakeClient.Data[key2] = EtcdResponseWithError{ R: &etcd.Response{ Node: nil, }, } key3 := etcdtest.AddPrefix("/some/key3") fakeClient.Data[key3] = EtcdResponseWithError{ R: &etcd.Response{ Node: &etcd.Node{ Value: "", }, }, } try := func(key string) { var got api.Pod err := helper.ExtractObj(key, &got, false) if err == nil { t.Errorf("%s: wanted error but didn't get one", key) } err = helper.ExtractObj(key, &got, true) if err != nil { t.Errorf("%s: didn't want error but got %#v", key, err) } } try("/some/key") try("/some/key2") try("/some/key3") }
func TestWatchFromOtherError(t *testing.T) { fakeClient := NewFakeEtcdClient(t) key := "/some/key" prefixedKey := etcdtest.AddPrefix(key) fakeClient.Data[prefixedKey] = EtcdResponseWithError{ R: &etcd.Response{ Node: nil, }, E: &etcd.EtcdError{ Index: 2, ErrorCode: 101, }, } h := NewEtcdHelper(fakeClient, codec, etcdtest.PathPrefix()) watching, err := h.Watch(key, 0, Everything) if err != nil { t.Fatalf("Unexpected error: %v", err) } errEvent := <-watching.ResultChan() if e, a := watch.Error, errEvent.Type; e != a { t.Errorf("Expected %v, got %v", e, a) } if e, a := "101: () [2]", errEvent.Object.(*api.Status).Message; e != a { t.Errorf("Expected %v, got %v", e, a) } select { case _, ok := <-watching.ResultChan(): if ok { t.Fatalf("expected result channel to be closed") } case <-time.After(1 * time.Second): t.Fatalf("watch should have closed channel: %#v", watching) } if fakeClient.WatchResponse != nil || fakeClient.WatchIndex != 0 { t.Fatalf("Watch should not have been invoked: %#v", fakeClient) } }
func TestGetServersToValidate(t *testing.T) { master := Master{} config := Config{} fakeClient := tools.NewFakeEtcdClient(t) fakeClient.Machines = []string{"http://machine1:4001", "http://machine2", "http://machine3:4003"} config.EtcdHelper = tools.NewEtcdHelper(fakeClient, latest.Codec, etcdtest.PathPrefix()) config.EtcdHelper.Versioner = nil master.nodeRegistry = registrytest.NewMinionRegistry([]string{"node1", "node2"}, api.NodeResources{}) servers := master.getServersToValidate(&config) if len(servers) != 5 { t.Errorf("unexpected server list: %#v", servers) } for _, server := range []string{"scheduler", "controller-manager", "etcd-0", "etcd-1", "etcd-2"} { if _, ok := servers[server]; !ok { t.Errorf("server list missing: %s", server) } } }
func TestExtractObj(t *testing.T) { fakeClient := NewFakeEtcdClient(t) helper := NewEtcdHelper(fakeClient, testapi.Codec(), etcdtest.PathPrefix()) key := etcdtest.AddPrefix("/some/key") expect := api.Pod{ ObjectMeta: api.ObjectMeta{Name: "foo"}, Spec: api.PodSpec{ RestartPolicy: api.RestartPolicyAlways, DNSPolicy: api.DNSClusterFirst, }, } fakeClient.Set(key, runtime.EncodeOrDie(testapi.Codec(), &expect), 0) var got api.Pod err := helper.ExtractObj("/some/key", &got, false) if err != nil { t.Errorf("Unexpected error %#v", err) } if !reflect.DeepEqual(got, expect) { t.Errorf("Wanted %#v, got %#v", expect, got) } }
func NewTestGenericEtcdRegistry(t *testing.T) (*tools.FakeEtcdClient, *Etcd) { f := tools.NewFakeEtcdClient(t) f.TestIndex = true h := tools.NewEtcdHelper(f, testapi.Codec(), etcdtest.PathPrefix()) strategy := &testRESTStrategy{api.Scheme, api.SimpleNameGenerator, true, false, true} podPrefix := "/pods" return f, &Etcd{ NewFunc: func() runtime.Object { return &api.Pod{} }, NewListFunc: func() runtime.Object { return &api.PodList{} }, EndpointName: "pods", CreateStrategy: strategy, UpdateStrategy: strategy, KeyRootFunc: func(ctx api.Context) string { return podPrefix }, KeyFunc: func(ctx api.Context, id string) (string, error) { return path.Join(podPrefix, id), nil }, ObjectNameFunc: func(obj runtime.Object) (string, error) { return obj.(*api.Pod).Name, nil }, Helper: h, } }
// Benchmark pod listing by waiting on `Tasks` listers to list `Pods` pods via `Workers`. func BenchmarkPodListEtcd(b *testing.B) { b.StopTimer() m := framework.NewMasterComponents(&framework.Config{nil, true, false, 250.0, 500}) defer m.Stop(true, true) numPods, numTasks, iter := getPods(b.N), getTasks(b.N), getIterations(b.N) podsPerNode := numPods / numTasks if podsPerNode < 1 { podsPerNode = 1 } startPodsOnNodes(numPods, numTasks, m.RestClient) // Stop the rc manager so it doesn't steal resources m.Stop(false, true) glog.Infof("Starting benchmark: b.N %d, pods %d, workers %d, podsPerNode %d", b.N, numPods, numTasks, podsPerNode) ctx := api.WithNamespace(api.NewContext(), framework.TestNS) key := etcdgeneric.NamespaceKeyRootFunc(ctx, fmt.Sprintf("%s/pods", etcdtest.PathPrefix())) b.StartTimer() for i := 0; i < iter; i++ { framework.RunParallel(func(id int) error { now := time.Now() defer func() { glog.V(3).Infof("Worker %d: listing pods took %v", id, time.Since(now)) }() if response, err := m.EtcdHelper.Client.Get(key, true, true); err != nil { return err } else if len(response.Node.Nodes) < podsPerNode { glog.Fatalf("List retrieved %d pods, which is less than %d", len(response.Node.Nodes), podsPerNode) } return nil }, numTasks, Workers) } b.StopTimer() }
// TODO: Merge this into startMasterOrDie. func RunAMaster(t *testing.T) (*master.Master, *httptest.Server) { helper, err := master.NewEtcdHelper(NewEtcdClient(), testapi.Version(), etcdtest.PathPrefix()) if err != nil { t.Fatalf("unexpected error: %v", err) } m := master.New(&master.Config{ EtcdHelper: helper, QingletClient: client.FakeQingletClient{}, EnableLogsSupport: false, EnableProfiling: true, EnableUISupport: false, APIPrefix: "/api", Authorizer: apiserver.NewAlwaysAllowAuthorizer(), AdmissionControl: admit.NewAlwaysAdmit(), }) s := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) { m.Handler.ServeHTTP(w, req) })) return m, s }
func TestSetObjWithVersion(t *testing.T) { obj := &api.Pod{ObjectMeta: api.ObjectMeta{Name: "foo", ResourceVersion: "1"}} fakeClient := NewFakeEtcdClient(t) fakeClient.TestIndex = true helper := NewEtcdHelper(fakeClient, testapi.Codec(), etcdtest.PathPrefix()) key := etcdtest.AddPrefix("/some/key") fakeClient.Data[key] = EtcdResponseWithError{ R: &etcd.Response{ Node: &etcd.Node{ Value: runtime.EncodeOrDie(testapi.Codec(), obj), ModifiedIndex: 1, }, }, } returnedObj := &api.Pod{} err := helper.SetObj("/some/key", obj, returnedObj, 7) if err != nil { t.Fatalf("Unexpected error %#v", err) } data, err := testapi.Codec().Encode(obj) if err != nil { t.Fatalf("Unexpected error %#v", err) } expect := string(data) got := fakeClient.Data[key].R.Node.Value if expect != got { t.Errorf("Wanted %v, got %v", expect, got) } if e, a := uint64(7), fakeClient.LastSetTTL; e != a { t.Errorf("Wanted %v, got %v", e, a) } if obj.ResourceVersion != returnedObj.ResourceVersion || obj.Name != returnedObj.Name { t.Errorf("If set was successful but returned object did not have correct resource version") } }
func NewHelper() (tools.EtcdHelper, error) { return master.NewEtcdHelper(NewEtcdClient(), testapi.Version(), etcdtest.PathPrefix()) }
// startServiceAccountTestServer returns a started server // It is the responsibility of the caller to ensure the returned stopFunc is called func startServiceAccountTestServer(t *testing.T) (*client.Client, client.Config, func()) { deleteAllEtcdKeys() // Etcd helper, err := master.NewEtcdHelper(newEtcdClient(), testapi.Version(), etcdtest.PathPrefix()) if err != nil { t.Fatalf("unexpected error: %v", err) } // Listener var m *master.Master apiServer := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) { m.Handler.ServeHTTP(w, req) })) // Anonymous client config clientConfig := client.Config{Host: apiServer.URL, Version: testapi.Version()} // Root client rootClient := client.NewOrDie(&client.Config{Host: apiServer.URL, Version: testapi.Version(), BearerToken: rootToken}) // Set up two authenticators: // 1. A token authenticator that maps the rootToken to the "root" user // 2. A ServiceAccountToken authenticator that validates ServiceAccount tokens rootTokenAuth := authenticator.TokenFunc(func(token string) (user.Info, bool, error) { if token == rootToken { return &user.DefaultInfo{rootUserName, "", []string{}}, true, nil } return nil, false, nil }) serviceAccountKey, err := rsa.GenerateKey(rand.Reader, 2048) serviceAccountTokenGetter := serviceaccount.NewGetterFromClient(rootClient) serviceAccountTokenAuth := serviceaccount.JWTTokenAuthenticator([]*rsa.PublicKey{&serviceAccountKey.PublicKey}, true, serviceAccountTokenGetter) authenticator := union.New( bearertoken.New(rootTokenAuth), bearertoken.New(serviceAccountTokenAuth), ) // Set up a stub authorizer: // 1. The "root" user is allowed to do anything // 2. ServiceAccounts named "ro" are allowed read-only operations in their namespace // 3. ServiceAccounts named "rw" are allowed any operation in their namespace authorizer := authorizer.AuthorizerFunc(func(attrs authorizer.Attributes) error { username := attrs.GetUserName() ns := attrs.GetNamespace() // If the user is "root"... if username == rootUserName { // allow them to do anything return nil } // If the user is a service account... if serviceAccountNamespace, serviceAccountName, err := serviceaccount.SplitUsername(username); err == nil { // Limit them to their own namespace if serviceAccountNamespace == ns { switch serviceAccountName { case readOnlyServiceAccountName: if attrs.IsReadOnly() { return nil } case readWriteServiceAccountName: return nil } } } return fmt.Errorf("User %s is denied (ns=%s, readonly=%v, resource=%s)", username, ns, attrs.IsReadOnly(), attrs.GetResource()) }) // Set up admission plugin to auto-assign serviceaccounts to pods serviceAccountAdmission := serviceaccountadmission.NewServiceAccount(rootClient) // Create a master and install handlers into mux. m = master.New(&master.Config{ EtcdHelper: helper, QingletClient: client.FakeQingletClient{}, EnableLogsSupport: false, EnableUISupport: false, EnableIndex: true, APIPrefix: "/api", Authenticator: authenticator, Authorizer: authorizer, AdmissionControl: serviceAccountAdmission, }) // Start the service account and service account token controllers tokenController := serviceaccount.NewTokensController(rootClient, serviceaccount.DefaultTokenControllerOptions(serviceaccount.JWTTokenGenerator(serviceAccountKey))) tokenController.Run() serviceAccountController := serviceaccount.NewServiceAccountsController(rootClient, serviceaccount.DefaultServiceAccountsControllerOptions()) serviceAccountController.Run() // Start the admission plugin reflectors serviceAccountAdmission.Run() stop := func() { tokenController.Stop() serviceAccountController.Stop() serviceAccountAdmission.Stop() apiServer.Close() } return rootClient, clientConfig, stop }
func newHelper(t *testing.T) (*tools.FakeEtcdClient, tools.EtcdHelper) { fakeEtcdClient := tools.NewFakeEtcdClient(t) fakeEtcdClient.TestIndex = true helper := tools.NewEtcdHelper(fakeEtcdClient, testapi.Codec(), etcdtest.PathPrefix()) return fakeEtcdClient, helper }
func TestWatchListFromZeroIndex(t *testing.T) { codec := latest.Codec pod := &api.Pod{ObjectMeta: api.ObjectMeta{Name: "foo"}} key := "/some/key" prefixedKey := etcdtest.AddPrefix(key) fakeClient := NewFakeEtcdClient(t) fakeClient.Data[prefixedKey] = EtcdResponseWithError{ R: &etcd.Response{ Node: &etcd.Node{ Dir: true, Nodes: etcd.Nodes{ &etcd.Node{ Value: runtime.EncodeOrDie(codec, pod), CreatedIndex: 1, ModifiedIndex: 1, Nodes: etcd.Nodes{}, }, &etcd.Node{ Value: runtime.EncodeOrDie(codec, pod), CreatedIndex: 2, ModifiedIndex: 2, Nodes: etcd.Nodes{}, }, }, }, Action: "get", EtcdIndex: 3, }, } h := NewEtcdHelper(fakeClient, codec, etcdtest.PathPrefix()) watching, err := h.WatchList(key, 0, Everything) if err != nil { t.Fatalf("Unexpected error: %v", err) } // the existing node is detected and the index set event, open := <-watching.ResultChan() if !open { t.Fatalf("unexpected channel close") } for i := 0; i < 2; i++ { if e, a := watch.Added, event.Type; e != a { t.Errorf("Expected %v, got %v", e, a) } actualPod, ok := event.Object.(*api.Pod) if !ok { t.Fatalf("expected a pod, got %#v", event.Object) } if actualPod.ResourceVersion != "1" { t.Errorf("Expected pod with resource version %d, Got %#v", 1, actualPod) } pod.ResourceVersion = "1" if e, a := pod, event.Object; !api.Semantic.DeepDerivative(e, a) { t.Errorf("Expected %v, got %v", e, a) } } fakeClient.WaitForWatchCompletion() watching.Stop() }