Files
open-cluster-management/pkg/registration/hub/managedclusterset/controller_test.go
Jian Qiu e810520961 🌱 Refactor code to fix lint warning (#218)
* Refactor code to fix lint warning

Signed-off-by: Jian Qiu <jqiu@redhat.com>

* enable lint for testing files

Signed-off-by: Jian Qiu <jqiu@redhat.com>

---------

Signed-off-by: Jian Qiu <jqiu@redhat.com>
2023-07-25 07:12:34 +02:00

448 lines
14 KiB
Go

package managedclusterset
import (
"context"
"reflect"
"testing"
"time"
"github.com/openshift/library-go/pkg/operator/events/eventstesting"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/apimachinery/pkg/util/sets"
clusterfake "open-cluster-management.io/api/client/cluster/clientset/versioned/fake"
clusterinformers "open-cluster-management.io/api/client/cluster/informers/externalversions"
clusterv1 "open-cluster-management.io/api/cluster/v1"
clusterv1beta2 "open-cluster-management.io/api/cluster/v1beta2"
"open-cluster-management.io/ocm/pkg/common/patcher"
testingcommon "open-cluster-management.io/ocm/pkg/common/testing"
)
func TestSyncClusterSet(t *testing.T) {
cases := []struct {
name string
existingClusterSet *clusterv1beta2.ManagedClusterSet
existingClusters []*clusterv1.ManagedCluster
expectCondition metav1.Condition
expectErr bool
}{
{
name: "sync a empty cluster set",
existingClusterSet: &clusterv1beta2.ManagedClusterSet{
ObjectMeta: metav1.ObjectMeta{
Name: "mcs1",
},
},
existingClusters: []*clusterv1.ManagedCluster{
newManagedCluster("cluster1", map[string]string{
clusterv1beta2.ClusterSetLabel: "mcs1",
}),
},
expectCondition: metav1.Condition{
Type: clusterv1beta2.ManagedClusterSetConditionEmpty,
Status: metav1.ConditionFalse,
Reason: ReasonClusterSelected,
Message: "1 ManagedClusters selected",
},
},
{
name: "sync a legacy clusterset",
existingClusterSet: &clusterv1beta2.ManagedClusterSet{
ObjectMeta: metav1.ObjectMeta{
Name: "mcs1",
},
Spec: clusterv1beta2.ManagedClusterSetSpec{
ClusterSelector: clusterv1beta2.ManagedClusterSelector{
SelectorType: clusterv1beta2.ExclusiveClusterSetLabel,
},
},
},
existingClusters: []*clusterv1.ManagedCluster{
newManagedCluster("cluster1", map[string]string{
clusterv1beta2.ClusterSetLabel: "mcs1",
}),
},
expectCondition: metav1.Condition{
Type: clusterv1beta2.ManagedClusterSetConditionEmpty,
Status: metav1.ConditionFalse,
Reason: ReasonClusterSelected,
Message: "1 ManagedClusters selected",
},
},
{
name: "sync a legacy clusterset, and no cluster matched",
existingClusterSet: &clusterv1beta2.ManagedClusterSet{
ObjectMeta: metav1.ObjectMeta{
Name: "mcs1",
},
Spec: clusterv1beta2.ManagedClusterSetSpec{
ClusterSelector: clusterv1beta2.ManagedClusterSelector{
SelectorType: clusterv1beta2.ExclusiveClusterSetLabel,
},
},
},
existingClusters: []*clusterv1.ManagedCluster{
newManagedCluster("cluster1", map[string]string{
"vendor": "openShift",
}),
},
expectCondition: metav1.Condition{
Type: clusterv1beta2.ManagedClusterSetConditionEmpty,
Status: metav1.ConditionTrue,
Reason: ReasonNoClusterMatchced,
Message: "No ManagedCluster selected",
},
},
{
name: "sync a labelselector clusterset",
existingClusterSet: &clusterv1beta2.ManagedClusterSet{
ObjectMeta: metav1.ObjectMeta{
Name: "mcs1",
},
Spec: clusterv1beta2.ManagedClusterSetSpec{
ClusterSelector: clusterv1beta2.ManagedClusterSelector{
SelectorType: clusterv1beta2.LabelSelector,
LabelSelector: &metav1.LabelSelector{
MatchLabels: map[string]string{
"vendor": "openShift",
},
},
},
},
},
existingClusters: []*clusterv1.ManagedCluster{
newManagedCluster("cluster1", map[string]string{
clusterv1beta2.ClusterSetLabel: "mcs1",
"vendor": "openShift",
}),
newManagedCluster("cluster2", map[string]string{
clusterv1beta2.ClusterSetLabel: "mcs2",
"vendor": "openShift",
}),
},
expectCondition: metav1.Condition{
Type: clusterv1beta2.ManagedClusterSetConditionEmpty,
Status: metav1.ConditionFalse,
Reason: ReasonClusterSelected,
Message: "2 ManagedClusters selected",
},
},
{
name: "sync a global clusterset",
existingClusterSet: &clusterv1beta2.ManagedClusterSet{
ObjectMeta: metav1.ObjectMeta{
Name: "mcs1",
},
Spec: clusterv1beta2.ManagedClusterSetSpec{
ClusterSelector: clusterv1beta2.ManagedClusterSelector{
SelectorType: clusterv1beta2.LabelSelector,
LabelSelector: &metav1.LabelSelector{},
},
},
},
existingClusters: []*clusterv1.ManagedCluster{
newManagedCluster("cluster1", map[string]string{
clusterv1beta2.ClusterSetLabel: "mcs1",
"vendor": "openShift",
}),
newManagedCluster("cluster2", map[string]string{
clusterv1beta2.ClusterSetLabel: "mcs2",
"vendor": "openShift",
}),
},
expectCondition: metav1.Condition{
Type: clusterv1beta2.ManagedClusterSetConditionEmpty,
Status: metav1.ConditionFalse,
Reason: ReasonClusterSelected,
Message: "2 ManagedClusters selected",
},
},
{
name: "sync a label clusterset with no labelselector specified(no cluster matched)",
existingClusterSet: &clusterv1beta2.ManagedClusterSet{
ObjectMeta: metav1.ObjectMeta{
Name: "mcs1",
},
Spec: clusterv1beta2.ManagedClusterSetSpec{
ClusterSelector: clusterv1beta2.ManagedClusterSelector{
SelectorType: clusterv1beta2.LabelSelector,
},
},
},
existingClusters: []*clusterv1.ManagedCluster{
newManagedCluster("cluster1", map[string]string{
clusterv1beta2.ClusterSetLabel: "mcs1",
"vendor": "openShift",
}),
newManagedCluster("cluster2", map[string]string{
clusterv1beta2.ClusterSetLabel: "mcs2",
"vendor": "openShift",
}),
},
expectCondition: metav1.Condition{
Type: clusterv1beta2.ManagedClusterSetConditionEmpty,
Status: metav1.ConditionTrue,
Reason: ReasonNoClusterMatchced,
Message: "No ManagedCluster selected",
},
},
{
name: "ignore any other clusterset",
existingClusterSet: &clusterv1beta2.ManagedClusterSet{
ObjectMeta: metav1.ObjectMeta{
Name: "mcs1",
},
Spec: clusterv1beta2.ManagedClusterSetSpec{
ClusterSelector: clusterv1beta2.ManagedClusterSelector{
SelectorType: "SingleClusterLabel",
},
},
},
expectErr: true,
},
}
for _, c := range cases {
t.Run(c.name, func(t *testing.T) {
var objects []runtime.Object
for _, cluster := range c.existingClusters {
objects = append(objects, cluster)
}
if c.existingClusterSet != nil {
objects = append(objects, c.existingClusterSet)
}
clusterClient := clusterfake.NewSimpleClientset(objects...)
informerFactory := clusterinformers.NewSharedInformerFactory(clusterClient, 5*time.Minute)
for _, cluster := range c.existingClusters {
err := informerFactory.Cluster().V1().ManagedClusters().Informer().GetStore().Add(cluster)
if err != nil {
t.Errorf("Failed to add cluster: %v, error: %v", cluster.Name, err)
}
}
if c.existingClusterSet != nil {
err := informerFactory.Cluster().V1beta2().ManagedClusterSets().Informer().GetStore().Add(c.existingClusterSet)
if err != nil {
t.Errorf("Failed to add clusterset: %v, error: %v", c.existingClusterSet.Name, err)
}
}
ctrl := managedClusterSetController{
patcher: patcher.NewPatcher[
*clusterv1beta2.ManagedClusterSet, clusterv1beta2.ManagedClusterSetSpec, clusterv1beta2.ManagedClusterSetStatus](
clusterClient.ClusterV1beta2().ManagedClusterSets()),
clusterLister: informerFactory.Cluster().V1().ManagedClusters().Lister(),
clusterSetLister: informerFactory.Cluster().V1beta2().ManagedClusterSets().Lister(),
eventRecorder: eventstesting.NewTestingEventRecorder(t),
}
syncErr := ctrl.syncClusterSet(context.Background(), c.existingClusterSet)
if c.expectErr {
if syncErr != nil {
return
}
t.Errorf("Should syncClusterSet fail")
return
}
if syncErr != nil {
t.Errorf("unexpected err: %v", syncErr)
}
updatedSet, err := clusterClient.ClusterV1beta2().ManagedClusterSets().Get(context.Background(), c.existingClusterSet.Name, metav1.GetOptions{})
if err != nil {
t.Errorf("Failed to get clusterset: %v, error: %v", c.existingClusterSet.Name, err)
}
if !hasCondition(updatedSet.Status.Conditions, c.expectCondition) {
t.Errorf("expected condition:%v. is not found: %v", c.expectCondition, updatedSet.Status.Conditions)
}
})
}
}
func TestGetDiffClustersets(t *testing.T) {
cases := []struct {
name string
oldSets []*clusterv1beta2.ManagedClusterSet
newSets []*clusterv1beta2.ManagedClusterSet
expectDiffSet sets.Set[string]
}{
{
name: "update a set",
oldSets: []*clusterv1beta2.ManagedClusterSet{
newManagedClusterSet("s1"), newManagedClusterSet("s2"),
},
newSets: []*clusterv1beta2.ManagedClusterSet{
newManagedClusterSet("s1"), newManagedClusterSet("s3"),
},
expectDiffSet: sets.New[string]("s2", "s3"),
},
{
name: "add a set",
oldSets: []*clusterv1beta2.ManagedClusterSet{
newManagedClusterSet("s1"),
},
newSets: []*clusterv1beta2.ManagedClusterSet{
newManagedClusterSet("s1"), newManagedClusterSet("s2"),
},
expectDiffSet: sets.New[string]("s2"),
},
{
name: "delete a set",
oldSets: []*clusterv1beta2.ManagedClusterSet{
newManagedClusterSet("s1"), newManagedClusterSet("s2"),
},
newSets: []*clusterv1beta2.ManagedClusterSet{
newManagedClusterSet("s1"),
},
expectDiffSet: sets.New[string]("s2"),
},
{
name: "old set is nil",
oldSets: []*clusterv1beta2.ManagedClusterSet{},
newSets: []*clusterv1beta2.ManagedClusterSet{
newManagedClusterSet("s1"),
},
expectDiffSet: sets.New[string]("s1"),
},
{
name: "new set is nil",
oldSets: []*clusterv1beta2.ManagedClusterSet{
newManagedClusterSet("s1"),
},
newSets: []*clusterv1beta2.ManagedClusterSet{},
expectDiffSet: sets.New[string]("s1"),
},
}
for _, c := range cases {
t.Run(c.name, func(t *testing.T) {
retSets := getDiffClusterSetsNames(c.oldSets, c.newSets)
if !reflect.DeepEqual(retSets, c.expectDiffSet) {
t.Errorf("Case: %v, Failed to getDiffClustersets. returnSets: %v, expectSets: %v", c.name, retSets, c.expectDiffSet)
}
})
}
}
func TestEnqueueUpdateClusterClusterSet(t *testing.T) {
cases := []struct {
name string
existingClusterSets []*clusterv1beta2.ManagedClusterSet
oldCluster *clusterv1.ManagedCluster
newCluster *clusterv1.ManagedCluster
expectQueueLen int
}{
{
name: "update a cluster's clusterset",
existingClusterSets: []*clusterv1beta2.ManagedClusterSet{
newManagedClusterSet("mcs1"),
newManagedClusterSet("mcs2"),
},
oldCluster: newClusterWithLabel("c1", map[string]string{clusterv1beta2.ClusterSetLabel: "mcs1"}),
newCluster: newClusterWithLabel("c1", map[string]string{clusterv1beta2.ClusterSetLabel: "mcs2"}),
expectQueueLen: 2,
},
{
name: "add a cluster's clusterset",
existingClusterSets: []*clusterv1beta2.ManagedClusterSet{
newManagedClusterSet("mcs1"),
newManagedClusterSet("mcs2"),
},
oldCluster: newClusterWithLabel("c1", nil),
newCluster: newClusterWithLabel("c1", map[string]string{clusterv1beta2.ClusterSetLabel: "mcs2"}),
expectQueueLen: 1,
},
{
name: "remove a cluster's clusterset",
existingClusterSets: []*clusterv1beta2.ManagedClusterSet{
newManagedClusterSet("mcs1"),
newManagedClusterSet("mcs2"),
},
newCluster: newClusterWithLabel("c1", nil),
oldCluster: newClusterWithLabel("c1", map[string]string{clusterv1beta2.ClusterSetLabel: "mcs2"}),
expectQueueLen: 1,
},
}
for _, c := range cases {
t.Run(c.name, func(t *testing.T) {
var objects []runtime.Object
for _, clusterset := range c.existingClusterSets {
objects = append(objects, clusterset)
}
clusterClient := clusterfake.NewSimpleClientset(objects...)
informerFactory := clusterinformers.NewSharedInformerFactory(clusterClient, 5*time.Minute)
for _, clusterset := range c.existingClusterSets {
err := informerFactory.Cluster().V1beta2().ManagedClusterSets().Informer().GetStore().Add(clusterset)
if err != nil {
t.Errorf("Failed to add clusterset: %v, error: %v", clusterset, err)
}
}
syncCtx := testingcommon.NewFakeSyncContext(t, "fake")
ctrl := managedClusterSetController{
clusterSetLister: informerFactory.Cluster().V1beta2().ManagedClusterSets().Lister(),
eventRecorder: eventstesting.NewTestingEventRecorder(t),
queue: syncCtx.Queue(),
}
ctrl.enqueueUpdateClusterClusterSet(c.oldCluster, c.newCluster)
if syncCtx.Queue().Len() != c.expectQueueLen {
t.Errorf("Expect len:%v, return len:%v", c.expectQueueLen, syncCtx.Queue().Len())
}
})
}
}
func newManagedCluster(name string, labels map[string]string) *clusterv1.ManagedCluster {
cluster := &clusterv1.ManagedCluster{
ObjectMeta: metav1.ObjectMeta{
Name: name,
},
}
cluster.Labels = labels
return cluster
}
func newManagedClusterSet(name string) *clusterv1beta2.ManagedClusterSet {
clusterSet := &clusterv1beta2.ManagedClusterSet{
ObjectMeta: metav1.ObjectMeta{
Name: name,
},
}
return clusterSet
}
func hasCondition(conditions []metav1.Condition, expectCondition metav1.Condition) bool {
for _, condition := range conditions {
if condition.Type != expectCondition.Type {
continue
}
if condition.Status != expectCondition.Status {
continue
}
if condition.Reason != expectCondition.Reason {
continue
}
if condition.Message != expectCondition.Message {
continue
}
return true
}
return false
}
func newClusterWithLabel(name string, labels map[string]string) *clusterv1.ManagedCluster {
cluster := &clusterv1.ManagedCluster{
ObjectMeta: metav1.ObjectMeta{
Name: name,
Labels: labels,
},
}
return cluster
}