diff --git a/test/integration/ldap_client_test.go b/test/integration/ldap_client_test.go index e6d97326d..69cd43e19 100644 --- a/test/integration/ldap_client_test.go +++ b/test/integration/ldap_client_test.go @@ -49,10 +49,10 @@ func TestLDAPSearch_Parallel(t *testing.T) { ldapsLocalhostPort := localhostPorts[1] unusedLocalhostPort := localhostPorts[2] - // Expose the the test LDAP server's TLS port on the localhost. + // Expose the test LDAP server's TLS port on the localhost. startKubectlPortForward(ctx, t, ldapsLocalhostPort, "ldaps", "ldap", env.ToolsNamespace) - // Expose the the test LDAP server's StartTLS port on the localhost. + // Expose the test LDAP server's StartTLS port on the localhost. startKubectlPortForward(ctx, t, ldapLocalhostPort, "ldap", "ldap", env.ToolsNamespace) providerConfig := func(editFunc func(p *upstreamldap.ProviderConfig)) *upstreamldap.ProviderConfig { @@ -853,11 +853,11 @@ func startKubectlPortForward(ctx context.Context, t *testing.T, hostPort, remote func findRecentlyUnusedLocalhostPorts(t *testing.T, howManyPorts int) []string { t.Helper() - listeners := []net.Listener{} - for range howManyPorts { - unusedPortGrabbingListener, err := net.Listen("tcp", "127.0.0.1:0") + listeners := make([]net.Listener, howManyPorts) + for i := range howManyPorts { + var err error + listeners[i], err = net.Listen("tcp", "127.0.0.1:0") require.NoError(t, err) - listeners = append(listeners, unusedPortGrabbingListener) } ports := make([]string, len(listeners)) diff --git a/test/integration/supervisor_ad_idp_test.go b/test/integration/supervisor_ad_idp_test.go new file mode 100644 index 000000000..91841590f --- /dev/null +++ b/test/integration/supervisor_ad_idp_test.go @@ -0,0 +1,193 @@ +// Copyright 2024 the Pinniped contributors. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 + +package integration + +import ( + "context" + "encoding/base64" + "fmt" + "testing" + "time" + + corev1 "k8s.io/api/core/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + + idpv1alpha1 "go.pinniped.dev/generated/latest/apis/supervisor/idp/v1alpha1" + "go.pinniped.dev/test/testlib" +) + +func TestActiveDirectoryIDPPhaseAndConditions_Parallel(t *testing.T) { + env := testlib.IntegrationEnv(t) + testlib.SkipTestWhenActiveDirectoryIsUnavailable(t, env) + + supervisorNamespace := testlib.IntegrationEnv(t).SupervisorNamespace + ctx, cancel := context.WithTimeout(context.Background(), 10*time.Minute) + t.Cleanup(cancel) + + adIDPClient := testlib.NewSupervisorClientset(t).IDPV1alpha1().ActiveDirectoryIdentityProviders(supervisorNamespace) + + bindSecret := testlib.CreateTestSecret( + t, + env.SupervisorNamespace, + "ad-bind-secret", + corev1.SecretTypeBasicAuth, + map[string]string{ + corev1.BasicAuthUsernameKey: env.SupervisorUpstreamActiveDirectory.BindUsername, + corev1.BasicAuthPasswordKey: env.SupervisorUpstreamActiveDirectory.BindPassword, + }, + ) + + happySpec := idpv1alpha1.ActiveDirectoryIdentityProviderSpec{ + Host: env.SupervisorUpstreamActiveDirectory.Host, + Bind: idpv1alpha1.ActiveDirectoryIdentityProviderBind{ + SecretName: bindSecret.Name, + }, + TLS: &idpv1alpha1.TLSSpec{ + CertificateAuthorityData: base64.StdEncoding.EncodeToString([]byte(env.SupervisorUpstreamActiveDirectory.CABundle)), + }, + UserSearch: idpv1alpha1.ActiveDirectoryIdentityProviderUserSearch{ + Base: env.SupervisorUpstreamActiveDirectory.UserSearchBase, + Filter: "", + Attributes: idpv1alpha1.ActiveDirectoryIdentityProviderUserSearchAttributes{ + Username: env.SupervisorUpstreamActiveDirectory.TestUserMailAttributeName, + UID: env.SupervisorUpstreamActiveDirectory.TestUserUniqueIDAttributeName, + }, + }, + GroupSearch: idpv1alpha1.ActiveDirectoryIdentityProviderGroupSearch{ + Base: env.SupervisorUpstreamActiveDirectory.GroupSearchBase, + Filter: "", // use the default value of "member={}" + Attributes: idpv1alpha1.ActiveDirectoryIdentityProviderGroupSearchAttributes{ + GroupName: "", // use the default value of "dn" + }, + }, + } + + tests := []struct { + name string + adSpec idpv1alpha1.ActiveDirectoryIdentityProviderSpec + wantPhase idpv1alpha1.ActiveDirectoryIdentityProviderPhase + wantConditions []*metav1.Condition + }{ + { + name: "Happy Path", + adSpec: happySpec, + wantPhase: idpv1alpha1.ActiveDirectoryPhaseReady, + wantConditions: []*metav1.Condition{ + { + Type: "BindSecretValid", + Status: "True", + Reason: "Success", + Message: "loaded bind secret", + }, + { + Type: "LDAPConnectionValid", + Status: "True", + Reason: "Success", + Message: fmt.Sprintf( + `successfully able to connect to %q and bind as user %q [validated with Secret %q at version %q]`, + env.SupervisorUpstreamActiveDirectory.Host, + env.SupervisorUpstreamActiveDirectory.BindUsername, + bindSecret.Name, + bindSecret.ResourceVersion), + }, + { + Type: "SearchBaseFound", + Status: "True", + Reason: "UsingConfigurationFromSpec", + Message: "Using search base from ActiveDirectoryIdentityProvider config.", + }, + { + Type: "TLSConfigurationValid", + Status: "True", + Reason: "Success", + Message: "spec.tls is valid: using configured CA bundle", + }, + }, + }, + { + name: "CA bundle is invalid yields conditions TLSConfigurationValid with status 'False' and LDAPConnectionValid with status 'Unknown'", + adSpec: func() idpv1alpha1.ActiveDirectoryIdentityProviderSpec { + temp := happySpec.DeepCopy() + temp.TLS.CertificateAuthorityData = "this-is-not-base64-encoded" + return *temp + }(), + wantPhase: idpv1alpha1.ActiveDirectoryPhaseError, + wantConditions: []*metav1.Condition{ + { + Type: "BindSecretValid", + Status: "True", + Reason: "Success", + Message: "loaded bind secret", + }, + { + Type: "LDAPConnectionValid", + Status: "Unknown", + Reason: "UnableToValidate", + Message: "unable to validate; see other conditions for details", + }, + { + Type: "SearchBaseFound", + Status: "Unknown", + Reason: "UnableToValidate", + Message: "unable to validate; see other conditions for details", + }, + { + Type: "TLSConfigurationValid", + Status: "False", + Reason: "InvalidTLSConfig", + Message: "spec.tls.certificateAuthorityData is invalid: illegal base64 data at input byte 4", + }, + }, + }, + { + name: "Bind secret not found yields conditions BindSecretValid with status 'False' and LDAPConnectionValid with status 'Unknown'", + adSpec: func() idpv1alpha1.ActiveDirectoryIdentityProviderSpec { + temp := happySpec.DeepCopy() + temp.Bind.SecretName = "this-secret-does-not-exist" + return *temp + }(), + wantPhase: idpv1alpha1.ActiveDirectoryPhaseError, + wantConditions: []*metav1.Condition{ + { + Type: "BindSecretValid", + Status: "False", + Reason: "SecretNotFound", + Message: `secret "this-secret-does-not-exist" not found`, + }, + { + Type: "LDAPConnectionValid", + Status: "Unknown", + Reason: "UnableToValidate", + Message: "unable to validate; see other conditions for details", + }, + { + Type: "SearchBaseFound", + Status: "Unknown", + Reason: "UnableToValidate", + Message: "unable to validate; see other conditions for details", + }, + { + Type: "TLSConfigurationValid", + Status: "True", + Reason: "Success", + Message: "spec.tls is valid: using configured CA bundle", + }, + }, + }, + } + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + t.Parallel() + + idp := testlib.CreateTestActiveDirectoryIdentityProvider(t, test.adSpec, test.wantPhase) + testlib.WaitForActiveDirectoryIdentityProviderStatusConditions( + ctx, + t, + adIDPClient, + idp.Name, + test.wantConditions, + ) + }) + } +} diff --git a/test/integration/supervisor_github_idp_test.go b/test/integration/supervisor_github_idp_test.go index 54f272aa0..bd713254a 100644 --- a/test/integration/supervisor_github_idp_test.go +++ b/test/integration/supervisor_github_idp_test.go @@ -24,7 +24,7 @@ import ( "go.pinniped.dev/test/testlib" ) -const generateNamePrefix = "integration-test-github-idp-" +const generateGitHubNamePrefix = "integration-test-github-idp-" func TestGitHubIDPStaticValidationOnCreate_Parallel(t *testing.T) { adminClient := testlib.NewKubernetesClientset(t) @@ -37,7 +37,7 @@ func TestGitHubIDPStaticValidationOnCreate_Parallel(t *testing.T) { ns, err := namespaceClient.Create(ctx, &corev1.Namespace{ ObjectMeta: metav1.ObjectMeta{ - GenerateName: generateNamePrefix, + GenerateName: generateGitHubNamePrefix, }, }, metav1.CreateOptions{}) require.NoError(t, err) @@ -240,7 +240,7 @@ func TestGitHubIDPStaticValidationOnCreate_Parallel(t *testing.T) { input := &idpv1alpha1.GitHubIdentityProvider{ ObjectMeta: metav1.ObjectMeta{ - GenerateName: generateNamePrefix, + GenerateName: generateGitHubNamePrefix, }, Spec: tt.inputSpec, } @@ -268,7 +268,7 @@ func TestGitHubIDPSetsDefaultsWithKubectl_Parallel(t *testing.T) { ns, err := namespaceClient.Create(ctx, &corev1.Namespace{ ObjectMeta: metav1.ObjectMeta{ - GenerateName: generateNamePrefix, + GenerateName: generateGitHubNamePrefix, }, }, metav1.CreateOptions{}) require.NoError(t, err) @@ -278,7 +278,7 @@ func TestGitHubIDPSetsDefaultsWithKubectl_Parallel(t *testing.T) { }) t.Logf("Created namespace %s", ns.Name) - idpName := generateNamePrefix + testlib.RandHex(t, 16) + idpName := generateGitHubNamePrefix + testlib.RandHex(t, 16) githubIDPYaml := []byte(here.Doc(fmt.Sprintf(` --- @@ -336,8 +336,8 @@ func TestGitHubIDPPhaseAndConditions_Parallel(t *testing.T) { secretsClient := kubernetesClient.CoreV1().Secrets(supervisorNamespace) gitHubIDPClient := testlib.NewSupervisorClientset(t).IDPV1alpha1().GitHubIdentityProviders(supervisorNamespace) - happySecretName := generateNamePrefix + testlib.RandHex(t, 16) - invalidSecretName := generateNamePrefix + testlib.RandHex(t, 16) + happySecretName := generateGitHubNamePrefix + testlib.RandHex(t, 16) + invalidSecretName := generateGitHubNamePrefix + testlib.RandHex(t, 16) tests := []struct { name string @@ -490,7 +490,7 @@ func TestGitHubIDPPhaseAndConditions_Parallel(t *testing.T) { var secretName string for _, secret := range tt.secrets { - secret.GenerateName = generateNamePrefix + secret.GenerateName = generateGitHubNamePrefix created, err := secretsClient.Create(ctx, secret, metav1.CreateOptions{}) require.NoError(t, err) @@ -505,7 +505,7 @@ func TestGitHubIDPPhaseAndConditions_Parallel(t *testing.T) { for _, idp := range tt.idps { idp.Name = "" - idp.GenerateName = generateNamePrefix + idp.GenerateName = generateGitHubNamePrefix idp.Spec.Client.SecretName = secretName created, err := gitHubIDPClient.Create(ctx, idp, metav1.CreateOptions{}) @@ -532,7 +532,7 @@ func TestGitHubIDPInWrongNamespace_Parallel(t *testing.T) { namespaceClient := kubernetesClient.CoreV1().Namespaces() otherNamespace, err := namespaceClient.Create(ctx, &corev1.Namespace{ ObjectMeta: metav1.ObjectMeta{ - GenerateName: generateNamePrefix, + GenerateName: generateGitHubNamePrefix, }, }, metav1.CreateOptions{}) require.NoError(t, err) @@ -545,7 +545,7 @@ func TestGitHubIDPInWrongNamespace_Parallel(t *testing.T) { idp := &idpv1alpha1.GitHubIdentityProvider{ ObjectMeta: metav1.ObjectMeta{ - GenerateName: generateNamePrefix, + GenerateName: generateGitHubNamePrefix, Namespace: otherNamespace.Name, }, Spec: idpv1alpha1.GitHubIdentityProviderSpec{ @@ -592,7 +592,7 @@ func TestGitHubIDPSecretInOtherNamespace_Parallel(t *testing.T) { namespaceClient := kubernetesClient.CoreV1().Namespaces() otherNamespace, err := namespaceClient.Create(ctx, &corev1.Namespace{ ObjectMeta: metav1.ObjectMeta{ - GenerateName: generateNamePrefix, + GenerateName: generateGitHubNamePrefix, }, }, metav1.CreateOptions{}) require.NoError(t, err) @@ -605,7 +605,7 @@ func TestGitHubIDPSecretInOtherNamespace_Parallel(t *testing.T) { secret := &corev1.Secret{ ObjectMeta: metav1.ObjectMeta{ - GenerateName: generateNamePrefix, + GenerateName: generateGitHubNamePrefix, Namespace: otherNamespace.Name, }, Type: "secrets.pinniped.dev/github-client", @@ -621,7 +621,7 @@ func TestGitHubIDPSecretInOtherNamespace_Parallel(t *testing.T) { idp := &idpv1alpha1.GitHubIdentityProvider{ ObjectMeta: metav1.ObjectMeta{ - GenerateName: generateNamePrefix, + GenerateName: generateGitHubNamePrefix, Namespace: supervisorNamespace, }, Spec: idpv1alpha1.GitHubIdentityProviderSpec{ @@ -701,7 +701,7 @@ func TestGitHubIDPTooManyOrganizationsStaticValidationOnCreate_Parallel(t *testi ns, err := namespaceClient.Create(ctx, &corev1.Namespace{ ObjectMeta: metav1.ObjectMeta{ - GenerateName: generateNamePrefix, + GenerateName: generateGitHubNamePrefix, }, }, metav1.CreateOptions{}) require.NoError(t, err) @@ -714,7 +714,7 @@ func TestGitHubIDPTooManyOrganizationsStaticValidationOnCreate_Parallel(t *testi input := &idpv1alpha1.GitHubIdentityProvider{ ObjectMeta: metav1.ObjectMeta{ - GenerateName: generateNamePrefix, + GenerateName: generateGitHubNamePrefix, }, Spec: idpv1alpha1.GitHubIdentityProviderSpec{ AllowAuthentication: idpv1alpha1.GitHubAllowAuthenticationSpec{ diff --git a/test/integration/supervisor_ldap_idp_test.go b/test/integration/supervisor_ldap_idp_test.go new file mode 100644 index 000000000..ad33865bf --- /dev/null +++ b/test/integration/supervisor_ldap_idp_test.go @@ -0,0 +1,174 @@ +// Copyright 2024 the Pinniped contributors. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 + +package integration + +import ( + "context" + "encoding/base64" + "fmt" + "testing" + "time" + + corev1 "k8s.io/api/core/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + + idpv1alpha1 "go.pinniped.dev/generated/latest/apis/supervisor/idp/v1alpha1" + "go.pinniped.dev/test/testlib" +) + +func TestLDAPIDPPhaseAndConditions_Parallel(t *testing.T) { + env := testlib.IntegrationEnv(t) + + supervisorNamespace := testlib.IntegrationEnv(t).SupervisorNamespace + ctx, cancel := context.WithTimeout(context.Background(), 10*time.Minute) + t.Cleanup(cancel) + + ldapIDPClient := testlib.NewSupervisorClientset(t).IDPV1alpha1().LDAPIdentityProviders(supervisorNamespace) + + bindSecret := testlib.CreateTestSecret( + t, + env.SupervisorNamespace, + "ldap-bind-secret", + corev1.SecretTypeBasicAuth, + map[string]string{ + corev1.BasicAuthUsernameKey: env.SupervisorUpstreamLDAP.BindUsername, + corev1.BasicAuthPasswordKey: env.SupervisorUpstreamLDAP.BindPassword, + }, + ) + + happySpec := idpv1alpha1.LDAPIdentityProviderSpec{ + Host: env.SupervisorUpstreamLDAP.Host, + Bind: idpv1alpha1.LDAPIdentityProviderBind{ + SecretName: bindSecret.Name, + }, + TLS: &idpv1alpha1.TLSSpec{ + CertificateAuthorityData: base64.StdEncoding.EncodeToString([]byte(env.SupervisorUpstreamLDAP.CABundle)), + }, + UserSearch: idpv1alpha1.LDAPIdentityProviderUserSearch{ + Base: env.SupervisorUpstreamLDAP.UserSearchBase, + Filter: "", + Attributes: idpv1alpha1.LDAPIdentityProviderUserSearchAttributes{ + Username: env.SupervisorUpstreamLDAP.TestUserMailAttributeName, + UID: env.SupervisorUpstreamLDAP.TestUserUniqueIDAttributeName, + }, + }, + GroupSearch: idpv1alpha1.LDAPIdentityProviderGroupSearch{ + Base: env.SupervisorUpstreamLDAP.GroupSearchBase, + Filter: "", // use the default value of "member={}" + Attributes: idpv1alpha1.LDAPIdentityProviderGroupSearchAttributes{ + GroupName: "", // use the default value of "dn" + }, + }, + } + + tests := []struct { + name string + ldapSpec idpv1alpha1.LDAPIdentityProviderSpec + wantPhase idpv1alpha1.LDAPIdentityProviderPhase + wantConditions []*metav1.Condition + }{ + { + name: "Happy Path", + ldapSpec: happySpec, + wantPhase: idpv1alpha1.LDAPPhaseReady, + wantConditions: []*metav1.Condition{ + { + Type: "BindSecretValid", + Status: "True", + Reason: "Success", + Message: "loaded bind secret", + }, + { + Type: "LDAPConnectionValid", + Status: "True", + Reason: "Success", + Message: fmt.Sprintf( + `successfully able to connect to %q and bind as user %q [validated with Secret %q at version %q]`, + env.SupervisorUpstreamLDAP.Host, + env.SupervisorUpstreamLDAP.BindUsername, + bindSecret.Name, + bindSecret.ResourceVersion), + }, + { + Type: "TLSConfigurationValid", + Status: "True", + Reason: "Success", + Message: "spec.tls is valid: using configured CA bundle", + }, + }, + }, + { + name: "CA bundle is invalid yields conditions TLSConfigurationValid with status 'False' and LDAPConnectionValid/SearchBaseFound with status 'Unknown'", + ldapSpec: func() idpv1alpha1.LDAPIdentityProviderSpec { + temp := happySpec.DeepCopy() + temp.TLS.CertificateAuthorityData = "this-is-not-base64-encoded" + return *temp + }(), + wantPhase: idpv1alpha1.LDAPPhaseError, + wantConditions: []*metav1.Condition{ + { + Type: "BindSecretValid", + Status: "True", + Reason: "Success", + Message: "loaded bind secret", + }, + { + Type: "LDAPConnectionValid", + Status: "Unknown", + Reason: "UnableToValidate", + Message: "unable to validate; see other conditions for details", + }, + { + Type: "TLSConfigurationValid", + Status: "False", + Reason: "InvalidTLSConfig", + Message: "spec.tls.certificateAuthorityData is invalid: illegal base64 data at input byte 4", + }, + }, + }, + { + name: "Bind secret not found yields conditions BindSecretValid with status 'False' and LDAPConnectionValid/SearchBaseFound with status 'Unknown'", + ldapSpec: func() idpv1alpha1.LDAPIdentityProviderSpec { + temp := happySpec.DeepCopy() + temp.Bind.SecretName = "this-secret-does-not-exist" + return *temp + }(), + wantPhase: idpv1alpha1.LDAPPhaseError, + wantConditions: []*metav1.Condition{ + { + Type: "BindSecretValid", + Status: "False", + Reason: "SecretNotFound", + Message: `secret "this-secret-does-not-exist" not found`, + }, + { + Type: "LDAPConnectionValid", + Status: "Unknown", + Reason: "UnableToValidate", + Message: "unable to validate; see other conditions for details", + }, + { + Type: "TLSConfigurationValid", + Status: "True", + Reason: "Success", + Message: "spec.tls is valid: using configured CA bundle", + }, + }, + }, + } + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + t.Parallel() + + idp := testlib.CreateTestLDAPIdentityProvider(t, test.ldapSpec, test.wantPhase) + testlib.WaitForLDAPIdentityProviderStatusConditions( + ctx, + t, + ldapIDPClient, + idp.Name, + test.wantConditions, + ) + }) + } +} diff --git a/test/testlib/client.go b/test/testlib/client.go index 36f455e82..41271f3e6 100644 --- a/test/testlib/client.go +++ b/test/testlib/client.go @@ -1000,6 +1000,80 @@ func WaitForGitHubIdentityProviderStatusConditions( }, 60*time.Second, 1*time.Second, "wanted conditions for GitHubIdentityProvider %q", gitHubIDPName) } +func WaitForLDAPIdentityProviderStatusConditions( + ctx context.Context, + t *testing.T, + client alpha1.LDAPIdentityProviderInterface, + ldapIDPName string, + expectConditions []*metav1.Condition, +) { + t.Helper() + + RequireEventuallyf(t, func(requireEventually *require.Assertions) { + idp, err := client.Get(ctx, ldapIDPName, metav1.GetOptions{}) + requireEventually.NoError(err) + + actualConditions := make([]*metav1.Condition, len(idp.Status.Conditions)) + for i, c := range idp.Status.Conditions { + actualConditions[i] = c.DeepCopy() + } + + requireEventually.Lenf(actualConditions, len(expectConditions), + "wanted status conditions: %#v", expectConditions) + + for i, wantCond := range expectConditions { + actualCond := actualConditions[i] + + // This is a cheat to avoid needing to make equality assertions on these fields. + requireEventually.NotZero(actualCond.LastTransitionTime) + wantCond.LastTransitionTime = actualCond.LastTransitionTime + requireEventually.NotZero(actualCond.ObservedGeneration) + wantCond.ObservedGeneration = actualCond.ObservedGeneration + + requireEventually.Equalf(wantCond, actualCond, + "wanted status conditions: %#v\nactual status conditions were: %#v\nnot equal at index %d", + expectConditions, &actualConditions, i) + } + }, 60*time.Second, 1*time.Second, "wanted conditions for LDAPIdentityProvider %q", ldapIDPName) +} + +func WaitForActiveDirectoryIdentityProviderStatusConditions( + ctx context.Context, + t *testing.T, + client alpha1.ActiveDirectoryIdentityProviderInterface, + activeDirectoryIDPName string, + expectConditions []*metav1.Condition, +) { + t.Helper() + + RequireEventuallyf(t, func(requireEventually *require.Assertions) { + idp, err := client.Get(ctx, activeDirectoryIDPName, metav1.GetOptions{}) + requireEventually.NoError(err) + + actualConditions := make([]*metav1.Condition, len(idp.Status.Conditions)) + for i, c := range idp.Status.Conditions { + actualConditions[i] = c.DeepCopy() + } + + requireEventually.Lenf(actualConditions, len(expectConditions), + "wanted status conditions: %#v", expectConditions) + + for i, wantCond := range expectConditions { + actualCond := actualConditions[i] + + // This is a cheat to avoid needing to make equality assertions on these fields. + requireEventually.NotZero(actualCond.LastTransitionTime) + wantCond.LastTransitionTime = actualCond.LastTransitionTime + requireEventually.NotZero(actualCond.ObservedGeneration) + wantCond.ObservedGeneration = actualCond.ObservedGeneration + + requireEventually.Equalf(wantCond, actualCond, + "wanted status conditions: %#v\nactual status conditions were: %#v\nnot equal at index %d", + expectConditions, &actualConditions, i) + } + }, 60*time.Second, 1*time.Second, "wanted conditions for ActiveDirectoryIdentityProvider %q", activeDirectoryIDPName) +} + func TestObjectMeta(t *testing.T, baseName string) metav1.ObjectMeta { return metav1.ObjectMeta{ GenerateName: fmt.Sprintf("test-%s-", baseName),