Skip to content

Commit a6d2763

Browse files
committed
improved rex UI tests reliability
1 parent e4f0dc2 commit a6d2763

1 file changed

Lines changed: 91 additions & 49 deletions

File tree

tests/foreman/ui/test_remoteexecution.py

Lines changed: 91 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -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

Comments
 (0)