@@ -1656,3 +1656,207 @@ func TestPlug_reconcileConfigMap_changedLabels(t *testing.T) {
16561656 })
16571657 }
16581658}
1659+
1660+ // Tests that reconciliation does NOT trigger an update when containers are returned in different order from etcd.
1661+ func TestReconcileDeployment_NoUpdateWhenContainersOrderDiffers (t * testing.T ) {
1662+ s := scheme .Scheme
1663+ addKnownTypesToScheme (s )
1664+
1665+ fakeClient := fake .NewClientBuilder ().WithScheme (s ).WithRuntimeObjects (newGitopsService ()).Build ()
1666+ reconciler := newReconcileGitOpsService (fakeClient , s )
1667+ instance := & pipelinesv1alpha1.GitopsService {}
1668+
1669+ // Create deployment
1670+ _ , err := reconciler .reconcileDeployment (instance , newRequest (serviceNamespace , gitopsPluginName ))
1671+ assertNoError (t , err )
1672+
1673+ // Get the deployment and capture initial ResourceVersion and Generation
1674+ deployment := & appsv1.Deployment {}
1675+ err = fakeClient .Get (context .TODO (), types.NamespacedName {Name : gitopsPluginName , Namespace : serviceNamespace }, deployment )
1676+ assertNoError (t , err )
1677+ initialRV := deployment .ResourceVersion
1678+ initialGen := deployment .Generation
1679+
1680+ // Simulate etcd returning containers in different order
1681+ if len (deployment .Spec .Template .Spec .Containers ) >= 2 {
1682+ containers := deployment .Spec .Template .Spec .Containers
1683+ reversedContainers := make ([]corev1.Container , len (containers ))
1684+ for i := range containers {
1685+ reversedContainers [len (containers )- 1 - i ] = containers [i ]
1686+ }
1687+ deployment .Spec .Template .Spec .Containers = reversedContainers
1688+ err = fakeClient .Update (context .TODO (), deployment )
1689+ assertNoError (t , err )
1690+ }
1691+
1692+ // Reconcile again - should NOT trigger an update
1693+ _ , err = reconciler .reconcileDeployment (instance , newRequest (serviceNamespace , gitopsPluginName ))
1694+ assertNoError (t , err )
1695+
1696+ // Verify no update was triggered
1697+ err = fakeClient .Get (context .TODO (), types.NamespacedName {Name : gitopsPluginName , Namespace : serviceNamespace }, deployment )
1698+ assertNoError (t , err )
1699+
1700+ assert .Equal (t , deployment .ResourceVersion , initialRV ,
1701+ "ResourceVersion should NOT change when only container order differs" )
1702+ assert .Equal (t , deployment .Generation , initialGen ,
1703+ "Generation should NOT change when only container order differs" )
1704+ }
1705+
1706+ // Tests that reconciliation does NOT trigger an update when volumes are returned in different order from etcd.
1707+ func TestReconcileDeployment_NoUpdateWhenVolumesOrderDiffers (t * testing.T ) {
1708+ s := scheme .Scheme
1709+ addKnownTypesToScheme (s )
1710+
1711+ fakeClient := fake .NewClientBuilder ().WithScheme (s ).WithRuntimeObjects (newGitopsService ()).Build ()
1712+ reconciler := newReconcileGitOpsService (fakeClient , s )
1713+ instance := & pipelinesv1alpha1.GitopsService {}
1714+
1715+ // Create deployment
1716+ _ , err := reconciler .reconcileDeployment (instance , newRequest (serviceNamespace , gitopsPluginName ))
1717+ assertNoError (t , err )
1718+
1719+ // Get the deployment
1720+ deployment := & appsv1.Deployment {}
1721+ err = fakeClient .Get (context .TODO (), types.NamespacedName {Name : gitopsPluginName , Namespace : serviceNamespace }, deployment )
1722+ assertNoError (t , err )
1723+
1724+ // Simulate etcd returning volumes in different order
1725+ if len (deployment .Spec .Template .Spec .Volumes ) >= 2 {
1726+ volumes := deployment .Spec .Template .Spec .Volumes
1727+ reversedVolumes := make ([]corev1.Volume , len (volumes ))
1728+ for i := range volumes {
1729+ reversedVolumes [len (volumes )- 1 - i ] = volumes [i ]
1730+ }
1731+ deployment .Spec .Template .Spec .Volumes = reversedVolumes
1732+ err = fakeClient .Update (context .TODO (), deployment )
1733+ assertNoError (t , err )
1734+
1735+ err = fakeClient .Get (context .TODO (), types.NamespacedName {Name : gitopsPluginName , Namespace : serviceNamespace }, deployment )
1736+ assertNoError (t , err )
1737+ rvAfterManualUpdate := deployment .ResourceVersion
1738+ genAfterManualUpdate := deployment .Generation
1739+
1740+ // Reconcile again - should NOT trigger an update
1741+ _ , err = reconciler .reconcileDeployment (instance , newRequest (serviceNamespace , gitopsPluginName ))
1742+ assertNoError (t , err )
1743+
1744+ // Verify no update was triggered
1745+ err = fakeClient .Get (context .TODO (), types.NamespacedName {Name : gitopsPluginName , Namespace : serviceNamespace }, deployment )
1746+ assertNoError (t , err )
1747+
1748+ assert .Equal (t , deployment .ResourceVersion , rvAfterManualUpdate ,
1749+ "ResourceVersion should NOT change when only volume order differs" )
1750+ assert .Equal (t , deployment .Generation , genAfterManualUpdate ,
1751+ "Generation should NOT change when only volume order differs" )
1752+ } else {
1753+ t .Skip ("Skipping test: deployment has less than 2 volumes, cannot test order difference" )
1754+ }
1755+ }
1756+
1757+ // Tests that reconciliation does NOT trigger an update when tolerations are returned in different order from etcd.
1758+ func TestReconcileDeployment_NoUpdateWhenTolerationsOrderDiffers (t * testing.T ) {
1759+ s := scheme .Scheme
1760+ addKnownTypesToScheme (s )
1761+
1762+ // Create GitopsService with tolerations
1763+ gitopsService := & pipelinesv1alpha1.GitopsService {
1764+ ObjectMeta : metav1.ObjectMeta {
1765+ Name : serviceName ,
1766+ },
1767+ Spec : pipelinesv1alpha1.GitopsServiceSpec {
1768+ Tolerations : []corev1.Toleration {
1769+ {
1770+ Key : "key-a" ,
1771+ Operator : corev1 .TolerationOpEqual ,
1772+ Effect : corev1 .TaintEffectNoSchedule ,
1773+ },
1774+ {
1775+ Key : "key-b" ,
1776+ Operator : corev1 .TolerationOpEqual ,
1777+ Effect : corev1 .TaintEffectNoSchedule ,
1778+ },
1779+ },
1780+ },
1781+ }
1782+
1783+ fakeClient := fake .NewClientBuilder ().WithScheme (s ).WithRuntimeObjects (gitopsService ).Build ()
1784+ reconciler := newReconcileGitOpsService (fakeClient , s )
1785+
1786+ // Create deployment
1787+ _ , err := reconciler .reconcileDeployment (gitopsService , newRequest (serviceNamespace , gitopsPluginName ))
1788+ assertNoError (t , err )
1789+
1790+ // Get the deployment
1791+ deployment := & appsv1.Deployment {}
1792+ err = fakeClient .Get (context .TODO (), types.NamespacedName {Name : gitopsPluginName , Namespace : serviceNamespace }, deployment )
1793+ assertNoError (t , err )
1794+
1795+ // Simulate etcd returning tolerations in different order
1796+ if len (deployment .Spec .Template .Spec .Tolerations ) >= 2 {
1797+ tolerations := deployment .Spec .Template .Spec .Tolerations
1798+ reversedTolerations := make ([]corev1.Toleration , len (tolerations ))
1799+ for i := range tolerations {
1800+ reversedTolerations [len (tolerations )- 1 - i ] = tolerations [i ]
1801+ }
1802+ deployment .Spec .Template .Spec .Tolerations = reversedTolerations
1803+ err = fakeClient .Update (context .TODO (), deployment )
1804+ assertNoError (t , err )
1805+
1806+ err = fakeClient .Get (context .TODO (), types.NamespacedName {Name : gitopsPluginName , Namespace : serviceNamespace }, deployment )
1807+ assertNoError (t , err )
1808+ rvAfterManualUpdate := deployment .ResourceVersion
1809+ genAfterManualUpdate := deployment .Generation
1810+
1811+ // Reconcile again - should NOT trigger an update
1812+ _ , err = reconciler .reconcileDeployment (gitopsService , newRequest (serviceNamespace , gitopsPluginName ))
1813+ assertNoError (t , err )
1814+
1815+ // Verify no update was triggered
1816+ err = fakeClient .Get (context .TODO (), types.NamespacedName {Name : gitopsPluginName , Namespace : serviceNamespace }, deployment )
1817+ assertNoError (t , err )
1818+
1819+ assert .Equal (t , deployment .ResourceVersion , rvAfterManualUpdate ,
1820+ "ResourceVersion should NOT change when only toleration order differs" )
1821+ assert .Equal (t , deployment .Generation , genAfterManualUpdate ,
1822+ "Generation should NOT change when only toleration order differs" )
1823+ } else {
1824+ t .Skip ("Skipping test: deployment has less than 2 tolerations, cannot test order difference" )
1825+ }
1826+ }
1827+
1828+ // Tests that legitimate changes do trigger updates.
1829+ func TestReconcileDeployment_UpdateWhenActualChange (t * testing.T ) {
1830+ s := scheme .Scheme
1831+ addKnownTypesToScheme (s )
1832+
1833+ fakeClient := fake .NewClientBuilder ().WithScheme (s ).WithRuntimeObjects (newGitopsService ()).Build ()
1834+ reconciler := newReconcileGitOpsService (fakeClient , s )
1835+ instance := & pipelinesv1alpha1.GitopsService {}
1836+
1837+ // Create deployment
1838+ _ , err := reconciler .reconcileDeployment (instance , newRequest (serviceNamespace , gitopsPluginName ))
1839+ assertNoError (t , err )
1840+
1841+ // Get the deployment and capture initial ResourceVersion and Generation
1842+ deployment := & appsv1.Deployment {}
1843+ err = fakeClient .Get (context .TODO (), types.NamespacedName {Name : gitopsPluginName , Namespace : serviceNamespace }, deployment )
1844+ assertNoError (t , err )
1845+ initialRV := deployment .ResourceVersion
1846+
1847+ // Make an actual change
1848+ deployment .Spec .Template .Spec .Containers [0 ].Image = "different-image:tag"
1849+ err = fakeClient .Update (context .TODO (), deployment )
1850+ assertNoError (t , err )
1851+
1852+ // Reconcile again - should trigger an update
1853+ _ , err = reconciler .reconcileDeployment (instance , newRequest (serviceNamespace , gitopsPluginName ))
1854+ assertNoError (t , err )
1855+
1856+ // Verify update was triggered
1857+ err = fakeClient .Get (context .TODO (), types.NamespacedName {Name : gitopsPluginName , Namespace : serviceNamespace }, deployment )
1858+ assertNoError (t , err )
1859+
1860+ assert .Assert (t , deployment .ResourceVersion != initialRV ,
1861+ "ResourceVersion SHOULD change when actual change is made" )
1862+ }
0 commit comments