2014-06-06 23:40:48 +00:00
|
|
|
/*
|
|
|
|
Copyright 2014 Google Inc. All rights reserved.
|
|
|
|
|
|
|
|
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.
|
|
|
|
*/
|
2014-06-23 18:32:11 +00:00
|
|
|
|
2014-06-06 23:40:48 +00:00
|
|
|
package apiserver
|
|
|
|
|
|
|
|
import (
|
|
|
|
"bytes"
|
2014-07-31 18:16:13 +00:00
|
|
|
"encoding/json"
|
|
|
|
"errors"
|
2014-06-06 23:40:48 +00:00
|
|
|
"fmt"
|
|
|
|
"io/ioutil"
|
|
|
|
"net/http"
|
|
|
|
"net/http/httptest"
|
|
|
|
"reflect"
|
2014-07-31 18:26:34 +00:00
|
|
|
"strings"
|
2014-06-19 04:04:11 +00:00
|
|
|
"sync"
|
2014-06-06 23:40:48 +00:00
|
|
|
"testing"
|
2014-06-25 20:21:32 +00:00
|
|
|
"time"
|
2014-06-17 01:03:44 +00:00
|
|
|
|
2015-01-06 16:44:43 +00:00
|
|
|
"github.com/GoogleCloudPlatform/kubernetes/pkg/admission"
|
2014-06-20 23:18:36 +00:00
|
|
|
"github.com/GoogleCloudPlatform/kubernetes/pkg/api"
|
2014-09-03 21:16:00 +00:00
|
|
|
apierrs "github.com/GoogleCloudPlatform/kubernetes/pkg/api/errors"
|
2014-11-11 07:11:45 +00:00
|
|
|
"github.com/GoogleCloudPlatform/kubernetes/pkg/api/meta"
|
2014-06-17 01:03:44 +00:00
|
|
|
"github.com/GoogleCloudPlatform/kubernetes/pkg/labels"
|
2014-09-02 17:55:27 +00:00
|
|
|
"github.com/GoogleCloudPlatform/kubernetes/pkg/runtime"
|
2014-09-09 21:05:18 +00:00
|
|
|
"github.com/GoogleCloudPlatform/kubernetes/pkg/util"
|
2014-07-31 18:16:13 +00:00
|
|
|
"github.com/GoogleCloudPlatform/kubernetes/pkg/version"
|
2014-07-17 17:05:14 +00:00
|
|
|
"github.com/GoogleCloudPlatform/kubernetes/pkg/watch"
|
2015-01-07 19:33:21 +00:00
|
|
|
"github.com/GoogleCloudPlatform/kubernetes/plugin/pkg/admission/admit"
|
|
|
|
"github.com/GoogleCloudPlatform/kubernetes/plugin/pkg/admission/deny"
|
2014-06-06 23:40:48 +00:00
|
|
|
)
|
|
|
|
|
2014-09-08 04:14:18 +00:00
|
|
|
func convert(obj runtime.Object) (runtime.Object, error) {
|
2014-07-16 21:30:28 +00:00
|
|
|
return obj, nil
|
|
|
|
}
|
|
|
|
|
2014-11-11 07:11:45 +00:00
|
|
|
// This creates a fake API version, similar to api/latest.go
|
|
|
|
const testVersion = "version"
|
|
|
|
|
|
|
|
var versions = []string{testVersion}
|
|
|
|
var codec = runtime.CodecFor(api.Scheme, testVersion)
|
|
|
|
var accessor = meta.NewAccessor()
|
|
|
|
var versioner runtime.ResourceVersioner = accessor
|
|
|
|
var selfLinker runtime.SelfLinker = accessor
|
2015-01-31 00:08:59 +00:00
|
|
|
var mapper, namespaceMapper, legacyNamespaceMapper meta.RESTMapper // The mappers with namespace and with legacy namespace scopes.
|
2015-01-07 19:33:21 +00:00
|
|
|
var admissionControl admission.Interface
|
2014-11-11 07:11:45 +00:00
|
|
|
|
|
|
|
func interfacesFor(version string) (*meta.VersionInterfaces, error) {
|
|
|
|
switch version {
|
|
|
|
case testVersion:
|
|
|
|
return &meta.VersionInterfaces{
|
|
|
|
Codec: codec,
|
|
|
|
ObjectConvertor: api.Scheme,
|
|
|
|
MetadataAccessor: accessor,
|
|
|
|
}, nil
|
|
|
|
default:
|
|
|
|
return nil, fmt.Errorf("unsupported storage version: %s (valid: %s)", version, strings.Join(versions, ", "))
|
|
|
|
}
|
|
|
|
}
|
2014-08-06 03:10:48 +00:00
|
|
|
|
2015-01-31 00:08:59 +00:00
|
|
|
func newMapper() *meta.DefaultRESTMapper {
|
|
|
|
return meta.NewDefaultRESTMapper(
|
|
|
|
versions,
|
|
|
|
func(version string) (*meta.VersionInterfaces, bool) {
|
|
|
|
interfaces, err := interfacesFor(version)
|
|
|
|
if err != nil {
|
|
|
|
return nil, false
|
|
|
|
}
|
|
|
|
return interfaces, true
|
|
|
|
},
|
|
|
|
)
|
|
|
|
}
|
|
|
|
|
2014-06-20 23:18:36 +00:00
|
|
|
func init() {
|
2014-11-11 07:11:45 +00:00
|
|
|
// Certain API objects are returned regardless of the contents of storage:
|
|
|
|
// api.Status is returned in errors
|
|
|
|
|
|
|
|
// "internal" version
|
|
|
|
api.Scheme.AddKnownTypes("", &Simple{}, &SimpleList{},
|
2015-01-29 04:41:37 +00:00
|
|
|
&api.Status{})
|
2014-11-11 07:11:45 +00:00
|
|
|
// "version" version
|
|
|
|
// TODO: Use versioned api objects?
|
|
|
|
api.Scheme.AddKnownTypes(testVersion, &Simple{}, &SimpleList{},
|
2015-01-29 04:41:37 +00:00
|
|
|
&api.Status{})
|
2014-11-11 07:11:45 +00:00
|
|
|
|
2015-01-31 00:08:59 +00:00
|
|
|
nsMapper := newMapper()
|
|
|
|
legacyNsMapper := newMapper()
|
2015-01-29 22:46:54 +00:00
|
|
|
// enumerate all supported versions, get the kinds, and register with the mapper how to address our resources
|
|
|
|
for _, version := range versions {
|
|
|
|
for kind := range api.Scheme.KnownTypes(version) {
|
|
|
|
mixedCase := true
|
2015-01-31 00:08:59 +00:00
|
|
|
legacyNsMapper.Add(meta.RESTScopeNamespaceLegacy, kind, version, mixedCase)
|
|
|
|
nsMapper.Add(meta.RESTScopeNamespace, kind, version, mixedCase)
|
2015-01-29 22:46:54 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-01-31 00:08:59 +00:00
|
|
|
mapper = legacyNsMapper
|
|
|
|
legacyNamespaceMapper = legacyNsMapper
|
|
|
|
namespaceMapper = nsMapper
|
2015-01-07 19:33:21 +00:00
|
|
|
admissionControl = admit.NewAlwaysAdmit()
|
2014-06-20 23:18:36 +00:00
|
|
|
}
|
|
|
|
|
2014-06-06 23:40:48 +00:00
|
|
|
type Simple struct {
|
2014-12-01 05:31:52 +00:00
|
|
|
api.TypeMeta `json:",inline"`
|
|
|
|
api.ObjectMeta `json:"metadata"`
|
|
|
|
Other string `json:"other,omitempty"`
|
2014-06-06 23:40:48 +00:00
|
|
|
}
|
|
|
|
|
2014-09-08 04:14:18 +00:00
|
|
|
func (*Simple) IsAnAPIObject() {}
|
|
|
|
|
2014-06-06 23:40:48 +00:00
|
|
|
type SimpleList struct {
|
2014-12-01 05:31:52 +00:00
|
|
|
api.TypeMeta `json:",inline"`
|
|
|
|
api.ListMeta `json:"metadata,inline"`
|
|
|
|
Items []Simple `json:"items,omitempty"`
|
2014-06-06 23:40:48 +00:00
|
|
|
}
|
|
|
|
|
2014-09-08 04:14:18 +00:00
|
|
|
func (*SimpleList) IsAnAPIObject() {}
|
|
|
|
|
2014-11-06 01:22:18 +00:00
|
|
|
func TestSimpleSetupRight(t *testing.T) {
|
|
|
|
s := &Simple{ObjectMeta: api.ObjectMeta{Name: "aName"}}
|
|
|
|
wire, err := codec.Encode(s)
|
|
|
|
if err != nil {
|
|
|
|
t.Fatal(err)
|
|
|
|
}
|
|
|
|
s2, err := codec.Decode(wire)
|
|
|
|
if err != nil {
|
|
|
|
t.Fatal(err)
|
|
|
|
}
|
|
|
|
if !reflect.DeepEqual(s, s2) {
|
|
|
|
t.Fatalf("encode/decode broken:\n%#v\n%#v\n", s, s2)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-06-06 23:40:48 +00:00
|
|
|
type SimpleRESTStorage struct {
|
2014-07-16 05:27:15 +00:00
|
|
|
errors map[string]error
|
2014-06-06 23:40:48 +00:00
|
|
|
list []Simple
|
|
|
|
item Simple
|
|
|
|
deleted string
|
2014-08-06 03:10:48 +00:00
|
|
|
updated *Simple
|
|
|
|
created *Simple
|
2014-06-25 20:21:32 +00:00
|
|
|
|
2014-08-06 21:55:37 +00:00
|
|
|
// These are set when Watch is called
|
2014-10-30 16:55:17 +00:00
|
|
|
fakeWatch *watch.FakeWatcher
|
|
|
|
requestedLabelSelector labels.Selector
|
|
|
|
requestedFieldSelector labels.Selector
|
|
|
|
requestedResourceVersion string
|
|
|
|
requestedResourceNamespace string
|
2014-08-05 20:33:25 +00:00
|
|
|
|
2014-08-27 23:10:44 +00:00
|
|
|
// The id requested, and location to return for ResourceLocation
|
2014-08-25 21:36:15 +00:00
|
|
|
requestedResourceLocationID string
|
2014-08-27 23:10:44 +00:00
|
|
|
resourceLocation string
|
2014-10-20 20:25:08 +00:00
|
|
|
expectedResourceNamespace string
|
2014-08-25 21:36:15 +00:00
|
|
|
|
2014-06-26 17:51:29 +00:00
|
|
|
// If non-nil, called inside the WorkFunc when answering update, delete, create.
|
2014-07-28 13:15:50 +00:00
|
|
|
// obj receives the original input to the update, delete, or create call.
|
2014-09-08 04:14:18 +00:00
|
|
|
injectedFunction func(obj runtime.Object) (returnObj runtime.Object, err error)
|
2014-06-06 23:40:48 +00:00
|
|
|
}
|
|
|
|
|
2014-09-26 15:46:04 +00:00
|
|
|
func (storage *SimpleRESTStorage) List(ctx api.Context, label, field labels.Selector) (runtime.Object, error) {
|
2014-06-20 23:18:36 +00:00
|
|
|
result := &SimpleList{
|
2014-06-06 23:40:48 +00:00
|
|
|
Items: storage.list,
|
|
|
|
}
|
2014-07-16 05:27:15 +00:00
|
|
|
return result, storage.errors["list"]
|
2014-06-06 23:40:48 +00:00
|
|
|
}
|
|
|
|
|
2014-09-26 15:46:04 +00:00
|
|
|
func (storage *SimpleRESTStorage) Get(ctx api.Context, id string) (runtime.Object, error) {
|
2014-09-11 17:02:53 +00:00
|
|
|
return api.Scheme.CopyOrDie(&storage.item), storage.errors["get"]
|
2014-06-06 23:40:48 +00:00
|
|
|
}
|
|
|
|
|
2015-02-10 14:26:26 +00:00
|
|
|
func (storage *SimpleRESTStorage) Delete(ctx api.Context, id string) (runtime.Object, error) {
|
2014-06-06 23:40:48 +00:00
|
|
|
storage.deleted = id
|
2014-07-17 17:05:14 +00:00
|
|
|
if err := storage.errors["delete"]; err != nil {
|
|
|
|
return nil, err
|
2014-06-25 20:21:32 +00:00
|
|
|
}
|
2015-02-10 14:26:26 +00:00
|
|
|
var obj runtime.Object = &api.Status{Status: api.StatusSuccess}
|
|
|
|
var err error
|
|
|
|
if storage.injectedFunction != nil {
|
|
|
|
obj, err = storage.injectedFunction(&Simple{ObjectMeta: api.ObjectMeta{Name: id}})
|
|
|
|
}
|
|
|
|
return obj, err
|
2014-06-06 23:40:48 +00:00
|
|
|
}
|
|
|
|
|
2014-09-08 04:14:18 +00:00
|
|
|
func (storage *SimpleRESTStorage) New() runtime.Object {
|
2014-08-06 03:10:48 +00:00
|
|
|
return &Simple{}
|
2014-06-06 23:40:48 +00:00
|
|
|
}
|
|
|
|
|
2015-01-12 05:33:25 +00:00
|
|
|
func (storage *SimpleRESTStorage) NewList() runtime.Object {
|
|
|
|
return &SimpleList{}
|
|
|
|
}
|
|
|
|
|
2015-02-10 14:26:26 +00:00
|
|
|
func (storage *SimpleRESTStorage) Create(ctx api.Context, obj runtime.Object) (runtime.Object, error) {
|
2014-08-06 03:10:48 +00:00
|
|
|
storage.created = obj.(*Simple)
|
2014-07-17 17:05:14 +00:00
|
|
|
if err := storage.errors["create"]; err != nil {
|
|
|
|
return nil, err
|
2014-06-25 20:21:32 +00:00
|
|
|
}
|
2015-02-10 14:26:26 +00:00
|
|
|
var err error
|
|
|
|
if storage.injectedFunction != nil {
|
|
|
|
obj, err = storage.injectedFunction(obj)
|
|
|
|
}
|
|
|
|
return obj, err
|
2014-06-06 23:40:48 +00:00
|
|
|
}
|
|
|
|
|
2015-02-10 14:26:26 +00:00
|
|
|
func (storage *SimpleRESTStorage) Update(ctx api.Context, obj runtime.Object) (runtime.Object, bool, error) {
|
2014-08-06 03:10:48 +00:00
|
|
|
storage.updated = obj.(*Simple)
|
2014-07-17 17:05:14 +00:00
|
|
|
if err := storage.errors["update"]; err != nil {
|
2015-02-10 14:26:26 +00:00
|
|
|
return nil, false, err
|
2014-06-25 20:21:32 +00:00
|
|
|
}
|
2015-02-10 14:26:26 +00:00
|
|
|
var err error
|
|
|
|
if storage.injectedFunction != nil {
|
|
|
|
obj, err = storage.injectedFunction(obj)
|
|
|
|
}
|
|
|
|
return obj, false, err
|
2014-06-06 23:40:48 +00:00
|
|
|
}
|
|
|
|
|
2014-07-17 17:05:14 +00:00
|
|
|
// Implement ResourceWatcher.
|
2014-10-07 20:51:28 +00:00
|
|
|
func (storage *SimpleRESTStorage) Watch(ctx api.Context, label, field labels.Selector, resourceVersion string) (watch.Interface, error) {
|
2014-08-05 20:33:25 +00:00
|
|
|
storage.requestedLabelSelector = label
|
|
|
|
storage.requestedFieldSelector = field
|
|
|
|
storage.requestedResourceVersion = resourceVersion
|
2015-01-19 21:50:00 +00:00
|
|
|
storage.requestedResourceNamespace = api.NamespaceValue(ctx)
|
2014-08-06 21:55:37 +00:00
|
|
|
if err := storage.errors["watch"]; err != nil {
|
2014-07-17 17:05:14 +00:00
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
storage.fakeWatch = watch.NewFake()
|
|
|
|
return storage.fakeWatch, nil
|
|
|
|
}
|
|
|
|
|
2014-08-25 21:36:15 +00:00
|
|
|
// Implement Redirector.
|
2014-09-26 15:46:04 +00:00
|
|
|
func (storage *SimpleRESTStorage) ResourceLocation(ctx api.Context, id string) (string, error) {
|
2014-10-20 20:25:08 +00:00
|
|
|
// validate that the namespace context on the request matches the expected input
|
2015-01-19 21:50:00 +00:00
|
|
|
storage.requestedResourceNamespace = api.NamespaceValue(ctx)
|
2014-10-30 16:55:17 +00:00
|
|
|
if storage.expectedResourceNamespace != storage.requestedResourceNamespace {
|
|
|
|
return "", fmt.Errorf("Expected request namespace %s, but got namespace %s", storage.expectedResourceNamespace, storage.requestedResourceNamespace)
|
2014-10-20 20:25:08 +00:00
|
|
|
}
|
2014-08-25 21:36:15 +00:00
|
|
|
storage.requestedResourceLocationID = id
|
|
|
|
if err := storage.errors["resourceLocation"]; err != nil {
|
|
|
|
return "", err
|
|
|
|
}
|
2014-08-27 23:10:44 +00:00
|
|
|
return storage.resourceLocation, nil
|
2014-08-25 21:36:15 +00:00
|
|
|
}
|
|
|
|
|
2014-09-08 04:14:18 +00:00
|
|
|
func extractBody(response *http.Response, object runtime.Object) (string, error) {
|
2014-06-06 23:40:48 +00:00
|
|
|
defer response.Body.Close()
|
|
|
|
body, err := ioutil.ReadAll(response.Body)
|
|
|
|
if err != nil {
|
|
|
|
return string(body), err
|
|
|
|
}
|
2014-08-06 03:10:48 +00:00
|
|
|
err = codec.DecodeInto(body, object)
|
2014-06-06 23:40:48 +00:00
|
|
|
return string(body), err
|
|
|
|
}
|
|
|
|
|
2014-07-31 18:16:13 +00:00
|
|
|
func TestNotFound(t *testing.T) {
|
|
|
|
type T struct {
|
|
|
|
Method string
|
|
|
|
Path string
|
2014-11-11 07:11:45 +00:00
|
|
|
Status int
|
2014-07-31 18:16:13 +00:00
|
|
|
}
|
|
|
|
cases := map[string]T{
|
2014-11-11 07:11:45 +00:00
|
|
|
"PATCH method": {"PATCH", "/prefix/version/foo", http.StatusMethodNotAllowed},
|
|
|
|
"GET long prefix": {"GET", "/prefix/", http.StatusNotFound},
|
|
|
|
"GET missing storage": {"GET", "/prefix/version/blah", http.StatusNotFound},
|
|
|
|
"GET with extra segment": {"GET", "/prefix/version/foo/bar/baz", http.StatusNotFound},
|
|
|
|
"POST with extra segment": {"POST", "/prefix/version/foo/bar", http.StatusMethodNotAllowed},
|
|
|
|
"DELETE without extra segment": {"DELETE", "/prefix/version/foo", http.StatusMethodNotAllowed},
|
|
|
|
"DELETE with extra segment": {"DELETE", "/prefix/version/foo/bar/baz", http.StatusNotFound},
|
|
|
|
"PUT without extra segment": {"PUT", "/prefix/version/foo", http.StatusMethodNotAllowed},
|
|
|
|
"PUT with extra segment": {"PUT", "/prefix/version/foo/bar/baz", http.StatusNotFound},
|
|
|
|
"watch missing storage": {"GET", "/prefix/version/watch/", http.StatusNotFound},
|
2015-01-31 00:08:59 +00:00
|
|
|
"watch with bad method": {"POST", "/prefix/version/watch/foo/bar", http.StatusMethodNotAllowed},
|
2014-07-31 18:16:13 +00:00
|
|
|
}
|
2014-08-09 21:12:55 +00:00
|
|
|
handler := Handle(map[string]RESTStorage{
|
2014-07-31 18:16:13 +00:00
|
|
|
"foo": &SimpleRESTStorage{},
|
2015-01-29 22:46:54 +00:00
|
|
|
}, codec, "/prefix", testVersion, selfLinker, admissionControl, mapper)
|
2014-07-31 18:16:13 +00:00
|
|
|
server := httptest.NewServer(handler)
|
2014-10-31 01:15:44 +00:00
|
|
|
defer server.Close()
|
2014-07-31 18:16:13 +00:00
|
|
|
client := http.Client{}
|
|
|
|
for k, v := range cases {
|
|
|
|
request, err := http.NewRequest(v.Method, server.URL+v.Path, nil)
|
2014-08-04 00:01:15 +00:00
|
|
|
if err != nil {
|
2014-10-20 22:23:28 +00:00
|
|
|
t.Fatalf("unexpected error: %v", err)
|
2014-08-04 00:01:15 +00:00
|
|
|
}
|
|
|
|
|
2014-07-31 18:16:13 +00:00
|
|
|
response, err := client.Do(request)
|
2014-08-04 00:01:15 +00:00
|
|
|
if err != nil {
|
|
|
|
t.Errorf("unexpected error: %v", err)
|
|
|
|
}
|
|
|
|
|
2014-11-11 07:11:45 +00:00
|
|
|
if response.StatusCode != v.Status {
|
2014-11-20 12:42:48 +00:00
|
|
|
t.Errorf("Expected %d for %s (%s), Got %#v", v.Status, v.Method, k, response)
|
2015-01-29 22:46:54 +00:00
|
|
|
t.Errorf("MAPPER: %v", mapper)
|
2014-07-31 18:16:13 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-01-12 05:33:25 +00:00
|
|
|
type UnimplementedRESTStorage struct{}
|
|
|
|
|
|
|
|
func (UnimplementedRESTStorage) New() runtime.Object {
|
|
|
|
return &Simple{}
|
|
|
|
}
|
|
|
|
|
2015-01-30 20:43:53 +00:00
|
|
|
// TestUnimplementedRESTStorage ensures that if a RESTStorage does not implement a given
|
|
|
|
// method, that it is literally not registered with the server. In the past,
|
|
|
|
// we registered everything, and returned method not supported if it didn't support
|
|
|
|
// a verb. Now we literally do not register a storage if it does not implement anything.
|
|
|
|
// TODO: in future, we should update proxy/redirect
|
|
|
|
func TestUnimplementedRESTStorage(t *testing.T) {
|
2015-01-12 05:33:25 +00:00
|
|
|
type T struct {
|
2015-01-30 20:43:53 +00:00
|
|
|
Method string
|
|
|
|
Path string
|
|
|
|
ErrCode int
|
2015-01-12 05:33:25 +00:00
|
|
|
}
|
|
|
|
cases := map[string]T{
|
2015-01-31 00:08:59 +00:00
|
|
|
"GET object": {"GET", "/prefix/version/foo/bar", http.StatusNotFound},
|
|
|
|
"GET list": {"GET", "/prefix/version/foo", http.StatusNotFound},
|
|
|
|
"POST list": {"POST", "/prefix/version/foo", http.StatusNotFound},
|
|
|
|
"PUT object": {"PUT", "/prefix/version/foo/bar", http.StatusNotFound},
|
|
|
|
"DELETE object": {"DELETE", "/prefix/version/foo/bar", http.StatusNotFound},
|
|
|
|
"watch list": {"GET", "/prefix/version/watch/foo", http.StatusNotFound},
|
|
|
|
"watch object": {"GET", "/prefix/version/watch/foo/bar", http.StatusNotFound},
|
|
|
|
"proxy object": {"GET", "/prefix/version/proxy/foo/bar", http.StatusNotFound},
|
|
|
|
"redirect object": {"GET", "/prefix/version/redirect/foo/bar", http.StatusNotFound},
|
2015-01-12 05:33:25 +00:00
|
|
|
}
|
|
|
|
handler := Handle(map[string]RESTStorage{
|
|
|
|
"foo": UnimplementedRESTStorage{},
|
2015-01-29 22:46:54 +00:00
|
|
|
}, codec, "/prefix", testVersion, selfLinker, admissionControl, mapper)
|
2015-01-12 05:33:25 +00:00
|
|
|
server := httptest.NewServer(handler)
|
|
|
|
defer server.Close()
|
|
|
|
client := http.Client{}
|
|
|
|
for k, v := range cases {
|
|
|
|
request, err := http.NewRequest(v.Method, server.URL+v.Path, bytes.NewReader([]byte(`{"kind":"Simple","apiVersion":"version"}`)))
|
|
|
|
if err != nil {
|
|
|
|
t.Fatalf("unexpected error: %v", err)
|
|
|
|
}
|
|
|
|
|
|
|
|
response, err := client.Do(request)
|
|
|
|
if err != nil {
|
|
|
|
t.Fatalf("unexpected error: %v", err)
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
defer response.Body.Close()
|
|
|
|
data, _ := ioutil.ReadAll(response.Body)
|
2015-01-30 20:43:53 +00:00
|
|
|
if response.StatusCode != v.ErrCode {
|
2015-01-31 00:08:59 +00:00
|
|
|
t.Errorf("%s: expected %d for %s, Got %s", k, v.ErrCode, v.Method, string(data))
|
2015-01-12 05:33:25 +00:00
|
|
|
continue
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-07-31 18:16:13 +00:00
|
|
|
func TestVersion(t *testing.T) {
|
2015-01-29 22:46:54 +00:00
|
|
|
handler := Handle(map[string]RESTStorage{}, codec, "/prefix", testVersion, selfLinker, admissionControl, mapper)
|
2014-07-31 18:16:13 +00:00
|
|
|
server := httptest.NewServer(handler)
|
2014-10-31 01:15:44 +00:00
|
|
|
defer server.Close()
|
2014-07-31 18:16:13 +00:00
|
|
|
client := http.Client{}
|
|
|
|
|
|
|
|
request, err := http.NewRequest("GET", server.URL+"/version", nil)
|
2014-08-04 00:01:15 +00:00
|
|
|
if err != nil {
|
|
|
|
t.Errorf("unexpected error: %v", err)
|
|
|
|
}
|
|
|
|
|
2014-07-31 18:16:13 +00:00
|
|
|
response, err := client.Do(request)
|
2014-08-04 00:01:15 +00:00
|
|
|
if err != nil {
|
|
|
|
t.Errorf("unexpected error: %v", err)
|
|
|
|
}
|
|
|
|
|
2014-07-31 18:16:13 +00:00
|
|
|
var info version.Info
|
|
|
|
err = json.NewDecoder(response.Body).Decode(&info)
|
2014-08-04 00:01:15 +00:00
|
|
|
if err != nil {
|
|
|
|
t.Errorf("unexpected error: %v", err)
|
|
|
|
}
|
|
|
|
|
2014-07-31 18:16:13 +00:00
|
|
|
if !reflect.DeepEqual(version.Get(), info) {
|
|
|
|
t.Errorf("Expected %#v, Got %#v", version.Get(), info)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-06-06 23:40:48 +00:00
|
|
|
func TestSimpleList(t *testing.T) {
|
|
|
|
storage := map[string]RESTStorage{}
|
|
|
|
simpleStorage := SimpleRESTStorage{}
|
|
|
|
storage["simple"] = &simpleStorage
|
2014-09-26 00:20:28 +00:00
|
|
|
selfLinker := &setTestSelfLinker{
|
|
|
|
t: t,
|
2014-11-24 18:35:24 +00:00
|
|
|
namespace: "other",
|
|
|
|
expectedSet: "/prefix/version/simple?namespace=other",
|
2014-09-26 00:20:28 +00:00
|
|
|
}
|
2015-01-29 22:46:54 +00:00
|
|
|
handler := Handle(storage, codec, "/prefix", testVersion, selfLinker, admissionControl, mapper)
|
2014-06-06 23:40:48 +00:00
|
|
|
server := httptest.NewServer(handler)
|
2014-10-31 01:15:44 +00:00
|
|
|
defer server.Close()
|
2014-06-06 23:40:48 +00:00
|
|
|
|
|
|
|
resp, err := http.Get(server.URL + "/prefix/version/simple")
|
2014-08-04 00:01:15 +00:00
|
|
|
if err != nil {
|
|
|
|
t.Errorf("unexpected error: %v", err)
|
|
|
|
}
|
2014-06-06 23:40:48 +00:00
|
|
|
|
2014-07-16 05:27:15 +00:00
|
|
|
if resp.StatusCode != http.StatusOK {
|
|
|
|
t.Errorf("Unexpected status: %d, Expected: %d, %#v", resp.StatusCode, http.StatusOK, resp)
|
2014-06-06 23:40:48 +00:00
|
|
|
}
|
2014-09-26 00:20:28 +00:00
|
|
|
if !selfLinker.called {
|
|
|
|
t.Errorf("Never set self link")
|
|
|
|
}
|
2014-06-06 23:40:48 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
func TestErrorList(t *testing.T) {
|
|
|
|
storage := map[string]RESTStorage{}
|
|
|
|
simpleStorage := SimpleRESTStorage{
|
2014-07-16 05:27:15 +00:00
|
|
|
errors: map[string]error{"list": fmt.Errorf("test Error")},
|
2014-06-06 23:40:48 +00:00
|
|
|
}
|
|
|
|
storage["simple"] = &simpleStorage
|
2015-01-29 22:46:54 +00:00
|
|
|
handler := Handle(storage, codec, "/prefix", testVersion, selfLinker, admissionControl, mapper)
|
2014-06-06 23:40:48 +00:00
|
|
|
server := httptest.NewServer(handler)
|
2014-10-31 01:15:44 +00:00
|
|
|
defer server.Close()
|
2014-06-06 23:40:48 +00:00
|
|
|
|
|
|
|
resp, err := http.Get(server.URL + "/prefix/version/simple")
|
2014-08-04 00:01:15 +00:00
|
|
|
if err != nil {
|
|
|
|
t.Errorf("unexpected error: %v", err)
|
|
|
|
}
|
2014-06-06 23:40:48 +00:00
|
|
|
|
2014-07-16 05:27:15 +00:00
|
|
|
if resp.StatusCode != http.StatusInternalServerError {
|
2014-11-11 07:11:45 +00:00
|
|
|
t.Errorf("Unexpected status: %d, Expected: %d, %#v", resp.StatusCode, http.StatusInternalServerError, resp)
|
2014-06-06 23:40:48 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestNonEmptyList(t *testing.T) {
|
|
|
|
storage := map[string]RESTStorage{}
|
|
|
|
simpleStorage := SimpleRESTStorage{
|
|
|
|
list: []Simple{
|
2014-06-12 21:09:40 +00:00
|
|
|
{
|
2014-11-24 18:35:24 +00:00
|
|
|
TypeMeta: api.TypeMeta{Kind: "Simple"},
|
|
|
|
ObjectMeta: api.ObjectMeta{Namespace: "other"},
|
|
|
|
Other: "foo",
|
2014-06-06 23:40:48 +00:00
|
|
|
},
|
|
|
|
},
|
|
|
|
}
|
|
|
|
storage["simple"] = &simpleStorage
|
2015-01-29 22:46:54 +00:00
|
|
|
handler := Handle(storage, codec, "/prefix", testVersion, selfLinker, admissionControl, mapper)
|
2014-06-06 23:40:48 +00:00
|
|
|
server := httptest.NewServer(handler)
|
2014-10-31 01:15:44 +00:00
|
|
|
defer server.Close()
|
2014-06-06 23:40:48 +00:00
|
|
|
|
|
|
|
resp, err := http.Get(server.URL + "/prefix/version/simple")
|
2014-08-04 00:01:15 +00:00
|
|
|
if err != nil {
|
|
|
|
t.Errorf("unexpected error: %v", err)
|
|
|
|
}
|
2014-06-06 23:40:48 +00:00
|
|
|
|
2014-07-16 05:27:15 +00:00
|
|
|
if resp.StatusCode != http.StatusOK {
|
|
|
|
t.Errorf("Unexpected status: %d, Expected: %d, %#v", resp.StatusCode, http.StatusOK, resp)
|
2014-10-23 20:51:34 +00:00
|
|
|
body, _ := ioutil.ReadAll(resp.Body)
|
|
|
|
t.Logf("Data: %s", string(body))
|
2014-06-06 23:40:48 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
var listOut SimpleList
|
|
|
|
body, err := extractBody(resp, &listOut)
|
2014-08-04 00:01:15 +00:00
|
|
|
if err != nil {
|
|
|
|
t.Errorf("unexpected error: %v", err)
|
|
|
|
}
|
|
|
|
|
2014-06-06 23:40:48 +00:00
|
|
|
if len(listOut.Items) != 1 {
|
|
|
|
t.Errorf("Unexpected response: %#v", listOut)
|
2014-06-20 23:18:36 +00:00
|
|
|
return
|
2014-06-06 23:40:48 +00:00
|
|
|
}
|
2014-10-22 17:02:02 +00:00
|
|
|
if listOut.Items[0].Other != simpleStorage.list[0].Other {
|
2014-06-06 23:40:48 +00:00
|
|
|
t.Errorf("Unexpected data: %#v, %s", listOut.Items[0], string(body))
|
|
|
|
}
|
2014-11-24 18:35:24 +00:00
|
|
|
expectedSelfLink := "/prefix/version/simple?namespace=other"
|
|
|
|
if listOut.Items[0].ObjectMeta.SelfLink != expectedSelfLink {
|
|
|
|
t.Errorf("Unexpected data: %#v, %s", listOut.Items[0].ObjectMeta.SelfLink, expectedSelfLink)
|
|
|
|
}
|
2014-06-06 23:40:48 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
func TestGet(t *testing.T) {
|
|
|
|
storage := map[string]RESTStorage{}
|
|
|
|
simpleStorage := SimpleRESTStorage{
|
|
|
|
item: Simple{
|
2014-10-22 17:02:02 +00:00
|
|
|
Other: "foo",
|
2014-06-06 23:40:48 +00:00
|
|
|
},
|
|
|
|
}
|
2014-09-26 00:20:28 +00:00
|
|
|
selfLinker := &setTestSelfLinker{
|
|
|
|
t: t,
|
2015-02-09 14:47:13 +00:00
|
|
|
expectedSet: "/prefix/version/simple/id?namespace=default",
|
|
|
|
name: "id",
|
|
|
|
namespace: "default",
|
2014-09-26 00:20:28 +00:00
|
|
|
}
|
2014-06-06 23:40:48 +00:00
|
|
|
storage["simple"] = &simpleStorage
|
2015-01-29 22:46:54 +00:00
|
|
|
handler := Handle(storage, codec, "/prefix", testVersion, selfLinker, admissionControl, mapper)
|
2014-06-06 23:40:48 +00:00
|
|
|
server := httptest.NewServer(handler)
|
2014-10-31 01:15:44 +00:00
|
|
|
defer server.Close()
|
2014-06-06 23:40:48 +00:00
|
|
|
|
|
|
|
resp, err := http.Get(server.URL + "/prefix/version/simple/id")
|
2015-02-09 14:47:13 +00:00
|
|
|
if err != nil {
|
|
|
|
t.Fatalf("unexpected error: %v", err)
|
|
|
|
}
|
|
|
|
if resp.StatusCode != http.StatusOK {
|
|
|
|
t.Fatalf("unexpected response: %#v", resp)
|
|
|
|
}
|
2014-06-06 23:40:48 +00:00
|
|
|
var itemOut Simple
|
|
|
|
body, err := extractBody(resp, &itemOut)
|
2014-08-04 00:01:15 +00:00
|
|
|
if err != nil {
|
|
|
|
t.Errorf("unexpected error: %v", err)
|
|
|
|
}
|
|
|
|
|
2014-06-06 23:40:48 +00:00
|
|
|
if itemOut.Name != simpleStorage.item.Name {
|
|
|
|
t.Errorf("Unexpected data: %#v, expected %#v (%s)", itemOut, simpleStorage.item, string(body))
|
|
|
|
}
|
2014-09-26 00:20:28 +00:00
|
|
|
if !selfLinker.called {
|
|
|
|
t.Errorf("Never set self link")
|
|
|
|
}
|
2014-06-06 23:40:48 +00:00
|
|
|
}
|
|
|
|
|
2015-02-09 14:47:13 +00:00
|
|
|
func TestGetAlternateSelfLink(t *testing.T) {
|
|
|
|
storage := map[string]RESTStorage{}
|
|
|
|
simpleStorage := SimpleRESTStorage{
|
|
|
|
item: Simple{
|
|
|
|
Other: "foo",
|
|
|
|
},
|
|
|
|
}
|
|
|
|
selfLinker := &setTestSelfLinker{
|
|
|
|
t: t,
|
|
|
|
expectedSet: "/prefix/version/simple/id?namespace=test",
|
|
|
|
name: "id",
|
|
|
|
namespace: "test",
|
|
|
|
}
|
|
|
|
storage["simple"] = &simpleStorage
|
|
|
|
handler := Handle(storage, codec, "/prefix", testVersion, selfLinker, admissionControl, legacyNamespaceMapper)
|
|
|
|
server := httptest.NewServer(handler)
|
|
|
|
defer server.Close()
|
|
|
|
|
|
|
|
resp, err := http.Get(server.URL + "/prefix/version/simple/id?namespace=test")
|
|
|
|
if err != nil {
|
|
|
|
t.Fatalf("unexpected error: %v", err)
|
|
|
|
}
|
|
|
|
if resp.StatusCode != http.StatusOK {
|
|
|
|
t.Fatalf("unexpected response: %#v", resp)
|
|
|
|
}
|
|
|
|
var itemOut Simple
|
|
|
|
body, err := extractBody(resp, &itemOut)
|
|
|
|
if err != nil {
|
|
|
|
t.Fatalf("unexpected error: %v", err)
|
|
|
|
}
|
|
|
|
if itemOut.Name != simpleStorage.item.Name {
|
|
|
|
t.Errorf("Unexpected data: %#v, expected %#v (%s)", itemOut, simpleStorage.item, string(body))
|
|
|
|
}
|
|
|
|
if !selfLinker.called {
|
|
|
|
t.Errorf("Never set self link")
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestGetNamespaceSelfLink(t *testing.T) {
|
|
|
|
storage := map[string]RESTStorage{}
|
|
|
|
simpleStorage := SimpleRESTStorage{
|
|
|
|
item: Simple{
|
|
|
|
Other: "foo",
|
|
|
|
},
|
|
|
|
}
|
|
|
|
selfLinker := &setTestSelfLinker{
|
|
|
|
t: t,
|
|
|
|
expectedSet: "/prefix/version/namespaces/foo/simple/id",
|
|
|
|
name: "id",
|
|
|
|
namespace: "foo",
|
|
|
|
}
|
|
|
|
storage["simple"] = &simpleStorage
|
|
|
|
handler := Handle(storage, codec, "/prefix", testVersion, selfLinker, admissionControl, namespaceMapper)
|
|
|
|
server := httptest.NewServer(handler)
|
|
|
|
defer server.Close()
|
|
|
|
|
|
|
|
resp, err := http.Get(server.URL + "/prefix/version/namespaces/foo/simple/id")
|
|
|
|
if err != nil {
|
|
|
|
t.Fatalf("unexpected error: %v", err)
|
|
|
|
}
|
|
|
|
if resp.StatusCode != http.StatusOK {
|
|
|
|
t.Fatalf("unexpected response: %#v", resp)
|
|
|
|
}
|
|
|
|
var itemOut Simple
|
|
|
|
body, err := extractBody(resp, &itemOut)
|
|
|
|
if err != nil {
|
|
|
|
t.Fatalf("unexpected error: %v", err)
|
|
|
|
}
|
|
|
|
if itemOut.Name != simpleStorage.item.Name {
|
|
|
|
t.Errorf("Unexpected data: %#v, expected %#v (%s)", itemOut, simpleStorage.item, string(body))
|
|
|
|
}
|
|
|
|
if !selfLinker.called {
|
|
|
|
t.Errorf("Never set self link")
|
|
|
|
}
|
|
|
|
}
|
2014-07-16 05:27:15 +00:00
|
|
|
func TestGetMissing(t *testing.T) {
|
|
|
|
storage := map[string]RESTStorage{}
|
|
|
|
simpleStorage := SimpleRESTStorage{
|
2014-09-03 21:16:00 +00:00
|
|
|
errors: map[string]error{"get": apierrs.NewNotFound("simple", "id")},
|
2014-07-16 05:27:15 +00:00
|
|
|
}
|
|
|
|
storage["simple"] = &simpleStorage
|
2015-01-29 22:46:54 +00:00
|
|
|
handler := Handle(storage, codec, "/prefix", testVersion, selfLinker, admissionControl, mapper)
|
2014-07-16 05:27:15 +00:00
|
|
|
server := httptest.NewServer(handler)
|
2014-10-31 01:15:44 +00:00
|
|
|
defer server.Close()
|
2014-07-16 05:27:15 +00:00
|
|
|
|
|
|
|
resp, err := http.Get(server.URL + "/prefix/version/simple/id")
|
2014-08-04 00:01:15 +00:00
|
|
|
if err != nil {
|
|
|
|
t.Errorf("unexpected error: %v", err)
|
|
|
|
}
|
|
|
|
|
2014-07-16 05:27:15 +00:00
|
|
|
if resp.StatusCode != http.StatusNotFound {
|
|
|
|
t.Errorf("Unexpected response %#v", resp)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-06-06 23:40:48 +00:00
|
|
|
func TestDelete(t *testing.T) {
|
|
|
|
storage := map[string]RESTStorage{}
|
|
|
|
simpleStorage := SimpleRESTStorage{}
|
|
|
|
ID := "id"
|
|
|
|
storage["simple"] = &simpleStorage
|
2015-01-29 22:46:54 +00:00
|
|
|
handler := Handle(storage, codec, "/prefix", testVersion, selfLinker, admissionControl, mapper)
|
2014-06-06 23:40:48 +00:00
|
|
|
server := httptest.NewServer(handler)
|
2014-10-31 01:15:44 +00:00
|
|
|
defer server.Close()
|
2014-06-06 23:40:48 +00:00
|
|
|
|
|
|
|
client := http.Client{}
|
|
|
|
request, err := http.NewRequest("DELETE", server.URL+"/prefix/version/simple/"+ID, nil)
|
2015-02-09 14:47:13 +00:00
|
|
|
res, err := client.Do(request)
|
2014-08-04 00:01:15 +00:00
|
|
|
if err != nil {
|
2015-02-09 14:47:13 +00:00
|
|
|
t.Fatalf("unexpected error: %v", err)
|
|
|
|
}
|
|
|
|
if res.StatusCode != http.StatusOK {
|
|
|
|
t.Errorf("unexpected response: %#v", res)
|
2014-08-04 00:01:15 +00:00
|
|
|
}
|
2014-06-06 23:40:48 +00:00
|
|
|
if simpleStorage.deleted != ID {
|
2014-07-18 19:03:22 +00:00
|
|
|
t.Errorf("Unexpected delete: %s, expected %s", simpleStorage.deleted, ID)
|
2014-06-06 23:40:48 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-01-06 20:16:13 +00:00
|
|
|
func TestDeleteInvokesAdmissionControl(t *testing.T) {
|
|
|
|
storage := map[string]RESTStorage{}
|
|
|
|
simpleStorage := SimpleRESTStorage{}
|
|
|
|
ID := "id"
|
|
|
|
storage["simple"] = &simpleStorage
|
2015-01-29 22:46:54 +00:00
|
|
|
handler := Handle(storage, codec, "/prefix", testVersion, selfLinker, deny.NewAlwaysDeny(), mapper)
|
2015-01-06 20:16:13 +00:00
|
|
|
server := httptest.NewServer(handler)
|
|
|
|
defer server.Close()
|
|
|
|
|
|
|
|
client := http.Client{}
|
|
|
|
request, err := http.NewRequest("DELETE", server.URL+"/prefix/version/simple/"+ID, nil)
|
|
|
|
response, err := client.Do(request)
|
|
|
|
if err != nil {
|
|
|
|
t.Errorf("unexpected error: %v", err)
|
|
|
|
}
|
2015-01-07 19:33:21 +00:00
|
|
|
if response.StatusCode != http.StatusForbidden {
|
2015-01-06 20:16:13 +00:00
|
|
|
t.Errorf("Unexpected response %#v", response)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-07-16 05:27:15 +00:00
|
|
|
func TestDeleteMissing(t *testing.T) {
|
|
|
|
storage := map[string]RESTStorage{}
|
|
|
|
ID := "id"
|
|
|
|
simpleStorage := SimpleRESTStorage{
|
2014-09-03 21:16:00 +00:00
|
|
|
errors: map[string]error{"delete": apierrs.NewNotFound("simple", ID)},
|
2014-07-16 05:27:15 +00:00
|
|
|
}
|
|
|
|
storage["simple"] = &simpleStorage
|
2015-01-29 22:46:54 +00:00
|
|
|
handler := Handle(storage, codec, "/prefix", testVersion, selfLinker, admissionControl, mapper)
|
2014-07-16 05:27:15 +00:00
|
|
|
server := httptest.NewServer(handler)
|
2014-10-31 01:15:44 +00:00
|
|
|
defer server.Close()
|
2014-07-16 05:27:15 +00:00
|
|
|
|
|
|
|
client := http.Client{}
|
|
|
|
request, err := http.NewRequest("DELETE", server.URL+"/prefix/version/simple/"+ID, nil)
|
|
|
|
response, err := client.Do(request)
|
2014-08-04 00:01:15 +00:00
|
|
|
if err != nil {
|
|
|
|
t.Errorf("unexpected error: %v", err)
|
|
|
|
}
|
|
|
|
|
2014-07-16 05:27:15 +00:00
|
|
|
if response.StatusCode != http.StatusNotFound {
|
|
|
|
t.Errorf("Unexpected response %#v", response)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-06-06 23:40:48 +00:00
|
|
|
func TestUpdate(t *testing.T) {
|
|
|
|
storage := map[string]RESTStorage{}
|
|
|
|
simpleStorage := SimpleRESTStorage{}
|
|
|
|
ID := "id"
|
|
|
|
storage["simple"] = &simpleStorage
|
2014-09-26 00:20:28 +00:00
|
|
|
selfLinker := &setTestSelfLinker{
|
|
|
|
t: t,
|
2015-02-09 14:47:13 +00:00
|
|
|
expectedSet: "/prefix/version/simple/" + ID + "?namespace=default",
|
|
|
|
name: ID,
|
|
|
|
namespace: api.NamespaceDefault,
|
2014-09-26 00:20:28 +00:00
|
|
|
}
|
2015-01-29 22:46:54 +00:00
|
|
|
handler := Handle(storage, codec, "/prefix", testVersion, selfLinker, admissionControl, mapper)
|
2014-06-06 23:40:48 +00:00
|
|
|
server := httptest.NewServer(handler)
|
2014-10-31 01:15:44 +00:00
|
|
|
defer server.Close()
|
2014-06-06 23:40:48 +00:00
|
|
|
|
2014-09-08 04:14:18 +00:00
|
|
|
item := &Simple{
|
2015-02-09 14:47:13 +00:00
|
|
|
ObjectMeta: api.ObjectMeta{
|
|
|
|
Name: ID,
|
|
|
|
Namespace: "", // update should allow the client to send an empty namespace
|
|
|
|
},
|
2014-10-22 17:02:02 +00:00
|
|
|
Other: "bar",
|
2014-06-06 23:40:48 +00:00
|
|
|
}
|
2014-08-06 03:10:48 +00:00
|
|
|
body, err := codec.Encode(item)
|
2014-08-04 00:01:15 +00:00
|
|
|
if err != nil {
|
2014-11-11 07:11:45 +00:00
|
|
|
// The following cases will fail, so die now
|
|
|
|
t.Fatalf("unexpected error: %v", err)
|
2014-08-04 00:01:15 +00:00
|
|
|
}
|
|
|
|
|
2014-06-06 23:40:48 +00:00
|
|
|
client := http.Client{}
|
|
|
|
request, err := http.NewRequest("PUT", server.URL+"/prefix/version/simple/"+ID, bytes.NewReader(body))
|
|
|
|
_, err = client.Do(request)
|
2014-08-04 00:01:15 +00:00
|
|
|
if err != nil {
|
|
|
|
t.Errorf("unexpected error: %v", err)
|
|
|
|
}
|
|
|
|
|
2014-11-11 07:11:45 +00:00
|
|
|
if simpleStorage.updated == nil || simpleStorage.updated.Name != item.Name {
|
2014-06-06 23:40:48 +00:00
|
|
|
t.Errorf("Unexpected update value %#v, expected %#v.", simpleStorage.updated, item)
|
|
|
|
}
|
2014-09-26 00:20:28 +00:00
|
|
|
if !selfLinker.called {
|
|
|
|
t.Errorf("Never set self link")
|
|
|
|
}
|
2014-06-06 23:40:48 +00:00
|
|
|
}
|
|
|
|
|
2015-01-06 20:16:13 +00:00
|
|
|
func TestUpdateInvokesAdmissionControl(t *testing.T) {
|
|
|
|
storage := map[string]RESTStorage{}
|
|
|
|
simpleStorage := SimpleRESTStorage{}
|
|
|
|
ID := "id"
|
|
|
|
storage["simple"] = &simpleStorage
|
2015-01-29 22:46:54 +00:00
|
|
|
handler := Handle(storage, codec, "/prefix", testVersion, selfLinker, deny.NewAlwaysDeny(), mapper)
|
2015-01-06 20:16:13 +00:00
|
|
|
server := httptest.NewServer(handler)
|
|
|
|
defer server.Close()
|
|
|
|
|
|
|
|
item := &Simple{
|
2015-02-09 14:47:13 +00:00
|
|
|
ObjectMeta: api.ObjectMeta{
|
|
|
|
Name: ID,
|
|
|
|
Namespace: api.NamespaceDefault,
|
|
|
|
},
|
2015-01-06 20:16:13 +00:00
|
|
|
Other: "bar",
|
|
|
|
}
|
|
|
|
body, err := codec.Encode(item)
|
|
|
|
if err != nil {
|
|
|
|
// The following cases will fail, so die now
|
|
|
|
t.Fatalf("unexpected error: %v", err)
|
|
|
|
}
|
|
|
|
|
|
|
|
client := http.Client{}
|
|
|
|
request, err := http.NewRequest("PUT", server.URL+"/prefix/version/simple/"+ID, bytes.NewReader(body))
|
|
|
|
response, err := client.Do(request)
|
|
|
|
if err != nil {
|
|
|
|
t.Errorf("unexpected error: %v", err)
|
|
|
|
}
|
2015-01-07 19:33:21 +00:00
|
|
|
if response.StatusCode != http.StatusForbidden {
|
2015-01-06 20:16:13 +00:00
|
|
|
t.Errorf("Unexpected response %#v", response)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-02-09 14:47:13 +00:00
|
|
|
func TestUpdateRequiresMatchingName(t *testing.T) {
|
|
|
|
storage := map[string]RESTStorage{}
|
|
|
|
simpleStorage := SimpleRESTStorage{}
|
|
|
|
ID := "id"
|
|
|
|
storage["simple"] = &simpleStorage
|
|
|
|
handler := Handle(storage, codec, "/prefix", testVersion, selfLinker, deny.NewAlwaysDeny(), mapper)
|
|
|
|
server := httptest.NewServer(handler)
|
|
|
|
defer server.Close()
|
|
|
|
|
|
|
|
item := &Simple{
|
|
|
|
Other: "bar",
|
|
|
|
}
|
|
|
|
body, err := codec.Encode(item)
|
|
|
|
if err != nil {
|
|
|
|
// The following cases will fail, so die now
|
|
|
|
t.Fatalf("unexpected error: %v", err)
|
|
|
|
}
|
|
|
|
|
|
|
|
client := http.Client{}
|
|
|
|
request, err := http.NewRequest("PUT", server.URL+"/prefix/version/simple/"+ID, bytes.NewReader(body))
|
|
|
|
response, err := client.Do(request)
|
|
|
|
if err != nil {
|
|
|
|
t.Errorf("unexpected error: %v", err)
|
|
|
|
}
|
|
|
|
if response.StatusCode != http.StatusBadRequest {
|
|
|
|
t.Errorf("Unexpected response %#v", response)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestUpdateAllowsMissingNamespace(t *testing.T) {
|
|
|
|
storage := map[string]RESTStorage{}
|
|
|
|
simpleStorage := SimpleRESTStorage{}
|
|
|
|
ID := "id"
|
|
|
|
storage["simple"] = &simpleStorage
|
|
|
|
handler := Handle(storage, codec, "/prefix", testVersion, selfLinker, admissionControl, mapper)
|
|
|
|
server := httptest.NewServer(handler)
|
|
|
|
defer server.Close()
|
|
|
|
|
|
|
|
item := &Simple{
|
|
|
|
ObjectMeta: api.ObjectMeta{
|
|
|
|
Name: ID,
|
|
|
|
},
|
|
|
|
Other: "bar",
|
|
|
|
}
|
|
|
|
body, err := codec.Encode(item)
|
|
|
|
if err != nil {
|
|
|
|
// The following cases will fail, so die now
|
|
|
|
t.Fatalf("unexpected error: %v", err)
|
|
|
|
}
|
|
|
|
|
|
|
|
client := http.Client{}
|
|
|
|
request, err := http.NewRequest("PUT", server.URL+"/prefix/version/simple/"+ID, bytes.NewReader(body))
|
|
|
|
response, err := client.Do(request)
|
|
|
|
if err != nil {
|
|
|
|
t.Errorf("unexpected error: %v", err)
|
|
|
|
}
|
|
|
|
if response.StatusCode != http.StatusOK {
|
|
|
|
t.Errorf("Unexpected response %#v", response)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestUpdatePreventsMismatchedNamespace(t *testing.T) {
|
|
|
|
storage := map[string]RESTStorage{}
|
|
|
|
simpleStorage := SimpleRESTStorage{}
|
|
|
|
ID := "id"
|
|
|
|
storage["simple"] = &simpleStorage
|
|
|
|
handler := Handle(storage, codec, "/prefix", testVersion, selfLinker, admissionControl, mapper)
|
|
|
|
server := httptest.NewServer(handler)
|
|
|
|
defer server.Close()
|
|
|
|
|
|
|
|
item := &Simple{
|
|
|
|
ObjectMeta: api.ObjectMeta{
|
|
|
|
Name: ID,
|
|
|
|
Namespace: "other",
|
|
|
|
},
|
|
|
|
Other: "bar",
|
|
|
|
}
|
|
|
|
body, err := codec.Encode(item)
|
|
|
|
if err != nil {
|
|
|
|
// The following cases will fail, so die now
|
|
|
|
t.Fatalf("unexpected error: %v", err)
|
|
|
|
}
|
|
|
|
|
|
|
|
client := http.Client{}
|
|
|
|
request, err := http.NewRequest("PUT", server.URL+"/prefix/version/simple/"+ID, bytes.NewReader(body))
|
|
|
|
response, err := client.Do(request)
|
|
|
|
if err != nil {
|
|
|
|
t.Errorf("unexpected error: %v", err)
|
|
|
|
}
|
|
|
|
if response.StatusCode != http.StatusBadRequest {
|
|
|
|
t.Errorf("Unexpected response %#v", response)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-07-16 05:27:15 +00:00
|
|
|
func TestUpdateMissing(t *testing.T) {
|
|
|
|
storage := map[string]RESTStorage{}
|
|
|
|
ID := "id"
|
|
|
|
simpleStorage := SimpleRESTStorage{
|
2014-09-03 21:16:00 +00:00
|
|
|
errors: map[string]error{"update": apierrs.NewNotFound("simple", ID)},
|
2014-07-16 05:27:15 +00:00
|
|
|
}
|
|
|
|
storage["simple"] = &simpleStorage
|
2015-01-29 22:46:54 +00:00
|
|
|
handler := Handle(storage, codec, "/prefix", testVersion, selfLinker, admissionControl, mapper)
|
2014-07-16 05:27:15 +00:00
|
|
|
server := httptest.NewServer(handler)
|
2014-10-31 01:15:44 +00:00
|
|
|
defer server.Close()
|
2014-07-16 05:27:15 +00:00
|
|
|
|
2014-09-08 04:14:18 +00:00
|
|
|
item := &Simple{
|
2015-02-09 14:47:13 +00:00
|
|
|
ObjectMeta: api.ObjectMeta{
|
|
|
|
Name: ID,
|
|
|
|
Namespace: api.NamespaceDefault,
|
|
|
|
},
|
2014-10-22 17:02:02 +00:00
|
|
|
Other: "bar",
|
2014-07-16 05:27:15 +00:00
|
|
|
}
|
2014-08-06 03:10:48 +00:00
|
|
|
body, err := codec.Encode(item)
|
2014-08-04 00:01:15 +00:00
|
|
|
if err != nil {
|
|
|
|
t.Errorf("unexpected error: %v", err)
|
|
|
|
}
|
|
|
|
|
2014-07-16 05:27:15 +00:00
|
|
|
client := http.Client{}
|
|
|
|
request, err := http.NewRequest("PUT", server.URL+"/prefix/version/simple/"+ID, bytes.NewReader(body))
|
|
|
|
response, err := client.Do(request)
|
2014-08-04 00:01:15 +00:00
|
|
|
if err != nil {
|
|
|
|
t.Errorf("unexpected error: %v", err)
|
|
|
|
}
|
2014-07-16 05:27:15 +00:00
|
|
|
if response.StatusCode != http.StatusNotFound {
|
|
|
|
t.Errorf("Unexpected response %#v", response)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestCreateNotFound(t *testing.T) {
|
2014-08-09 21:12:55 +00:00
|
|
|
handler := Handle(map[string]RESTStorage{
|
2014-07-31 18:16:13 +00:00
|
|
|
"simple": &SimpleRESTStorage{
|
|
|
|
// storage.Create can fail with not found error in theory.
|
|
|
|
// See https://github.com/GoogleCloudPlatform/kubernetes/pull/486#discussion_r15037092.
|
2014-09-03 21:16:00 +00:00
|
|
|
errors: map[string]error{"create": apierrs.NewNotFound("simple", "id")},
|
2014-07-31 18:16:13 +00:00
|
|
|
},
|
2015-01-29 22:46:54 +00:00
|
|
|
}, codec, "/prefix", testVersion, selfLinker, admissionControl, mapper)
|
2014-07-16 05:27:15 +00:00
|
|
|
server := httptest.NewServer(handler)
|
2014-10-31 01:15:44 +00:00
|
|
|
defer server.Close()
|
2014-07-16 05:27:15 +00:00
|
|
|
client := http.Client{}
|
|
|
|
|
2014-10-22 17:02:02 +00:00
|
|
|
simple := &Simple{Other: "foo"}
|
2014-08-06 03:10:48 +00:00
|
|
|
data, _ := codec.Encode(simple)
|
2014-07-31 18:16:13 +00:00
|
|
|
request, err := http.NewRequest("POST", server.URL+"/prefix/version/simple", bytes.NewBuffer(data))
|
2014-08-04 00:01:15 +00:00
|
|
|
if err != nil {
|
|
|
|
t.Errorf("unexpected error: %v", err)
|
|
|
|
}
|
|
|
|
|
2014-07-16 05:27:15 +00:00
|
|
|
response, err := client.Do(request)
|
2014-08-04 00:01:15 +00:00
|
|
|
if err != nil {
|
|
|
|
t.Errorf("unexpected error: %v", err)
|
|
|
|
}
|
|
|
|
|
2014-07-16 05:27:15 +00:00
|
|
|
if response.StatusCode != http.StatusNotFound {
|
|
|
|
t.Errorf("Unexpected response %#v", response)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-06-25 20:21:32 +00:00
|
|
|
func TestParseTimeout(t *testing.T) {
|
|
|
|
if d := parseTimeout(""); d != 30*time.Second {
|
|
|
|
t.Errorf("blank timeout produces %v", d)
|
|
|
|
}
|
|
|
|
if d := parseTimeout("not a timeout"); d != 30*time.Second {
|
|
|
|
t.Errorf("bad timeout produces %v", d)
|
|
|
|
}
|
|
|
|
if d := parseTimeout("10s"); d != 10*time.Second {
|
|
|
|
t.Errorf("10s timeout produced: %v", d)
|
2014-06-06 23:40:48 +00:00
|
|
|
}
|
|
|
|
}
|
2014-06-19 04:04:11 +00:00
|
|
|
|
2014-09-26 00:20:28 +00:00
|
|
|
type setTestSelfLinker struct {
|
|
|
|
t *testing.T
|
|
|
|
expectedSet string
|
2014-10-23 02:54:34 +00:00
|
|
|
name string
|
2014-11-24 18:35:24 +00:00
|
|
|
namespace string
|
2014-09-26 00:20:28 +00:00
|
|
|
called bool
|
|
|
|
}
|
|
|
|
|
2014-11-24 18:35:24 +00:00
|
|
|
func (s *setTestSelfLinker) Namespace(runtime.Object) (string, error) { return s.namespace, nil }
|
|
|
|
func (s *setTestSelfLinker) Name(runtime.Object) (string, error) { return s.name, nil }
|
|
|
|
func (*setTestSelfLinker) SelfLink(runtime.Object) (string, error) { return "", nil }
|
2014-09-26 00:20:28 +00:00
|
|
|
func (s *setTestSelfLinker) SetSelfLink(obj runtime.Object, selfLink string) error {
|
|
|
|
if e, a := s.expectedSet, selfLink; e != a {
|
|
|
|
s.t.Errorf("expected '%v', got '%v'", e, a)
|
|
|
|
}
|
|
|
|
s.called = true
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2015-01-22 05:20:57 +00:00
|
|
|
func TestCreate(t *testing.T) {
|
2014-06-19 04:04:11 +00:00
|
|
|
storage := SimpleRESTStorage{
|
2014-09-08 04:14:18 +00:00
|
|
|
injectedFunction: func(obj runtime.Object) (runtime.Object, error) {
|
2014-07-31 18:16:13 +00:00
|
|
|
time.Sleep(5 * time.Millisecond)
|
2014-06-25 20:21:32 +00:00
|
|
|
return obj, nil
|
|
|
|
},
|
2014-06-19 04:04:11 +00:00
|
|
|
}
|
2014-09-26 00:20:28 +00:00
|
|
|
selfLinker := &setTestSelfLinker{
|
|
|
|
t: t,
|
2014-10-23 02:54:34 +00:00
|
|
|
name: "bar",
|
2014-11-24 18:35:24 +00:00
|
|
|
namespace: "other",
|
2015-01-29 22:46:54 +00:00
|
|
|
expectedSet: "/prefix/version/foo/bar?namespace=other",
|
2014-09-26 00:20:28 +00:00
|
|
|
}
|
2014-08-09 21:12:55 +00:00
|
|
|
handler := Handle(map[string]RESTStorage{
|
2014-06-19 04:04:11 +00:00
|
|
|
"foo": &storage,
|
2015-01-29 22:46:54 +00:00
|
|
|
}, codec, "/prefix", testVersion, selfLinker, admissionControl, mapper)
|
2014-06-19 04:04:11 +00:00
|
|
|
server := httptest.NewServer(handler)
|
2014-10-31 01:15:44 +00:00
|
|
|
defer server.Close()
|
2014-06-19 04:04:11 +00:00
|
|
|
client := http.Client{}
|
|
|
|
|
2014-09-08 04:14:18 +00:00
|
|
|
simple := &Simple{
|
2014-10-22 17:02:02 +00:00
|
|
|
Other: "bar",
|
2014-07-16 21:30:28 +00:00
|
|
|
}
|
2014-08-06 03:10:48 +00:00
|
|
|
data, _ := codec.Encode(simple)
|
2015-01-29 22:46:54 +00:00
|
|
|
request, err := http.NewRequest("POST", server.URL+"/prefix/version/foo?namespace=other", bytes.NewBuffer(data))
|
2014-08-04 00:01:15 +00:00
|
|
|
if err != nil {
|
|
|
|
t.Errorf("unexpected error: %v", err)
|
|
|
|
}
|
|
|
|
|
2014-06-19 04:04:11 +00:00
|
|
|
wg := sync.WaitGroup{}
|
|
|
|
wg.Add(1)
|
|
|
|
var response *http.Response
|
|
|
|
go func() {
|
|
|
|
response, err = client.Do(request)
|
|
|
|
wg.Done()
|
|
|
|
}()
|
|
|
|
wg.Wait()
|
2014-08-04 00:01:15 +00:00
|
|
|
if err != nil {
|
|
|
|
t.Errorf("unexpected error: %v", err)
|
|
|
|
}
|
|
|
|
|
2014-06-19 04:04:11 +00:00
|
|
|
var itemOut Simple
|
|
|
|
body, err := extractBody(response, &itemOut)
|
2014-08-04 00:01:15 +00:00
|
|
|
if err != nil {
|
|
|
|
t.Errorf("unexpected error: %v", err)
|
|
|
|
}
|
|
|
|
|
2014-09-08 04:14:18 +00:00
|
|
|
if !reflect.DeepEqual(&itemOut, simple) {
|
2014-06-19 04:04:11 +00:00
|
|
|
t.Errorf("Unexpected data: %#v, expected %#v (%s)", itemOut, simple, string(body))
|
|
|
|
}
|
2015-02-10 14:26:26 +00:00
|
|
|
if response.StatusCode != http.StatusCreated {
|
2014-06-25 20:21:32 +00:00
|
|
|
t.Errorf("Unexpected status: %d, Expected: %d, %#v", response.StatusCode, http.StatusOK, response)
|
|
|
|
}
|
2014-09-26 00:20:28 +00:00
|
|
|
if !selfLinker.called {
|
|
|
|
t.Errorf("Never set self link")
|
|
|
|
}
|
2014-06-19 04:04:11 +00:00
|
|
|
}
|
|
|
|
|
2015-01-22 05:20:57 +00:00
|
|
|
func TestCreateInvokesAdmissionControl(t *testing.T) {
|
|
|
|
storage := SimpleRESTStorage{
|
|
|
|
injectedFunction: func(obj runtime.Object) (runtime.Object, error) {
|
|
|
|
time.Sleep(5 * time.Millisecond)
|
|
|
|
return obj, nil
|
|
|
|
},
|
|
|
|
}
|
|
|
|
selfLinker := &setTestSelfLinker{
|
|
|
|
t: t,
|
|
|
|
name: "bar",
|
|
|
|
namespace: "other",
|
2015-01-29 22:46:54 +00:00
|
|
|
expectedSet: "/prefix/version/foo/bar?namespace=other",
|
2015-01-22 05:20:57 +00:00
|
|
|
}
|
|
|
|
handler := Handle(map[string]RESTStorage{
|
|
|
|
"foo": &storage,
|
2015-01-29 22:46:54 +00:00
|
|
|
}, codec, "/prefix", testVersion, selfLinker, deny.NewAlwaysDeny(), mapper)
|
2015-01-22 05:20:57 +00:00
|
|
|
server := httptest.NewServer(handler)
|
|
|
|
defer server.Close()
|
|
|
|
client := http.Client{}
|
|
|
|
|
|
|
|
simple := &Simple{
|
|
|
|
Other: "bar",
|
|
|
|
}
|
|
|
|
data, _ := codec.Encode(simple)
|
2015-01-29 22:46:54 +00:00
|
|
|
request, err := http.NewRequest("POST", server.URL+"/prefix/version/foo?namespace=other", bytes.NewBuffer(data))
|
2015-01-22 05:20:57 +00:00
|
|
|
if err != nil {
|
|
|
|
t.Errorf("unexpected error: %v", err)
|
|
|
|
}
|
|
|
|
|
|
|
|
wg := sync.WaitGroup{}
|
|
|
|
wg.Add(1)
|
|
|
|
var response *http.Response
|
|
|
|
go func() {
|
|
|
|
response, err = client.Do(request)
|
|
|
|
wg.Done()
|
|
|
|
}()
|
|
|
|
wg.Wait()
|
|
|
|
if err != nil {
|
|
|
|
t.Errorf("unexpected error: %v", err)
|
|
|
|
}
|
|
|
|
if response.StatusCode != http.StatusForbidden {
|
|
|
|
t.Errorf("Unexpected status: %d, Expected: %d, %#v", response.StatusCode, http.StatusForbidden, response)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-07-31 18:16:13 +00:00
|
|
|
func expectApiStatus(t *testing.T, method, url string, data []byte, code int) *api.Status {
|
|
|
|
client := http.Client{}
|
|
|
|
request, err := http.NewRequest(method, url, bytes.NewBuffer(data))
|
|
|
|
if err != nil {
|
|
|
|
t.Fatalf("unexpected error %#v", err)
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
response, err := client.Do(request)
|
|
|
|
if err != nil {
|
2014-07-31 18:26:34 +00:00
|
|
|
t.Fatalf("unexpected error on %s %s: %v", method, url, err)
|
2014-07-31 18:16:13 +00:00
|
|
|
return nil
|
|
|
|
}
|
|
|
|
var status api.Status
|
|
|
|
_, err = extractBody(response, &status)
|
|
|
|
if err != nil {
|
2014-07-31 18:26:34 +00:00
|
|
|
t.Fatalf("unexpected error on %s %s: %v", method, url, err)
|
2014-07-31 18:16:13 +00:00
|
|
|
return nil
|
|
|
|
}
|
|
|
|
if code != response.StatusCode {
|
2014-07-31 18:26:34 +00:00
|
|
|
t.Fatalf("Expected %s %s to return %d, Got %d", method, url, code, response.StatusCode)
|
2014-07-31 18:16:13 +00:00
|
|
|
}
|
|
|
|
return &status
|
|
|
|
}
|
|
|
|
|
2015-01-22 05:20:57 +00:00
|
|
|
func TestDelayReturnsError(t *testing.T) {
|
2014-07-31 18:16:13 +00:00
|
|
|
storage := SimpleRESTStorage{
|
2014-09-08 04:14:18 +00:00
|
|
|
injectedFunction: func(obj runtime.Object) (runtime.Object, error) {
|
2014-09-03 21:16:00 +00:00
|
|
|
return nil, apierrs.NewAlreadyExists("foo", "bar")
|
2014-07-31 18:16:13 +00:00
|
|
|
},
|
|
|
|
}
|
2015-01-29 22:46:54 +00:00
|
|
|
handler := Handle(map[string]RESTStorage{"foo": &storage}, codec, "/prefix", testVersion, selfLinker, admissionControl, mapper)
|
2014-07-31 18:16:13 +00:00
|
|
|
server := httptest.NewServer(handler)
|
2014-10-31 01:15:44 +00:00
|
|
|
defer server.Close()
|
2014-07-31 18:16:13 +00:00
|
|
|
|
2014-07-31 18:26:34 +00:00
|
|
|
status := expectApiStatus(t, "DELETE", fmt.Sprintf("%s/prefix/version/foo/bar", server.URL), nil, http.StatusConflict)
|
2014-08-26 17:36:09 +00:00
|
|
|
if status.Status != api.StatusFailure || status.Message == "" || status.Details == nil || status.Reason != api.StatusReasonAlreadyExists {
|
2014-07-31 18:16:13 +00:00
|
|
|
t.Errorf("Unexpected status %#v", status)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-09-08 04:14:18 +00:00
|
|
|
type UnregisteredAPIObject struct {
|
|
|
|
Value string
|
|
|
|
}
|
|
|
|
|
|
|
|
func (*UnregisteredAPIObject) IsAnAPIObject() {}
|
|
|
|
|
2014-07-31 18:16:13 +00:00
|
|
|
func TestWriteJSONDecodeError(t *testing.T) {
|
|
|
|
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) {
|
2014-11-11 07:11:45 +00:00
|
|
|
writeJSON(http.StatusOK, codec, &UnregisteredAPIObject{"Undecodable"}, w)
|
2014-07-31 18:16:13 +00:00
|
|
|
}))
|
2014-10-31 01:15:44 +00:00
|
|
|
defer server.Close()
|
2014-07-31 18:26:34 +00:00
|
|
|
status := expectApiStatus(t, "GET", server.URL, nil, http.StatusInternalServerError)
|
2014-08-26 17:36:09 +00:00
|
|
|
if status.Reason != api.StatusReasonUnknown {
|
2014-07-31 18:26:34 +00:00
|
|
|
t.Errorf("unexpected reason %#v", status)
|
2014-08-04 00:01:15 +00:00
|
|
|
}
|
2014-09-08 04:14:18 +00:00
|
|
|
if !strings.Contains(status.Message, "type apiserver.UnregisteredAPIObject is not registered") {
|
2014-07-31 18:26:34 +00:00
|
|
|
t.Errorf("unexpected message %#v", status)
|
2014-07-31 18:16:13 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
type marshalError struct {
|
|
|
|
err error
|
|
|
|
}
|
|
|
|
|
|
|
|
func (m *marshalError) MarshalJSON() ([]byte, error) {
|
|
|
|
return []byte{}, m.err
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestWriteRAWJSONMarshalError(t *testing.T) {
|
|
|
|
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) {
|
|
|
|
writeRawJSON(http.StatusOK, &marshalError{errors.New("Undecodable")}, w)
|
|
|
|
}))
|
2014-10-31 01:15:44 +00:00
|
|
|
defer server.Close()
|
2014-07-31 18:16:13 +00:00
|
|
|
client := http.Client{}
|
|
|
|
resp, err := client.Get(server.URL)
|
2014-08-04 00:01:15 +00:00
|
|
|
if err != nil {
|
|
|
|
t.Errorf("unexpected error: %v", err)
|
|
|
|
}
|
|
|
|
|
2014-07-31 18:16:13 +00:00
|
|
|
if resp.StatusCode != http.StatusInternalServerError {
|
|
|
|
t.Errorf("unexpected status code %d", resp.StatusCode)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-01-22 05:20:57 +00:00
|
|
|
func TestCreateTimeout(t *testing.T) {
|
2014-08-12 00:12:53 +00:00
|
|
|
testOver := make(chan struct{})
|
|
|
|
defer close(testOver)
|
2014-06-25 20:21:32 +00:00
|
|
|
storage := SimpleRESTStorage{
|
2014-09-08 04:14:18 +00:00
|
|
|
injectedFunction: func(obj runtime.Object) (runtime.Object, error) {
|
2014-08-12 00:12:53 +00:00
|
|
|
// Eliminate flakes by ensuring the create operation takes longer than this test.
|
|
|
|
<-testOver
|
2014-06-25 20:21:32 +00:00
|
|
|
return obj, nil
|
|
|
|
},
|
|
|
|
}
|
2014-08-09 21:12:55 +00:00
|
|
|
handler := Handle(map[string]RESTStorage{
|
2014-06-25 20:21:32 +00:00
|
|
|
"foo": &storage,
|
2015-01-29 22:46:54 +00:00
|
|
|
}, codec, "/prefix", testVersion, selfLinker, admissionControl, mapper)
|
2014-06-19 04:04:11 +00:00
|
|
|
server := httptest.NewServer(handler)
|
2014-10-31 01:15:44 +00:00
|
|
|
defer server.Close()
|
2014-06-19 04:04:11 +00:00
|
|
|
|
2014-10-22 17:02:02 +00:00
|
|
|
simple := &Simple{Other: "foo"}
|
2014-08-06 03:10:48 +00:00
|
|
|
data, _ := codec.Encode(simple)
|
2015-02-12 17:24:34 +00:00
|
|
|
itemOut := expectApiStatus(t, "POST", server.URL+"/prefix/version/foo?timeout=4ms", data, apierrs.StatusServerTimeout)
|
2015-01-22 05:20:57 +00:00
|
|
|
if itemOut.Status != api.StatusFailure || itemOut.Reason != api.StatusReasonTimeout {
|
2014-06-25 20:21:32 +00:00
|
|
|
t.Errorf("Unexpected status %#v", itemOut)
|
|
|
|
}
|
2014-06-19 04:04:11 +00:00
|
|
|
}
|
2014-09-02 16:28:24 +00:00
|
|
|
|
2014-09-09 21:05:18 +00:00
|
|
|
func TestCORSAllowedOrigins(t *testing.T) {
|
|
|
|
table := []struct {
|
|
|
|
allowedOrigins util.StringList
|
|
|
|
origin string
|
|
|
|
allowed bool
|
|
|
|
}{
|
|
|
|
{[]string{}, "example.com", false},
|
|
|
|
{[]string{"example.com"}, "example.com", true},
|
|
|
|
{[]string{"example.com"}, "not-allowed.com", false},
|
|
|
|
{[]string{"not-matching.com", "example.com"}, "example.com", true},
|
|
|
|
{[]string{".*"}, "example.com", true},
|
2014-09-03 18:33:52 +00:00
|
|
|
}
|
|
|
|
|
2014-09-09 21:05:18 +00:00
|
|
|
for _, item := range table {
|
|
|
|
allowedOriginRegexps, err := util.CompileRegexps(item.allowedOrigins)
|
|
|
|
if err != nil {
|
|
|
|
t.Errorf("unexpected error: %v", err)
|
|
|
|
}
|
2014-09-03 18:33:52 +00:00
|
|
|
|
2014-09-26 00:20:28 +00:00
|
|
|
handler := CORS(
|
2015-01-29 22:46:54 +00:00
|
|
|
Handle(map[string]RESTStorage{}, codec, "/prefix", testVersion, selfLinker, admissionControl, mapper),
|
2014-09-26 00:20:28 +00:00
|
|
|
allowedOriginRegexps, nil, nil, "true",
|
|
|
|
)
|
2014-09-09 21:05:18 +00:00
|
|
|
server := httptest.NewServer(handler)
|
2014-10-31 01:15:44 +00:00
|
|
|
defer server.Close()
|
2014-09-09 21:05:18 +00:00
|
|
|
client := http.Client{}
|
2014-09-03 18:33:52 +00:00
|
|
|
|
2014-09-09 21:05:18 +00:00
|
|
|
request, err := http.NewRequest("GET", server.URL+"/version", nil)
|
|
|
|
if err != nil {
|
|
|
|
t.Errorf("unexpected error: %v", err)
|
|
|
|
}
|
|
|
|
request.Header.Set("Origin", item.origin)
|
2014-09-03 18:33:52 +00:00
|
|
|
|
2014-09-09 21:05:18 +00:00
|
|
|
response, err := client.Do(request)
|
|
|
|
if err != nil {
|
|
|
|
t.Errorf("unexpected error: %v", err)
|
|
|
|
}
|
2014-09-03 18:33:52 +00:00
|
|
|
|
2014-09-09 21:05:18 +00:00
|
|
|
if item.allowed {
|
|
|
|
if !reflect.DeepEqual(item.origin, response.Header.Get("Access-Control-Allow-Origin")) {
|
|
|
|
t.Errorf("Expected %#v, Got %#v", item.origin, response.Header.Get("Access-Control-Allow-Origin"))
|
|
|
|
}
|
|
|
|
|
|
|
|
if response.Header.Get("Access-Control-Allow-Credentials") == "" {
|
|
|
|
t.Errorf("Expected Access-Control-Allow-Credentials header to be set")
|
|
|
|
}
|
|
|
|
|
|
|
|
if response.Header.Get("Access-Control-Allow-Headers") == "" {
|
|
|
|
t.Errorf("Expected Access-Control-Allow-Headers header to be set")
|
|
|
|
}
|
|
|
|
|
|
|
|
if response.Header.Get("Access-Control-Allow-Methods") == "" {
|
|
|
|
t.Errorf("Expected Access-Control-Allow-Methods header to be set")
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
if response.Header.Get("Access-Control-Allow-Origin") != "" {
|
|
|
|
t.Errorf("Expected Access-Control-Allow-Origin header to not be set")
|
|
|
|
}
|
|
|
|
|
|
|
|
if response.Header.Get("Access-Control-Allow-Credentials") != "" {
|
|
|
|
t.Errorf("Expected Access-Control-Allow-Credentials header to not be set")
|
|
|
|
}
|
|
|
|
|
|
|
|
if response.Header.Get("Access-Control-Allow-Headers") != "" {
|
|
|
|
t.Errorf("Expected Access-Control-Allow-Headers header to not be set")
|
|
|
|
}
|
|
|
|
|
|
|
|
if response.Header.Get("Access-Control-Allow-Methods") != "" {
|
|
|
|
t.Errorf("Expected Access-Control-Allow-Methods header to not be set")
|
|
|
|
}
|
|
|
|
}
|
2014-09-03 18:33:52 +00:00
|
|
|
}
|
|
|
|
}
|