Add more extensive tests to apiserver for variations in version
Formalize v1beta1 and v1beta3 style APIs in our test cases.
This commit is contained in:
@@ -38,6 +38,7 @@ import (
|
||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/api/meta"
|
||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/api/rest"
|
||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/api/v1beta1"
|
||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/api/v1beta3"
|
||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/fields"
|
||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/labels"
|
||||
"github.com/GoogleCloudPlatform/kubernetes/pkg/runtime"
|
||||
@@ -54,11 +55,21 @@ func convert(obj runtime.Object) (runtime.Object, error) {
|
||||
return obj, nil
|
||||
}
|
||||
|
||||
// This creates a fake API version, similar to api/latest.go
|
||||
// This creates a fake API version, similar to api/latest.go for a v1beta1 equivalent api. It is distinct
|
||||
// from the Kubernetes API versions to allow clients to properly distinguish the two.
|
||||
const testVersion = "version"
|
||||
|
||||
var versions = []string{testVersion}
|
||||
var codec = runtime.CodecFor(api.Scheme, testVersion)
|
||||
// The equivalent of the Kubernetes v1beta3 API.
|
||||
const testVersion2 = "version2"
|
||||
|
||||
var versions = []string{testVersion, testVersion2}
|
||||
var legacyCodec = runtime.CodecFor(api.Scheme, testVersion)
|
||||
var codec = runtime.CodecFor(api.Scheme, testVersion2)
|
||||
|
||||
// these codecs reflect ListOptions/DeleteOptions coming from the serverAPIversion
|
||||
var versionServerCodec = runtime.CodecFor(api.Scheme, "v1beta1")
|
||||
var version2ServerCodec = runtime.CodecFor(api.Scheme, "v1beta3")
|
||||
|
||||
var accessor = meta.NewAccessor()
|
||||
var versioner runtime.ResourceVersioner = accessor
|
||||
var selfLinker runtime.SelfLinker = accessor
|
||||
@@ -69,6 +80,12 @@ var requestContextMapper api.RequestContextMapper
|
||||
func interfacesFor(version string) (*meta.VersionInterfaces, error) {
|
||||
switch version {
|
||||
case testVersion:
|
||||
return &meta.VersionInterfaces{
|
||||
Codec: legacyCodec,
|
||||
ObjectConvertor: api.Scheme,
|
||||
MetadataAccessor: accessor,
|
||||
}, nil
|
||||
case testVersion2:
|
||||
return &meta.VersionInterfaces{
|
||||
Codec: codec,
|
||||
ObjectConvertor: api.Scheme,
|
||||
@@ -100,7 +117,10 @@ func init() {
|
||||
api.Scheme.AddKnownTypes("", &Simple{}, &SimpleList{}, &api.Status{}, &api.ListOptions{})
|
||||
// "version" version
|
||||
// TODO: Use versioned api objects?
|
||||
api.Scheme.AddKnownTypes(testVersion, &Simple{}, &SimpleList{}, &v1beta1.DeleteOptions{}, &v1beta1.Status{}, &v1beta1.ListOptions{})
|
||||
api.Scheme.AddKnownTypes(testVersion, &Simple{}, &SimpleList{}, &v1beta1.Status{})
|
||||
// "version2" version
|
||||
// TODO: Use versioned api objects?
|
||||
api.Scheme.AddKnownTypes(testVersion2, &Simple{}, &SimpleList{}, &v1beta3.Status{})
|
||||
|
||||
nsMapper := newMapper()
|
||||
legacyNsMapper := newMapper()
|
||||
@@ -118,6 +138,18 @@ func init() {
|
||||
namespaceMapper = nsMapper
|
||||
admissionControl = admit.NewAlwaysAdmit()
|
||||
requestContextMapper = api.NewRequestContextMapper()
|
||||
|
||||
//mapper.(*meta.DefaultRESTMapper).Add(meta.RESTScopeNamespaceLegacy, "Simple", testVersion, false)
|
||||
api.Scheme.AddFieldLabelConversionFunc(testVersion, "Simple",
|
||||
func(label, value string) (string, string, error) {
|
||||
return label, value, nil
|
||||
},
|
||||
)
|
||||
api.Scheme.AddFieldLabelConversionFunc(testVersion2, "Simple",
|
||||
func(label, value string) (string, string, error) {
|
||||
return label, value, nil
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
// defaultAPIServer exposes nested objects for testability.
|
||||
@@ -129,46 +161,61 @@ type defaultAPIServer struct {
|
||||
|
||||
// uses the default settings
|
||||
func handle(storage map[string]rest.Storage) http.Handler {
|
||||
return handleInternal(storage, admissionControl, mapper, selfLinker)
|
||||
return handleInternal(true, storage, admissionControl, selfLinker)
|
||||
}
|
||||
|
||||
// uses the default settings for a v1beta3 compatible api
|
||||
func handleNew(storage map[string]rest.Storage) http.Handler {
|
||||
return handleInternal(false, storage, admissionControl, selfLinker)
|
||||
}
|
||||
|
||||
// tests with a deny admission controller
|
||||
func handleDeny(storage map[string]rest.Storage) http.Handler {
|
||||
return handleInternal(storage, deny.NewAlwaysDeny(), mapper, selfLinker)
|
||||
return handleInternal(true, storage, deny.NewAlwaysDeny(), selfLinker)
|
||||
}
|
||||
|
||||
// tests using the new namespace scope mechanism
|
||||
func handleNamespaced(storage map[string]rest.Storage) http.Handler {
|
||||
return handleInternal(storage, admissionControl, namespaceMapper, selfLinker)
|
||||
return handleInternal(false, storage, admissionControl, selfLinker)
|
||||
}
|
||||
|
||||
// tests using a custom self linker
|
||||
func handleLinker(storage map[string]rest.Storage, selfLinker runtime.SelfLinker) http.Handler {
|
||||
return handleInternal(storage, admissionControl, mapper, selfLinker)
|
||||
return handleInternal(true, storage, admissionControl, selfLinker)
|
||||
}
|
||||
|
||||
func handleInternal(storage map[string]rest.Storage, admissionControl admission.Interface, mapper meta.RESTMapper, selfLinker runtime.SelfLinker) http.Handler {
|
||||
func handleInternal(legacy bool, storage map[string]rest.Storage, admissionControl admission.Interface, selfLinker runtime.SelfLinker) http.Handler {
|
||||
group := &APIGroupVersion{
|
||||
Storage: storage,
|
||||
|
||||
Mapper: mapper,
|
||||
|
||||
Root: "/api",
|
||||
Version: testVersion,
|
||||
Root: "/api",
|
||||
|
||||
Creater: api.Scheme,
|
||||
Convertor: api.Scheme,
|
||||
Typer: api.Scheme,
|
||||
Codec: codec,
|
||||
Linker: selfLinker,
|
||||
|
||||
Admit: admissionControl,
|
||||
Context: requestContextMapper,
|
||||
}
|
||||
if legacy {
|
||||
group.Version = testVersion
|
||||
group.ServerVersion = "v1beta1"
|
||||
group.Codec = legacyCodec
|
||||
group.Mapper = legacyNamespaceMapper
|
||||
} else {
|
||||
group.Version = testVersion2
|
||||
group.ServerVersion = "v1beta3"
|
||||
group.Codec = codec
|
||||
group.Mapper = namespaceMapper
|
||||
}
|
||||
|
||||
container := restful.NewContainer()
|
||||
container.Router(restful.CurlyRouter{})
|
||||
mux := container.ServeMux
|
||||
group.InstallREST(container)
|
||||
if err := group.InstallREST(container); err != nil {
|
||||
panic(fmt.Sprintf("unable to install container %s: %v", group.Version, err))
|
||||
}
|
||||
ws := new(restful.WebService)
|
||||
InstallSupport(mux, ws)
|
||||
container.Add(ws)
|
||||
@@ -557,27 +604,27 @@ func TestList(t *testing.T) {
|
||||
},
|
||||
// list items in a namespace, v1beta3+
|
||||
{
|
||||
url: "/api/version/namespaces/default/simple",
|
||||
url: "/api/version2/namespaces/default/simple",
|
||||
namespace: "default",
|
||||
selfLink: "/api/version/namespaces/default/simple",
|
||||
selfLink: "/api/version2/namespaces/default/simple",
|
||||
},
|
||||
{
|
||||
url: "/api/version/namespaces/other/simple",
|
||||
url: "/api/version2/namespaces/other/simple",
|
||||
namespace: "other",
|
||||
selfLink: "/api/version/namespaces/other/simple",
|
||||
selfLink: "/api/version2/namespaces/other/simple",
|
||||
},
|
||||
{
|
||||
url: "/api/version/namespaces/other/simple?labels=a%3Db&fields=c%3Dd",
|
||||
url: "/api/version2/namespaces/other/simple?labelSelector=a%3Db&fieldSelector=c%3Dd",
|
||||
namespace: "other",
|
||||
selfLink: "/api/version/namespaces/other/simple",
|
||||
selfLink: "/api/version2/namespaces/other/simple",
|
||||
label: "a=b",
|
||||
field: "c=d",
|
||||
},
|
||||
// list items across all namespaces
|
||||
{
|
||||
url: "/api/version/simple",
|
||||
url: "/api/version2/simple",
|
||||
namespace: "",
|
||||
selfLink: "/api/version/simple",
|
||||
selfLink: "/api/version2/simple",
|
||||
},
|
||||
}
|
||||
for i, testCase := range testCases {
|
||||
@@ -593,7 +640,7 @@ func TestList(t *testing.T) {
|
||||
if testCase.legacy {
|
||||
handler = handleLinker(storage, selfLinker)
|
||||
} else {
|
||||
handler = handleInternal(storage, admissionControl, namespaceMapper, selfLinker)
|
||||
handler = handleInternal(false, storage, admissionControl, selfLinker)
|
||||
}
|
||||
server := httptest.NewServer(handler)
|
||||
defer server.Close()
|
||||
@@ -605,6 +652,9 @@ func TestList(t *testing.T) {
|
||||
}
|
||||
if resp.StatusCode != http.StatusOK {
|
||||
t.Errorf("%d: unexpected status: %d, Expected: %d, %#v", i, resp.StatusCode, http.StatusOK, resp)
|
||||
body, _ := ioutil.ReadAll(resp.Body)
|
||||
t.Logf("%d: body: %s", string(body))
|
||||
continue
|
||||
}
|
||||
// TODO: future, restore get links
|
||||
if !selfLinker.called {
|
||||
@@ -875,16 +925,16 @@ func TestGetNamespaceSelfLink(t *testing.T) {
|
||||
}
|
||||
selfLinker := &setTestSelfLinker{
|
||||
t: t,
|
||||
expectedSet: "/api/version/namespaces/foo/simple/id",
|
||||
expectedSet: "/api/version2/namespaces/foo/simple/id",
|
||||
name: "id",
|
||||
namespace: "foo",
|
||||
}
|
||||
storage["simple"] = &simpleStorage
|
||||
handler := handleInternal(storage, admissionControl, namespaceMapper, selfLinker)
|
||||
handler := handleInternal(false, storage, admissionControl, selfLinker)
|
||||
server := httptest.NewServer(handler)
|
||||
defer server.Close()
|
||||
|
||||
resp, err := http.Get(server.URL + "/api/version/namespaces/foo/simple/id")
|
||||
resp, err := http.Get(server.URL + "/api/version2/namespaces/foo/simple/id")
|
||||
if err != nil {
|
||||
t.Fatalf("unexpected error: %v", err)
|
||||
}
|
||||
@@ -959,7 +1009,7 @@ func TestDeleteWithOptions(t *testing.T) {
|
||||
item := &api.DeleteOptions{
|
||||
GracePeriodSeconds: &grace,
|
||||
}
|
||||
body, err := codec.Encode(item)
|
||||
body, err := versionServerCodec.Encode(item)
|
||||
if err != nil {
|
||||
t.Fatalf("unexpected error: %v", err)
|
||||
}
|
||||
@@ -1020,7 +1070,7 @@ func TestLegacyDeleteIgnoresOptions(t *testing.T) {
|
||||
defer server.Close()
|
||||
|
||||
item := api.NewDeleteOptions(300)
|
||||
body, err := codec.Encode(item)
|
||||
body, err := versionServerCodec.Encode(item)
|
||||
if err != nil {
|
||||
t.Fatalf("unexpected error: %v", err)
|
||||
}
|
||||
@@ -1629,7 +1679,7 @@ func TestCreateInvokesAdmissionControl(t *testing.T) {
|
||||
namespace: "other",
|
||||
expectedSet: "/api/version/foo/bar?namespace=other",
|
||||
}
|
||||
handler := handleInternal(map[string]rest.Storage{"foo": &storage}, deny.NewAlwaysDeny(), mapper, selfLinker)
|
||||
handler := handleInternal(true, map[string]rest.Storage{"foo": &storage}, deny.NewAlwaysDeny(), selfLinker)
|
||||
server := httptest.NewServer(handler)
|
||||
defer server.Close()
|
||||
client := http.Client{}
|
||||
|
Reference in New Issue
Block a user