Populate internal GitHub IDP Config from CRD

This commit is contained in:
Joshua Casey
2024-04-16 14:33:01 -05:00
parent 349039ff5d
commit c9b61ef010
51 changed files with 3256 additions and 289 deletions
+378 -28
View File
@@ -21,6 +21,8 @@ import (
"go.pinniped.dev/test/testlib"
)
const generateNamePrefix = "integration-test-github-idp-"
func TestGitHubIDPStaticValidationOnCreate_Parallel(t *testing.T) {
adminClient := testlib.NewKubernetesClientset(t)
@@ -32,7 +34,7 @@ func TestGitHubIDPStaticValidationOnCreate_Parallel(t *testing.T) {
ns, err := namespaceClient.Create(ctx, &corev1.Namespace{
ObjectMeta: metav1.ObjectMeta{
GenerateName: "test-github-idp-",
GenerateName: generateNamePrefix,
},
}, metav1.CreateOptions{})
require.NoError(t, err)
@@ -45,10 +47,10 @@ func TestGitHubIDPStaticValidationOnCreate_Parallel(t *testing.T) {
tests := []struct {
name string
inputSpec idpv1alpha1.GitHubIdentityProviderSpec
expectedSpec idpv1alpha1.GitHubIdentityProviderSpec
usesCELValidation bool
expectedErr string
inputSpec idpv1alpha1.GitHubIdentityProviderSpec
wantSpec idpv1alpha1.GitHubIdentityProviderSpec
wantErr string
}{
{
name: "all fields set",
@@ -78,7 +80,7 @@ func TestGitHubIDPStaticValidationOnCreate_Parallel(t *testing.T) {
SecretName: "any-name-goes-here",
},
},
expectedSpec: idpv1alpha1.GitHubIdentityProviderSpec{
wantSpec: idpv1alpha1.GitHubIdentityProviderSpec{
GitHubAPI: idpv1alpha1.GitHubAPIConfig{
Host: ptr.To("some-host.example.com"),
TLS: &idpv1alpha1.TLSSpec{
@@ -115,7 +117,7 @@ func TestGitHubIDPStaticValidationOnCreate_Parallel(t *testing.T) {
SecretName: "name-of-a-secret",
},
},
expectedSpec: idpv1alpha1.GitHubIdentityProviderSpec{
wantSpec: idpv1alpha1.GitHubIdentityProviderSpec{
GitHubAPI: idpv1alpha1.GitHubAPIConfig{
Host: ptr.To("github.com"),
},
@@ -137,6 +139,7 @@ func TestGitHubIDPStaticValidationOnCreate_Parallel(t *testing.T) {
name: fmt.Sprintf(
"cannot set AllowedOrganizationsPolicy=%s and set AllowedOrganizations",
string(idpv1alpha1.GitHubAllowedAuthOrganizationsPolicyAllGitHubUsers)),
usesCELValidation: true,
inputSpec: idpv1alpha1.GitHubIdentityProviderSpec{
AllowAuthentication: idpv1alpha1.GitHubAllowAuthenticationSpec{
Organizations: idpv1alpha1.GitHubOrganizationsSpec{
@@ -150,11 +153,11 @@ func TestGitHubIDPStaticValidationOnCreate_Parallel(t *testing.T) {
SecretName: "name-of-a-secret",
},
},
usesCELValidation: true,
expectedErr: "spec.allowAuthentication.organizations.policy must be 'OnlyUsersFromAllowedOrganizations' when spec.allowAuthentication.organizations.allowed has organizations listed",
wantErr: "spec.allowAuthentication.organizations.policy must be 'OnlyUsersFromAllowedOrganizations' when spec.allowAuthentication.organizations.allowed has organizations listed",
},
{
name: fmt.Sprintf("spec.allowAuthentication.organizations.policy must be '%s' when spec.allowAuthentication.organizations.allowed is empty (nil)", string(idpv1alpha1.GitHubAllowedAuthOrganizationsPolicyAllGitHubUsers)),
name: fmt.Sprintf("spec.allowAuthentication.organizations.policy must be '%s' when spec.allowAuthentication.organizations.allowed is empty (nil)", string(idpv1alpha1.GitHubAllowedAuthOrganizationsPolicyAllGitHubUsers)),
usesCELValidation: true,
inputSpec: idpv1alpha1.GitHubIdentityProviderSpec{
AllowAuthentication: idpv1alpha1.GitHubAllowAuthenticationSpec{
Organizations: idpv1alpha1.GitHubOrganizationsSpec{
@@ -165,11 +168,11 @@ func TestGitHubIDPStaticValidationOnCreate_Parallel(t *testing.T) {
SecretName: "name-of-a-secret",
},
},
usesCELValidation: true,
expectedErr: "spec.allowAuthentication.organizations.policy must be 'AllGitHubUsers' when spec.allowAuthentication.organizations.allowed is empty",
wantErr: "spec.allowAuthentication.organizations.policy must be 'AllGitHubUsers' when spec.allowAuthentication.organizations.allowed is empty",
},
{
name: fmt.Sprintf("spec.allowAuthentication.organizations.policy must be '%s' when spec.allowAuthentication.organizations.allowed is empty", string(idpv1alpha1.GitHubAllowedAuthOrganizationsPolicyAllGitHubUsers)),
name: fmt.Sprintf("spec.allowAuthentication.organizations.policy must be '%s' when spec.allowAuthentication.organizations.allowed is empty", string(idpv1alpha1.GitHubAllowedAuthOrganizationsPolicyAllGitHubUsers)),
usesCELValidation: true,
inputSpec: idpv1alpha1.GitHubIdentityProviderSpec{
AllowAuthentication: idpv1alpha1.GitHubAllowAuthenticationSpec{
Organizations: idpv1alpha1.GitHubOrganizationsSpec{
@@ -181,13 +184,12 @@ func TestGitHubIDPStaticValidationOnCreate_Parallel(t *testing.T) {
SecretName: "name-of-a-secret",
},
},
usesCELValidation: true,
expectedErr: "spec.allowAuthentication.organizations.policy must be 'AllGitHubUsers' when spec.allowAuthentication.organizations.allowed is empty",
wantErr: "spec.allowAuthentication.organizations.policy must be 'AllGitHubUsers' when spec.allowAuthentication.organizations.allowed is empty",
},
{
name: "spec.client.secretName in body should be at least 1 chars long",
inputSpec: idpv1alpha1.GitHubIdentityProviderSpec{},
expectedErr: "spec.client.secretName in body should be at least 1 chars long",
name: "spec.client.secretName in body should be at least 1 chars long",
inputSpec: idpv1alpha1.GitHubIdentityProviderSpec{},
wantErr: "spec.client.secretName in body should be at least 1 chars long",
},
{
name: "spec.githubAPI.host in body should be at least 1 chars long",
@@ -204,7 +206,7 @@ func TestGitHubIDPStaticValidationOnCreate_Parallel(t *testing.T) {
SecretName: "name-of-a-secret",
},
},
expectedErr: "spec.githubAPI.host in body should be at least 1 chars long",
wantErr: "spec.githubAPI.host in body should be at least 1 chars long",
},
{
name: "duplicates not permitted in spec.allowAuthentication.organizations.allowed",
@@ -222,7 +224,7 @@ func TestGitHubIDPStaticValidationOnCreate_Parallel(t *testing.T) {
SecretName: "name-of-a-secret",
},
},
expectedErr: `spec.allowAuthentication.organizations.allowed[1]: Duplicate value: "org1"`,
wantErr: `spec.allowAuthentication.organizations.allowed[1]: Duplicate value: "org1"`,
},
}
for _, tt := range tests {
@@ -236,22 +238,370 @@ func TestGitHubIDPStaticValidationOnCreate_Parallel(t *testing.T) {
input := &idpv1alpha1.GitHubIdentityProvider{
ObjectMeta: metav1.ObjectMeta{
GenerateName: "integration-test-",
GenerateName: generateNamePrefix,
},
Spec: tt.inputSpec,
}
outputGitHubIDP, err := gitHubIDPClient.Create(ctx, input, metav1.CreateOptions{})
if tt.expectedErr == "" {
if tt.wantErr == "" {
require.NoError(t, err)
require.Equal(t, tt.expectedSpec, outputGitHubIDP.Spec)
require.Equal(t, tt.wantSpec, outputGitHubIDP.Spec)
} else {
require.ErrorContains(t, err, tt.expectedErr)
require.ErrorContains(t, err, tt.wantErr)
}
})
}
}
func TestGitHubIDPPhaseAndConditions_Parallel(t *testing.T) {
// These operations must be performed in the Supervisor's namespace so that the controller can find GitHubIdentityProvider
supervisorNamespace := testlib.IntegrationEnv(t).SupervisorNamespace
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Minute)
t.Cleanup(cancel)
kubernetesClient := testlib.NewKubernetesClientset(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)
tests := []struct {
name string
secrets []*corev1.Secret // Secrets will be created first, and the first secret found will be listed as the configured GitHub Client secret
idps []*idpv1alpha1.GitHubIdentityProvider
wantPhase idpv1alpha1.GitHubIdentityProviderPhase
wantConditions []*metav1.Condition
}{
{
name: "Happy Path",
secrets: []*corev1.Secret{
{
ObjectMeta: metav1.ObjectMeta{
Name: happySecretName,
},
Type: "secrets.pinniped.dev/github-client",
Data: map[string][]byte{
"clientID": []byte("foo"),
"clientSecret": []byte("bar"),
},
},
},
idps: []*idpv1alpha1.GitHubIdentityProvider{
{
Spec: idpv1alpha1.GitHubIdentityProviderSpec{
GitHubAPI: idpv1alpha1.GitHubAPIConfig{
Host: ptr.To("github.com"),
},
AllowAuthentication: idpv1alpha1.GitHubAllowAuthenticationSpec{
Organizations: idpv1alpha1.GitHubOrganizationsSpec{
Policy: ptr.To(idpv1alpha1.GitHubAllowedAuthOrganizationsPolicyAllGitHubUsers),
},
},
},
},
},
wantPhase: idpv1alpha1.GitHubPhaseReady,
wantConditions: []*metav1.Condition{
{
Type: "ClientCredentialsObtained",
Status: metav1.ConditionTrue,
Reason: "Success",
Message: fmt.Sprintf("clientID and clientSecret have been read from spec.client.SecretName (%q)", happySecretName),
},
{
Type: "GitHubConnectionValid",
Status: metav1.ConditionTrue,
Reason: "Success",
Message: `spec.githubAPI.host ("github.com:443") is reachable and TLS verification succeeds`,
},
{
Type: "HostValid",
Status: metav1.ConditionTrue,
Reason: "Success",
Message: `spec.githubAPI.host ("github.com") is valid`,
},
{
Type: "OrganizationsPolicyValid",
Status: metav1.ConditionTrue,
Reason: "Success",
Message: `spec.allowAuthentication.organizations.policy ("AllGitHubUsers") is valid`,
},
{
Type: "TLSConfigurationValid",
Status: metav1.ConditionTrue,
Reason: "Success",
Message: "spec.githubAPI.tls.certificateAuthorityData is valid",
},
},
},
{
name: "Invalid Client Secret",
secrets: []*corev1.Secret{
{
Type: "secrets.pinniped.dev/github-client",
ObjectMeta: metav1.ObjectMeta{
Name: invalidSecretName,
},
},
},
idps: []*idpv1alpha1.GitHubIdentityProvider{
{
Spec: idpv1alpha1.GitHubIdentityProviderSpec{
GitHubAPI: idpv1alpha1.GitHubAPIConfig{
Host: ptr.To("github.com"),
},
AllowAuthentication: idpv1alpha1.GitHubAllowAuthenticationSpec{
Organizations: idpv1alpha1.GitHubOrganizationsSpec{
Policy: ptr.To(idpv1alpha1.GitHubAllowedAuthOrganizationsPolicyAllGitHubUsers),
},
},
Client: idpv1alpha1.GitHubClientSpec{
SecretName: invalidSecretName,
},
},
},
},
wantPhase: idpv1alpha1.GitHubPhaseError,
wantConditions: []*metav1.Condition{
{
Type: "ClientCredentialsObtained",
Status: metav1.ConditionFalse,
Reason: "SecretNotFound",
Message: fmt.Sprintf(`missing key "clientID": secret from spec.client.SecretName (%q) must be found in namespace %q with type "secrets.pinniped.dev/github-client" and keys "clientID" and "clientSecret"`,
invalidSecretName,
supervisorNamespace),
},
{
Type: "GitHubConnectionValid",
Status: metav1.ConditionTrue,
Reason: "Success",
Message: `spec.githubAPI.host ("github.com:443") is reachable and TLS verification succeeds`,
},
{
Type: "HostValid",
Status: metav1.ConditionTrue,
Reason: "Success",
Message: `spec.githubAPI.host ("github.com") is valid`,
},
{
Type: "OrganizationsPolicyValid",
Status: metav1.ConditionTrue,
Reason: "Success",
Message: `spec.allowAuthentication.organizations.policy ("AllGitHubUsers") is valid`,
},
{
Type: "TLSConfigurationValid",
Status: metav1.ConditionTrue,
Reason: "Success",
Message: `spec.githubAPI.tls.certificateAuthorityData is valid`,
},
},
},
}
for _, tt := range tests {
tt := tt
t.Run(tt.name, func(t *testing.T) {
t.Parallel()
var secretName string
for _, secret := range tt.secrets {
secret.GenerateName = generateNamePrefix
created, err := secretsClient.Create(ctx, secret, metav1.CreateOptions{})
require.NoError(t, err)
t.Cleanup(func() {
err := secretsClient.Delete(ctx, created.Name, metav1.DeleteOptions{})
require.NoError(t, err)
})
if secretName == "" {
secretName = created.Name
}
}
for _, idp := range tt.idps {
idp.Name = ""
idp.GenerateName = generateNamePrefix
idp.Spec.Client.SecretName = secretName
created, err := gitHubIDPClient.Create(ctx, idp, metav1.CreateOptions{})
require.NoError(t, err)
t.Cleanup(func() {
err := gitHubIDPClient.Delete(ctx, created.Name, metav1.DeleteOptions{})
require.NoError(t, err)
})
testlib.WaitForGitHubIDPPhase(ctx, t, gitHubIDPClient, created.Name, tt.wantPhase)
testlib.WaitForGitHubIdentityProviderStatusConditions(ctx, t, gitHubIDPClient, created.Name, tt.wantConditions)
}
})
}
}
func TestGitHubIDPInWrongNamespace_Parallel(t *testing.T) {
// The GitHubIdentityProvider must be in the same namespace as the controller
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Minute)
t.Cleanup(cancel)
kubernetesClient := testlib.NewKubernetesClientset(t)
namespaceClient := kubernetesClient.CoreV1().Namespaces()
otherNamespace, err := namespaceClient.Create(ctx, &corev1.Namespace{
ObjectMeta: metav1.ObjectMeta{
GenerateName: generateNamePrefix,
},
}, metav1.CreateOptions{})
require.NoError(t, err)
t.Cleanup(func() {
require.NoError(t, namespaceClient.Delete(ctx, otherNamespace.Name, metav1.DeleteOptions{}))
})
gitHubIDPClient := testlib.NewSupervisorClientset(t).IDPV1alpha1().GitHubIdentityProviders(otherNamespace.Name)
idp := &idpv1alpha1.GitHubIdentityProvider{
ObjectMeta: metav1.ObjectMeta{
GenerateName: generateNamePrefix,
Namespace: otherNamespace.Name,
},
Spec: idpv1alpha1.GitHubIdentityProviderSpec{
GitHubAPI: idpv1alpha1.GitHubAPIConfig{
Host: ptr.To("github.com"),
},
AllowAuthentication: idpv1alpha1.GitHubAllowAuthenticationSpec{
Organizations: idpv1alpha1.GitHubOrganizationsSpec{
Policy: ptr.To(idpv1alpha1.GitHubAllowedAuthOrganizationsPolicyAllGitHubUsers),
},
},
Client: idpv1alpha1.GitHubClientSpec{
SecretName: "does-not-matter",
},
},
}
createdIDP, err := gitHubIDPClient.Create(ctx, idp, metav1.CreateOptions{})
require.NoError(t, err)
t.Cleanup(func() {
err := gitHubIDPClient.Delete(ctx, createdIDP.Name, metav1.DeleteOptions{})
require.NoError(t, err)
})
// We require that there's never an error
// ... and that the status phase is never anything but Pending
// ... and that there are no status conditions
require.Never(t, func() bool {
idp, err := gitHubIDPClient.Get(ctx, createdIDP.Name, metav1.GetOptions{})
return err != nil && idp.Status.Phase != idpv1alpha1.GitHubPhasePending && len(idp.Status.Conditions) > 0
}, 2*time.Minute, 10*time.Second)
}
func TestGitHubIDPSecretInOtherNamespace_Parallel(t *testing.T) {
// The GitHubIdentityProvider must be in the same namespace as the controller
supervisorNamespace := testlib.IntegrationEnv(t).SupervisorNamespace
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Minute)
t.Cleanup(cancel)
kubernetesClient := testlib.NewKubernetesClientset(t)
gitHubIDPClient := testlib.NewSupervisorClientset(t).IDPV1alpha1().GitHubIdentityProviders(supervisorNamespace)
namespaceClient := kubernetesClient.CoreV1().Namespaces()
otherNamespace, err := namespaceClient.Create(ctx, &corev1.Namespace{
ObjectMeta: metav1.ObjectMeta{
GenerateName: generateNamePrefix,
},
}, metav1.CreateOptions{})
require.NoError(t, err)
t.Cleanup(func() {
require.NoError(t, namespaceClient.Delete(ctx, otherNamespace.Name, metav1.DeleteOptions{}))
})
secretsClient := kubernetesClient.CoreV1().Secrets(otherNamespace.Name)
secret := &corev1.Secret{
ObjectMeta: metav1.ObjectMeta{
GenerateName: generateNamePrefix,
Namespace: otherNamespace.Name,
},
Type: "secrets.pinniped.dev/github-client",
Data: map[string][]byte{
"clientID": []byte("foo"),
"clientSecret": []byte("bar"),
},
}
// This secret will be cleaned up when its namespace is deleted
createdSecret, err := secretsClient.Create(ctx, secret, metav1.CreateOptions{})
require.NoError(t, err)
idp := &idpv1alpha1.GitHubIdentityProvider{
ObjectMeta: metav1.ObjectMeta{
GenerateName: generateNamePrefix,
Namespace: supervisorNamespace,
},
Spec: idpv1alpha1.GitHubIdentityProviderSpec{
GitHubAPI: idpv1alpha1.GitHubAPIConfig{
Host: ptr.To("github.com"),
},
AllowAuthentication: idpv1alpha1.GitHubAllowAuthenticationSpec{
Organizations: idpv1alpha1.GitHubOrganizationsSpec{
Policy: ptr.To(idpv1alpha1.GitHubAllowedAuthOrganizationsPolicyAllGitHubUsers),
},
},
Client: idpv1alpha1.GitHubClientSpec{
SecretName: createdSecret.Name,
},
},
}
created, err := gitHubIDPClient.Create(ctx, idp, metav1.CreateOptions{})
require.NoError(t, err)
t.Cleanup(func() {
err := gitHubIDPClient.Delete(ctx, created.Name, metav1.DeleteOptions{})
require.NoError(t, err)
})
testlib.WaitForGitHubIDPPhase(ctx, t, gitHubIDPClient, created.Name, idpv1alpha1.GitHubPhaseError)
testlib.WaitForGitHubIdentityProviderStatusConditions(ctx, t, gitHubIDPClient, created.Name, []*metav1.Condition{
{
Type: "ClientCredentialsObtained",
Status: metav1.ConditionFalse,
Reason: "SecretNotFound",
Message: fmt.Sprintf(`secret %q not found: secret from spec.client.SecretName (%q) must be found in namespace %q with type "secrets.pinniped.dev/github-client" and keys "clientID" and "clientSecret"`,
idp.Spec.Client.SecretName,
idp.Spec.Client.SecretName,
supervisorNamespace),
},
{
Type: "GitHubConnectionValid",
Status: metav1.ConditionTrue,
Reason: "Success",
Message: `spec.githubAPI.host ("github.com:443") is reachable and TLS verification succeeds`,
},
{
Type: "HostValid",
Status: metav1.ConditionTrue,
Reason: "Success",
Message: `spec.githubAPI.host ("github.com") is valid`,
},
{
Type: "OrganizationsPolicyValid",
Status: metav1.ConditionTrue,
Reason: "Success",
Message: `spec.allowAuthentication.organizations.policy ("AllGitHubUsers") is valid`,
},
{
Type: "TLSConfigurationValid",
Status: metav1.ConditionTrue,
Reason: "Success",
Message: "spec.githubAPI.tls.certificateAuthorityData is valid",
},
})
}
func TestGitHubIDPTooManyOrganizationsStaticValidationOnCreate_Parallel(t *testing.T) {
adminClient := testlib.NewKubernetesClientset(t)
@@ -262,7 +612,7 @@ func TestGitHubIDPTooManyOrganizationsStaticValidationOnCreate_Parallel(t *testi
ns, err := namespaceClient.Create(ctx, &corev1.Namespace{
ObjectMeta: metav1.ObjectMeta{
GenerateName: "test-github-idp-",
GenerateName: generateNamePrefix,
},
}, metav1.CreateOptions{})
require.NoError(t, err)
@@ -275,7 +625,7 @@ func TestGitHubIDPTooManyOrganizationsStaticValidationOnCreate_Parallel(t *testi
input := &idpv1alpha1.GitHubIdentityProvider{
ObjectMeta: metav1.ObjectMeta{
GenerateName: "integration-test-",
GenerateName: generateNamePrefix,
},
Spec: idpv1alpha1.GitHubIdentityProviderSpec{
AllowAuthentication: idpv1alpha1.GitHubAllowAuthenticationSpec{
@@ -298,10 +648,10 @@ func TestGitHubIDPTooManyOrganizationsStaticValidationOnCreate_Parallel(t *testi
_, err = gitHubIDPClient.Create(ctx, input, metav1.CreateOptions{})
expectedErr := "spec.allowAuthentication.organizations.allowed: Invalid value: 100: spec.allowAuthentication.organizations.allowed in body should have at most 64 items"
wantErr := "spec.allowAuthentication.organizations.allowed: Invalid value: 100: spec.allowAuthentication.organizations.allowed in body should have at most 64 items"
if testutil.KubeServerMinorVersionAtLeastInclusive(t, adminClient.Discovery(), 24) {
expectedErr = "spec.allowAuthentication.organizations.allowed: Too many: 100: must have at most 64 items"
wantErr = "spec.allowAuthentication.organizations.allowed: Too many: 100: must have at most 64 items"
}
require.ErrorContains(t, err, expectedErr)
require.ErrorContains(t, err, wantErr)
}
+54
View File
@@ -34,6 +34,7 @@ import (
idpv1alpha1 "go.pinniped.dev/generated/latest/apis/supervisor/idp/v1alpha1"
conciergeclientset "go.pinniped.dev/generated/latest/client/concierge/clientset/versioned"
supervisorclientset "go.pinniped.dev/generated/latest/client/supervisor/clientset/versioned"
alpha1 "go.pinniped.dev/generated/latest/client/supervisor/clientset/versioned/typed/idp/v1alpha1"
"go.pinniped.dev/internal/groupsuffix"
"go.pinniped.dev/internal/kubeclient"
@@ -836,6 +837,59 @@ func WaitForUserToHaveAccess(t *testing.T, user string, groups []string, shouldH
}, time.Minute, 500*time.Millisecond)
}
func WaitForGitHubIDPPhase(
ctx context.Context,
t *testing.T,
client alpha1.GitHubIdentityProviderInterface,
gitHubIDPName string,
expectPhase idpv1alpha1.GitHubIdentityProviderPhase,
) {
t.Helper()
RequireEventuallyf(t, func(requireEventually *require.Assertions) {
idp, err := client.Get(ctx, gitHubIDPName, metav1.GetOptions{})
requireEventually.NoError(err)
requireEventually.Equalf(expectPhase, idp.Status.Phase, "actual status conditions were: %#v", idp.Status.Conditions)
}, 60*time.Second, 1*time.Second, "expected the GitHubIDP to have status %q", expectPhase)
}
func WaitForGitHubIdentityProviderStatusConditions(
ctx context.Context,
t *testing.T,
client alpha1.GitHubIdentityProviderInterface,
gitHubIDPName string,
expectConditions []*metav1.Condition,
) {
t.Helper()
RequireEventuallyf(t, func(requireEventually *require.Assertions) {
idp, err := client.Get(ctx, gitHubIDPName, 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 GitHubIdentityProvider %q", gitHubIDPName)
}
func testObjectMeta(t *testing.T, baseName string) metav1.ObjectMeta {
return metav1.ObjectMeta{
GenerateName: fmt.Sprintf("test-%s-", baseName),