2014-11-02 20:52:31 +00:00
/ *
2015-05-01 16:19:44 +00:00
Copyright 2014 The Kubernetes Authors All rights reserved .
2014-11-02 20:52:31 +00:00
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 (
2015-08-20 05:08:26 +00:00
"bytes"
2015-10-09 05:18:16 +00:00
"crypto/tls"
2015-08-20 05:08:26 +00:00
"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"
2015-08-20 05:08:26 +00:00
"reflect"
2015-09-09 21:36:19 +00:00
"strings"
2014-11-02 20:52:31 +00:00
"testing"
2015-08-05 22:03:47 +00:00
"k8s.io/kubernetes/pkg/api"
2016-05-09 21:47:02 +00:00
"k8s.io/kubernetes/pkg/api/meta"
2015-09-11 00:20:53 +00:00
"k8s.io/kubernetes/pkg/api/testapi"
2015-09-09 21:59:11 +00:00
"k8s.io/kubernetes/pkg/api/unversioned"
2016-04-07 22:34:40 +00:00
apiv1 "k8s.io/kubernetes/pkg/api/v1"
2016-03-16 14:17:04 +00:00
"k8s.io/kubernetes/pkg/apimachinery/registered"
2016-04-15 22:30:15 +00:00
"k8s.io/kubernetes/pkg/apis/apps"
appsapi "k8s.io/kubernetes/pkg/apis/apps"
2016-02-08 14:03:59 +00:00
"k8s.io/kubernetes/pkg/apis/autoscaling"
2016-04-07 22:34:40 +00:00
autoscalingapiv1 "k8s.io/kubernetes/pkg/apis/autoscaling/v1"
2016-02-17 22:06:35 +00:00
"k8s.io/kubernetes/pkg/apis/batch"
2016-04-07 22:34:40 +00:00
batchapiv1 "k8s.io/kubernetes/pkg/apis/batch/v1"
2016-04-28 12:41:45 +00:00
batchapiv2alpha1 "k8s.io/kubernetes/pkg/apis/batch/v2alpha1"
2015-10-09 22:04:41 +00:00
"k8s.io/kubernetes/pkg/apis/extensions"
2016-04-07 22:34:40 +00:00
extensionsapiv1beta1 "k8s.io/kubernetes/pkg/apis/extensions/v1beta1"
2016-05-25 21:20:41 +00:00
"k8s.io/kubernetes/pkg/apis/rbac"
2016-04-20 04:11:39 +00:00
"k8s.io/kubernetes/pkg/apiserver"
2015-11-16 21:46:00 +00:00
"k8s.io/kubernetes/pkg/genericapiserver"
2015-10-27 13:18:45 +00:00
"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"
2016-05-09 21:47:02 +00:00
"k8s.io/kubernetes/pkg/registry/thirdpartyresourcedata"
2015-11-20 08:16:41 +00:00
"k8s.io/kubernetes/pkg/runtime"
"k8s.io/kubernetes/pkg/storage"
2015-11-10 11:23:51 +00:00
"k8s.io/kubernetes/pkg/storage/etcd/etcdtest"
2015-11-17 13:35:00 +00:00
etcdtesting "k8s.io/kubernetes/pkg/storage/etcd/testing"
2016-04-20 04:11:39 +00:00
"k8s.io/kubernetes/pkg/storage/storagebackend"
2015-11-10 06:28:45 +00:00
"k8s.io/kubernetes/pkg/util/intstr"
2016-04-20 04:11:39 +00:00
utilnet "k8s.io/kubernetes/pkg/util/net"
"k8s.io/kubernetes/pkg/util/sets"
2015-09-09 21:36:19 +00:00
"github.com/stretchr/testify/assert"
2015-11-20 08:16:41 +00:00
"golang.org/x/net/context"
2014-11-02 20:52:31 +00:00
)
2015-09-03 17:35:04 +00:00
// setUp is a convience function for setting up for (most) tests.
2016-03-23 23:45:24 +00:00
func setUp ( t * testing . T ) ( * Master , * etcdtesting . EtcdTestServer , Config , * assert . Assertions ) {
2015-11-17 13:35:00 +00:00
server := etcdtesting . NewEtcdTestClientServer ( t )
2016-03-23 23:45:24 +00:00
master := & Master {
2015-11-16 21:46:00 +00:00
GenericAPIServer : & genericapiserver . GenericAPIServer { } ,
}
config := Config {
Config : & genericapiserver . Config { } ,
}
2016-03-16 14:17:04 +00:00
2016-04-20 04:11:39 +00:00
storageConfig := storagebackend . Config {
2016-03-16 14:17:04 +00:00
Prefix : etcdtest . PathPrefix ( ) ,
CAFile : server . CAFile ,
KeyFile : server . KeyFile ,
CertFile : server . CertFile ,
}
for _ , url := range server . ClientURLs {
2016-04-20 04:11:39 +00:00
storageConfig . ServerList = append ( storageConfig . ServerList , url . String ( ) )
2016-03-16 14:17:04 +00:00
}
resourceEncoding := genericapiserver . NewDefaultResourceEncodingConfig ( )
resourceEncoding . SetVersionEncoding ( api . GroupName , * testapi . Default . GroupVersion ( ) , unversioned . GroupVersion { Group : api . GroupName , Version : runtime . APIVersionInternal } )
resourceEncoding . SetVersionEncoding ( autoscaling . GroupName , * testapi . Autoscaling . GroupVersion ( ) , unversioned . GroupVersion { Group : autoscaling . GroupName , Version : runtime . APIVersionInternal } )
resourceEncoding . SetVersionEncoding ( batch . GroupName , * testapi . Batch . GroupVersion ( ) , unversioned . GroupVersion { Group : batch . GroupName , Version : runtime . APIVersionInternal } )
resourceEncoding . SetVersionEncoding ( apps . GroupName , * testapi . Apps . GroupVersion ( ) , unversioned . GroupVersion { Group : apps . GroupName , Version : runtime . APIVersionInternal } )
resourceEncoding . SetVersionEncoding ( extensions . GroupName , * testapi . Extensions . GroupVersion ( ) , unversioned . GroupVersion { Group : extensions . GroupName , Version : runtime . APIVersionInternal } )
2016-05-25 21:20:41 +00:00
resourceEncoding . SetVersionEncoding ( rbac . GroupName , * testapi . Rbac . GroupVersion ( ) , unversioned . GroupVersion { Group : rbac . GroupName , Version : runtime . APIVersionInternal } )
2016-04-23 19:00:28 +00:00
storageFactory := genericapiserver . NewDefaultStorageFactory ( storageConfig , testapi . StorageMediaType ( ) , api . Codecs , resourceEncoding , DefaultAPIResourceConfigSource ( ) )
2016-03-16 14:17:04 +00:00
config . StorageFactory = storageFactory
config . APIResourceConfigSource = DefaultAPIResourceConfigSource ( )
2015-11-12 06:52:24 +00:00
config . PublicAddress = net . ParseIP ( "192.168.10.4" )
2015-12-21 05:27:49 +00:00
config . Serializer = api . Codecs
2015-09-03 17:35:04 +00:00
config . KubeletClient = client . FakeKubeletClient { }
2016-02-03 01:29:17 +00:00
config . APIPrefix = "/api"
config . APIGroupPrefix = "/apis"
2016-03-22 16:45:23 +00:00
config . APIResourceConfigSource = DefaultAPIResourceConfigSource ( )
2015-10-09 05:18:16 +00:00
config . ProxyDialer = func ( network , addr string ) ( net . Conn , error ) { return nil , nil }
config . ProxyTLSClientConfig = & tls . Config { }
2016-03-24 22:44:31 +00:00
// TODO: this is kind of hacky. The trouble is that the sync loop
// runs in a go-routine and there is no way to validate in the test
// that the sync routine has actually run. The right answer here
// is probably to add some sort of callback that we can register
// to validate that it's actually been run, but for now we don't
// run the sync routine and register types manually.
2016-03-10 04:06:31 +00:00
config . disableThirdPartyControllerForTesting = true
2016-04-07 22:34:40 +00:00
master . nodeRegistry = registrytest . NewNodeRegistry ( [ ] string { "node1" , "node2" } , api . NodeResources { } )
return master , server , config , assert . New ( t )
}
func newMaster ( t * testing . T ) ( * Master , * etcdtesting . EtcdTestServer , Config , * assert . Assertions ) {
_ , etcdserver , config , assert := setUp ( t )
master , err := New ( & config )
if err != nil {
t . Fatalf ( "Error in bringing up the master: %v" , err )
}
return master , etcdserver , config , assert
}
// limitedAPIResourceConfigSource only enables the core group, the extensions group, the batch group, and the autoscaling group.
func limitedAPIResourceConfigSource ( ) * genericapiserver . ResourceConfig {
ret := genericapiserver . NewResourceConfig ( )
2016-04-28 12:41:45 +00:00
ret . EnableVersions ( apiv1 . SchemeGroupVersion , extensionsapiv1beta1 . SchemeGroupVersion ,
batchapiv1 . SchemeGroupVersion , batchapiv2alpha1 . SchemeGroupVersion ,
appsapi . SchemeGroupVersion , autoscalingapiv1 . SchemeGroupVersion )
2016-04-07 22:34:40 +00:00
return ret
}
// newLimitedMaster only enables the core group, the extensions group, the batch group, and the autoscaling group.
func newLimitedMaster ( t * testing . T ) ( * Master , * etcdtesting . EtcdTestServer , Config , * assert . Assertions ) {
_ , etcdserver , config , assert := setUp ( t )
config . APIResourceConfigSource = limitedAPIResourceConfigSource ( )
2016-02-03 22:26:11 +00:00
master , err := New ( & config )
if err != nil {
t . Fatalf ( "Error in bringing up the master: %v" , err )
}
2015-11-16 21:46:00 +00:00
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 )
2015-10-09 05:18:16 +00:00
assert . Equal ( master . tunneler , config . Tunneler )
2015-12-22 21:22:28 +00:00
assert . Equal ( master . APIPrefix , config . APIPrefix )
assert . Equal ( master . APIGroupPrefix , config . APIGroupPrefix )
2015-11-16 21:46:00 +00:00
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 )
2015-10-09 05:18:16 +00:00
// These functions should point to the same memory location
2016-01-06 15:56:41 +00:00
masterDialer , _ := utilnet . Dialer ( master . ProxyTransport )
2015-10-09 05:18:16 +00:00
masterDialerFunc := fmt . Sprintf ( "%p" , masterDialer )
configDialerFunc := fmt . Sprintf ( "%p" , config . ProxyDialer )
assert . Equal ( masterDialerFunc , configDialerFunc )
2015-11-16 21:46:00 +00:00
assert . Equal ( master . ProxyTransport . ( * http . Transport ) . TLSClientConfig , config . ProxyTLSClientConfig )
2015-09-03 17:35:04 +00:00
}
2016-03-13 03:46:20 +00:00
// TestNamespaceSubresources ensures the namespace subresource parsing in apiserver/handlers.go doesn't drift
func TestNamespaceSubresources ( t * testing . T ) {
master , etcdserver , _ , _ := newMaster ( t )
defer etcdserver . Terminate ( t )
expectedSubresources := apiserver . NamespaceSubResourcesForTest
foundSubresources := sets . NewString ( )
for k := range master . v1ResourcesStorage {
parts := strings . Split ( k , "/" )
if len ( parts ) == 2 && parts [ 0 ] == "namespaces" {
foundSubresources . Insert ( parts [ 1 ] )
}
}
if ! reflect . DeepEqual ( expectedSubresources . List ( ) , foundSubresources . List ( ) ) {
t . Errorf ( "Expected namespace subresources %#v, got %#v. Update apiserver/handlers.go#namespaceSubresources" , expectedSubresources . List ( ) , foundSubresources . List ( ) )
}
}
2015-09-03 17:35:04 +00:00
// TestGetServersToValidate verifies the unexported getServersToValidate function
func TestGetServersToValidate ( t * testing . T ) {
2015-11-17 13:35:00 +00:00
master , etcdserver , config , assert := setUp ( t )
defer etcdserver . Terminate ( t )
2015-05-14 00:29:25 +00:00
servers := master . getServersToValidate ( & config )
2015-05-04 21:17:35 +00:00
2015-11-17 13:35:00 +00:00
// 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
2015-11-17 13:35:00 +00:00
for _ , server := range [ ] string { "scheduler" , "controller-manager" , "etcd-0" } {
2015-05-04 21:17:35 +00:00
if _ , ok := servers [ server ] ; ! ok {
t . Errorf ( "server list missing: %s" , server )
}
}
2014-11-02 20:52:31 +00:00
}
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
2015-11-17 13:35:00 +00:00
master , etcdserver , _ , assert := setUp ( t )
defer etcdserver . Terminate ( t )
2016-01-06 15:56:41 +00:00
portRange := utilnet . PortRange { Base : 10 , Size : 10 }
2015-09-03 17:35:04 +00:00
master . namespaceRegistry = namespace . NewRegistry ( nil )
master . serviceRegistry = registrytest . NewServiceRegistry ( )
master . endpointRegistry = endpoint . NewRegistry ( nil )
2015-11-16 21:46:00 +00:00
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 )
2016-06-06 21:48:22 +00:00
assert . Equal ( controller . EndpointReconciler , NewMasterCountEndpointReconciler ( master . MasterCount , master . endpointRegistry ) )
2015-09-03 17:35:04 +00:00
assert . Equal ( controller . ServiceRegistry , master . serviceRegistry )
assert . Equal ( controller . ServiceNodePortRange , portRange )
2015-11-16 21:46:00 +00:00
assert . Equal ( controller . ServicePort , master . ServiceReadWritePort )
assert . Equal ( controller . PublicServicePort , master . PublicReadWritePort )
2015-09-03 17:35:04 +00:00
}
2015-10-07 15:06:05 +00:00
// TestControllerServicePorts verifies master extraServicePorts are
// correctly copied into controller
func TestControllerServicePorts ( t * testing . T ) {
2015-11-17 13:35:00 +00:00
master , etcdserver , _ , assert := setUp ( t )
defer etcdserver . Terminate ( t )
2015-10-07 15:06:05 +00:00
master . namespaceRegistry = namespace . NewRegistry ( nil )
master . serviceRegistry = registrytest . NewServiceRegistry ( )
master . endpointRegistry = endpoint . NewRegistry ( nil )
2015-11-16 21:46:00 +00:00
master . ExtraServicePorts = [ ] api . ServicePort {
2015-10-07 15:06:05 +00:00
{
Name : "additional-port-1" ,
Port : 1000 ,
Protocol : api . ProtocolTCP ,
2015-11-10 06:28:45 +00:00
TargetPort : intstr . FromInt ( 1000 ) ,
2015-10-07 15:06:05 +00:00
} ,
{
Name : "additional-port-2" ,
Port : 1010 ,
Protocol : api . ProtocolTCP ,
2015-11-10 06:28:45 +00:00
TargetPort : intstr . FromInt ( 1010 ) ,
2015-10-07 15:06:05 +00:00
} ,
}
controller := master . NewBootstrapController ( )
2016-04-27 04:35:14 +00:00
assert . Equal ( int32 ( 1000 ) , controller . ExtraServicePorts [ 0 ] . Port )
assert . Equal ( int32 ( 1010 ) , controller . ExtraServicePorts [ 1 ] . Port )
2015-10-07 15:06:05 +00:00
}
2015-09-03 17:35:04 +00:00
// TestGetNodeAddresses verifies that proper results are returned
// when requesting node addresses.
func TestGetNodeAddresses ( t * testing . T ) {
2015-11-17 13:35:00 +00:00
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 )
}
2016-02-12 01:03:43 +00:00
// Because we need to be backwards compatible with release 1.1, at endpoints
// that exist in release 1.1, the responses should have empty APIVersion.
func TestAPIVersionOfDiscoveryEndpoints ( t * testing . T ) {
master , etcdserver , _ , assert := newMaster ( t )
defer etcdserver . Terminate ( t )
server := httptest . NewServer ( master . HandlerContainer . ServeMux )
// /api exists in release-1.1
resp , err := http . Get ( server . URL + "/api" )
if err != nil {
t . Errorf ( "unexpected error: %v" , err )
}
apiVersions := unversioned . APIVersions { }
assert . NoError ( decodeResponse ( resp , & apiVersions ) )
assert . Equal ( apiVersions . APIVersion , "" )
// /api/v1 exists in release-1.1
resp , err = http . Get ( server . URL + "/api/v1" )
if err != nil {
t . Errorf ( "unexpected error: %v" , err )
}
resourceList := unversioned . APIResourceList { }
assert . NoError ( decodeResponse ( resp , & resourceList ) )
assert . Equal ( resourceList . APIVersion , "" )
// /apis exists in release-1.1
resp , err = http . Get ( server . URL + "/apis" )
if err != nil {
t . Errorf ( "unexpected error: %v" , err )
}
groupList := unversioned . APIGroupList { }
assert . NoError ( decodeResponse ( resp , & groupList ) )
assert . Equal ( groupList . APIVersion , "" )
// /apis/extensions exists in release-1.1
resp , err = http . Get ( server . URL + "/apis/extensions" )
if err != nil {
t . Errorf ( "unexpected error: %v" , err )
}
group := unversioned . APIGroup { }
assert . NoError ( decodeResponse ( resp , & group ) )
assert . Equal ( group . APIVersion , "" )
// /apis/extensions/v1beta1 exists in release-1.1
resp , err = http . Get ( server . URL + "/apis/extensions/v1beta1" )
if err != nil {
t . Errorf ( "unexpected error: %v" , err )
}
resourceList = unversioned . APIResourceList { }
assert . NoError ( decodeResponse ( resp , & resourceList ) )
assert . Equal ( resourceList . APIVersion , "" )
// /apis/autoscaling doesn't exist in release-1.1, so the APIVersion field
// should be non-empty in the results returned by the server.
resp , err = http . Get ( server . URL + "/apis/autoscaling" )
if err != nil {
t . Errorf ( "unexpected error: %v" , err )
}
group = unversioned . APIGroup { }
assert . NoError ( decodeResponse ( resp , & group ) )
assert . Equal ( group . APIVersion , "v1" )
// apis/autoscaling/v1 doesn't exist in release-1.1, so the APIVersion field
// should be non-empty in the results returned by the server.
resp , err = http . Get ( server . URL + "/apis/autoscaling/v1" )
if err != nil {
t . Errorf ( "unexpected error: %v" , err )
}
resourceList = unversioned . APIResourceList { }
assert . NoError ( decodeResponse ( resp , & resourceList ) )
assert . Equal ( resourceList . APIVersion , "v1" )
}
2015-09-28 18:08:47 +00:00
func TestDiscoveryAtAPIS ( t * testing . T ) {
2016-03-16 14:17:04 +00:00
master , etcdserver , _ , assert := newLimitedMaster ( t )
2016-04-07 22:34:40 +00:00
defer etcdserver . Terminate ( t )
2015-09-28 18:08:47 +00:00
2016-04-07 22:34:40 +00:00
server := httptest . NewServer ( master . HandlerContainer . ServeMux )
resp , err := http . Get ( server . URL + "/apis" )
if ! assert . NoError ( err ) {
t . Errorf ( "unexpected error: %v" , err )
}
2015-09-28 18:08:47 +00:00
2016-04-07 22:34:40 +00:00
assert . Equal ( http . StatusOK , resp . StatusCode )
2015-09-28 18:08:47 +00:00
2016-04-07 22:34:40 +00:00
groupList := unversioned . APIGroupList { }
assert . NoError ( decodeResponse ( resp , & groupList ) )
if err != nil {
t . Fatalf ( "unexpected error: %v" , err )
}
2016-04-15 22:30:15 +00:00
expectGroupNames := sets . NewString ( autoscaling . GroupName , batch . GroupName , apps . GroupName , extensions . GroupName )
2016-04-07 22:34:40 +00:00
expectVersions := map [ string ] [ ] unversioned . GroupVersionForDiscovery {
autoscaling . GroupName : {
2016-02-19 18:31:12 +00:00
{
2016-04-07 22:34:40 +00:00
GroupVersion : testapi . Autoscaling . GroupVersion ( ) . String ( ) ,
Version : testapi . Autoscaling . GroupVersion ( ) . Version ,
2016-02-19 18:31:12 +00:00
} ,
2016-04-07 22:34:40 +00:00
} ,
2016-05-17 08:52:07 +00:00
// batch is using its pkg/apis/batch/ types here since during installation
// both versions get installed and testapi.go currently does not support
// multi-versioned clients
batch . GroupName : {
{
GroupVersion : batchapiv1 . SchemeGroupVersion . String ( ) ,
Version : batchapiv1 . SchemeGroupVersion . Version ,
} ,
{
GroupVersion : batchapiv2alpha1 . SchemeGroupVersion . String ( ) ,
Version : batchapiv2alpha1 . SchemeGroupVersion . Version ,
} ,
} ,
2016-04-15 22:30:15 +00:00
apps . GroupName : {
{
GroupVersion : testapi . Apps . GroupVersion ( ) . String ( ) ,
Version : testapi . Apps . GroupVersion ( ) . Version ,
} ,
} ,
2016-04-07 22:34:40 +00:00
extensions . GroupName : {
2016-02-19 18:31:12 +00:00
{
2016-04-07 22:34:40 +00:00
GroupVersion : testapi . Extensions . GroupVersion ( ) . String ( ) ,
Version : testapi . Extensions . GroupVersion ( ) . Version ,
2016-02-19 18:31:12 +00:00
} ,
2016-04-07 22:34:40 +00:00
} ,
}
expectPreferredVersion := map [ string ] unversioned . GroupVersionForDiscovery {
autoscaling . GroupName : {
2016-03-16 14:17:04 +00:00
GroupVersion : registered . GroupOrDie ( autoscaling . GroupName ) . GroupVersion . String ( ) ,
Version : registered . GroupOrDie ( autoscaling . GroupName ) . GroupVersion . Version ,
2016-04-07 22:34:40 +00:00
} ,
batch . GroupName : {
2016-03-16 14:17:04 +00:00
GroupVersion : registered . GroupOrDie ( batch . GroupName ) . GroupVersion . String ( ) ,
Version : registered . GroupOrDie ( batch . GroupName ) . GroupVersion . Version ,
2016-04-07 22:34:40 +00:00
} ,
2016-04-15 22:30:15 +00:00
apps . GroupName : {
2016-03-16 14:17:04 +00:00
GroupVersion : registered . GroupOrDie ( apps . GroupName ) . GroupVersion . String ( ) ,
Version : registered . GroupOrDie ( apps . GroupName ) . GroupVersion . Version ,
2016-04-15 22:30:15 +00:00
} ,
2016-04-07 22:34:40 +00:00
extensions . GroupName : {
2016-03-16 14:17:04 +00:00
GroupVersion : registered . GroupOrDie ( extensions . GroupName ) . GroupVersion . String ( ) ,
Version : registered . GroupOrDie ( extensions . GroupName ) . GroupVersion . Version ,
2016-04-07 22:34:40 +00:00
} ,
}
2015-12-10 00:35:35 +00:00
2016-04-07 22:34:40 +00:00
assert . Equal ( 3 , len ( groupList . Groups ) )
for _ , group := range groupList . Groups {
if ! expectGroupNames . Has ( group . Name ) {
t . Errorf ( "got unexpected group %s" , group . Name )
}
assert . Equal ( expectVersions [ group . Name ] , group . Versions )
assert . Equal ( expectPreferredVersion [ group . Name ] , group . PreferredVersion )
}
2015-12-10 00:35:35 +00:00
2016-04-07 22:34:40 +00:00
thirdPartyGV := unversioned . GroupVersionForDiscovery { GroupVersion : "company.com/v1" , Version : "v1" }
master . addThirdPartyResourceStorage ( "/apis/company.com/v1" , nil ,
unversioned . APIGroup {
Name : "company.com" ,
Versions : [ ] unversioned . GroupVersionForDiscovery { thirdPartyGV } ,
PreferredVersion : thirdPartyGV ,
} )
2015-12-10 00:35:35 +00:00
2016-04-07 22:34:40 +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 )
assert . NoError ( decodeResponse ( resp , & groupList ) )
if err != nil {
t . Fatalf ( "unexpected error: %v" , err )
}
2015-12-10 00:35:35 +00:00
2016-04-07 22:34:40 +00:00
assert . Equal ( 4 , len ( groupList . Groups ) )
2015-12-10 00:35:35 +00:00
2016-04-07 22:34:40 +00:00
expectGroupNames . Insert ( "company.com" )
expectVersions [ "company.com" ] = [ ] unversioned . GroupVersionForDiscovery { thirdPartyGV }
expectPreferredVersion [ "company.com" ] = thirdPartyGV
for _ , group := range groupList . Groups {
if ! expectGroupNames . Has ( group . Name ) {
t . Errorf ( "got unexpected group %s" , group . Name )
2016-02-19 18:31:12 +00:00
}
2016-04-07 22:34:40 +00:00
assert . Equal ( expectVersions [ group . Name ] , group . Versions )
assert . Equal ( expectPreferredVersion [ group . Name ] , group . PreferredVersion )
}
2015-09-28 18:08:47 +00:00
}
2015-09-01 05:28:08 +00:00
var versionsToTest = [ ] string { "v1" , "v3" }
2015-08-20 05:08:26 +00:00
type Foo struct {
2015-09-09 21:59:11 +00:00
unversioned . TypeMeta ` json:",inline" `
api . ObjectMeta ` json:"metadata,omitempty" description:"standard object metadata" `
2015-08-20 05:08:26 +00:00
SomeField string ` json:"someField" `
OtherField int ` json:"otherField" `
}
type FooList struct {
2015-09-09 21:59:11 +00:00
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" `
2015-08-20 05:08:26 +00:00
2015-09-09 21:36:19 +00:00
Items [ ] Foo ` json:"items" `
2015-08-20 05:08:26 +00:00
}
2016-05-09 21:47:02 +00:00
func initThirdParty ( t * testing . T , version , name string ) ( * Master , * etcdtesting . EtcdTestServer , * httptest . Server , * assert . Assertions ) {
2016-02-03 01:29:17 +00:00
master , etcdserver , _ , assert := newMaster ( t )
2015-10-09 22:49:10 +00:00
api := & extensions . ThirdPartyResource {
2015-08-19 18:02:01 +00:00
ObjectMeta : api . ObjectMeta {
2016-05-09 21:47:02 +00:00
Name : name ,
2015-08-19 18:02:01 +00:00
} ,
2015-10-09 22:49:10 +00:00
Versions : [ ] extensions . APIVersion {
2015-08-20 05:08:26 +00:00
{
2016-03-10 04:06:31 +00:00
Name : version ,
2015-08-19 18:02:01 +00:00
} ,
} ,
}
2016-02-04 05:55:04 +00:00
_ , master . ServiceClusterIPRange , _ = net . ParseCIDR ( "10.0.0.0/24" )
2015-08-20 05:08:26 +00:00
2015-09-09 21:36:19 +00:00
if ! assert . NoError ( master . InstallThirdPartyResource ( api ) ) {
2015-08-20 05:08:26 +00:00
t . FailNow ( )
2015-08-19 18:02:01 +00:00
}
2015-08-20 05:08:26 +00:00
2015-11-16 21:46:00 +00:00
server := httptest . NewServer ( master . HandlerContainer . ServeMux )
2016-02-03 01:29:17 +00:00
return master , etcdserver , server , assert
2015-08-20 05:08:26 +00:00
}
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 ) {
2015-09-09 21:36:19 +00:00
tests := [ ] struct {
items [ ] Foo
2016-05-09 21:47:02 +00:00
name string
test string
2015-09-09 21:36:19 +00:00
} {
2016-05-09 21:47:02 +00:00
{
name : "foo.company.com" ,
test : "null" ,
} ,
2015-09-09 21:36:19 +00:00
{
items : [ ] Foo { } ,
2016-05-09 21:47:02 +00:00
name : "foo.company.com" ,
test : "empty" ,
} ,
{
items : [ ] Foo { } ,
name : "policy.company.com" ,
test : "plurals" ,
2015-09-09 21:36:19 +00:00
} ,
{
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 ,
} ,
} ,
2016-05-09 21:47:02 +00:00
name : "foo.company.com" ,
test : "real list" ,
2015-09-09 21:36:19 +00:00
} ,
}
for _ , test := range tests {
2015-11-17 14:21:42 +00:00
func ( ) {
2016-05-09 21:47:02 +00:00
master , etcdserver , server , assert := initThirdParty ( t , version , test . name )
2016-04-21 11:50:55 +00:00
defer server . Close ( )
2015-11-17 14:21:42 +00:00
defer etcdserver . Terminate ( t )
2016-05-09 21:47:02 +00:00
kind , group , err := thirdpartyresourcedata . ExtractApiGroupAndKind (
& extensions . ThirdPartyResource { ObjectMeta : api . ObjectMeta { Name : test . name } } )
assert . NoError ( err , test . test )
plural , _ := meta . KindToResource ( unversioned . GroupVersionKind {
Group : group ,
Version : version ,
Kind : kind ,
} )
2015-11-17 14:21:42 +00:00
if test . items != nil {
2016-05-09 21:47:02 +00:00
err := createThirdPartyList ( master . thirdPartyStorage ,
fmt . Sprintf ( "/ThirdPartyResourceData/%s/%s/default" , group , plural . Resource ) ,
test . items )
if ! assert . NoError ( err , test . test ) {
2016-03-10 04:06:31 +00:00
return
}
2015-11-17 14:21:42 +00:00
}
2015-08-20 05:08:26 +00:00
2016-05-09 21:47:02 +00:00
resp , err := http . Get (
fmt . Sprintf ( "%s/apis/%s/%s/namespaces/default/%s" , server . URL , group , version , plural . Resource ) )
if ! assert . NoError ( err , test . test ) {
2015-11-17 14:21:42 +00:00
return
}
defer resp . Body . Close ( )
2015-09-03 17:35:04 +00:00
2016-05-09 21:47:02 +00:00
assert . Equal ( http . StatusOK , resp . StatusCode , test . test )
2015-08-20 05:08:26 +00:00
2015-11-17 14:21:42 +00:00
data , err := ioutil . ReadAll ( resp . Body )
2016-05-09 21:47:02 +00:00
assert . NoError ( err , test . test )
2015-08-20 05:08:26 +00:00
2015-11-17 14:21:42 +00:00
list := FooList { }
if err = json . Unmarshal ( data , & list ) ; err != nil {
2016-05-09 21:47:02 +00:00
assert . NoError ( err , "unexpected error: %v %s" , err , test . test )
2015-11-17 14:21:42 +00:00
}
2015-08-20 05:08:26 +00:00
2015-11-17 14:21:42 +00:00
if test . items == nil {
if len ( list . Items ) != 0 {
2016-05-09 21:47:02 +00:00
assert . NoError ( err , "expected no items, saw: %v %s" , err , list . Items , test . test )
2015-11-17 14:21:42 +00:00
}
return
2015-09-09 21:36:19 +00:00
}
2015-09-03 17:35:04 +00:00
2015-11-17 14:21:42 +00:00
if len ( list . Items ) != len ( test . items ) {
2016-05-09 21:47:02 +00:00
t . Fatalf ( "(%s) unexpected length: %d vs %d" , test . name , len ( list . Items ) , len ( test . items ) )
2015-09-09 21:36:19 +00:00
}
2015-11-17 14:21:42 +00:00
// 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 ) {
2016-05-09 21:47:02 +00:00
t . Errorf ( "(%s) expected:\n%#v\nsaw:\n%#v\n" , test . name , expectedObj , list . Items [ ix ] )
2015-11-17 14:21:42 +00:00
}
}
} ( )
2015-09-09 21:36:19 +00:00
}
2015-08-20 05:08:26 +00:00
}
2015-11-20 08:16:41 +00:00
func encodeToThirdParty ( name string , obj interface { } ) ( runtime . Object , error ) {
2015-08-20 05:08:26 +00:00
serial , err := json . Marshal ( obj )
if err != nil {
return nil , err
}
2015-10-09 22:49:10 +00:00
thirdPartyData := extensions . ThirdPartyResourceData {
2015-08-20 05:08:26 +00:00
ObjectMeta : api . ObjectMeta { Name : name } ,
Data : serial ,
}
2015-11-20 08:16:41 +00:00
return & thirdPartyData , nil
2015-08-20 05:08:26 +00:00
}
2016-03-25 13:24:58 +00:00
func createThirdPartyObject ( s storage . Interface , path , name string , obj interface { } ) error {
2015-08-20 05:08:26 +00:00
data , err := encodeToThirdParty ( name , obj )
if err != nil {
return err
}
2016-03-25 13:24:58 +00:00
return s . Create ( context . TODO ( ) , etcdtest . AddPrefix ( path ) , data , nil , 0 )
2015-08-20 05:08:26 +00:00
}
2016-03-25 13:24:58 +00:00
func createThirdPartyList ( s storage . Interface , path string , list [ ] Foo ) error {
2015-09-09 21:36:19 +00:00
for _ , obj := range list {
2016-03-25 13:24:58 +00:00
if err := createThirdPartyObject ( s , path + "/" + obj . Name , obj . Name , obj ) ; err != nil {
2015-09-09 21:36:19 +00:00
return err
}
}
return nil
}
2015-08-20 05:08:26 +00:00
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 ) {
2016-05-09 21:47:02 +00:00
master , etcdserver , server , assert := initThirdParty ( t , version , "foo.company.com" )
2016-04-21 11:50:55 +00:00
defer server . Close ( )
2015-11-17 14:21:42 +00:00
defer etcdserver . Terminate ( t )
2015-08-20 05:08:26 +00:00
expectedObj := Foo {
ObjectMeta : api . ObjectMeta {
Name : "test" ,
} ,
2015-09-09 21:59:11 +00:00
TypeMeta : unversioned . TypeMeta {
2015-09-01 05:28:08 +00:00
Kind : "Foo" ,
APIVersion : version ,
2015-08-20 05:08:26 +00:00
} ,
SomeField : "test field" ,
OtherField : 10 ,
}
2016-03-25 13:24:58 +00:00
if ! assert . NoError ( createThirdPartyObject ( master . thirdPartyStorage , "/ThirdPartyResourceData/company.com/foos/default/test" , "test" , expectedObj ) ) {
2015-08-20 05:08:26 +00:00
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 ) {
2015-08-20 05:08:26 +00:00
return
}
2015-09-03 17:35:04 +00:00
assert . Equal ( http . StatusOK , resp . StatusCode )
2015-08-20 05:08:26 +00:00
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 )
2015-08-20 05:08:26 +00:00
}
2015-09-03 00:13:38 +00:00
// Fill in data that the apiserver injects
expectedObj . SelfLink = item . SelfLink
2015-11-17 14:21:42 +00:00
expectedObj . ResourceVersion = item . ResourceVersion
2015-09-03 17:35:04 +00:00
if ! assert . True ( reflect . DeepEqual ( item , expectedObj ) ) {
2015-09-03 00:13:38 +00:00
t . Errorf ( "expected:\n%#v\nsaw:\n%#v\n" , expectedObj , item )
2015-08-20 05:08:26 +00:00
}
}
func TestInstallThirdPartyAPIPost ( t * testing . T ) {
2016-05-12 22:59:19 +00:00
registered . AddThirdPartyAPIGroupVersions ( unversioned . GroupVersion { Group : "company.com" , Version : "v1" } , unversioned . GroupVersion { Group : "company.com" , Version : "v3" } )
2015-09-01 05:28:08 +00:00
for _ , version := range versionsToTest {
testInstallThirdPartyAPIPostForVersion ( t , version )
}
}
func testInstallThirdPartyAPIPostForVersion ( t * testing . T , version string ) {
2016-05-09 21:47:02 +00:00
master , etcdserver , server , assert := initThirdParty ( t , version , "foo.company.com" )
2016-04-21 11:50:55 +00:00
defer server . Close ( )
2015-11-17 14:21:42 +00:00
defer etcdserver . Terminate ( t )
2015-08-20 05:08:26 +00:00
inputObj := Foo {
ObjectMeta : api . ObjectMeta {
Name : "test" ,
} ,
2015-09-09 21:59:11 +00:00
TypeMeta : unversioned . TypeMeta {
2015-09-01 05:28:08 +00:00
Kind : "Foo" ,
2015-09-29 21:36:47 +00:00
APIVersion : "company.com/" + version ,
2015-08-20 05:08:26 +00:00
} ,
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 ) {
2015-08-20 05:08:26 +00:00
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 ) {
2016-02-25 06:07:54 +00:00
t . Fatalf ( "unexpected error: %v" , err )
2015-08-20 05:08:26 +00:00
}
2015-09-03 17:35:04 +00:00
assert . Equal ( http . StatusCreated , resp . StatusCode )
2015-08-20 05:08:26 +00:00
item := Foo { }
2015-09-03 17:35:04 +00:00
assert . NoError ( decodeResponse ( resp , & item ) )
2015-08-20 05:08:26 +00:00
2015-09-03 00:13:38 +00:00
// fill in fields set by the apiserver
expectedObj := inputObj
expectedObj . SelfLink = item . SelfLink
2015-11-17 14:21:42 +00:00
expectedObj . ResourceVersion = item . ResourceVersion
2015-09-03 00:13:38 +00:00
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 ) ) {
2015-09-03 00:13:38 +00:00
t . Errorf ( "expected:\n%v\nsaw:\n%v\n" , expectedObj , item )
2015-08-20 05:08:26 +00:00
}
2015-11-20 08:16:41 +00:00
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-08-20 05:08:26 +00:00
}
2015-09-03 17:35:04 +00:00
2015-08-20 05:08:26 +00:00
item = Foo { }
2015-09-03 17:35:04 +00:00
assert . NoError ( json . Unmarshal ( thirdPartyObj . Data , & item ) )
2015-08-20 05:08:26 +00:00
2015-09-03 17:35:04 +00:00
if ! assert . True ( reflect . DeepEqual ( item , inputObj ) ) {
2015-08-20 05:08:26 +00:00
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 ) {
2016-05-09 21:47:02 +00:00
master , etcdserver , server , assert := initThirdParty ( t , version , "foo.company.com" )
2016-04-21 11:50:55 +00:00
defer server . Close ( )
2015-11-17 14:21:42 +00:00
defer etcdserver . Terminate ( t )
2015-08-20 05:08:26 +00:00
expectedObj := Foo {
ObjectMeta : api . ObjectMeta {
2015-09-03 00:13:38 +00:00
Name : "test" ,
Namespace : "default" ,
2015-08-20 05:08:26 +00:00
} ,
2015-09-09 21:59:11 +00:00
TypeMeta : unversioned . TypeMeta {
2015-08-21 21:24:16 +00:00
Kind : "Foo" ,
2015-08-20 05:08:26 +00:00
} ,
SomeField : "test field" ,
OtherField : 10 ,
}
2016-03-25 13:24:58 +00:00
if ! assert . NoError ( createThirdPartyObject ( master . thirdPartyStorage , "/ThirdPartyResourceData/company.com/foos/default/test" , "test" , expectedObj ) ) {
2015-08-20 05:08:26 +00:00
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 ) {
2015-08-20 05:08:26 +00:00
return
}
2015-09-03 17:35:04 +00:00
assert . Equal ( http . StatusOK , resp . StatusCode )
2015-08-20 05:08:26 +00:00
item := Foo { }
2015-09-03 17:35:04 +00:00
assert . NoError ( decodeResponse ( resp , & item ) )
2015-08-20 05:08:26 +00:00
2015-09-03 00:13:38 +00:00
// Fill in fields set by the apiserver
expectedObj . SelfLink = item . SelfLink
2015-11-17 14:21:42 +00:00
expectedObj . ResourceVersion = item . ResourceVersion
2015-09-03 00:13:38 +00:00
expectedObj . Namespace = item . Namespace
2015-09-03 17:35:04 +00:00
if ! assert . True ( reflect . DeepEqual ( item , expectedObj ) ) {
2015-08-20 05:08:26 +00:00
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 ) {
2015-08-20 05:08:26 +00:00
return
}
2015-09-03 17:35:04 +00:00
assert . Equal ( http . StatusOK , resp . StatusCode )
2015-08-20 05:08:26 +00:00
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 ) {
2015-08-20 05:08:26 +00:00
return
}
2015-09-03 17:35:04 +00:00
assert . Equal ( http . StatusNotFound , resp . StatusCode )
2015-11-17 14:21:42 +00:00
expectedDeletedKey := etcdtest . AddPrefix ( "ThirdPartyResourceData/company.com/foos/default/test" )
2015-11-20 08:16:41 +00:00
thirdPartyObj := extensions . ThirdPartyResourceData { }
err = master . thirdPartyStorage . Get (
context . TODO ( ) , expectedDeletedKey , & thirdPartyObj , false )
2015-12-03 16:09:45 +00:00
if ! storage . IsNotFound ( err ) {
2015-11-17 14:21:42 +00:00
t . Errorf ( "expected deletion didn't happen: %v" , err )
2015-08-20 05:08:26 +00:00
}
}
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
}
2015-08-20 05:08:26 +00:00
client := & http . Client { }
return client . Do ( req )
2015-08-19 18:02:01 +00:00
}
2015-09-09 21:36:19 +00:00
2016-02-25 06:07:54 +00:00
func TestInstallThirdPartyAPIListOptions ( t * testing . T ) {
for _ , version := range versionsToTest {
testInstallThirdPartyAPIListOptionsForVersion ( t , version )
}
}
func testInstallThirdPartyAPIListOptionsForVersion ( t * testing . T , version string ) {
2016-05-09 21:47:02 +00:00
_ , etcdserver , server , assert := initThirdParty ( t , version , "foo.company.com" )
2016-04-21 11:50:55 +00:00
defer server . Close ( )
2016-02-25 06:07:54 +00:00
defer etcdserver . Terminate ( t )
// send a GET request with query parameter
resp , err := httpGetWithRV ( server . URL + "/apis/company.com/" + version + "/namespaces/default/foos" )
if ! assert . NoError ( err ) {
t . Fatalf ( "unexpected error: %v" , err )
}
assert . Equal ( http . StatusOK , resp . StatusCode )
}
func httpGetWithRV ( url string ) ( * http . Response , error ) {
req , err := http . NewRequest ( "GET" , url , nil )
if err != nil {
return nil , err
}
q := req . URL . Query ( )
// resourceversion is part of a ListOptions
q . Add ( "resourceversion" , "0" )
req . URL . RawQuery = q . Encode ( )
client := & http . Client { }
return client . Do ( req )
}
2015-09-09 21:36:19 +00:00
func TestInstallThirdPartyResourceRemove ( t * testing . T ) {
for _ , version := range versionsToTest {
testInstallThirdPartyResourceRemove ( t , version )
}
}
func testInstallThirdPartyResourceRemove ( t * testing . T , version string ) {
2016-05-09 21:47:02 +00:00
master , etcdserver , server , assert := initThirdParty ( t , version , "foo.company.com" )
2016-04-21 11:50:55 +00:00
defer server . Close ( )
2015-11-17 14:21:42 +00:00
defer etcdserver . Terminate ( t )
2015-09-09 21:36:19 +00:00
expectedObj := Foo {
ObjectMeta : api . ObjectMeta {
Name : "test" ,
} ,
TypeMeta : unversioned . TypeMeta {
Kind : "Foo" ,
} ,
SomeField : "test field" ,
OtherField : 10 ,
}
2016-03-25 13:24:58 +00:00
if ! assert . NoError ( createThirdPartyObject ( master . thirdPartyStorage , "/ThirdPartyResourceData/company.com/foos/default/test" , "test" , expectedObj ) ) {
2015-09-09 21:36:19 +00:00
t . FailNow ( )
return
}
secondObj := expectedObj
secondObj . Name = "bar"
2016-03-25 13:24:58 +00:00
if ! assert . NoError ( createThirdPartyObject ( master . thirdPartyStorage , "/ThirdPartyResourceData/company.com/foos/default/bar" , "bar" , secondObj ) ) {
2015-09-09 21:36:19 +00:00
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 )
}
2015-11-17 14:21:42 +00:00
expectedDeletedKeys := [ ] string {
etcdtest . AddPrefix ( "/ThirdPartyResourceData/company.com/foos/default/test" ) ,
etcdtest . AddPrefix ( "/ThirdPartyResourceData/company.com/foos/default/bar" ) ,
2015-09-09 21:36:19 +00:00
}
2015-11-17 14:21:42 +00:00
for _ , key := range expectedDeletedKeys {
2015-11-20 08:16:41 +00:00
thirdPartyObj := extensions . ThirdPartyResourceData { }
err := master . thirdPartyStorage . Get ( context . TODO ( ) , key , & thirdPartyObj , false )
2015-12-03 16:09:45 +00:00
if ! storage . IsNotFound ( err ) {
2015-11-17 14:21:42 +00:00
t . Errorf ( "expected deletion didn't happen: %v" , err )
}
2015-09-09 21:36:19 +00:00
}
installed := master . ListThirdPartyResources ( )
if len ( installed ) != 0 {
t . Errorf ( "Resource(s) still installed: %v" , installed )
}
2015-11-16 21:46:00 +00:00
services := master . HandlerContainer . RegisteredWebServices ( )
2015-09-09 21:36:19 +00:00
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 ] )
}
}
}
2016-02-25 22:13:28 +00:00
func TestThirdPartyDiscovery ( t * testing . T ) {
for _ , version := range versionsToTest {
testThirdPartyDiscovery ( t , version )
}
}
2016-04-22 00:48:35 +00:00
type FakeTunneler struct {
SecondsSinceSyncValue int64
SecondsSinceSSHKeySyncValue int64
}
func ( t * FakeTunneler ) Run ( genericapiserver . AddressFunc ) { }
func ( t * FakeTunneler ) Stop ( ) { }
func ( t * FakeTunneler ) Dial ( net , addr string ) ( net . Conn , error ) { return nil , nil }
func ( t * FakeTunneler ) SecondsSinceSync ( ) int64 { return t . SecondsSinceSyncValue }
func ( t * FakeTunneler ) SecondsSinceSSHKeySync ( ) int64 { return t . SecondsSinceSSHKeySyncValue }
// TestIsTunnelSyncHealthy verifies that the 600 second lag test
// is honored.
func TestIsTunnelSyncHealthy ( t * testing . T ) {
assert := assert . New ( t )
tunneler := & FakeTunneler { }
master := & Master {
GenericAPIServer : & genericapiserver . GenericAPIServer { } ,
tunneler : tunneler ,
}
// Pass case: 540 second lag
tunneler . SecondsSinceSyncValue = 540
err := master . IsTunnelSyncHealthy ( nil )
assert . NoError ( err , "IsTunnelSyncHealthy() should not have returned an error." )
// Fail case: 720 second lag
tunneler . SecondsSinceSyncValue = 720
err = master . IsTunnelSyncHealthy ( nil )
assert . Error ( err , "IsTunnelSyncHealthy() should have returned an error." )
}
2016-02-25 22:13:28 +00:00
func testThirdPartyDiscovery ( t * testing . T , version string ) {
2016-05-09 21:47:02 +00:00
_ , etcdserver , server , assert := initThirdParty ( t , version , "foo.company.com" )
2016-04-21 11:50:55 +00:00
defer server . Close ( )
2016-02-25 22:13:28 +00:00
defer etcdserver . Terminate ( t )
resp , err := http . Get ( server . URL + "/apis/company.com/" )
if ! assert . NoError ( err ) {
return
}
assert . Equal ( http . StatusOK , resp . StatusCode )
group := unversioned . APIGroup { }
assert . NoError ( decodeResponse ( resp , & group ) )
assert . Equal ( group . APIVersion , "v1" )
assert . Equal ( group . Kind , "APIGroup" )
assert . Equal ( group . Name , "company.com" )
2016-04-07 22:34:40 +00:00
expectedVersion := unversioned . GroupVersionForDiscovery {
GroupVersion : "company.com/" + version ,
Version : version ,
}
assert . Equal ( group . Versions , [ ] unversioned . GroupVersionForDiscovery { expectedVersion } )
assert . Equal ( group . PreferredVersion , expectedVersion )
2016-02-25 22:13:28 +00:00
resp , err = http . Get ( server . URL + "/apis/company.com/" + version )
if ! assert . NoError ( err ) {
return
}
assert . Equal ( http . StatusOK , resp . StatusCode )
resourceList := unversioned . APIResourceList { }
assert . NoError ( decodeResponse ( resp , & resourceList ) )
assert . Equal ( resourceList . APIVersion , "v1" )
assert . Equal ( resourceList . Kind , "APIResourceList" )
assert . Equal ( resourceList . GroupVersion , "company.com/" + version )
assert . Equal ( resourceList . APIResources , [ ] unversioned . APIResource {
{
Name : "foos" ,
Namespaced : true ,
Kind : "Foo" ,
} ,
} )
}