2020-09-16 14:19:51 +00:00
|
|
|
// Copyright 2020 the Pinniped contributors. All Rights Reserved.
|
|
|
|
// SPDX-License-Identifier: Apache-2.0
|
2020-07-16 16:40:44 +00:00
|
|
|
|
2020-08-11 17:14:57 +00:00
|
|
|
package apicerts
|
2020-07-16 16:40:44 +00:00
|
|
|
|
|
|
|
import (
|
|
|
|
"context"
|
|
|
|
"fmt"
|
|
|
|
"testing"
|
|
|
|
|
|
|
|
"github.com/stretchr/testify/require"
|
2020-08-04 23:46:27 +00:00
|
|
|
apierrors "k8s.io/apimachinery/pkg/api/errors"
|
2020-07-16 16:40:44 +00:00
|
|
|
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
|
|
|
"k8s.io/apimachinery/pkg/runtime"
|
2020-08-04 23:46:27 +00:00
|
|
|
"k8s.io/apimachinery/pkg/runtime/schema"
|
2020-07-16 16:40:44 +00:00
|
|
|
kubetesting "k8s.io/client-go/testing"
|
|
|
|
apiregistrationv1 "k8s.io/kube-aggregator/pkg/apis/apiregistration/v1"
|
2020-08-11 01:53:53 +00:00
|
|
|
aggregatorv1fake "k8s.io/kube-aggregator/pkg/client/clientset_generated/clientset/fake"
|
2020-09-16 19:59:23 +00:00
|
|
|
|
2020-09-17 17:56:54 +00:00
|
|
|
pinnipedv1alpha1 "github.com/vmware-tanzu/pinniped/generated/1.19/apis/pinniped/v1alpha1"
|
2020-07-16 16:40:44 +00:00
|
|
|
)
|
|
|
|
|
2020-08-04 23:46:27 +00:00
|
|
|
func TestUpdateAPIService(t *testing.T) {
|
2020-08-20 17:54:15 +00:00
|
|
|
const apiServiceName = "v1alpha1.pinniped.dev"
|
2020-07-16 16:40:44 +00:00
|
|
|
|
|
|
|
tests := []struct {
|
|
|
|
name string
|
2020-08-11 01:53:53 +00:00
|
|
|
mocks func(*aggregatorv1fake.Clientset)
|
2020-08-04 23:46:27 +00:00
|
|
|
caInput []byte
|
2020-07-16 16:40:44 +00:00
|
|
|
wantObjects []apiregistrationv1.APIService
|
|
|
|
wantErr string
|
|
|
|
}{
|
|
|
|
{
|
2020-08-04 23:46:27 +00:00
|
|
|
name: "happy path update when the pre-existing APIService did not already have a CA bundle",
|
2020-08-11 01:53:53 +00:00
|
|
|
mocks: func(c *aggregatorv1fake.Clientset) {
|
2020-08-04 23:46:27 +00:00
|
|
|
_ = c.Tracker().Add(&apiregistrationv1.APIService{
|
|
|
|
ObjectMeta: metav1.ObjectMeta{Name: apiServiceName},
|
|
|
|
Spec: apiregistrationv1.APIServiceSpec{
|
|
|
|
GroupPriorityMinimum: 999,
|
|
|
|
CABundle: nil,
|
|
|
|
},
|
2020-07-16 16:40:44 +00:00
|
|
|
})
|
|
|
|
},
|
2020-08-04 23:46:27 +00:00
|
|
|
caInput: []byte("some-ca-bundle"),
|
2020-07-16 16:40:44 +00:00
|
|
|
wantObjects: []apiregistrationv1.APIService{{
|
2020-08-04 23:46:27 +00:00
|
|
|
ObjectMeta: metav1.ObjectMeta{Name: apiServiceName},
|
2020-07-16 16:40:44 +00:00
|
|
|
Spec: apiregistrationv1.APIServiceSpec{
|
2020-08-04 23:46:27 +00:00
|
|
|
GroupPriorityMinimum: 999,
|
|
|
|
CABundle: []byte("some-ca-bundle"),
|
2020-07-16 16:40:44 +00:00
|
|
|
},
|
|
|
|
}},
|
|
|
|
},
|
|
|
|
{
|
2020-08-04 23:46:27 +00:00
|
|
|
name: "happy path update when the pre-existing APIService already had a CA bundle",
|
2020-08-11 01:53:53 +00:00
|
|
|
mocks: func(c *aggregatorv1fake.Clientset) {
|
2020-07-16 16:40:44 +00:00
|
|
|
_ = c.Tracker().Add(&apiregistrationv1.APIService{
|
2020-08-04 23:46:27 +00:00
|
|
|
ObjectMeta: metav1.ObjectMeta{Name: apiServiceName},
|
2020-07-16 16:40:44 +00:00
|
|
|
Spec: apiregistrationv1.APIServiceSpec{
|
|
|
|
GroupPriorityMinimum: 999,
|
2020-08-04 23:46:27 +00:00
|
|
|
CABundle: []byte("some-other-different-ca-bundle"),
|
2020-07-16 16:40:44 +00:00
|
|
|
},
|
|
|
|
})
|
|
|
|
},
|
2020-08-04 23:46:27 +00:00
|
|
|
caInput: []byte("some-ca-bundle"),
|
2020-07-16 16:40:44 +00:00
|
|
|
wantObjects: []apiregistrationv1.APIService{{
|
2020-08-04 23:46:27 +00:00
|
|
|
ObjectMeta: metav1.ObjectMeta{Name: apiServiceName},
|
2020-07-16 16:40:44 +00:00
|
|
|
Spec: apiregistrationv1.APIServiceSpec{
|
2020-08-04 23:46:27 +00:00
|
|
|
GroupPriorityMinimum: 999,
|
|
|
|
CABundle: []byte("some-ca-bundle"),
|
2020-07-16 16:40:44 +00:00
|
|
|
},
|
|
|
|
}},
|
|
|
|
},
|
2020-09-08 23:36:49 +00:00
|
|
|
{
|
|
|
|
name: "happy path update when the pre-existing APIService already has the same CA bundle so there is no need to update",
|
|
|
|
mocks: func(c *aggregatorv1fake.Clientset) {
|
|
|
|
_ = c.Tracker().Add(&apiregistrationv1.APIService{
|
|
|
|
ObjectMeta: metav1.ObjectMeta{Name: apiServiceName},
|
|
|
|
Spec: apiregistrationv1.APIServiceSpec{
|
|
|
|
GroupPriorityMinimum: 999,
|
|
|
|
CABundle: []byte("some-ca-bundle"),
|
|
|
|
},
|
|
|
|
})
|
|
|
|
c.PrependReactor("update", "apiservices", func(_ kubetesting.Action) (bool, runtime.Object, error) {
|
|
|
|
return true, nil, fmt.Errorf("should not encounter this error because update should be skipped in this case")
|
|
|
|
})
|
|
|
|
},
|
|
|
|
caInput: []byte("some-ca-bundle"),
|
|
|
|
wantObjects: []apiregistrationv1.APIService{{
|
|
|
|
ObjectMeta: metav1.ObjectMeta{Name: apiServiceName},
|
|
|
|
Spec: apiregistrationv1.APIServiceSpec{
|
|
|
|
GroupPriorityMinimum: 999,
|
|
|
|
CABundle: []byte("some-ca-bundle"), // unchanged
|
|
|
|
},
|
|
|
|
}},
|
|
|
|
},
|
2020-08-04 23:46:27 +00:00
|
|
|
{
|
|
|
|
name: "error on update",
|
2020-08-11 01:53:53 +00:00
|
|
|
mocks: func(c *aggregatorv1fake.Clientset) {
|
2020-08-04 23:46:27 +00:00
|
|
|
_ = c.Tracker().Add(&apiregistrationv1.APIService{
|
|
|
|
ObjectMeta: metav1.ObjectMeta{Name: apiServiceName},
|
2020-09-08 23:36:49 +00:00
|
|
|
Spec: apiregistrationv1.APIServiceSpec{
|
|
|
|
GroupPriorityMinimum: 999,
|
|
|
|
CABundle: []byte("some-other-different-ca-bundle"),
|
|
|
|
},
|
2020-08-04 23:46:27 +00:00
|
|
|
})
|
|
|
|
c.PrependReactor("update", "apiservices", func(_ kubetesting.Action) (bool, runtime.Object, error) {
|
|
|
|
return true, nil, fmt.Errorf("error on update")
|
|
|
|
})
|
|
|
|
},
|
2020-09-08 23:36:49 +00:00
|
|
|
caInput: []byte("some-ca-bundle"),
|
2020-08-04 23:46:27 +00:00
|
|
|
wantErr: "could not update API service: error on update",
|
|
|
|
},
|
2020-07-16 16:40:44 +00:00
|
|
|
{
|
|
|
|
name: "error on get",
|
2020-08-11 01:53:53 +00:00
|
|
|
mocks: func(c *aggregatorv1fake.Clientset) {
|
2020-07-16 16:40:44 +00:00
|
|
|
_ = c.Tracker().Add(&apiregistrationv1.APIService{
|
2020-08-04 23:46:27 +00:00
|
|
|
ObjectMeta: metav1.ObjectMeta{Name: apiServiceName},
|
|
|
|
Spec: apiregistrationv1.APIServiceSpec{},
|
2020-07-16 16:40:44 +00:00
|
|
|
})
|
|
|
|
c.PrependReactor("get", "apiservices", func(_ kubetesting.Action) (bool, runtime.Object, error) {
|
|
|
|
return true, nil, fmt.Errorf("error on get")
|
|
|
|
})
|
|
|
|
},
|
2020-08-04 23:46:27 +00:00
|
|
|
caInput: []byte("some-ca-bundle"),
|
2020-07-16 16:40:44 +00:00
|
|
|
wantErr: "could not update API service: could not get existing version of API service: error on get",
|
|
|
|
},
|
|
|
|
{
|
2020-08-04 23:46:27 +00:00
|
|
|
name: "conflict error on update, followed by successful retry",
|
2020-08-11 01:53:53 +00:00
|
|
|
mocks: func(c *aggregatorv1fake.Clientset) {
|
2020-07-16 16:40:44 +00:00
|
|
|
_ = c.Tracker().Add(&apiregistrationv1.APIService{
|
2020-08-04 23:46:27 +00:00
|
|
|
ObjectMeta: metav1.ObjectMeta{Name: apiServiceName},
|
2020-07-16 16:40:44 +00:00
|
|
|
Spec: apiregistrationv1.APIServiceSpec{
|
2020-08-04 23:46:27 +00:00
|
|
|
GroupPriorityMinimum: 111,
|
|
|
|
CABundle: nil,
|
2020-07-16 16:40:44 +00:00
|
|
|
},
|
|
|
|
})
|
|
|
|
hit := false
|
2020-08-04 23:46:27 +00:00
|
|
|
c.PrependReactor("update", "apiservices", func(_ kubetesting.Action) (bool, runtime.Object, error) {
|
2020-07-16 16:40:44 +00:00
|
|
|
// Return an error on the first call, then fall through to the default (successful) response.
|
|
|
|
if !hit {
|
2020-08-04 23:46:27 +00:00
|
|
|
// Before the update fails, also change the object that will be returned by the next Get(),
|
|
|
|
// to make sure that the production code does a fresh Get() after detecting a conflict.
|
|
|
|
_ = c.Tracker().Update(schema.GroupVersionResource{
|
|
|
|
Group: apiregistrationv1.GroupName,
|
|
|
|
Version: apiregistrationv1.SchemeGroupVersion.Version,
|
|
|
|
Resource: "apiservices",
|
|
|
|
}, &apiregistrationv1.APIService{
|
|
|
|
ObjectMeta: metav1.ObjectMeta{Name: apiServiceName},
|
|
|
|
Spec: apiregistrationv1.APIServiceSpec{
|
|
|
|
GroupPriorityMinimum: 222,
|
|
|
|
CABundle: nil,
|
|
|
|
},
|
|
|
|
}, "")
|
2020-07-16 16:40:44 +00:00
|
|
|
hit = true
|
2020-08-04 23:46:27 +00:00
|
|
|
return true, nil, apierrors.NewConflict(schema.GroupResource{
|
|
|
|
Group: apiregistrationv1.GroupName,
|
|
|
|
Resource: "apiservices",
|
|
|
|
}, apiServiceName, fmt.Errorf("there was a conflict"))
|
2020-07-16 16:40:44 +00:00
|
|
|
}
|
|
|
|
return false, nil, nil
|
|
|
|
})
|
|
|
|
},
|
2020-08-04 23:46:27 +00:00
|
|
|
caInput: []byte("some-ca-bundle"),
|
|
|
|
wantObjects: []apiregistrationv1.APIService{{
|
|
|
|
ObjectMeta: metav1.ObjectMeta{Name: apiServiceName},
|
2020-07-16 16:40:44 +00:00
|
|
|
Spec: apiregistrationv1.APIServiceSpec{
|
2020-08-04 23:46:27 +00:00
|
|
|
GroupPriorityMinimum: 222,
|
|
|
|
CABundle: []byte("some-ca-bundle"),
|
2020-07-16 16:40:44 +00:00
|
|
|
},
|
2020-08-04 23:46:27 +00:00
|
|
|
}},
|
2020-07-16 16:40:44 +00:00
|
|
|
},
|
|
|
|
}
|
2020-09-08 23:36:49 +00:00
|
|
|
|
2020-07-16 16:40:44 +00:00
|
|
|
for _, tt := range tests {
|
|
|
|
tt := tt
|
|
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
|
|
ctx := context.Background()
|
|
|
|
|
2020-08-11 01:53:53 +00:00
|
|
|
client := aggregatorv1fake.NewSimpleClientset()
|
2020-07-16 16:40:44 +00:00
|
|
|
if tt.mocks != nil {
|
|
|
|
tt.mocks(client)
|
|
|
|
}
|
|
|
|
|
2020-09-16 19:59:23 +00:00
|
|
|
err := UpdateAPIService(ctx, client, pinnipedv1alpha1.SchemeGroupVersion.Version+"."+pinnipedv1alpha1.GroupName, tt.caInput)
|
2020-07-16 16:40:44 +00:00
|
|
|
if tt.wantErr != "" {
|
|
|
|
require.EqualError(t, err, tt.wantErr)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
require.NoError(t, err)
|
|
|
|
if tt.wantObjects != nil {
|
|
|
|
objects, err := client.ApiregistrationV1().APIServices().List(ctx, metav1.ListOptions{})
|
|
|
|
require.NoError(t, err)
|
|
|
|
require.Equal(t, tt.wantObjects, objects.Items)
|
|
|
|
}
|
|
|
|
})
|
|
|
|
}
|
|
|
|
}
|