func NewTestGenericEtcdRegistry(t *testing.T) (*tools.FakeEtcdClient, *Etcd) { f := tools.NewFakeEtcdClient(t) f.TestIndex = true s := etcdstorage.NewEtcdStorage(f, testapi.Default.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) { if _, ok := api.NamespaceFrom(ctx); !ok { return "", fmt.Errorf("namespace is required") } return path.Join(podPrefix, id), nil }, ObjectNameFunc: func(obj runtime.Object) (string, error) { return obj.(*api.Pod).Name, nil }, Storage: s, } }
func initThirdParty(t *testing.T, version string) (*Master, *tools.FakeEtcdClient, *httptest.Server, *assert.Assertions) { master, _, assert := setUp(t) master.thirdPartyResources = map[string]*thirdpartyresourcedatastorage.REST{} api := &extensions.ThirdPartyResource{ ObjectMeta: api.ObjectMeta{ Name: "foo.company.com", }, Versions: []extensions.APIVersion{ { APIGroup: "group", Name: version, }, }, } master.handlerContainer = restful.NewContainer() fakeClient := tools.NewFakeEtcdClient(t) fakeClient.Machines = []string{"http://machine1:4001", "http://machine2", "http://machine3:4003"} master.thirdPartyStorage = etcdstorage.NewEtcdStorage(fakeClient, testapi.Extensions.Codec(), etcdtest.PathPrefix()) if !assert.NoError(master.InstallThirdPartyResource(api)) { t.FailNow() } server := httptest.NewServer(master.handlerContainer.ServeMux) return &master, fakeClient, server, assert }
// NewEtcdStorage returns a storage.Interface for the provided arguments or an error if the version // is incorrect. func NewEtcdStorage(client tools.EtcdClient, interfacesFunc meta.VersionInterfacesFunc, version, prefix string) (etcdStorage storage.Interface, err error) { versionInterfaces, err := interfacesFunc(version) if err != nil { return etcdStorage, err } return etcdstorage.NewEtcdStorage(client, versionInterfaces.Codec, prefix), nil }
// setUp is a convience function for setting up for (most) tests. func setUp(t *testing.T) (Master, Config, *assert.Assertions) { master := Master{} config := Config{} fakeClient := tools.NewFakeEtcdClient(t) fakeClient.Machines = []string{"http://machine1:4001", "http://machine2", "http://machine3:4003"} storageVersions := make(map[string]string) storageDestinations := NewStorageDestinations() storageDestinations.AddAPIGroup("", etcdstorage.NewEtcdStorage(fakeClient, testapi.Default.Codec(), etcdtest.PathPrefix())) storageDestinations.AddAPIGroup("extensions", etcdstorage.NewEtcdStorage(fakeClient, testapi.Extensions.Codec(), etcdtest.PathPrefix())) config.StorageDestinations = storageDestinations storageVersions[""] = testapi.Default.Version() storageVersions["extensions"] = testapi.Extensions.GroupAndVersion() config.StorageVersions = storageVersions master.nodeRegistry = registrytest.NewNodeRegistry([]string{"node1", "node2"}, api.NodeResources{}) return master, config, assert.New(t) }
func TestWatch(t *testing.T) { client := framework.NewEtcdClient() etcdStorage := etcd.NewEtcdStorage(client, testapi.Default.Codec(), etcdtest.PathPrefix()) framework.WithEtcdKey(func(key string) { key = etcdtest.AddPrefix(key) resp, err := client.Set(key, runtime.EncodeOrDie(testapi.Default.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 := etcdStorage.Watch(key, 0, storage.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 TestWriteTTL(t *testing.T) { client := framework.NewEtcdClient() etcdStorage := etcd.NewEtcdStorage(client, testapi.Default.Codec(), "") framework.WithEtcdKey(func(key string) { testObject := api.ServiceAccount{ObjectMeta: api.ObjectMeta{Name: "foo"}} if err := etcdStorage.Set(key, &testObject, nil, 0); err != nil { t.Fatalf("unexpected error: %v", err) } result := &api.ServiceAccount{} err := etcdStorage.GuaranteedUpdate(key, result, false, func(obj runtime.Object, res storage.ResponseMeta) (runtime.Object, *uint64, error) { if in, ok := obj.(*api.ServiceAccount); !ok || in.Name != "foo" { t.Fatalf("unexpected existing object: %v", obj) } if res.TTL != 0 { t.Fatalf("unexpected TTL: %#v", res) } ttl := uint64(10) out := &api.ServiceAccount{ObjectMeta: api.ObjectMeta{Name: "out"}} return out, &ttl, nil }) if err != nil { t.Fatalf("unexpected error: %v", err) } if result.Name != "out" { t.Errorf("unexpected response: %#v", result) } if res, err := client.Get(key, false, false); err != nil || res == nil || res.Node.TTL != 10 { t.Fatalf("unexpected get: %v %#v", err, res) } result = &api.ServiceAccount{} err = etcdStorage.GuaranteedUpdate(key, result, false, func(obj runtime.Object, res storage.ResponseMeta) (runtime.Object, *uint64, error) { if in, ok := obj.(*api.ServiceAccount); !ok || in.Name != "out" { t.Fatalf("unexpected existing object: %v", obj) } if res.TTL <= 1 { t.Fatalf("unexpected TTL: %#v", res) } out := &api.ServiceAccount{ObjectMeta: api.ObjectMeta{Name: "out2"}} return out, nil, nil }) if err != nil { t.Fatalf("unexpected error: %v", err) } if result.Name != "out2" { t.Errorf("unexpected response: %#v", result) } if res, err := client.Get(key, false, false); err != nil || res == nil || res.Node.TTL <= 1 { t.Fatalf("unexpected get: %v %#v", err, res) } }) }
func newTestCacher(client tools.EtcdClient) *storage.Cacher { prefix := "pods" config := storage.CacherConfig{ CacheCapacity: 10, Versioner: etcdstorage.APIObjectVersioner{}, Storage: etcdstorage.NewEtcdStorage(client, testapi.Default.Codec(), etcdtest.PathPrefix()), Type: &api.Pod{}, ResourcePrefix: prefix, KeyFunc: func(obj runtime.Object) (string, error) { return storage.NamespaceKeyFunc(prefix, obj) }, NewListFunc: func() runtime.Object { return &api.PodList{} }, StopChannel: util.NeverStop, } return storage.NewCacher(config) }
func TestSet(t *testing.T) { client := framework.NewEtcdClient() etcdStorage := etcd.NewEtcdStorage(client, testapi.Default.Codec(), "") framework.WithEtcdKey(func(key string) { testObject := api.ServiceAccount{ObjectMeta: api.ObjectMeta{Name: "foo"}} if err := etcdStorage.Set(key, &testObject, nil, 0); err != nil { t.Fatalf("unexpected error: %v", err) } resp, err := client.Get(key, false, false) if err != nil || resp.Node == nil { t.Fatalf("unexpected error: %v %v", err, resp) } decoded, err := testapi.Default.Codec().Decode([]byte(resp.Node.Value)) if err != nil { t.Fatalf("unexpected response: %#v", resp.Node) } result := *decoded.(*api.ServiceAccount) if !api.Semantic.DeepEqual(testObject, result) { t.Errorf("expected: %#v got: %#v", testObject, result) } }) }
func TestGet(t *testing.T) { client := framework.NewEtcdClient() etcdStorage := etcd.NewEtcdStorage(client, testapi.Default.Codec(), "") framework.WithEtcdKey(func(key string) { testObject := api.ServiceAccount{ObjectMeta: api.ObjectMeta{Name: "foo"}} coded, err := testapi.Default.Codec().Encode(&testObject) if err != nil { t.Fatalf("unexpected error: %v", err) } _, err = client.Set(key, string(coded), 0) if err != nil { t.Fatalf("unexpected error: %v", err) } result := api.ServiceAccount{} if err := etcdStorage.Get(key, &result, false); err != nil { t.Fatalf("unexpected error: %v", err) } // Propagate ResourceVersion (it is set automatically). testObject.ObjectMeta.ResourceVersion = result.ObjectMeta.ResourceVersion if !api.Semantic.DeepEqual(testObject, result) { t.Errorf("expected: %#v got: %#v", testObject, result) } }) }
func NewEtcdStorage(t *testing.T, group string) (storage.Interface, *tools.FakeEtcdClient) { fakeClient := tools.NewFakeEtcdClient(t) fakeClient.TestIndex = true etcdStorage := etcdstorage.NewEtcdStorage(fakeClient, testapi.Groups[group].Codec(), etcdtest.PathPrefix()) return etcdStorage, fakeClient }