From c416ee584c178bb89c6cd11c93b504f2098fac0f Mon Sep 17 00:00:00 2001 From: Clayton Coleman Date: Tue, 12 Feb 2019 00:31:54 -0500 Subject: [PATCH] Remove deprecated-dynamic client It is now unused. --- hack/.golint_failures | 1 - staging/src/k8s.io/client-go/BUILD | 1 - .../k8s.io/client-go/deprecated-dynamic/BUILD | 54 -- .../client-go/deprecated-dynamic/client.go | 131 ---- .../deprecated-dynamic/client_pool.go | 122 ---- .../deprecated-dynamic/client_test.go | 624 ------------------ 6 files changed, 933 deletions(-) delete mode 100644 staging/src/k8s.io/client-go/deprecated-dynamic/BUILD delete mode 100644 staging/src/k8s.io/client-go/deprecated-dynamic/client.go delete mode 100644 staging/src/k8s.io/client-go/deprecated-dynamic/client_pool.go delete mode 100644 staging/src/k8s.io/client-go/deprecated-dynamic/client_test.go diff --git a/hack/.golint_failures b/hack/.golint_failures index 877f1da5dfa..882b494988a 100644 --- a/hack/.golint_failures +++ b/hack/.golint_failures @@ -412,7 +412,6 @@ staging/src/k8s.io/apiserver/plugin/pkg/authorizer/webhook staging/src/k8s.io/cli-runtime/pkg/genericclioptions staging/src/k8s.io/cli-runtime/pkg/printers staging/src/k8s.io/cli-runtime/pkg/resource -staging/src/k8s.io/client-go/deprecated-dynamic staging/src/k8s.io/client-go/discovery staging/src/k8s.io/client-go/discovery/fake staging/src/k8s.io/client-go/dynamic diff --git a/staging/src/k8s.io/client-go/BUILD b/staging/src/k8s.io/client-go/BUILD index ba10f5c810e..7a555102ec7 100644 --- a/staging/src/k8s.io/client-go/BUILD +++ b/staging/src/k8s.io/client-go/BUILD @@ -9,7 +9,6 @@ filegroup( name = "all-srcs", srcs = [ ":package-srcs", - "//staging/src/k8s.io/client-go/deprecated-dynamic:all-srcs", "//staging/src/k8s.io/client-go/discovery:all-srcs", "//staging/src/k8s.io/client-go/dynamic:all-srcs", "//staging/src/k8s.io/client-go/examples/create-update-delete-deployment:all-srcs", diff --git a/staging/src/k8s.io/client-go/deprecated-dynamic/BUILD b/staging/src/k8s.io/client-go/deprecated-dynamic/BUILD deleted file mode 100644 index 4ce83f632d9..00000000000 --- a/staging/src/k8s.io/client-go/deprecated-dynamic/BUILD +++ /dev/null @@ -1,54 +0,0 @@ -load("@io_bazel_rules_go//go:def.bzl", "go_library", "go_test") - -go_library( - name = "go_default_library", - srcs = [ - "client.go", - "client_pool.go", - ], - importmap = "k8s.io/kubernetes/vendor/k8s.io/client-go/deprecated-dynamic", - importpath = "k8s.io/client-go/deprecated-dynamic", - visibility = ["//visibility:public"], - deps = [ - "//staging/src/k8s.io/apimachinery/pkg/api/meta:go_default_library", - "//staging/src/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library", - "//staging/src/k8s.io/apimachinery/pkg/apis/meta/v1/unstructured:go_default_library", - "//staging/src/k8s.io/apimachinery/pkg/runtime:go_default_library", - "//staging/src/k8s.io/apimachinery/pkg/runtime/schema:go_default_library", - "//staging/src/k8s.io/apimachinery/pkg/types:go_default_library", - "//staging/src/k8s.io/apimachinery/pkg/watch:go_default_library", - "//staging/src/k8s.io/client-go/dynamic:go_default_library", - "//staging/src/k8s.io/client-go/rest:go_default_library", - ], -) - -go_test( - name = "go_default_test", - srcs = ["client_test.go"], - embed = [":go_default_library"], - deps = [ - "//staging/src/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library", - "//staging/src/k8s.io/apimachinery/pkg/apis/meta/v1/unstructured:go_default_library", - "//staging/src/k8s.io/apimachinery/pkg/runtime:go_default_library", - "//staging/src/k8s.io/apimachinery/pkg/runtime/schema:go_default_library", - "//staging/src/k8s.io/apimachinery/pkg/runtime/serializer/streaming:go_default_library", - "//staging/src/k8s.io/apimachinery/pkg/types:go_default_library", - "//staging/src/k8s.io/apimachinery/pkg/watch:go_default_library", - "//staging/src/k8s.io/client-go/rest:go_default_library", - "//staging/src/k8s.io/client-go/rest/watch:go_default_library", - ], -) - -filegroup( - name = "package-srcs", - srcs = glob(["**"]), - tags = ["automanaged"], - visibility = ["//visibility:private"], -) - -filegroup( - name = "all-srcs", - srcs = [":package-srcs"], - tags = ["automanaged"], - visibility = ["//visibility:public"], -) diff --git a/staging/src/k8s.io/client-go/deprecated-dynamic/client.go b/staging/src/k8s.io/client-go/deprecated-dynamic/client.go deleted file mode 100644 index bcbfed706f4..00000000000 --- a/staging/src/k8s.io/client-go/deprecated-dynamic/client.go +++ /dev/null @@ -1,131 +0,0 @@ -/* -Copyright 2016 The Kubernetes Authors. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -// Package dynamic provides a client interface to arbitrary Kubernetes -// APIs that exposes common high level operations and exposes common -// metadata. -package deprecated_dynamic - -import ( - "strings" - - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" - "k8s.io/apimachinery/pkg/runtime" - "k8s.io/apimachinery/pkg/runtime/schema" - "k8s.io/apimachinery/pkg/types" - "k8s.io/apimachinery/pkg/watch" - "k8s.io/client-go/dynamic" - restclient "k8s.io/client-go/rest" -) - -// Interface is a Kubernetes client that allows you to access metadata -// and manipulate metadata of a Kubernetes API group. -type Interface interface { - // Resource returns an API interface to the specified resource for this client's - // group and version. If resource is not a namespaced resource, then namespace - // is ignored. The ResourceInterface inherits the parameter codec of this client. - Resource(resource *metav1.APIResource, namespace string) ResourceInterface -} - -// ResourceInterface is an API interface to a specific resource under a -// dynamic client. -type ResourceInterface interface { - // List returns a list of objects for this resource. - List(opts metav1.ListOptions) (runtime.Object, error) - // Get gets the resource with the specified name. - Get(name string, opts metav1.GetOptions) (*unstructured.Unstructured, error) - // Delete deletes the resource with the specified name. - Delete(name string, opts *metav1.DeleteOptions) error - // DeleteCollection deletes a collection of objects. - DeleteCollection(deleteOptions *metav1.DeleteOptions, listOptions metav1.ListOptions) error - // Create creates the provided resource. - Create(obj *unstructured.Unstructured) (*unstructured.Unstructured, error) - // Update updates the provided resource. - Update(obj *unstructured.Unstructured) (*unstructured.Unstructured, error) - // Watch returns a watch.Interface that watches the resource. - Watch(opts metav1.ListOptions) (watch.Interface, error) - // Patch patches the provided resource. - Patch(name string, pt types.PatchType, data []byte) (*unstructured.Unstructured, error) -} - -// Client is a Kubernetes client that allows you to access metadata -// and manipulate metadata of a Kubernetes API group, and implements Interface. -type Client struct { - version schema.GroupVersion - delegate dynamic.Interface -} - -// NewClient returns a new client based on the passed in config. The -// codec is ignored, as the dynamic client uses it's own codec. -func NewClient(conf *restclient.Config, version schema.GroupVersion) (*Client, error) { - delegate, err := dynamic.NewForConfig(conf) - if err != nil { - return nil, err - } - - return &Client{version: version, delegate: delegate}, nil -} - -// Resource returns an API interface to the specified resource for this client's -// group and version. If resource is not a namespaced resource, then namespace -// is ignored. The ResourceInterface inherits the parameter codec of c. -func (c *Client) Resource(resource *metav1.APIResource, namespace string) ResourceInterface { - resourceTokens := strings.SplitN(resource.Name, "/", 2) - subresources := []string{} - if len(resourceTokens) > 1 { - subresources = strings.Split(resourceTokens[1], "/") - } - - if len(namespace) == 0 { - return oldResourceShim(c.delegate.Resource(c.version.WithResource(resourceTokens[0])), subresources) - } - return oldResourceShim(c.delegate.Resource(c.version.WithResource(resourceTokens[0])).Namespace(namespace), subresources) -} - -// the old interfaces used the wrong type for lists. this fixes that -func oldResourceShim(in dynamic.ResourceInterface, subresources []string) ResourceInterface { - return oldResourceShimType{ResourceInterface: in, subresources: subresources} -} - -type oldResourceShimType struct { - dynamic.ResourceInterface - subresources []string -} - -func (s oldResourceShimType) Create(obj *unstructured.Unstructured) (*unstructured.Unstructured, error) { - return s.ResourceInterface.Create(obj, metav1.CreateOptions{}, s.subresources...) -} - -func (s oldResourceShimType) Update(obj *unstructured.Unstructured) (*unstructured.Unstructured, error) { - return s.ResourceInterface.Update(obj, metav1.UpdateOptions{}, s.subresources...) -} - -func (s oldResourceShimType) Delete(name string, opts *metav1.DeleteOptions) error { - return s.ResourceInterface.Delete(name, opts, s.subresources...) -} - -func (s oldResourceShimType) Get(name string, opts metav1.GetOptions) (*unstructured.Unstructured, error) { - return s.ResourceInterface.Get(name, opts, s.subresources...) -} - -func (s oldResourceShimType) List(opts metav1.ListOptions) (runtime.Object, error) { - return s.ResourceInterface.List(opts) -} - -func (s oldResourceShimType) Patch(name string, pt types.PatchType, data []byte) (*unstructured.Unstructured, error) { - return s.ResourceInterface.Patch(name, pt, data, metav1.PatchOptions{}, s.subresources...) -} diff --git a/staging/src/k8s.io/client-go/deprecated-dynamic/client_pool.go b/staging/src/k8s.io/client-go/deprecated-dynamic/client_pool.go deleted file mode 100644 index 36dc54ce487..00000000000 --- a/staging/src/k8s.io/client-go/deprecated-dynamic/client_pool.go +++ /dev/null @@ -1,122 +0,0 @@ -/* -Copyright 2016 The Kubernetes Authors. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -package deprecated_dynamic - -import ( - "sync" - - "k8s.io/apimachinery/pkg/api/meta" - "k8s.io/apimachinery/pkg/runtime/schema" - restclient "k8s.io/client-go/rest" -) - -// ClientPool manages a pool of dynamic clients. -type ClientPool interface { - // ClientForGroupVersionResource returns a client configured for the specified groupVersionResource. - // Resource may be empty. - ClientForGroupVersionResource(resource schema.GroupVersionResource) (Interface, error) - // ClientForGroupVersionKind returns a client configured for the specified groupVersionKind. - // Kind may be empty. - ClientForGroupVersionKind(kind schema.GroupVersionKind) (Interface, error) -} - -// APIPathResolverFunc knows how to convert a groupVersion to its API path. The Kind field is -// optional. -type APIPathResolverFunc func(kind schema.GroupVersionKind) string - -// LegacyAPIPathResolverFunc can resolve paths properly with the legacy API. -func LegacyAPIPathResolverFunc(kind schema.GroupVersionKind) string { - if len(kind.Group) == 0 { - return "/api" - } - return "/apis" -} - -// clientPoolImpl implements ClientPool and caches clients for the resource group versions -// is asked to retrieve. This type is thread safe. -type clientPoolImpl struct { - lock sync.RWMutex - config *restclient.Config - clients map[schema.GroupVersion]*Client - apiPathResolverFunc APIPathResolverFunc - mapper meta.RESTMapper -} - -// NewClientPool returns a ClientPool from the specified config. It reuses clients for the same -// group version. It is expected this type may be wrapped by specific logic that special cases certain -// resources or groups. -func NewClientPool(config *restclient.Config, mapper meta.RESTMapper, apiPathResolverFunc APIPathResolverFunc) ClientPool { - confCopy := *config - - return &clientPoolImpl{ - config: &confCopy, - clients: map[schema.GroupVersion]*Client{}, - apiPathResolverFunc: apiPathResolverFunc, - mapper: mapper, - } -} - -// Instantiates a new dynamic client pool with the given config. -func NewDynamicClientPool(cfg *restclient.Config) ClientPool { - // restMapper is not needed when using LegacyAPIPathResolverFunc - emptyMapper := meta.MultiRESTMapper{} - return NewClientPool(cfg, emptyMapper, LegacyAPIPathResolverFunc) -} - -// ClientForGroupVersionResource uses the provided RESTMapper to identify the appropriate resource. Resource may -// be empty. If no matching kind is found the underlying client for that group is still returned. -func (c *clientPoolImpl) ClientForGroupVersionResource(resource schema.GroupVersionResource) (Interface, error) { - kinds, err := c.mapper.KindsFor(resource) - if err != nil { - if meta.IsNoMatchError(err) { - return c.ClientForGroupVersionKind(schema.GroupVersionKind{Group: resource.Group, Version: resource.Version}) - } - return nil, err - } - return c.ClientForGroupVersionKind(kinds[0]) -} - -// ClientForGroupVersion returns a client for the specified groupVersion, creates one if none exists. Kind -// in the GroupVersionKind may be empty. -func (c *clientPoolImpl) ClientForGroupVersionKind(kind schema.GroupVersionKind) (Interface, error) { - c.lock.Lock() - defer c.lock.Unlock() - - gv := kind.GroupVersion() - - // do we have a client already configured? - if existingClient, found := c.clients[gv]; found { - return existingClient, nil - } - - // avoid changing the original config - confCopy := *c.config - conf := &confCopy - - // we need to set the api path based on group version, if no group, default to legacy path - conf.APIPath = c.apiPathResolverFunc(kind) - - // we need to make a client - conf.GroupVersion = &gv - - dynamicClient, err := NewClient(conf, gv) - if err != nil { - return nil, err - } - c.clients[gv] = dynamicClient - return dynamicClient, nil -} diff --git a/staging/src/k8s.io/client-go/deprecated-dynamic/client_test.go b/staging/src/k8s.io/client-go/deprecated-dynamic/client_test.go deleted file mode 100644 index de88edb5422..00000000000 --- a/staging/src/k8s.io/client-go/deprecated-dynamic/client_test.go +++ /dev/null @@ -1,624 +0,0 @@ -/* -Copyright 2016 The Kubernetes Authors. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -package deprecated_dynamic - -import ( - "bytes" - "fmt" - "io/ioutil" - "net/http" - "net/http/httptest" - "reflect" - "testing" - - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" - "k8s.io/apimachinery/pkg/runtime" - "k8s.io/apimachinery/pkg/runtime/schema" - "k8s.io/apimachinery/pkg/runtime/serializer/streaming" - "k8s.io/apimachinery/pkg/types" - "k8s.io/apimachinery/pkg/watch" - restclient "k8s.io/client-go/rest" - restclientwatch "k8s.io/client-go/rest/watch" -) - -func getJSON(version, kind, name string) []byte { - return []byte(fmt.Sprintf(`{"apiVersion": %q, "kind": %q, "metadata": {"name": %q}}`, version, kind, name)) -} - -func getListJSON(version, kind string, items ...[]byte) []byte { - json := fmt.Sprintf(`{"apiVersion": %q, "kind": %q, "items": [%s]}`, - version, kind, bytes.Join(items, []byte(","))) - return []byte(json) -} - -func getObject(version, kind, name string) *unstructured.Unstructured { - return &unstructured.Unstructured{ - Object: map[string]interface{}{ - "apiVersion": version, - "kind": kind, - "metadata": map[string]interface{}{ - "name": name, - }, - }, - } -} - -func getClientServer(gv *schema.GroupVersion, h func(http.ResponseWriter, *http.Request)) (Interface, *httptest.Server, error) { - srv := httptest.NewServer(http.HandlerFunc(h)) - cl, err := NewClient(&restclient.Config{ - Host: srv.URL, - ContentConfig: restclient.ContentConfig{GroupVersion: gv}, - }, *gv) - if err != nil { - srv.Close() - return nil, nil, err - } - return cl, srv, nil -} - -func TestList(t *testing.T) { - tcs := []struct { - name string - namespace string - path string - resp []byte - want *unstructured.UnstructuredList - }{ - { - name: "normal_list", - path: "/apis/gtest/vtest/rtest", - resp: getListJSON("vTest", "rTestList", - getJSON("vTest", "rTest", "item1"), - getJSON("vTest", "rTest", "item2")), - want: &unstructured.UnstructuredList{ - Object: map[string]interface{}{ - "apiVersion": "vTest", - "kind": "rTestList", - }, - Items: []unstructured.Unstructured{ - *getObject("vTest", "rTest", "item1"), - *getObject("vTest", "rTest", "item2"), - }, - }, - }, - { - name: "namespaced_list", - namespace: "nstest", - path: "/apis/gtest/vtest/namespaces/nstest/rtest", - resp: getListJSON("vTest", "rTestList", - getJSON("vTest", "rTest", "item1"), - getJSON("vTest", "rTest", "item2")), - want: &unstructured.UnstructuredList{ - Object: map[string]interface{}{ - "apiVersion": "vTest", - "kind": "rTestList", - }, - Items: []unstructured.Unstructured{ - *getObject("vTest", "rTest", "item1"), - *getObject("vTest", "rTest", "item2"), - }, - }, - }, - } - for _, tc := range tcs { - gv := &schema.GroupVersion{Group: "gtest", Version: "vtest"} - resource := &metav1.APIResource{Name: "rtest", Namespaced: len(tc.namespace) != 0} - cl, srv, err := getClientServer(gv, func(w http.ResponseWriter, r *http.Request) { - if r.Method != "GET" { - t.Errorf("List(%q) got HTTP method %s. wanted GET", tc.name, r.Method) - } - - if r.URL.Path != tc.path { - t.Errorf("List(%q) got path %s. wanted %s", tc.name, r.URL.Path, tc.path) - } - - w.Header().Set("Content-Type", runtime.ContentTypeJSON) - w.Write(tc.resp) - }) - if err != nil { - t.Errorf("unexpected error when creating client: %v", err) - continue - } - defer srv.Close() - - got, err := cl.Resource(resource, tc.namespace).List(metav1.ListOptions{}) - if err != nil { - t.Errorf("unexpected error when listing %q: %v", tc.name, err) - continue - } - - if !reflect.DeepEqual(got, tc.want) { - t.Errorf("List(%q) want: %v\ngot: %v", tc.name, tc.want, got) - } - } -} - -func TestGet(t *testing.T) { - tcs := []struct { - resource string - namespace string - name string - path string - resp []byte - want *unstructured.Unstructured - }{ - { - resource: "rtest", - name: "normal_get", - path: "/apis/gtest/vtest/rtest/normal_get", - resp: getJSON("vTest", "rTest", "normal_get"), - want: getObject("vTest", "rTest", "normal_get"), - }, - { - resource: "rtest", - namespace: "nstest", - name: "namespaced_get", - path: "/apis/gtest/vtest/namespaces/nstest/rtest/namespaced_get", - resp: getJSON("vTest", "rTest", "namespaced_get"), - want: getObject("vTest", "rTest", "namespaced_get"), - }, - { - resource: "rtest/srtest", - name: "normal_subresource_get", - path: "/apis/gtest/vtest/rtest/normal_subresource_get/srtest", - resp: getJSON("vTest", "srTest", "normal_subresource_get"), - want: getObject("vTest", "srTest", "normal_subresource_get"), - }, - { - resource: "rtest/srtest", - namespace: "nstest", - name: "namespaced_subresource_get", - path: "/apis/gtest/vtest/namespaces/nstest/rtest/namespaced_subresource_get/srtest", - resp: getJSON("vTest", "srTest", "namespaced_subresource_get"), - want: getObject("vTest", "srTest", "namespaced_subresource_get"), - }, - } - for _, tc := range tcs { - gv := &schema.GroupVersion{Group: "gtest", Version: "vtest"} - resource := &metav1.APIResource{Name: tc.resource, Namespaced: len(tc.namespace) != 0} - cl, srv, err := getClientServer(gv, func(w http.ResponseWriter, r *http.Request) { - if r.Method != "GET" { - t.Errorf("Get(%q) got HTTP method %s. wanted GET", tc.name, r.Method) - } - - if r.URL.Path != tc.path { - t.Errorf("Get(%q) got path %s. wanted %s", tc.name, r.URL.Path, tc.path) - } - - w.Header().Set("Content-Type", runtime.ContentTypeJSON) - w.Write(tc.resp) - }) - if err != nil { - t.Errorf("unexpected error when creating client: %v", err) - continue - } - defer srv.Close() - - got, err := cl.Resource(resource, tc.namespace).Get(tc.name, metav1.GetOptions{}) - if err != nil { - t.Errorf("unexpected error when getting %q: %v", tc.name, err) - continue - } - - if !reflect.DeepEqual(got, tc.want) { - t.Errorf("Get(%q) want: %v\ngot: %v", tc.name, tc.want, got) - } - } -} - -func TestDelete(t *testing.T) { - background := metav1.DeletePropagationBackground - uid := types.UID("uid") - - statusOK := &metav1.Status{ - TypeMeta: metav1.TypeMeta{Kind: "Status"}, - Status: metav1.StatusSuccess, - } - tcs := []struct { - namespace string - name string - path string - deleteOptions *metav1.DeleteOptions - }{ - { - name: "normal_delete", - path: "/apis/gtest/vtest/rtest/normal_delete", - }, - { - namespace: "nstest", - name: "namespaced_delete", - path: "/apis/gtest/vtest/namespaces/nstest/rtest/namespaced_delete", - }, - { - namespace: "nstest", - name: "namespaced_delete_with_options", - path: "/apis/gtest/vtest/namespaces/nstest/rtest/namespaced_delete_with_options", - deleteOptions: &metav1.DeleteOptions{Preconditions: &metav1.Preconditions{UID: &uid}, PropagationPolicy: &background}, - }, - } - for _, tc := range tcs { - gv := &schema.GroupVersion{Group: "gtest", Version: "vtest"} - resource := &metav1.APIResource{Name: "rtest", Namespaced: len(tc.namespace) != 0} - cl, srv, err := getClientServer(gv, func(w http.ResponseWriter, r *http.Request) { - if r.Method != "DELETE" { - t.Errorf("Delete(%q) got HTTP method %s. wanted DELETE", tc.name, r.Method) - } - - if r.URL.Path != tc.path { - t.Errorf("Delete(%q) got path %s. wanted %s", tc.name, r.URL.Path, tc.path) - } - - w.Header().Set("Content-Type", runtime.ContentTypeJSON) - unstructured.UnstructuredJSONScheme.Encode(statusOK, w) - }) - if err != nil { - t.Errorf("unexpected error when creating client: %v", err) - continue - } - defer srv.Close() - - err = cl.Resource(resource, tc.namespace).Delete(tc.name, tc.deleteOptions) - if err != nil { - t.Errorf("unexpected error when deleting %q: %v", tc.name, err) - continue - } - } -} - -func TestDeleteCollection(t *testing.T) { - statusOK := &metav1.Status{ - TypeMeta: metav1.TypeMeta{Kind: "Status"}, - Status: metav1.StatusSuccess, - } - tcs := []struct { - namespace string - name string - path string - }{ - { - name: "normal_delete_collection", - path: "/apis/gtest/vtest/rtest", - }, - { - namespace: "nstest", - name: "namespaced_delete_collection", - path: "/apis/gtest/vtest/namespaces/nstest/rtest", - }, - } - for _, tc := range tcs { - gv := &schema.GroupVersion{Group: "gtest", Version: "vtest"} - resource := &metav1.APIResource{Name: "rtest", Namespaced: len(tc.namespace) != 0} - cl, srv, err := getClientServer(gv, func(w http.ResponseWriter, r *http.Request) { - if r.Method != "DELETE" { - t.Errorf("DeleteCollection(%q) got HTTP method %s. wanted DELETE", tc.name, r.Method) - } - - if r.URL.Path != tc.path { - t.Errorf("DeleteCollection(%q) got path %s. wanted %s", tc.name, r.URL.Path, tc.path) - } - - w.Header().Set("Content-Type", runtime.ContentTypeJSON) - unstructured.UnstructuredJSONScheme.Encode(statusOK, w) - }) - if err != nil { - t.Errorf("unexpected error when creating client: %v", err) - continue - } - defer srv.Close() - - err = cl.Resource(resource, tc.namespace).DeleteCollection(nil, metav1.ListOptions{}) - if err != nil { - t.Errorf("unexpected error when deleting collection %q: %v", tc.name, err) - continue - } - } -} - -func TestCreate(t *testing.T) { - tcs := []struct { - resource string - name string - namespace string - obj *unstructured.Unstructured - path string - }{ - { - resource: "rtest", - name: "normal_create", - path: "/apis/gtest/vtest/rtest", - obj: getObject("gtest/vTest", "rTest", "normal_create"), - }, - { - resource: "rtest", - name: "namespaced_create", - namespace: "nstest", - path: "/apis/gtest/vtest/namespaces/nstest/rtest", - obj: getObject("gtest/vTest", "rTest", "namespaced_create"), - }, - } - for _, tc := range tcs { - gv := &schema.GroupVersion{Group: "gtest", Version: "vtest"} - resource := &metav1.APIResource{Name: tc.resource, Namespaced: len(tc.namespace) != 0} - cl, srv, err := getClientServer(gv, func(w http.ResponseWriter, r *http.Request) { - if r.Method != "POST" { - t.Errorf("Create(%q) got HTTP method %s. wanted POST", tc.name, r.Method) - } - - if r.URL.Path != tc.path { - t.Errorf("Create(%q) got path %s. wanted %s", tc.name, r.URL.Path, tc.path) - } - - w.Header().Set("Content-Type", runtime.ContentTypeJSON) - data, err := ioutil.ReadAll(r.Body) - if err != nil { - t.Errorf("Create(%q) unexpected error reading body: %v", tc.name, err) - w.WriteHeader(http.StatusInternalServerError) - return - } - - w.Write(data) - }) - if err != nil { - t.Errorf("unexpected error when creating client: %v", err) - continue - } - defer srv.Close() - - got, err := cl.Resource(resource, tc.namespace).Create(tc.obj) - if err != nil { - t.Errorf("unexpected error when creating %q: %v", tc.name, err) - continue - } - - if !reflect.DeepEqual(got, tc.obj) { - t.Errorf("Create(%q) want: %v\ngot: %v", tc.name, tc.obj, got) - } - } -} - -func TestUpdate(t *testing.T) { - tcs := []struct { - resource string - name string - namespace string - obj *unstructured.Unstructured - path string - }{ - { - resource: "rtest", - name: "normal_update", - path: "/apis/gtest/vtest/rtest/normal_update", - obj: getObject("gtest/vTest", "rTest", "normal_update"), - }, - { - resource: "rtest", - name: "namespaced_update", - namespace: "nstest", - path: "/apis/gtest/vtest/namespaces/nstest/rtest/namespaced_update", - obj: getObject("gtest/vTest", "rTest", "namespaced_update"), - }, - { - resource: "rtest/srtest", - name: "normal_subresource_update", - path: "/apis/gtest/vtest/rtest/normal_update/srtest", - obj: getObject("gtest/vTest", "srTest", "normal_update"), - }, - { - resource: "rtest/srtest", - name: "namespaced_subresource_update", - namespace: "nstest", - path: "/apis/gtest/vtest/namespaces/nstest/rtest/namespaced_update/srtest", - obj: getObject("gtest/vTest", "srTest", "namespaced_update"), - }, - } - for _, tc := range tcs { - gv := &schema.GroupVersion{Group: "gtest", Version: "vtest"} - resource := &metav1.APIResource{Name: tc.resource, Namespaced: len(tc.namespace) != 0} - cl, srv, err := getClientServer(gv, func(w http.ResponseWriter, r *http.Request) { - if r.Method != "PUT" { - t.Errorf("Update(%q) got HTTP method %s. wanted PUT", tc.name, r.Method) - } - - if r.URL.Path != tc.path { - t.Errorf("Update(%q) got path %s. wanted %s", tc.name, r.URL.Path, tc.path) - } - - w.Header().Set("Content-Type", runtime.ContentTypeJSON) - data, err := ioutil.ReadAll(r.Body) - if err != nil { - t.Errorf("Update(%q) unexpected error reading body: %v", tc.name, err) - w.WriteHeader(http.StatusInternalServerError) - return - } - - w.Write(data) - }) - if err != nil { - t.Errorf("unexpected error when creating client: %v", err) - continue - } - defer srv.Close() - - got, err := cl.Resource(resource, tc.namespace).Update(tc.obj) - if err != nil { - t.Errorf("unexpected error when updating %q: %v", tc.name, err) - continue - } - - if !reflect.DeepEqual(got, tc.obj) { - t.Errorf("Update(%q) want: %v\ngot: %v", tc.name, tc.obj, got) - } - } -} - -func TestWatch(t *testing.T) { - tcs := []struct { - name string - namespace string - events []watch.Event - path string - query string - }{ - { - name: "normal_watch", - path: "/apis/gtest/vtest/rtest", - query: "watch=true", - events: []watch.Event{ - {Type: watch.Added, Object: getObject("gtest/vTest", "rTest", "normal_watch")}, - {Type: watch.Modified, Object: getObject("gtest/vTest", "rTest", "normal_watch")}, - {Type: watch.Deleted, Object: getObject("gtest/vTest", "rTest", "normal_watch")}, - }, - }, - { - name: "namespaced_watch", - namespace: "nstest", - path: "/apis/gtest/vtest/namespaces/nstest/rtest", - query: "watch=true", - events: []watch.Event{ - {Type: watch.Added, Object: getObject("gtest/vTest", "rTest", "namespaced_watch")}, - {Type: watch.Modified, Object: getObject("gtest/vTest", "rTest", "namespaced_watch")}, - {Type: watch.Deleted, Object: getObject("gtest/vTest", "rTest", "namespaced_watch")}, - }, - }, - } - for _, tc := range tcs { - gv := &schema.GroupVersion{Group: "gtest", Version: "vtest"} - resource := &metav1.APIResource{Name: "rtest", Namespaced: len(tc.namespace) != 0} - cl, srv, err := getClientServer(gv, func(w http.ResponseWriter, r *http.Request) { - if r.Method != "GET" { - t.Errorf("Watch(%q) got HTTP method %s. wanted GET", tc.name, r.Method) - } - - if r.URL.Path != tc.path { - t.Errorf("Watch(%q) got path %s. wanted %s", tc.name, r.URL.Path, tc.path) - } - if r.URL.RawQuery != tc.query { - t.Errorf("Watch(%q) got query %s. wanted %s", tc.name, r.URL.RawQuery, tc.query) - } - - codec := unstructured.UnstructuredJSONScheme - enc := restclientwatch.NewEncoder(streaming.NewEncoder(w, codec), codec) - for _, e := range tc.events { - enc.Encode(&e) - } - }) - if err != nil { - t.Errorf("unexpected error when creating client: %v", err) - continue - } - defer srv.Close() - - watcher, err := cl.Resource(resource, tc.namespace).Watch(metav1.ListOptions{}) - if err != nil { - t.Errorf("unexpected error when watching %q: %v", tc.name, err) - continue - } - - for _, want := range tc.events { - got := <-watcher.ResultChan() - if !reflect.DeepEqual(got, want) { - t.Errorf("Watch(%q) want: %v\ngot: %v", tc.name, want, got) - } - } - } -} - -func TestPatch(t *testing.T) { - tcs := []struct { - resource string - name string - namespace string - patch []byte - want *unstructured.Unstructured - path string - }{ - { - resource: "rtest", - name: "normal_patch", - path: "/apis/gtest/vtest/rtest/normal_patch", - patch: getJSON("gtest/vTest", "rTest", "normal_patch"), - want: getObject("gtest/vTest", "rTest", "normal_patch"), - }, - { - resource: "rtest", - name: "namespaced_patch", - namespace: "nstest", - path: "/apis/gtest/vtest/namespaces/nstest/rtest/namespaced_patch", - patch: getJSON("gtest/vTest", "rTest", "namespaced_patch"), - want: getObject("gtest/vTest", "rTest", "namespaced_patch"), - }, - { - resource: "rtest/srtest", - name: "normal_subresource_patch", - path: "/apis/gtest/vtest/rtest/normal_subresource_patch/srtest", - patch: getJSON("gtest/vTest", "srTest", "normal_subresource_patch"), - want: getObject("gtest/vTest", "srTest", "normal_subresource_patch"), - }, - { - resource: "rtest/srtest", - name: "namespaced_subresource_patch", - namespace: "nstest", - path: "/apis/gtest/vtest/namespaces/nstest/rtest/namespaced_subresource_patch/srtest", - patch: getJSON("gtest/vTest", "srTest", "namespaced_subresource_patch"), - want: getObject("gtest/vTest", "srTest", "namespaced_subresource_patch"), - }, - } - for _, tc := range tcs { - gv := &schema.GroupVersion{Group: "gtest", Version: "vtest"} - resource := &metav1.APIResource{Name: tc.resource, Namespaced: len(tc.namespace) != 0} - cl, srv, err := getClientServer(gv, func(w http.ResponseWriter, r *http.Request) { - if r.Method != "PATCH" { - t.Errorf("Patch(%q) got HTTP method %s. wanted PATCH", tc.name, r.Method) - } - - if r.URL.Path != tc.path { - t.Errorf("Patch(%q) got path %s. wanted %s", tc.name, r.URL.Path, tc.path) - } - - content := r.Header.Get("Content-Type") - if content != string(types.StrategicMergePatchType) { - t.Errorf("Patch(%q) got Content-Type %s. wanted %s", tc.name, content, types.StrategicMergePatchType) - } - - data, err := ioutil.ReadAll(r.Body) - if err != nil { - t.Errorf("Patch(%q) unexpected error reading body: %v", tc.name, err) - w.WriteHeader(http.StatusInternalServerError) - return - } - - w.Header().Set("Content-Type", "application/json") - w.Write(data) - }) - if err != nil { - t.Errorf("unexpected error when creating client: %v", err) - continue - } - defer srv.Close() - - got, err := cl.Resource(resource, tc.namespace).Patch(tc.name, types.StrategicMergePatchType, tc.patch) - if err != nil { - t.Errorf("unexpected error when patching %q: %v", tc.name, err) - continue - } - - if !reflect.DeepEqual(got, tc.want) { - t.Errorf("Patch(%q) want: %v\ngot: %v", tc.name, tc.want, got) - } - } -}