vendor: remove dep and use vndr

Signed-off-by: Antonio Murdaca <runcom@redhat.com>
This commit is contained in:
Antonio Murdaca 2017-06-06 09:19:04 +02:00
parent 16f44674a4
commit 148e72d81e
No known key found for this signature in database
GPG key ID: B2BEAD150DE936B9
16131 changed files with 73815 additions and 4235138 deletions

24
vendor/k8s.io/client-go/rest/OWNERS generated vendored
View file

@ -1,24 +0,0 @@
reviewers:
- thockin
- smarterclayton
- caesarxuchao
- wojtek-t
- deads2k
- brendandburns
- liggitt
- nikhiljindal
- gmarek
- erictune
- sttts
- luxas
- dims
- errordeveloper
- hongchaodeng
- krousey
- resouer
- cjcullen
- rmmh
- lixiaobing10051267
- asalkeld
- juanvallejo
- lojies

View file

@ -1,342 +0,0 @@
/*
Copyright 2014 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 rest
import (
"net/http"
"net/http/httptest"
"net/url"
"os"
"reflect"
"testing"
"time"
"fmt"
"k8s.io/apimachinery/pkg/api/errors"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/apimachinery/pkg/runtime/schema"
"k8s.io/apimachinery/pkg/types"
"k8s.io/apimachinery/pkg/util/diff"
"k8s.io/client-go/pkg/api"
"k8s.io/client-go/pkg/api/v1"
utiltesting "k8s.io/client-go/util/testing"
_ "k8s.io/client-go/pkg/api/install"
)
type TestParam struct {
actualError error
expectingError bool
actualCreated bool
expCreated bool
expStatus *metav1.Status
testBody bool
testBodyErrorIsNotNil bool
}
// TestSerializer makes sure that you're always able to decode an unversioned API object
func TestSerializer(t *testing.T) {
contentConfig := ContentConfig{
ContentType: "application/json",
GroupVersion: &schema.GroupVersion{Group: "other", Version: runtime.APIVersionInternal},
NegotiatedSerializer: api.Codecs,
}
serializer, err := createSerializers(contentConfig)
if err != nil {
t.Fatal(err)
}
// bytes based on actual return from API server when encoding an "unversioned" object
obj, err := runtime.Decode(serializer.Decoder, []byte(`{"kind":"Status","apiVersion":"v1","metadata":{},"status":"Success"}`))
t.Log(obj)
if err != nil {
t.Fatal(err)
}
}
func TestDoRequestSuccess(t *testing.T) {
testServer, fakeHandler, status := testServerEnv(t, 200)
defer testServer.Close()
c, err := restClient(testServer)
if err != nil {
t.Fatalf("unexpected error: %v", err)
}
body, err := c.Get().Prefix("test").Do().Raw()
testParam := TestParam{actualError: err, expectingError: false, expCreated: true,
expStatus: status, testBody: true, testBodyErrorIsNotNil: false}
validate(testParam, t, body, fakeHandler)
}
func TestDoRequestFailed(t *testing.T) {
status := &metav1.Status{
Code: http.StatusNotFound,
Status: metav1.StatusFailure,
Reason: metav1.StatusReasonNotFound,
Message: " \"\" not found",
Details: &metav1.StatusDetails{},
}
expectedBody, _ := runtime.Encode(api.Codecs.LegacyCodec(v1.SchemeGroupVersion), status)
fakeHandler := utiltesting.FakeHandler{
StatusCode: 404,
ResponseBody: string(expectedBody),
T: t,
}
testServer := httptest.NewServer(&fakeHandler)
defer testServer.Close()
c, err := restClient(testServer)
if err != nil {
t.Fatalf("unexpected error: %v", err)
}
err = c.Get().Do().Error()
if err == nil {
t.Errorf("unexpected non-error")
}
ss, ok := err.(errors.APIStatus)
if !ok {
t.Errorf("unexpected error type %v", err)
}
actual := ss.Status()
if !reflect.DeepEqual(status, &actual) {
t.Errorf("Unexpected mis-match: %s", diff.ObjectReflectDiff(status, &actual))
}
}
func TestDoRawRequestFailed(t *testing.T) {
status := &metav1.Status{
Code: http.StatusNotFound,
Status: metav1.StatusFailure,
Reason: metav1.StatusReasonNotFound,
Message: "the server could not find the requested resource",
Details: &metav1.StatusDetails{
Causes: []metav1.StatusCause{
{Type: metav1.CauseTypeUnexpectedServerResponse, Message: "unknown"},
},
},
}
expectedBody, _ := runtime.Encode(api.Codecs.LegacyCodec(v1.SchemeGroupVersion), status)
fakeHandler := utiltesting.FakeHandler{
StatusCode: 404,
ResponseBody: string(expectedBody),
T: t,
}
testServer := httptest.NewServer(&fakeHandler)
defer testServer.Close()
c, err := restClient(testServer)
if err != nil {
t.Fatalf("unexpected error: %v", err)
}
body, err := c.Get().Do().Raw()
if err == nil || body == nil {
t.Errorf("unexpected non-error: %#v", body)
}
ss, ok := err.(errors.APIStatus)
if !ok {
t.Errorf("unexpected error type %v", err)
}
actual := ss.Status()
if !reflect.DeepEqual(status, &actual) {
t.Errorf("Unexpected mis-match: %s", diff.ObjectReflectDiff(status, &actual))
}
}
func TestDoRequestCreated(t *testing.T) {
testServer, fakeHandler, status := testServerEnv(t, 201)
defer testServer.Close()
c, err := restClient(testServer)
if err != nil {
t.Fatalf("unexpected error: %v", err)
}
created := false
body, err := c.Get().Prefix("test").Do().WasCreated(&created).Raw()
testParam := TestParam{actualError: err, expectingError: false, expCreated: true,
expStatus: status, testBody: false}
validate(testParam, t, body, fakeHandler)
}
func TestDoRequestNotCreated(t *testing.T) {
testServer, fakeHandler, expectedStatus := testServerEnv(t, 202)
defer testServer.Close()
c, err := restClient(testServer)
if err != nil {
t.Fatalf("unexpected error: %v", err)
}
created := false
body, err := c.Get().Prefix("test").Do().WasCreated(&created).Raw()
testParam := TestParam{actualError: err, expectingError: false, expCreated: false,
expStatus: expectedStatus, testBody: false}
validate(testParam, t, body, fakeHandler)
}
func TestDoRequestAcceptedNoContentReturned(t *testing.T) {
testServer, fakeHandler, _ := testServerEnv(t, 204)
defer testServer.Close()
c, err := restClient(testServer)
if err != nil {
t.Fatalf("unexpected error: %v", err)
}
created := false
body, err := c.Get().Prefix("test").Do().WasCreated(&created).Raw()
testParam := TestParam{actualError: err, expectingError: false, expCreated: false,
testBody: false}
validate(testParam, t, body, fakeHandler)
}
func TestBadRequest(t *testing.T) {
testServer, fakeHandler, _ := testServerEnv(t, 400)
defer testServer.Close()
c, err := restClient(testServer)
if err != nil {
t.Fatalf("unexpected error: %v", err)
}
created := false
body, err := c.Get().Prefix("test").Do().WasCreated(&created).Raw()
testParam := TestParam{actualError: err, expectingError: true, expCreated: false,
testBody: true}
validate(testParam, t, body, fakeHandler)
}
func validate(testParam TestParam, t *testing.T, body []byte, fakeHandler *utiltesting.FakeHandler) {
switch {
case testParam.expectingError && testParam.actualError == nil:
t.Errorf("Expected error")
case !testParam.expectingError && testParam.actualError != nil:
t.Error(testParam.actualError)
}
if !testParam.expCreated {
if testParam.actualCreated {
t.Errorf("Expected object not to be created")
}
}
statusOut, err := runtime.Decode(api.Codecs.LegacyCodec(v1.SchemeGroupVersion), body)
if testParam.testBody {
if testParam.testBodyErrorIsNotNil {
if err == nil {
t.Errorf("Expected Error")
}
}
}
if testParam.expStatus != nil {
if !reflect.DeepEqual(testParam.expStatus, statusOut) {
t.Errorf("Unexpected mis-match. Expected %#v. Saw %#v", testParam.expStatus, statusOut)
}
}
fakeHandler.ValidateRequest(t, "/"+api.Registry.GroupOrDie(api.GroupName).GroupVersion.String()+"/test", "GET", nil)
}
func TestHttpMethods(t *testing.T) {
testServer, _, _ := testServerEnv(t, 200)
defer testServer.Close()
c, _ := restClient(testServer)
request := c.Post()
if request == nil {
t.Errorf("Post : Object returned should not be nil")
}
request = c.Get()
if request == nil {
t.Errorf("Get: Object returned should not be nil")
}
request = c.Put()
if request == nil {
t.Errorf("Put : Object returned should not be nil")
}
request = c.Delete()
if request == nil {
t.Errorf("Delete : Object returned should not be nil")
}
request = c.Patch(types.JSONPatchType)
if request == nil {
t.Errorf("Patch : Object returned should not be nil")
}
}
func TestCreateBackoffManager(t *testing.T) {
theUrl, _ := url.Parse("http://localhost")
// 1 second base backoff + duration of 2 seconds -> exponential backoff for requests.
os.Setenv(envBackoffBase, "1")
os.Setenv(envBackoffDuration, "2")
backoff := readExpBackoffConfig()
backoff.UpdateBackoff(theUrl, nil, 500)
backoff.UpdateBackoff(theUrl, nil, 500)
if backoff.CalculateBackoff(theUrl)/time.Second != 2 {
t.Errorf("Backoff env not working.")
}
// 0 duration -> no backoff.
os.Setenv(envBackoffBase, "1")
os.Setenv(envBackoffDuration, "0")
backoff.UpdateBackoff(theUrl, nil, 500)
backoff.UpdateBackoff(theUrl, nil, 500)
backoff = readExpBackoffConfig()
if backoff.CalculateBackoff(theUrl)/time.Second != 0 {
t.Errorf("Zero backoff duration, but backoff still occuring.")
}
// No env -> No backoff.
os.Setenv(envBackoffBase, "")
os.Setenv(envBackoffDuration, "")
backoff = readExpBackoffConfig()
backoff.UpdateBackoff(theUrl, nil, 500)
backoff.UpdateBackoff(theUrl, nil, 500)
if backoff.CalculateBackoff(theUrl)/time.Second != 0 {
t.Errorf("Backoff should have been 0.")
}
}
func testServerEnv(t *testing.T, statusCode int) (*httptest.Server, *utiltesting.FakeHandler, *metav1.Status) {
status := &metav1.Status{Status: fmt.Sprintf("%s", metav1.StatusSuccess)}
expectedBody, _ := runtime.Encode(api.Codecs.LegacyCodec(v1.SchemeGroupVersion), status)
fakeHandler := utiltesting.FakeHandler{
StatusCode: statusCode,
ResponseBody: string(expectedBody),
T: t,
}
testServer := httptest.NewServer(&fakeHandler)
return testServer, &fakeHandler, status
}
func restClient(testServer *httptest.Server) (*RESTClient, error) {
c, err := RESTClientFor(&Config{
Host: testServer.URL,
ContentConfig: ContentConfig{
GroupVersion: &api.Registry.GroupOrDie(api.GroupName).GroupVersion,
NegotiatedSerializer: api.Codecs,
},
Username: "user",
Password: "pass",
})
return c, err
}

View file

@ -83,10 +83,6 @@ type Config struct {
// TLSClientConfig contains settings to enable transport layer security
TLSClientConfig
// Server should be accessed without verifying the TLS
// certificate. For testing only.
Insecure bool
// UserAgent is an optional field that specifies the caller of this request.
UserAgent string
@ -132,6 +128,13 @@ type ImpersonationConfig struct {
// TLSClientConfig contains settings to enable transport layer security
type TLSClientConfig struct {
// Server should be accessed without verifying the TLS certificate. For testing only.
Insecure bool
// ServerName is passed to the server for SNI and is used in the client to check server
// ceritificates against. If ServerName is empty, the hostname used to contact the
// server is used.
ServerName string
// Server requires TLS client certificate authentication
CertFile string
// Server requires TLS client certificate authentication
@ -365,11 +368,12 @@ func AnonymousClientConfig(config *Config) *Config {
Prefix: config.Prefix,
ContentConfig: config.ContentConfig,
TLSClientConfig: TLSClientConfig{
CAFile: config.TLSClientConfig.CAFile,
CAData: config.TLSClientConfig.CAData,
Insecure: config.Insecure,
ServerName: config.ServerName,
CAFile: config.TLSClientConfig.CAFile,
CAData: config.TLSClientConfig.CAData,
},
RateLimiter: config.RateLimiter,
Insecure: config.Insecure,
UserAgent: config.UserAgent,
Transport: config.Transport,
WrapTransport: config.WrapTransport,

View file

@ -1,232 +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 rest
import (
"io"
"net/http"
"reflect"
"strings"
"testing"
fuzz "github.com/google/gofuzz"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/apimachinery/pkg/runtime/schema"
"k8s.io/apimachinery/pkg/util/diff"
"k8s.io/client-go/pkg/api"
clientcmdapi "k8s.io/client-go/tools/clientcmd/api"
"k8s.io/client-go/util/flowcontrol"
_ "k8s.io/client-go/pkg/api/install"
)
func TestIsConfigTransportTLS(t *testing.T) {
testCases := []struct {
Config *Config
TransportTLS bool
}{
{
Config: &Config{},
TransportTLS: false,
},
{
Config: &Config{
Host: "https://localhost",
},
TransportTLS: true,
},
{
Config: &Config{
Host: "localhost",
TLSClientConfig: TLSClientConfig{
CertFile: "foo",
},
},
TransportTLS: true,
},
{
Config: &Config{
Host: "///:://localhost",
TLSClientConfig: TLSClientConfig{
CertFile: "foo",
},
},
TransportTLS: false,
},
{
Config: &Config{
Host: "1.2.3.4:567",
Insecure: true,
},
TransportTLS: true,
},
}
for _, testCase := range testCases {
if err := SetKubernetesDefaults(testCase.Config); err != nil {
t.Errorf("setting defaults failed for %#v: %v", testCase.Config, err)
continue
}
useTLS := IsConfigTransportTLS(*testCase.Config)
if testCase.TransportTLS != useTLS {
t.Errorf("expected %v for %#v", testCase.TransportTLS, testCase.Config)
}
}
}
func TestSetKubernetesDefaultsUserAgent(t *testing.T) {
config := &Config{}
if err := SetKubernetesDefaults(config); err != nil {
t.Errorf("unexpected error: %v", err)
}
if !strings.Contains(config.UserAgent, "kubernetes/") {
t.Errorf("no user agent set: %#v", config)
}
}
func TestRESTClientRequires(t *testing.T) {
if _, err := RESTClientFor(&Config{Host: "127.0.0.1", ContentConfig: ContentConfig{NegotiatedSerializer: api.Codecs}}); err == nil {
t.Errorf("unexpected non-error")
}
if _, err := RESTClientFor(&Config{Host: "127.0.0.1", ContentConfig: ContentConfig{GroupVersion: &api.Registry.GroupOrDie(api.GroupName).GroupVersion}}); err == nil {
t.Errorf("unexpected non-error")
}
if _, err := RESTClientFor(&Config{Host: "127.0.0.1", ContentConfig: ContentConfig{GroupVersion: &api.Registry.GroupOrDie(api.GroupName).GroupVersion, NegotiatedSerializer: api.Codecs}}); err != nil {
t.Errorf("unexpected error: %v", err)
}
}
type fakeLimiter struct {
FakeSaturation float64
FakeQPS float32
}
func (t *fakeLimiter) TryAccept() bool {
return true
}
func (t *fakeLimiter) Saturation() float64 {
return t.FakeSaturation
}
func (t *fakeLimiter) QPS() float32 {
return t.FakeQPS
}
func (t *fakeLimiter) Stop() {}
func (t *fakeLimiter) Accept() {}
type fakeCodec struct{}
func (c *fakeCodec) Decode([]byte, *schema.GroupVersionKind, runtime.Object) (runtime.Object, *schema.GroupVersionKind, error) {
return nil, nil, nil
}
func (c *fakeCodec) Encode(obj runtime.Object, stream io.Writer) error {
return nil
}
type fakeRoundTripper struct{}
func (r *fakeRoundTripper) RoundTrip(*http.Request) (*http.Response, error) {
return nil, nil
}
var fakeWrapperFunc = func(http.RoundTripper) http.RoundTripper {
return &fakeRoundTripper{}
}
type fakeNegotiatedSerializer struct{}
func (n *fakeNegotiatedSerializer) SupportedMediaTypes() []runtime.SerializerInfo {
return nil
}
func (n *fakeNegotiatedSerializer) EncoderForVersion(serializer runtime.Encoder, gv runtime.GroupVersioner) runtime.Encoder {
return &fakeCodec{}
}
func (n *fakeNegotiatedSerializer) DecoderToVersion(serializer runtime.Decoder, gv runtime.GroupVersioner) runtime.Decoder {
return &fakeCodec{}
}
func TestAnonymousConfig(t *testing.T) {
f := fuzz.New().NilChance(0.0).NumElements(1, 1)
f.Funcs(
func(r *runtime.Codec, f fuzz.Continue) {
codec := &fakeCodec{}
f.Fuzz(codec)
*r = codec
},
func(r *http.RoundTripper, f fuzz.Continue) {
roundTripper := &fakeRoundTripper{}
f.Fuzz(roundTripper)
*r = roundTripper
},
func(fn *func(http.RoundTripper) http.RoundTripper, f fuzz.Continue) {
*fn = fakeWrapperFunc
},
func(r *runtime.NegotiatedSerializer, f fuzz.Continue) {
serializer := &fakeNegotiatedSerializer{}
f.Fuzz(serializer)
*r = serializer
},
func(r *flowcontrol.RateLimiter, f fuzz.Continue) {
limiter := &fakeLimiter{}
f.Fuzz(limiter)
*r = limiter
},
// Authentication does not require fuzzer
func(r *AuthProviderConfigPersister, f fuzz.Continue) {},
func(r *clientcmdapi.AuthProviderConfig, f fuzz.Continue) {
r.Config = map[string]string{}
},
)
for i := 0; i < 20; i++ {
original := &Config{}
f.Fuzz(original)
actual := AnonymousClientConfig(original)
expected := *original
// this is the list of known security related fields, add to this list if a new field
// is added to Config, update AnonymousClientConfig to preserve the field otherwise.
expected.Impersonate = ImpersonationConfig{}
expected.BearerToken = ""
expected.Username = ""
expected.Password = ""
expected.AuthProvider = nil
expected.AuthConfigPersister = nil
expected.TLSClientConfig.CertData = nil
expected.TLSClientConfig.CertFile = ""
expected.TLSClientConfig.KeyData = nil
expected.TLSClientConfig.KeyFile = ""
// The DeepEqual cannot handle the func comparison, so we just verify if the
// function return the expected object.
if actual.WrapTransport == nil || !reflect.DeepEqual(expected.WrapTransport(nil), &fakeRoundTripper{}) {
t.Fatalf("AnonymousClientConfig dropped the WrapTransport field")
} else {
actual.WrapTransport = nil
expected.WrapTransport = nil
}
if !reflect.DeepEqual(*actual, expected) {
t.Fatalf("AnonymousClientConfig dropped unexpected fields, identify whether they are security related or not: %s", diff.ObjectGoPrintDiff(expected, actual))
}
}
}

View file

@ -1,125 +0,0 @@
/*
Copyright 2014 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.
*/
// This is made a separate package and should only be imported by tests, because
// it imports testapi
package fake
import (
"net/http"
"net/url"
"k8s.io/apimachinery/pkg/apimachinery/registered"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/apimachinery/pkg/runtime/schema"
"k8s.io/apimachinery/pkg/types"
restclient "k8s.io/client-go/rest"
"k8s.io/client-go/util/flowcontrol"
)
func CreateHTTPClient(roundTripper func(*http.Request) (*http.Response, error)) *http.Client {
return &http.Client{
Transport: roundTripperFunc(roundTripper),
}
}
type roundTripperFunc func(*http.Request) (*http.Response, error)
func (f roundTripperFunc) RoundTrip(req *http.Request) (*http.Response, error) {
return f(req)
}
// RESTClient provides a fake RESTClient interface.
type RESTClient struct {
Client *http.Client
NegotiatedSerializer runtime.NegotiatedSerializer
GroupName string
APIRegistry *registered.APIRegistrationManager
Req *http.Request
Resp *http.Response
Err error
}
func (c *RESTClient) Get() *restclient.Request {
return c.request("GET")
}
func (c *RESTClient) Put() *restclient.Request {
return c.request("PUT")
}
func (c *RESTClient) Patch(_ types.PatchType) *restclient.Request {
return c.request("PATCH")
}
func (c *RESTClient) Post() *restclient.Request {
return c.request("POST")
}
func (c *RESTClient) Delete() *restclient.Request {
return c.request("DELETE")
}
func (c *RESTClient) Verb(verb string) *restclient.Request {
return c.request(verb)
}
func (c *RESTClient) APIVersion() schema.GroupVersion {
return c.APIRegistry.GroupOrDie("").GroupVersion
}
func (c *RESTClient) GetRateLimiter() flowcontrol.RateLimiter {
return nil
}
func (c *RESTClient) request(verb string) *restclient.Request {
config := restclient.ContentConfig{
ContentType: runtime.ContentTypeJSON,
// TODO this was hardcoded before, but it doesn't look right
GroupVersion: &c.APIRegistry.GroupOrDie("").GroupVersion,
NegotiatedSerializer: c.NegotiatedSerializer,
}
ns := c.NegotiatedSerializer
info, _ := runtime.SerializerInfoForMediaType(ns.SupportedMediaTypes(), runtime.ContentTypeJSON)
internalVersion := schema.GroupVersion{
Group: c.APIRegistry.GroupOrDie(c.GroupName).GroupVersion.Group,
Version: runtime.APIVersionInternal,
}
internalVersion.Version = runtime.APIVersionInternal
serializers := restclient.Serializers{
// TODO this was hardcoded before, but it doesn't look right
Encoder: ns.EncoderForVersion(info.Serializer, c.APIRegistry.GroupOrDie("").GroupVersion),
Decoder: ns.DecoderToVersion(info.Serializer, internalVersion),
}
if info.StreamSerializer != nil {
serializers.StreamingSerializer = info.StreamSerializer.Serializer
serializers.Framer = info.StreamSerializer.Framer
}
return restclient.NewRequest(c, verb, &url.URL{Host: "localhost"}, "", config, serializers, nil, nil)
}
func (c *RESTClient) Do(req *http.Request) (*http.Response, error) {
if c.Err != nil {
return nil, c.Err
}
c.Req = req
if c.Client != nil {
return c.Client.Do(req)
}
return c.Resp, nil
}

