2023-06-05 21:40:39 +00:00
// Copyright 2020-2023 the Pinniped contributors. All Rights Reserved.
2020-10-09 00:40:58 +00:00
// SPDX-License-Identifier: Apache-2.0
package supervisorconfig
import (
"context"
2020-10-09 14:39:17 +00:00
"errors"
2021-02-05 17:56:05 +00:00
"fmt"
2020-10-23 23:25:44 +00:00
"net/url"
2023-07-07 21:10:07 +00:00
"sort"
2020-10-09 00:40:58 +00:00
"testing"
"time"
"github.com/stretchr/testify/require"
2023-07-05 20:33:21 +00:00
corev1 "k8s.io/api/core/v1"
2020-10-09 00:40:58 +00:00
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
2020-10-09 14:39:17 +00:00
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/apimachinery/pkg/runtime/schema"
2023-07-17 23:41:28 +00:00
"k8s.io/apimachinery/pkg/types"
2020-10-09 14:39:17 +00:00
coretesting "k8s.io/client-go/testing"
2021-12-10 22:22:36 +00:00
clocktesting "k8s.io/utils/clock/testing"
2023-07-10 21:09:19 +00:00
"k8s.io/utils/pointer"
2020-10-09 00:40:58 +00:00
2023-07-05 20:33:21 +00:00
configv1alpha1 "go.pinniped.dev/generated/latest/apis/supervisor/config/v1alpha1"
idpv1alpha1 "go.pinniped.dev/generated/latest/apis/supervisor/idp/v1alpha1"
2021-02-16 19:00:08 +00:00
pinnipedfake "go.pinniped.dev/generated/latest/client/supervisor/clientset/versioned/fake"
pinnipedinformers "go.pinniped.dev/generated/latest/client/supervisor/informers/externalversions"
2023-07-17 23:41:28 +00:00
"go.pinniped.dev/internal/celtransformer"
2020-10-09 00:40:58 +00:00
"go.pinniped.dev/internal/controllerlib"
2023-06-22 22:12:33 +00:00
"go.pinniped.dev/internal/federationdomain/federationdomainproviders"
2023-07-14 19:06:20 +00:00
"go.pinniped.dev/internal/here"
2023-07-07 21:10:07 +00:00
"go.pinniped.dev/internal/idtransform"
2020-10-09 00:40:58 +00:00
"go.pinniped.dev/internal/testutil"
)
2023-07-05 20:33:21 +00:00
func TestFederationDomainWatcherControllerInformerFilters ( t * testing . T ) {
t . Parallel ( )
federationDomainInformer := pinnipedinformers . NewSharedInformerFactoryWithOptions ( nil , 0 ) . Config ( ) . V1alpha1 ( ) . FederationDomains ( )
oidcIdentityProviderInformer := pinnipedinformers . NewSharedInformerFactoryWithOptions ( nil , 0 ) . IDP ( ) . V1alpha1 ( ) . OIDCIdentityProviders ( )
ldapIdentityProviderInformer := pinnipedinformers . NewSharedInformerFactoryWithOptions ( nil , 0 ) . IDP ( ) . V1alpha1 ( ) . LDAPIdentityProviders ( )
adIdentityProviderInformer := pinnipedinformers . NewSharedInformerFactoryWithOptions ( nil , 0 ) . IDP ( ) . V1alpha1 ( ) . ActiveDirectoryIdentityProviders ( )
tests := [ ] struct {
name string
obj metav1 . Object
informer controllerlib . InformerGetter
wantAdd bool
wantUpdate bool
wantDelete bool
} {
{
name : "any FederationDomain changes" ,
obj : & configv1alpha1 . FederationDomain { } ,
informer : federationDomainInformer ,
wantAdd : true ,
wantUpdate : true ,
wantDelete : true ,
} ,
{
name : "any OIDCIdentityProvider adds or deletes, but updates are ignored" ,
obj : & idpv1alpha1 . OIDCIdentityProvider { } ,
informer : oidcIdentityProviderInformer ,
wantAdd : true ,
wantUpdate : false ,
wantDelete : true ,
} ,
{
name : "any LDAPIdentityProvider adds or deletes, but updates are ignored" ,
obj : & idpv1alpha1 . LDAPIdentityProvider { } ,
informer : ldapIdentityProviderInformer ,
wantAdd : true ,
wantUpdate : false ,
wantDelete : true ,
} ,
{
name : "any ActiveDirectoryIdentityProvider adds or deletes, but updates are ignored" ,
obj : & idpv1alpha1 . ActiveDirectoryIdentityProvider { } ,
informer : adIdentityProviderInformer ,
wantAdd : true ,
wantUpdate : false ,
wantDelete : true ,
} ,
}
for _ , test := range tests {
test := test
t . Run ( test . name , func ( t * testing . T ) {
t . Parallel ( )
withInformer := testutil . NewObservableWithInformerOption ( )
NewFederationDomainWatcherController (
2020-10-09 00:40:58 +00:00
nil ,
2023-07-12 17:34:15 +00:00
"" ,
2020-10-09 00:40:58 +00:00
nil ,
nil ,
2020-12-17 19:34:49 +00:00
federationDomainInformer ,
2023-06-05 21:40:39 +00:00
oidcIdentityProviderInformer ,
ldapIdentityProviderInformer ,
adIdentityProviderInformer ,
2023-07-05 20:33:21 +00:00
withInformer . WithInformer , // make it possible to observe the behavior of the Filters
2020-10-09 00:40:58 +00:00
)
2023-07-05 20:33:21 +00:00
unrelatedObj := corev1 . Secret { }
filter := withInformer . GetFilterForInformer ( test . informer )
require . Equal ( t , test . wantAdd , filter . Add ( test . obj ) )
require . Equal ( t , test . wantUpdate , filter . Update ( & unrelatedObj , test . obj ) )
require . Equal ( t , test . wantUpdate , filter . Update ( test . obj , & unrelatedObj ) )
require . Equal ( t , test . wantDelete , filter . Delete ( test . obj ) )
2020-10-09 00:40:58 +00:00
} )
2023-07-05 20:33:21 +00:00
}
2020-10-09 00:40:58 +00:00
}
2023-06-13 21:20:39 +00:00
type fakeFederationDomainsSetter struct {
SetFederationDomainsWasCalled bool
2023-06-22 20:12:50 +00:00
FederationDomainsReceived [ ] * federationdomainproviders . FederationDomainIssuer
2020-10-09 00:40:58 +00:00
}
2023-06-22 20:12:50 +00:00
func ( f * fakeFederationDomainsSetter ) SetFederationDomains ( federationDomains ... * federationdomainproviders . FederationDomainIssuer ) {
2023-06-13 21:20:39 +00:00
f . SetFederationDomainsWasCalled = true
2020-12-16 22:27:09 +00:00
f . FederationDomainsReceived = federationDomains
2020-10-09 00:40:58 +00:00
}
2023-07-10 22:41:48 +00:00
var federationDomainGVR = schema . GroupVersionResource {
Group : configv1alpha1 . SchemeGroupVersion . Group ,
Version : configv1alpha1 . SchemeGroupVersion . Version ,
Resource : "federationdomains" ,
}
2023-07-05 20:33:21 +00:00
func TestTestFederationDomainWatcherControllerSync ( t * testing . T ) {
2023-07-06 00:41:27 +00:00
t . Parallel ( )
2020-10-09 00:40:58 +00:00
2023-07-06 00:41:27 +00:00
const namespace = "some-namespace"
2023-07-12 17:34:15 +00:00
const apiGroupSuffix = "custom.suffix.pinniped.dev"
const apiGroupSupervisor = "idp.supervisor." + apiGroupSuffix
2020-10-09 00:40:58 +00:00
2023-07-06 00:41:27 +00:00
frozenNow := time . Date ( 2020 , time . September , 23 , 7 , 42 , 0 , 0 , time . Local )
frozenMetav1Now := metav1 . NewTime ( frozenNow )
2020-10-09 00:40:58 +00:00
2023-07-11 16:42:20 +00:00
oidcIdentityProvider := & idpv1alpha1 . OIDCIdentityProvider {
2023-07-07 21:10:07 +00:00
ObjectMeta : metav1 . ObjectMeta {
2023-07-11 16:42:20 +00:00
Name : "some-oidc-idp" ,
2023-07-10 22:41:48 +00:00
Namespace : namespace ,
2023-07-11 16:42:20 +00:00
UID : "some-oidc-uid" ,
2023-07-10 21:09:19 +00:00
} ,
}
2023-07-11 16:42:20 +00:00
ldapIdentityProvider := & idpv1alpha1 . LDAPIdentityProvider {
ObjectMeta : metav1 . ObjectMeta {
Name : "some-ldap-idp" ,
Namespace : namespace ,
UID : "some-ldap-uid" ,
} ,
}
adIdentityProvider := & idpv1alpha1 . ActiveDirectoryIdentityProvider {
2023-07-10 21:09:19 +00:00
ObjectMeta : metav1 . ObjectMeta {
2023-07-11 16:42:20 +00:00
Name : "some-ad-idp" ,
2023-07-10 22:41:48 +00:00
Namespace : namespace ,
2023-07-11 16:42:20 +00:00
UID : "some-ad-uid" ,
2023-07-07 21:10:07 +00:00
} ,
}
2023-07-06 00:41:27 +00:00
federationDomain1 := & configv1alpha1 . FederationDomain {
ObjectMeta : metav1 . ObjectMeta { Name : "config1" , Namespace : namespace , Generation : 123 } ,
Spec : configv1alpha1 . FederationDomainSpec { Issuer : "https://issuer1.com" } ,
}
2020-10-09 00:40:58 +00:00
2023-07-06 00:41:27 +00:00
federationDomain2 := & configv1alpha1 . FederationDomain {
ObjectMeta : metav1 . ObjectMeta { Name : "config2" , Namespace : namespace , Generation : 123 } ,
Spec : configv1alpha1 . FederationDomainSpec { Issuer : "https://issuer2.com" } ,
}
2020-10-09 14:39:17 +00:00
2023-07-10 22:41:48 +00:00
invalidIssuerURLFederationDomain := & configv1alpha1 . FederationDomain {
2023-07-06 00:41:27 +00:00
ObjectMeta : metav1 . ObjectMeta { Name : "invalid-config" , Namespace : namespace , Generation : 123 } ,
Spec : configv1alpha1 . FederationDomainSpec { Issuer : "https://invalid-issuer.com?some=query" } ,
}
2023-06-30 20:43:40 +00:00
2023-07-10 22:41:48 +00:00
federationDomainIssuerWithIDPs := func ( t * testing . T , fedDomainIssuer string , fdIDPs [ ] * federationdomainproviders . FederationDomainIdentityProvider ) * federationdomainproviders . FederationDomainIssuer {
fdIssuer , err := federationdomainproviders . NewFederationDomainIssuer ( fedDomainIssuer , fdIDPs )
require . NoError ( t , err )
return fdIssuer
}
2023-07-07 21:10:07 +00:00
federationDomainIssuerWithDefaultIDP := func ( t * testing . T , fedDomainIssuer string , idpObjectMeta metav1 . ObjectMeta ) * federationdomainproviders . FederationDomainIssuer {
fdIDP := & federationdomainproviders . FederationDomainIdentityProvider {
DisplayName : idpObjectMeta . Name ,
UID : idpObjectMeta . UID ,
Transforms : idtransform . NewTransformationPipeline ( ) ,
}
fdIssuer , err := federationdomainproviders . NewFederationDomainIssuerWithDefaultIDP ( fedDomainIssuer , fdIDP )
require . NoError ( t , err )
return fdIssuer
}
2023-07-06 00:41:27 +00:00
happyReadyCondition := func ( issuer string , time metav1 . Time , observedGeneration int64 ) configv1alpha1 . Condition {
return configv1alpha1 . Condition {
Type : "Ready" ,
Status : "True" ,
ObservedGeneration : observedGeneration ,
LastTransitionTime : time ,
Reason : "Success" ,
Message : fmt . Sprintf ( "the FederationDomain is ready and its endpoints are available: " +
"the discovery endpoint is %s/.well-known/openid-configuration" , issuer ) ,
}
}
2023-06-30 20:43:40 +00:00
2023-07-06 00:41:27 +00:00
sadReadyCondition := func ( time metav1 . Time , observedGeneration int64 ) configv1alpha1 . Condition {
return configv1alpha1 . Condition {
Type : "Ready" ,
Status : "False" ,
ObservedGeneration : observedGeneration ,
LastTransitionTime : time ,
Reason : "NotReady" ,
Message : "the FederationDomain is not ready: see other conditions for details" ,
}
}
2023-06-30 20:43:40 +00:00
2023-07-06 00:41:27 +00:00
happyIssuerIsUniqueCondition := func ( time metav1 . Time , observedGeneration int64 ) configv1alpha1 . Condition {
return configv1alpha1 . Condition {
Type : "IssuerIsUnique" ,
Status : "True" ,
ObservedGeneration : observedGeneration ,
LastTransitionTime : time ,
Reason : "Success" ,
Message : "spec.issuer is unique among all FederationDomains" ,
}
}
2023-06-30 20:43:40 +00:00
2023-07-06 00:41:27 +00:00
unknownIssuerIsUniqueCondition := func ( time metav1 . Time , observedGeneration int64 ) configv1alpha1 . Condition {
return configv1alpha1 . Condition {
Type : "IssuerIsUnique" ,
Status : "Unknown" ,
ObservedGeneration : observedGeneration ,
LastTransitionTime : time ,
Reason : "UnableToValidate" ,
Message : "unable to check if spec.issuer is unique among all FederationDomains because URL cannot be parsed" ,
}
}
2023-06-30 20:43:40 +00:00
2023-07-06 00:41:27 +00:00
sadIssuerIsUniqueCondition := func ( time metav1 . Time , observedGeneration int64 ) configv1alpha1 . Condition {
return configv1alpha1 . Condition {
Type : "IssuerIsUnique" ,
Status : "False" ,
ObservedGeneration : observedGeneration ,
LastTransitionTime : time ,
Reason : "DuplicateIssuer" ,
Message : "multiple FederationDomains have the same spec.issuer URL: these URLs must be unique (can use different hosts or paths)" ,
}
}
2023-06-30 20:43:40 +00:00
2023-07-06 00:41:27 +00:00
happyOneTLSSecretPerIssuerHostnameCondition := func ( time metav1 . Time , observedGeneration int64 ) configv1alpha1 . Condition {
return configv1alpha1 . Condition {
Type : "OneTLSSecretPerIssuerHostname" ,
Status : "True" ,
ObservedGeneration : observedGeneration ,
LastTransitionTime : time ,
Reason : "Success" ,
Message : "all FederationDomains are using the same TLS secret when using the same hostname in the spec.issuer URL" ,
}
}
2023-06-30 20:43:40 +00:00
2023-07-06 00:41:27 +00:00
unknownOneTLSSecretPerIssuerHostnameCondition := func ( time metav1 . Time , observedGeneration int64 ) configv1alpha1 . Condition {
return configv1alpha1 . Condition {
Type : "OneTLSSecretPerIssuerHostname" ,
Status : "Unknown" ,
ObservedGeneration : observedGeneration ,
LastTransitionTime : time ,
Reason : "UnableToValidate" ,
Message : "unable to check if all FederationDomains are using the same TLS secret when using the same hostname in the spec.issuer URL because URL cannot be parsed" ,
}
}
2023-06-30 20:43:40 +00:00
2023-07-06 00:41:27 +00:00
sadOneTLSSecretPerIssuerHostnameCondition := func ( time metav1 . Time , observedGeneration int64 ) configv1alpha1 . Condition {
return configv1alpha1 . Condition {
Type : "OneTLSSecretPerIssuerHostname" ,
Status : "False" ,
ObservedGeneration : observedGeneration ,
LastTransitionTime : time ,
Reason : "DifferentSecretRefsFound" ,
Message : "when different FederationDomains are using the same hostname in the spec.issuer URL then they must also use the same TLS secretRef: different secretRefs found" ,
}
}
2023-06-30 20:43:40 +00:00
2023-07-06 00:41:27 +00:00
happyIssuerURLValidCondition := func ( time metav1 . Time , observedGeneration int64 ) configv1alpha1 . Condition {
return configv1alpha1 . Condition {
Type : "IssuerURLValid" ,
Status : "True" ,
ObservedGeneration : observedGeneration ,
LastTransitionTime : time ,
Reason : "Success" ,
Message : "spec.issuer is a valid URL" ,
}
}
2023-06-30 20:43:40 +00:00
2023-07-06 00:41:27 +00:00
sadIssuerURLValidConditionCannotHaveQuery := func ( time metav1 . Time , observedGeneration int64 ) configv1alpha1 . Condition {
return configv1alpha1 . Condition {
Type : "IssuerURLValid" ,
Status : "False" ,
ObservedGeneration : observedGeneration ,
LastTransitionTime : time ,
Reason : "InvalidIssuerURL" ,
Message : "issuer must not have query" ,
}
}
2023-06-30 20:43:40 +00:00
2023-07-06 00:41:27 +00:00
sadIssuerURLValidConditionCannotParse := func ( time metav1 . Time , observedGeneration int64 ) configv1alpha1 . Condition {
return configv1alpha1 . Condition {
Type : "IssuerURLValid" ,
Status : "False" ,
ObservedGeneration : observedGeneration ,
LastTransitionTime : time ,
Reason : "InvalidIssuerURL" ,
Message : ` could not parse issuer as URL: parse ":/host//path": missing protocol scheme ` ,
}
}
2020-10-09 00:40:58 +00:00
2023-07-07 21:10:07 +00:00
happyIdentityProvidersFoundConditionLegacyConfigurationSuccess := func ( idpName string , time metav1 . Time , observedGeneration int64 ) configv1alpha1 . Condition {
return configv1alpha1 . Condition {
Type : "IdentityProvidersFound" ,
Status : "True" ,
ObservedGeneration : observedGeneration ,
LastTransitionTime : time ,
Reason : "LegacyConfigurationSuccess" ,
Message : fmt . Sprintf ( "no resources were specified by .spec.identityProviders[].objectRef but exactly one " +
"identity provider resource has been found: using %q as " +
"identity provider: please explicitly list identity providers in .spec.identityProviders " +
"(this legacy configuration mode may be removed in a future version of Pinniped)" , idpName ) ,
}
}
2023-07-10 22:41:48 +00:00
happyIdentityProvidersFoundConditionSuccess := func ( time metav1 . Time , observedGeneration int64 ) configv1alpha1 . Condition {
return configv1alpha1 . Condition {
Type : "IdentityProvidersFound" ,
Status : "True" ,
ObservedGeneration : observedGeneration ,
LastTransitionTime : time ,
Reason : "Success" ,
Message : "the resources specified by .spec.identityProviders[].objectRef were found" ,
}
}
2023-07-10 21:09:19 +00:00
sadIdentityProvidersFoundConditionLegacyConfigurationIdentityProviderNotFound := func ( time metav1 . Time , observedGeneration int64 ) configv1alpha1 . Condition {
return configv1alpha1 . Condition {
Type : "IdentityProvidersFound" ,
Status : "False" ,
ObservedGeneration : observedGeneration ,
LastTransitionTime : time ,
Reason : "LegacyConfigurationIdentityProviderNotFound" ,
Message : "no resources were specified by .spec.identityProviders[].objectRef and no identity provider " +
"resources have been found: please create an identity provider resource" ,
}
}
sadIdentityProvidersFoundConditionIdentityProviderNotSpecified := func ( idpCRsCount int , time metav1 . Time , observedGeneration int64 ) configv1alpha1 . Condition {
return configv1alpha1 . Condition {
Type : "IdentityProvidersFound" ,
Status : "False" ,
ObservedGeneration : observedGeneration ,
LastTransitionTime : time ,
Reason : "IdentityProviderNotSpecified" ,
Message : fmt . Sprintf ( "no resources were specified by .spec.identityProviders[].objectRef " +
2023-07-20 22:49:01 +00:00
"and %d identity provider resources have been found: " +
2023-07-10 21:09:19 +00:00
"please update .spec.identityProviders to specify which identity providers " +
"this federation domain should use" , idpCRsCount ) ,
}
}
2023-07-12 20:15:52 +00:00
sadIdentityProvidersFoundConditionIdentityProvidersObjectRefsNotFound := func ( idpsNotFound string , time metav1 . Time , observedGeneration int64 ) configv1alpha1 . Condition {
2023-07-10 21:09:19 +00:00
return configv1alpha1 . Condition {
Type : "IdentityProvidersFound" ,
Status : "False" ,
ObservedGeneration : observedGeneration ,
LastTransitionTime : time ,
Reason : "IdentityProvidersObjectRefsNotFound" ,
2023-07-12 20:15:52 +00:00
Message : fmt . Sprintf ( ".spec.identityProviders[].objectRef identifies resource(s) that cannot be found: %s" , idpsNotFound ) ,
2023-07-10 21:09:19 +00:00
}
}
2023-07-07 21:10:07 +00:00
2023-07-12 16:43:33 +00:00
happyDisplayNamesUniqueCondition := func ( time metav1 . Time , observedGeneration int64 ) configv1alpha1 . Condition {
return configv1alpha1 . Condition {
2023-07-12 20:15:52 +00:00
Type : "IdentityProvidersDisplayNamesUnique" ,
2023-07-12 16:43:33 +00:00
Status : "True" ,
ObservedGeneration : observedGeneration ,
LastTransitionTime : time ,
Reason : "Success" ,
Message : "the names specified by .spec.identityProviders[].displayName are unique" ,
}
}
sadDisplayNamesUniqueCondition := func ( duplicateNames string , time metav1 . Time , observedGeneration int64 ) configv1alpha1 . Condition {
return configv1alpha1 . Condition {
2023-07-12 20:15:52 +00:00
Type : "IdentityProvidersDisplayNamesUnique" ,
2023-07-12 16:43:33 +00:00
Status : "False" ,
ObservedGeneration : observedGeneration ,
LastTransitionTime : time ,
Reason : "DuplicateDisplayNames" ,
Message : fmt . Sprintf ( "the names specified by .spec.identityProviders[].displayName contain duplicates: %s" , duplicateNames ) ,
}
}
2023-07-13 22:26:32 +00:00
happyConstNamesUniqueCondition := func ( time metav1 . Time , observedGeneration int64 ) configv1alpha1 . Condition {
return configv1alpha1 . Condition {
Type : "TransformsConstantsNamesUnique" ,
Status : "True" ,
ObservedGeneration : observedGeneration ,
LastTransitionTime : time ,
Reason : "Success" ,
Message : "the names specified by .spec.identityProviders[].transforms.constants[].name are unique" ,
}
}
2023-07-18 22:00:58 +00:00
sadConstNamesUniqueCondition := func ( errorMessages string , time metav1 . Time , observedGeneration int64 ) configv1alpha1 . Condition {
2023-07-13 22:26:32 +00:00
return configv1alpha1 . Condition {
Type : "TransformsConstantsNamesUnique" ,
Status : "False" ,
ObservedGeneration : observedGeneration ,
LastTransitionTime : time ,
Reason : "DuplicateConstantsNames" ,
2023-07-18 22:00:58 +00:00
Message : errorMessages ,
2023-07-13 22:26:32 +00:00
}
}
2023-07-14 19:06:20 +00:00
happyTransformationExpressionsCondition := func ( time metav1 . Time , observedGeneration int64 ) configv1alpha1 . Condition {
return configv1alpha1 . Condition {
Type : "TransformsExpressionsValid" ,
Status : "True" ,
ObservedGeneration : observedGeneration ,
LastTransitionTime : time ,
Reason : "Success" ,
Message : "the expressions specified by .spec.identityProviders[].transforms.expressions[] are valid" ,
}
}
sadTransformationExpressionsCondition := func ( errorMessages string , time metav1 . Time , observedGeneration int64 ) configv1alpha1 . Condition {
return configv1alpha1 . Condition {
Type : "TransformsExpressionsValid" ,
Status : "False" ,
ObservedGeneration : observedGeneration ,
LastTransitionTime : time ,
Reason : "InvalidTransformsExpressions" ,
2023-07-18 22:00:58 +00:00
Message : errorMessages ,
2023-07-14 19:06:20 +00:00
}
}
2023-07-14 23:50:43 +00:00
happyTransformationExamplesCondition := func ( time metav1 . Time , observedGeneration int64 ) configv1alpha1 . Condition {
return configv1alpha1 . Condition {
Type : "TransformsExamplesPassed" ,
Status : "True" ,
ObservedGeneration : observedGeneration ,
LastTransitionTime : time ,
Reason : "Success" ,
Message : "the examples specified by .spec.identityProviders[].transforms.examples[] had no errors" ,
}
}
sadTransformationExamplesCondition := func ( errorMessages string , time metav1 . Time , observedGeneration int64 ) configv1alpha1 . Condition {
return configv1alpha1 . Condition {
Type : "TransformsExamplesPassed" ,
Status : "False" ,
ObservedGeneration : observedGeneration ,
LastTransitionTime : time ,
Reason : "TransformsExamplesFailed" ,
2023-07-18 22:00:58 +00:00
Message : errorMessages ,
2023-07-14 23:50:43 +00:00
}
}
2023-07-12 17:34:15 +00:00
happyAPIGroupSuffixCondition := func ( time metav1 . Time , observedGeneration int64 ) configv1alpha1 . Condition {
return configv1alpha1 . Condition {
2023-07-12 20:15:52 +00:00
Type : "IdentityProvidersObjectRefAPIGroupSuffixValid" ,
2023-07-12 17:34:15 +00:00
Status : "True" ,
ObservedGeneration : observedGeneration ,
LastTransitionTime : time ,
Reason : "Success" ,
Message : "the API groups specified by .spec.identityProviders[].objectRef.apiGroup are recognized" ,
}
}
2023-07-12 20:15:52 +00:00
sadAPIGroupSuffixCondition := func ( badApiGroups string , time metav1 . Time , observedGeneration int64 ) configv1alpha1 . Condition {
2023-07-12 17:34:15 +00:00
return configv1alpha1 . Condition {
2023-07-12 20:15:52 +00:00
Type : "IdentityProvidersObjectRefAPIGroupSuffixValid" ,
2023-07-12 17:34:15 +00:00
Status : "False" ,
ObservedGeneration : observedGeneration ,
LastTransitionTime : time ,
2023-07-12 20:15:52 +00:00
Reason : "APIGroupUnrecognized" ,
Message : fmt . Sprintf ( "the API groups specified by .spec.identityProviders[].objectRef.apiGroup " +
"are not recognized (should be \"idp.supervisor.%s\"): %s" , apiGroupSuffix , badApiGroups ) ,
2023-07-12 17:34:15 +00:00
}
}
2023-07-12 20:15:52 +00:00
happyKindCondition := func ( time metav1 . Time , observedGeneration int64 ) configv1alpha1 . Condition {
return configv1alpha1 . Condition {
Type : "IdentityProvidersObjectRefKindValid" ,
Status : "True" ,
ObservedGeneration : observedGeneration ,
LastTransitionTime : time ,
Reason : "Success" ,
Message : "the kinds specified by .spec.identityProviders[].objectRef.kind are recognized" ,
}
}
sadKindCondition := func ( badKinds string , time metav1 . Time , observedGeneration int64 ) configv1alpha1 . Condition {
return configv1alpha1 . Condition {
Type : "IdentityProvidersObjectRefKindValid" ,
Status : "False" ,
ObservedGeneration : observedGeneration ,
LastTransitionTime : time ,
Reason : "KindUnrecognized" ,
Message : fmt . Sprintf ( ` the kinds specified by .spec.identityProviders[].objectRef.kind are ` +
` not recognized (should be one of "ActiveDirectoryIdentityProvider", "LDAPIdentityProvider", "OIDCIdentityProvider"): %s ` , badKinds ) ,
}
}
sortConditionsByType := func ( c [ ] configv1alpha1 . Condition ) [ ] configv1alpha1 . Condition {
cp := make ( [ ] configv1alpha1 . Condition , len ( c ) )
copy ( cp , c )
sort . SliceStable ( cp , func ( i , j int ) bool {
return cp [ i ] . Type < cp [ j ] . Type
} )
return cp
}
2023-07-14 19:06:20 +00:00
replaceConditions := func ( conditions [ ] configv1alpha1 . Condition , sadConditions [ ] configv1alpha1 . Condition ) [ ] configv1alpha1 . Condition {
for _ , sadReplaceCondition := range sadConditions {
for origIndex , origCondition := range conditions {
if origCondition . Type == sadReplaceCondition . Type {
conditions [ origIndex ] = sadReplaceCondition
break
}
}
}
return conditions
2023-07-06 00:41:27 +00:00
}
2020-10-09 00:40:58 +00:00
2023-07-10 22:41:48 +00:00
allHappyConditionsSuccess := func ( issuer string , time metav1 . Time , observedGeneration int64 ) [ ] configv1alpha1 . Condition {
2023-07-12 20:15:52 +00:00
return sortConditionsByType ( [ ] configv1alpha1 . Condition {
2023-07-14 23:50:43 +00:00
happyTransformationExamplesCondition ( frozenMetav1Now , 123 ) ,
2023-07-14 19:06:20 +00:00
happyTransformationExpressionsCondition ( frozenMetav1Now , 123 ) ,
2023-07-13 22:26:32 +00:00
happyConstNamesUniqueCondition ( frozenMetav1Now , 123 ) ,
2023-07-12 20:15:52 +00:00
happyKindCondition ( frozenMetav1Now , 123 ) ,
2023-07-12 17:34:15 +00:00
happyAPIGroupSuffixCondition ( frozenMetav1Now , 123 ) ,
2023-07-12 16:43:33 +00:00
happyDisplayNamesUniqueCondition ( frozenMetav1Now , 123 ) ,
2023-07-10 22:41:48 +00:00
happyIdentityProvidersFoundConditionSuccess ( frozenMetav1Now , 123 ) ,
happyIssuerIsUniqueCondition ( frozenMetav1Now , 123 ) ,
happyIssuerURLValidCondition ( frozenMetav1Now , 123 ) ,
happyOneTLSSecretPerIssuerHostnameCondition ( frozenMetav1Now , 123 ) ,
happyReadyCondition ( issuer , frozenMetav1Now , 123 ) ,
2023-07-12 20:15:52 +00:00
} )
2023-07-10 22:41:48 +00:00
}
2023-07-14 19:06:20 +00:00
allHappyConditionsLegacyConfigurationSuccess := func ( issuer string , idpName string , time metav1 . Time , observedGeneration int64 ) [ ] configv1alpha1 . Condition {
return replaceConditions (
allHappyConditionsSuccess ( issuer , time , observedGeneration ) ,
[ ] configv1alpha1 . Condition {
happyIdentityProvidersFoundConditionLegacyConfigurationSuccess ( idpName , time , observedGeneration ) ,
} ,
)
2023-07-14 17:27:25 +00:00
}
2023-07-06 00:41:27 +00:00
invalidIssuerURL := ":/host//path"
2023-07-07 21:10:07 +00:00
_ , err := url . Parse ( invalidIssuerURL ) //nolint:staticcheck // Yes, this URL is intentionally invalid.
2023-07-06 00:41:27 +00:00
require . Error ( t , err )
tests := [ ] struct {
2023-07-11 16:42:20 +00:00
name string
inputObjects [ ] runtime . Object
configClient func ( * pinnipedfake . Clientset )
wantErr string
wantStatusUpdates [ ] * configv1alpha1 . FederationDomain
wantFDIssuers [ ] * federationdomainproviders . FederationDomainIssuer
2023-07-06 00:41:27 +00:00
} {
{
2023-07-11 16:42:20 +00:00
name : "when there are no FederationDomains, no update actions happen and the list of FederationDomainIssuers is set to the empty list" ,
inputObjects : [ ] runtime . Object { } ,
wantFDIssuers : [ ] * federationdomainproviders . FederationDomainIssuer { } ,
2023-07-06 00:41:27 +00:00
} ,
{
2023-07-18 22:00:58 +00:00
name : "legacy config: when no identity provider is specified on federation domains, but exactly one OIDC identity " +
2023-07-07 21:10:07 +00:00
"provider resource exists on cluster, the controller will set a default IDP on each federation domain " +
"matching the only identity provider found" ,
2023-07-06 00:41:27 +00:00
inputObjects : [ ] runtime . Object {
federationDomain1 ,
federationDomain2 ,
2023-07-11 16:42:20 +00:00
oidcIdentityProvider ,
2023-07-06 00:41:27 +00:00
} ,
2023-07-11 16:42:20 +00:00
wantFDIssuers : [ ] * federationdomainproviders . FederationDomainIssuer {
federationDomainIssuerWithDefaultIDP ( t , federationDomain1 . Spec . Issuer , oidcIdentityProvider . ObjectMeta ) ,
federationDomainIssuerWithDefaultIDP ( t , federationDomain2 . Spec . Issuer , oidcIdentityProvider . ObjectMeta ) ,
2023-07-10 22:41:48 +00:00
} ,
wantStatusUpdates : [ ] * configv1alpha1 . FederationDomain {
expectedFederationDomainStatusUpdate ( federationDomain1 ,
configv1alpha1 . FederationDomainPhaseReady ,
2023-07-11 16:42:20 +00:00
allHappyConditionsLegacyConfigurationSuccess ( federationDomain1 . Spec . Issuer , oidcIdentityProvider . Name , frozenMetav1Now , 123 ) ,
2023-07-10 22:41:48 +00:00
) ,
expectedFederationDomainStatusUpdate ( federationDomain2 ,
configv1alpha1 . FederationDomainPhaseReady ,
2023-07-11 16:42:20 +00:00
allHappyConditionsLegacyConfigurationSuccess ( federationDomain2 . Spec . Issuer , oidcIdentityProvider . Name , frozenMetav1Now , 123 ) ,
2023-07-10 22:41:48 +00:00
) ,
2023-07-06 00:41:27 +00:00
} ,
} ,
2023-07-18 22:00:58 +00:00
{
name : "legacy config: when no identity provider is specified on federation domains, but exactly one LDAP identity " +
"provider resource exists on cluster, the controller will set a default IDP on each federation domain " +
"matching the only identity provider found" ,
inputObjects : [ ] runtime . Object {
federationDomain1 ,
federationDomain2 ,
ldapIdentityProvider ,
} ,
wantFDIssuers : [ ] * federationdomainproviders . FederationDomainIssuer {
federationDomainIssuerWithDefaultIDP ( t , federationDomain1 . Spec . Issuer , ldapIdentityProvider . ObjectMeta ) ,
federationDomainIssuerWithDefaultIDP ( t , federationDomain2 . Spec . Issuer , ldapIdentityProvider . ObjectMeta ) ,
} ,
wantStatusUpdates : [ ] * configv1alpha1 . FederationDomain {
expectedFederationDomainStatusUpdate ( federationDomain1 ,
configv1alpha1 . FederationDomainPhaseReady ,
allHappyConditionsLegacyConfigurationSuccess ( federationDomain1 . Spec . Issuer , ldapIdentityProvider . Name , frozenMetav1Now , 123 ) ,
) ,
expectedFederationDomainStatusUpdate ( federationDomain2 ,
configv1alpha1 . FederationDomainPhaseReady ,
allHappyConditionsLegacyConfigurationSuccess ( federationDomain2 . Spec . Issuer , ldapIdentityProvider . Name , frozenMetav1Now , 123 ) ,
) ,
} ,
} ,
{
name : "legacy config: when no identity provider is specified on federation domains, but exactly one AD identity " +
"provider resource exists on cluster, the controller will set a default IDP on each federation domain " +
"matching the only identity provider found" ,
inputObjects : [ ] runtime . Object {
federationDomain1 ,
federationDomain2 ,
adIdentityProvider ,
} ,
wantFDIssuers : [ ] * federationdomainproviders . FederationDomainIssuer {
federationDomainIssuerWithDefaultIDP ( t , federationDomain1 . Spec . Issuer , adIdentityProvider . ObjectMeta ) ,
federationDomainIssuerWithDefaultIDP ( t , federationDomain2 . Spec . Issuer , adIdentityProvider . ObjectMeta ) ,
} ,
wantStatusUpdates : [ ] * configv1alpha1 . FederationDomain {
expectedFederationDomainStatusUpdate ( federationDomain1 ,
configv1alpha1 . FederationDomainPhaseReady ,
allHappyConditionsLegacyConfigurationSuccess ( federationDomain1 . Spec . Issuer , adIdentityProvider . Name , frozenMetav1Now , 123 ) ,
) ,
expectedFederationDomainStatusUpdate ( federationDomain2 ,
configv1alpha1 . FederationDomainPhaseReady ,
allHappyConditionsLegacyConfigurationSuccess ( federationDomain2 . Spec . Issuer , adIdentityProvider . Name , frozenMetav1Now , 123 ) ,
) ,
} ,
} ,
2023-07-06 00:41:27 +00:00
{
2023-07-07 21:10:07 +00:00
name : "when there are two valid FederationDomains, but one is already up to date, the sync loop only updates " +
"the out-of-date FederationDomain" ,
2023-07-06 00:41:27 +00:00
inputObjects : [ ] runtime . Object {
2023-07-11 16:42:20 +00:00
oidcIdentityProvider ,
2023-07-10 22:41:48 +00:00
& configv1alpha1 . FederationDomain {
ObjectMeta : metav1 . ObjectMeta { Name : federationDomain1 . Name , Namespace : federationDomain1 . Namespace , Generation : 123 } ,
Spec : configv1alpha1 . FederationDomainSpec { Issuer : federationDomain1 . Spec . Issuer } ,
Status : configv1alpha1 . FederationDomainStatus {
Phase : configv1alpha1 . FederationDomainPhaseReady ,
2023-07-11 16:42:20 +00:00
Conditions : allHappyConditionsLegacyConfigurationSuccess ( federationDomain1 . Spec . Issuer , oidcIdentityProvider . Name , frozenMetav1Now , 123 ) ,
2023-07-10 22:41:48 +00:00
} ,
} ,
2023-07-06 00:41:27 +00:00
federationDomain2 ,
} ,
2023-07-11 16:42:20 +00:00
wantFDIssuers : [ ] * federationdomainproviders . FederationDomainIssuer {
federationDomainIssuerWithDefaultIDP ( t , federationDomain1 . Spec . Issuer , oidcIdentityProvider . ObjectMeta ) ,
federationDomainIssuerWithDefaultIDP ( t , federationDomain2 . Spec . Issuer , oidcIdentityProvider . ObjectMeta ) ,
2023-07-10 22:41:48 +00:00
} ,
wantStatusUpdates : [ ] * configv1alpha1 . FederationDomain {
// only one update, because the other FederationDomain already had the right status
expectedFederationDomainStatusUpdate ( federationDomain2 ,
configv1alpha1 . FederationDomainPhaseReady ,
2023-07-11 16:42:20 +00:00
allHappyConditionsLegacyConfigurationSuccess ( federationDomain2 . Spec . Issuer , oidcIdentityProvider . Name , frozenMetav1Now , 123 ) ,
2023-07-10 22:41:48 +00:00
) ,
2023-07-06 00:41:27 +00:00
} ,
} ,
2023-07-18 22:00:58 +00:00
{
name : "when the status of the FederationDomains is based on an old generation, it is updated" ,
inputObjects : [ ] runtime . Object {
oidcIdentityProvider ,
& configv1alpha1 . FederationDomain {
ObjectMeta : metav1 . ObjectMeta { Name : federationDomain1 . Name , Namespace : federationDomain1 . Namespace , Generation : 123 } ,
Spec : configv1alpha1 . FederationDomainSpec { Issuer : federationDomain1 . Spec . Issuer } ,
Status : configv1alpha1 . FederationDomainStatus {
Phase : configv1alpha1 . FederationDomainPhaseReady ,
Conditions : allHappyConditionsLegacyConfigurationSuccess (
federationDomain1 . Spec . Issuer ,
oidcIdentityProvider . Name ,
frozenMetav1Now ,
2 , // this is an older generation
) ,
} ,
} ,
} ,
wantFDIssuers : [ ] * federationdomainproviders . FederationDomainIssuer {
federationDomainIssuerWithDefaultIDP ( t , federationDomain1 . Spec . Issuer , oidcIdentityProvider . ObjectMeta ) ,
} ,
wantStatusUpdates : [ ] * configv1alpha1 . FederationDomain {
// only one update, because the other FederationDomain already had the right status
expectedFederationDomainStatusUpdate ( federationDomain1 ,
configv1alpha1 . FederationDomainPhaseReady ,
allHappyConditionsLegacyConfigurationSuccess (
federationDomain1 . Spec . Issuer ,
oidcIdentityProvider . Name ,
frozenMetav1Now ,
123 , // all conditions are updated to the new observed generation
) ,
) ,
} ,
} ,
2023-07-06 00:41:27 +00:00
{
2023-07-07 21:10:07 +00:00
name : "when there are two valid FederationDomains, but updating one fails, the status on the FederationDomain will not change" ,
2023-07-06 00:41:27 +00:00
inputObjects : [ ] runtime . Object {
federationDomain1 ,
federationDomain2 ,
2023-07-11 16:42:20 +00:00
oidcIdentityProvider ,
2023-07-06 00:41:27 +00:00
} ,
2023-07-11 16:42:20 +00:00
configClient : func ( client * pinnipedfake . Clientset ) {
2023-07-06 00:41:27 +00:00
client . PrependReactor (
"update" ,
"federationdomains" ,
func ( action coretesting . Action ) ( bool , runtime . Object , error ) {
fd := action . ( coretesting . UpdateAction ) . GetObject ( ) . ( * configv1alpha1 . FederationDomain )
if fd . Name == federationDomain1 . Name {
return true , nil , errors . New ( "some update error" )
}
return false , nil , nil
2020-10-09 14:39:17 +00:00
} ,
)
2023-07-06 00:41:27 +00:00
} ,
wantErr : "could not update status: some update error" ,
2023-07-11 16:42:20 +00:00
wantFDIssuers : [ ] * federationdomainproviders . FederationDomainIssuer {
2023-07-11 17:57:11 +00:00
federationDomainIssuerWithDefaultIDP ( t , federationDomain1 . Spec . Issuer , oidcIdentityProvider . ObjectMeta ) ,
2023-07-11 16:42:20 +00:00
federationDomainIssuerWithDefaultIDP ( t , federationDomain2 . Spec . Issuer , oidcIdentityProvider . ObjectMeta ) ,
2023-07-10 22:41:48 +00:00
} ,
wantStatusUpdates : [ ] * configv1alpha1 . FederationDomain {
expectedFederationDomainStatusUpdate ( federationDomain1 ,
configv1alpha1 . FederationDomainPhaseReady ,
2023-07-11 16:42:20 +00:00
allHappyConditionsLegacyConfigurationSuccess ( federationDomain1 . Spec . Issuer , oidcIdentityProvider . Name , frozenMetav1Now , 123 ) ,
2023-07-10 22:41:48 +00:00
) ,
expectedFederationDomainStatusUpdate ( federationDomain2 ,
configv1alpha1 . FederationDomainPhaseReady ,
2023-07-11 16:42:20 +00:00
allHappyConditionsLegacyConfigurationSuccess ( federationDomain2 . Spec . Issuer , oidcIdentityProvider . Name , frozenMetav1Now , 123 ) ,
2023-07-10 22:41:48 +00:00
) ,
2023-07-06 00:41:27 +00:00
} ,
} ,
{
2023-07-07 21:10:07 +00:00
name : "when there are both valid and invalid FederationDomains, the status will be correctly set on each " +
"FederationDomain individually" ,
2023-07-06 00:41:27 +00:00
inputObjects : [ ] runtime . Object {
2023-07-10 22:41:48 +00:00
invalidIssuerURLFederationDomain ,
2023-07-06 00:41:27 +00:00
federationDomain2 ,
2023-07-11 16:42:20 +00:00
oidcIdentityProvider ,
2023-07-06 00:41:27 +00:00
} ,
2023-07-11 16:42:20 +00:00
wantFDIssuers : [ ] * federationdomainproviders . FederationDomainIssuer {
2023-07-10 22:41:48 +00:00
// only the valid FederationDomain
2023-07-11 16:42:20 +00:00
federationDomainIssuerWithDefaultIDP ( t , federationDomain2 . Spec . Issuer , oidcIdentityProvider . ObjectMeta ) ,
2023-07-10 22:41:48 +00:00
} ,
wantStatusUpdates : [ ] * configv1alpha1 . FederationDomain {
expectedFederationDomainStatusUpdate ( invalidIssuerURLFederationDomain ,
configv1alpha1 . FederationDomainPhaseError ,
2023-07-14 17:27:25 +00:00
replaceConditions (
allHappyConditionsLegacyConfigurationSuccess ( federationDomain2 . Spec . Issuer , oidcIdentityProvider . Name , frozenMetav1Now , 123 ) ,
[ ] configv1alpha1 . Condition {
sadIssuerURLValidConditionCannotHaveQuery ( frozenMetav1Now , 123 ) ,
sadReadyCondition ( frozenMetav1Now , 123 ) ,
} ) ,
2023-07-10 22:41:48 +00:00
) ,
expectedFederationDomainStatusUpdate ( federationDomain2 ,
configv1alpha1 . FederationDomainPhaseReady ,
2023-07-11 16:42:20 +00:00
allHappyConditionsLegacyConfigurationSuccess ( federationDomain2 . Spec . Issuer , oidcIdentityProvider . Name , frozenMetav1Now , 123 ) ,
2023-07-10 22:41:48 +00:00
) ,
2023-07-06 00:41:27 +00:00
} ,
} ,
{
2023-07-07 21:10:07 +00:00
name : "when there are both valid and invalid FederationDomains, but updating the invalid one fails, the " +
"existing status will be unchanged" ,
2023-07-06 00:41:27 +00:00
inputObjects : [ ] runtime . Object {
2023-07-10 22:41:48 +00:00
invalidIssuerURLFederationDomain ,
2023-07-06 00:41:27 +00:00
federationDomain2 ,
2023-07-11 16:42:20 +00:00
oidcIdentityProvider ,
2023-07-06 00:41:27 +00:00
} ,
2023-07-11 16:42:20 +00:00
configClient : func ( client * pinnipedfake . Clientset ) {
2023-07-06 00:41:27 +00:00
client . PrependReactor (
"update" ,
"federationdomains" ,
func ( action coretesting . Action ) ( bool , runtime . Object , error ) {
fd := action . ( coretesting . UpdateAction ) . GetObject ( ) . ( * configv1alpha1 . FederationDomain )
2023-07-10 22:41:48 +00:00
if fd . Name == invalidIssuerURLFederationDomain . Name {
2020-10-09 14:39:17 +00:00
return true , nil , errors . New ( "some update error" )
2023-07-06 00:41:27 +00:00
}
return false , nil , nil
2020-10-09 14:39:17 +00:00
} ,
)
2023-07-06 00:41:27 +00:00
} ,
wantErr : "could not update status: some update error" ,
2023-07-11 16:42:20 +00:00
wantFDIssuers : [ ] * federationdomainproviders . FederationDomainIssuer {
2023-07-10 22:41:48 +00:00
// only the valid FederationDomain
2023-07-11 16:42:20 +00:00
federationDomainIssuerWithDefaultIDP ( t , federationDomain2 . Spec . Issuer , oidcIdentityProvider . ObjectMeta ) ,
2023-07-10 22:41:48 +00:00
} ,
wantStatusUpdates : [ ] * configv1alpha1 . FederationDomain {
expectedFederationDomainStatusUpdate ( invalidIssuerURLFederationDomain ,
configv1alpha1 . FederationDomainPhaseError ,
2023-07-14 17:27:25 +00:00
replaceConditions (
allHappyConditionsLegacyConfigurationSuccess ( federationDomain2 . Spec . Issuer , oidcIdentityProvider . Name , frozenMetav1Now , 123 ) ,
[ ] configv1alpha1 . Condition {
sadIssuerURLValidConditionCannotHaveQuery ( frozenMetav1Now , 123 ) ,
sadReadyCondition ( frozenMetav1Now , 123 ) ,
} ) ,
2023-07-10 22:41:48 +00:00
) ,
expectedFederationDomainStatusUpdate ( federationDomain2 ,
configv1alpha1 . FederationDomainPhaseReady ,
2023-07-11 16:42:20 +00:00
allHappyConditionsLegacyConfigurationSuccess ( federationDomain2 . Spec . Issuer , oidcIdentityProvider . Name , frozenMetav1Now , 123 ) ,
2023-07-10 22:41:48 +00:00
) ,
2023-07-06 00:41:27 +00:00
} ,
} ,
{
2023-07-07 21:10:07 +00:00
name : "when there are FederationDomains with duplicate issuer strings these particular FederationDomains " +
"will report error on IssuerUnique conditions" ,
2023-07-06 00:41:27 +00:00
inputObjects : [ ] runtime . Object {
& configv1alpha1 . FederationDomain {
2023-06-30 20:43:40 +00:00
ObjectMeta : metav1 . ObjectMeta { Name : "duplicate1" , Namespace : namespace , Generation : 123 } ,
2023-07-05 20:33:21 +00:00
Spec : configv1alpha1 . FederationDomainSpec { Issuer : "https://iSSueR-duPlicAte.cOm/a" } ,
2023-07-06 00:41:27 +00:00
} ,
& configv1alpha1 . FederationDomain {
2023-06-30 20:43:40 +00:00
ObjectMeta : metav1 . ObjectMeta { Name : "duplicate2" , Namespace : namespace , Generation : 123 } ,
2023-07-05 20:33:21 +00:00
Spec : configv1alpha1 . FederationDomainSpec { Issuer : "https://issuer-duplicate.com/a" } ,
2023-07-06 00:41:27 +00:00
} ,
& configv1alpha1 . FederationDomain {
2023-06-30 20:43:40 +00:00
ObjectMeta : metav1 . ObjectMeta { Name : "not-duplicate" , Namespace : namespace , Generation : 123 } ,
2023-07-06 00:41:27 +00:00
Spec : configv1alpha1 . FederationDomainSpec { Issuer : "https://issuer-duplicate.com/A" } , // different path (paths are case-sensitive)
} ,
2023-07-11 16:42:20 +00:00
oidcIdentityProvider ,
2023-07-06 00:41:27 +00:00
} ,
2023-07-11 16:42:20 +00:00
wantFDIssuers : [ ] * federationdomainproviders . FederationDomainIssuer {
federationDomainIssuerWithDefaultIDP ( t , "https://issuer-duplicate.com/A" , oidcIdentityProvider . ObjectMeta ) ,
2023-07-10 22:41:48 +00:00
} ,
wantStatusUpdates : [ ] * configv1alpha1 . FederationDomain {
expectedFederationDomainStatusUpdate (
& configv1alpha1 . FederationDomain {
ObjectMeta : metav1 . ObjectMeta { Name : "duplicate1" , Namespace : namespace , Generation : 123 } ,
} ,
configv1alpha1 . FederationDomainPhaseError ,
2023-07-14 17:27:25 +00:00
replaceConditions (
allHappyConditionsLegacyConfigurationSuccess ( "https://iSSueR-duPlicAte.cOm/a" , oidcIdentityProvider . Name , frozenMetav1Now , 123 ) ,
[ ] configv1alpha1 . Condition {
sadIssuerIsUniqueCondition ( frozenMetav1Now , 123 ) ,
sadReadyCondition ( frozenMetav1Now , 123 ) ,
} ) ,
2023-07-10 22:41:48 +00:00
) ,
expectedFederationDomainStatusUpdate (
& configv1alpha1 . FederationDomain {
ObjectMeta : metav1 . ObjectMeta { Name : "duplicate2" , Namespace : namespace , Generation : 123 } ,
} ,
configv1alpha1 . FederationDomainPhaseError ,
2023-07-14 17:27:25 +00:00
replaceConditions (
allHappyConditionsLegacyConfigurationSuccess ( "https://issuer-duplicate.com/a" , oidcIdentityProvider . Name , frozenMetav1Now , 123 ) ,
[ ] configv1alpha1 . Condition {
sadIssuerIsUniqueCondition ( frozenMetav1Now , 123 ) ,
sadReadyCondition ( frozenMetav1Now , 123 ) ,
} ) ,
2023-07-10 22:41:48 +00:00
) ,
expectedFederationDomainStatusUpdate (
& configv1alpha1 . FederationDomain {
ObjectMeta : metav1 . ObjectMeta { Name : "not-duplicate" , Namespace : namespace , Generation : 123 } ,
} ,
configv1alpha1 . FederationDomainPhaseReady ,
2023-07-11 16:42:20 +00:00
allHappyConditionsLegacyConfigurationSuccess ( "https://issuer-duplicate.com/A" , oidcIdentityProvider . Name , frozenMetav1Now , 123 ) ,
2023-07-10 22:41:48 +00:00
) ,
2023-07-06 00:41:27 +00:00
} ,
} ,
{
2023-07-07 21:10:07 +00:00
name : "when there are FederationDomains with the same issuer DNS hostname using different secretNames these " +
"particular FederationDomains will report errors on OneTLSSecretPerIssuerHostname conditions" ,
2023-07-06 00:41:27 +00:00
inputObjects : [ ] runtime . Object {
& configv1alpha1 . FederationDomain {
2023-06-30 20:43:40 +00:00
ObjectMeta : metav1 . ObjectMeta { Name : "fd1" , Namespace : namespace , Generation : 123 } ,
2023-07-05 20:33:21 +00:00
Spec : configv1alpha1 . FederationDomainSpec {
2020-11-02 22:55:29 +00:00
Issuer : "https://iSSueR-duPlicAte-adDress.cOm/path1" ,
2023-07-05 20:33:21 +00:00
TLS : & configv1alpha1 . FederationDomainTLSSpec { SecretName : "secret1" } ,
2020-10-23 23:25:44 +00:00
} ,
2023-07-06 00:41:27 +00:00
} ,
& configv1alpha1 . FederationDomain {
2023-06-30 20:43:40 +00:00
ObjectMeta : metav1 . ObjectMeta { Name : "fd2" , Namespace : namespace , Generation : 123 } ,
2023-07-05 20:33:21 +00:00
Spec : configv1alpha1 . FederationDomainSpec {
2020-10-27 00:03:26 +00:00
// Validation treats these as the same DNS hostname even though they have different port numbers,
// because SNI information on the incoming requests is not going to include port numbers.
2020-11-02 22:55:29 +00:00
Issuer : "https://issuer-duplicate-address.com:1234/path2" ,
2023-07-05 20:33:21 +00:00
TLS : & configv1alpha1 . FederationDomainTLSSpec { SecretName : "secret2" } ,
2020-10-23 23:25:44 +00:00
} ,
2023-07-06 00:41:27 +00:00
} ,
& configv1alpha1 . FederationDomain {
2023-06-30 20:43:40 +00:00
ObjectMeta : metav1 . ObjectMeta { Name : "differentIssuerAddressFederationDomain" , Namespace : namespace , Generation : 123 } ,
2023-07-05 20:33:21 +00:00
Spec : configv1alpha1 . FederationDomainSpec {
2020-11-02 22:55:29 +00:00
Issuer : "https://issuer-not-duplicate.com" ,
2023-07-05 20:33:21 +00:00
TLS : & configv1alpha1 . FederationDomainTLSSpec { SecretName : "secret1" } ,
2020-10-23 23:25:44 +00:00
} ,
2023-07-06 00:41:27 +00:00
} ,
& configv1alpha1 . FederationDomain {
2023-06-30 20:43:40 +00:00
ObjectMeta : metav1 . ObjectMeta { Name : "invalidIssuerURLFederationDomain" , Namespace : namespace , Generation : 123 } ,
2023-07-05 20:33:21 +00:00
Spec : configv1alpha1 . FederationDomainSpec {
2020-11-02 22:55:29 +00:00
Issuer : invalidIssuerURL ,
2023-07-05 20:33:21 +00:00
TLS : & configv1alpha1 . FederationDomainTLSSpec { SecretName : "secret1" } ,
2020-10-23 23:25:44 +00:00
} ,
2023-07-06 00:41:27 +00:00
} ,
2023-07-11 16:42:20 +00:00
oidcIdentityProvider ,
2023-07-06 00:41:27 +00:00
} ,
2023-07-11 16:42:20 +00:00
wantFDIssuers : [ ] * federationdomainproviders . FederationDomainIssuer {
federationDomainIssuerWithDefaultIDP ( t , "https://issuer-not-duplicate.com" , oidcIdentityProvider . ObjectMeta ) ,
2023-07-10 22:41:48 +00:00
} ,
wantStatusUpdates : [ ] * configv1alpha1 . FederationDomain {
expectedFederationDomainStatusUpdate (
& configv1alpha1 . FederationDomain {
ObjectMeta : metav1 . ObjectMeta { Name : "fd1" , Namespace : namespace , Generation : 123 } ,
} ,
configv1alpha1 . FederationDomainPhaseError ,
2023-07-14 17:27:25 +00:00
replaceConditions (
allHappyConditionsLegacyConfigurationSuccess ( "https://iSSueR-duPlicAte-adDress.cOm/path1" , oidcIdentityProvider . Name , frozenMetav1Now , 123 ) ,
[ ] configv1alpha1 . Condition {
sadOneTLSSecretPerIssuerHostnameCondition ( frozenMetav1Now , 123 ) ,
sadReadyCondition ( frozenMetav1Now , 123 ) ,
} ) ,
2023-07-10 22:41:48 +00:00
) ,
expectedFederationDomainStatusUpdate (
& configv1alpha1 . FederationDomain {
ObjectMeta : metav1 . ObjectMeta { Name : "fd2" , Namespace : namespace , Generation : 123 } ,
} ,
configv1alpha1 . FederationDomainPhaseError ,
2023-07-14 17:27:25 +00:00
replaceConditions (
allHappyConditionsLegacyConfigurationSuccess ( "https://issuer-duplicate-address.com:1234/path2" , oidcIdentityProvider . Name , frozenMetav1Now , 123 ) ,
[ ] configv1alpha1 . Condition {
sadOneTLSSecretPerIssuerHostnameCondition ( frozenMetav1Now , 123 ) ,
sadReadyCondition ( frozenMetav1Now , 123 ) ,
} ) ,
2023-07-10 22:41:48 +00:00
) ,
expectedFederationDomainStatusUpdate (
& configv1alpha1 . FederationDomain {
ObjectMeta : metav1 . ObjectMeta { Name : "invalidIssuerURLFederationDomain" , Namespace : namespace , Generation : 123 } ,
} ,
configv1alpha1 . FederationDomainPhaseError ,
2023-07-14 17:27:25 +00:00
replaceConditions (
allHappyConditionsLegacyConfigurationSuccess ( invalidIssuerURL , oidcIdentityProvider . Name , frozenMetav1Now , 123 ) ,
[ ] configv1alpha1 . Condition {
unknownIssuerIsUniqueCondition ( frozenMetav1Now , 123 ) ,
sadIssuerURLValidConditionCannotParse ( frozenMetav1Now , 123 ) ,
unknownOneTLSSecretPerIssuerHostnameCondition ( frozenMetav1Now , 123 ) ,
sadReadyCondition ( frozenMetav1Now , 123 ) ,
} ) ,
2023-07-10 22:41:48 +00:00
) ,
expectedFederationDomainStatusUpdate (
& configv1alpha1 . FederationDomain {
ObjectMeta : metav1 . ObjectMeta { Name : "differentIssuerAddressFederationDomain" , Namespace : namespace , Generation : 123 } ,
} ,
configv1alpha1 . FederationDomainPhaseReady ,
2023-07-11 16:42:20 +00:00
allHappyConditionsLegacyConfigurationSuccess ( "https://issuer-not-duplicate.com" , oidcIdentityProvider . Name , frozenMetav1Now , 123 ) ,
2023-07-10 22:41:48 +00:00
) ,
2023-07-10 21:09:19 +00:00
} ,
} ,
{
name : "legacy config: no identity provider specified in federation domain and no identity providers found results in not found status" ,
inputObjects : [ ] runtime . Object {
federationDomain1 ,
federationDomain2 ,
} ,
2023-07-11 16:42:20 +00:00
wantFDIssuers : [ ] * federationdomainproviders . FederationDomainIssuer { } ,
2023-07-10 22:41:48 +00:00
wantStatusUpdates : [ ] * configv1alpha1 . FederationDomain {
expectedFederationDomainStatusUpdate ( federationDomain1 ,
configv1alpha1 . FederationDomainPhaseError ,
2023-07-14 17:27:25 +00:00
replaceConditions (
allHappyConditionsLegacyConfigurationSuccess ( federationDomain1 . Spec . Issuer , "" , frozenMetav1Now , 123 ) ,
[ ] configv1alpha1 . Condition {
sadIdentityProvidersFoundConditionLegacyConfigurationIdentityProviderNotFound ( frozenMetav1Now , 123 ) ,
sadReadyCondition ( frozenMetav1Now , 123 ) ,
} ) ,
2023-07-10 22:41:48 +00:00
) ,
expectedFederationDomainStatusUpdate ( federationDomain2 ,
configv1alpha1 . FederationDomainPhaseError ,
2023-07-14 17:27:25 +00:00
replaceConditions (
allHappyConditionsLegacyConfigurationSuccess ( federationDomain2 . Spec . Issuer , "" , frozenMetav1Now , 123 ) ,
[ ] configv1alpha1 . Condition {
sadIdentityProvidersFoundConditionLegacyConfigurationIdentityProviderNotFound ( frozenMetav1Now , 123 ) ,
sadReadyCondition ( frozenMetav1Now , 123 ) ,
} ) ,
2023-07-10 22:41:48 +00:00
) ,
2023-07-10 21:09:19 +00:00
} ,
} ,
{
name : "legacy config: no identity provider specified in federation domain and multiple identity providers found results in not specified status" ,
inputObjects : [ ] runtime . Object {
federationDomain1 ,
2023-07-11 16:42:20 +00:00
oidcIdentityProvider ,
ldapIdentityProvider ,
adIdentityProvider ,
2023-07-10 21:09:19 +00:00
} ,
2023-07-11 16:42:20 +00:00
wantFDIssuers : [ ] * federationdomainproviders . FederationDomainIssuer { } ,
2023-07-10 22:41:48 +00:00
wantStatusUpdates : [ ] * configv1alpha1 . FederationDomain {
expectedFederationDomainStatusUpdate ( federationDomain1 ,
configv1alpha1 . FederationDomainPhaseError ,
2023-07-14 17:27:25 +00:00
replaceConditions (
allHappyConditionsLegacyConfigurationSuccess ( federationDomain1 . Spec . Issuer , "" , frozenMetav1Now , 123 ) ,
[ ] configv1alpha1 . Condition {
sadIdentityProvidersFoundConditionIdentityProviderNotSpecified ( 3 , frozenMetav1Now , 123 ) ,
sadReadyCondition ( frozenMetav1Now , 123 ) ,
} ) ,
2023-07-10 22:41:48 +00:00
) ,
2023-07-10 21:09:19 +00:00
} ,
} ,
{
name : "the federation domain specifies identity providers that cannot be found" ,
inputObjects : [ ] runtime . Object {
& configv1alpha1 . FederationDomain {
ObjectMeta : metav1 . ObjectMeta { Name : "config1" , Namespace : namespace , Generation : 123 } ,
Spec : configv1alpha1 . FederationDomainSpec {
Issuer : "https://issuer1.com" ,
IdentityProviders : [ ] configv1alpha1 . FederationDomainIdentityProvider {
{
DisplayName : "cant-find-me" ,
ObjectRef : corev1 . TypedLocalObjectReference {
APIGroup : pointer . String ( apiGroupSupervisor ) ,
Kind : "OIDCIdentityProvider" ,
2023-07-11 16:42:20 +00:00
Name : "cant-find-me-name" ,
2023-07-10 21:09:19 +00:00
} ,
} ,
2023-07-10 22:41:48 +00:00
{
DisplayName : "cant-find-me-either" ,
ObjectRef : corev1 . TypedLocalObjectReference {
APIGroup : pointer . String ( apiGroupSupervisor ) ,
Kind : "OIDCIdentityProvider" ,
2023-07-11 16:42:20 +00:00
Name : "cant-find-me-either-name" ,
} ,
} ,
{
DisplayName : "cant-find-me-still" ,
ObjectRef : corev1 . TypedLocalObjectReference {
APIGroup : pointer . String ( apiGroupSupervisor ) ,
Kind : "ActiveDirectoryIdentityProvider" ,
Name : "cant-find-me-still-name" ,
2023-07-10 22:41:48 +00:00
} ,
} ,
2023-07-10 21:09:19 +00:00
} ,
} ,
} ,
} ,
2023-07-11 16:42:20 +00:00
wantFDIssuers : [ ] * federationdomainproviders . FederationDomainIssuer { } ,
2023-07-10 22:41:48 +00:00
wantStatusUpdates : [ ] * configv1alpha1 . FederationDomain {
expectedFederationDomainStatusUpdate (
& configv1alpha1 . FederationDomain {
ObjectMeta : metav1 . ObjectMeta { Name : "config1" , Namespace : namespace , Generation : 123 } ,
} ,
configv1alpha1 . FederationDomainPhaseError ,
2023-07-14 17:27:25 +00:00
replaceConditions (
allHappyConditionsSuccess ( "https://issuer1.com" , frozenMetav1Now , 123 ) ,
[ ] configv1alpha1 . Condition {
sadIdentityProvidersFoundConditionIdentityProvidersObjectRefsNotFound (
` .spec.identityProviders[0] with displayName "cant-find-me", ` +
` .spec.identityProviders[1] with displayName "cant-find-me-either", ` +
` .spec.identityProviders[2] with displayName "cant-find-me-still" ` ,
frozenMetav1Now , 123 ) ,
sadReadyCondition ( frozenMetav1Now , 123 ) ,
} ) ,
2023-07-10 22:41:48 +00:00
) ,
} ,
} ,
{
name : "the federation domain specifies identity providers that all exist" ,
inputObjects : [ ] runtime . Object {
2023-07-11 16:42:20 +00:00
oidcIdentityProvider ,
ldapIdentityProvider ,
adIdentityProvider ,
2023-07-10 22:41:48 +00:00
& configv1alpha1 . FederationDomain {
ObjectMeta : metav1 . ObjectMeta { Name : "config1" , Namespace : namespace , Generation : 123 } ,
Spec : configv1alpha1 . FederationDomainSpec {
Issuer : "https://issuer1.com" ,
IdentityProviders : [ ] configv1alpha1 . FederationDomainIdentityProvider {
{
DisplayName : "can-find-me" ,
ObjectRef : corev1 . TypedLocalObjectReference {
APIGroup : pointer . String ( apiGroupSupervisor ) ,
Kind : "OIDCIdentityProvider" ,
2023-07-11 16:42:20 +00:00
Name : oidcIdentityProvider . Name ,
2023-07-10 21:09:19 +00:00
} ,
} ,
2023-07-10 22:41:48 +00:00
{
DisplayName : "can-find-me-too" ,
ObjectRef : corev1 . TypedLocalObjectReference {
APIGroup : pointer . String ( apiGroupSupervisor ) ,
2023-07-11 16:42:20 +00:00
Kind : "LDAPIdentityProvider" ,
Name : ldapIdentityProvider . Name ,
} ,
} ,
{
DisplayName : "can-find-me-three" ,
ObjectRef : corev1 . TypedLocalObjectReference {
APIGroup : pointer . String ( apiGroupSupervisor ) ,
Kind : "ActiveDirectoryIdentityProvider" ,
Name : adIdentityProvider . Name ,
2023-07-10 22:41:48 +00:00
} ,
2023-07-10 21:09:19 +00:00
} ,
2023-07-10 22:41:48 +00:00
} ,
} ,
} ,
} ,
2023-07-11 16:42:20 +00:00
wantFDIssuers : [ ] * federationdomainproviders . FederationDomainIssuer {
2023-07-10 22:41:48 +00:00
federationDomainIssuerWithIDPs ( t , "https://issuer1.com" ,
[ ] * federationdomainproviders . FederationDomainIdentityProvider {
{
DisplayName : "can-find-me" ,
2023-07-11 16:42:20 +00:00
UID : oidcIdentityProvider . UID ,
2023-07-10 22:41:48 +00:00
Transforms : idtransform . NewTransformationPipeline ( ) ,
} ,
{
DisplayName : "can-find-me-too" ,
2023-07-11 16:42:20 +00:00
UID : ldapIdentityProvider . UID ,
Transforms : idtransform . NewTransformationPipeline ( ) ,
} ,
{
DisplayName : "can-find-me-three" ,
UID : adIdentityProvider . UID ,
2023-07-10 22:41:48 +00:00
Transforms : idtransform . NewTransformationPipeline ( ) ,
} ,
} ) ,
} ,
wantStatusUpdates : [ ] * configv1alpha1 . FederationDomain {
expectedFederationDomainStatusUpdate (
& configv1alpha1 . FederationDomain {
ObjectMeta : metav1 . ObjectMeta { Name : "config1" , Namespace : namespace , Generation : 123 } ,
} ,
configv1alpha1 . FederationDomainPhaseReady ,
allHappyConditionsSuccess ( "https://issuer1.com" , frozenMetav1Now , 123 ) ,
) ,
2023-07-06 00:41:27 +00:00
} ,
2023-07-12 16:43:33 +00:00
} ,
{
name : "the federation domain has duplicate display names for IDPs" ,
inputObjects : [ ] runtime . Object {
oidcIdentityProvider ,
ldapIdentityProvider ,
adIdentityProvider ,
& configv1alpha1 . FederationDomain {
ObjectMeta : metav1 . ObjectMeta { Name : "config1" , Namespace : namespace , Generation : 123 } ,
Spec : configv1alpha1 . FederationDomainSpec {
Issuer : "https://issuer1.com" ,
IdentityProviders : [ ] configv1alpha1 . FederationDomainIdentityProvider {
{
DisplayName : "duplicate1" ,
ObjectRef : corev1 . TypedLocalObjectReference {
APIGroup : pointer . String ( apiGroupSupervisor ) ,
Kind : "OIDCIdentityProvider" ,
Name : oidcIdentityProvider . Name ,
} ,
} ,
{
DisplayName : "duplicate1" ,
ObjectRef : corev1 . TypedLocalObjectReference {
APIGroup : pointer . String ( apiGroupSupervisor ) ,
Kind : "LDAPIdentityProvider" ,
Name : ldapIdentityProvider . Name ,
} ,
} ,
2023-07-13 22:26:32 +00:00
{
DisplayName : "duplicate1" ,
ObjectRef : corev1 . TypedLocalObjectReference {
APIGroup : pointer . String ( apiGroupSupervisor ) ,
Kind : "LDAPIdentityProvider" ,
Name : ldapIdentityProvider . Name ,
} ,
} ,
2023-07-12 16:43:33 +00:00
{
DisplayName : "unique" ,
ObjectRef : corev1 . TypedLocalObjectReference {
APIGroup : pointer . String ( apiGroupSupervisor ) ,
Kind : "ActiveDirectoryIdentityProvider" ,
Name : adIdentityProvider . Name ,
} ,
} ,
{
DisplayName : "duplicate2" ,
ObjectRef : corev1 . TypedLocalObjectReference {
APIGroup : pointer . String ( apiGroupSupervisor ) ,
Kind : "LDAPIdentityProvider" ,
Name : ldapIdentityProvider . Name ,
} ,
} ,
{
DisplayName : "duplicate2" ,
ObjectRef : corev1 . TypedLocalObjectReference {
APIGroup : pointer . String ( apiGroupSupervisor ) ,
Kind : "ActiveDirectoryIdentityProvider" ,
Name : adIdentityProvider . Name ,
} ,
} ,
} ,
} ,
} ,
} ,
wantFDIssuers : [ ] * federationdomainproviders . FederationDomainIssuer { } ,
wantStatusUpdates : [ ] * configv1alpha1 . FederationDomain {
expectedFederationDomainStatusUpdate (
& configv1alpha1 . FederationDomain {
ObjectMeta : metav1 . ObjectMeta { Name : "config1" , Namespace : namespace , Generation : 123 } ,
} ,
configv1alpha1 . FederationDomainPhaseError ,
2023-07-14 17:27:25 +00:00
replaceConditions (
allHappyConditionsSuccess ( "https://issuer1.com" , frozenMetav1Now , 123 ) ,
[ ] configv1alpha1 . Condition {
sadDisplayNamesUniqueCondition ( ` "duplicate1", "duplicate2" ` , frozenMetav1Now , 123 ) ,
sadReadyCondition ( frozenMetav1Now , 123 ) ,
} ) ,
) ,
2023-07-12 16:43:33 +00:00
} ,
2023-07-06 00:41:27 +00:00
} ,
2023-07-12 17:34:15 +00:00
{
name : "the federation domain has unrecognized api group names in objectRefs" ,
inputObjects : [ ] runtime . Object {
oidcIdentityProvider ,
ldapIdentityProvider ,
adIdentityProvider ,
& configv1alpha1 . FederationDomain {
ObjectMeta : metav1 . ObjectMeta { Name : "config1" , Namespace : namespace , Generation : 123 } ,
Spec : configv1alpha1 . FederationDomainSpec {
Issuer : "https://issuer1.com" ,
IdentityProviders : [ ] configv1alpha1 . FederationDomainIdentityProvider {
{
DisplayName : "name1" ,
ObjectRef : corev1 . TypedLocalObjectReference {
APIGroup : pointer . String ( "wrong.example.com" ) ,
Kind : "OIDCIdentityProvider" ,
Name : oidcIdentityProvider . Name ,
} ,
} ,
{
DisplayName : "name2" ,
ObjectRef : corev1 . TypedLocalObjectReference {
2023-07-12 20:15:52 +00:00
APIGroup : pointer . String ( "" ) , // empty string is wrong
2023-07-12 17:34:15 +00:00
Kind : "LDAPIdentityProvider" ,
Name : ldapIdentityProvider . Name ,
} ,
} ,
{
DisplayName : "name3" ,
ObjectRef : corev1 . TypedLocalObjectReference {
2023-07-12 20:15:52 +00:00
APIGroup : nil , // nil is wrong, and gets treated like an empty string in the error condition
2023-07-12 17:34:15 +00:00
Kind : "LDAPIdentityProvider" ,
Name : ldapIdentityProvider . Name ,
} ,
} ,
{
DisplayName : "name4" ,
ObjectRef : corev1 . TypedLocalObjectReference {
APIGroup : pointer . String ( apiGroupSupervisor ) , // correct
Kind : "ActiveDirectoryIdentityProvider" ,
Name : adIdentityProvider . Name ,
} ,
} ,
} ,
} ,
} ,
} ,
wantFDIssuers : [ ] * federationdomainproviders . FederationDomainIssuer { } ,
wantStatusUpdates : [ ] * configv1alpha1 . FederationDomain {
expectedFederationDomainStatusUpdate (
& configv1alpha1 . FederationDomain {
ObjectMeta : metav1 . ObjectMeta { Name : "config1" , Namespace : namespace , Generation : 123 } ,
} ,
configv1alpha1 . FederationDomainPhaseError ,
2023-07-14 17:27:25 +00:00
replaceConditions (
allHappyConditionsSuccess ( "https://issuer1.com" , frozenMetav1Now , 123 ) ,
[ ] configv1alpha1 . Condition {
sadAPIGroupSuffixCondition ( ` "", "", "wrong.example.com" ` , frozenMetav1Now , 123 ) ,
sadIdentityProvidersFoundConditionIdentityProvidersObjectRefsNotFound (
` .spec.identityProviders[0] with displayName "name1", ` +
` .spec.identityProviders[1] with displayName "name2", ` +
` .spec.identityProviders[2] with displayName "name3" ` ,
frozenMetav1Now , 123 ) ,
sadReadyCondition ( frozenMetav1Now , 123 ) ,
} ) ,
) ,
2023-07-12 20:15:52 +00:00
} ,
} ,
{
name : "the federation domain has unrecognized kind names in objectRefs" ,
inputObjects : [ ] runtime . Object {
oidcIdentityProvider ,
ldapIdentityProvider ,
adIdentityProvider ,
& configv1alpha1 . FederationDomain {
ObjectMeta : metav1 . ObjectMeta { Name : "config1" , Namespace : namespace , Generation : 123 } ,
Spec : configv1alpha1 . FederationDomainSpec {
Issuer : "https://issuer1.com" ,
IdentityProviders : [ ] configv1alpha1 . FederationDomainIdentityProvider {
{
DisplayName : "name1" ,
ObjectRef : corev1 . TypedLocalObjectReference {
APIGroup : pointer . String ( apiGroupSupervisor ) ,
Kind : "OIDCIdentityProvider" , // correct
Name : oidcIdentityProvider . Name ,
} ,
} ,
{
DisplayName : "name2" ,
ObjectRef : corev1 . TypedLocalObjectReference {
APIGroup : pointer . String ( apiGroupSupervisor ) ,
Kind : "wrong" ,
Name : ldapIdentityProvider . Name ,
} ,
} ,
{
DisplayName : "name3" ,
ObjectRef : corev1 . TypedLocalObjectReference {
APIGroup : pointer . String ( apiGroupSupervisor ) ,
Kind : "" , // empty is also wrong
Name : ldapIdentityProvider . Name ,
} ,
} ,
} ,
} ,
} ,
} ,
wantFDIssuers : [ ] * federationdomainproviders . FederationDomainIssuer { } ,
wantStatusUpdates : [ ] * configv1alpha1 . FederationDomain {
expectedFederationDomainStatusUpdate (
& configv1alpha1 . FederationDomain {
ObjectMeta : metav1 . ObjectMeta { Name : "config1" , Namespace : namespace , Generation : 123 } ,
} ,
configv1alpha1 . FederationDomainPhaseError ,
2023-07-14 17:27:25 +00:00
replaceConditions (
allHappyConditionsSuccess ( "https://issuer1.com" , frozenMetav1Now , 123 ) ,
[ ] configv1alpha1 . Condition {
sadKindCondition ( ` "", "wrong" ` , frozenMetav1Now , 123 ) ,
sadIdentityProvidersFoundConditionIdentityProvidersObjectRefsNotFound (
` .spec.identityProviders[1] with displayName "name2", ` +
` .spec.identityProviders[2] with displayName "name3" ` ,
frozenMetav1Now , 123 ) ,
sadReadyCondition ( frozenMetav1Now , 123 ) ,
} ) ,
) ,
2023-07-12 17:34:15 +00:00
} ,
} ,
2023-07-13 22:26:32 +00:00
{
name : "the federation domain has duplicate transformation const names" ,
inputObjects : [ ] runtime . Object {
oidcIdentityProvider ,
& configv1alpha1 . FederationDomain {
ObjectMeta : metav1 . ObjectMeta { Name : "config1" , Namespace : namespace , Generation : 123 } ,
Spec : configv1alpha1 . FederationDomainSpec {
Issuer : "https://issuer1.com" ,
IdentityProviders : [ ] configv1alpha1 . FederationDomainIdentityProvider {
{
DisplayName : "name1" ,
ObjectRef : corev1 . TypedLocalObjectReference {
APIGroup : pointer . String ( apiGroupSupervisor ) ,
Kind : "OIDCIdentityProvider" ,
Name : oidcIdentityProvider . Name ,
} ,
Transforms : configv1alpha1 . FederationDomainTransforms {
Constants : [ ] configv1alpha1 . FederationDomainTransformsConstant {
2023-07-14 19:06:20 +00:00
{ Name : "duplicate1" , Type : "string" , StringValue : "abc" } ,
2023-07-17 23:41:28 +00:00
{ Name : "duplicate1" , Type : "stringList" , StringListValue : [ ] string { "def" } } ,
2023-07-14 19:06:20 +00:00
{ Name : "duplicate1" , Type : "string" , StringValue : "efg" } ,
{ Name : "duplicate2" , Type : "string" , StringValue : "123" } ,
{ Name : "duplicate2" , Type : "string" , StringValue : "456" } ,
{ Name : "uniqueName" , Type : "string" , StringValue : "hij" } ,
2023-07-13 22:26:32 +00:00
} ,
} ,
} ,
} ,
} ,
} ,
} ,
wantFDIssuers : [ ] * federationdomainproviders . FederationDomainIssuer { } ,
wantStatusUpdates : [ ] * configv1alpha1 . FederationDomain {
expectedFederationDomainStatusUpdate (
& configv1alpha1 . FederationDomain {
ObjectMeta : metav1 . ObjectMeta { Name : "config1" , Namespace : namespace , Generation : 123 } ,
} ,
configv1alpha1 . FederationDomainPhaseError ,
2023-07-14 17:27:25 +00:00
replaceConditions (
allHappyConditionsSuccess ( "https://issuer1.com" , frozenMetav1Now , 123 ) ,
[ ] configv1alpha1 . Condition {
2023-07-18 22:00:58 +00:00
sadConstNamesUniqueCondition (
` the names specified by .spec.identityProviders[0].transforms.constants[].name contain duplicates: "duplicate1", "duplicate2" ` ,
frozenMetav1Now , 123 ) ,
2023-07-14 17:27:25 +00:00
sadReadyCondition ( frozenMetav1Now , 123 ) ,
} ) ,
) ,
2023-07-13 22:26:32 +00:00
} ,
} ,
2023-07-14 19:06:20 +00:00
{
name : "the federation domain has transformation expressions which don't compile" ,
inputObjects : [ ] runtime . Object {
oidcIdentityProvider ,
& configv1alpha1 . FederationDomain {
ObjectMeta : metav1 . ObjectMeta { Name : "config1" , Namespace : namespace , Generation : 123 } ,
Spec : configv1alpha1 . FederationDomainSpec {
Issuer : "https://issuer1.com" ,
IdentityProviders : [ ] configv1alpha1 . FederationDomainIdentityProvider {
{
DisplayName : "name1" ,
ObjectRef : corev1 . TypedLocalObjectReference {
APIGroup : pointer . String ( apiGroupSupervisor ) ,
Kind : "OIDCIdentityProvider" ,
Name : oidcIdentityProvider . Name ,
} ,
Transforms : configv1alpha1 . FederationDomainTransforms {
Expressions : [ ] configv1alpha1 . FederationDomainTransformsExpression {
{ Type : "username/v1" , Expression : "this is not a valid cel expression" } ,
{ Type : "groups/v1" , Expression : "this is also not a valid cel expression" } ,
{ Type : "username/v1" , Expression : "username" } , // valid
{ Type : "policy/v1" , Expression : "still not a valid cel expression" } ,
} ,
} ,
} ,
} ,
} ,
} ,
} ,
wantFDIssuers : [ ] * federationdomainproviders . FederationDomainIssuer { } ,
wantStatusUpdates : [ ] * configv1alpha1 . FederationDomain {
expectedFederationDomainStatusUpdate (
& configv1alpha1 . FederationDomain {
ObjectMeta : metav1 . ObjectMeta { Name : "config1" , Namespace : namespace , Generation : 123 } ,
} ,
configv1alpha1 . FederationDomainPhaseError ,
replaceConditions (
allHappyConditionsSuccess ( "https://issuer1.com" , frozenMetav1Now , 123 ) ,
[ ] configv1alpha1 . Condition {
2023-07-18 22:00:58 +00:00
sadTransformationExpressionsCondition ( here . Doc (
` spec . identityProvider [ 0 ] . transforms . expressions [ 0 ] . expression was invalid :
CEL expression compile error : ERROR : < input > : 1 : 6 : Syntax error : mismatched input ' is ' expecting < EOF >
| this is not a valid cel expression
| ... . . ^
spec . identityProvider [ 0 ] . transforms . expressions [ 1 ] . expression was invalid :
CEL expression compile error : ERROR : < input > : 1 : 6 : Syntax error : mismatched input ' is ' expecting < EOF >
| this is also not a valid cel expression
| ... . . ^
spec . identityProvider [ 0 ] . transforms . expressions [ 3 ] . expression was invalid :
CEL expression compile error : ERROR : < input > : 1 : 7 : Syntax error : mismatched input ' not ' expecting < EOF >
| still not a valid cel expression
| ... ... ^ ` ,
) , frozenMetav1Now , 123 ) ,
sadTransformationExamplesCondition (
"unable to check if the examples specified by .spec.identityProviders[0].transforms.examples[] had errors because an expression was invalid" ,
2023-07-14 23:50:43 +00:00
frozenMetav1Now , 123 ) ,
sadReadyCondition ( frozenMetav1Now , 123 ) ,
} ) ,
) ,
} ,
} ,
{
name : "the federation domain has transformation examples which don't pass" ,
inputObjects : [ ] runtime . Object {
oidcIdentityProvider ,
& configv1alpha1 . FederationDomain {
ObjectMeta : metav1 . ObjectMeta { Name : "config1" , Namespace : namespace , Generation : 123 } ,
Spec : configv1alpha1 . FederationDomainSpec {
Issuer : "https://issuer1.com" ,
IdentityProviders : [ ] configv1alpha1 . FederationDomainIdentityProvider {
{
DisplayName : "name1" ,
ObjectRef : corev1 . TypedLocalObjectReference {
APIGroup : pointer . String ( apiGroupSupervisor ) ,
Kind : "OIDCIdentityProvider" ,
Name : oidcIdentityProvider . Name ,
} ,
Transforms : configv1alpha1 . FederationDomainTransforms {
Expressions : [ ] configv1alpha1 . FederationDomainTransformsExpression {
{ Type : "policy/v1" , Expression : ` username == "ryan" || username == "rejectMeWithDefaultMessage" ` , Message : "only ryan allowed" } ,
{ Type : "policy/v1" , Expression : ` username != "rejectMeWithDefaultMessage" ` } , // no message specified
{ Type : "username/v1" , Expression : ` "pre:" + username ` } ,
{ Type : "groups/v1" , Expression : ` groups.map(g, "pre:" + g) ` } ,
} ,
Examples : [ ] configv1alpha1 . FederationDomainTransformsExample {
{ // this example should pass
Username : "ryan" ,
Groups : [ ] string { "a" , "b" } ,
Expects : configv1alpha1 . FederationDomainTransformsExampleExpects {
Username : "pre:ryan" ,
Groups : [ ] string { "pre:b" , "pre:a" , "pre:b" , "pre:a" } , // order and repeats don't matter, treated like a set
Rejected : false ,
} ,
} ,
{ // this example should pass
Username : "other" ,
Expects : configv1alpha1 . FederationDomainTransformsExampleExpects {
Rejected : true ,
Message : "only ryan allowed" ,
} ,
} ,
{ // this example should fail because it expects the user to be rejected but the user was actually not rejected
Username : "ryan" ,
Groups : [ ] string { "a" , "b" } ,
Expects : configv1alpha1 . FederationDomainTransformsExampleExpects {
Rejected : true ,
Message : "this input is ignored in this case" ,
} ,
} ,
{ // this example should fail because it expects the user not to be rejected but they were actually rejected
Username : "other" ,
Groups : [ ] string { "a" , "b" } ,
Expects : configv1alpha1 . FederationDomainTransformsExampleExpects {
Username : "pre:other" ,
Groups : [ ] string { "pre:a" , "pre:b" } ,
Rejected : false ,
} ,
} ,
{ // this example should fail because it expects the wrong rejection message
Username : "other" ,
Groups : [ ] string { "a" , "b" } ,
Expects : configv1alpha1 . FederationDomainTransformsExampleExpects {
Rejected : true ,
Message : "wrong message" ,
} ,
} ,
{ // this example should pass even though it does not make any assertion about the rejection message
// because the message assertions defaults to asserting the default rejection message
Username : "rejectMeWithDefaultMessage" ,
Groups : [ ] string { "a" , "b" } ,
Expects : configv1alpha1 . FederationDomainTransformsExampleExpects {
Rejected : true ,
} ,
} ,
{ // this example should fail because it expects both the wrong username and groups
Username : "ryan" ,
Groups : [ ] string { "b" , "a" } ,
Expects : configv1alpha1 . FederationDomainTransformsExampleExpects {
Username : "wrong" ,
Groups : [ ] string { } ,
Rejected : false ,
} ,
} ,
{ // this example should fail because it expects the wrong username only
Username : "ryan" ,
Groups : [ ] string { "a" , "b" } ,
Expects : configv1alpha1 . FederationDomainTransformsExampleExpects {
Username : "wrong" ,
Groups : [ ] string { "pre:b" , "pre:a" } ,
Rejected : false ,
} ,
} ,
{ // this example should fail because it expects the wrong groups only
Username : "ryan" ,
Groups : [ ] string { "b" , "a" } ,
Expects : configv1alpha1 . FederationDomainTransformsExampleExpects {
Username : "pre:ryan" ,
Groups : [ ] string { "wrong2" , "wrong1" } ,
Rejected : false ,
} ,
} ,
{ // this example should fail because it does not expect anything but the auth actually was successful
Username : "ryan" ,
Groups : [ ] string { "b" , "a" } ,
Expects : configv1alpha1 . FederationDomainTransformsExampleExpects { } ,
} ,
} ,
} ,
} ,
} ,
} ,
} ,
} ,
wantFDIssuers : [ ] * federationdomainproviders . FederationDomainIssuer { } ,
wantStatusUpdates : [ ] * configv1alpha1 . FederationDomain {
expectedFederationDomainStatusUpdate (
& configv1alpha1 . FederationDomain {
ObjectMeta : metav1 . ObjectMeta { Name : "config1" , Namespace : namespace , Generation : 123 } ,
} ,
configv1alpha1 . FederationDomainPhaseError ,
replaceConditions (
allHappyConditionsSuccess ( "https://issuer1.com" , frozenMetav1Now , 123 ) ,
[ ] configv1alpha1 . Condition {
2023-07-18 22:00:58 +00:00
sadTransformationExamplesCondition ( here . Doc (
` . spec . identityProviders [ 0 ] . transforms . examples [ 2 ] example failed :
expected : authentication to be rejected
actual : authentication was not rejected
. spec . identityProviders [ 0 ] . transforms . examples [ 3 ] example failed :
expected : authentication not to be rejected
actual : authentication was rejected with message "only ryan allowed"
. spec . identityProviders [ 0 ] . transforms . examples [ 4 ] example failed :
expected : authentication rejection message "wrong message"
actual : authentication rejection message "only ryan allowed"
. spec . identityProviders [ 0 ] . transforms . examples [ 6 ] example failed :
expected : username "wrong"
actual : username "pre:ryan"
. spec . identityProviders [ 0 ] . transforms . examples [ 6 ] example failed :
expected : groups [ ]
actual : groups [ "pre:a" , "pre:b" ]
. spec . identityProviders [ 0 ] . transforms . examples [ 7 ] example failed :
expected : username "wrong"
actual : username "pre:ryan"
. spec . identityProviders [ 0 ] . transforms . examples [ 8 ] example failed :
expected : groups [ "wrong1" , "wrong2" ]
actual : groups [ "pre:a" , "pre:b" ]
. spec . identityProviders [ 0 ] . transforms . examples [ 9 ] example failed :
expected : username ""
actual : username "pre:ryan"
. spec . identityProviders [ 0 ] . transforms . examples [ 9 ] example failed :
expected : groups [ ]
actual : groups [ "pre:a" , "pre:b" ] ` ,
) , frozenMetav1Now , 123 ) ,
2023-07-14 23:50:43 +00:00
sadReadyCondition ( frozenMetav1Now , 123 ) ,
} ) ,
) ,
} ,
} ,
{
name : "the federation domain has transformation expressions that return illegal values with examples which exercise them" ,
inputObjects : [ ] runtime . Object {
oidcIdentityProvider ,
& configv1alpha1 . FederationDomain {
ObjectMeta : metav1 . ObjectMeta { Name : "config1" , Namespace : namespace , Generation : 123 } ,
Spec : configv1alpha1 . FederationDomainSpec {
Issuer : "https://issuer1.com" ,
IdentityProviders : [ ] configv1alpha1 . FederationDomainIdentityProvider {
{
DisplayName : "name1" ,
ObjectRef : corev1 . TypedLocalObjectReference {
APIGroup : pointer . String ( apiGroupSupervisor ) ,
Kind : "OIDCIdentityProvider" ,
Name : oidcIdentityProvider . Name ,
} ,
Transforms : configv1alpha1 . FederationDomainTransforms {
Expressions : [ ] configv1alpha1 . FederationDomainTransformsExpression {
{ Type : "username/v1" , Expression : ` username == "ryan" ? "" : username ` } , // not allowed to return an empty string as the transformed username
} ,
Examples : [ ] configv1alpha1 . FederationDomainTransformsExample {
{ // every example which encounters an unexpected error should fail because the transformation pipeline returned an error
Username : "ryan" ,
Groups : [ ] string { "a" , "b" } ,
Expects : configv1alpha1 . FederationDomainTransformsExampleExpects { } ,
} ,
{ // every example which encounters an unexpected error should fail because the transformation pipeline returned an error
Username : "ryan" ,
Groups : [ ] string { "a" , "b" } ,
Expects : configv1alpha1 . FederationDomainTransformsExampleExpects { } ,
} ,
{ // this should pass
Username : "other" ,
Groups : [ ] string { "a" , "b" } ,
Expects : configv1alpha1 . FederationDomainTransformsExampleExpects {
Username : "other" ,
Groups : [ ] string { "a" , "b" } ,
Rejected : false ,
} ,
} ,
} ,
} ,
} ,
} ,
} ,
} ,
} ,
wantFDIssuers : [ ] * federationdomainproviders . FederationDomainIssuer { } ,
wantStatusUpdates : [ ] * configv1alpha1 . FederationDomain {
expectedFederationDomainStatusUpdate (
& configv1alpha1 . FederationDomain {
ObjectMeta : metav1 . ObjectMeta { Name : "config1" , Namespace : namespace , Generation : 123 } ,
} ,
configv1alpha1 . FederationDomainPhaseError ,
replaceConditions (
allHappyConditionsSuccess ( "https://issuer1.com" , frozenMetav1Now , 123 ) ,
[ ] configv1alpha1 . Condition {
2023-07-18 22:00:58 +00:00
sadTransformationExamplesCondition ( here . Doc (
` . spec . identityProviders [ 0 ] . transforms . examples [ 0 ] example failed :
expected : no transformation errors
actual : transformations resulted in an unexpected error "identity transformation returned an empty username, which is not allowed"
. spec . identityProviders [ 0 ] . transforms . examples [ 1 ] example failed :
expected : no transformation errors
actual : transformations resulted in an unexpected error "identity transformation returned an empty username, which is not allowed" ` ,
) , frozenMetav1Now , 123 ) ,
sadReadyCondition ( frozenMetav1Now , 123 ) ,
} ) ,
) ,
} ,
} ,
{
name : "the federation domain has lots of errors including errors from multiple IDPs, which are all shown in the status conditions using IDP indices in the messages" ,
inputObjects : [ ] runtime . Object {
oidcIdentityProvider ,
& configv1alpha1 . FederationDomain {
ObjectMeta : metav1 . ObjectMeta { Name : "config1" , Namespace : namespace , Generation : 123 } ,
Spec : configv1alpha1 . FederationDomainSpec {
Issuer : "https://not-unique.com" ,
IdentityProviders : [ ] configv1alpha1 . FederationDomainIdentityProvider {
{
DisplayName : "not unique" ,
ObjectRef : corev1 . TypedLocalObjectReference {
APIGroup : pointer . String ( apiGroupSupervisor ) ,
Kind : "OIDCIdentityProvider" ,
Name : "this will not be found" ,
} ,
Transforms : configv1alpha1 . FederationDomainTransforms {
Constants : [ ] configv1alpha1 . FederationDomainTransformsConstant {
{ Name : "foo" , Type : "string" , StringValue : "bar" } ,
{ Name : "foo" , Type : "string" , StringValue : "baz" } ,
} ,
Expressions : [ ] configv1alpha1 . FederationDomainTransformsExpression {
{ Type : "username/v1" , Expression : ` username + ":suffix" ` } ,
} ,
Examples : [ ] configv1alpha1 . FederationDomainTransformsExample {
{ // this should fail
Username : "ryan" ,
Groups : [ ] string { "a" , "b" } ,
Expects : configv1alpha1 . FederationDomainTransformsExampleExpects {
Username : "this is wrong string" ,
Groups : [ ] string { "this is wrong string list" } ,
} ,
} ,
{ // this should fail
Username : "ryan" ,
Groups : [ ] string { "a" , "b" } ,
Expects : configv1alpha1 . FederationDomainTransformsExampleExpects {
Username : "this is also wrong string" ,
Groups : [ ] string { "this is also wrong string list" } ,
} ,
} ,
} ,
} ,
} ,
{
DisplayName : "not unique" ,
ObjectRef : corev1 . TypedLocalObjectReference {
APIGroup : pointer . String ( apiGroupSupervisor ) ,
Kind : "this is wrong" ,
Name : "foo" ,
} ,
Transforms : configv1alpha1 . FederationDomainTransforms {
Constants : [ ] configv1alpha1 . FederationDomainTransformsConstant {
{ Name : "foo" , Type : "string" , StringValue : "bar" } ,
{ Name : "foo" , Type : "string" , StringValue : "baz" } ,
} ,
Expressions : [ ] configv1alpha1 . FederationDomainTransformsExpression {
{ Type : "username/v1" , Expression : ` username + ":suffix" ` } ,
} ,
Examples : [ ] configv1alpha1 . FederationDomainTransformsExample {
{ // this should pass
Username : "ryan" ,
Groups : [ ] string { "a" , "b" } ,
Expects : configv1alpha1 . FederationDomainTransformsExampleExpects {
Username : "ryan:suffix" ,
Groups : [ ] string { "a" , "b" } ,
} ,
} ,
{ // this should fail
Username : "ryan" ,
Groups : [ ] string { "a" , "b" } ,
Expects : configv1alpha1 . FederationDomainTransformsExampleExpects {
Username : "this is still wrong string" ,
Groups : [ ] string { "this is still wrong string list" } ,
} ,
} ,
} ,
} ,
} ,
{
DisplayName : "name1" ,
ObjectRef : corev1 . TypedLocalObjectReference {
APIGroup : pointer . String ( "this is wrong" ) ,
Kind : "OIDCIdentityProvider" ,
Name : "foo" ,
} ,
Transforms : configv1alpha1 . FederationDomainTransforms {
Expressions : [ ] configv1alpha1 . FederationDomainTransformsExpression {
{ Type : "username/v1" , Expression : ` username ` } ,
{ Type : "username/v1" , Expression : ` this does not compile ` } ,
{ Type : "username/v1" , Expression : ` username ` } ,
{ Type : "username/v1" , Expression : ` this also does not compile ` } ,
} ,
} ,
} ,
} ,
} ,
} ,
& configv1alpha1 . FederationDomain {
ObjectMeta : metav1 . ObjectMeta { Name : "config2" , Namespace : namespace , Generation : 123 } ,
Spec : configv1alpha1 . FederationDomainSpec {
Issuer : "https://not-unique.com" ,
IdentityProviders : [ ] configv1alpha1 . FederationDomainIdentityProvider {
{
DisplayName : "name1" ,
ObjectRef : corev1 . TypedLocalObjectReference {
APIGroup : pointer . String ( apiGroupSupervisor ) ,
Kind : "OIDCIdentityProvider" ,
Name : oidcIdentityProvider . Name ,
} ,
Transforms : configv1alpha1 . FederationDomainTransforms {
Expressions : [ ] configv1alpha1 . FederationDomainTransformsExpression {
{ Type : "username/v1" , Expression : ` username ` } ,
{ Type : "username/v1" , Expression : ` this still does not compile ` } ,
{ Type : "username/v1" , Expression : ` username ` } ,
{ Type : "username/v1" , Expression : ` this really does not compile ` } ,
} ,
} ,
} ,
} ,
} ,
} ,
} ,
wantFDIssuers : [ ] * federationdomainproviders . FederationDomainIssuer { } ,
wantStatusUpdates : [ ] * configv1alpha1 . FederationDomain {
expectedFederationDomainStatusUpdate (
& configv1alpha1 . FederationDomain {
ObjectMeta : metav1 . ObjectMeta { Name : "config1" , Namespace : namespace , Generation : 123 } ,
} ,
configv1alpha1 . FederationDomainPhaseError ,
replaceConditions (
allHappyConditionsSuccess ( "https://not-unique.com" , frozenMetav1Now , 123 ) ,
[ ] configv1alpha1 . Condition {
sadConstNamesUniqueCondition ( here . Doc (
` the names specified by . spec . identityProviders [ 0 ] . transforms . constants [ ] . name contain duplicates : "foo"
the names specified by . spec . identityProviders [ 1 ] . transforms . constants [ ] . name contain duplicates : "foo" ` ,
) , frozenMetav1Now , 123 ) ,
sadAPIGroupSuffixCondition ( ` "this is wrong" ` , frozenMetav1Now , 123 ) ,
sadDisplayNamesUniqueCondition ( ` "not unique" ` , frozenMetav1Now , 123 ) ,
sadIdentityProvidersFoundConditionIdentityProvidersObjectRefsNotFound (
` .spec.identityProviders[0] with displayName "not unique", .spec.identityProviders[1] with displayName "not unique", .spec.identityProviders[2] with displayName "name1" ` ,
frozenMetav1Now , 123 ) ,
sadIssuerIsUniqueCondition ( frozenMetav1Now , 123 ) ,
sadKindCondition ( ` "this is wrong" ` , frozenMetav1Now , 123 ) ,
sadTransformationExpressionsCondition ( here . Doc (
` spec . identityProvider [ 2 ] . transforms . expressions [ 1 ] . expression was invalid :
CEL expression compile error : ERROR : < input > : 1 : 6 : Syntax error : mismatched input ' does ' expecting < EOF >
| this does not compile
| ... . . ^
spec . identityProvider [ 2 ] . transforms . expressions [ 3 ] . expression was invalid :
CEL expression compile error : ERROR : < input > : 1 : 6 : Syntax error : mismatched input ' also ' expecting < EOF >
| this also does not compile
| ... . . ^ ` ,
) , frozenMetav1Now , 123 ) ,
sadTransformationExamplesCondition ( here . Doc (
` . spec . identityProviders [ 0 ] . transforms . examples [ 0 ] example failed :
expected : username "this is wrong string"
actual : username "ryan:suffix"
. spec . identityProviders [ 0 ] . transforms . examples [ 0 ] example failed :
expected : groups [ "this is wrong string list" ]
actual : groups [ "a" , "b" ]
. spec . identityProviders [ 0 ] . transforms . examples [ 1 ] example failed :
expected : username "this is also wrong string"
actual : username "ryan:suffix"
. spec . identityProviders [ 0 ] . transforms . examples [ 1 ] example failed :
expected : groups [ "this is also wrong string list" ]
actual : groups [ "a" , "b" ]
. spec . identityProviders [ 1 ] . transforms . examples [ 1 ] example failed :
expected : username "this is still wrong string"
actual : username "ryan:suffix"
. spec . identityProviders [ 1 ] . transforms . examples [ 1 ] example failed :
expected : groups [ "this is still wrong string list" ]
actual : groups [ "a" , "b" ]
unable to check if the examples specified by . spec . identityProviders [ 2 ] . transforms . examples [ ] had errors because an expression was invalid ` ,
) , frozenMetav1Now , 123 ) ,
sadReadyCondition ( frozenMetav1Now , 123 ) ,
} ) ,
) ,
expectedFederationDomainStatusUpdate (
& configv1alpha1 . FederationDomain {
ObjectMeta : metav1 . ObjectMeta { Name : "config2" , Namespace : namespace , Generation : 123 } ,
} ,
configv1alpha1 . FederationDomainPhaseError ,
replaceConditions (
allHappyConditionsSuccess ( "https://not-unique.com" , frozenMetav1Now , 123 ) ,
[ ] configv1alpha1 . Condition {
sadIssuerIsUniqueCondition ( frozenMetav1Now , 123 ) ,
sadTransformationExpressionsCondition ( here . Doc (
` spec . identityProvider [ 0 ] . transforms . expressions [ 1 ] . expression was invalid :
CEL expression compile error : ERROR : < input > : 1 : 6 : Syntax error : mismatched input ' still ' expecting < EOF >
| this still does not compile
| ... . . ^
spec . identityProvider [ 0 ] . transforms . expressions [ 3 ] . expression was invalid :
CEL expression compile error : ERROR : < input > : 1 : 6 : Syntax error : mismatched input ' really ' expecting < EOF >
| this really does not compile
| ... . . ^ ` ,
) , frozenMetav1Now , 123 ) ,
2023-07-14 23:50:43 +00:00
sadTransformationExamplesCondition (
2023-07-18 22:00:58 +00:00
"unable to check if the examples specified by .spec.identityProviders[0].transforms.examples[] had errors because an expression was invalid" ,
2023-07-14 19:06:20 +00:00
frozenMetav1Now , 123 ) ,
sadReadyCondition ( frozenMetav1Now , 123 ) ,
} ) ,
) ,
} ,
} ,
2023-07-17 23:41:28 +00:00
{
name : "the federation domain has valid IDPs and transformations and examples" ,
inputObjects : [ ] runtime . Object {
oidcIdentityProvider ,
ldapIdentityProvider ,
& configv1alpha1 . FederationDomain {
ObjectMeta : metav1 . ObjectMeta { Name : "config1" , Namespace : namespace , Generation : 123 } ,
Spec : configv1alpha1 . FederationDomainSpec {
Issuer : "https://issuer1.com" ,
IdentityProviders : [ ] configv1alpha1 . FederationDomainIdentityProvider {
{
DisplayName : "name1" ,
ObjectRef : corev1 . TypedLocalObjectReference {
APIGroup : pointer . String ( apiGroupSupervisor ) ,
Kind : "OIDCIdentityProvider" ,
Name : oidcIdentityProvider . Name ,
} ,
Transforms : configv1alpha1 . FederationDomainTransforms {
Expressions : [ ] configv1alpha1 . FederationDomainTransformsExpression {
{ Type : "policy/v1" , Expression : ` username == "ryan" || username == "rejectMeWithDefaultMessage" ` , Message : "only ryan allowed" } ,
{ Type : "policy/v1" , Expression : ` username != "rejectMeWithDefaultMessage" ` } , // no message specified
{ Type : "username/v1" , Expression : ` "pre:" + username ` } ,
{ Type : "groups/v1" , Expression : ` groups.map(g, "pre:" + g) ` } ,
} ,
Constants : [ ] configv1alpha1 . FederationDomainTransformsConstant {
{ Name : "str" , Type : "string" , StringValue : "abc" } ,
{ Name : "strL" , Type : "stringList" , StringListValue : [ ] string { "def" } } ,
} ,
Examples : [ ] configv1alpha1 . FederationDomainTransformsExample {
{
Username : "ryan" ,
Groups : [ ] string { "a" , "b" } ,
Expects : configv1alpha1 . FederationDomainTransformsExampleExpects {
Username : "pre:ryan" ,
Groups : [ ] string { "pre:b" , "pre:a" } ,
Rejected : false ,
} ,
} ,
{
Username : "other" ,
Expects : configv1alpha1 . FederationDomainTransformsExampleExpects {
Rejected : true ,
Message : "only ryan allowed" ,
} ,
} ,
{
Username : "rejectMeWithDefaultMessage" ,
Expects : configv1alpha1 . FederationDomainTransformsExampleExpects {
Rejected : true ,
// Not specifying message is the same as expecting the default message.
} ,
} ,
{
Username : "rejectMeWithDefaultMessage" ,
Expects : configv1alpha1 . FederationDomainTransformsExampleExpects {
Rejected : true ,
2023-07-19 21:56:46 +00:00
Message : "authentication was rejected by a configured policy" , // this is the default message
2023-07-17 23:41:28 +00:00
} ,
} ,
} ,
} ,
} ,
{
DisplayName : "name2" ,
ObjectRef : corev1 . TypedLocalObjectReference {
APIGroup : pointer . String ( apiGroupSupervisor ) ,
Kind : "LDAPIdentityProvider" ,
Name : ldapIdentityProvider . Name ,
} ,
Transforms : configv1alpha1 . FederationDomainTransforms {
Expressions : [ ] configv1alpha1 . FederationDomainTransformsExpression {
{ Type : "username/v1" , Expression : ` "pre:" + username ` } ,
} ,
Examples : [ ] configv1alpha1 . FederationDomainTransformsExample {
{
Username : "ryan" ,
Groups : [ ] string { "a" , "b" } ,
Expects : configv1alpha1 . FederationDomainTransformsExampleExpects {
Username : "pre:ryan" ,
Groups : [ ] string { "b" , "a" } ,
Rejected : false ,
} ,
} ,
} ,
} ,
} ,
} ,
} ,
} ,
} ,
wantFDIssuers : [ ] * federationdomainproviders . FederationDomainIssuer {
federationDomainIssuerWithIDPs ( t , "https://issuer1.com" , [ ] * federationdomainproviders . FederationDomainIdentityProvider {
{
DisplayName : "name1" ,
UID : oidcIdentityProvider . UID ,
Transforms : newTransformationPipeline ( t , & celtransformer . TransformationConstants {
StringConstants : map [ string ] string { "str" : "abc" } ,
StringListConstants : map [ string ] [ ] string { "strL" : { "def" } } ,
} ,
& celtransformer . AllowAuthenticationPolicy {
Expression : ` username == "ryan" || username == "rejectMeWithDefaultMessage" ` ,
RejectedAuthenticationMessage : "only ryan allowed" ,
} ,
& celtransformer . AllowAuthenticationPolicy { Expression : ` username != "rejectMeWithDefaultMessage" ` } ,
& celtransformer . UsernameTransformation { Expression : ` "pre:" + username ` } ,
& celtransformer . GroupsTransformation { Expression : ` groups.map(g, "pre:" + g) ` } ,
) ,
} ,
{
DisplayName : "name2" ,
UID : ldapIdentityProvider . UID ,
Transforms : newTransformationPipeline ( t , & celtransformer . TransformationConstants { } ,
& celtransformer . UsernameTransformation { Expression : ` "pre:" + username ` } ,
) ,
} ,
} ) ,
} ,
wantStatusUpdates : [ ] * configv1alpha1 . FederationDomain {
expectedFederationDomainStatusUpdate (
& configv1alpha1 . FederationDomain {
ObjectMeta : metav1 . ObjectMeta { Name : "config1" , Namespace : namespace , Generation : 123 } ,
} ,
configv1alpha1 . FederationDomainPhaseReady ,
allHappyConditionsSuccess ( "https://issuer1.com" , frozenMetav1Now , 123 ) ,
) ,
} ,
} ,
2023-07-11 22:42:34 +00:00
{
name : "the federation domain specifies illegal const type, which shouldn't really happen since the CRD validates it" ,
inputObjects : [ ] runtime . Object {
oidcIdentityProvider ,
& configv1alpha1 . FederationDomain {
ObjectMeta : metav1 . ObjectMeta { Name : "config1" , Namespace : namespace , Generation : 123 } ,
Spec : configv1alpha1 . FederationDomainSpec {
Issuer : "https://issuer1.com" ,
IdentityProviders : [ ] configv1alpha1 . FederationDomainIdentityProvider {
{
DisplayName : "can-find-me" ,
ObjectRef : corev1 . TypedLocalObjectReference {
APIGroup : pointer . String ( apiGroupSupervisor ) ,
Kind : "OIDCIdentityProvider" ,
Name : oidcIdentityProvider . Name ,
} ,
Transforms : configv1alpha1 . FederationDomainTransforms {
Constants : [ ] configv1alpha1 . FederationDomainTransformsConstant {
{
Type : "this is illegal" ,
} ,
} ,
} ,
} ,
} ,
} ,
} ,
} ,
wantErr : ` one of spec.identityProvider[].transforms.constants[].type is invalid: "this is illegal" ` ,
} ,
{
name : "the federation domain specifies illegal expression type, which shouldn't really happen since the CRD validates it" ,
inputObjects : [ ] runtime . Object {
oidcIdentityProvider ,
& configv1alpha1 . FederationDomain {
ObjectMeta : metav1 . ObjectMeta { Name : "config1" , Namespace : namespace , Generation : 123 } ,
Spec : configv1alpha1 . FederationDomainSpec {
Issuer : "https://issuer1.com" ,
IdentityProviders : [ ] configv1alpha1 . FederationDomainIdentityProvider {
{
DisplayName : "can-find-me" ,
ObjectRef : corev1 . TypedLocalObjectReference {
APIGroup : pointer . String ( apiGroupSupervisor ) ,
Kind : "OIDCIdentityProvider" ,
Name : oidcIdentityProvider . Name ,
} ,
Transforms : configv1alpha1 . FederationDomainTransforms {
Expressions : [ ] configv1alpha1 . FederationDomainTransformsExpression {
{
Type : "this is illegal" ,
} ,
} ,
} ,
} ,
} ,
} ,
} ,
} ,
wantErr : ` one of spec.identityProvider[].transforms.expressions[].type is invalid: "this is illegal" ` ,
} ,
2023-07-06 00:41:27 +00:00
}
2020-10-23 23:25:44 +00:00
2023-07-06 00:41:27 +00:00
for _ , tt := range tests {
tt := tt
t . Run ( tt . name , func ( t * testing . T ) {
t . Parallel ( )
federationDomainsSetter := & fakeFederationDomainsSetter { }
pinnipedAPIClient := pinnipedfake . NewSimpleClientset ( )
pinnipedInformerClient := pinnipedfake . NewSimpleClientset ( )
for _ , o := range tt . inputObjects {
require . NoError ( t , pinnipedAPIClient . Tracker ( ) . Add ( o ) )
require . NoError ( t , pinnipedInformerClient . Tracker ( ) . Add ( o ) )
}
2023-07-11 16:42:20 +00:00
if tt . configClient != nil {
tt . configClient ( pinnipedAPIClient )
2023-07-06 00:41:27 +00:00
}
pinnipedInformers := pinnipedinformers . NewSharedInformerFactory ( pinnipedInformerClient , 0 )
controller := NewFederationDomainWatcherController (
federationDomainsSetter ,
2023-07-12 17:34:15 +00:00
apiGroupSuffix ,
2023-07-06 00:41:27 +00:00
clocktesting . NewFakeClock ( frozenNow ) ,
pinnipedAPIClient ,
pinnipedInformers . Config ( ) . V1alpha1 ( ) . FederationDomains ( ) ,
pinnipedInformers . IDP ( ) . V1alpha1 ( ) . OIDCIdentityProviders ( ) ,
pinnipedInformers . IDP ( ) . V1alpha1 ( ) . LDAPIdentityProviders ( ) ,
pinnipedInformers . IDP ( ) . V1alpha1 ( ) . ActiveDirectoryIdentityProviders ( ) ,
controllerlib . WithInformer ,
)
ctx , cancel := context . WithCancel ( context . Background ( ) )
defer cancel ( )
pinnipedInformers . Start ( ctx . Done ( ) )
controllerlib . TestRunSynchronously ( t , controller )
syncCtx := controllerlib . Context { Context : ctx , Key : controllerlib . Key { Namespace : namespace , Name : "config-name" } }
if err := controllerlib . TestSync ( t , controller , syncCtx ) ; tt . wantErr != "" {
require . EqualError ( t , err , tt . wantErr )
} else {
require . NoError ( t , err )
}
2023-07-11 16:42:20 +00:00
if tt . wantFDIssuers != nil {
2023-07-06 00:41:27 +00:00
require . True ( t , federationDomainsSetter . SetFederationDomainsWasCalled )
2023-07-17 23:41:28 +00:00
// This is ugly, but we cannot test equality on compiled identity transformations because cel.Program
// cannot be compared for equality. This converts them to a type which can be tested for equality,
// which should be good enough for the purposes of this test.
require . ElementsMatch ( t ,
convertToComparableType ( tt . wantFDIssuers ) ,
convertToComparableType ( federationDomainsSetter . FederationDomainsReceived ) )
2023-07-06 00:41:27 +00:00
} else {
require . False ( t , federationDomainsSetter . SetFederationDomainsWasCalled )
}
2023-07-07 21:10:07 +00:00
2023-07-10 22:41:48 +00:00
if tt . wantStatusUpdates != nil {
// This controller should only perform updates to FederationDomain statuses.
// In this controller we don't actually care about the order of the actions, since the FederationDomains
// statuses can be updated in any order. Therefore, we are sorting here so we can use require.Equal
// to make the test output easier to read. Unfortunately the timezone nested in the condition can still
// make the test failure diffs ugly sometimes, but we do want to assert about timestamps so there's not
// much we can do about those.
actualFederationDomainUpdates := getFederationDomainStatusUpdates ( t , pinnipedAPIClient . Actions ( ) )
sortFederationDomainsByName ( actualFederationDomainUpdates )
sortFederationDomainsByName ( tt . wantStatusUpdates )
// Use require.Equal instead of require.ElementsMatch because require.Equal prints a nice diff.
require . Equal ( t , tt . wantStatusUpdates , actualFederationDomainUpdates )
2023-07-07 21:10:07 +00:00
} else {
require . Empty ( t , pinnipedAPIClient . Actions ( ) )
}
2020-10-09 00:40:58 +00:00
} )
2023-07-06 00:41:27 +00:00
}
2020-10-09 00:40:58 +00:00
}
2023-07-07 21:10:07 +00:00
2023-07-17 23:41:28 +00:00
type comparableFederationDomainIssuer struct {
issuer string
identityProviders [ ] * comparableFederationDomainIdentityProvider
defaultIdentityProvider * comparableFederationDomainIdentityProvider
}
type comparableFederationDomainIdentityProvider struct {
DisplayName string
UID types . UID
TransformsSource [ ] interface { }
}
func makeFederationDomainIdentityProviderComparable ( fdi * federationdomainproviders . FederationDomainIdentityProvider ) * comparableFederationDomainIdentityProvider {
if fdi == nil {
return nil
}
return & comparableFederationDomainIdentityProvider {
DisplayName : fdi . DisplayName ,
UID : fdi . UID ,
TransformsSource : fdi . Transforms . Source ( ) ,
}
}
func convertToComparableType ( fdis [ ] * federationdomainproviders . FederationDomainIssuer ) [ ] * comparableFederationDomainIssuer {
result := [ ] * comparableFederationDomainIssuer { }
for _ , fdi := range fdis {
comparableFDIs := make ( [ ] * comparableFederationDomainIdentityProvider , len ( fdi . IdentityProviders ( ) ) )
for _ , idp := range fdi . IdentityProviders ( ) {
comparableFDIs = append ( comparableFDIs , makeFederationDomainIdentityProviderComparable ( idp ) )
}
converted := & comparableFederationDomainIssuer {
issuer : fdi . Issuer ( ) ,
identityProviders : comparableFDIs ,
defaultIdentityProvider : makeFederationDomainIdentityProviderComparable ( fdi . DefaultIdentityProvider ( ) ) ,
}
result = append ( result , converted )
}
return result
}
2023-07-10 22:41:48 +00:00
func expectedFederationDomainStatusUpdate (
fd * configv1alpha1 . FederationDomain ,
phase configv1alpha1 . FederationDomainPhase ,
conditions [ ] configv1alpha1 . Condition ,
) * configv1alpha1 . FederationDomain {
fdCopy := fd . DeepCopy ( )
// We don't care about the spec of a FederationDomain in an update status action,
// so clear it out to make it easier to write expected values.
fdCopy . Spec = configv1alpha1 . FederationDomainSpec { }
2023-07-07 21:10:07 +00:00
2023-07-10 22:41:48 +00:00
fdCopy . Status . Phase = phase
fdCopy . Status . Conditions = conditions
return fdCopy
}
func getFederationDomainStatusUpdates ( t * testing . T , actions [ ] coretesting . Action ) [ ] * configv1alpha1 . FederationDomain {
federationDomains := [ ] * configv1alpha1 . FederationDomain { }
for _ , action := range actions {
updateAction , ok := action . ( coretesting . UpdateAction )
require . True ( t , ok , "failed to cast an action as an coretesting.UpdateAction: %#v" , action )
require . Equal ( t , federationDomainGVR , updateAction . GetResource ( ) , "an update action should have updated a FederationDomain but updated something else" )
require . Equal ( t , "status" , updateAction . GetSubresource ( ) , "an update action should have updated the status subresource but updated something else" )
fd , ok := updateAction . GetObject ( ) . ( * configv1alpha1 . FederationDomain )
require . True ( t , ok , "failed to cast an action's object as a FederationDomain: %#v" , updateAction . GetObject ( ) )
require . Equal ( t , fd . Namespace , updateAction . GetNamespace ( ) , "an update action might have been called on the wrong namespace for a FederationDomain" )
// We don't care about the spec of a FederationDomain in an update status action,
// so clear it out to make it easier to write expected values.
copyOfFD := fd . DeepCopy ( )
copyOfFD . Spec = configv1alpha1 . FederationDomainSpec { }
federationDomains = append ( federationDomains , copyOfFD )
}
return federationDomains
}
2023-07-07 21:10:07 +00:00
2023-07-10 22:41:48 +00:00
func sortFederationDomainsByName ( federationDomains [ ] * configv1alpha1 . FederationDomain ) {
sort . SliceStable ( federationDomains , func ( a , b int ) bool {
return federationDomains [ a ] . GetName ( ) < federationDomains [ b ] . GetName ( )
2023-07-07 21:10:07 +00:00
} )
}
2023-07-17 23:41:28 +00:00
func newTransformationPipeline (
t * testing . T ,
consts * celtransformer . TransformationConstants ,
transformations ... celtransformer . CELTransformation ,
) * idtransform . TransformationPipeline {
pipeline := idtransform . NewTransformationPipeline ( )
compiler , err := celtransformer . NewCELTransformer ( celTransformerMaxExpressionRuntime )
require . NoError ( t , err )
if consts . StringConstants == nil {
consts . StringConstants = map [ string ] string { }
}
if consts . StringListConstants == nil {
consts . StringListConstants = map [ string ] [ ] string { }
}
for _ , transform := range transformations {
compiledTransform , err := compiler . CompileTransformation ( transform , consts )
require . NoError ( t , err )
pipeline . AppendTransformation ( compiledTransform )
}
return pipeline
}
func TestTransformationPipelinesCanBeTestedForEqualityUsingSourceToMakeTestingEasier ( t * testing . T ) {
compiler , err := celtransformer . NewCELTransformer ( 5 * time . Second )
require . NoError ( t , err )
transforms := [ ] celtransformer . CELTransformation {
& celtransformer . AllowAuthenticationPolicy {
Expression : ` username == "ryan" || username == "rejectMeWithDefaultMessage" ` ,
RejectedAuthenticationMessage : "only ryan allowed" ,
} ,
& celtransformer . UsernameTransformation { Expression : ` "pre:" + username ` } ,
& celtransformer . GroupsTransformation { Expression : ` groups.map(g, "pre:" + g) ` } ,
}
differentTransforms := [ ] celtransformer . CELTransformation {
& celtransformer . AllowAuthenticationPolicy {
Expression : ` username == "ryan" || username == "different" ` ,
RejectedAuthenticationMessage : "different" ,
} ,
& celtransformer . UsernameTransformation { Expression : ` "different:" + username ` } ,
& celtransformer . GroupsTransformation { Expression : ` groups.map(g, "different:" + g) ` } ,
}
consts := & celtransformer . TransformationConstants {
StringConstants : map [ string ] string {
"foo" : "bar" ,
"baz" : "bat" ,
} ,
StringListConstants : map [ string ] [ ] string {
"foo" : { "a" , "b" } ,
"bar" : { "c" , "d" } ,
} ,
}
differentConsts := & celtransformer . TransformationConstants {
StringConstants : map [ string ] string {
"foo" : "barDifferent" ,
"baz" : "bat" ,
} ,
StringListConstants : map [ string ] [ ] string {
"foo" : { "aDifferent" , "b" } ,
"bar" : { "c" , "d" } ,
} ,
}
pipeline := idtransform . NewTransformationPipeline ( )
equalPipeline := idtransform . NewTransformationPipeline ( )
differentPipeline1 := idtransform . NewTransformationPipeline ( )
differentPipeline2 := idtransform . NewTransformationPipeline ( )
expectedSourceList := [ ] interface { } { }
for i , transform := range transforms {
// Compile and append to a pipeline.
compiledTransform1 , err := compiler . CompileTransformation ( transform , consts )
require . NoError ( t , err )
pipeline . AppendTransformation ( compiledTransform1 )
// Recompile the same thing and append it to another pipeline.
// This pipeline should end up being equal to the first one.
compiledTransform2 , err := compiler . CompileTransformation ( transform , consts )
require . NoError ( t , err )
equalPipeline . AppendTransformation ( compiledTransform2 )
// Build up a test expectation value.
expectedSourceList = append ( expectedSourceList , & celtransformer . CELTransformationSource { Expr : transform , Consts : consts } )
// Compile a different expression using the same constants and append it to a different pipeline.
// This should not be equal to the other pipelines.
compiledDifferentExpressionSameConsts , err := compiler . CompileTransformation ( differentTransforms [ i ] , consts )
require . NoError ( t , err )
differentPipeline1 . AppendTransformation ( compiledDifferentExpressionSameConsts )
// Compile the same expression using the different constants and append it to a different pipeline.
// This should not be equal to the other pipelines.
compiledSameExpressionDifferentConsts , err := compiler . CompileTransformation ( transform , differentConsts )
require . NoError ( t , err )
differentPipeline2 . AppendTransformation ( compiledSameExpressionDifferentConsts )
}
require . Equal ( t , expectedSourceList , pipeline . Source ( ) )
require . Equal ( t , expectedSourceList , equalPipeline . Source ( ) )
// The source of compiled pipelines can be compared to each other in this way for testing purposes.
require . Equal ( t , pipeline . Source ( ) , equalPipeline . Source ( ) )
require . NotEqual ( t , pipeline . Source ( ) , differentPipeline1 . Source ( ) )
require . NotEqual ( t , pipeline . Source ( ) , differentPipeline2 . Source ( ) )
}