mirror of
https://github.com/k3s-io/kubernetes.git
synced 2025-07-23 19:56:01 +00:00
Remove deprecated-dynamic client
It is now unused.
This commit is contained in:
parent
35cfd327c8
commit
c416ee584c
@ -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/genericclioptions
|
||||||
staging/src/k8s.io/cli-runtime/pkg/printers
|
staging/src/k8s.io/cli-runtime/pkg/printers
|
||||||
staging/src/k8s.io/cli-runtime/pkg/resource
|
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
|
||||||
staging/src/k8s.io/client-go/discovery/fake
|
staging/src/k8s.io/client-go/discovery/fake
|
||||||
staging/src/k8s.io/client-go/dynamic
|
staging/src/k8s.io/client-go/dynamic
|
||||||
|
@ -9,7 +9,6 @@ filegroup(
|
|||||||
name = "all-srcs",
|
name = "all-srcs",
|
||||||
srcs = [
|
srcs = [
|
||||||
":package-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/discovery:all-srcs",
|
||||||
"//staging/src/k8s.io/client-go/dynamic:all-srcs",
|
"//staging/src/k8s.io/client-go/dynamic:all-srcs",
|
||||||
"//staging/src/k8s.io/client-go/examples/create-update-delete-deployment:all-srcs",
|
"//staging/src/k8s.io/client-go/examples/create-update-delete-deployment:all-srcs",
|
||||||
|
@ -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"],
|
|
||||||
)
|
|
@ -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...)
|
|
||||||
}
|
|
@ -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
|
|
||||||
}
|
|
@ -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)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
Loading…
Reference in New Issue
Block a user