k3s/pkg/master/master_test.go

781 lines
24 KiB
Go
Raw Normal View History

/*
Copyright 2014 The Kubernetes Authors 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.
*/
package master
import (
"bytes"
"crypto/tls"
"encoding/json"
2015-09-03 17:35:04 +00:00
"fmt"
2015-08-19 18:02:01 +00:00
"io/ioutil"
2015-09-03 17:35:04 +00:00
"net"
2015-08-19 18:02:01 +00:00
"net/http"
"net/http/httptest"
"reflect"
"strings"
"testing"
2015-08-05 22:03:47 +00:00
"k8s.io/kubernetes/pkg/api"
"k8s.io/kubernetes/pkg/api/testapi"
"k8s.io/kubernetes/pkg/api/unversioned"
2015-09-28 18:08:47 +00:00
apiutil "k8s.io/kubernetes/pkg/api/util"
2015-10-09 22:04:41 +00:00
"k8s.io/kubernetes/pkg/apis/extensions"
"k8s.io/kubernetes/pkg/genericapiserver"
"k8s.io/kubernetes/pkg/kubelet/client"
2015-09-03 17:35:04 +00:00
"k8s.io/kubernetes/pkg/registry/endpoint"
"k8s.io/kubernetes/pkg/registry/namespace"
2015-08-05 22:03:47 +00:00
"k8s.io/kubernetes/pkg/registry/registrytest"
"k8s.io/kubernetes/pkg/runtime"
"k8s.io/kubernetes/pkg/storage"
2015-08-05 22:03:47 +00:00
etcdstorage "k8s.io/kubernetes/pkg/storage/etcd"
"k8s.io/kubernetes/pkg/storage/etcd/etcdtest"
etcdtesting "k8s.io/kubernetes/pkg/storage/etcd/testing"
2015-09-03 17:35:04 +00:00
"k8s.io/kubernetes/pkg/util"
"k8s.io/kubernetes/pkg/util/intstr"
"github.com/emicklei/go-restful"
"github.com/stretchr/testify/assert"
"golang.org/x/net/context"
)
2015-09-03 17:35:04 +00:00
// setUp is a convience function for setting up for (most) tests.
func setUp(t *testing.T) (Master, *etcdtesting.EtcdTestServer, Config, *assert.Assertions) {
server := etcdtesting.NewEtcdTestClientServer(t)
master := Master{
GenericAPIServer: &genericapiserver.GenericAPIServer{},
}
config := Config{
Config: &genericapiserver.Config{},
}
2015-09-15 03:55:18 +00:00
storageVersions := make(map[string]string)
storageDestinations := genericapiserver.NewStorageDestinations()
storageDestinations.AddAPIGroup(
2015-12-08 14:21:04 +00:00
api.GroupName, etcdstorage.NewEtcdStorage(server.Client, testapi.Default.Codec(), etcdtest.PathPrefix()))
storageDestinations.AddAPIGroup(
2015-12-08 14:21:04 +00:00
extensions.GroupName, etcdstorage.NewEtcdStorage(server.Client, testapi.Extensions.Codec(), etcdtest.PathPrefix()))
2015-09-30 07:56:51 +00:00
config.StorageDestinations = storageDestinations
2015-12-08 14:21:04 +00:00
storageVersions[api.GroupName] = testapi.Default.GroupVersion().String()
storageVersions[extensions.GroupName] = testapi.Extensions.GroupVersion().String()
2015-09-15 03:55:18 +00:00
config.StorageVersions = storageVersions
config.PublicAddress = net.ParseIP("192.168.10.4")
master.nodeRegistry = registrytest.NewNodeRegistry([]string{"node1", "node2"}, api.NodeResources{})
return master, server, config, assert.New(t)
2015-09-03 17:35:04 +00:00
}
func newMaster(t *testing.T) (*Master, *etcdtesting.EtcdTestServer, Config, *assert.Assertions) {
_, etcdserver, config, assert := setUp(t)
2015-09-03 17:35:04 +00:00
config.KubeletClient = client.FakeKubeletClient{}
config.ProxyDialer = func(network, addr string) (net.Conn, error) { return nil, nil }
config.ProxyTLSClientConfig = &tls.Config{}
2015-09-03 17:35:04 +00:00
master := New(&config)
return master, etcdserver, config, assert
}
// TestNew verifies that the New function returns a Master
// using the configuration properly.
func TestNew(t *testing.T) {
master, etcdserver, config, assert := newMaster(t)
defer etcdserver.Terminate(t)
2015-09-03 17:35:04 +00:00
// Verify many of the variables match their config counterparts
assert.Equal(master.enableCoreControllers, config.EnableCoreControllers)
assert.Equal(master.tunneler, config.Tunneler)
assert.Equal(master.APIPrefix, config.APIPrefix)
assert.Equal(master.APIGroupPrefix, config.APIGroupPrefix)
assert.Equal(master.ApiGroupVersionOverrides, config.APIGroupVersionOverrides)
assert.Equal(master.RequestContextMapper, config.RequestContextMapper)
assert.Equal(master.MasterCount, config.MasterCount)
assert.Equal(master.ClusterIP, config.PublicAddress)
assert.Equal(master.PublicReadWritePort, config.ReadWritePort)
assert.Equal(master.ServiceReadWriteIP, config.ServiceReadWriteIP)
// These functions should point to the same memory location
masterDialer, _ := util.Dialer(master.ProxyTransport)
masterDialerFunc := fmt.Sprintf("%p", masterDialer)
configDialerFunc := fmt.Sprintf("%p", config.ProxyDialer)
assert.Equal(masterDialerFunc, configDialerFunc)
assert.Equal(master.ProxyTransport.(*http.Transport).TLSClientConfig, config.ProxyTLSClientConfig)
2015-09-03 17:35:04 +00:00
}
// TestGetServersToValidate verifies the unexported getServersToValidate function
func TestGetServersToValidate(t *testing.T) {
master, etcdserver, config, assert := setUp(t)
defer etcdserver.Terminate(t)
2015-05-14 00:29:25 +00:00
servers := master.getServersToValidate(&config)
// Expected servers to validate: scheduler, controller-manager and etcd.
assert.Equal(3, len(servers), "unexpected server list: %#v", servers)
2015-09-03 17:35:04 +00:00
for _, server := range []string{"scheduler", "controller-manager", "etcd-0"} {
if _, ok := servers[server]; !ok {
t.Errorf("server list missing: %s", server)
}
}
}
2015-07-28 08:10:48 +00:00
2015-09-03 17:35:04 +00:00
// TestFindExternalAddress verifies both pass and fail cases for the unexported
// findExternalAddress function
2015-07-28 08:10:48 +00:00
func TestFindExternalAddress(t *testing.T) {
2015-09-03 17:35:04 +00:00
assert := assert.New(t)
2015-07-28 08:10:48 +00:00
expectedIP := "172.0.0.1"
nodes := []*api.Node{new(api.Node), new(api.Node), new(api.Node)}
nodes[0].Status.Addresses = []api.NodeAddress{{"ExternalIP", expectedIP}}
nodes[1].Status.Addresses = []api.NodeAddress{{"LegacyHostIP", expectedIP}}
nodes[2].Status.Addresses = []api.NodeAddress{{"ExternalIP", expectedIP}, {"LegacyHostIP", "172.0.0.2"}}
2015-09-03 17:35:04 +00:00
// Pass Case
2015-07-28 08:10:48 +00:00
for _, node := range nodes {
ip, err := findExternalAddress(node)
2015-09-03 17:35:04 +00:00
assert.NoError(err, "error getting node external address")
assert.Equal(expectedIP, ip, "expected ip to be %s, but was %s", expectedIP, ip)
2015-07-28 08:10:48 +00:00
}
2015-09-03 17:35:04 +00:00
// Fail case
2015-07-28 08:10:48 +00:00
_, err := findExternalAddress(new(api.Node))
2015-09-03 17:35:04 +00:00
assert.Error(err, "expected findExternalAddress to fail on a node with missing ip information")
}
// TestNewBootstrapController verifies master fields are properly copied into controller
func TestNewBootstrapController(t *testing.T) {
// Tests a subset of inputs to ensure they are set properly in the controller
master, etcdserver, _, assert := setUp(t)
defer etcdserver.Terminate(t)
2015-09-03 17:35:04 +00:00
portRange := util.PortRange{Base: 10, Size: 10}
master.namespaceRegistry = namespace.NewRegistry(nil)
master.serviceRegistry = registrytest.NewServiceRegistry()
master.endpointRegistry = endpoint.NewRegistry(nil)
master.ServiceNodePortRange = portRange
master.MasterCount = 1
master.ServiceReadWritePort = 1000
master.PublicReadWritePort = 1010
2015-09-03 17:35:04 +00:00
controller := master.NewBootstrapController()
assert.Equal(controller.NamespaceRegistry, master.namespaceRegistry)
assert.Equal(controller.EndpointRegistry, master.endpointRegistry)
assert.Equal(controller.ServiceRegistry, master.serviceRegistry)
assert.Equal(controller.ServiceNodePortRange, portRange)
assert.Equal(controller.MasterCount, master.MasterCount)
assert.Equal(controller.ServicePort, master.ServiceReadWritePort)
assert.Equal(controller.PublicServicePort, master.PublicReadWritePort)
2015-09-03 17:35:04 +00:00
}
// TestControllerServicePorts verifies master extraServicePorts are
// correctly copied into controller
func TestControllerServicePorts(t *testing.T) {
master, etcdserver, _, assert := setUp(t)
defer etcdserver.Terminate(t)
master.namespaceRegistry = namespace.NewRegistry(nil)
master.serviceRegistry = registrytest.NewServiceRegistry()
master.endpointRegistry = endpoint.NewRegistry(nil)
master.ExtraServicePorts = []api.ServicePort{
{
Name: "additional-port-1",
Port: 1000,
Protocol: api.ProtocolTCP,
TargetPort: intstr.FromInt(1000),
},
{
Name: "additional-port-2",
Port: 1010,
Protocol: api.ProtocolTCP,
TargetPort: intstr.FromInt(1010),
},
}
controller := master.NewBootstrapController()
assert.Equal(1000, controller.ExtraServicePorts[0].Port)
assert.Equal(1010, controller.ExtraServicePorts[1].Port)
}
2015-09-03 17:35:04 +00:00
// TestGetNodeAddresses verifies that proper results are returned
// when requesting node addresses.
func TestGetNodeAddresses(t *testing.T) {
master, etcdserver, _, assert := setUp(t)
defer etcdserver.Terminate(t)
2015-09-03 17:35:04 +00:00
// Fail case (no addresses associated with nodes)
2015-10-27 13:47:58 +00:00
nodes, _ := master.nodeRegistry.ListNodes(api.NewDefaultContext(), nil)
2015-09-03 17:35:04 +00:00
addrs, err := master.getNodeAddresses()
assert.Error(err, "getNodeAddresses should have caused an error as there are no addresses.")
assert.Equal([]string(nil), addrs)
// Pass case with External type IP
2015-10-27 13:47:58 +00:00
nodes, _ = master.nodeRegistry.ListNodes(api.NewDefaultContext(), nil)
2015-09-03 17:35:04 +00:00
for index := range nodes.Items {
nodes.Items[index].Status.Addresses = []api.NodeAddress{{Type: api.NodeExternalIP, Address: "127.0.0.1"}}
}
addrs, err = master.getNodeAddresses()
assert.NoError(err, "getNodeAddresses should not have returned an error.")
assert.Equal([]string{"127.0.0.1", "127.0.0.1"}, addrs)
// Pass case with LegacyHost type IP
2015-10-27 13:47:58 +00:00
nodes, _ = master.nodeRegistry.ListNodes(api.NewDefaultContext(), nil)
2015-09-03 17:35:04 +00:00
for index := range nodes.Items {
nodes.Items[index].Status.Addresses = []api.NodeAddress{{Type: api.NodeLegacyHostIP, Address: "127.0.0.2"}}
}
addrs, err = master.getNodeAddresses()
assert.NoError(err, "getNodeAddresses failback should not have returned an error.")
assert.Equal([]string{"127.0.0.2", "127.0.0.2"}, addrs)
}
2015-09-28 18:08:47 +00:00
func TestDiscoveryAtAPIS(t *testing.T) {
master, etcdserver, config, assert := newMaster(t)
defer etcdserver.Terminate(t)
server := httptest.NewServer(master.HandlerContainer.ServeMux)
2015-09-28 18:08:47 +00:00
resp, err := http.Get(server.URL + "/apis")
if !assert.NoError(err) {
t.Errorf("unexpected error: %v", err)
}
assert.Equal(http.StatusOK, resp.StatusCode)
2015-10-09 01:33:22 +00:00
groupList := unversioned.APIGroupList{}
2015-09-28 18:08:47 +00:00
assert.NoError(decodeResponse(resp, &groupList))
if err != nil {
t.Fatalf("unexpected error: %v", err)
}
2015-12-08 14:21:04 +00:00
expectGroupName := extensions.GroupName
expectVersions := []unversioned.GroupVersionForDiscovery{
2015-09-28 18:08:47 +00:00
{
GroupVersion: testapi.Extensions.GroupVersion().String(),
Version: testapi.Extensions.GroupVersion().Version,
2015-09-28 18:08:47 +00:00
},
}
expectPreferredVersion := unversioned.GroupVersionForDiscovery{
2015-12-08 14:21:04 +00:00
GroupVersion: config.StorageVersions[extensions.GroupName],
Version: apiutil.GetVersion(config.StorageVersions[extensions.GroupName]),
2015-09-28 18:08:47 +00:00
}
assert.Equal(expectGroupName, groupList.Groups[0].Name)
assert.Equal(expectVersions, groupList.Groups[0].Versions)
assert.Equal(expectPreferredVersion, groupList.Groups[0].PreferredVersion)
thirdPartyGV := unversioned.GroupVersionForDiscovery{GroupVersion: "company.com/v1", Version: "v1"}
master.thirdPartyResources["/apis/company.com/v1"] = thirdPartyEntry{
nil,
unversioned.APIGroup{
Name: "company.com",
Versions: []unversioned.GroupVersionForDiscovery{thirdPartyGV},
PreferredVersion: thirdPartyGV,
},
}
resp, err = http.Get(server.URL + "/apis")
if !assert.NoError(err) {
t.Errorf("unexpected error: %v", err)
}
assert.Equal(http.StatusOK, resp.StatusCode)
assert.NoError(decodeResponse(resp, &groupList))
if err != nil {
t.Fatalf("unexpected error: %v", err)
}
thirdPartyGroupName := "company.com"
thirdPartyExpectVersions := []unversioned.GroupVersionForDiscovery{thirdPartyGV}
assert.Equal(thirdPartyGroupName, groupList.Groups[1].Name)
assert.Equal(thirdPartyExpectVersions, groupList.Groups[1].Versions)
assert.Equal(thirdPartyGV, groupList.Groups[1].PreferredVersion)
2015-09-28 18:08:47 +00:00
}
2015-09-01 05:28:08 +00:00
var versionsToTest = []string{"v1", "v3"}
type Foo struct {
unversioned.TypeMeta `json:",inline"`
api.ObjectMeta `json:"metadata,omitempty" description:"standard object metadata"`
SomeField string `json:"someField"`
OtherField int `json:"otherField"`
}
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"`
}
func initThirdParty(t *testing.T, version string) (*Master, *etcdtesting.EtcdTestServer, *httptest.Server, *assert.Assertions) {
master, etcdserver, _, assert := setUp(t)
master.thirdPartyResources = map[string]thirdPartyEntry{}
2015-10-09 22:49:10 +00:00
api := &extensions.ThirdPartyResource{
2015-08-19 18:02:01 +00:00
ObjectMeta: api.ObjectMeta{
Name: "foo.company.com",
2015-08-19 18:02:01 +00:00
},
2015-10-09 22:49:10 +00:00
Versions: []extensions.APIVersion{
{
2015-08-19 18:02:01 +00:00
APIGroup: "group",
2015-09-01 05:28:08 +00:00
Name: version,
2015-08-19 18:02:01 +00:00
},
},
}
master.HandlerContainer = restful.NewContainer()
master.thirdPartyStorage = etcdstorage.NewEtcdStorage(etcdserver.Client, testapi.Extensions.Codec(), etcdtest.PathPrefix())
if !assert.NoError(master.InstallThirdPartyResource(api)) {
t.FailNow()
2015-08-19 18:02:01 +00:00
}
server := httptest.NewServer(master.HandlerContainer.ServeMux)
return &master, etcdserver, server, assert
}
func TestInstallThirdPartyAPIList(t *testing.T) {
2015-09-01 05:28:08 +00:00
for _, version := range versionsToTest {
testInstallThirdPartyAPIListVersion(t, version)
}
}
func testInstallThirdPartyAPIListVersion(t *testing.T, version string) {
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 {
func() {
master, etcdserver, server, assert := initThirdParty(t, version)
defer server.Close()
defer etcdserver.Terminate(t)
if test.items != nil {
storeThirdPartyList(master.thirdPartyStorage, "/ThirdPartyResourceData/company.com/foos/default", test.items)
}
resp, err := http.Get(server.URL + "/apis/company.com/" + version + "/namespaces/default/foos")
if !assert.NoError(err) {
return
}
defer resp.Body.Close()
2015-09-03 17:35:04 +00:00
assert.Equal(http.StatusOK, resp.StatusCode)
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)
}
return
}
2015-09-03 17:35:04 +00:00
if len(list.Items) != len(test.items) {
t.Errorf("unexpected length: %d vs %d", len(list.Items), len(test.items))
return
}
// The order of elements in LIST is not guaranteed.
mapping := make(map[string]int)
for ix := range test.items {
mapping[test.items[ix].Name] = ix
}
for ix := range list.Items {
// Copy things that are set dynamically on the server
expectedObj := test.items[mapping[list.Items[ix].Name]]
expectedObj.SelfLink = list.Items[ix].SelfLink
expectedObj.ResourceVersion = list.Items[ix].ResourceVersion
expectedObj.Namespace = list.Items[ix].Namespace
expectedObj.UID = list.Items[ix].UID
expectedObj.CreationTimestamp = list.Items[ix].CreationTimestamp
// We endure the order of items by sorting them (using 'mapping')
// so that this function passes.
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{}) (runtime.Object, error) {
serial, err := json.Marshal(obj)
if err != nil {
return nil, err
}
2015-10-09 22:49:10 +00:00
thirdPartyData := extensions.ThirdPartyResourceData{
ObjectMeta: api.ObjectMeta{Name: name},
Data: serial,
}
return &thirdPartyData, nil
}
func storeThirdPartyObject(s storage.Interface, path, name string, obj interface{}) error {
data, err := encodeToThirdParty(name, obj)
if err != nil {
return err
}
return s.Set(context.TODO(), etcdtest.AddPrefix(path), data, nil, 0)
}
func storeThirdPartyList(s storage.Interface, path string, list []Foo) error {
for _, obj := range list {
if err := storeThirdPartyObject(s, path+"/"+obj.Name, obj.Name, obj); err != nil {
return err
}
}
return nil
}
func decodeResponse(resp *http.Response, obj interface{}) error {
defer resp.Body.Close()
data, err := ioutil.ReadAll(resp.Body)
if err != nil {
return err
}
if err := json.Unmarshal(data, obj); err != nil {
return err
}
return nil
}
func TestInstallThirdPartyAPIGet(t *testing.T) {
2015-09-01 05:28:08 +00:00
for _, version := range versionsToTest {
testInstallThirdPartyAPIGetVersion(t, version)
}
}
func testInstallThirdPartyAPIGetVersion(t *testing.T, version string) {
master, etcdserver, server, assert := initThirdParty(t, version)
defer server.Close()
defer etcdserver.Terminate(t)
expectedObj := Foo{
ObjectMeta: api.ObjectMeta{
Name: "test",
},
TypeMeta: unversioned.TypeMeta{
2015-09-01 05:28:08 +00:00
Kind: "Foo",
APIVersion: version,
},
SomeField: "test field",
OtherField: 10,
}
if !assert.NoError(storeThirdPartyObject(master.thirdPartyStorage, "/ThirdPartyResourceData/company.com/foos/default/test", "test", expectedObj)) {
t.FailNow()
return
}
2015-09-14 20:37:40 +00:00
resp, err := http.Get(server.URL + "/apis/company.com/" + version + "/namespaces/default/foos/test")
2015-09-03 17:35:04 +00:00
if !assert.NoError(err) {
return
}
2015-09-03 17:35:04 +00:00
assert.Equal(http.StatusOK, resp.StatusCode)
item := Foo{}
2015-09-03 17:35:04 +00:00
assert.NoError(decodeResponse(resp, &item))
if !assert.False(reflect.DeepEqual(item, expectedObj)) {
t.Errorf("expected objects to not be equal:\n%v\nsaw:\n%v\n", expectedObj, item)
}
// Fill in data that the apiserver injects
expectedObj.SelfLink = item.SelfLink
expectedObj.ResourceVersion = item.ResourceVersion
2015-09-03 17:35:04 +00:00
if !assert.True(reflect.DeepEqual(item, expectedObj)) {
t.Errorf("expected:\n%#v\nsaw:\n%#v\n", expectedObj, item)
}
}
func TestInstallThirdPartyAPIPost(t *testing.T) {
2015-09-01 05:28:08 +00:00
for _, version := range versionsToTest {
testInstallThirdPartyAPIPostForVersion(t, version)
}
}
func testInstallThirdPartyAPIPostForVersion(t *testing.T, version string) {
master, etcdserver, server, assert := initThirdParty(t, version)
defer server.Close()
defer etcdserver.Terminate(t)
inputObj := Foo{
ObjectMeta: api.ObjectMeta{
Name: "test",
},
TypeMeta: unversioned.TypeMeta{
2015-09-01 05:28:08 +00:00
Kind: "Foo",
APIVersion: "company.com/" + version,
},
SomeField: "test field",
OtherField: 10,
}
2015-08-21 21:24:16 +00:00
data, err := json.Marshal(inputObj)
2015-09-03 17:35:04 +00:00
if !assert.NoError(err) {
return
}
2015-09-14 20:37:40 +00:00
resp, err := http.Post(server.URL+"/apis/company.com/"+version+"/namespaces/default/foos", "application/json", bytes.NewBuffer(data))
2015-09-03 17:35:04 +00:00
if !assert.NoError(err) {
2015-09-14 20:37:40 +00:00
t.Errorf("unexpected error: %v", err)
return
}
2015-09-03 17:35:04 +00:00
assert.Equal(http.StatusCreated, resp.StatusCode)
item := Foo{}
2015-09-03 17:35:04 +00:00
assert.NoError(decodeResponse(resp, &item))
// fill in fields set by the apiserver
expectedObj := inputObj
expectedObj.SelfLink = item.SelfLink
expectedObj.ResourceVersion = item.ResourceVersion
expectedObj.Namespace = item.Namespace
expectedObj.UID = item.UID
expectedObj.CreationTimestamp = item.CreationTimestamp
2015-09-03 17:35:04 +00:00
if !assert.True(reflect.DeepEqual(item, expectedObj)) {
t.Errorf("expected:\n%v\nsaw:\n%v\n", expectedObj, item)
}
thirdPartyObj := extensions.ThirdPartyResourceData{}
err = master.thirdPartyStorage.Get(
context.TODO(), etcdtest.AddPrefix("/ThirdPartyResourceData/company.com/foos/default/test"),
&thirdPartyObj, false)
2015-09-03 17:35:04 +00:00
if !assert.NoError(err) {
2015-09-01 05:28:08 +00:00
t.FailNow()
}
2015-09-03 17:35:04 +00:00
item = Foo{}
2015-09-03 17:35:04 +00:00
assert.NoError(json.Unmarshal(thirdPartyObj.Data, &item))
2015-09-03 17:35:04 +00:00
if !assert.True(reflect.DeepEqual(item, inputObj)) {
t.Errorf("expected:\n%v\nsaw:\n%v\n", inputObj, item)
}
}
func TestInstallThirdPartyAPIDelete(t *testing.T) {
2015-09-01 05:28:08 +00:00
for _, version := range versionsToTest {
testInstallThirdPartyAPIDeleteVersion(t, version)
}
}
func testInstallThirdPartyAPIDeleteVersion(t *testing.T, version string) {
master, etcdserver, server, assert := initThirdParty(t, version)
defer server.Close()
defer etcdserver.Terminate(t)
expectedObj := Foo{
ObjectMeta: api.ObjectMeta{
Name: "test",
Namespace: "default",
},
TypeMeta: unversioned.TypeMeta{
2015-08-21 21:24:16 +00:00
Kind: "Foo",
},
SomeField: "test field",
OtherField: 10,
}
if !assert.NoError(storeThirdPartyObject(master.thirdPartyStorage, "/ThirdPartyResourceData/company.com/foos/default/test", "test", expectedObj)) {
t.FailNow()
return
}
2015-09-14 20:37:40 +00:00
resp, err := http.Get(server.URL + "/apis/company.com/" + version + "/namespaces/default/foos/test")
2015-09-03 17:35:04 +00:00
if !assert.NoError(err) {
return
}
2015-09-03 17:35:04 +00:00
assert.Equal(http.StatusOK, resp.StatusCode)
item := Foo{}
2015-09-03 17:35:04 +00:00
assert.NoError(decodeResponse(resp, &item))
// Fill in fields set by the apiserver
expectedObj.SelfLink = item.SelfLink
expectedObj.ResourceVersion = item.ResourceVersion
expectedObj.Namespace = item.Namespace
2015-09-03 17:35:04 +00:00
if !assert.True(reflect.DeepEqual(item, expectedObj)) {
t.Errorf("expected:\n%v\nsaw:\n%v\n", expectedObj, item)
}
2015-09-14 20:37:40 +00:00
resp, err = httpDelete(server.URL + "/apis/company.com/" + version + "/namespaces/default/foos/test")
2015-09-03 17:35:04 +00:00
if !assert.NoError(err) {
return
}
2015-09-03 17:35:04 +00:00
assert.Equal(http.StatusOK, resp.StatusCode)
2015-09-14 20:37:40 +00:00
resp, err = http.Get(server.URL + "/apis/company.com/" + version + "/namespaces/default/foos/test")
2015-09-03 17:35:04 +00:00
if !assert.NoError(err) {
return
}
2015-09-03 17:35:04 +00:00
assert.Equal(http.StatusNotFound, resp.StatusCode)
expectedDeletedKey := etcdtest.AddPrefix("ThirdPartyResourceData/company.com/foos/default/test")
thirdPartyObj := extensions.ThirdPartyResourceData{}
err = master.thirdPartyStorage.Get(
context.TODO(), expectedDeletedKey, &thirdPartyObj, false)
if !storage.IsNotFound(err) {
t.Errorf("expected deletion didn't happen: %v", err)
}
}
func httpDelete(url string) (*http.Response, error) {
req, err := http.NewRequest("DELETE", url, nil)
if err != nil {
return nil, err
2015-08-19 18:02:01 +00:00
}
client := &http.Client{}
return client.Do(req)
2015-08-19 18:02:01 +00:00
}
func TestInstallThirdPartyResourceRemove(t *testing.T) {
for _, version := range versionsToTest {
testInstallThirdPartyResourceRemove(t, version)
}
}
func testInstallThirdPartyResourceRemove(t *testing.T, version string) {
master, etcdserver, server, assert := initThirdParty(t, version)
defer server.Close()
defer etcdserver.Terminate(t)
expectedObj := Foo{
ObjectMeta: api.ObjectMeta{
Name: "test",
},
TypeMeta: unversioned.TypeMeta{
Kind: "Foo",
},
SomeField: "test field",
OtherField: 10,
}
if !assert.NoError(storeThirdPartyObject(master.thirdPartyStorage, "/ThirdPartyResourceData/company.com/foos/default/test", "test", expectedObj)) {
t.FailNow()
return
}
secondObj := expectedObj
secondObj.Name = "bar"
if !assert.NoError(storeThirdPartyObject(master.thirdPartyStorage, "/ThirdPartyResourceData/company.com/foos/default/bar", "bar", secondObj)) {
t.FailNow()
return
}
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)
}
expectedDeletedKeys := []string{
etcdtest.AddPrefix("/ThirdPartyResourceData/company.com/foos/default/test"),
etcdtest.AddPrefix("/ThirdPartyResourceData/company.com/foos/default/bar"),
}
for _, key := range expectedDeletedKeys {
thirdPartyObj := extensions.ThirdPartyResourceData{}
err := master.thirdPartyStorage.Get(context.TODO(), key, &thirdPartyObj, false)
if !storage.IsNotFound(err) {
t.Errorf("expected deletion didn't happen: %v", err)
}
}
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])
}
}
}