diff --git a/plugin/pkg/scheduler/BUILD b/plugin/pkg/scheduler/BUILD index b028b281c40..29a0fddc114 100644 --- a/plugin/pkg/scheduler/BUILD +++ b/plugin/pkg/scheduler/BUILD @@ -15,12 +15,12 @@ go_test( tags = ["automanaged"], deps = [ "//pkg/api:go_default_library", - "//pkg/api/testapi:go_default_library", "//plugin/pkg/scheduler/algorithm:go_default_library", "//plugin/pkg/scheduler/algorithm/predicates:go_default_library", "//plugin/pkg/scheduler/core:go_default_library", "//plugin/pkg/scheduler/schedulercache:go_default_library", "//plugin/pkg/scheduler/testing:go_default_library", + "//plugin/pkg/scheduler/util:go_default_library", "//vendor/k8s.io/api/core/v1:go_default_library", "//vendor/k8s.io/apimachinery/pkg/api/resource:go_default_library", "//vendor/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library", diff --git a/plugin/pkg/scheduler/factory/BUILD b/plugin/pkg/scheduler/factory/BUILD index b15b4e885b8..8cc5d9d9442 100644 --- a/plugin/pkg/scheduler/factory/BUILD +++ b/plugin/pkg/scheduler/factory/BUILD @@ -57,7 +57,6 @@ go_test( tags = ["automanaged"], deps = [ "//pkg/api:go_default_library", - "//pkg/api/testapi:go_default_library", "//pkg/api/testing:go_default_library", "//pkg/client/clientset_generated/clientset:go_default_library", "//pkg/client/informers/informers_generated/externalversions:go_default_library", diff --git a/plugin/pkg/scheduler/factory/factory_test.go b/plugin/pkg/scheduler/factory/factory_test.go index 6bc4c225b66..290ab049416 100644 --- a/plugin/pkg/scheduler/factory/factory_test.go +++ b/plugin/pkg/scheduler/factory/factory_test.go @@ -30,7 +30,6 @@ import ( "k8s.io/client-go/tools/cache" utiltesting "k8s.io/client-go/util/testing" "k8s.io/kubernetes/pkg/api" - "k8s.io/kubernetes/pkg/api/testapi" apitesting "k8s.io/kubernetes/pkg/api/testing" "k8s.io/kubernetes/pkg/client/clientset_generated/clientset" informers "k8s.io/kubernetes/pkg/client/informers/informers_generated/externalversions" @@ -244,13 +243,13 @@ func TestDefaultErrorFunc(t *testing.T) { } handler := utiltesting.FakeHandler{ StatusCode: 200, - ResponseBody: runtime.EncodeOrDie(testapi.Default.Codec(), testPod), + ResponseBody: runtime.EncodeOrDie(util.Test.Codec(), testPod), T: t, } mux := http.NewServeMux() // FakeHandler musn't be sent requests other than the one you want to test. - mux.Handle(testapi.Default.ResourcePath("pods", "bar", "foo"), &handler) + mux.Handle(util.Test.ResourcePath("pods", "bar", "foo"), &handler) server := httptest.NewServer(mux) defer server.Close() client := clientset.NewForConfigOrDie(&restclient.Config{Host: server.URL, ContentConfig: restclient.ContentConfig{GroupVersion: &api.Registry.GroupOrDie(v1.GroupName).GroupVersion}}) @@ -282,7 +281,7 @@ func TestDefaultErrorFunc(t *testing.T) { if !exists { continue } - handler.ValidateRequest(t, testapi.Default.ResourcePath("pods", "bar", "foo"), "GET", nil) + handler.ValidateRequest(t, util.Test.ResourcePath("pods", "bar", "foo"), "GET", nil) if e, a := testPod, got; !reflect.DeepEqual(e, a) { t.Errorf("Expected %v, got %v", e, a) } @@ -344,9 +343,9 @@ func TestBind(t *testing.T) { t.Errorf("Unexpected error: %v", err) continue } - expectedBody := runtime.EncodeOrDie(testapi.Default.Codec(), item.binding) + expectedBody := runtime.EncodeOrDie(util.Test.Codec(), item.binding) handler.ValidateRequest(t, - testapi.Default.SubResourcePath("pods", metav1.NamespaceDefault, "foo", "binding"), + util.Test.SubResourcePath("pods", metav1.NamespaceDefault, "foo", "binding"), "POST", &expectedBody) } } diff --git a/plugin/pkg/scheduler/scheduler_test.go b/plugin/pkg/scheduler/scheduler_test.go index 069ce956290..e5195440d94 100644 --- a/plugin/pkg/scheduler/scheduler_test.go +++ b/plugin/pkg/scheduler/scheduler_test.go @@ -33,12 +33,12 @@ import ( clientcache "k8s.io/client-go/tools/cache" "k8s.io/client-go/tools/record" "k8s.io/kubernetes/pkg/api" - "k8s.io/kubernetes/pkg/api/testapi" "k8s.io/kubernetes/plugin/pkg/scheduler/algorithm" "k8s.io/kubernetes/plugin/pkg/scheduler/algorithm/predicates" "k8s.io/kubernetes/plugin/pkg/scheduler/core" "k8s.io/kubernetes/plugin/pkg/scheduler/schedulercache" schedulertesting "k8s.io/kubernetes/plugin/pkg/scheduler/testing" + "k8s.io/kubernetes/plugin/pkg/scheduler/util" ) type fakeBinder struct { @@ -55,7 +55,7 @@ func (fc fakePodConditionUpdater) Update(pod *v1.Pod, podCondition *v1.PodCondit func podWithID(id, desiredHost string) *v1.Pod { return &v1.Pod{ - ObjectMeta: metav1.ObjectMeta{Name: id, SelfLink: testapi.Default.SelfLink("pods", id)}, + ObjectMeta: metav1.ObjectMeta{Name: id, SelfLink: util.Test.SelfLink("pods", id)}, Spec: v1.PodSpec{ NodeName: desiredHost, }, @@ -65,7 +65,7 @@ func podWithID(id, desiredHost string) *v1.Pod { func deletingPod(id string) *v1.Pod { deletionTimestamp := metav1.Now() return &v1.Pod{ - ObjectMeta: metav1.ObjectMeta{Name: id, SelfLink: testapi.Default.SelfLink("pods", id), DeletionTimestamp: &deletionTimestamp}, + ObjectMeta: metav1.ObjectMeta{Name: id, SelfLink: util.Test.SelfLink("pods", id), DeletionTimestamp: &deletionTimestamp}, Spec: v1.PodSpec{ NodeName: "", }, diff --git a/plugin/pkg/scheduler/util/BUILD b/plugin/pkg/scheduler/util/BUILD index 824f7d5bef8..7bba7524005 100644 --- a/plugin/pkg/scheduler/util/BUILD +++ b/plugin/pkg/scheduler/util/BUILD @@ -20,12 +20,17 @@ go_library( name = "go_default_library", srcs = [ "backoff_utils.go", + "testutil.go", "utils.go", ], tags = ["automanaged"], deps = [ + "//pkg/api:go_default_library", + "//pkg/api/install:go_default_library", "//vendor/github.com/golang/glog:go_default_library", "//vendor/k8s.io/api/core/v1:go_default_library", + "//vendor/k8s.io/apimachinery/pkg/runtime:go_default_library", + "//vendor/k8s.io/apimachinery/pkg/runtime/schema:go_default_library", "//vendor/k8s.io/apimachinery/pkg/types:go_default_library", ], ) diff --git a/plugin/pkg/scheduler/util/testutil.go b/plugin/pkg/scheduler/util/testutil.go new file mode 100644 index 00000000000..8b5ef89e830 --- /dev/null +++ b/plugin/pkg/scheduler/util/testutil.go @@ -0,0 +1,168 @@ +/* +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 util + +import ( + "fmt" + "mime" + "os" + "reflect" + "strings" + + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/apimachinery/pkg/runtime/schema" + "k8s.io/kubernetes/pkg/api" + + _ "k8s.io/kubernetes/pkg/api/install" +) + +type TestGroup struct { + externalGroupVersion schema.GroupVersion + internalGroupVersion schema.GroupVersion + internalTypes map[string]reflect.Type + externalTypes map[string]reflect.Type +} + +var ( + Groups = make(map[string]TestGroup) + Test TestGroup + + serializer runtime.SerializerInfo +) + +func init() { + if apiMediaType := os.Getenv("KUBE_TEST_API_TYPE"); len(apiMediaType) > 0 { + var ok bool + mediaType, _, err := mime.ParseMediaType(apiMediaType) + if err != nil { + panic(err) + } + serializer, ok = runtime.SerializerInfoForMediaType(api.Codecs.SupportedMediaTypes(), mediaType) + if !ok { + panic(fmt.Sprintf("no serializer for %s", apiMediaType)) + } + } + + kubeTestAPI := os.Getenv("KUBE_TEST_API") + if len(kubeTestAPI) != 0 { + // priority is "first in list preferred", so this has to run in reverse order + testGroupVersions := strings.Split(kubeTestAPI, ",") + for i := len(testGroupVersions) - 1; i >= 0; i-- { + gvString := testGroupVersions[i] + groupVersion, err := schema.ParseGroupVersion(gvString) + if err != nil { + panic(fmt.Sprintf("Error parsing groupversion %v: %v", gvString, err)) + } + + internalGroupVersion := schema.GroupVersion{Group: groupVersion.Group, Version: runtime.APIVersionInternal} + Groups[groupVersion.Group] = TestGroup{ + externalGroupVersion: groupVersion, + internalGroupVersion: internalGroupVersion, + internalTypes: api.Scheme.KnownTypes(internalGroupVersion), + externalTypes: api.Scheme.KnownTypes(groupVersion), + } + } + } + + if _, ok := Groups[api.GroupName]; !ok { + externalGroupVersion := schema.GroupVersion{Group: api.GroupName, Version: api.Registry.GroupOrDie(api.GroupName).GroupVersion.Version} + Groups[api.GroupName] = TestGroup{ + externalGroupVersion: externalGroupVersion, + internalGroupVersion: api.SchemeGroupVersion, + internalTypes: api.Scheme.KnownTypes(api.SchemeGroupVersion), + externalTypes: api.Scheme.KnownTypes(externalGroupVersion), + } + } + + Test = Groups[api.GroupName] +} + +// Codec returns the codec for the API version to test against, as set by the +// KUBE_TEST_API_TYPE env var. +func (g TestGroup) Codec() runtime.Codec { + if serializer.Serializer == nil { + return api.Codecs.LegacyCodec(g.externalGroupVersion) + } + return api.Codecs.CodecForVersions(serializer.Serializer, api.Codecs.UniversalDeserializer(), schema.GroupVersions{g.externalGroupVersion}, nil) +} + +// SelfLink returns a self link that will appear to be for the version Version(). +// 'resource' should be the resource path, e.g. "pods" for the Pod type. 'name' should be +// empty for lists. +func (g TestGroup) SelfLink(resource, name string) string { + if g.externalGroupVersion.Group == api.GroupName { + if name == "" { + return fmt.Sprintf("/api/%s/%s", g.externalGroupVersion.Version, resource) + } + return fmt.Sprintf("/api/%s/%s/%s", g.externalGroupVersion.Version, resource, name) + } + + // TODO: will need a /apis prefix once we have proper multi-group + // support + if name == "" { + return fmt.Sprintf("/apis/%s/%s/%s", g.externalGroupVersion.Group, g.externalGroupVersion.Version, resource) + } + return fmt.Sprintf("/apis/%s/%s/%s/%s", g.externalGroupVersion.Group, g.externalGroupVersion.Version, resource, name) +} + +// ResourcePathWithPrefix returns the appropriate path for the given prefix (watch, proxy, redirect, etc), resource, namespace and name. +// For ex, this is of the form: +// /api/v1/watch/namespaces/foo/pods/pod0 for v1. +func (g TestGroup) ResourcePathWithPrefix(prefix, resource, namespace, name string) string { + var path string + if g.externalGroupVersion.Group == api.GroupName { + path = "/api/" + g.externalGroupVersion.Version + } else { + // TODO: switch back once we have proper multiple group support + // path = "/apis/" + g.Group + "/" + Version(group...) + path = "/apis/" + g.externalGroupVersion.Group + "/" + g.externalGroupVersion.Version + } + + if prefix != "" { + path = path + "/" + prefix + } + if namespace != "" { + path = path + "/namespaces/" + namespace + } + // Resource names are lower case. + resource = strings.ToLower(resource) + if resource != "" { + path = path + "/" + resource + } + if name != "" { + path = path + "/" + name + } + return path +} + +// ResourcePath returns the appropriate path for the given resource, namespace and name. +// For example, this is of the form: +// /api/v1/namespaces/foo/pods/pod0 for v1. +func (g TestGroup) ResourcePath(resource, namespace, name string) string { + return g.ResourcePathWithPrefix("", resource, namespace, name) +} + +// SubResourcePath returns the appropriate path for the given resource, namespace, +// name and subresource. +func (g TestGroup) SubResourcePath(resource, namespace, name, sub string) string { + path := g.ResourcePathWithPrefix("", resource, namespace, name) + if sub != "" { + path = path + "/" + sub + } + + return path +}