This is an automated email from the ASF dual-hosted git repository.

squakez pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/camel-k.git

commit 514e775aa83a85611830dd11ed31215f4cb263e4
Author: chaojixinren <[email protected]>
AuthorDate: Thu Apr 16 10:13:26 2026 +0800

    chore(controller): move action declarations from reconcile to init
    
    Closes #6567
    
    Made-with: Cursor
---
 pkg/controller/catalog/catalog_controller.go       |  27 ++-
 pkg/controller/catalog/catalog_controller_test.go  |  44 +++++
 .../integration/integration_controller.go          |  56 ++++--
 .../integration/integration_controller_test.go     | 202 ++++-----------------
 .../integrationkit/integrationkit_controller.go    |  31 +++-
 .../integrationkit_controller_test.go              |  50 +++++
 .../integrationplatform_controller.go              |  29 ++-
 .../integrationplatform_controller_test.go         |  47 +++++
 pkg/controller/pipe/pipe_controller.go             |  27 ++-
 pkg/controller/pipe/pipe_controller_test.go        |  44 +++++
 10 files changed, 342 insertions(+), 215 deletions(-)

diff --git a/pkg/controller/catalog/catalog_controller.go 
b/pkg/controller/catalog/catalog_controller.go
index 58aa4eacb..1294c82ed 100644
--- a/pkg/controller/catalog/catalog_controller.go
+++ b/pkg/controller/catalog/catalog_controller.go
@@ -45,6 +45,8 @@ const (
        requeueAfterDuration = 5 * time.Second
 )
 
+type actionFactory func() Action
+
 // Add creates a new Catalog Controller and adds it to the Manager. The 
