@@ -18,8 +18,10 @@ package parallel
1818
1919import (
2020 "context"
21+ "fmt"
2122
2223 argov1beta1api "github.com/argoproj-labs/argocd-operator/api/v1beta1"
24+ argoprojv1a1 "github.com/argoproj/argo-cd/v3/pkg/apis/application/v1alpha1"
2325 . "github.com/onsi/ginkgo/v2"
2426 . "github.com/onsi/gomega"
2527 "github.com/redhat-developer/gitops-operator/test/openshift/e2e/ginkgo/fixture"
@@ -28,7 +30,9 @@ import (
2830 statefulsetFixture "github.com/redhat-developer/gitops-operator/test/openshift/e2e/ginkgo/fixture/statefulset"
2931 fixtureUtils "github.com/redhat-developer/gitops-operator/test/openshift/e2e/ginkgo/fixture/utils"
3032 appsv1 "k8s.io/api/apps/v1"
33+ corev1 "k8s.io/api/core/v1"
3134 metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
35+ "k8s.io/apimachinery/pkg/types"
3236 "sigs.k8s.io/controller-runtime/pkg/client"
3337)
3438
@@ -49,8 +53,7 @@ var _ = Describe("GitOps Operator Parallel E2E Tests", func() {
4953
5054 })
5155
52- It ("ensuring that extra arguments can be added to application controller" , func () {
53-
56+ It ("ensuring extra arguments are deduplicated, replaced, or preserved as expected in application-controller" , func () {
5457 By ("creating a simple ArgoCD CR and waiting for it to become available" )
5558 ns , cleanupFunc := fixture .CreateRandomE2ETestNamespaceWithCleanupFunc ()
5659 defer cleanupFunc ()
@@ -62,61 +65,251 @@ var _ = Describe("GitOps Operator Parallel E2E Tests", func() {
6265 },
6366 }
6467 Expect (k8sClient .Create (ctx , argoCD )).To (Succeed ())
65-
6668 Eventually (argoCD , "5m" , "5s" ).Should (argocdFixture .BeAvailable ())
6769
68- By ("verifying app controller becomes availables" )
6970 appControllerSS := & appsv1.StatefulSet {
7071 ObjectMeta : metav1.ObjectMeta {
7172 Name : "example-argocd-application-controller" ,
7273 Namespace : ns .Name ,
7374 },
7475 }
75-
7676 Eventually (appControllerSS ).Should (k8sFixture .ExistByName ())
7777 Eventually (appControllerSS ).Should (statefulsetFixture .HaveReadyReplicas (1 ))
7878
79- By ("adding a new parameter via .spec.controller.extraCommandArgs" )
79+ // 1: Add new flag
80+ By ("adding a new flag via extraCommandArgs" )
8081 argocdFixture .Update (argoCD , func (ac * argov1beta1api.ArgoCD ) {
81- ac .Spec .Controller .ExtraCommandArgs = []string {"--app-hard-resync" }
82+ ac .Spec .Controller .ExtraCommandArgs = []string {"--app-hard-resync" , "2" }
8283 })
83-
84- By ("verifying new parameter is added, and the existing paramaters are still present" )
8584 Eventually (appControllerSS ).Should (statefulsetFixture .HaveContainerCommandSubstring ("--app-hard-resync" , 0 ))
8685
87- Expect (len (appControllerSS .Spec .Template .Spec .Containers [0 ].Command )).To (BeNumerically (">=" , 10 ))
86+ // 2: Replace existing non-repeatable flag
87+ By ("replacing existing default flag with extraCommandArgs" )
88+ argocdFixture .Update (argoCD , func (ac * argov1beta1api.ArgoCD ) {
89+ ac .Spec .Controller .ExtraCommandArgs = []string {
90+ "--status-processors" , "15" ,
91+ "--kubectl-parallelism-limit" , "20" ,
92+ }
93+ })
94+
95+ // Expect new values to appear
96+ Eventually (appControllerSS ).Should (statefulsetFixture .HaveContainerCommandSubstring ("--status-processors" , 0 ))
97+ Eventually (appControllerSS ).Should (statefulsetFixture .HaveContainerCommandSubstring ("15" , 0 ))
98+ Eventually (appControllerSS ).Should (statefulsetFixture .HaveContainerCommandSubstring ("--kubectl-parallelism-limit" , 0 ))
99+ Eventually (appControllerSS ).Should (statefulsetFixture .HaveContainerCommandSubstring ("20" , 0 ))
88100
89- By ("removing the extra command arg" )
101+ // Expect default values to be replaced (old default 10 should not appear)
102+ Consistently (func () bool {
103+ cmd := appControllerSS .Spec .Template .Spec .Containers [0 ].Command
104+ for i := range cmd {
105+ if cmd [i ] == "--status-processors" && i + 1 < len (cmd ) && cmd [i + 1 ] == "10" {
106+ return true
107+ }
108+ }
109+ return false
110+ }).Should (BeFalse ())
111+
112+ // 3: Add duplicate flag+value pairs, which should be ignored
113+ By ("adding duplicate flags with same values" )
90114 argocdFixture .Update (argoCD , func (ac * argov1beta1api.ArgoCD ) {
91- ac .Spec .Controller .ExtraCommandArgs = nil
115+ ac .Spec .Controller .ExtraCommandArgs = []string {
116+ "--status-processors" , "15" , // duplicate
117+ "--kubectl-parallelism-limit" , "20" , // duplicate
118+ "--hydrator-enabled" ,
119+ }
92120 })
121+ // Verify --hydrator-enabled gets added
122+ Eventually (appControllerSS ).Should (statefulsetFixture .HaveContainerCommandSubstring ("--hydrator-enabled" , 0 ))
123+
124+ // But no duplicate --status-processors or --kubectl-parallelism-limit
125+ Consistently (func () bool {
126+ cmd := appControllerSS .Spec .Template .Spec .Containers [0 ].Command
93127
94- By ("verifying the parameter has been removed" )
95- Eventually (appControllerSS ).ShouldNot (statefulsetFixture .HaveContainerCommandSubstring ("--app-hard-resync" , 0 ))
96- Consistently (appControllerSS ).ShouldNot (statefulsetFixture .HaveContainerCommandSubstring ("--app-hard-resync" , 0 ))
97- Expect (len (appControllerSS .Spec .Template .Spec .Containers [0 ].Command )).To (BeNumerically (">=" , 10 ))
128+ statusProcessorsCount := 0
129+ kubectlLimitCount := 0
130+
131+ for i := 0 ; i < len (cmd ); i ++ {
132+ if cmd [i ] == "--status-processors" {
133+ statusProcessorsCount ++
134+ }
135+ if cmd [i ] == "--kubectl-parallelism-limit" {
136+ kubectlLimitCount ++
137+ }
138+ }
98139
99- By ("adding a new extra command arg that has the same name as existing parameters" )
140+ // Fail if either flag appears more than once
141+ return statusProcessorsCount > 1 || kubectlLimitCount > 1
142+ }).Should (BeFalse ())
143+
144+ // 4: Add a repeatable flag multiple times with different values
145+ By ("adding a repeatable flag with multiple values" )
100146 argocdFixture .Update (argoCD , func (ac * argov1beta1api.ArgoCD ) {
101147 ac .Spec .Controller .ExtraCommandArgs = []string {
102- "--status-processors" ,
103- "15" ,
104- "--kubectl-parallelism-limit" ,
105- "20" ,
148+ "--metrics-application-labels" , "application.argoproj.io/template-version" ,
149+ "--metrics-application-labels" , "application.argoproj.io/chart-version" ,
106150 }
107151 })
108152
109- // TODO: These lines are currently failing: they are ported correctly from the original kuttl test, but the original kuttl test did not check them correctly (and thus either the behaviour in the operator changed, or the tests never worked )
153+ Eventually ( appControllerSS ). Should ( statefulsetFixture . HaveContainerCommandSubstring ( "--metrics-application-labels" , 0 ) )
110154
111- // Eventually(appControllerSS).ShouldNot(statefulsetFixture.HaveContainerCommandSubstring("--status-processors 15", 0))
155+ // Check that both --metrics-application-labels flags are present
156+ Eventually (func () bool {
157+ cmd := appControllerSS .Spec .Template .Spec .Containers [0 ].Command
112158
113- // Consistently(appControllerSS).ShouldNot(statefulsetFixture.HaveContainerCommandSubstring("--status-processors 15", 0))
159+ metricVals := []string {}
160+ for i := 0 ; i < len (cmd ); i ++ {
161+ if cmd [i ] == "--metrics-application-labels" && i + 1 < len (cmd ) {
162+ metricVals = append (metricVals , cmd [i + 1 ])
163+ }
164+ }
114165
115- // Eventually(appControllerSS).ShouldNot(statefulsetFixture.HaveContainerCommandSubstring("--kubectl-parallelism-limit 20", 0))
166+ // Ensure both values are present
167+ hasMetricLabelTemplate := false
168+ hasMetricLabelChart := false
169+ for _ , v := range metricVals {
170+ if v == "application.argoproj.io/template-version" {
171+ hasMetricLabelTemplate = true
172+ }
173+ if v == "application.argoproj.io/chart-version" {
174+ hasMetricLabelChart = true
175+ }
176+ }
177+ return hasMetricLabelTemplate && hasMetricLabelChart
178+ }).Should (BeTrue ())
116179
117- // Consistently(appControllerSS).ShouldNot(statefulsetFixture.HaveContainerCommandSubstring("--kubectl-parallelism-limit 20", 0))
180+ // 5: Remove all extra args
181+ By ("removing all extra args" )
182+ argocdFixture .Update (argoCD , func (ac * argov1beta1api.ArgoCD ) {
183+ ac .Spec .Controller .ExtraCommandArgs = nil
184+ })
118185
186+ // Expect all custom flags to disappear
187+ Eventually (appControllerSS ).ShouldNot (statefulsetFixture .HaveContainerCommandSubstring ("--metrics-application-labels" , 0 ))
188+ Eventually (appControllerSS ).ShouldNot (statefulsetFixture .HaveContainerCommandSubstring ("--status-processors 15" , 0 ))
189+ Eventually (appControllerSS ).ShouldNot (statefulsetFixture .HaveContainerCommandSubstring ("--kubectl-parallelism-limit 20" , 0 ))
190+ Eventually (appControllerSS ).ShouldNot (statefulsetFixture .HaveContainerCommandSubstring ("--hydrator-enabled" , 0 ))
119191 })
192+ })
193+
194+ })
195+
196+ var _ = Describe ("ArgoCD Resource Health Persist" , func () {
197+ var (
198+ argoCDName = "example-argocd"
199+ appName = "guestbook"
200+ appNamespace = "guestbook"
201+ )
202+
203+ var (
204+ k8sClient client.Client
205+ ctx context.Context
206+ )
207+
208+ BeforeEach (func () {
209+ fmt .Println ("YUOOo" )
210+ fixture .EnsureParallelCleanSlate ()
211+
212+ k8sClient , _ = fixtureUtils .GetE2ETestKubeClient ()
213+ ctx = context .Background ()
214+
215+ })
216+
217+ Context ("1-115_validate_resource_health_persisted_in_application_status" , func () {
218+ It ("should persist resource health in Application CR status when configured" , func () {
219+ ns , cleanupFunc := fixture .CreateRandomE2ETestNamespaceWithCleanupFunc ()
220+ defer cleanupFunc ()
221+
222+ err := k8sClient .Get (ctx , client.ObjectKey {
223+ Name : ns .Name ,
224+ Namespace : ns .Namespace ,
225+ }, ns )
226+ Expect (err ).Should (BeNil ())
120227
228+ By ("Creating ArgoCD CR with controller.resource.health.persist=true" )
229+ argoCD := & argov1beta1api.ArgoCD {
230+ ObjectMeta : metav1.ObjectMeta {Name : "example-argocd" , Namespace : ns .Name },
231+ Spec : argov1beta1api.ArgoCDSpec {
232+ Controller : argov1beta1api.ArgoCDApplicationControllerSpec {},
233+ },
234+ }
235+ Expect (k8sClient .Create (ctx , argoCD )).To (Succeed ())
236+ Eventually (argoCD , "5m" , "5s" ).Should (argocdFixture .BeAvailable ())
237+
238+ By ("Waiting for Application Controller to be ready" )
239+ Eventually (func () bool {
240+ deploy := & appsv1.StatefulSet {}
241+ err := k8sClient .Get (ctx , client.ObjectKey {
242+ Name : argoCDName + "-application-controller" ,
243+ Namespace : ns .Name ,
244+ }, deploy )
245+ return err == nil && deploy .Status .ReadyReplicas > 0
246+ }, "1m" , "5s" ).Should (BeTrue ())
247+
248+ targetNamespace := & corev1.Namespace {
249+ ObjectMeta : metav1.ObjectMeta {
250+ Name : appNamespace ,
251+ Labels : map [string ]string {
252+ "argocd.argoproj.io/managed-by" : ns .Name ,
253+ },
254+ },
255+ }
256+ By ("Creating target namespace for Application" )
257+ Expect (k8sClient .Create (ctx , targetNamespace )).To (Succeed ())
258+
259+ By ("Creating ArgoCD Application CR" )
260+ app := & argoprojv1a1.Application {
261+ ObjectMeta : metav1.ObjectMeta {
262+ Name : appName ,
263+ Namespace : ns .Name ,
264+ },
265+ Spec : argoprojv1a1.ApplicationSpec {
266+ Project : "default" ,
267+ Source : & argoprojv1a1.ApplicationSource {
268+ RepoURL : "https://github.com/Rizwana777/argocd-example-apps" ,
269+ Path : "guestbook" ,
270+ TargetRevision : "HEAD" ,
271+ },
272+ Destination : argoprojv1a1.ApplicationDestination {
273+ Server : "https://kubernetes.default.svc" ,
274+ Namespace : targetNamespace .Name ,
275+ },
276+ SyncPolicy : & argoprojv1a1.SyncPolicy {
277+ Automated : & argoprojv1a1.SyncPolicyAutomated {},
278+ },
279+ },
280+ }
281+ Expect (k8sClient .Create (ctx , app )).To (Succeed ())
282+
283+ By ("Validating that resource health is persisted in Application CR" )
284+ Eventually (func () bool {
285+ var fetched argoprojv1a1.Application
286+ err := k8sClient .Get (ctx , types.NamespacedName {
287+ Name : appName ,
288+ Namespace : ns .Name ,
289+ }, & fetched )
290+ if err != nil {
291+ return false
292+ }
293+
294+ // Check if application has resources with health information
295+ if len (fetched .Status .Resources ) == 0 {
296+ return false
297+ }
298+
299+ for _ , res := range fetched .Status .Resources {
300+ if res .Health == nil {
301+ return false
302+ }
303+ if res .Health .Status == "" {
304+ return false
305+ }
306+ }
307+
308+ // Validate resourceHealthSource is NOT present (it is omitted when health is persisted)
309+ return len (fetched .Status .ResourceHealthSource ) == 0
310+ }, "3m" , "5s" ).Should (BeTrue ())
311+
312+ Expect (k8sClient .Delete (ctx , targetNamespace )).To (Succeed ())
313+ })
121314 })
122315})
0 commit comments