Dep helper (#2151)

* Add dep task to update go dependencies

* Update go dependencies
This commit is contained in:
Manuel Alejandro de Brito Fontes
2018-09-29 19:47:07 -03:00
committed by Miek Gieben
parent 8f8b81f56b
commit 0e8977761d
764 changed files with 172 additions and 267451 deletions

View File

@@ -1,169 +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 discovery
import (
"io/ioutil"
"os"
"testing"
"time"
"github.com/googleapis/gnostic/OpenAPIv2"
"github.com/stretchr/testify/assert"
"k8s.io/apimachinery/pkg/api/errors"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/runtime/schema"
"k8s.io/apimachinery/pkg/version"
restclient "k8s.io/client-go/rest"
"k8s.io/client-go/rest/fake"
)
func TestCachedDiscoveryClient_Fresh(t *testing.T) {
assert := assert.New(t)
d, err := ioutil.TempDir("", "")
assert.NoError(err)
defer os.RemoveAll(d)
c := fakeDiscoveryClient{}
cdc := newCachedDiscoveryClient(&c, d, 60*time.Second)
assert.True(cdc.Fresh(), "should be fresh after creation")
cdc.ServerGroups()
assert.True(cdc.Fresh(), "should be fresh after groups call without cache")
assert.Equal(c.groupCalls, 1)
cdc.ServerGroups()
assert.True(cdc.Fresh(), "should be fresh after another groups call")
assert.Equal(c.groupCalls, 1)
cdc.ServerResources()
assert.True(cdc.Fresh(), "should be fresh after resources call")
assert.Equal(c.resourceCalls, 1)
cdc.ServerResources()
assert.True(cdc.Fresh(), "should be fresh after another resources call")
assert.Equal(c.resourceCalls, 1)
cdc = newCachedDiscoveryClient(&c, d, 60*time.Second)
cdc.ServerGroups()
assert.False(cdc.Fresh(), "should NOT be fresh after recreation with existing groups cache")
assert.Equal(c.groupCalls, 1)
cdc.ServerResources()
assert.False(cdc.Fresh(), "should NOT be fresh after recreation with existing resources cache")
assert.Equal(c.resourceCalls, 1)
cdc.Invalidate()
assert.True(cdc.Fresh(), "should be fresh after cache invalidation")
cdc.ServerResources()
assert.True(cdc.Fresh(), "should ignore existing resources cache after invalidation")
assert.Equal(c.resourceCalls, 2)
}
func TestNewCachedDiscoveryClient_TTL(t *testing.T) {
assert := assert.New(t)
d, err := ioutil.TempDir("", "")
assert.NoError(err)
defer os.RemoveAll(d)
c := fakeDiscoveryClient{}
cdc := newCachedDiscoveryClient(&c, d, 1*time.Nanosecond)
cdc.ServerGroups()
assert.Equal(c.groupCalls, 1)
time.Sleep(1 * time.Second)
cdc.ServerGroups()
assert.Equal(c.groupCalls, 2)
}
type fakeDiscoveryClient struct {
groupCalls int
resourceCalls int
versionCalls int
openAPICalls int
serverResourcesHandler func() ([]*metav1.APIResourceList, error)
}
var _ DiscoveryInterface = &fakeDiscoveryClient{}
func (c *fakeDiscoveryClient) RESTClient() restclient.Interface {
return &fake.RESTClient{}
}
func (c *fakeDiscoveryClient) ServerGroups() (*metav1.APIGroupList, error) {
c.groupCalls = c.groupCalls + 1
return &metav1.APIGroupList{
Groups: []metav1.APIGroup{
{
Name: "a",
Versions: []metav1.GroupVersionForDiscovery{
{
GroupVersion: "a/v1",
Version: "v1",
},
},
PreferredVersion: metav1.GroupVersionForDiscovery{
GroupVersion: "a/v1",
Version: "v1",
},
},
},
}, nil
}
func (c *fakeDiscoveryClient) ServerResourcesForGroupVersion(groupVersion string) (*metav1.APIResourceList, error) {
c.resourceCalls = c.resourceCalls + 1
if groupVersion == "a/v1" {
return &metav1.APIResourceList{APIResources: []metav1.APIResource{{Name: "widgets", Kind: "Widget"}}}, nil
}
return nil, errors.NewNotFound(schema.GroupResource{}, "")
}
func (c *fakeDiscoveryClient) ServerResources() ([]*metav1.APIResourceList, error) {
c.resourceCalls = c.resourceCalls + 1
if c.serverResourcesHandler != nil {
return c.serverResourcesHandler()
}
return []*metav1.APIResourceList{}, nil
}
func (c *fakeDiscoveryClient) ServerPreferredResources() ([]*metav1.APIResourceList, error) {
c.resourceCalls = c.resourceCalls + 1
return nil, nil
}
func (c *fakeDiscoveryClient) ServerPreferredNamespacedResources() ([]*metav1.APIResourceList, error) {
c.resourceCalls = c.resourceCalls + 1
return nil, nil
}
func (c *fakeDiscoveryClient) ServerVersion() (*version.Info, error) {
c.versionCalls = c.versionCalls + 1
return &version.Info{}, nil
}
func (c *fakeDiscoveryClient) OpenAPISchema() (*openapi_v2.Document, error) {
c.openAPICalls = c.openAPICalls + 1
return &openapi_v2.Document{}, nil
}

View File

@@ -1,882 +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 discovery
import (
"encoding/json"
"fmt"
"mime"
"net/http"
"net/http/httptest"
"reflect"
"testing"
"github.com/gogo/protobuf/proto"
"github.com/googleapis/gnostic/OpenAPIv2"
"github.com/stretchr/testify/assert"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/runtime/schema"
"k8s.io/apimachinery/pkg/util/diff"
"k8s.io/apimachinery/pkg/util/sets"
"k8s.io/apimachinery/pkg/version"
restclient "k8s.io/client-go/rest"
)
func TestGetServerVersion(t *testing.T) {
expect := version.Info{
Major: "foo",
Minor: "bar",
GitCommit: "baz",
}
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) {
output, err := json.Marshal(expect)
if err != nil {
t.Errorf("unexpected encoding error: %v", err)
return
}
w.Header().Set("Content-Type", "application/json")
w.WriteHeader(http.StatusOK)
w.Write(output)
}))
defer server.Close()
client := NewDiscoveryClientForConfigOrDie(&restclient.Config{Host: server.URL})
got, err := client.ServerVersion()
if err != nil {
t.Fatalf("unexpected encoding error: %v", err)
}
if e, a := expect, *got; !reflect.DeepEqual(e, a) {
t.Errorf("expected %v, got %v", e, a)
}
}
func TestGetServerGroupsWithV1Server(t *testing.T) {
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) {
var obj interface{}
switch req.URL.Path {
case "/api":
obj = &metav1.APIVersions{
Versions: []string{
"v1",
},
}
case "/apis":
obj = &metav1.APIGroupList{
Groups: []metav1.APIGroup{
{
Name: "extensions",
Versions: []metav1.GroupVersionForDiscovery{
{GroupVersion: "extensions/v1beta1"},
},
},
},
}
default:
w.WriteHeader(http.StatusNotFound)
return
}
output, err := json.Marshal(obj)
if err != nil {
t.Fatalf("unexpected encoding error: %v", err)
return
}
w.Header().Set("Content-Type", "application/json")
w.WriteHeader(http.StatusOK)
w.Write(output)
}))
defer server.Close()
client := NewDiscoveryClientForConfigOrDie(&restclient.Config{Host: server.URL})
// ServerGroups should not return an error even if server returns error at /api and /apis
apiGroupList, err := client.ServerGroups()
if err != nil {
t.Fatalf("unexpected error: %v", err)
}
groupVersions := metav1.ExtractGroupVersions(apiGroupList)
if !reflect.DeepEqual(groupVersions, []string{"v1", "extensions/v1beta1"}) {
t.Errorf("expected: %q, got: %q", []string{"v1", "extensions/v1beta1"}, groupVersions)
}
}
func TestGetServerGroupsWithBrokenServer(t *testing.T) {
for _, statusCode := range []int{http.StatusNotFound, http.StatusForbidden} {
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) {
w.WriteHeader(statusCode)
}))
defer server.Close()
client := NewDiscoveryClientForConfigOrDie(&restclient.Config{Host: server.URL})
// ServerGroups should not return an error even if server returns Not Found or Forbidden error at all end points
apiGroupList, err := client.ServerGroups()
if err != nil {
t.Fatalf("unexpected error: %v", err)
}
groupVersions := metav1.ExtractGroupVersions(apiGroupList)
if len(groupVersions) != 0 {
t.Errorf("expected empty list, got: %q", groupVersions)
}
}
}
func TestTimeoutIsSet(t *testing.T) {
cfg := &restclient.Config{}
setDiscoveryDefaults(cfg)
assert.Equal(t, defaultTimeout, cfg.Timeout)
}
func TestGetServerResourcesWithV1Server(t *testing.T) {
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) {
var obj interface{}
switch req.URL.Path {
case "/api":
obj = &metav1.APIVersions{
Versions: []string{
"v1",
},
}
default:
w.WriteHeader(http.StatusNotFound)
return
}
output, err := json.Marshal(obj)
if err != nil {
t.Errorf("unexpected encoding error: %v", err)
return
}
w.Header().Set("Content-Type", "application/json")
w.WriteHeader(http.StatusOK)
w.Write(output)
}))
defer server.Close()
client := NewDiscoveryClientForConfigOrDie(&restclient.Config{Host: server.URL})
// ServerResources should not return an error even if server returns error at /api/v1.
serverResources, err := client.ServerResources()
if err != nil {
t.Errorf("unexpected error: %v", err)
}
gvs := groupVersions(serverResources)
if !sets.NewString(gvs...).Has("v1") {
t.Errorf("missing v1 in resource list: %v", serverResources)
}
}
func TestGetServerResources(t *testing.T) {
stable := metav1.APIResourceList{
GroupVersion: "v1",
APIResources: []metav1.APIResource{
{Name: "pods", Namespaced: true, Kind: "Pod"},
{Name: "services", Namespaced: true, Kind: "Service"},
{Name: "namespaces", Namespaced: false, Kind: "Namespace"},
},
}
beta := metav1.APIResourceList{
GroupVersion: "extensions/v1beta1",
APIResources: []metav1.APIResource{
{Name: "deployments", Namespaced: true, Kind: "Deployment"},
{Name: "ingresses", Namespaced: true, Kind: "Ingress"},
{Name: "jobs", Namespaced: true, Kind: "Job"},
},
}
beta2 := metav1.APIResourceList{
GroupVersion: "extensions/v1beta2",
APIResources: []metav1.APIResource{
{Name: "deployments", Namespaced: true, Kind: "Deployment"},
{Name: "ingresses", Namespaced: true, Kind: "Ingress"},
{Name: "jobs", Namespaced: true, Kind: "Job"},
},
}
tests := []struct {
resourcesList *metav1.APIResourceList
path string
request string
expectErr bool
}{
{
resourcesList: &stable,
path: "/api/v1",
request: "v1",
expectErr: false,
},
{
resourcesList: &beta,
path: "/apis/extensions/v1beta1",
request: "extensions/v1beta1",
expectErr: false,
},
{
resourcesList: &stable,
path: "/api/v1",
request: "foobar",
expectErr: true,
},
}
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) {
var list interface{}
switch req.URL.Path {
case "/api/v1":
list = &stable
case "/apis/extensions/v1beta1":
list = &beta
case "/apis/extensions/v1beta2":
list = &beta2
case "/api":
list = &metav1.APIVersions{
Versions: []string{
"v1",
},
}
case "/apis":
list = &metav1.APIGroupList{
Groups: []metav1.APIGroup{
{
Name: "extensions",
Versions: []metav1.GroupVersionForDiscovery{
{GroupVersion: "extensions/v1beta1", Version: "v1beta1"},
{GroupVersion: "extensions/v1beta2", Version: "v1beta2"},
},
},
},
}
default:
t.Logf("unexpected request: %s", req.URL.Path)
w.WriteHeader(http.StatusNotFound)
return
}
output, err := json.Marshal(list)
if err != nil {
t.Errorf("unexpected encoding error: %v", err)
return
}
w.Header().Set("Content-Type", "application/json")
w.WriteHeader(http.StatusOK)
w.Write(output)
}))
defer server.Close()
client := NewDiscoveryClientForConfigOrDie(&restclient.Config{Host: server.URL})
for _, test := range tests {
got, err := client.ServerResourcesForGroupVersion(test.request)
if test.expectErr {
if err == nil {
t.Error("unexpected non-error")
}
continue
}
if err != nil {
t.Errorf("unexpected error: %v", err)
continue
}
if !reflect.DeepEqual(got, test.resourcesList) {
t.Errorf("expected:\n%v\ngot:\n%v\n", test.resourcesList, got)
}
}
serverResources, err := client.ServerResources()
if err != nil {
t.Errorf("unexpected error: %v", err)
}
serverGroupVersions := groupVersions(serverResources)
expectedGroupVersions := []string{"v1", "extensions/v1beta1", "extensions/v1beta2"}
if !reflect.DeepEqual(expectedGroupVersions, serverGroupVersions) {
t.Errorf("unexpected group versions: %v", diff.ObjectReflectDiff(expectedGroupVersions, serverGroupVersions))
}
}
var returnedOpenAPI = openapi_v2.Document{
Definitions: &openapi_v2.Definitions{
AdditionalProperties: []*openapi_v2.NamedSchema{
{
Name: "fake.type.1",
Value: &openapi_v2.Schema{
Properties: &openapi_v2.Properties{
AdditionalProperties: []*openapi_v2.NamedSchema{
{
Name: "count",
Value: &openapi_v2.Schema{
Type: &openapi_v2.TypeItem{
Value: []string{"integer"},
},
},
},
},
},
},
},
{
Name: "fake.type.2",
Value: &openapi_v2.Schema{
Properties: &openapi_v2.Properties{
AdditionalProperties: []*openapi_v2.NamedSchema{
{
Name: "count",
Value: &openapi_v2.Schema{
Type: &openapi_v2.TypeItem{
Value: []string{"array"},
},
Items: &openapi_v2.ItemsItem{
Schema: []*openapi_v2.Schema{
{
Type: &openapi_v2.TypeItem{
Value: []string{"string"},
},
},
},
},
},
},
},
},
},
},
},
},
}
func openapiSchemaDeprecatedFakeServer(status int) (*httptest.Server, error) {
var sErr error
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) {
if req.URL.Path == "/openapi/v2" {
// write the error status for the new endpoint request
w.WriteHeader(status)
return
}
if req.URL.Path != "/swagger-2.0.0.pb-v1" {
sErr = fmt.Errorf("Unexpected url %v", req.URL)
}
if req.Method != "GET" {
sErr = fmt.Errorf("Unexpected method %v", req.Method)
}
mime.AddExtensionType(".pb-v1", "application/com.github.googleapis.gnostic.OpenAPIv2@68f4ded+protobuf")
output, err := proto.Marshal(&returnedOpenAPI)
if err != nil {
sErr = err
return
}
w.WriteHeader(http.StatusOK)
w.Write(output)
}))
return server, sErr
}
func openapiSchemaFakeServer() (*httptest.Server, error) {
var sErr error
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) {
if req.URL.Path != "/openapi/v2" {
sErr = fmt.Errorf("Unexpected url %v", req.URL)
}
if req.Method != "GET" {
sErr = fmt.Errorf("Unexpected method %v", req.Method)
}
decipherableFormat := req.Header.Get("Accept")
if decipherableFormat != "application/com.github.proto-openapi.spec.v2@v1.0+protobuf" {
sErr = fmt.Errorf("Unexpected accept mime type %v", decipherableFormat)
}
mime.AddExtensionType(".pb-v1", "application/com.github.googleapis.gnostic.OpenAPIv2@68f4ded+protobuf")
output, err := proto.Marshal(&returnedOpenAPI)
if err != nil {
sErr = err
return
}
w.WriteHeader(http.StatusOK)
w.Write(output)
}))
return server, sErr
}
func TestGetOpenAPISchema(t *testing.T) {
server, err := openapiSchemaFakeServer()
if err != nil {
t.Errorf("unexpected error starting fake server: %v", err)
}
defer server.Close()
client := NewDiscoveryClientForConfigOrDie(&restclient.Config{Host: server.URL})
got, err := client.OpenAPISchema()
if err != nil {
t.Fatalf("unexpected error getting openapi: %v", err)
}
if e, a := returnedOpenAPI, *got; !reflect.DeepEqual(e, a) {
t.Errorf("expected %v, got %v", e, a)
}
}
func TestGetOpenAPISchemaForbiddenFallback(t *testing.T) {
server, err := openapiSchemaDeprecatedFakeServer(http.StatusForbidden)
if err != nil {
t.Errorf("unexpected error starting fake server: %v", err)
}
defer server.Close()
client := NewDiscoveryClientForConfigOrDie(&restclient.Config{Host: server.URL})
got, err := client.OpenAPISchema()
if err != nil {
t.Fatalf("unexpected error getting openapi: %v", err)
}
if e, a := returnedOpenAPI, *got; !reflect.DeepEqual(e, a) {
t.Errorf("expected %v, got %v", e, a)
}
}
func TestGetOpenAPISchemaNotFoundFallback(t *testing.T) {
server, err := openapiSchemaDeprecatedFakeServer(http.StatusNotFound)
if err != nil {
t.Errorf("unexpected error starting fake server: %v", err)
}
defer server.Close()
client := NewDiscoveryClientForConfigOrDie(&restclient.Config{Host: server.URL})
got, err := client.OpenAPISchema()
if err != nil {
t.Fatalf("unexpected error getting openapi: %v", err)
}
if e, a := returnedOpenAPI, *got; !reflect.DeepEqual(e, a) {
t.Errorf("expected %v, got %v", e, a)
}
}
func TestGetOpenAPISchemaNotAcceptableFallback(t *testing.T) {
server, err := openapiSchemaDeprecatedFakeServer(http.StatusNotAcceptable)
if err != nil {
t.Errorf("unexpected error starting fake server: %v", err)
}
defer server.Close()
client := NewDiscoveryClientForConfigOrDie(&restclient.Config{Host: server.URL})
got, err := client.OpenAPISchema()
if err != nil {
t.Fatalf("unexpected error getting openapi: %v", err)
}
if e, a := returnedOpenAPI, *got; !reflect.DeepEqual(e, a) {
t.Errorf("expected %v, got %v", e, a)
}
}
func TestServerPreferredResources(t *testing.T) {
stable := metav1.APIResourceList{
GroupVersion: "v1",
APIResources: []metav1.APIResource{
{Name: "pods", Namespaced: true, Kind: "Pod"},
{Name: "services", Namespaced: true, Kind: "Service"},
{Name: "namespaces", Namespaced: false, Kind: "Namespace"},
},
}
tests := []struct {
resourcesList []*metav1.APIResourceList
response func(w http.ResponseWriter, req *http.Request)
expectErr func(err error) bool
}{
{
resourcesList: []*metav1.APIResourceList{&stable},
expectErr: IsGroupDiscoveryFailedError,
response: func(w http.ResponseWriter, req *http.Request) {
var list interface{}
switch req.URL.Path {
case "/apis/extensions/v1beta1":
w.WriteHeader(http.StatusInternalServerError)
return
case "/api/v1":
list = &stable
case "/api":
list = &metav1.APIVersions{
Versions: []string{
"v1",
},
}
case "/apis":
list = &metav1.APIGroupList{
Groups: []metav1.APIGroup{
{
Versions: []metav1.GroupVersionForDiscovery{
{GroupVersion: "extensions/v1beta1"},
},
},
},
}
default:
t.Logf("unexpected request: %s", req.URL.Path)
w.WriteHeader(http.StatusNotFound)
return
}
output, err := json.Marshal(list)
if err != nil {
t.Errorf("unexpected encoding error: %v", err)
return
}
w.Header().Set("Content-Type", "application/json")
w.WriteHeader(http.StatusOK)
w.Write(output)
},
},
{
resourcesList: nil,
expectErr: IsGroupDiscoveryFailedError,
response: func(w http.ResponseWriter, req *http.Request) {
var list interface{}
switch req.URL.Path {
case "/apis/extensions/v1beta1":
w.WriteHeader(http.StatusInternalServerError)
return
case "/api/v1":
w.WriteHeader(http.StatusInternalServerError)
case "/api":
list = &metav1.APIVersions{
Versions: []string{
"v1",
},
}
case "/apis":
list = &metav1.APIGroupList{
Groups: []metav1.APIGroup{
{
Versions: []metav1.GroupVersionForDiscovery{
{GroupVersion: "extensions/v1beta1"},
},
},
},
}
default:
t.Logf("unexpected request: %s", req.URL.Path)
w.WriteHeader(http.StatusNotFound)
return
}
output, err := json.Marshal(list)
if err != nil {
t.Errorf("unexpected encoding error: %v", err)
return
}
w.Header().Set("Content-Type", "application/json")
w.WriteHeader(http.StatusOK)
w.Write(output)
},
},
}
for _, test := range tests {
server := httptest.NewServer(http.HandlerFunc(test.response))
defer server.Close()
client := NewDiscoveryClientForConfigOrDie(&restclient.Config{Host: server.URL})
resources, err := client.ServerPreferredResources()
if test.expectErr != nil {
if err == nil {
t.Error("unexpected non-error")
}
continue
}
if err != nil {
t.Errorf("unexpected error: %v", err)
continue
}
got, err := GroupVersionResources(resources)
if err != nil {
t.Errorf("unexpected error: %v", err)
continue
}
expected, _ := GroupVersionResources(test.resourcesList)
if !reflect.DeepEqual(got, expected) {
t.Errorf("expected:\n%v\ngot:\n%v\n", test.resourcesList, got)
}
server.Close()
}
}
func TestServerPreferredResourcesRetries(t *testing.T) {
stable := metav1.APIResourceList{
GroupVersion: "v1",
APIResources: []metav1.APIResource{
{Name: "pods", Namespaced: true, Kind: "Pod"},
},
}
beta := metav1.APIResourceList{
GroupVersion: "extensions/v1",
APIResources: []metav1.APIResource{
{Name: "deployments", Namespaced: true, Kind: "Deployment"},
},
}
response := func(numErrors int) http.HandlerFunc {
var i = 0
return func(w http.ResponseWriter, req *http.Request) {
var list interface{}
switch req.URL.Path {
case "/apis/extensions/v1beta1":
if i < numErrors {
i++
w.WriteHeader(http.StatusInternalServerError)
return
}
list = &beta
case "/api/v1":
list = &stable
case "/api":
list = &metav1.APIVersions{
Versions: []string{
"v1",
},
}
case "/apis":
list = &metav1.APIGroupList{
Groups: []metav1.APIGroup{
{
Name: "extensions",
Versions: []metav1.GroupVersionForDiscovery{
{GroupVersion: "extensions/v1beta1", Version: "v1beta1"},
},
PreferredVersion: metav1.GroupVersionForDiscovery{
GroupVersion: "extensions/v1beta1",
Version: "v1beta1",
},
},
},
}
default:
t.Logf("unexpected request: %s", req.URL.Path)
w.WriteHeader(http.StatusNotFound)
return
}
output, err := json.Marshal(list)
if err != nil {
t.Errorf("unexpected encoding error: %v", err)
return
}
w.Header().Set("Content-Type", "application/json")
w.WriteHeader(http.StatusOK)
w.Write(output)
}
}
tests := []struct {
responseErrors int
expectResources int
expectedError func(err error) bool
}{
{
responseErrors: 1,
expectResources: 2,
expectedError: func(err error) bool {
return err == nil
},
},
{
responseErrors: 2,
expectResources: 1,
expectedError: IsGroupDiscoveryFailedError,
},
}
for i, tc := range tests {
server := httptest.NewServer(http.HandlerFunc(response(tc.responseErrors)))
defer server.Close()
client := NewDiscoveryClientForConfigOrDie(&restclient.Config{Host: server.URL})
resources, err := client.ServerPreferredResources()
if !tc.expectedError(err) {
t.Errorf("case %d: unexpected error: %v", i, err)
}
got, err := GroupVersionResources(resources)
if err != nil {
t.Errorf("case %d: unexpected error: %v", i, err)
}
if len(got) != tc.expectResources {
t.Errorf("case %d: expect %d resources, got %#v", i, tc.expectResources, got)
}
server.Close()
}
}
func TestServerPreferredNamespacedResources(t *testing.T) {
stable := metav1.APIResourceList{
GroupVersion: "v1",
APIResources: []metav1.APIResource{
{Name: "pods", Namespaced: true, Kind: "Pod"},
{Name: "services", Namespaced: true, Kind: "Service"},
{Name: "namespaces", Namespaced: false, Kind: "Namespace"},
},
}
batchv1 := metav1.APIResourceList{
GroupVersion: "batch/v1",
APIResources: []metav1.APIResource{
{Name: "jobs", Namespaced: true, Kind: "Job"},
},
}
batchv2alpha1 := metav1.APIResourceList{
GroupVersion: "batch/v2alpha1",
APIResources: []metav1.APIResource{
{Name: "jobs", Namespaced: true, Kind: "Job"},
{Name: "cronjobs", Namespaced: true, Kind: "CronJob"},
},
}
batchv3alpha1 := metav1.APIResourceList{
GroupVersion: "batch/v3alpha1",
APIResources: []metav1.APIResource{
{Name: "jobs", Namespaced: true, Kind: "Job"},
{Name: "cronjobs", Namespaced: true, Kind: "CronJob"},
},
}
tests := []struct {
response func(w http.ResponseWriter, req *http.Request)
expected map[schema.GroupVersionResource]struct{}
}{
{
response: func(w http.ResponseWriter, req *http.Request) {
var list interface{}
switch req.URL.Path {
case "/api/v1":
list = &stable
case "/api":
list = &metav1.APIVersions{
Versions: []string{
"v1",
},
}
default:
t.Logf("unexpected request: %s", req.URL.Path)
w.WriteHeader(http.StatusNotFound)
return
}
output, err := json.Marshal(list)
if err != nil {
t.Errorf("unexpected encoding error: %v", err)
return
}
w.Header().Set("Content-Type", "application/json")
w.WriteHeader(http.StatusOK)
w.Write(output)
},
expected: map[schema.GroupVersionResource]struct{}{
{Group: "", Version: "v1", Resource: "pods"}: {},
{Group: "", Version: "v1", Resource: "services"}: {},
},
},
{
response: func(w http.ResponseWriter, req *http.Request) {
var list interface{}
switch req.URL.Path {
case "/apis":
list = &metav1.APIGroupList{
Groups: []metav1.APIGroup{
{
Name: "batch",
Versions: []metav1.GroupVersionForDiscovery{
{GroupVersion: "batch/v1", Version: "v1"},
{GroupVersion: "batch/v2alpha1", Version: "v2alpha1"},
{GroupVersion: "batch/v3alpha1", Version: "v3alpha1"},
},
PreferredVersion: metav1.GroupVersionForDiscovery{GroupVersion: "batch/v1", Version: "v1"},
},
},
}
case "/apis/batch/v1":
list = &batchv1
case "/apis/batch/v2alpha1":
list = &batchv2alpha1
case "/apis/batch/v3alpha1":
list = &batchv3alpha1
default:
t.Logf("unexpected request: %s", req.URL.Path)
w.WriteHeader(http.StatusNotFound)
return
}
output, err := json.Marshal(list)
if err != nil {
t.Errorf("unexpected encoding error: %v", err)
return
}
w.Header().Set("Content-Type", "application/json")
w.WriteHeader(http.StatusOK)
w.Write(output)
},
expected: map[schema.GroupVersionResource]struct{}{
{Group: "batch", Version: "v1", Resource: "jobs"}: {},
{Group: "batch", Version: "v2alpha1", Resource: "cronjobs"}: {},
},
},
{
response: func(w http.ResponseWriter, req *http.Request) {
var list interface{}
switch req.URL.Path {
case "/apis":
list = &metav1.APIGroupList{
Groups: []metav1.APIGroup{
{
Name: "batch",
Versions: []metav1.GroupVersionForDiscovery{
{GroupVersion: "batch/v1", Version: "v1"},
{GroupVersion: "batch/v2alpha1", Version: "v2alpha1"},
{GroupVersion: "batch/v3alpha1", Version: "v3alpha1"},
},
PreferredVersion: metav1.GroupVersionForDiscovery{GroupVersion: "batch/v2alpha", Version: "v2alpha1"},
},
},
}
case "/apis/batch/v1":
list = &batchv1
case "/apis/batch/v2alpha1":
list = &batchv2alpha1
case "/apis/batch/v3alpha1":
list = &batchv3alpha1
default:
t.Logf("unexpected request: %s", req.URL.Path)
w.WriteHeader(http.StatusNotFound)
return
}
output, err := json.Marshal(list)
if err != nil {
t.Errorf("unexpected encoding error: %v", err)
return
}
w.Header().Set("Content-Type", "application/json")
w.WriteHeader(http.StatusOK)
w.Write(output)
},
expected: map[schema.GroupVersionResource]struct{}{
{Group: "batch", Version: "v2alpha1", Resource: "jobs"}: {},
{Group: "batch", Version: "v2alpha1", Resource: "cronjobs"}: {},
},
},
}
for i, test := range tests {
server := httptest.NewServer(http.HandlerFunc(test.response))
defer server.Close()
client := NewDiscoveryClientForConfigOrDie(&restclient.Config{Host: server.URL})
resources, err := client.ServerPreferredNamespacedResources()
if err != nil {
t.Errorf("[%d] unexpected error: %v", i, err)
continue
}
got, err := GroupVersionResources(resources)
if err != nil {
t.Errorf("[%d] unexpected error: %v", i, err)
continue
}
if !reflect.DeepEqual(got, test.expected) {
t.Errorf("[%d] expected:\n%v\ngot:\n%v\n", i, test.expected, got)
}
server.Close()
}
}
func groupVersions(resources []*metav1.APIResourceList) []string {
result := []string{}
for _, resourceList := range resources {
result = append(result, resourceList.GroupVersion)
}
return result
}