Manager will set fields on the Controller
 // and Start it when the Manager is Started.
 func Add(ctx context.Context, mgr manager.Manager, c client.Client) error {
@@ -57,6 +59,10 @@ func newReconciler(mgr manager.Manager, c client.Client) 
reconcile.Reconciler {
                        client:   c,
                        scheme:   mgr.GetScheme(),
                        recorder: 
mgr.GetEventRecorder("camel-k-catalog-controller"),
+                       actionFactories: []actionFactory{
+                               NewInitializeAction,
+                               NewMonitorAction,
+                       },
                },
                schema.GroupVersionKind{
                        Group:   v1.SchemeGroupVersion.Group,
@@ -104,9 +110,19 @@ var _ reconcile.Reconciler = &reconcileCatalog{}
 type reconcileCatalog struct {
        // This client, initialized using mgr.Client() above, is a split client
        // that reads objects from the cache and writes to the API server
-       client   client.Client
-       scheme   *runtime.Scheme
-       recorder events.EventRecorder
+       client          client.Client
+       scheme          *runtime.Scheme
+       recorder        events.EventRecorder
+       actionFactories []actionFactory
+}
+
+func (r *reconcileCatalog) newActions() []Action {
+       actions := make([]Action, 0, len(r.actionFactories))
+       for _, newAction := range r.actionFactories {
+               actions = append(actions, newAction())
+       }
+
+       return actions
 }
 
 // Reconcile reads that state of the cluster for a catalog object and makes 
changes based
@@ -150,10 +166,7 @@ func (r *reconcileCatalog) Reconcile(ctx context.Context, 
request reconcile.Requ
                return reconcile.Result{}, nil
        }
 
-       actions := []Action{
-               NewInitializeAction(),
-               NewMonitorAction(),
-       }
+       actions := r.newActions()
 
        var targetPhase v1.CamelCatalogPhase
        var err error
diff --git a/pkg/controller/catalog/catalog_controller_test.go 
b/pkg/controller/catalog/catalog_controller_test.go
new file mode 100644
index 000000000..7ed735228
--- /dev/null
+++ b/pkg/controller/catalog/catalog_controller_test.go
@@ -0,0 +1,44 @@
+/*
+Licensed to the Apache Software Foundation (ASF) under one or more
+contributor license agreements.  See the NOTICE file distributed with
+this work for additional information regarding copyright ownership.
+The ASF licenses this file to You under the Apache License, Version 2.0
+(the "License"); you may not use this file except in compliance with
+the License.  You may obtain a copy of the License at
+
+   http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+package catalog
+
+import (
+       "testing"
+
+       "github.com/stretchr/testify/assert"
+       "github.com/stretchr/testify/require"
+)
+
+func TestNewActions(t *testing.T) {
+       reconciler := reconcileCatalog{
+               actionFactories: []actionFactory{
+                       NewInitializeAction,
+                       NewMonitorAction,
+               },
+       }
+
+       actions := reconciler.newActions()
+       require.Len(t, actions, 2)
+
+       assert.IsType(t, &initializeAction{}, actions[0])
+       assert.IsType(t, &monitorAction{}, actions[1])
+
+       nextActions := reconciler.newActions()
+       assert.NotSame(t, actions[0], nextActions[0])
+       assert.NotSame(t, actions[1], nextActions[1])
+}
diff --git a/pkg/controller/integration/integration_controller.go 
b/pkg/controller/integration/integration_controller.go
index e9de81d93..9c8e084d4 100644
--- a/pkg/controller/integration/integration_controller.go
+++ b/pkg/controller/integration/integration_controller.go
@@ -58,6 +58,8 @@ import (
 
 const retryMonitoring = 5
 
+type actionFactory func() Action
+
 func Add(ctx context.Context, mgr manager.Manager, c client.Client) error {
        err := mgr.GetFieldIndexer().IndexField(ctx, &corev1.Pod{}, 
"status.phase",
                func(obj ctrl.Object) []string {
@@ -79,6 +81,20 @@ func newReconciler(mgr manager.Manager, c client.Client) 
reconcile.Reconciler {
                        client:   c,
                        scheme:   mgr.GetScheme(),
                        recorder: 
mgr.GetEventRecorder("camel-k-integration-controller"),
+                       baseActionFactories: []actionFactory{
+                               NewPlatformSetupAction,
+                               NewInitializeAction,
+                               NewBuildAction,
+                               newBuildKitAction,
+                               NewBuildCompleteAction,
+                       },
+                       syntheticActionFactories: []actionFactory{
+                               NewMonitorSyntheticAction,
+                       },
+                       nonSyntheticActionFactories: []actionFactory{
+                               NewMonitorAction,
+                               NewMonitorUnknownAction,
+                       },
                },
                schema.GroupVersionKind{
                        Group:   v1.SchemeGroupVersion.Group,
@@ -453,9 +469,29 @@ var _ reconcile.Reconciler = &reconcileIntegration{}
 type reconcileIntegration struct {
        // This client, initialized using mgr.Client() above, is a split client
        // that reads objects from the cache and writes to the API server
-       client   client.Client
-       scheme   *runtime.Scheme
-       recorder events.EventRecorder
+       client                      client.Client
+       scheme                      *runtime.Scheme
+       recorder                    events.EventRecorder
+       baseActionFactories         []actionFactory
+       syntheticActionFactories    []actionFactory
+       nonSyntheticActionFactories []actionFactory
+}
+
+func (r *reconcileIntegration) newActions(synthetic bool) []Action {
+       factories := make([]actionFactory, 0, 
len(r.baseActionFactories)+len(r.syntheticActionFactories))
+       factories = append(factories, r.baseActionFactories...)
+       if synthetic {
+               factories = append(factories, r.syntheticActionFactories...)
+       } else {
+               factories = append(factories, r.nonSyntheticActionFactories...)
+       }
+
+       actions := make([]Action, 0, len(factories))
+       for _, newAction := range factories {
+               actions = append(actions, newAction())
+       }
+
+       return actions
 }
 
 // Reconcile reads that state of the cluster for an Integration object and 
makes changes based on the state read
@@ -500,19 +536,7 @@ func (r *reconcileIntegration) Reconcile(ctx 
context.Context, request reconcile.
        target := instance.DeepCopy()
        targetLog := rlog.ForIntegration(target)
 
-       actions := []Action{
-               NewPlatformSetupAction(),
-               NewInitializeAction(),
-               NewBuildAction(),
-               newBuildKitAction(),
-               NewBuildCompleteAction(),
-       }
-
-       if instance.IsSynthetic() {
-               actions = append(actions, NewMonitorSyntheticAction())
-       } else {
-               actions = append(actions, NewMonitorAction(), 
NewMonitorUnknownAction())
-       }
+       actions := r.newActions(instance.IsSynthetic())
 
        for _, a := range actions {
                a.InjectClient(r.client)
diff --git a/pkg/controller/integration/integration_controller_test.go 
b/pkg/controller/integration/integration_controller_test.go
index 31403528b..f019cac14 100644
--- a/pkg/controller/integration/integration_controller_test.go
+++ b/pkg/controller/integration/integration_controller_test.go
@@ -19,186 +19,52 @@ package integration
 
 import (
        "testing"
-       "time"
 
        "github.com/stretchr/testify/assert"
-       corev1 "k8s.io/api/core/v1"
-       metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
-
-       v1 "github.com/apache/camel-k/v2/pkg/apis/camel/v1"
+       "github.com/stretchr/testify/require"
 )
 
-func TestIsIntegrationUpdated(t *testing.T) {
-       now := metav1.Now()
-
-       tests := []struct {
-               name     string
-               it       *v1.Integration
-               previous *v1.IntegrationCondition
-               next     *v1.IntegrationCondition
-               expected bool
-       }{
-               {
-                       name: "should return true when transitioning to ready",
-                       it: &v1.Integration{
-                               Status: v1.IntegrationStatus{
-                                       InitializationTimestamp: &now,
-                               },
-                       },
-                       previous: nil,
-                       next: &v1.IntegrationCondition{
-                               Status:          corev1.ConditionTrue,
-                               FirstTruthyTime: &now,
-                       },
-                       expected: true,
-               },
-               {
-                       name: "should return false when no 
InitializationTimestamp",
-                       it: &v1.Integration{
-                               Status: v1.IntegrationStatus{},
-                       },
-                       previous: nil,
-                       next: &v1.IntegrationCondition{
-                               Status:          corev1.ConditionTrue,
-                               FirstTruthyTime: &now,
-                       },
-                       expected: false,
-               },
-               {
-                       name: "should return false when already ready",
-                       it: &v1.Integration{
-                               Status: v1.IntegrationStatus{
-                                       InitializationTimestamp: &now,
-                               },
-                       },
-                       previous: &v1.IntegrationCondition{
-                               Status:          corev1.ConditionTrue,
-                               FirstTruthyTime: &now,
-                       },
-                       next: &v1.IntegrationCondition{
-                               Status:          corev1.ConditionTrue,
-                               FirstTruthyTime: &now,
-                       },
-                       expected: false,
-               },
-       }
-
-       for _, tt := range tests {
-               t.Run(tt.name, func(t *testing.T) {
-                       result := isIntegrationUpdated(tt.it, tt.previous, 
tt.next)
-                       assert.Equal(t, tt.expected, result)
-               })
-       }
-}
-
-func TestReadinessTimestampCalculation(t *testing.T) {
-       initTime := metav1.NewTime(time.Date(2025, 1, 1, 10, 0, 0, 0, time.UTC))
-       deployTime := metav1.NewTime(time.Date(2025, 1, 1, 12, 0, 0, 0, 
time.UTC))
-       readyTime := metav1.NewTime(time.Date(2025, 1, 1, 12, 5, 0, 0, 
time.UTC))
-       zeroTime := metav1.Time{}
-
-       tests := []struct {
-               name                    string
-               initializationTimestamp *metav1.Time
-               deploymentTimestamp     *metav1.Time
-               firstTruthyTime         *metav1.Time
-               expectedDuration        time.Duration
-               description             string
-       }{
-               {
-                       name:                    "normal build - uses 
InitializationTimestamp",
-                       initializationTimestamp: &initTime,
-                       deploymentTimestamp:     nil,
-                       firstTruthyTime:         &readyTime,
-                       expectedDuration:        2*time.Hour + 5*time.Minute,
-                       description:             "Without DeploymentTimestamp, 
should use InitializationTimestamp",
+func TestNewActions(t *testing.T) {
+       reconciler := reconcileIntegration{
+               baseActionFactories: []actionFactory{
+                       NewPlatformSetupAction,
+                       NewInitializeAction,
+                       NewBuildAction,
+                       newBuildKitAction,
+                       NewBuildCompleteAction,
                },
-               {
-                       name:                    "dry build - uses 
DeploymentTimestamp",
-                       initializationTimestamp: &initTime,
-                       deploymentTimestamp:     &deployTime,
-                       firstTruthyTime:         &readyTime,
-                       expectedDuration:        5 * time.Minute,
-                       description:             "With DeploymentTimestamp, 
should use it instead of InitializationTimestamp",
+               syntheticActionFactories: []actionFactory{
+                       NewMonitorSyntheticAction,
                },
-               {
-                       name:                    "DeploymentTimestamp is zero - 
falls back to InitializationTimestamp",
-                       initializationTimestamp: &initTime,
-                       deploymentTimestamp:     &zeroTime,
-                       firstTruthyTime:         &readyTime,
-                       expectedDuration:        2*time.Hour + 5*time.Minute,
-                       description:             "Zero DeploymentTimestamp 
should fall back to InitializationTimestamp",
+               nonSyntheticActionFactories: []actionFactory{
+                       NewMonitorAction,
+                       NewMonitorUnknownAction,
                },
        }
 
-       for _, tt := range tests {
-               t.Run(tt.name, func(t *testing.T) {
-                       it := &v1.Integration{
-                               Status: v1.IntegrationStatus{
-                                       InitializationTimestamp: 
tt.initializationTimestamp,
-                                       DeploymentTimestamp:     
tt.deploymentTimestamp,
-                               },
-                       }
+       t.Run("non-synthetic", func(t *testing.T) {
+               actions := reconciler.newActions(false)
+               require.Len(t, actions, 7)
 
-                       startTime := it.Status.InitializationTimestamp.Time
-                       if it.Status.DeploymentTimestamp != nil && 
!it.Status.DeploymentTimestamp.IsZero() {
-                               startTime = it.Status.DeploymentTimestamp.Time
-                       }
-                       duration := tt.firstTruthyTime.Sub(startTime)
-                       assert.Equal(t, tt.expectedDuration, duration, 
tt.description)
-               })
-       }
-}
+               assert.IsType(t, &platformSetupAction{}, actions[0])
+               assert.IsType(t, &initializeAction{}, actions[1])
+               assert.IsType(t, &buildAction{}, actions[2])
+               assert.IsType(t, &buildKitAction{}, actions[3])
+               assert.IsType(t, &buildCompleteAction{}, actions[4])
+               assert.IsType(t, &monitorAction{}, actions[5])
+               assert.IsType(t, &monitorUnknownAction{}, actions[6])
 
-func TestDeploymentTimestampIsSet(t *testing.T) {
-       tests := []struct {
-               name                      string
-               hasDontRunAnnotation      bool
-               expectedPhase             v1.IntegrationPhase
-               expectDeploymentTimestamp bool
-       }{
-               {
-                       name:                      "normal build sets 
DeploymentTimestamp",
-                       hasDontRunAnnotation:      false,
-                       expectedPhase:             v1.IntegrationPhaseDeploying,
-                       expectDeploymentTimestamp: true,
-               },
-               {
-                       name:                      "dry build does not set 
DeploymentTimestamp yet",
-                       hasDontRunAnnotation:      true,
-                       expectedPhase:             
v1.IntegrationPhaseBuildComplete,
-                       expectDeploymentTimestamp: false,
-               },
-       }
+               nextActions := reconciler.newActions(false)
+               assert.NotSame(t, actions[0], nextActions[0])
+       })
 
-       for _, tt := range tests {
-               t.Run(tt.name, func(t *testing.T) {
-                       it := &v1.Integration{
-                               ObjectMeta: metav1.ObjectMeta{
-                                       Annotations: map[string]string{},
-                               },
-                               Status: v1.IntegrationStatus{},
-                       }
+       t.Run("synthetic", func(t *testing.T) {
+               actions := reconciler.newActions(true)
+               require.Len(t, actions, 6)
 
-                       if tt.hasDontRunAnnotation {
-                               
it.Annotations[v1.IntegrationDontRunAfterBuildAnnotation] = 
v1.IntegrationDontRunAfterBuildAnnotationTrueValue
-                       }
+               assert.IsType(t, &monitorSyntheticAction{}, actions[5])
 
-                       if 
it.Annotations[v1.IntegrationDontRunAfterBuildAnnotation] == 
v1.IntegrationDontRunAfterBuildAnnotationTrueValue {
-                               it.Status.Phase = 
v1.IntegrationPhaseBuildComplete
-                       } else {
-                               now := metav1.Now().Rfc3339Copy()
-                               it.Status.DeploymentTimestamp = &now
-                               it.Status.Phase = v1.IntegrationPhaseDeploying
-                       }
-
-                       assert.Equal(t, tt.expectedPhase, it.Status.Phase)
-                       if tt.expectDeploymentTimestamp {
-                               assert.NotNil(t, it.Status.DeploymentTimestamp)
-                               assert.False(t, 
it.Status.DeploymentTimestamp.IsZero())
-                       } else {
-                               assert.Nil(t, it.Status.DeploymentTimestamp)
-                       }
-               })
-       }
+               nextActions := reconciler.newActions(true)
+               assert.NotSame(t, actions[0], nextActions[0])
+       })
 }
diff --git a/pkg/controller/integrationkit/integrationkit_controller.go 
b/pkg/controller/integrationkit/integrationkit_controller.go
index 8456db539..95ece1c5c 100644
--- a/pkg/controller/integrationkit/integrationkit_controller.go
+++ b/pkg/controller/integrationkit/integrationkit_controller.go
@@ -48,6 +48,8 @@ const (
        requeueAfterDuration = 2 * time.Second
 )
 
+type actionFactory func() Action
+
 // Add creates a new IntegrationKit Controller and adds it to the Manager. The 
Manager will set fields on the Controller
 // and Start it when the Manager is Started.
 func Add(ctx context.Context, mgr manager.Manager, c client.Client) error {
@@ -60,6 +62,12 @@ func newReconciler(mgr manager.Manager, c client.Client) 
reconcile.Reconciler {
                        client:   c,
                        scheme:   mgr.GetScheme(),
                        recorder: 
mgr.GetEventRecorder("camel-k-integration-kit-controller"),
+                       actionFactories: []actionFactory{
+                               NewInitializeAction,
+                               NewBuildAction,
+                               NewMonitorAction,
+                               NewErrorAction,
+                       },
                },
                schema.GroupVersionKind{
                        Group:   v1.SchemeGroupVersion.Group,
@@ -180,9 +188,19 @@ var _ reconcile.Reconciler = &reconcileIntegrationKit{}
 type reconcileIntegrationKit struct {
        // This client, initialized using mgr.Client() above, is a split client
        // that reads objects from the cache and writes to the API server
-       client   client.Client
-       scheme   *runtime.Scheme
-       recorder events.EventRecorder
+       client          client.Client
+       scheme          *runtime.Scheme
+       recorder        events.EventRecorder
+       actionFactories []actionFactory
+}
+
+func (r *reconcileIntegrationKit) newActions() []Action {
+       actions := make([]Action, 0, len(r.actionFactories))
+       for _, newAction := range r.actionFactories {
+               actions = append(actions, newAction())
+       }
+
+       return actions
 }
 
 // Reconcile reads that state of the cluster for a IntegrationKit object and 
makes changes based on the state read
@@ -263,12 +281,7 @@ func (r *reconcileIntegrationKit) Reconcile(ctx 
context.Context, request reconci
                return reconcile.Result{}, err
        }
 
-       actions := []Action{
-               NewInitializeAction(),
-               NewBuildAction(),
-               NewMonitorAction(),
-               NewErrorAction(),
-       }
+       actions := r.newActions()
 
        targetPhase := instance.Status.Phase
 
diff --git a/pkg/controller/integrationkit/integrationkit_controller_test.go 
b/pkg/controller/integrationkit/integrationkit_controller_test.go
new file mode 100644
index 000000000..694aba5e0
--- /dev/null
+++ b/pkg/controller/integrationkit/integrationkit_controller_test.go
@@ -0,0 +1,50 @@
+/*
+Licensed to the Apache Software Foundation (ASF) under one or more
+contributor license agreements.  See the NOTICE file distributed with
+this work for additional information regarding copyright ownership.
+The ASF licenses this file to You under the Apache License, Version 2.0
+(the "License"); you may not use this file except in compliance with
+the License.  You may obtain a copy of the License at
+
+   http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+package integrationkit
+
+import (
+       "testing"
+
+       "github.com/stretchr/testify/assert"
+       "github.com/stretchr/testify/require"
+)
+
+func TestNewActions(t *testing.T) {
+       reconciler := reconcileIntegrationKit{
+               actionFactories: []actionFactory{
+                       NewInitializeAction,
+                       NewBuildAction,
+                       NewMonitorAction,
+                       NewErrorAction,
+               },
+       }
+
+       actions := reconciler.newActions()
+       require.Len(t, actions, 4)
+
+       assert.IsType(t, &initializeAction{}, actions[0])
+       assert.IsType(t, &buildAction{}, actions[1])
+       assert.IsType(t, &monitorAction{}, actions[2])
+       assert.IsType(t, &errorAction{}, actions[3])
+
+       nextActions := reconciler.newActions()
+       assert.NotSame(t, actions[0], nextActions[0])
+       assert.NotSame(t, actions[1], nextActions[1])
+       assert.NotSame(t, actions[2], nextActions[2])
+       assert.NotSame(t, actions[3], nextActions[3])
+}
diff --git 
a/pkg/controller/integrationplatform/integrationplatform_controller.go 
b/pkg/controller/integrationplatform/integrationplatform_controller.go
index 1efbce909..bddf866f4 100644
--- a/pkg/controller/integrationplatform/integrationplatform_controller.go
+++ b/pkg/controller/integrationplatform/integrationplatform_controller.go
@@ -40,6 +40,8 @@ import (
        "github.com/apache/camel-k/v2/pkg/util/monitoring"
 )
 
+type actionFactory func() Action
+
 // Add creates a new IntegrationPlatform Controller and adds it to the 
Manager. The Manager will set fields
 // on the Controller and Start it when the Manager is Started.
 func Add(ctx context.Context, mgr manager.Manager, c client.Client) error {
@@ -53,6 +55,11 @@ func newReconciler(mgr manager.Manager, c client.Client) 
reconcile.Reconciler {
                        reader:   mgr.GetAPIReader(),
                        scheme:   mgr.GetScheme(),
                        recorder: 
mgr.GetEventRecorder("camel-k-integration-platform-controller"),
+                       actionFactories: []actionFactory{
+                               NewInitializeAction,
+                               NewCreateAction,
+                               NewMonitorAction,
+                       },
                },
                schema.GroupVersionKind{
                        Group:   v1.SchemeGroupVersion.Group,
@@ -104,9 +111,19 @@ type reconcileIntegrationPlatform struct {
        // that reads objects from the cache and writes to the API server
        client client.Client
        // Non-caching client
-       reader   ctrl.Reader
-       scheme   *runtime.Scheme
-       recorder events.EventRecorder
+       reader          ctrl.Reader
+       scheme          *runtime.Scheme
+       recorder        events.EventRecorder
+       actionFactories []actionFactory
+}
+
+func (r *reconcileIntegrationPlatform) newActions() []Action {
+       actions := make([]Action, 0, len(r.actionFactories))
+       for _, newAction := range r.actionFactories {
+               actions = append(actions, newAction())
+       }
+
+       return actions
 }
 
 // Reconcile reads that state of the cluster for a IntegrationPlatform object 
and makes changes based
@@ -150,11 +167,7 @@ func (r *reconcileIntegrationPlatform) Reconcile(ctx 
context.Context, request re
                return reconcile.Result{}, nil
        }
 
-       actions := []Action{
-               NewInitializeAction(),
-               NewCreateAction(),
-               NewMonitorAction(),
-       }
+       actions := r.newActions()
 
        var targetPhase v1.IntegrationPlatformPhase
        var err error
diff --git 
a/pkg/controller/integrationplatform/integrationplatform_controller_test.go 
b/pkg/controller/integrationplatform/integrationplatform_controller_test.go
new file mode 100644
index 000000000..2497a5fe2
--- /dev/null
+++ b/pkg/controller/integrationplatform/integrationplatform_controller_test.go
@@ -0,0 +1,47 @@
+/*
+Licensed to the Apache Software Foundation (ASF) under one or more
+contributor license agreements.  See the NOTICE file distributed with
+this work for additional information regarding copyright ownership.
+The ASF licenses this file to You under the Apache License, Version 2.0
+(the "License"); you may not use this file except in compliance with
+the License.  You may obtain a copy of the License at
+
+   http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+package integrationplatform
+
+import (
+       "testing"
+
+       "github.com/stretchr/testify/assert"
+       "github.com/stretchr/testify/require"
+)
+
+func TestNewActions(t *testing.T) {
+       reconciler := reconcileIntegrationPlatform{
+               actionFactories: []actionFactory{
+                       NewInitializeAction,
+                       NewCreateAction,
+                       NewMonitorAction,
+               },
+       }
+
+       actions := reconciler.newActions()
+       require.Len(t, actions, 3)
+
+       assert.IsType(t, &initializeAction{}, actions[0])
+       assert.IsType(t, &createAction{}, actions[1])
+       assert.IsType(t, &monitorAction{}, actions[2])
+
+       nextActions := reconciler.newActions()
+       assert.NotSame(t, actions[0], nextActions[0])
+       assert.NotSame(t, actions[1], nextActions[1])
+       assert.NotSame(t, actions[2], nextActions[2])
+}
diff --git a/pkg/controller/pipe/pipe_controller.go 
b/pkg/controller/pipe/pipe_controller.go
index ca8762ed6..e3130e92a 100644
--- a/pkg/controller/pipe/pipe_controller.go
+++ b/pkg/controller/pipe/pipe_controller.go
@@ -44,6 +44,8 @@ import (
        "github.com/apache/camel-k/v2/pkg/util/monitoring"
 )
 
+type actionFactory func() Action
+
 // Add creates a new Pipe Controller and adds it to the Manager. The Manager 
will set fields on the Controller
 // and Start it when the Manager is Started.
 func Add(ctx context.Context, mgr manager.Manager, c client.Client) error {
@@ -56,6 +58,10 @@ func newReconciler(mgr manager.Manager, c client.Client) 
reconcile.Reconciler {
                        client:   c,
                        scheme:   mgr.GetScheme(),
                        recorder: 
mgr.GetEventRecorder("camel-k-pipe-controller"),
+                       actionFactories: []actionFactory{
+                               NewInitializeAction,
+                               NewMonitorAction,
+                       },
                },
                schema.GroupVersionKind{
                        Group:   v1.SchemeGroupVersion.Group,
@@ -132,9 +138,19 @@ var _ reconcile.Reconciler = &ReconcilePipe{}
 type ReconcilePipe struct {
        // This client, initialized using mgr.Client() above, is a split client
        // that reads objects from the cache and writes to the API server
-       client   client.Client
-       scheme   *runtime.Scheme
-       recorder events.EventRecorder
+       client          client.Client
+       scheme          *runtime.Scheme
+       recorder        events.EventRecorder
+       actionFactories []actionFactory
+}
+
+func (r *ReconcilePipe) newActions() []Action {
+       actions := make([]Action, 0, len(r.actionFactories))
+       for _, newAction := range r.actionFactories {
+               actions = append(actions, newAction())
+       }
+
+       return actions
 }
 
 // Reconcile reads that state of the cluster for a Pipe object and makes 
changes based
@@ -178,10 +194,7 @@ func (r *ReconcilePipe) Reconcile(ctx context.Context, 
request reconcile.Request
                return reconcile.Result{}, nil
        }
 
-       actions := []Action{
-               NewInitializeAction(),
-               NewMonitorAction(),
-       }
+       actions := r.newActions()
 
        var err error
 
diff --git a/pkg/controller/pipe/pipe_controller_test.go 
b/pkg/controller/pipe/pipe_controller_test.go
new file mode 100644
index 000000000..9772cd994
--- /dev/null
+++ b/pkg/controller/pipe/pipe_controller_test.go
@@ -0,0 +1,44 @@
+/*
+Licensed to the Apache Software Foundation (ASF) under one or more
+contributor license agreements.  See the NOTICE file distributed with
+this work for additional information regarding copyright ownership.
+The ASF licenses this file to You under the Apache License, Version 2.0
+(the "License"); you may not use this file except in compliance with
+the License.  You may obtain a copy of the License at
+
+   http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+package pipe
+
+import (
+       "testing"
+
+       "github.com/stretchr/testify/assert"
+       "github.com/stretchr/testify/require"
+)
+
+func TestNewActions(t *testing.T) {
+       reconciler := ReconcilePipe{
+               actionFactories: []actionFactory{
+                       NewInitializeAction,
+                       NewMonitorAction,
+               },
+       }
+
+       actions := reconciler.newActions()
+       require.Len(t, actions, 2)
+
+       assert.IsType(t, &initializeAction{}, actions[0])
+       assert.IsType(t, &monitorAction{}, actions[1])
+
+       nextActions := reconciler.newActions()
+       assert.NotSame(t, actions[0], nextActions[0])
+       assert.NotSame(t, actions[1], nextActions[1])
+}

Reply via email to