| ############################################################################ | |
| # Copyright (C) SchedMD LLC. | |
| ############################################################################ | |
| import pytest | |
| import atf | |
| # Setup | |
| @pytest.fixture(scope="module", autouse=True) | |
| def setup(): | |
| atf.require_nodes(2, [("ThreadsPerCore", 2), ("Cores", 4), ("Sockets", 1)]) | |
| atf.require_slurm_running() | |
| @pytest.mark.xfail( | |
| atf.get_version() < (26, 5) | |
| and atf.get_config_parameter("SelectType", live=False) != "select/linear", | |
| reason="Ticket 20799: Concurrent steps are not started and identified correctly", | |
| ) | |
| def test_no_missing_step(): | |
| """ | |
| This test confirms steps 0 and 1 are run concurrently, and that step 2 is | |
| queued while they hold the resources and then runs as soon as they free up, | |
| keeping the same step id it was assigned at submission. | |
| """ | |
| atf.make_bash_script( | |
| "my_script.sh", | |
| """ | |
| srun -l -n 3 --hint=nomultithread --distribution=pack --exact sleep 20 & | |
| sleep 3 | |
| srun -l -n 3 --hint=nomultithread --distribution=pack --exact sleep 10 & | |
| sleep 3 | |
| srun -l -n 2 --hint=nomultithread --distribution=pack --exact sleep 10 & | |
| wait $(jobs -p) | |
| """, | |
| ) | |
| job_id = atf.submit_job_sbatch("-N2 -n16 my_script.sh", fatal=True) | |
| # Issue 50938: as of 26.11 a queued step is assigned its real StepId at | |
| # submission, so the third step is visible as <jobid>.2 in PENDING while it | |
| # waits. Before 26.11 it had no id until it launched. | |
| id_at_submit = atf.get_version("bin/srun") >= (26, 11) | |
| def _state(steps, step_id): | |
| return steps.get(f"{job_id}.{step_id}", {}).get("State") | |
| # The first two steps run in parallel while the third is queued. | |
| steps = {} | |
| for _ in atf.timer(): | |
| steps = atf.get_steps(job_id) | |
| if ( | |
| _state(steps, 0) == "RUNNING" | |
| and _state(steps, 1) == "RUNNING" | |
| and ( | |
| _state(steps, 2) == "PENDING" | |
| if id_at_submit | |
| else f"{job_id}.2" not in steps | |
| ) | |
| ): | |
| break | |
| else: | |
| assert False, ( | |
| f"First two steps should run in parallel before the third one, " | |
| f"got {steps}" | |
| ) | |
| # The third step runs as soon as the second ends, so in parallel with the | |
| # first one. | |
| for _ in atf.timer(): | |
| steps = atf.get_steps(job_id) | |
| if ( | |
| _state(steps, 0) == "RUNNING" | |
| and f"{job_id}.1" not in steps | |
| and _state(steps, 2) == "RUNNING" | |
| ): | |
| break | |
| else: | |
| assert ( | |
| False | |
| ), f"The third step should run as soon as the second ends, got {steps}" |