Skip to content

Commit b728a92

Browse files
authored
[6.19.z] improved rex UI tests reliability (#22276)
1 parent 128319d commit b728a92

1 file changed

Lines changed: 91 additions & 60 deletions

File tree

tests/foreman/ui/test_remoteexecution.py

Lines changed: 91 additions & 60 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@
2121
from wait_for import wait_for
2222

2323
from robottelo.config import settings
24-
from robottelo.constants import ANY_CONTEXT
24+
from robottelo.constants import ANY_CONTEXT, DEFAULT_LOC
2525
from robottelo.utils.datafactory import (
2626
gen_string,
2727
valid_hostgroups_list_short,
@@ -98,7 +98,6 @@ def test_positive_hostgroups_full_nested_names(
9898

9999
@pytest.mark.rhel_ver_list([settings.content_host.default_rhel_version])
100100
def test_positive_run_default_job_template(
101-
session,
102101
target_sat,
103102
rex_contenthost,
104103
module_org,
@@ -129,7 +128,15 @@ def test_positive_run_default_job_template(
129128

130129
with target_sat.ui_session() as session:
131130
session.organization.select(module_org.name)
132-
assert session.host.search(hostname)[0]['Name'] == hostname
131+
session.location.select(loc_name=DEFAULT_LOC)
132+
# Search with retry to handle potential context/indexing delays
133+
result = wait_for(
134+
lambda: session.all_hosts.search(f"name = {hostname}"),
135+
timeout=30,
136+
delay=2,
137+
fail_condition=[],
138+
).out
139+
assert result[0]['Name'] == hostname
133140
command = 'ls'
134141
session.jobinvocation.run(
135142
{
@@ -153,7 +160,7 @@ def test_positive_run_default_job_template(
153160

154161

155162
@pytest.mark.rhel_ver_list([settings.content_host.default_rhel_version])
156-
def test_rex_through_host_details(session, target_sat, rex_contenthost, module_org):
163+
def test_rex_through_host_details(target_sat, rex_contenthost, module_org):
157164
"""Run remote execution using the new host details page
158165
159166
:id: ee625595-4995-43b2-9e6d-633c9b33ff93
@@ -185,7 +192,17 @@ def test_rex_through_host_details(session, target_sat, rex_contenthost, module_o
185192
)
186193
task_status = target_sat.api.ForemanTask(id=task_result[0].id).poll()
187194
assert task_status['result'] == 'success'
188-
recent_jobs = session.host_new.get_details(hostname, "overview.recent_jobs")['overview']
195+
196+
# Wait for recent jobs table to load with job data
197+
recent_jobs = wait_for(
198+
lambda: session.host_new.get_details(hostname, "overview.recent_jobs")['overview'],
199+
timeout=30,
200+
delay=2,
201+
fail_condition=lambda result: (
202+
not result.get('recent_jobs', {}).get('finished', {}).get('table')
203+
),
204+
).out
205+
189206
assert recent_jobs['recent_jobs']['finished']['table'][0]['column0'] == "Run ls"
190207
assert recent_jobs['recent_jobs']['finished']['table'][0]['column2'] == "succeeded"
191208

@@ -195,7 +212,7 @@ def test_rex_through_host_details(session, target_sat, rex_contenthost, module_o
195212
'ui_user', [{'admin': True}, {'admin': False}], indirect=True, ids=['adminuser', 'nonadminuser']
196213
)
197214
def test_positive_run_custom_job_template(
198-
session, module_org, default_location, target_sat, ui_user, rex_contenthost
215+
module_org, default_location, target_sat, ui_user, rex_contenthost
199216
):
200217
"""Run a job template on a host
201218
@@ -226,7 +243,15 @@ def test_positive_run_custom_job_template(
226243
job_template_name = gen_string('alpha')
227244
with target_sat.ui_session() as session:
228245
session.organization.select(module_org.name)
229-
assert session.host.search(hostname)[0]['Name'] == hostname
246+
session.location.select(default_location.name)
247+
# Search with retry to handle potential context/indexing delays
248+
result = wait_for(
249+
lambda: session.all_hosts.search(f"name = {hostname}"),
250+
timeout=30,
251+
delay=2,
252+
fail_condition=[],
253+
).out
254+
assert result[0]['Name'] == hostname
230255
session.jobtemplate.create(
231256
{
232257
'template.name': job_template_name,
@@ -255,9 +280,7 @@ def test_positive_run_custom_job_template(
255280

256281
@pytest.mark.upgrade
257282
@pytest.mark.rhel_ver_list([settings.content_host.default_rhel_version])
258-
def test_positive_run_job_template_multiple_hosts(
259-
session, module_org, target_sat, rex_contenthosts
260-
):
283+
def test_positive_run_job_template_multiple_hosts(module_org, target_sat, rex_contenthosts):
261284
"""Run a job template against multiple hosts
262285
263286
:id: c4439ec0-bb80-47f6-bc31-fa7193bfbeeb
@@ -268,7 +291,7 @@ def test_positive_run_job_template_multiple_hosts(
268291
269292
1. Set remote_execution_connect_by_ip on hosts to true
270293
2. Navigate to the hosts page and select at least two hosts
271-
3. Click the "Select Action"
294+
3. Click the "Schedule a job"
272295
4. Select the job and appropriate template
273296
5. Run the job
274297
@@ -282,9 +305,15 @@ def test_positive_run_job_template_multiple_hosts(
282305
with target_sat.ui_session() as session:
283306
session.organization.select(module_org.name)
284307
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(
308+
# Search with retry to handle potential context/indexing delays
309+
result = wait_for(
310+
lambda h=host: session.all_hosts.search(f"name = {h}"),
311+
timeout=30,
312+
delay=2,
313+
fail_condition=[],
314+
).out
315+
assert result[0]['Name'] == host
316+
job_status = session.host_new.schedule_remote_job(
288317
host_names,
289318
{
290319
'category_and_template.job_category': 'Commands',
@@ -298,7 +327,7 @@ def test_positive_run_job_template_multiple_hosts(
298327

299328

300329
@pytest.mark.rhel_ver_list([settings.content_host.default_rhel_version])
301-
def test_positive_run_scheduled_job_template_by_ip(session, module_org, rex_contenthost):
330+
def test_positive_run_scheduled_job_template_by_ip(module_org, target_sat, rex_contenthost):
302331
"""Schedule a job to be ran against a host by ip
303332
304333
:id: 4387bed9-969d-45fb-80c2-b0905bb7f1bd
@@ -323,13 +352,20 @@ def test_positive_run_scheduled_job_template_by_ip(session, module_org, rex_cont
323352
"""
324353
job_time = 6 * 60
325354
hostname = rex_contenthost.hostname
326-
with session:
355+
with target_sat.ui_session() as session:
327356
session.organization.select(module_org.name)
328-
session.location.select('Default Location')
329-
assert session.host.search(hostname)[0]['Name'] == hostname
357+
session.location.select(loc_name=DEFAULT_LOC)
358+
# Search with retry to handle potential context/indexing delays
359+
result = wait_for(
360+
lambda: session.all_hosts.search(f"name = {hostname}"),
361+
timeout=30,
362+
delay=2,
363+
fail_condition=[],
364+
).out
365+
assert result[0]['Name'] == hostname
330366
plan_time = session.browser.get_client_datetime() + datetime.timedelta(seconds=job_time)
331367
command_to_run = 'sleep 10'
332-
job_status = session.host.schedule_remote_job(
368+
job_status = session.host_new.schedule_remote_job(
333369
[hostname],
334370
{
335371
'category_and_template.job_category': 'Commands',
@@ -341,52 +377,47 @@ def test_positive_run_scheduled_job_template_by_ip(session, module_org, rex_cont
341377
},
342378
wait_for_results=False,
343379
)
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
380+
# Track state transitions through polling
346381
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
350-
assert job_status['hosts'][0]['Name'] == hostname
351-
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')
382+
assert job_left_time > 0, "Job scheduled time already passed during creation"
383+
355384
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-
)
385+
assert job_status['hosts'][0]['Status'] in ('Awaiting start', 'Scheduled')
386+
387+
# Poll for state transitions and record them
388+
observed_states = [job_status['hosts'][0]['Status']]
389+
poll_timeout = job_left_time + 60 # Extra buffer for job execution
390+
poll_start = time.time()
391+
392+
while time.time() - poll_start < poll_timeout:
393+
job_status = session.jobinvocation.read(f'Run {command_to_run}', hostname, 'hosts')
394+
current_status = job_status['hosts'][0]['Status']
395+
396+
# Record state changes
397+
if current_status != observed_states[-1]:
398+
observed_states.append(current_status)
399+
400+
# Exit when job completes
401+
if current_status in ('Succeeded', 'Failed', 'Cancelled'):
402+
break
403+
404+
time.sleep(2)
405+
406+
# Read final complete status
386407
job_status = session.jobinvocation.read(f'Run {command_to_run}', hostname)
408+
final_status = job_status['hosts'][0]['Status']
409+
if final_status != observed_states[-1]:
410+
observed_states.append(final_status)
411+
412+
# Verify state progression
413+
# Expected: Awaiting start/Scheduled -> Running/Pending -> Succeeded
414+
assert 'Succeeded' in observed_states, f"Job never succeeded. States: {observed_states}"
415+
416+
has_pre_run_state = any(s in ('Awaiting start', 'Scheduled') for s in observed_states[:-1])
417+
assert has_pre_run_state, f"Missing pre-run state. States: {observed_states}"
418+
387419
assert job_status['overall_status']['is_success']
388420
assert job_status['hosts'][0]['Name'] == hostname
389-
assert job_status['hosts'][0]['Status'] == 'Succeeded'
390421

391422

392423
@pytest.mark.rhel_ver_list([settings.content_host.default_rhel_version])

0 commit comments

Comments
 (0)