View File

@@ -1,46 +0,0 @@
/*
Copyright 2017 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 fake_test
import (
"testing"
"k8s.io/apimachinery/pkg/version"
fakediscovery "k8s.io/client-go/discovery/fake"
fakeclientset "k8s.io/client-go/kubernetes/fake"
)
func TestFakingServerVersion(t *testing.T) {
client := fakeclientset.NewSimpleClientset()
fakeDiscovery, ok := client.Discovery().(*fakediscovery.FakeDiscovery)
if !ok {
t.Fatalf("couldn't convert Discovery() to *FakeDiscovery")
}
testGitCommit := "v1.0.0"
fakeDiscovery.FakedServerVersion = &version.Info{
GitCommit: testGitCommit,
}
sv, err := client.Discovery().ServerVersion()
if err != nil {
t.Fatalf("unexpected error: %v", err)
}
if sv.GitCommit != testGitCommit {
t.Fatalf("unexpected faked discovery return value: %q", sv.GitCommit)
}
}

View File

@@ -1,184 +0,0 @@
/*
Copyright 2015 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 discovery_test
import (
"bytes"
"encoding/json"
"errors"
"io"
"io/ioutil"
"net/http"
"strings"
"testing"
"k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/apimachinery/pkg/runtime/schema"
"k8s.io/apimachinery/pkg/util/sets"
"k8s.io/client-go/discovery"
"k8s.io/client-go/kubernetes/scheme"
restclient "k8s.io/client-go/rest"
"k8s.io/client-go/rest/fake"
)
func objBody(object interface{}) io.ReadCloser {
output, err := json.MarshalIndent(object, "", "")
if err != nil {
panic(err)
}
return ioutil.NopCloser(bytes.NewReader([]byte(output)))
}
func TestServerSupportsVersion(t *testing.T) {
tests := []struct {
name string
requiredVersion schema.GroupVersion
serverVersions []string
expectErr func(err error) bool
sendErr error
statusCode int
}{
{
name: "explicit version supported",
requiredVersion: schema.GroupVersion{Version: "v1"},
serverVersions: []string{"/version1", v1.SchemeGroupVersion.String()},
statusCode: http.StatusOK,
},
{
name: "explicit version not supported on server",
requiredVersion: schema.GroupVersion{Version: "v1"},
serverVersions: []string{"version1"},
expectErr: func(err error) bool { return strings.Contains(err.Error(), `server does not support API version "v1"`) },
statusCode: http.StatusOK,
},
{
name: "connection refused error",
serverVersions: []string{"version1"},
sendErr: errors.New("connection refused"),
expectErr: func(err error) bool { return strings.Contains(err.Error(), "connection refused") },
statusCode: http.StatusOK,
},
{
name: "discovery fails due to 404 Not Found errors and thus serverVersions is empty, use requested GroupVersion",
requiredVersion: schema.GroupVersion{Version: "version1"},
statusCode: http.StatusNotFound,
},
}
for _, test := range tests {
fakeClient := &fake.RESTClient{
NegotiatedSerializer: scheme.Codecs,
Resp: &http.Response{
StatusCode: test.statusCode,
Body: objBody(&metav1.APIVersions{Versions: test.serverVersions}),
},
Client: fake.CreateHTTPClient(func(req *http.Request) (*http.Response, error) {
if test.sendErr != nil {
return nil, test.sendErr
}
header := http.Header{}
header.Set("Content-Type", runtime.ContentTypeJSON)
return &http.Response{StatusCode: test.statusCode, Header: header, Body: objBody(&metav1.APIVersions{Versions: test.serverVersions})}, nil
}),
}
c := discovery.NewDiscoveryClientForConfigOrDie(&restclient.Config{})
c.RESTClient().(*restclient.RESTClient).Client = fakeClient.Client
err := discovery.ServerSupportsVersion(c, test.requiredVersion)
if err == nil && test.expectErr != nil {
t.Errorf("expected error, got nil for [%s].", test.name)
}
if err != nil {
if test.expectErr == nil || !test.expectErr(err) {
t.Errorf("unexpected error for [%s]: %v.", test.name, err)
}
continue
}
}
}
func TestFilteredBy(t *testing.T) {
all := discovery.ResourcePredicateFunc(func(gv string, r *metav1.APIResource) bool {
return true
})
none := discovery.ResourcePredicateFunc(func(gv string, r *metav1.APIResource) bool {
return false
})
onlyV2 := discovery.ResourcePredicateFunc(func(gv string, r *metav1.APIResource) bool {
return strings.HasSuffix(gv, "/v2") || gv == "v2"
})
onlyBar := discovery.ResourcePredicateFunc(func(gv string, r *metav1.APIResource) bool {
return r.Kind == "Bar"
})
foo := []*metav1.APIResourceList{
{
GroupVersion: "foo/v1",
APIResources: []metav1.APIResource{
{Name: "bar", Kind: "Bar"},
{Name: "test", Kind: "Test"},
},
},
{
GroupVersion: "foo/v2",
APIResources: []metav1.APIResource{
{Name: "bar", Kind: "Bar"},
{Name: "test", Kind: "Test"},
},
},
{
GroupVersion: "foo/v3",
APIResources: []metav1.APIResource{},
},
}
tests := []struct {
input []*metav1.APIResourceList
pred discovery.ResourcePredicate
expectedResources []string
}{
{nil, all, []string{}},
{[]*metav1.APIResourceList{
{GroupVersion: "foo/v1"},
}, all, []string{}},
{foo, all, []string{"foo/v1.bar", "foo/v1.test", "foo/v2.bar", "foo/v2.test"}},
{foo, onlyV2, []string{"foo/v2.bar", "foo/v2.test"}},
{foo, onlyBar, []string{"foo/v1.bar", "foo/v2.bar"}},
{foo, none, []string{}},
}
for i, test := range tests {
filtered := discovery.FilteredBy(test.pred, test.input)
if expected, got := sets.NewString(test.expectedResources...), sets.NewString(stringify(filtered)...); !expected.Equal(got) {
t.Errorf("[%d] unexpected group versions: expected=%v, got=%v", i, test.expectedResources, stringify(filtered))
}
}
}
func stringify(rls []*metav1.APIResourceList) []string {
result := []string{}
for _, rl := range rls {
for _, r := range rl.APIResources {
result = append(result, rl.GroupVersion+"."+r.Name)
}
if len(rl.APIResources) == 0 {
result = append(result, rl.GroupVersion)
}
}
return result
}

View File

@@ -1,95 +0,0 @@
/*
Copyright 2017 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 discovery
import (
"bytes"
"io/ioutil"
"net/http"
"net/url"
"os"
"testing"
)
// copied from k8s.io/client-go/transport/round_trippers_test.go
type testRoundTripper struct {
Request *http.Request
Response *http.Response
Err error
}
func (rt *testRoundTripper) RoundTrip(req *http.Request) (*http.Response, error) {
rt.Request = req
return rt.Response, rt.Err
}
func TestCacheRoundTripper(t *testing.T) {
rt := &testRoundTripper{}
cacheDir, err := ioutil.TempDir("", "cache-rt")
defer os.RemoveAll(cacheDir)
if err != nil {
t.Fatal(err)
}
cache := newCacheRoundTripper(cacheDir, rt)
// First call, caches the response
req := &http.Request{
Method: http.MethodGet,
URL: &url.URL{Host: "localhost"},
}
rt.Response = &http.Response{
Header: http.Header{"ETag": []string{`"123456"`}},
Body: ioutil.NopCloser(bytes.NewReader([]byte("Content"))),
StatusCode: http.StatusOK,
}
resp, err := cache.RoundTrip(req)
if err != nil {
t.Fatal(err)
}
content, err := ioutil.ReadAll(resp.Body)
if err != nil {
t.Fatal(err)
}
if string(content) != "Content" {
t.Errorf(`Expected Body to be "Content", got %q`, string(content))
}
// Second call, returns cached response
req = &http.Request{
Method: http.MethodGet,
URL: &url.URL{Host: "localhost"},
}
rt.Response = &http.Response{
StatusCode: http.StatusNotModified,
Body: ioutil.NopCloser(bytes.NewReader([]byte("Other Content"))),
}
resp, err = cache.RoundTrip(req)
if err != nil {
t.Fatal(err)
}
// Read body and make sure we have the initial content
content, err = ioutil.ReadAll(resp.Body)
resp.Body.Close()
if err != nil {
t.Fatal(err)
}
if string(content) != "Content" {
t.Errorf("Invalid content read from cache %q", string(content))
}
}