View file

@ -1,311 +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 rest
import (
"fmt"
"net/http"
"reflect"
"strconv"
"testing"
clientcmdapi "k8s.io/client-go/tools/clientcmd/api"
)
func TestAuthPluginWrapTransport(t *testing.T) {
if err := RegisterAuthProviderPlugin("pluginA", pluginAProvider); err != nil {
t.Errorf("Unexpected error: failed to register pluginA: %v", err)
}
if err := RegisterAuthProviderPlugin("pluginB", pluginBProvider); err != nil {
t.Errorf("Unexpected error: failed to register pluginB: %v", err)
}
if err := RegisterAuthProviderPlugin("pluginFail", pluginFailProvider); err != nil {
t.Errorf("Unexpected error: failed to register pluginFail: %v", err)
}
testCases := []struct {
useWrapTransport bool
plugin string
expectErr bool
expectPluginA bool
expectPluginB bool
}{
{false, "", false, false, false},
{false, "pluginA", false, true, false},
{false, "pluginB", false, false, true},
{false, "pluginFail", true, false, false},
{false, "pluginUnknown", true, false, false},
}
for i, tc := range testCases {
c := Config{}
if tc.useWrapTransport {
// Specify an existing WrapTransport in the config to make sure that
// plugins play nicely.
c.WrapTransport = func(rt http.RoundTripper) http.RoundTripper {
return &wrapTransport{rt}
}
}
if len(tc.plugin) != 0 {
c.AuthProvider = &clientcmdapi.AuthProviderConfig{Name: tc.plugin}
}
tConfig, err := c.TransportConfig()
if err != nil {
// Unknown/bad plugins are expected to fail here.
if !tc.expectErr {
t.Errorf("%d. Did not expect errors loading Auth Plugin: %q. Got: %v", i, tc.plugin, err)
}
continue
}
var fullyWrappedTransport http.RoundTripper
fullyWrappedTransport = &emptyTransport{}
if tConfig.WrapTransport != nil {
fullyWrappedTransport = tConfig.WrapTransport(&emptyTransport{})
}
res, err := fullyWrappedTransport.RoundTrip(&http.Request{})
if err != nil {
t.Errorf("%d. Unexpected error in RoundTrip: %v", i, err)
continue
}
hasWrapTransport := res.Header.Get("wrapTransport") == "Y"
hasPluginA := res.Header.Get("pluginA") == "Y"
hasPluginB := res.Header.Get("pluginB") == "Y"
if hasWrapTransport != tc.useWrapTransport {
t.Errorf("%d. Expected Existing config.WrapTransport: %t; Got: %t", i, tc.useWrapTransport, hasWrapTransport)
}
if hasPluginA != tc.expectPluginA {
t.Errorf("%d. Expected Plugin A: %t; Got: %t", i, tc.expectPluginA, hasPluginA)
}
if hasPluginB != tc.expectPluginB {
t.Errorf("%d. Expected Plugin B: %t; Got: %t", i, tc.expectPluginB, hasPluginB)
}
}
}
func TestAuthPluginPersist(t *testing.T) {
// register pluginA by a different name so we don't collide across tests.
if err := RegisterAuthProviderPlugin("pluginA2", pluginAProvider); err != nil {
t.Errorf("Unexpected error: failed to register pluginA: %v", err)
}
if err := RegisterAuthProviderPlugin("pluginPersist", pluginPersistProvider); err != nil {
t.Errorf("Unexpected error: failed to register pluginPersist: %v", err)
}
fooBarConfig := map[string]string{"foo": "bar"}
testCases := []struct {
plugin string
startingConfig map[string]string
expectedConfigAfterLogin map[string]string
expectedConfigAfterRoundTrip map[string]string
}{
// non-persisting plugins should work fine without modifying config.
{"pluginA2", map[string]string{}, map[string]string{}, map[string]string{}},
{"pluginA2", fooBarConfig, fooBarConfig, fooBarConfig},
// plugins that persist config should be able to persist when they want.
{
"pluginPersist",
map[string]string{},
map[string]string{
"login": "Y",
},
map[string]string{
"login": "Y",
"roundTrips": "1",
},
},
{
"pluginPersist",
map[string]string{
"login": "Y",
"roundTrips": "123",
},
map[string]string{
"login": "Y",
"roundTrips": "123",
},
map[string]string{
"login": "Y",
"roundTrips": "124",
},
},
}
for i, tc := range testCases {
cfg := &clientcmdapi.AuthProviderConfig{
Name: tc.plugin,
Config: tc.startingConfig,
}
persister := &inMemoryPersister{make(map[string]string)}
persister.Persist(tc.startingConfig)
plugin, err := GetAuthProvider("127.0.0.1", cfg, persister)
if err != nil {
t.Errorf("%d. Unexpected error: failed to get plugin %q: %v", i, tc.plugin, err)
}
if err := plugin.Login(); err != nil {
t.Errorf("%d. Unexpected error calling Login() w/ plugin %q: %v", i, tc.plugin, err)
}
// Make sure the plugin persisted what we expect after Login().
if !reflect.DeepEqual(persister.savedConfig, tc.expectedConfigAfterLogin) {
t.Errorf("%d. Unexpected persisted config after calling %s.Login(): \nGot:\n%v\nExpected:\n%v",
i, tc.plugin, persister.savedConfig, tc.expectedConfigAfterLogin)
}
if _, err := plugin.WrapTransport(&emptyTransport{}).RoundTrip(&http.Request{}); err != nil {
t.Errorf("%d. Unexpected error round-tripping w/ plugin %q: %v", i, tc.plugin, err)
}
// Make sure the plugin persisted what we expect after RoundTrip().
if !reflect.DeepEqual(persister.savedConfig, tc.expectedConfigAfterRoundTrip) {
t.Errorf("%d. Unexpected persisted config after calling %s.WrapTransport.RoundTrip(): \nGot:\n%v\nExpected:\n%v",
i, tc.plugin, persister.savedConfig, tc.expectedConfigAfterLogin)
}
}
}
// emptyTransport provides an empty http.Response with an initialized header
// to allow wrapping RoundTrippers to set header values.
type emptyTransport struct{}
func (*emptyTransport) RoundTrip(req *http.Request) (*http.Response, error) {
res := &http.Response{
Header: make(map[string][]string),
}
return res, nil
}
// wrapTransport sets "wrapTransport" = "Y" on the response.
type wrapTransport struct {
rt http.RoundTripper
}
func (w *wrapTransport) RoundTrip(req *http.Request) (*http.Response, error) {
res, err := w.rt.RoundTrip(req)
if err != nil {
return nil, err
}
res.Header.Add("wrapTransport", "Y")
return res, nil
}
// wrapTransportA sets "pluginA" = "Y" on the response.
type wrapTransportA struct {
rt http.RoundTripper
}
func (w *wrapTransportA) RoundTrip(req *http.Request) (*http.Response, error) {
res, err := w.rt.RoundTrip(req)
if err != nil {
return nil, err
}
res.Header.Add("pluginA", "Y")
return res, nil
}
type pluginA struct{}
func (*pluginA) WrapTransport(rt http.RoundTripper) http.RoundTripper {
return &wrapTransportA{rt}
}
func (*pluginA) Login() error { return nil }
func pluginAProvider(string, map[string]string, AuthProviderConfigPersister) (AuthProvider, error) {
return &pluginA{}, nil
}
// wrapTransportB sets "pluginB" = "Y" on the response.
type wrapTransportB struct {
rt http.RoundTripper
}
func (w *wrapTransportB) RoundTrip(req *http.Request) (*http.Response, error) {
res, err := w.rt.RoundTrip(req)
if err != nil {
return nil, err
}
res.Header.Add("pluginB", "Y")
return res, nil
}
type pluginB struct{}
func (*pluginB) WrapTransport(rt http.RoundTripper) http.RoundTripper {
return &wrapTransportB{rt}
}
func (*pluginB) Login() error { return nil }
func pluginBProvider(string, map[string]string, AuthProviderConfigPersister) (AuthProvider, error) {
return &pluginB{}, nil
}
// pluginFailProvider simulates a registered AuthPlugin that fails to load.
func pluginFailProvider(string, map[string]string, AuthProviderConfigPersister) (AuthProvider, error) {
return nil, fmt.Errorf("Failed to load AuthProvider")
}
type inMemoryPersister struct {
savedConfig map[string]string
}
func (i *inMemoryPersister) Persist(config map[string]string) error {
i.savedConfig = make(map[string]string)
for k, v := range config {
i.savedConfig[k] = v
}
return nil
}
// wrapTransportPersist increments the "roundTrips" entry from the config when
// roundTrip is called.
type wrapTransportPersist struct {
rt http.RoundTripper
config map[string]string
persister AuthProviderConfigPersister
}
func (w *wrapTransportPersist) RoundTrip(req *http.Request) (*http.Response, error) {
roundTrips := 0
if rtVal, ok := w.config["roundTrips"]; ok {
var err error
roundTrips, err = strconv.Atoi(rtVal)
if err != nil {
return nil, err
}
}
roundTrips++
w.config["roundTrips"] = fmt.Sprintf("%d", roundTrips)
if err := w.persister.Persist(w.config); err != nil {
return nil, err
}
return w.rt.RoundTrip(req)
}
type pluginPersist struct {
config map[string]string
persister AuthProviderConfigPersister
}
func (p *pluginPersist) WrapTransport(rt http.RoundTripper) http.RoundTripper {
return &wrapTransportPersist{rt, p.config, p.persister}
}
// Login sets the config entry "login" to "Y".
func (p *pluginPersist) Login() error {
p.config["login"] = "Y"
p.persister.Persist(p.config)
return nil
}
func pluginPersistProvider(_ string, config map[string]string, persister AuthProviderConfigPersister) (AuthProvider, error) {
return &pluginPersist{config, persister}, nil
}

