Files
open-cluster-management/pkg/placement/plugins/predicate/predicate_test.go
Qing Hao f4b6dcb159
Some checks failed
Post / images (amd64) (push) Failing after 3m11s
Post / coverage (push) Failing after 8m5s
Post / images (arm64) (push) Failing after 3m27s
Post / image manifest (push) Has been skipped
Post / trigger clusteradm e2e (push) Has been skipped
Close stale issues and PRs / stale (push) Successful in 7s
Scorecard supply-chain security / Scorecard analysis (push) Failing after 1m34s
select clusters with cel selector (#693)
Signed-off-by: Qing Hao <qhao@redhat.com>
2025-04-22 15:00:56 +00:00

249 lines
8.7 KiB
Go

package predicate
import (
"context"
"strings"
"testing"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/apimachinery/pkg/util/sets"
clusterapiv1 "open-cluster-management.io/api/cluster/v1"
clusterapiv1beta1 "open-cluster-management.io/api/cluster/v1beta1"
"open-cluster-management.io/ocm/pkg/placement/controllers/framework"
testinghelpers "open-cluster-management.io/ocm/pkg/placement/helpers/testing"
)
func TestMatchWithClusterPredicates(t *testing.T) {
cases := []struct {
name string
placement *clusterapiv1beta1.Placement
clusters []*clusterapiv1.ManagedCluster
existingAddOnScores []runtime.Object
expectedClusterNames []string
}{
{
name: "match with label",
placement: testinghelpers.NewPlacement("test", "test").AddPredicate(&metav1.LabelSelector{
MatchLabels: map[string]string{
"cloud": "Amazon",
},
}, nil, nil).Build(),
clusters: []*clusterapiv1.ManagedCluster{
testinghelpers.NewManagedCluster("cluster1").WithLabel("cloud", "Amazon").Build(),
testinghelpers.NewManagedCluster("cluster2").WithLabel("cloud", "Google").Build(),
},
expectedClusterNames: []string{"cluster1"},
},
{
name: "match with claim",
placement: testinghelpers.NewPlacement("test", "test").AddPredicate(
nil,
&clusterapiv1beta1.ClusterClaimSelector{
MatchExpressions: []metav1.LabelSelectorRequirement{
{
Key: "cloud",
Operator: metav1.LabelSelectorOpIn,
Values: []string{"Amazon"},
},
},
}, nil).Build(),
clusters: []*clusterapiv1.ManagedCluster{
testinghelpers.NewManagedCluster("cluster1").WithClaim("cloud", "Amazon").Build(),
testinghelpers.NewManagedCluster("cluster2").WithClaim("cloud", "Google").Build(),
},
expectedClusterNames: []string{"cluster1"},
},
{
name: "match with both label and claim",
placement: testinghelpers.NewPlacement("test", "test").AddPredicate(
&metav1.LabelSelector{
MatchLabels: map[string]string{
"cloud": "Amazon",
},
},
&clusterapiv1beta1.ClusterClaimSelector{
MatchExpressions: []metav1.LabelSelectorRequirement{
{
Key: "region",
Operator: metav1.LabelSelectorOpIn,
Values: []string{"us-east-1"},
},
},
}, nil).Build(),
clusters: []*clusterapiv1.ManagedCluster{
testinghelpers.NewManagedCluster("cluster1").
WithLabel("cloud", "Amazon").
WithClaim("region", "us-east-1").Build(),
testinghelpers.NewManagedCluster("cluster2").
WithLabel("cloud", "Amazon").
WithClaim("region", "us-east-2").Build(),
},
expectedClusterNames: []string{"cluster1"},
},
{
name: "match with multiple predicates",
placement: testinghelpers.NewPlacement("test", "test").AddPredicate(&metav1.LabelSelector{
MatchLabels: map[string]string{
"cloud": "Amazon",
},
}, nil, nil).AddPredicate(
nil, &clusterapiv1beta1.ClusterClaimSelector{
MatchExpressions: []metav1.LabelSelectorRequirement{
{
Key: "region",
Operator: metav1.LabelSelectorOpIn,
Values: []string{"us-east-1"},
},
},
}, nil).Build(),
clusters: []*clusterapiv1.ManagedCluster{
testinghelpers.NewManagedCluster("cluster1").WithLabel("cloud", "Amazon").Build(),
testinghelpers.NewManagedCluster("cluster2").WithClaim("region", "us-east-1").Build(),
testinghelpers.NewManagedCluster("cluster3").WithClaim("region", "us-east-2").Build(),
},
expectedClusterNames: []string{"cluster1", "cluster2"},
},
{
name: "match with CEL expression on labels",
placement: testinghelpers.NewPlacement("test", "test").AddPredicate(nil, nil,
&clusterapiv1beta1.ClusterCelSelector{
CelExpressions: []string{
`managedCluster.metadata.labels["region"] == "us-east-1"`,
},
},
).Build(),
clusters: []*clusterapiv1.ManagedCluster{
testinghelpers.NewManagedCluster("cluster1").WithLabel("region", "us-east-1").Build(),
testinghelpers.NewManagedCluster("cluster2").WithLabel("region", "us-west-1").Build(),
},
expectedClusterNames: []string{"cluster1"},
},
{
name: "match with CEL expression on claims",
placement: testinghelpers.NewPlacement("test", "test").AddPredicate(nil, nil,
&clusterapiv1beta1.ClusterCelSelector{
CelExpressions: []string{
`managedCluster.status.clusterClaims.exists(c, c.name == "cloud" && c.value == "Amazon")`,
},
},
).Build(),
clusters: []*clusterapiv1.ManagedCluster{
testinghelpers.NewManagedCluster("cluster1").WithClaim("cloud", "Amazon").Build(),
testinghelpers.NewManagedCluster("cluster2").WithClaim("cloud", "Google").Build(),
},
expectedClusterNames: []string{"cluster1"},
},
{
name: "match with CEL score expression",
placement: testinghelpers.NewPlacement("test", "test").AddPredicate(nil, nil,
&clusterapiv1beta1.ClusterCelSelector{
CelExpressions: []string{
`managedCluster.scores("test-addon").filter(s, s.name == 'test-score').all(e, e.value > 80)`,
},
},
).Build(),
clusters: []*clusterapiv1.ManagedCluster{
testinghelpers.NewManagedCluster("cluster1").Build(),
testinghelpers.NewManagedCluster("cluster2").Build(),
},
existingAddOnScores: []runtime.Object{
testinghelpers.NewAddOnPlacementScore("cluster1", "test-addon").WithScore("test-score", 90).Build(),
testinghelpers.NewAddOnPlacementScore("cluster2", "test-addon").WithScore("test-score", 70).Build(),
},
expectedClusterNames: []string{"cluster1"},
},
{
name: "match with multiple CEL expressions",
placement: testinghelpers.NewPlacement("test", "test").AddPredicate(nil, nil,
&clusterapiv1beta1.ClusterCelSelector{
CelExpressions: []string{
`managedCluster.metadata.labels["env"] == "prod"`,
`managedCluster.scores("test-addon").filter(s, s.name == 'test-score').all(e, e.value > 80)`,
},
},
).Build(),
clusters: []*clusterapiv1.ManagedCluster{
testinghelpers.NewManagedCluster("cluster1").WithLabel("env", "prod").Build(),
testinghelpers.NewManagedCluster("cluster2").WithLabel("env", "prod").Build(),
},
existingAddOnScores: []runtime.Object{
testinghelpers.NewAddOnPlacementScore("cluster1", "test-addon").WithScore("test-score", 90).Build(),
testinghelpers.NewAddOnPlacementScore("cluster2", "test-addon").WithScore("test-score", 70).Build(),
},
expectedClusterNames: []string{"cluster1"},
},
{
name: "match with CEL expression and other selectors",
placement: testinghelpers.NewPlacement("test", "test").AddPredicate(
&metav1.LabelSelector{
MatchLabels: map[string]string{
"env": "prod",
},
}, nil,
&clusterapiv1beta1.ClusterCelSelector{
CelExpressions: []string{
`managedCluster.status.clusterClaims.exists(c, c.name == "cloud" && c.value == "Amazon")`,
},
},
).Build(),
clusters: []*clusterapiv1.ManagedCluster{
testinghelpers.NewManagedCluster("cluster1").WithLabel("env", "prod").WithClaim("cloud", "Amazon").Build(),
testinghelpers.NewManagedCluster("cluster2").WithLabel("env", "prod").WithClaim("cloud", "Azure").Build(),
},
expectedClusterNames: []string{"cluster1"},
},
{
name: "invalid CEL expression",
placement: testinghelpers.NewPlacement("test", "test").AddPredicate(nil, nil,
&clusterapiv1beta1.ClusterCelSelector{
CelExpressions: []string{
`invalid.expression`,
},
},
).Build(),
clusters: []*clusterapiv1.ManagedCluster{
testinghelpers.NewManagedCluster("cluster1").Build(),
},
expectedClusterNames: []string{},
},
{
name: "empty CEL expressions",
placement: testinghelpers.NewPlacement("test", "test").AddPredicate(nil, nil,
&clusterapiv1beta1.ClusterCelSelector{
CelExpressions: []string{},
},
).Build(),
clusters: []*clusterapiv1.ManagedCluster{
testinghelpers.NewManagedCluster("cluster1").Build(),
},
expectedClusterNames: []string{"cluster1"},
},
}
for _, c := range cases {
t.Run(c.name, func(t *testing.T) {
p := &Predicate{handle: testinghelpers.NewFakePluginHandle(t, nil, c.existingAddOnScores...)}
result, status := p.Filter(context.TODO(), c.placement, c.clusters)
clusters := result.Filtered
err := status.AsError()
if err != nil && status.Code() != framework.Misconfigured {
t.Errorf("unexpected err: %v", err)
}
expectedClusterNames := sets.NewString(c.expectedClusterNames...)
if len(clusters) != expectedClusterNames.Len() {
t.Errorf("expected %d clusters but got %d", expectedClusterNames.Len(), len(clusters))
}
for _, cluster := range clusters {
expectedClusterNames.Delete(cluster.Name)
}
if expectedClusterNames.Len() > 0 {
t.Errorf("expected clusters not selected: %s", strings.Join(expectedClusterNames.List(), ","))
}
})
}
}