ContainerImage.Pinniped/internal/groupsuffix/groupsuffix_test.go
Ryan Richard ba98c8cc14 Enhance Kube middleware to rewrite API group of ownerRefs on update verb
When oidcclientsecretstorage.Set() wants to update the contents of the
storage Secret, it also wants to keep the original ownerRef of the
storage Secret, so it needs the middleware to rewrite the API group
of the ownerRef again during the update (just like it had initially done
during the create of the Secret).
2022-09-21 21:30:44 -07:00

689 lines
26 KiB
Go

// Copyright 2021-2022 the Pinniped contributors. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0
package groupsuffix
import (
"context"
"fmt"
"strings"
"testing"
"github.com/stretchr/testify/require"
corev1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/runtime/schema"
authv1alpha1 "go.pinniped.dev/generated/latest/apis/concierge/authentication/v1alpha1"
loginv1alpha1 "go.pinniped.dev/generated/latest/apis/concierge/login/v1alpha1"
configv1alpha1 "go.pinniped.dev/generated/latest/apis/supervisor/config/v1alpha1"
"go.pinniped.dev/internal/kubeclient"
"go.pinniped.dev/internal/testutil"
)
func ExampleReplace_loginv1alpha1() {
s, _ := Replace(loginv1alpha1.GroupName, "tuna.fish.io")
fmt.Println(s)
// Output: login.concierge.tuna.fish.io
}
func ExampleReplace_string() {
s, _ := Replace("idp.supervisor.pinniped.dev", "marlin.io")
fmt.Println(s)
// Output: idp.supervisor.marlin.io
}
func TestMiddlware(t *testing.T) {
const newSuffix = "some.suffix.com"
podWithoutOwner := &corev1.Pod{
TypeMeta: metav1.TypeMeta{
APIVersion: corev1.SchemeGroupVersion.String(),
Kind: "Pod",
},
ObjectMeta: metav1.ObjectMeta{
OwnerReferences: []metav1.OwnerReference{},
},
}
nonPinnipedOwner := &corev1.Pod{
ObjectMeta: metav1.ObjectMeta{
Name: "some-name",
UID: "some-uid",
},
}
nonPinnipedOwnerGVK := corev1.SchemeGroupVersion.WithKind("Pod")
podWithNonPinnipedOwner := &corev1.Pod{
TypeMeta: metav1.TypeMeta{
APIVersion: corev1.SchemeGroupVersion.String(),
Kind: "Pod",
},
ObjectMeta: metav1.ObjectMeta{
OwnerReferences: []metav1.OwnerReference{
*metav1.NewControllerRef(nonPinnipedOwner, nonPinnipedOwnerGVK),
},
},
}
var ok bool
pinnipedOwner := &configv1alpha1.FederationDomain{
ObjectMeta: metav1.ObjectMeta{
Name: "some-name",
UID: "some-uid",
},
}
pinnipedOwnerGVK := configv1alpha1.SchemeGroupVersion.WithKind("FederationDomain")
pinnipedOwnerWithNewGroupGVK := configv1alpha1.SchemeGroupVersion.WithKind("FederationDomain")
pinnipedOwnerWithNewGroupGVK.Group, ok = Replace(pinnipedOwnerWithNewGroupGVK.Group, newSuffix)
require.True(t, ok)
podWithPinnipedOwner := &corev1.Pod{
TypeMeta: metav1.TypeMeta{
APIVersion: corev1.SchemeGroupVersion.String(),
Kind: "Pod",
},
ObjectMeta: metav1.ObjectMeta{
OwnerReferences: []metav1.OwnerReference{
*metav1.NewControllerRef(pinnipedOwner, pinnipedOwnerGVK),
// make sure we don't update the non-pinniped owner
*metav1.NewControllerRef(nonPinnipedOwner, nonPinnipedOwnerGVK),
},
},
}
podWithPinnipedOwnerWithNewGroup := &corev1.Pod{
TypeMeta: metav1.TypeMeta{
APIVersion: corev1.SchemeGroupVersion.String(),
Kind: "Pod",
},
ObjectMeta: metav1.ObjectMeta{
OwnerReferences: []metav1.OwnerReference{
*metav1.NewControllerRef(pinnipedOwner, pinnipedOwnerWithNewGroupGVK),
// make sure we don't update the non-pinniped owner
*metav1.NewControllerRef(nonPinnipedOwner, nonPinnipedOwnerGVK),
},
},
}
federationDomainWithPinnipedOwner := &configv1alpha1.FederationDomain{
TypeMeta: metav1.TypeMeta{
APIVersion: configv1alpha1.SchemeGroupVersion.String(),
Kind: "FederationDomain",
},
ObjectMeta: metav1.ObjectMeta{
OwnerReferences: []metav1.OwnerReference{
*metav1.NewControllerRef(pinnipedOwner, pinnipedOwnerGVK),
// make sure we don't update the non-pinniped owner
*metav1.NewControllerRef(nonPinnipedOwner, nonPinnipedOwnerGVK),
},
},
}
federationDomainWithNewGroupAndPinnipedOwner := &configv1alpha1.FederationDomain{
TypeMeta: metav1.TypeMeta{
APIVersion: replaceGV(t, configv1alpha1.SchemeGroupVersion, newSuffix).String(),
Kind: "FederationDomain",
},
ObjectMeta: metav1.ObjectMeta{
OwnerReferences: []metav1.OwnerReference{
*metav1.NewControllerRef(pinnipedOwner, pinnipedOwnerGVK),
// make sure we don't update the non-pinniped owner
*metav1.NewControllerRef(nonPinnipedOwner, nonPinnipedOwnerGVK),
},
},
}
federationDomainWithNewGroupAndPinnipedOwnerWithNewGroup := &configv1alpha1.FederationDomain{
TypeMeta: metav1.TypeMeta{
APIVersion: replaceGV(t, configv1alpha1.SchemeGroupVersion, newSuffix).String(),
Kind: "FederationDomain",
},
ObjectMeta: metav1.ObjectMeta{
OwnerReferences: []metav1.OwnerReference{
*metav1.NewControllerRef(pinnipedOwner, pinnipedOwnerWithNewGroupGVK),
// make sure we don't update the non-pinniped owner
*metav1.NewControllerRef(nonPinnipedOwner, nonPinnipedOwnerGVK),
},
},
}
tokenCredentialRequest := with(
&loginv1alpha1.TokenCredentialRequest{},
gvk(replaceGV(t, loginv1alpha1.SchemeGroupVersion, newSuffix).WithKind("TokenCredentialRequest")),
)
tokenCredentialRequestWithPinnipedAuthenticator := with(
tokenCredentialRequest,
authenticatorAPIGroup(authv1alpha1.SchemeGroupVersion.Group),
)
tokenCredentialRequestWithCustomAPIGroupAuthenticator := with(
tokenCredentialRequest,
authenticatorAPIGroup(replaceGV(t, authv1alpha1.SchemeGroupVersion, newSuffix).Group),
)
tokenCredentialRequestWithNewGroup := with(
tokenCredentialRequest,
gvk(replaceGV(t, loginv1alpha1.SchemeGroupVersion, newSuffix).WithKind("TokenCredentialRequest")),
)
tokenCredentialRequestWithNewGroupAndPinnipedAuthenticator := with(
tokenCredentialRequestWithNewGroup,
authenticatorAPIGroup(authv1alpha1.SchemeGroupVersion.Group),
)
tokenCredentialRequestWithNewGroupAndCustomAPIGroupAuthenticator := with(
tokenCredentialRequestWithNewGroup,
authenticatorAPIGroup(replaceGV(t, authv1alpha1.SchemeGroupVersion, newSuffix).Group),
)
tests := []struct {
name string
apiGroupSuffix string
rt *testutil.RoundTrip
requestObj, responseObj kubeclient.Object
wantNilMiddleware bool
wantMutateRequests, wantMutateResponses int
wantMutateRequestErrors, wantMutateResponseErrors []string
wantRequestObj, wantResponseObj kubeclient.Object
}{
{
name: "api group suffix is empty",
apiGroupSuffix: "",
rt: (&testutil.RoundTrip{}).
WithVerb(kubeclient.VerbGet).
WithNamespace("some-namespace").
WithResource(corev1.SchemeGroupVersion.WithResource("pods")),
wantNilMiddleware: true,
},
{
name: "api group suffix is default",
apiGroupSuffix: "pinniped.dev",
rt: (&testutil.RoundTrip{}).
WithVerb(kubeclient.VerbGet).
WithNamespace("some-namespace").
WithResource(corev1.SchemeGroupVersion.WithResource("pods")),
wantNilMiddleware: true,
},
{
name: "get resource without pinniped.dev",
apiGroupSuffix: newSuffix,
rt: (&testutil.RoundTrip{}).
WithVerb(kubeclient.VerbGet).
WithNamespace("some-namespace").
WithResource(corev1.SchemeGroupVersion.WithResource("pods")),
responseObj: podWithoutOwner,
wantMutateResponses: 1,
wantResponseObj: podWithoutOwner,
},
{
name: "get resource without pinniped.dev with non-pinniped.dev owner ref",
apiGroupSuffix: newSuffix,
rt: (&testutil.RoundTrip{}).
WithVerb(kubeclient.VerbGet).
WithNamespace("some-namespace").
WithResource(corev1.SchemeGroupVersion.WithResource("pods")),
responseObj: podWithNonPinnipedOwner,
wantMutateResponses: 1,
wantResponseObj: podWithNonPinnipedOwner,
},
{
name: "get resource without pinniped.dev with pinniped.dev owner ref",
apiGroupSuffix: newSuffix,
rt: (&testutil.RoundTrip{}).
WithVerb(kubeclient.VerbGet).
WithNamespace("some-namespace").
WithResource(corev1.SchemeGroupVersion.WithResource("pods")),
responseObj: podWithPinnipedOwnerWithNewGroup,
wantMutateResponses: 1,
wantResponseObj: podWithPinnipedOwner,
},
{
name: "get resource with pinniped.dev",
apiGroupSuffix: newSuffix,
rt: (&testutil.RoundTrip{}).
WithVerb(kubeclient.VerbGet).
WithResource(loginv1alpha1.SchemeGroupVersion.WithResource("tokencredentialrequests")),
requestObj: with(&metav1.PartialObjectMetadata{}, gvk(loginv1alpha1.SchemeGroupVersion.WithKind("TokenCredentialRequest"))),
responseObj: tokenCredentialRequestWithNewGroup,
wantMutateRequests: 1,
wantMutateResponses: 1,
wantRequestObj: with(&metav1.PartialObjectMetadata{}, gvk(replaceGV(t, loginv1alpha1.SchemeGroupVersion, newSuffix).WithKind("TokenCredentialRequest"))),
wantResponseObj: tokenCredentialRequestWithNewGroup, // the middleware will reset object GVK for us
},
{
name: "create resource without pinniped.dev and without owner ref",
apiGroupSuffix: newSuffix,
rt: (&testutil.RoundTrip{}).
WithVerb(kubeclient.VerbCreate).
WithNamespace("some-namespace").
WithResource(corev1.SchemeGroupVersion.WithResource("pods")),
requestObj: podWithoutOwner,
responseObj: podWithoutOwner,
wantMutateRequests: 1,
wantMutateResponses: 1,
wantRequestObj: podWithoutOwner,
wantResponseObj: podWithoutOwner,
},
{
name: "create resource without pinniped.dev and with owner ref that has no pinniped.dev owner",
apiGroupSuffix: newSuffix,
rt: (&testutil.RoundTrip{}).
WithVerb(kubeclient.VerbCreate).
WithNamespace("some-namespace").
WithResource(corev1.SchemeGroupVersion.WithResource("pods")),
requestObj: podWithNonPinnipedOwner,
responseObj: podWithNonPinnipedOwner,
wantMutateRequests: 1,
wantMutateResponses: 1,
wantRequestObj: podWithNonPinnipedOwner,
wantResponseObj: podWithNonPinnipedOwner,
},
{
name: "create resource without pinniped.dev and with owner ref that has pinniped.dev owner",
apiGroupSuffix: newSuffix,
rt: (&testutil.RoundTrip{}).
WithVerb(kubeclient.VerbCreate).
WithNamespace("some-namespace").
WithResource(corev1.SchemeGroupVersion.WithResource("pods")),
requestObj: podWithPinnipedOwner,
responseObj: podWithPinnipedOwnerWithNewGroup,
wantMutateRequests: 1,
wantMutateResponses: 1,
wantRequestObj: podWithPinnipedOwnerWithNewGroup,
wantResponseObj: podWithPinnipedOwner,
},
{
name: "create subresource without pinniped.dev",
apiGroupSuffix: newSuffix,
rt: (&testutil.RoundTrip{}).
WithVerb(kubeclient.VerbCreate).
WithNamespace("some-namespace").
WithResource(corev1.SchemeGroupVersion.WithResource("pods")).
WithSubresource("some-subresource"),
responseObj: podWithPinnipedOwner,
wantMutateResponses: 1,
wantResponseObj: podWithPinnipedOwner,
},
{
// test that multiple of our middleware request mutations play nicely with each other on create
name: "create resource with pinniped.dev and with owner ref that has pinniped.dev owner",
apiGroupSuffix: newSuffix,
rt: (&testutil.RoundTrip{}).
WithVerb(kubeclient.VerbCreate).
WithNamespace("some-namespace").
WithResource(configv1alpha1.SchemeGroupVersion.WithResource("federationdomains")),
requestObj: federationDomainWithPinnipedOwner,
responseObj: federationDomainWithNewGroupAndPinnipedOwnerWithNewGroup,
wantMutateRequests: 2,
wantMutateResponses: 1,
wantRequestObj: federationDomainWithNewGroupAndPinnipedOwnerWithNewGroup,
wantResponseObj: federationDomainWithNewGroupAndPinnipedOwner, // the middleware will reset object GVK for us
},
{
// test that multiple of our middleware request mutations play nicely with each other on update
name: "update resource with pinniped.dev and with owner ref that has pinniped.dev owner",
apiGroupSuffix: newSuffix,
rt: (&testutil.RoundTrip{}).
WithVerb(kubeclient.VerbUpdate).
WithNamespace("some-namespace").
WithResource(configv1alpha1.SchemeGroupVersion.WithResource("federationdomains")),
requestObj: federationDomainWithPinnipedOwner,
responseObj: federationDomainWithNewGroupAndPinnipedOwnerWithNewGroup,
wantMutateRequests: 2,
wantMutateResponses: 1,
wantRequestObj: federationDomainWithNewGroupAndPinnipedOwnerWithNewGroup,
wantResponseObj: federationDomainWithNewGroupAndPinnipedOwner, // the middleware will reset object GVK for us
},
{
name: "update resource without pinniped.dev and without owner ref",
apiGroupSuffix: newSuffix,
rt: (&testutil.RoundTrip{}).
WithVerb(kubeclient.VerbUpdate).
WithNamespace("some-namespace").
WithResource(corev1.SchemeGroupVersion.WithResource("pods")),
requestObj: podWithoutOwner,
responseObj: podWithoutOwner,
wantMutateRequests: 1,
wantMutateResponses: 1,
wantRequestObj: podWithoutOwner,
wantResponseObj: podWithoutOwner,
},
{
name: "update resource without pinniped.dev and with owner ref that has pinniped.dev owner",
apiGroupSuffix: newSuffix,
rt: (&testutil.RoundTrip{}).
WithVerb(kubeclient.VerbUpdate).
WithNamespace("some-namespace").
WithResource(corev1.SchemeGroupVersion.WithResource("pods")),
requestObj: podWithPinnipedOwner,
responseObj: podWithPinnipedOwnerWithNewGroup,
wantMutateRequests: 1,
wantMutateResponses: 1,
wantRequestObj: podWithPinnipedOwnerWithNewGroup,
wantResponseObj: podWithPinnipedOwner,
},
{
name: "update resource with pinniped.dev and without owner ref",
apiGroupSuffix: newSuffix,
rt: (&testutil.RoundTrip{}).
WithVerb(kubeclient.VerbUpdate).
WithResource(loginv1alpha1.SchemeGroupVersion.WithResource("tokencredentialrequests")),
requestObj: tokenCredentialRequest,
responseObj: tokenCredentialRequestWithNewGroup,
wantMutateRequests: 2,
wantMutateResponses: 1,
wantRequestObj: tokenCredentialRequestWithNewGroup,
wantResponseObj: tokenCredentialRequestWithNewGroup, // the middleware will reset object GVK for us
},
{
name: "list resource without pinniped.dev",
apiGroupSuffix: newSuffix,
rt: (&testutil.RoundTrip{}).
WithVerb(kubeclient.VerbList).
WithNamespace("some-namespace").
WithResource(corev1.SchemeGroupVersion.WithResource("pods")),
responseObj: podWithoutOwner,
wantMutateResponses: 1,
wantResponseObj: podWithoutOwner,
},
{
name: "list resource with pinniped.dev",
apiGroupSuffix: newSuffix,
rt: (&testutil.RoundTrip{}).
WithVerb(kubeclient.VerbList).
WithResource(loginv1alpha1.SchemeGroupVersion.WithResource("tokencredentialrequests")),
requestObj: tokenCredentialRequest,
responseObj: tokenCredentialRequestWithNewGroup,
wantMutateRequests: 1,
wantMutateResponses: 1,
wantRequestObj: tokenCredentialRequestWithNewGroup,
wantResponseObj: tokenCredentialRequestWithNewGroup, // the middleware will reset object GVK for us
},
{
name: "watch resource without pinniped.dev",
apiGroupSuffix: newSuffix,
rt: (&testutil.RoundTrip{}).
WithVerb(kubeclient.VerbWatch).
WithNamespace("some-namespace").
WithResource(corev1.SchemeGroupVersion.WithResource("pods")),
responseObj: podWithoutOwner,
wantMutateResponses: 1,
wantResponseObj: podWithoutOwner,
},
{
name: "watch resource with pinniped.dev",
apiGroupSuffix: newSuffix,
rt: (&testutil.RoundTrip{}).
WithVerb(kubeclient.VerbList).
WithResource(loginv1alpha1.SchemeGroupVersion.WithResource("tokencredentialrequests")),
requestObj: tokenCredentialRequest,
responseObj: tokenCredentialRequestWithNewGroup,
wantMutateRequests: 1,
wantMutateResponses: 1,
wantRequestObj: tokenCredentialRequestWithNewGroup,
wantResponseObj: tokenCredentialRequestWithNewGroup, // the middleware will reset object GVK for us
},
{
name: "patch resource without pinniped.dev",
apiGroupSuffix: newSuffix,
rt: (&testutil.RoundTrip{}).
WithVerb(kubeclient.VerbPatch).
WithNamespace("some-namespace").
WithResource(corev1.SchemeGroupVersion.WithResource("pods")),
responseObj: podWithoutOwner,
wantMutateResponses: 1,
wantResponseObj: podWithoutOwner,
},
{
name: "patch resource with pinniped.dev",
apiGroupSuffix: newSuffix,
rt: (&testutil.RoundTrip{}).
WithVerb(kubeclient.VerbPatch).
WithResource(loginv1alpha1.SchemeGroupVersion.WithResource("tokencredentialrequests")),
requestObj: tokenCredentialRequest,
responseObj: tokenCredentialRequestWithNewGroup,
wantMutateRequests: 1,
wantMutateResponses: 1,
wantRequestObj: tokenCredentialRequestWithNewGroup,
wantResponseObj: tokenCredentialRequestWithNewGroup, // the middleware will reset object GVK for us
},
{
name: "create tokencredentialrequest with pinniped.dev authenticator api group",
apiGroupSuffix: newSuffix,
rt: (&testutil.RoundTrip{}).
WithVerb(kubeclient.VerbCreate).
WithResource(loginv1alpha1.SchemeGroupVersion.WithResource("tokencredentialrequests")),
requestObj: tokenCredentialRequestWithPinnipedAuthenticator,
responseObj: tokenCredentialRequestWithNewGroup, // a token credential response does not contain a spec
wantMutateRequests: 3,
wantMutateResponses: 1,
wantRequestObj: tokenCredentialRequestWithNewGroupAndCustomAPIGroupAuthenticator,
wantResponseObj: tokenCredentialRequestWithNewGroup, // the middleware will reset object GVK for us
},
{
name: "create tokencredentialrequest with custom authenticator api group fails because api group is expected to be pinniped.dev",
apiGroupSuffix: newSuffix,
rt: (&testutil.RoundTrip{}).
WithVerb(kubeclient.VerbCreate).
WithResource(loginv1alpha1.SchemeGroupVersion.WithResource("tokencredentialrequests")),
requestObj: tokenCredentialRequestWithCustomAPIGroupAuthenticator,
responseObj: tokenCredentialRequestWithNewGroup, // a token credential response does not contain a spec
wantMutateRequests: 3,
wantMutateResponses: 1,
wantMutateRequestErrors: []string{`cannot replace token credential request / authenticator API group "authentication.concierge.some.suffix.com" with group suffix "some.suffix.com"`},
wantResponseObj: tokenCredentialRequestWithNewGroup, // the middleware will reset object GVK for us
},
{
name: "create tokencredentialrequest with pinniped.dev authenticator api group and subresource",
apiGroupSuffix: newSuffix,
rt: (&testutil.RoundTrip{}).
WithVerb(kubeclient.VerbCreate).
WithResource(loginv1alpha1.SchemeGroupVersion.WithResource("tokencredentialrequests")).
WithSubresource("some-subresource"),
requestObj: tokenCredentialRequestWithPinnipedAuthenticator,
responseObj: tokenCredentialRequestWithNewGroup, // a token credential response does not contain a spec
wantMutateRequests: 1,
wantMutateResponses: 1,
wantRequestObj: tokenCredentialRequestWithNewGroupAndPinnipedAuthenticator,
wantResponseObj: tokenCredentialRequestWithNewGroup, // the middleware will reset object GVK for us
},
{
name: "non-create tokencredentialrequest with pinniped.dev authenticator api group",
apiGroupSuffix: newSuffix,
rt: (&testutil.RoundTrip{}).
WithVerb(kubeclient.VerbList).
WithResource(loginv1alpha1.SchemeGroupVersion.WithResource("tokencredentialrequests")),
requestObj: tokenCredentialRequestWithPinnipedAuthenticator,
responseObj: tokenCredentialRequestWithNewGroup, // a token credential response does not contain a spec
wantMutateRequests: 1,
wantMutateResponses: 1,
wantRequestObj: tokenCredentialRequestWithNewGroupAndPinnipedAuthenticator,
wantResponseObj: tokenCredentialRequestWithNewGroup, // the middleware will reset object GVK for us
},
{
name: "create tokencredentialrequest with nil authenticator api group",
apiGroupSuffix: newSuffix,
rt: (&testutil.RoundTrip{}).
WithVerb(kubeclient.VerbCreate).
WithResource(loginv1alpha1.SchemeGroupVersion.WithResource("tokencredentialrequests")),
requestObj: tokenCredentialRequest,
responseObj: tokenCredentialRequestWithNewGroup, // a token credential response does not contain a spec
wantMutateRequests: 3,
wantMutateResponses: 1,
wantMutateRequestErrors: []string{`cannot replace token credential request / without authenticator API group`},
wantResponseObj: tokenCredentialRequestWithNewGroup, // the middleware will reset object GVK for us
},
{
name: "create tokencredentialrequest with non-*loginv1alpha1.TokenCredentialRequest",
apiGroupSuffix: newSuffix,
rt: (&testutil.RoundTrip{}).
WithVerb(kubeclient.VerbCreate).
WithResource(loginv1alpha1.SchemeGroupVersion.WithResource("tokencredentialrequests")),
requestObj: podWithoutOwner,
responseObj: podWithoutOwner,
wantMutateRequests: 3,
wantMutateResponses: 1,
wantMutateRequestErrors: []string{`cannot cast obj of type *v1.Pod to *loginv1alpha1.TokenCredentialRequest`},
wantResponseObj: podWithoutOwner,
},
}
for _, test := range tests {
test := test
t.Run(test.name, func(t *testing.T) {
m := New(test.apiGroupSuffix)
if test.wantNilMiddleware {
require.Nil(t, m, "wanted nil middleware")
return
}
m.Handle(context.Background(), test.rt)
require.Len(t, test.rt.MutateRequests, test.wantMutateRequests, "undesired request mutation count")
require.Len(t, test.rt.MutateResponses, test.wantMutateResponses, "undesired response mutation count")
if test.wantMutateRequests != 0 {
require.NotNil(t, test.requestObj, "expected test.requestObj to be set")
objMutated := test.requestObj.DeepCopyObject().(kubeclient.Object)
var mutateRequestErrors []string
for _, mutateRequest := range test.rt.MutateRequests {
mutateRequest := mutateRequest
if err := mutateRequest(objMutated); err != nil {
mutateRequestErrors = append(mutateRequestErrors, err.Error())
}
}
if len(test.wantMutateRequestErrors) > 0 {
require.Equal(t, test.wantMutateRequestErrors, mutateRequestErrors, "mutate request errors did not match")
} else {
require.Equal(t, test.wantRequestObj, objMutated, "request obj did not match")
}
}
if test.wantMutateResponses != 0 {
require.NotNil(t, test.responseObj, "expected test.responseObj to be set")
objMutated := test.responseObj.DeepCopyObject().(kubeclient.Object)
var mutateResponseErrors []string
for _, mutateResponse := range test.rt.MutateResponses {
mutateResponse := mutateResponse
if err := mutateResponse(objMutated); err != nil {
mutateResponseErrors = append(mutateResponseErrors, err.Error())
}
}
if len(test.wantMutateRequestErrors) > 0 {
require.Equal(t, test.wantMutateResponseErrors, mutateResponseErrors, "mutate response errors did not match")
} else {
require.Equal(t, test.wantResponseObj, objMutated, "response obj did not match")
}
}
})
}
}
func TestReplaceError(t *testing.T) {
s, ok := Replace("bad-suffix-that-doesnt-end-in-pinniped-dot-dev", "shouldnt-matter.com")
require.Equal(t, "", s)
require.False(t, ok)
s, ok = Replace("bad-suffix-that-end-in.prefixed-pinniped.dev", "shouldnt-matter.com")
require.Equal(t, "", s)
require.False(t, ok)
}
func TestReplaceSuffix(t *testing.T) {
s, ok := Replace("something.pinniped.dev.something-else.pinniped.dev", "tuna.io")
require.Equal(t, "something.pinniped.dev.something-else.tuna.io", s)
require.True(t, ok)
// When the replace wasn't actually needed, it still returns true.
s, ok = Unreplace("something.pinniped.dev", "pinniped.dev")
require.Equal(t, "something.pinniped.dev", s)
require.True(t, ok)
}
func TestUnreplaceSuffix(t *testing.T) {
s, ok := Unreplace("something.pinniped.dev.something-else.tuna.io", "tuna.io")
require.Equal(t, "something.pinniped.dev.something-else.pinniped.dev", s)
require.True(t, ok)
// When the unreplace wasn't actually needed, it still returns true.
s, ok = Unreplace("something.pinniped.dev", "pinniped.dev")
require.Equal(t, "something.pinniped.dev", s)
require.True(t, ok)
// When the unreplace was needed but did not work, return false.
s, ok = Unreplace("something.pinniped.dev.something-else.tuna.io", "salmon.io")
require.Equal(t, "", s)
require.False(t, ok)
}
func TestValidate(t *testing.T) {
tests := []struct {
apiGroupSuffix string
wantErrorPrefix string
}{
{
apiGroupSuffix: "happy.suffix.com",
},
{
apiGroupSuffix: "no-dots",
wantErrorPrefix: "must contain '.'",
},
{
apiGroupSuffix: ".starts.with.dot",
wantErrorPrefix: "a lowercase RFC 1123 subdomain must consist",
},
{
apiGroupSuffix: "ends.with.dot.",
wantErrorPrefix: "a lowercase RFC 1123 subdomain must consist",
},
{
apiGroupSuffix: ".multiple-issues.because-this-string-is-longer-than-the-253-character-limit-of-a-dns-1123-identifier-" + chars(253),
wantErrorPrefix: "[must be no more than 253 characters, a lowercase RFC 1123 subdomain must consist",
},
}
for _, test := range tests {
test := test
t.Run(test.apiGroupSuffix, func(t *testing.T) {
err := Validate(test.apiGroupSuffix)
if test.wantErrorPrefix != "" {
require.Error(t, err)
require.Truef(
t,
strings.HasPrefix(err.Error(), test.wantErrorPrefix),
"%q does not start with %q", err.Error(), test.wantErrorPrefix)
} else {
require.NoError(t, err)
}
})
}
}
type withFunc func(obj kubeclient.Object)
func with(obj kubeclient.Object, withFuncs ...withFunc) kubeclient.Object {
obj = obj.DeepCopyObject().(kubeclient.Object)
for _, withFunc := range withFuncs {
withFunc(obj)
}
return obj
}
func gvk(gvk schema.GroupVersionKind) withFunc {
return func(obj kubeclient.Object) {
obj.GetObjectKind().SetGroupVersionKind(gvk)
}
}
func authenticatorAPIGroup(apiGroup string) withFunc {
return func(obj kubeclient.Object) {
tokenCredentialRequest := obj.(*loginv1alpha1.TokenCredentialRequest)
tokenCredentialRequest.Spec.Authenticator.APIGroup = &apiGroup
}
}
func replaceGV(t *testing.T, baseGV schema.GroupVersion, apiGroupSuffix string) schema.GroupVersion {
t.Helper()
groupName, ok := Replace(baseGV.Group, apiGroupSuffix)
require.True(t, ok, "expected to be able to replace %q's suffix with %q", baseGV.Group, apiGroupSuffix)
return schema.GroupVersion{Group: groupName, Version: baseGV.Version}
}
func chars(count int) string {
return strings.Repeat("a", count)
}