View file

@ -1035,13 +1035,15 @@ func (r *Request) newUnstructuredResponseError(body []byte, isTextResponse bool,
if isTextResponse {
message = strings.TrimSpace(string(body))
}
var groupResource schema.GroupResource
if len(r.resource) > 0 {
groupResource.Group = r.content.GroupVersion.Group
groupResource.Resource = r.resource
}
return errors.NewGenericServerResponse(
statusCode,
method,
schema.GroupResource{
Group: r.content.GroupVersion.Group,
Resource: r.resource,
},
groupResource,
r.resourceName,
message,
retryAfter,

File diff suppressed because it is too large Load diff

View file

@ -78,13 +78,14 @@ func (c *Config) TransportConfig() (*transport.Config, error) {
Transport: c.Transport,
WrapTransport: wt,
TLS: transport.TLSConfig{
CAFile: c.CAFile,
CAData: c.CAData,
CertFile: c.CertFile,
CertData: c.CertData,
KeyFile: c.KeyFile,
KeyData: c.KeyData,
Insecure: c.Insecure,
Insecure: c.Insecure,
ServerName: c.ServerName,
CAFile: c.CAFile,
CAData: c.CAData,
CertFile: c.CertFile,
CertData: c.CertData,
KeyFile: c.KeyFile,
KeyData: c.KeyData,
},
Username: c.Username,
Password: c.Password,

View file

@ -1,61 +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 rest
import (
"path"
"testing"
"k8s.io/client-go/pkg/api"
)
func TestValidatesHostParameter(t *testing.T) {
testCases := []struct {
Host string
APIPath string
URL string
Err bool
}{
{"127.0.0.1", "", "http://127.0.0.1/" + api.Registry.GroupOrDie(api.GroupName).GroupVersion.Version, false},
{"127.0.0.1:8080", "", "http://127.0.0.1:8080/" + api.Registry.GroupOrDie(api.GroupName).GroupVersion.Version, false},
{"foo.bar.com", "", "http://foo.bar.com/" + api.Registry.GroupOrDie(api.GroupName).GroupVersion.Version, false},
{"http://host/prefix", "", "http://host/prefix/" + api.Registry.GroupOrDie(api.GroupName).GroupVersion.Version, false},
{"http://host", "", "http://host/" + api.Registry.GroupOrDie(api.GroupName).GroupVersion.Version, false},
{"http://host", "/", "http://host/" + api.Registry.GroupOrDie(api.GroupName).GroupVersion.Version, false},
{"http://host", "/other", "http://host/other/" + api.Registry.GroupOrDie(api.GroupName).GroupVersion.Version, false},
{"host/server", "", "", true},
}
for i, testCase := range testCases {
u, versionedAPIPath, err := DefaultServerURL(testCase.Host, testCase.APIPath, api.Registry.GroupOrDie(api.GroupName).GroupVersion, false)
switch {
case err == nil && testCase.Err:
t.Errorf("expected error but was nil")
continue
case err != nil && !testCase.Err:
t.Errorf("unexpected error %v", err)
continue
case err != nil:
continue
}
u.Path = path.Join(u.Path, versionedAPIPath)
if e, a := testCase.URL, u.String(); e != a {
t.Errorf("%d: expected host %s, got %s", i, e, a)
continue
}
}
}

View file

@ -1,79 +0,0 @@
/*
Copyright 2014 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 rest
import (
"net/url"
"testing"
"time"
"k8s.io/client-go/util/flowcontrol"
)
func parse(raw string) *url.URL {
theUrl, _ := url.Parse(raw)
return theUrl
}
func TestURLBackoffFunctionalityCollisions(t *testing.T) {
myBackoff := &URLBackoff{
Backoff: flowcontrol.NewBackOff(1*time.Second, 60*time.Second),
}
// Add some noise and make sure backoff for a clean URL is zero.
myBackoff.UpdateBackoff(parse("http://100.200.300.400:8080"), nil, 500)
myBackoff.UpdateBackoff(parse("http://1.2.3.4:8080"), nil, 500)
if myBackoff.CalculateBackoff(parse("http://1.2.3.4:100")) > 0 {
t.Errorf("URLs are colliding in the backoff map!")
}
}
// TestURLBackoffFunctionality generally tests the URLBackoff wrapper. We avoid duplicating tests from backoff and request.
func TestURLBackoffFunctionality(t *testing.T) {
myBackoff := &URLBackoff{
Backoff: flowcontrol.NewBackOff(1*time.Second, 60*time.Second),
}
// Now test that backoff increases, then recovers.
// 200 and 300 should both result in clearing the backoff.
// all others like 429 should result in increased backoff.
seconds := []int{0,
1, 2, 4, 8, 0,
1, 2}
returnCodes := []int{
429, 500, 501, 502, 300,
500, 501, 502,
}
if len(seconds) != len(returnCodes) {
t.Fatalf("responseCode to backoff arrays should be the same length... sanity check failed.")
}
for i, sec := range seconds {
backoffSec := myBackoff.CalculateBackoff(parse("http://1.2.3.4:100"))
if backoffSec < time.Duration(sec)*time.Second || backoffSec > time.Duration(sec+5)*time.Second {
t.Errorf("Backoff out of range %v: %v %v", i, sec, backoffSec)
}
myBackoff.UpdateBackoff(parse("http://1.2.3.4:100/responseCodeForFuncTest"), nil, returnCodes[i])
}
if myBackoff.CalculateBackoff(parse("http://1.2.3.4:100")) == 0 {
t.Errorf("The final return code %v should have resulted in a backoff ! ", returnCodes[7])
}
}

View file

@ -1,117 +0,0 @@
/*
Copyright 2014 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 versioned_test
import (
"encoding/json"
"io"
"testing"
"time"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/apimachinery/pkg/runtime/serializer/streaming"
"k8s.io/apimachinery/pkg/util/wait"
"k8s.io/apimachinery/pkg/watch"
"k8s.io/client-go/pkg/api"
"k8s.io/client-go/pkg/api/v1"
restclientwatch "k8s.io/client-go/rest/watch"
apiequality "k8s.io/apimachinery/pkg/api/equality"
_ "k8s.io/client-go/pkg/api/install"
)
func TestDecoder(t *testing.T) {
table := []watch.EventType{watch.Added, watch.Deleted, watch.Modified, watch.Error}
for _, eventType := range table {
out, in := io.Pipe()
codec := api.Codecs.LegacyCodec(v1.SchemeGroupVersion)
decoder := restclientwatch.NewDecoder(streaming.NewDecoder(out, codec), codec)
expect := &api.Pod{ObjectMeta: metav1.ObjectMeta{Name: "foo"}}
encoder := json.NewEncoder(in)
go func() {
data, err := runtime.Encode(api.Codecs.LegacyCodec(v1.SchemeGroupVersion), expect)
if err != nil {
t.Fatalf("Unexpected error %v", err)
}
event := metav1.WatchEvent{
Type: string(eventType),
Object: runtime.RawExtension{Raw: json.RawMessage(data)},
}
if err := encoder.Encode(&event); err != nil {
t.Errorf("Unexpected error %v", err)
}
in.Close()
}()
done := make(chan struct{})
go func() {
action, got, err := decoder.Decode()
if err != nil {
t.Fatalf("Unexpected error %v", err)
}
if e, a := eventType, action; e != a {
t.Errorf("Expected %v, got %v", e, a)
}
if e, a := expect, got; !apiequality.Semantic.DeepDerivative(e, a) {
t.Errorf("Expected %v, got %v", e, a)
}
t.Logf("Exited read")
close(done)
}()
<-done
done = make(chan struct{})
go func() {
_, _, err := decoder.Decode()
if err == nil {
t.Errorf("Unexpected nil error")
}
close(done)
}()
<-done
decoder.Close()
}
}
func TestDecoder_SourceClose(t *testing.T) {
out, in := io.Pipe()
codec := api.Codecs.LegacyCodec(v1.SchemeGroupVersion)
decoder := restclientwatch.NewDecoder(streaming.NewDecoder(out, codec), codec)
done := make(chan struct{})
go func() {
_, _, err := decoder.Decode()
if err == nil {
t.Errorf("Unexpected nil error")
}
close(done)
}()
in.Close()
select {
case <-done:
break
case <-time.After(wait.ForeverTestTimeout):
t.Error("Timeout")
}
}

View file

@ -1,82 +0,0 @@
/*
Copyright 2014 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 versioned_test
import (
"bytes"
"io/ioutil"
"testing"
apiequality "k8s.io/apimachinery/pkg/api/equality"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/apimachinery/pkg/runtime/serializer/streaming"
"k8s.io/apimachinery/pkg/watch"
"k8s.io/client-go/pkg/api"
"k8s.io/client-go/pkg/api/v1"
restclientwatch "k8s.io/client-go/rest/watch"
_ "k8s.io/client-go/pkg/api/install"
)
func TestEncodeDecodeRoundTrip(t *testing.T) {
testCases := []struct {
Type watch.EventType
Object runtime.Object
Codec runtime.Codec
}{
{
watch.Added,
&api.Pod{ObjectMeta: metav1.ObjectMeta{Name: "foo"}},
api.Codecs.LegacyCodec(v1.SchemeGroupVersion),
},
{
watch.Modified,
&api.Pod{ObjectMeta: metav1.ObjectMeta{Name: "foo"}},
api.Codecs.LegacyCodec(v1.SchemeGroupVersion),
},
{
watch.Deleted,
&api.Pod{ObjectMeta: metav1.ObjectMeta{Name: "foo"}},
api.Codecs.LegacyCodec(v1.SchemeGroupVersion),
},
}
for i, testCase := range testCases {
buf := &bytes.Buffer{}
codec := testCase.Codec
encoder := restclientwatch.NewEncoder(streaming.NewEncoder(buf, codec), codec)
if err := encoder.Encode(&watch.Event{Type: testCase.Type, Object: testCase.Object}); err != nil {
t.Errorf("%d: unexpected error: %v", i, err)
continue
}
rc := ioutil.NopCloser(buf)
decoder := restclientwatch.NewDecoder(streaming.NewDecoder(rc, codec), codec)
event, obj, err := decoder.Decode()
if err != nil {
t.Errorf("%d: unexpected error: %v", i, err)
continue
}
if !apiequality.Semantic.DeepDerivative(testCase.Object, obj) {
t.Errorf("%d: expected %#v, got %#v", i, testCase.Object, obj)
}
if event != testCase.Type {
t.Errorf("%d: unexpected type: %#v", i, event)
}
}
}