Files
open-cluster-management/pkg/addon/controllers/addonconfiguration/controller_test.go
Jian Qiu df5b456f88
Some checks failed
Scorecard supply-chain security / Scorecard analysis (push) Failing after 35s
Post / coverage (push) Failing after 28s
Post / images (amd64, addon-manager) (push) Failing after 29s
Post / images (amd64, placement) (push) Failing after 27s
Post / images (amd64, registration) (push) Failing after 31s
Post / images (amd64, registration-operator) (push) Failing after 28s
Post / images (amd64, work) (push) Failing after 31s
Post / images (arm64, addon-manager) (push) Failing after 32s
Post / images (arm64, placement) (push) Failing after 32s
Post / images (arm64, registration) (push) Failing after 32s
Post / images (arm64, registration-operator) (push) Failing after 34s
Post / images (arm64, work) (push) Failing after 31s
Post / image manifest (addon-manager) (push) Has been skipped
Post / image manifest (placement) (push) Has been skipped
Post / image manifest (registration) (push) Has been skipped
Post / image manifest (registration-operator) (push) Has been skipped
Post / image manifest (work) (push) Has been skipped
Post / trigger clusteradm e2e (push) Has been skipped
Close stale issues and PRs / stale (push) Failing after 43s
Add more unit test to improve coverage (#1183)
Signed-off-by: Jian Qiu <jqiu@redhat.com>
2025-09-12 08:30:33 +00:00

259 lines
8.5 KiB
Go

package addonconfiguration
import (
"context"
"testing"
"time"
"github.com/openshift/library-go/pkg/controller/factory"
"github.com/openshift/library-go/pkg/operator/events/eventstesting"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/client-go/tools/cache"
"k8s.io/klog/v2/ktesting"
"open-cluster-management.io/addon-framework/pkg/addonmanager/addontesting"
addonv1alpha1 "open-cluster-management.io/api/addon/v1alpha1"
fakeaddon "open-cluster-management.io/api/client/addon/clientset/versioned/fake"
addoninformers "open-cluster-management.io/api/client/addon/informers/externalversions"
fakecluster "open-cluster-management.io/api/client/cluster/clientset/versioned/fake"
clusterv1informers "open-cluster-management.io/api/client/cluster/informers/externalversions"
clusterv1alpha1 "open-cluster-management.io/api/cluster/v1alpha1"
clusterv1beta1 "open-cluster-management.io/api/cluster/v1beta1"
addonindex "open-cluster-management.io/ocm/pkg/addon/index"
"open-cluster-management.io/ocm/pkg/common/helpers"
testingcommon "open-cluster-management.io/ocm/pkg/common/testing"
)
func TestNewAddonConfigurationController(t *testing.T) {
fakeAddonClient := fakeaddon.NewSimpleClientset()
fakeClusterClient := fakecluster.NewSimpleClientset()
addonInformers := addoninformers.NewSharedInformerFactory(fakeAddonClient, 10*time.Minute)
clusterInformers := clusterv1informers.NewSharedInformerFactory(fakeClusterClient, 10*time.Minute)
// Add required indexer
err := addonInformers.Addon().V1alpha1().ManagedClusterAddOns().Informer().AddIndexers(
cache.Indexers{
addonindex.ManagedClusterAddonByName: addonindex.IndexManagedClusterAddonByName,
})
if err != nil {
t.Fatal(err)
}
addonFilterFunc := func(obj interface{}) bool {
return true
}
recorder := eventstesting.NewTestingEventRecorder(t)
controller := NewAddonConfigurationController(
fakeAddonClient,
addonInformers.Addon().V1alpha1().ManagedClusterAddOns(),
addonInformers.Addon().V1alpha1().ClusterManagementAddOns(),
clusterInformers.Cluster().V1beta1().Placements(),
clusterInformers.Cluster().V1beta1().PlacementDecisions(),
addonFilterFunc,
recorder,
)
if controller == nil {
t.Error("Expected controller to be created, got nil")
}
// Verify controller is of correct type
if _, ok := controller.(factory.Controller); !ok {
t.Error("Expected controller to implement factory.Controller interface")
}
}
func TestAddonConfigurationControllerSync(t *testing.T) {
cases := []struct {
name string
queueKey string
managedClusterAddons []runtime.Object
clusterManagementAddons []runtime.Object
placements []runtime.Object
placementDecisions []runtime.Object
expectError bool
expectedErrorMessage string
addonFilterFuncResult bool
}{
{
name: "addon not found",
queueKey: "non-existent-addon",
managedClusterAddons: []runtime.Object{
addontesting.NewAddon("test-addon", "cluster1"),
},
clusterManagementAddons: []runtime.Object{},
expectError: false,
},
{
name: "addon filtered out",
queueKey: "test-addon",
managedClusterAddons: []runtime.Object{
addontesting.NewAddon("test-addon", "cluster1"),
},
clusterManagementAddons: []runtime.Object{
addontesting.NewClusterManagementAddon("test-addon", "", "").Build(),
},
addonFilterFuncResult: false,
expectError: false,
},
{
name: "basic addon sync",
queueKey: "test-addon",
managedClusterAddons: []runtime.Object{
addontesting.NewAddon("test-addon", "cluster1"),
},
clusterManagementAddons: []runtime.Object{
addontesting.NewClusterManagementAddon("test-addon", "", "").Build(),
},
placements: []runtime.Object{},
placementDecisions: []runtime.Object{},
addonFilterFuncResult: true,
expectError: false,
},
{
name: "addon with placement strategy",
queueKey: "test-addon",
managedClusterAddons: []runtime.Object{
addontesting.NewAddon("test-addon", "cluster1"),
addontesting.NewAddon("test-addon", "cluster2"),
},
clusterManagementAddons: []runtime.Object{
addontesting.NewClusterManagementAddon("test-addon", "", "").
WithPlacementStrategy(addonv1alpha1.PlacementStrategy{
PlacementRef: addonv1alpha1.PlacementRef{
Name: "test-placement",
Namespace: "default",
},
RolloutStrategy: clusterv1alpha1.RolloutStrategy{
Type: clusterv1alpha1.All,
},
}).
WithInstallProgression(addonv1alpha1.InstallProgression{
PlacementRef: addonv1alpha1.PlacementRef{
Name: "test-placement",
Namespace: "default",
},
}).Build(),
},
placements: []runtime.Object{
&clusterv1beta1.Placement{
ObjectMeta: metav1.ObjectMeta{
Name: "test-placement",
Namespace: "default",
},
},
},
placementDecisions: []runtime.Object{
&clusterv1beta1.PlacementDecision{
ObjectMeta: metav1.ObjectMeta{
Name: "test-placement",
Namespace: "default",
Labels: map[string]string{
clusterv1beta1.PlacementLabel: "test-placement",
clusterv1beta1.DecisionGroupIndexLabel: "0",
},
},
Status: clusterv1beta1.PlacementDecisionStatus{
Decisions: []clusterv1beta1.ClusterDecision{
{ClusterName: "cluster1"},
{ClusterName: "cluster2"},
},
},
},
},
addonFilterFuncResult: true,
expectError: false,
},
}
for _, c := range cases {
t.Run(c.name, func(t *testing.T) {
_, _ = ktesting.NewTestContext(t)
fakeAddonClient := fakeaddon.NewSimpleClientset(append(c.managedClusterAddons, c.clusterManagementAddons...)...)
clusterObjs := append(c.placements, c.placementDecisions...)
fakeClusterClient := fakecluster.NewSimpleClientset(clusterObjs...)
addonInformers := addoninformers.NewSharedInformerFactory(fakeAddonClient, 10*time.Minute)
clusterInformers := clusterv1informers.NewSharedInformerFactory(fakeClusterClient, 10*time.Minute)
// Add required indexer
err := addonInformers.Addon().V1alpha1().ManagedClusterAddOns().Informer().AddIndexers(
cache.Indexers{
addonindex.ManagedClusterAddonByName: addonindex.IndexManagedClusterAddonByName,
})
if err != nil {
t.Fatal(err)
}
// Populate informer stores
for _, obj := range c.managedClusterAddons {
if err := addonInformers.Addon().V1alpha1().ManagedClusterAddOns().Informer().GetStore().Add(obj); err != nil {
t.Fatal(err)
}
}
for _, obj := range c.clusterManagementAddons {
if err := addonInformers.Addon().V1alpha1().ClusterManagementAddOns().Informer().GetStore().Add(obj); err != nil {
t.Fatal(err)
}
}
for _, obj := range c.placements {
if err := clusterInformers.Cluster().V1beta1().Placements().Informer().GetStore().Add(obj); err != nil {
t.Fatal(err)
}
}
for _, obj := range c.placementDecisions {
if err := clusterInformers.Cluster().V1beta1().PlacementDecisions().Informer().GetStore().Add(obj); err != nil {
t.Fatal(err)
}
}
// Create controller with addon filter function
addonFilterFunc := func(obj interface{}) bool {
return c.addonFilterFuncResult
}
controller := &addonConfigurationController{
addonClient: fakeAddonClient,
clusterManagementAddonLister: addonInformers.Addon().V1alpha1().ClusterManagementAddOns().Lister(),
managedClusterAddonIndexer: addonInformers.Addon().V1alpha1().ManagedClusterAddOns().Informer().GetIndexer(),
placementLister: clusterInformers.Cluster().V1beta1().Placements().Lister(),
placementDecisionGetter: helpers.PlacementDecisionGetter{
Client: clusterInformers.Cluster().V1beta1().PlacementDecisions().Lister(),
},
addonFilterFunc: addonFilterFunc,
reconcilers: []addonConfigurationReconcile{
&managedClusterAddonConfigurationReconciler{
addonClient: fakeAddonClient,
},
},
}
// Create sync context
syncCtx := testingcommon.NewFakeSyncContext(t, c.queueKey)
// Test sync method
ctx := context.TODO()
err = controller.sync(ctx, syncCtx)
if c.expectError && err == nil {
t.Errorf("Expected error but got none")
}
if !c.expectError && err != nil {
t.Errorf("Expected no error but got: %v", err)
}
if c.expectedErrorMessage != "" && (err == nil || err.Error() != c.expectedErrorMessage) {
t.Errorf("Expected error message '%s', got '%v'", c.expectedErrorMessage, err)
}
})
}
}