@@ -129,7 +129,15 @@ def test_positive_run_default_job_template(
129129
130130 with target_sat .ui_session () as session :
131131 session .organization .select (module_org .name )
132- assert session .host .search (hostname )[0 ]['Name' ] == hostname
132+ session .location .select ('Default Location' )
133+ # Search with retry to handle potential context/indexing delays
134+ result = wait_for (
135+ lambda : session .all_hosts .search (hostname ),
136+ timeout = 30 ,
137+ delay = 2 ,
138+ fail_condition = [],
139+ ).out
140+ assert result [0 ]['Name' ] == hostname
133141 command = 'ls'
134142 session .jobinvocation .run (
135143 {
@@ -185,7 +193,17 @@ def test_rex_through_host_details(session, target_sat, rex_contenthost, module_o
185193 )
186194 task_status = target_sat .api .ForemanTask (id = task_result [0 ].id ).poll ()
187195 assert task_status ['result' ] == 'success'
188- recent_jobs = session .host_new .get_details (hostname , "overview.recent_jobs" )['overview' ]
196+
197+ # Wait for recent jobs table to load with job data
198+ recent_jobs = wait_for (
199+ lambda : session .host_new .get_details (hostname , "overview.recent_jobs" )['overview' ],
200+ timeout = 30 ,
201+ delay = 2 ,
202+ fail_condition = lambda result : (
203+ not result .get ('recent_jobs' , {}).get ('finished' , {}).get ('table' )
204+ ),
205+ ).out
206+
189207 assert recent_jobs ['recent_jobs' ]['finished' ]['table' ][0 ]['column0' ] == "Run ls"
190208 assert recent_jobs ['recent_jobs' ]['finished' ]['table' ][0 ]['column2' ] == "succeeded"
191209
@@ -226,7 +244,15 @@ def test_positive_run_custom_job_template(
226244 job_template_name = gen_string ('alpha' )
227245 with target_sat .ui_session () as session :
228246 session .organization .select (module_org .name )
229- assert session .host .search (hostname )[0 ]['Name' ] == hostname
247+ session .location .select (default_location .name )
248+ # Search with retry to handle potential context/indexing delays
249+ result = wait_for (
250+ lambda : session .all_hosts .search (hostname ),
251+ timeout = 30 ,
252+ delay = 2 ,
253+ fail_condition = [],
254+ ).out
255+ assert result [0 ]['Name' ] == hostname
230256 session .jobtemplate .create (
231257 {
232258 'template.name' : job_template_name ,
@@ -268,7 +294,7 @@ def test_positive_run_job_template_multiple_hosts(
268294
269295 1. Set remote_execution_connect_by_ip on hosts to true
270296 2. Navigate to the hosts page and select at least two hosts
271- 3. Click the "Select Action "
297+ 3. Click the "Schedule a job "
272298 4. Select the job and appropriate template
273299 5. Run the job
274300
@@ -282,9 +308,15 @@ def test_positive_run_job_template_multiple_hosts(
282308 with target_sat .ui_session () as session :
283309 session .organization .select (module_org .name )
284310 for host in host_names :
285- assert session .host .search (host )[0 ]['Name' ] == host
286- session .host .reset_search ()
287- job_status = session .host .schedule_remote_job (
311+ # Search with retry to handle potential context/indexing delays
312+ result = wait_for (
313+ lambda h = host : session .all_hosts .search (h ),
314+ timeout = 30 ,
315+ delay = 2 ,
316+ fail_condition = [],
317+ ).out
318+ assert result [0 ]['Name' ] == host
319+ job_status = session .host_new .schedule_remote_job (
288320 host_names ,
289321 {
290322 'category_and_template.job_category' : 'Commands' ,
@@ -326,10 +358,17 @@ def test_positive_run_scheduled_job_template_by_ip(session, module_org, rex_cont
326358 with session :
327359 session .organization .select (module_org .name )
328360 session .location .select ('Default Location' )
329- assert session .host .search (hostname )[0 ]['Name' ] == hostname
361+ # Search with retry to handle potential context/indexing delays
362+ result = wait_for (
363+ lambda : session .all_hosts .search (hostname ),
364+ timeout = 30 ,
365+ delay = 2 ,
366+ fail_condition = [],
367+ ).out
368+ assert result [0 ]['Name' ] == hostname
330369 plan_time = session .browser .get_client_datetime () + datetime .timedelta (seconds = job_time )
331370 command_to_run = 'sleep 10'
332- job_status = session .host .schedule_remote_job (
371+ job_status = session .host_new .schedule_remote_job (
333372 [hostname ],
334373 {
335374 'category_and_template.job_category' : 'Commands' ,
@@ -341,52 +380,55 @@ def test_positive_run_scheduled_job_template_by_ip(session, module_org, rex_cont
341380 },
342381 wait_for_results = False ,
343382 )
344- # Note that to create this host scheduled job we spent some time from that plan_time, as it
345- # was calculated before creating the job
383+ # Track state transitions through polling
346384 job_left_time = (plan_time - session .browser .get_client_datetime ()).total_seconds ()
347- # assert that we have time left to wait, otherwise we have to use more job time,
348- # the job_time must be significantly greater than job creation time.
349- assert job_left_time > 0
385+ assert job_left_time > 0 , "Job scheduled time already passed during creation"
386+
387+ # Initial state: should be waiting to start
350388 assert job_status ['hosts' ][0 ]['Name' ] == hostname
351389 assert job_status ['hosts' ][0 ]['Status' ] in ('Awaiting start' , 'N/A' )
352- # sleep 3/4 of the left time
353- time .sleep (job_left_time * 3 / 4 )
354- job_status = session .jobinvocation .read (f'Run { command_to_run } ' , hostname , 'hosts' )
355- assert job_status ['hosts' ][0 ]['Name' ] == hostname
356- assert job_status ['hosts' ][0 ]['Status' ] in (
357- 'Awaiting start' ,
358- 'N/A' ,
359- 'Succeeded' ,
360- )
361- # recalculate the job left time to be more accurate
362- job_left_time = (plan_time - session .browser .get_client_datetime ()).total_seconds ()
363- # the last read time should not take more than 1/4 of the last left time
364- assert job_left_time > 0
365- wait_for (
366- lambda : (
367- session .jobinvocation .read (f'Run { command_to_run } ' , hostname , 'hosts' )['hosts' ][0 ][
368- 'Status'
369- ]
370- == 'Pending'
371- ),
372- timeout = (job_left_time + 30 ),
373- delay = 1 ,
374- )
375- # wait the job to change status to "Succeeded"
376- wait_for (
377- lambda : (
378- session .jobinvocation .read (f'Run { command_to_run } ' , hostname , 'hosts' )['hosts' ][0 ][
379- 'Status'
380- ]
381- == 'Succeeded'
382- ),
383- timeout = 30 ,
384- delay = 1 ,
385- )
390+
391+ # Poll for state transitions and record them
392+ observed_states = [job_status ['hosts' ][0 ]['Status' ]]
393+ poll_timeout = job_left_time + 60 # Extra buffer for job execution
394+ poll_start = time .time ()
395+
396+ while time .time () - poll_start < poll_timeout :
397+ job_status = session .jobinvocation .read (f'Run { command_to_run } ' , hostname , 'hosts' )
398+ current_status = job_status ['hosts' ][0 ]['Status' ]
399+
400+ # Record state changes
401+ if current_status != observed_states [- 1 ]:
402+ observed_states .append (current_status )
403+
404+ # Exit when job completes
405+ if current_status in ('Succeeded' , 'Failed' , 'Cancelled' ):
406+ break
407+
408+ time .sleep (2 )
409+
410+ # Read final complete status
386411 job_status = session .jobinvocation .read (f'Run { command_to_run } ' , hostname )
412+ final_status = job_status ['hosts' ][0 ]['Status' ]
413+ if final_status != observed_states [- 1 ]:
414+ observed_states .append (final_status )
415+
416+ # Verify state progression
417+ # Expected: Awaiting start/N/A -> Running/Pending -> Succeeded
418+ assert 'Succeeded' in observed_states , f"Job never succeeded. States: { observed_states } "
419+ assert observed_states [- 1 ] == 'Succeeded' , f"Final state not Succeeded: { observed_states } "
420+
421+ # Verify it went through a running state (not immediate execution)
422+ has_pre_run_state = any (s in ('Awaiting start' , 'N/A' ) for s in observed_states [:- 1 ])
423+ has_running_state = any (s in ('Pending' , 'Running' ) for s in observed_states )
424+ assert has_pre_run_state , f"Missing pre-run state. States: { observed_states } "
425+ assert has_running_state or len (observed_states ) == 2 , (
426+ f"Job should go through running state or transition directly. States: { observed_states } "
427+ )
428+
429+ # Final assertions
387430 assert job_status ['overall_status' ]['is_success' ]
388431 assert job_status ['hosts' ][0 ]['Name' ] == hostname
389- assert job_status ['hosts' ][0 ]['Status' ] == 'Succeeded'
390432
391433
392434@pytest .mark .rhel_ver_list ([settings .content_host .default_rhel_version ])
0 commit comments