@@ -11,6 +11,8 @@ import (
1111
1212 . "github.com/onsi/ginkgo/v2"
1313 . "github.com/onsi/gomega"
14+ "github.com/prometheus/client_golang/prometheus"
15+ prometheusclientmodel "github.com/prometheus/client_model/go"
1416 k8serrors "k8s.io/apimachinery/pkg/api/errors"
1517 metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
1618 "k8s.io/apimachinery/pkg/labels"
@@ -21,6 +23,7 @@ import (
2123
2224 placementv1beta1 "go.goms.io/fleet/apis/placement/v1beta1"
2325 "go.goms.io/fleet/pkg/utils/condition"
26+ "go.goms.io/fleet/pkg/utils/controller/metrics"
2427 testutilseviction "go.goms.io/fleet/test/utils/eviction"
2528)
2629
@@ -41,15 +44,46 @@ const (
4144var _ = Describe ("Test ClusterResourcePlacementEviction Controller" , func () {
4245 crpName := fmt .Sprintf (crpNameTemplate , GinkgoParallelProcess ())
4346 evictionName := fmt .Sprintf (evictionNameTemplate , GinkgoParallelProcess ())
47+ var customRegistry * prometheus.Registry
48+
49+ BeforeEach (func () {
50+ // Create a test registry
51+ customRegistry = prometheus .NewRegistry ()
52+ Expect (customRegistry .Register (metrics .FleetEvictionStatus )).Should (Succeed ())
53+ // Reset metrics before each test
54+ metrics .FleetEvictionStatus .Reset ()
55+ // emit incomplete eviction metric to simulate eviction failed once.
56+ metrics .FleetEvictionStatus .WithLabelValues (evictionName , "false" , "unknown" ).SetToCurrentTime ()
57+ })
4458
4559 AfterEach (func () {
4660 ensureCRPDBRemoved (crpName )
4761 ensureAllBindingsAreRemoved (crpName )
4862 ensureEvictionRemoved (evictionName )
4963 ensureCRPRemoved (crpName )
64+ Expect (customRegistry .Unregister (metrics .FleetEvictionStatus )).Should (BeTrue ())
5065 })
5166
52- It ("Eviction Blocked - ClusterResourcePlacementDisruptionBudget's maxUnavailable blocks eviction" , func () {
67+ It ("Invalid Eviction Blocked - emit complete metric with isValid=false, isComplete=true" , func () {
68+ By ("Create ClusterResourcePlacementEviction" , func () {
69+ eviction := buildTestEviction (evictionName , "random-crp" , "test-cluster" )
70+ Expect (k8sClient .Create (ctx , eviction )).Should (Succeed ())
71+ })
72+
73+ By ("Check eviction status" , func () {
74+ evictionStatusUpdatedActual := testutilseviction .StatusUpdatedActual (
75+ ctx , k8sClient , evictionName ,
76+ & testutilseviction.IsValidEviction {IsValid : false , Msg : condition .EvictionInvalidMissingCRPMessage },
77+ nil )
78+ Eventually (evictionStatusUpdatedActual , eventuallyDuration , eventuallyInterval ).Should (Succeed ())
79+ })
80+
81+ By ("Ensure eviction complete metric was emitted" , func () {
82+ checkEvictionCompleteMetric (customRegistry , "false" , "true" )
83+ })
84+ })
85+
86+ It ("Eviction Blocked - ClusterResourcePlacementDisruptionBudget's maxUnavailable blocks eviction, emit complete isValid=true, isComplete=true" , func () {
5387 crbName := fmt .Sprintf (crbNameTemplate , GinkgoParallelProcess ())
5488
5589 By ("Create ClusterResourcePlacement" , func () {
@@ -122,9 +156,13 @@ var _ = Describe("Test ClusterResourcePlacementEviction Controller", func() {
122156 return ! k8serrors .IsNotFound (k8sClient .Get (ctx , types.NamespacedName {Name : crbName }, & crb ))
123157 }, consistentlyDuration , consistentlyInterval ).Should (BeTrue ())
124158 })
159+
160+ By ("Ensure eviction complete metric was emitted" , func () {
161+ checkEvictionCompleteMetric (customRegistry , "true" , "true" )
162+ })
125163 })
126164
127- It ("Eviction Allowed - ClusterResourcePlacementDisruptionBudget's maxUnavailable allows eviction" , func () {
165+ It ("Eviction Allowed - ClusterResourcePlacementDisruptionBudget's maxUnavailable allows eviction, emit complete isValid=true, isComplete=true " , func () {
128166 crbName := fmt .Sprintf (crbNameTemplate , GinkgoParallelProcess ())
129167
130168 By ("Create ClusterResourcePlacement" , func () {
@@ -218,9 +256,13 @@ var _ = Describe("Test ClusterResourcePlacementEviction Controller", func() {
218256 return k8serrors .IsNotFound (k8sClient .Get (ctx , types.NamespacedName {Name : crbName }, & crb ))
219257 }, consistentlyDuration , consistentlyInterval ).Should (BeTrue ())
220258 })
259+
260+ By ("Ensure eviction complete metric was emitted" , func () {
261+ checkEvictionCompleteMetric (customRegistry , "true" , "true" )
262+ })
221263 })
222264
223- It ("Eviction Blocked - ClusterResourcePlacementDisruptionBudget's minAvailable blocks eviction" , func () {
265+ It ("Eviction Blocked - ClusterResourcePlacementDisruptionBudget's minAvailable blocks eviction, emit complete isValid=true, isComplete=true " , func () {
224266 crbName := fmt .Sprintf (crbNameTemplate , GinkgoParallelProcess ())
225267
226268 By ("Create ClusterResourcePlacement" , func () {
@@ -293,9 +335,13 @@ var _ = Describe("Test ClusterResourcePlacementEviction Controller", func() {
293335 return ! k8serrors .IsNotFound (k8sClient .Get (ctx , types.NamespacedName {Name : crbName }, & crb ))
294336 }, consistentlyDuration , consistentlyInterval ).Should (BeTrue ())
295337 })
338+
339+ By ("Ensure eviction complete metric was emitted" , func () {
340+ checkEvictionCompleteMetric (customRegistry , "true" , "true" )
341+ })
296342 })
297343
298- It ("Eviction Allowed - ClusterResourcePlacementDisruptionBudget's minUnavailable allows eviction" , func () {
344+ It ("Eviction Allowed - ClusterResourcePlacementDisruptionBudget's minUnavailable allows eviction, emit complete isValid=true, isComplete=true " , func () {
299345 crbName := fmt .Sprintf (crbNameTemplate , GinkgoParallelProcess ())
300346 anotherCRBName := fmt .Sprintf (anotherCRBNameTemplate , GinkgoParallelProcess ())
301347
@@ -419,6 +465,10 @@ var _ = Describe("Test ClusterResourcePlacementEviction Controller", func() {
419465 return ! k8serrors .IsNotFound (k8sClient .Get (ctx , types.NamespacedName {Name : anotherCRBName }, & anotherCRB ))
420466 }, consistentlyDuration , consistentlyInterval ).Should (BeTrue ())
421467 })
468+
469+ By ("Ensure eviction complete metric was emitted" , func () {
470+ checkEvictionCompleteMetric (customRegistry , "true" , "true" )
471+ })
422472 })
423473})
424474
@@ -464,7 +514,7 @@ func ensureEvictionRemoved(name string) {
464514 Name : name ,
465515 },
466516 }
467- Expect (k8sClient .Delete (ctx , & eviction )).Should (Succeed ())
517+ Expect (client . IgnoreNotFound ( k8sClient .Delete (ctx , & eviction ) )).Should (Succeed ())
468518 // Ensure eviction doesn't exist.
469519 Eventually (func () error {
470520 if err := k8sClient .Get (ctx , types.NamespacedName {Name : name }, & eviction ); ! k8serrors .IsNotFound (err ) {
@@ -536,3 +586,26 @@ func ensureAllBindingsAreRemoved(crpName string) {
536586 ensureCRBRemoved (bindingList .Items [i ].Name )
537587 }
538588}
589+
590+ func checkEvictionCompleteMetric (registry * prometheus.Registry , isValid , isComplete string ) {
591+ metricFamilies , err := registry .Gather ()
592+ Expect (err ).Should (Succeed ())
593+ var evictionCompleteMetrics []* prometheusclientmodel.Metric
594+ for _ , mf := range metricFamilies {
595+ if mf .GetName () == "fleet_workload_eviction_complete" {
596+ evictionCompleteMetrics = mf .GetMetric ()
597+ }
598+ }
599+ // we only expect one metric, incomplete eviction metric should be removed.
600+ Expect (len (evictionCompleteMetrics )).Should (Equal (1 ))
601+ metricLabels := evictionCompleteMetrics [0 ].GetLabel ()
602+ Expect (len (metricLabels )).Should (Equal (3 ))
603+ for _ , label := range metricLabels {
604+ if label .GetName () == "isValid" {
605+ Expect (label .GetValue ()).Should (Equal (isValid ))
606+ }
607+ if label .GetName () == "isComplete" {
608+ Expect (label .GetValue ()).Should (Equal (isComplete ))
609+ }
610+ }
611+ }
0 commit comments