ba98c8cc14
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).
689 lines
26 KiB
Go
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)
|
|
}
|