Complete initial third party API support in the master
This commit is contained in:
@@ -28,11 +28,10 @@ import (
|
||||
"os"
|
||||
"path/filepath"
|
||||
"reflect"
|
||||
"strings"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/emicklei/go-restful"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"k8s.io/kubernetes/pkg/api"
|
||||
"k8s.io/kubernetes/pkg/api/latest"
|
||||
"k8s.io/kubernetes/pkg/api/meta"
|
||||
@@ -47,10 +46,15 @@ import (
|
||||
"k8s.io/kubernetes/pkg/registry/endpoint"
|
||||
"k8s.io/kubernetes/pkg/registry/namespace"
|
||||
"k8s.io/kubernetes/pkg/registry/registrytest"
|
||||
thirdpartyresourcedatastorage "k8s.io/kubernetes/pkg/registry/thirdpartyresourcedata/etcd"
|
||||
etcdstorage "k8s.io/kubernetes/pkg/storage/etcd"
|
||||
"k8s.io/kubernetes/pkg/tools"
|
||||
"k8s.io/kubernetes/pkg/tools/etcdtest"
|
||||
"k8s.io/kubernetes/pkg/util"
|
||||
|
||||
"github.com/coreos/go-etcd/etcd"
|
||||
"github.com/emicklei/go-restful"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
// setUp is a convience function for setting up for (most) tests.
|
||||
@@ -440,12 +444,12 @@ type FooList struct {
|
||||
unversioned.TypeMeta `json:",inline"`
|
||||
unversioned.ListMeta `json:"metadata,omitempty" description:"standard list metadata; see http://releases.k8s.io/HEAD/docs/devel/api-conventions.md#metadata"`
|
||||
|
||||
items []Foo `json:"items"`
|
||||
Items []Foo `json:"items"`
|
||||
}
|
||||
|
||||
func initThirdParty(t *testing.T, version string) (*tools.FakeEtcdClient, *httptest.Server, *assert.Assertions) {
|
||||
func initThirdParty(t *testing.T, version string) (*Master, *tools.FakeEtcdClient, *httptest.Server, *assert.Assertions) {
|
||||
master, _, assert := setUp(t)
|
||||
|
||||
master.thirdPartyResources = map[string]*thirdpartyresourcedatastorage.REST{}
|
||||
api := &experimental.ThirdPartyResource{
|
||||
ObjectMeta: api.ObjectMeta{
|
||||
Name: "foo.company.com",
|
||||
@@ -463,12 +467,12 @@ func initThirdParty(t *testing.T, version string) (*tools.FakeEtcdClient, *httpt
|
||||
fakeClient.Machines = []string{"http://machine1:4001", "http://machine2", "http://machine3:4003"}
|
||||
master.thirdPartyStorage = etcdstorage.NewEtcdStorage(fakeClient, testapi.Experimental.Codec(), etcdtest.PathPrefix())
|
||||
|
||||
if !assert.NoError(master.InstallThirdPartyAPI(api)) {
|
||||
if !assert.NoError(master.InstallThirdPartyResource(api)) {
|
||||
t.FailNow()
|
||||
}
|
||||
|
||||
server := httptest.NewServer(master.handlerContainer.ServeMux)
|
||||
return fakeClient, server, assert
|
||||
return &master, fakeClient, server, assert
|
||||
}
|
||||
|
||||
func TestInstallThirdPartyAPIList(t *testing.T) {
|
||||
@@ -478,27 +482,90 @@ func TestInstallThirdPartyAPIList(t *testing.T) {
|
||||
}
|
||||
|
||||
func testInstallThirdPartyAPIListVersion(t *testing.T, version string) {
|
||||
fakeClient, server, assert := initThirdParty(t, version)
|
||||
defer server.Close()
|
||||
|
||||
fakeClient.ExpectNotFoundGet(etcdtest.PathPrefix() + "/ThirdPartyResourceData/company.com/foos/default")
|
||||
|
||||
resp, err := http.Get(server.URL + "/apis/company.com/" + version + "/namespaces/default/foos")
|
||||
if !assert.NoError(err) {
|
||||
return
|
||||
tests := []struct {
|
||||
items []Foo
|
||||
}{
|
||||
{},
|
||||
{
|
||||
items: []Foo{},
|
||||
},
|
||||
{
|
||||
items: []Foo{
|
||||
{
|
||||
ObjectMeta: api.ObjectMeta{
|
||||
Name: "test",
|
||||
},
|
||||
TypeMeta: unversioned.TypeMeta{
|
||||
Kind: "Foo",
|
||||
APIVersion: version,
|
||||
},
|
||||
SomeField: "test field",
|
||||
OtherField: 10,
|
||||
},
|
||||
{
|
||||
ObjectMeta: api.ObjectMeta{
|
||||
Name: "bar",
|
||||
},
|
||||
TypeMeta: unversioned.TypeMeta{
|
||||
Kind: "Foo",
|
||||
APIVersion: version,
|
||||
},
|
||||
SomeField: "test field another",
|
||||
OtherField: 20,
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
for _, test := range tests {
|
||||
_, fakeClient, server, assert := initThirdParty(t, version)
|
||||
defer server.Close()
|
||||
|
||||
defer resp.Body.Close()
|
||||
if test.items == nil {
|
||||
fakeClient.ExpectNotFoundGet(etcdtest.PathPrefix() + "/ThirdPartyResourceData/company.com/foos/default")
|
||||
} else {
|
||||
setupEtcdList(fakeClient, "/ThirdPartyResourceData/company.com/foos/default", test.items)
|
||||
}
|
||||
|
||||
assert.Equal(http.StatusOK, resp.StatusCode)
|
||||
resp, err := http.Get(server.URL + "/apis/company.com/" + version + "/namespaces/default/foos")
|
||||
if !assert.NoError(err) {
|
||||
return
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
data, err := ioutil.ReadAll(resp.Body)
|
||||
assert.NoError(err)
|
||||
assert.Equal(http.StatusOK, resp.StatusCode)
|
||||
|
||||
list := FooList{}
|
||||
err = json.Unmarshal(data, &list)
|
||||
assert.NoError(err)
|
||||
data, err := ioutil.ReadAll(resp.Body)
|
||||
assert.NoError(err)
|
||||
|
||||
list := FooList{}
|
||||
if err = json.Unmarshal(data, &list); err != nil {
|
||||
t.Errorf("unexpected error: %v", err)
|
||||
}
|
||||
|
||||
if test.items == nil {
|
||||
if len(list.Items) != 0 {
|
||||
t.Errorf("expected no items, saw: %v", list.Items)
|
||||
}
|
||||
continue
|
||||
}
|
||||
|
||||
if len(list.Items) != len(test.items) {
|
||||
t.Errorf("unexpected length: %d vs %d", len(list.Items), len(test.items))
|
||||
continue
|
||||
}
|
||||
for ix := range list.Items {
|
||||
// Copy things that are set dynamically on the server
|
||||
expectedObj := test.items[ix]
|
||||
expectedObj.SelfLink = list.Items[ix].SelfLink
|
||||
expectedObj.Namespace = list.Items[ix].Namespace
|
||||
expectedObj.UID = list.Items[ix].UID
|
||||
expectedObj.CreationTimestamp = list.Items[ix].CreationTimestamp
|
||||
|
||||
if !reflect.DeepEqual(list.Items[ix], expectedObj) {
|
||||
t.Errorf("expected:\n%#v\nsaw:\n%#v\n", expectedObj, list.Items[ix])
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func encodeToThirdParty(name string, obj interface{}) ([]byte, error) {
|
||||
@@ -522,6 +589,23 @@ func storeToEtcd(fakeClient *tools.FakeEtcdClient, path, name string, obj interf
|
||||
return err
|
||||
}
|
||||
|
||||
func setupEtcdList(fakeClient *tools.FakeEtcdClient, path string, list []Foo) error {
|
||||
resp := tools.EtcdResponseWithError{
|
||||
R: &etcd.Response{
|
||||
Node: &etcd.Node{},
|
||||
},
|
||||
}
|
||||
for _, obj := range list {
|
||||
data, err := encodeToThirdParty(obj.Name, obj)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
resp.R.Node.Nodes = append(resp.R.Node.Nodes, &etcd.Node{Value: string(data)})
|
||||
}
|
||||
fakeClient.Data[etcdtest.PathPrefix()+path] = resp
|
||||
return nil
|
||||
}
|
||||
|
||||
func decodeResponse(resp *http.Response, obj interface{}) error {
|
||||
defer resp.Body.Close()
|
||||
|
||||
@@ -543,7 +627,7 @@ func TestInstallThirdPartyAPIGet(t *testing.T) {
|
||||
}
|
||||
|
||||
func testInstallThirdPartyAPIGetVersion(t *testing.T, version string) {
|
||||
fakeClient, server, assert := initThirdParty(t, version)
|
||||
_, fakeClient, server, assert := initThirdParty(t, version)
|
||||
defer server.Close()
|
||||
|
||||
expectedObj := Foo{
|
||||
@@ -588,7 +672,7 @@ func TestInstallThirdPartyAPIPost(t *testing.T) {
|
||||
}
|
||||
|
||||
func testInstallThirdPartyAPIPostForVersion(t *testing.T, version string) {
|
||||
fakeClient, server, assert := initThirdParty(t, version)
|
||||
_, fakeClient, server, assert := initThirdParty(t, version)
|
||||
defer server.Close()
|
||||
|
||||
inputObj := Foo{
|
||||
@@ -656,7 +740,7 @@ func TestInstallThirdPartyAPIDelete(t *testing.T) {
|
||||
}
|
||||
|
||||
func testInstallThirdPartyAPIDeleteVersion(t *testing.T, version string) {
|
||||
fakeClient, server, assert := initThirdParty(t, version)
|
||||
_, fakeClient, server, assert := initThirdParty(t, version)
|
||||
defer server.Close()
|
||||
|
||||
expectedObj := Foo{
|
||||
@@ -721,3 +805,88 @@ func httpDelete(url string) (*http.Response, error) {
|
||||
client := &http.Client{}
|
||||
return client.Do(req)
|
||||
}
|
||||
|
||||
func TestInstallThirdPartyResourceRemove(t *testing.T) {
|
||||
for _, version := range versionsToTest {
|
||||
testInstallThirdPartyResourceRemove(t, version)
|
||||
}
|
||||
}
|
||||
|
||||
func testInstallThirdPartyResourceRemove(t *testing.T, version string) {
|
||||
master, fakeClient, server, assert := initThirdParty(t, version)
|
||||
defer server.Close()
|
||||
|
||||
expectedObj := Foo{
|
||||
ObjectMeta: api.ObjectMeta{
|
||||
Name: "test",
|
||||
},
|
||||
TypeMeta: unversioned.TypeMeta{
|
||||
Kind: "Foo",
|
||||
},
|
||||
SomeField: "test field",
|
||||
OtherField: 10,
|
||||
}
|
||||
if !assert.NoError(storeToEtcd(fakeClient, "/ThirdPartyResourceData/company.com/foos/default/test", "test", expectedObj)) {
|
||||
t.FailNow()
|
||||
return
|
||||
}
|
||||
secondObj := expectedObj
|
||||
secondObj.Name = "bar"
|
||||
if !assert.NoError(storeToEtcd(fakeClient, "/ThirdPartyResourceData/company.com/foos/default/bar", "bar", secondObj)) {
|
||||
t.FailNow()
|
||||
return
|
||||
}
|
||||
|
||||
setupEtcdList(fakeClient, "/ThirdPartyResourceData/company.com/foos/default", []Foo{expectedObj, secondObj})
|
||||
|
||||
resp, err := http.Get(server.URL + "/apis/company.com/" + version + "/namespaces/default/foos/test")
|
||||
if !assert.NoError(err) {
|
||||
t.FailNow()
|
||||
return
|
||||
}
|
||||
|
||||
if resp.StatusCode != http.StatusOK {
|
||||
t.Errorf("unexpected status: %v", resp)
|
||||
}
|
||||
|
||||
item := Foo{}
|
||||
if err := decodeResponse(resp, &item); err != nil {
|
||||
t.Errorf("unexpected error: %v", err)
|
||||
}
|
||||
|
||||
// TODO: validate etcd set things here
|
||||
item.ObjectMeta = expectedObj.ObjectMeta
|
||||
|
||||
if !assert.True(reflect.DeepEqual(item, expectedObj)) {
|
||||
t.Errorf("expected:\n%v\nsaw:\n%v\n", expectedObj, item)
|
||||
}
|
||||
|
||||
path := makeThirdPartyPath("company.com")
|
||||
master.RemoveThirdPartyResource(path)
|
||||
|
||||
resp, err = http.Get(server.URL + "/apis/company.com/" + version + "/namespaces/default/foos/test")
|
||||
if !assert.NoError(err) {
|
||||
return
|
||||
}
|
||||
|
||||
if resp.StatusCode != http.StatusNotFound {
|
||||
t.Errorf("unexpected status: %v", resp)
|
||||
}
|
||||
expectDeletedKeys := []string{
|
||||
etcdtest.PathPrefix() + "/ThirdPartyResourceData/company.com/foos/default/test",
|
||||
etcdtest.PathPrefix() + "/ThirdPartyResourceData/company.com/foos/default/bar",
|
||||
}
|
||||
if !assert.True(reflect.DeepEqual(fakeClient.DeletedKeys, expectDeletedKeys)) {
|
||||
t.Errorf("unexpected deleted keys: %v", fakeClient.DeletedKeys)
|
||||
}
|
||||
installed := master.ListThirdPartyResources()
|
||||
if len(installed) != 0 {
|
||||
t.Errorf("Resource(s) still installed: %v", installed)
|
||||
}
|
||||
services := master.handlerContainer.RegisteredWebServices()
|
||||
for ix := range services {
|
||||
if strings.HasPrefix(services[ix].RootPath(), "/apis/company.com") {
|
||||
t.Errorf("Web service still installed at %s: %#v", services[ix].RootPath(), services[ix])
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user