@@ -125,7 +125,7 @@ def test_create_delete_ipv4(self, prefix_list_ipv4, ec2_validator):
125125 assert cr is not None
126126 assert 'status' in cr
127127 assert 'prefixListID' in cr ['status' ]
128-
128+
129129 prefix_list_id = cr ['status' ]['prefixListID' ]
130130 assert prefix_list_id is not None
131131 assert prefix_list_id .startswith ('pl-' )
@@ -136,17 +136,21 @@ def test_create_delete_ipv4(self, prefix_list_ipv4, ec2_validator):
136136 assert state in ['create-in-progress' , 'create-complete' ]
137137
138138 # Wait for AWS to complete creation
139- logging .info (f"Waiting for prefix list { prefix_list_id } to reach create-complete state..." )
140139 state_reached = ec2_validator .wait_managed_prefix_list_state (
141140 prefix_list_id ,
142141 'create-complete' ,
143142 max_wait_seconds = 180
144143 )
145144 assert state_reached , f"Prefix list { prefix_list_id } did not reach create-complete state within timeout"
146145
147- # Get updated resource from K8s
146+ # Wait for K8s controller to sync the state from AWS
147+ assert k8s .wait_on_condition (ref , "ACK.ResourceSynced" , "True" , wait_periods = 30 ), \
148+ "Resource did not sync within timeout"
149+
150+ # Verify final state
148151 cr = k8s .get_resource (ref )
149- assert cr ['status' ]['state' ] == 'create-complete' , f"K8s state is { cr ['status' ]['state' ]} , expected create-complete"
152+ assert cr ['status' ].get ('state' ) == 'create-complete' , \
153+ f"Expected state create-complete, got { cr ['status' ].get ('state' )} "
150154
151155 # Check that version was set
152156 assert 'version' in cr ['status' ]
@@ -160,7 +164,7 @@ def test_create_delete_ipv6(self, prefix_list_ipv6, ec2_validator):
160164 assert cr is not None
161165 assert 'status' in cr
162166 assert 'prefixListID' in cr ['status' ]
163-
167+
164168 prefix_list_id = cr ['status' ]['prefixListID' ]
165169 assert prefix_list_id is not None
166170 assert prefix_list_id .startswith ('pl-' )
@@ -169,41 +173,48 @@ def test_create_delete_ipv6(self, prefix_list_ipv6, ec2_validator):
169173 assert cr ['spec' ]['addressFamily' ] == 'IPv6'
170174
171175 # Wait for AWS to complete creation
172- logging .info (f"Waiting for IPv6 prefix list { prefix_list_id } to reach create-complete state..." )
173176 state_reached = ec2_validator .wait_managed_prefix_list_state (
174177 prefix_list_id ,
175178 'create-complete' ,
176179 max_wait_seconds = 180
177180 )
178181 assert state_reached , f"Prefix list { prefix_list_id } did not reach create-complete state within timeout"
179182
180- # Get updated resource from K8s
183+ # Wait for K8s controller to sync the state from AWS
184+ assert k8s .wait_on_condition (ref , "ACK.ResourceSynced" , "True" , wait_periods = 30 ), \
185+ "Resource did not sync within timeout"
186+
187+ # Verify final state
181188 cr = k8s .get_resource (ref )
182- assert cr ['status' ]['state' ] == 'create-complete' , f"K8s state is { cr ['status' ]['state' ]} , expected create-complete"
189+ assert cr ['status' ].get ('state' ) == 'create-complete' , \
190+ f"Expected state create-complete, got { cr ['status' ].get ('state' )} "
183191
184192 def test_update_entries (self , prefix_list_ipv4 , ec2_validator ):
185- """Test updating prefix list entries."""
193+ """Test adding and removing prefix list entries."""
186194 (ref , cr ) = prefix_list_ipv4
187195
188196 # Get the prefix list ID
189197 assert 'prefixListID' in cr ['status' ], "PrefixListID should be present in status"
190198 prefix_list_id = cr ['status' ]['prefixListID' ]
191199
192200 # Wait for initial creation to complete in AWS
193- logging .info (f"Waiting for prefix list { prefix_list_id } to reach create-complete state before update..." )
194201 state_reached = ec2_validator .wait_managed_prefix_list_state (
195202 prefix_list_id ,
196203 'create-complete' ,
197204 max_wait_seconds = 180
198205 )
199- assert state_reached , f"Prefix list { prefix_list_id } did not reach create-complete state before update"
206+ assert state_reached , f"Prefix list { prefix_list_id } did not reach create-complete state"
207+
208+ # Verify initial state - should have 3 entries
209+ aws_prefix_list = ec2_validator .get_managed_prefix_list (prefix_list_id )
210+ initial_count = len (aws_prefix_list .get ('Entries' , []))
211+ assert initial_count == 3 , f"Expected 3 initial entries, got { initial_count } "
200212
201- # Get the latest resource with the initial version
213+ # Get the latest resource
202214 cr = k8s .get_resource (ref )
203215 assert cr ['status' ]['state' ] == 'create-complete' , f"K8s state is { cr ['status' ]['state' ]} , expected create-complete"
204- initial_version = cr ['status' ]['version' ]
205216
206- # Update the entries - add a new CIDR block
217+ # ===== TEST 1: Add an entry (3 → 4) =====
207218 cr ['spec' ]['entries' ].append ({
208219 'cidr' : '10.0.2.0/24' ,
209220 'description' : 'New network C'
@@ -212,55 +223,69 @@ def test_update_entries(self, prefix_list_ipv4, ec2_validator):
212223 # Apply the update
213224 k8s .patch_custom_resource (ref , cr )
214225
215- # Wait for the prefix list to complete modification in AWS
216- # This can take some time as AWS needs to propagate the changes
217- logging .info (f"Waiting for prefix list { prefix_list_id } to reach modify-complete state..." )
226+ # Give AWS time to process the async modification
227+ time .sleep (UPDATE_WAIT_AFTER_SECONDS )
228+
229+ # Wait for the controller to process and sync the change
230+ assert k8s .wait_on_condition (ref , "ACK.ResourceSynced" , "True" , wait_periods = 40 ), \
231+ "Resource did not sync after add"
232+
233+ # Now wait for AWS to complete the modification
234+ state_reached = ec2_validator .wait_managed_prefix_list_state (
235+ prefix_list_id ,
236+ 'modify-complete' ,
237+ max_wait_seconds = 180
238+ )
239+ assert state_reached , f"Prefix list { prefix_list_id } did not reach modify-complete state after add"
240+
241+ # Verify in AWS
242+ aws_prefix_list = ec2_validator .get_managed_prefix_list (prefix_list_id )
243+ after_add_count = len (aws_prefix_list .get ('Entries' , []))
244+ assert after_add_count == 4 , f"Expected 4 entries after add, got { after_add_count } "
245+
246+ # ===== TEST 2: Remove an entry (4 → 3) =====
247+ cr = k8s .get_resource (ref )
248+ original_entries = cr ['spec' ]['entries' ][:]
249+
250+ # Remove the entry we just added
251+ entry_to_remove = '10.0.2.0/24'
252+ cr ['spec' ]['entries' ] = [e for e in original_entries if e ['cidr' ] != entry_to_remove ]
253+
254+ # Apply the update
255+ k8s .patch_custom_resource (ref , cr )
256+
257+ # Give AWS time to process the async modification
258+ time .sleep (UPDATE_WAIT_AFTER_SECONDS )
259+
260+ # Wait for the controller to process and sync the change
261+ assert k8s .wait_on_condition (ref , "ACK.ResourceSynced" , "True" , wait_periods = 40 ), \
262+ "Resource did not sync after removal"
263+
264+ # Now wait for AWS to complete the modification
218265 state_reached = ec2_validator .wait_managed_prefix_list_state (
219266 prefix_list_id ,
220267 'modify-complete' ,
221268 max_wait_seconds = 180
222269 )
223- assert state_reached , f"Prefix list { prefix_list_id } did not reach modify-complete state within timeout"
224-
225- # Wait for the controller to sync the status from AWS to K8s
226- # Poll K8s status until version is incremented AND state is modify-complete
227- logging .info (f"Waiting for K8s controller to sync updated version and state from AWS..." )
228- version_updated = False
229- state_updated = False
230- max_sync_tries = 30 # 30 * 5 = 150 seconds
231- for try_num in range (max_sync_tries ):
232- cr = k8s .get_resource (ref )
233- current_state = cr ['status' ].get ('state' , '' )
234- if 'version' in cr ['status' ]:
235- current_version = cr ['status' ]['version' ]
236- if current_version > initial_version and current_state == 'modify-complete' :
237- version_updated = True
238- state_updated = True
239- updated_version = current_version
240- logging .info (f"Version updated from { initial_version } to { updated_version } and state is { current_state } after { try_num * 5 } seconds" )
241- break
242- elif current_version > initial_version :
243- logging .info (f"Version updated to { current_version } but state is still { current_state } , waiting..." )
244- time .sleep (5 )
245-
246- assert version_updated , \
247- f"K8s status version did not increment from { initial_version } within { max_sync_tries * 5 } seconds"
248-
249- assert state_updated , \
250- f"K8s status state did not reach modify-complete within { max_sync_tries * 5 } seconds, last state: { cr ['status' ].get ('state' , 'unknown' )} "
251-
252- # Check that version was incremented
253- assert updated_version > initial_version , \
254- f"Version should have incremented from { initial_version } to greater value, got { updated_version } "
255-
256- # Verify entries were updated in K8s spec
257- assert len (cr ['spec' ]['entries' ]) == 4 , \
258- f"Expected 4 entries (3 original + 1 new), got { len (cr ['spec' ]['entries' ])} "
259-
260- # Verify entries in AWS
270+ assert state_reached , f"Prefix list { prefix_list_id } did not reach modify-complete state after removal"
271+
272+ # Verify in AWS
261273 aws_prefix_list = ec2_validator .get_managed_prefix_list (prefix_list_id )
262- assert aws_prefix_list ['Version' ] == updated_version , \
263- f"AWS version { aws_prefix_list ['Version' ]} should match K8s version { updated_version } "
274+ after_remove_entries = aws_prefix_list .get ('Entries' , [])
275+ after_remove_count = len (after_remove_entries )
276+ aws_cidrs = [e ['Cidr' ] for e in after_remove_entries ]
277+
278+ # Verify deletion happened
279+ assert after_remove_count == 3 , f"Expected 3 entries after removal, got { after_remove_count } "
280+ assert entry_to_remove not in aws_cidrs , \
281+ f"Entry { entry_to_remove } should have been removed but is still in AWS: { aws_cidrs } "
282+
283+ # Final verification - check K8s matches AWS
284+ cr = k8s .get_resource (ref )
285+ k8s_cidrs = [e ['cidr' ] for e in cr ['spec' ].get ('entries' , [])]
286+ assert len (k8s_cidrs ) == 3 , f"Expected 3 entries in K8s, got { len (k8s_cidrs )} "
287+ assert entry_to_remove not in k8s_cidrs , \
288+ f"Entry { entry_to_remove } should not be in K8s: { k8s_cidrs } "
264289
265290 def test_update_tags (self , prefix_list_ipv4 ):
266291 """Test updating prefix list tags."""
@@ -282,9 +307,13 @@ def test_update_tags(self, prefix_list_ipv4):
282307 k8s .patch_custom_resource (ref , cr )
283308 time .sleep (UPDATE_WAIT_AFTER_SECONDS )
284309
310+ # Wait for the resource to be synced
311+ assert k8s .wait_on_condition (ref , "ACK.ResourceSynced" , "True" , wait_periods = 5 ), \
312+ "Resource did not sync after tag update"
313+
285314 # Get the updated resource
286315 cr = k8s .get_resource (ref )
287-
316+
288317 # Verify tag was added
289318 tags = cr ['spec' ].get ('tags' , [])
290319 assert any (tag ['key' ] == 'Environment' and tag ['value' ] == 'Test' for tag in tags )
0 commit comments