blob: 2713befabb8157e9d49413243bd5413fb9d677ff [file]
############################################################################
# Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
############################################################################
import pytest
import atf
@pytest.fixture(scope="module", autouse=True)
def setup():
atf.require_config_parameter(
"PartitionName",
{
"p1": {"Nodes": "ALL", "OverSubscribe": "YES", "Default": "YES"},
"p2": {"Nodes": "ALL", "OverSubscribe": "YES"},
},
)
# Allow more than 4 jobs in terms of memory
atf.require_nodes(1, [("CPUs", 1), ("RealMemory", 2048)])
atf.require_config_parameter("DefMemPerNode", 256)
atf.require_slurm_running()
def test_oversubscribe_only():
"""
Verify behavior of --oversubscribe option.
Submits a job with --oversubscribe and --hold, then checks job parameters.
"""
job_id = atf.submit_job_sbatch(
"--oversubscribe --hold -t1 --wrap='sleep infinity'", fatal=True
)
# Issue 20588 (26.05): scontrol may show OverSubscribe=OK instead of YES.
expected = {"YES", "OK"} if atf.get_version() >= (26, 5) else {"YES"}
assert (
atf.get_job_parameter(job_id, "OverSubscribe") in expected
), f"OverSubscribe flag should be one of {expected}"
assert (
atf.get_job_parameter(job_id, "Contiguous") == 0
), "Contiguous flag should be 0"
def test_contiguous_only():
"""
Verify behavior of --contiguous option.
Submits a job with --contiguous and --hold, then checks job parameters.
"""
job_id = atf.submit_job_sbatch(
"--contiguous --hold -t1 --wrap='sleep infinity'", fatal=True
)
# A non-shareable job shows OverSubscribe=NO, or OK on 26.05+ (Issue 20588).
assert atf.get_job_parameter(job_id, "OverSubscribe") in {
"NO",
"OK",
}, "OverSubscribe flag should be 'NO' or 'OK'"
assert (
atf.get_job_parameter(job_id, "Contiguous") == 1
), "Contiguous flag should be 1"
def test_overlapping_oversubscribe():
"""
Jobs without -s on overlapping OverSubscribe=YES partitions shouldn't run concurrently.
"""
# Submit first job to p1 without --oversubscribe
job_id1 = atf.submit_job_sbatch("-p p1 --wrap='sleep infinity'", fatal=True)
# Wait for job 1 to start running
atf.wait_for_job_state(job_id1, "RUNNING", fatal=True)
# Submit second job to p2 without --oversubscribe
job_id2 = atf.submit_job_sbatch("-p p2 --wrap='sleep infinity'", fatal=True)
# Verify job 2 is PENDING with Reason=Resources
assert atf.wait_for_job_state(
job_id2,
"PENDING",
"Resources",
), "Job2 should be PENDING due Resources"
# Verify job 1 is still running
assert (
atf.get_job_parameter(job_id1, "JobState") == "RUNNING"
), "Job 1 should still be RUNNING"
def test_overlapping_oversubscribe_sharing_restriction_1():
"""
Job with -s should be blocked if a non -s job is running on overlapping partition.
"""
# Submit first job to p2 without --oversubscribe
job_id1 = atf.submit_job_sbatch("-p p2 --wrap='sleep infinity'", fatal=True)
# Wait for job 1 to start running
atf.wait_for_job_state(job_id1, "RUNNING", fatal=True)
# Submit second job to p1 *with* --oversubscribe
job_id2 = atf.submit_job_sbatch(
"-p p1 --oversubscribe --wrap='sleep infinity'", fatal=True
)
# Verify job 2 is PENDING with Reason=Resources
assert atf.wait_for_job_state(
job_id2,
"PENDING",
"Resources",
), "Job2 should be PENDING due Resources"
# Verify job 1 is still running
assert (
atf.get_job_parameter(job_id1, "JobState") == "RUNNING"
), "Job 1 should still be RUNNING"
def test_overlapping_oversubscribe_sharing_restriction_2():
"""
Job without -s should be blocked if a job with -s is running on overlapping partition.
"""
# Submit first job to p2 *with* --oversubscribe
job_id1 = atf.submit_job_sbatch(
"-p p2 --oversubscribe --wrap='sleep infinity'", fatal=True
)
# Wait for job 1 to start running
atf.wait_for_job_state(job_id1, "RUNNING", fatal=True)
# Submit second job to p1 *without* --oversubscribe
job_id2 = atf.submit_job_sbatch("-p p1 --wrap='sleep infinity'", fatal=True)
# Verify job 2 is PENDING with Reason=Resources
assert atf.wait_for_job_state(
job_id2,
"PENDING",
"Resources",
), "Job2 should be PENDING due Resources"
# Verify job 1 is still running
assert (
atf.get_job_parameter(job_id1, "JobState") == "RUNNING"
), "Job 1 should still be RUNNING"
def test_oversubscribe_same_partition():
"""
Test that two jobs *with* --oversubscribe can run on the same node
if they are in the same partition (p1).
"""
# Submit first job to p1 with --oversubscribe
job_id1 = atf.submit_job_sbatch(
"-p p1 --oversubscribe --wrap='sleep infinity'", fatal=True
)
# Wait for job 1 to start running
atf.wait_for_job_state(job_id1, "RUNNING", fatal=True)
node1 = atf.get_job_parameter(job_id1, "NodeList")
# Submit second job to p1 *with* --oversubscribe
job_id2 = atf.submit_job_sbatch(
"-p p1 --oversubscribe --wrap='sleep infinity'", fatal=True
)
# Wait for job 2 to start running (should run concurrently)
atf.wait_for_job_state(job_id2, "RUNNING", fatal=True)
node2 = atf.get_job_parameter(job_id2, "NodeList")
# Sanity check
if node1 is None or node2 is None:
pytest.fail(f"Both nodes should be specified but got {node1} and {node2}")
# Verify both jobs are running on the same node
assert node1 == node2, f"Jobs should run on the same node ({node1} vs {node2})"