blob: 55a92ca3699379e6cd7083f65c24915981dc883e [file] [edit]
############################################################################
# Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
############################################################################
"""Test jobcomp/kafka job start and end records on separate topics."""
import json
import logging
import random
import pytest
import atf
kafka = pytest.importorskip("kafka")
logging.getLogger("kafka").setLevel(logging.WARNING)
topic = f"slurm-qa-{random.randrange(0, 999999999)}-end"
topic_start = f"slurm-qa-{random.randrange(0, 999999999)}-start"
@pytest.fixture(scope="module", autouse=True)
def setup():
atf.require_version(
(25, 5),
component="sbin/slurmctld",
reason="Issue 50120: jobcomp/kafka enable_job_start and topic_job_start require 25.05+",
)
atf.require_build_config("HAVE_RDKAFKA")
try:
kafka.KafkaConsumer(bootstrap_servers=["localhost:9092"]).close()
except kafka.errors.NoBrokersAvailable as e:
pytest.skip(f"Kafka server not available at localhost:9092: {e}")
atf.require_config_parameter("JobCompType", "jobcomp/kafka")
atf.require_config_parameter(
"JobCompParams",
f"topic={topic},enable_job_start,topic_job_start={topic_start}",
)
k_conf_path = atf.properties["slurm-config-dir"] + f"/{topic}.conf"
atf.require_config_parameter("JobCompLoc", k_conf_path)
atf.require_config_parameter_includes(
"bootstrap.servers", "localhost:9092", source=topic
)
atf.require_slurm_running()
def test_kafka_basic_functionality():
"""Test that jobcomp/kafka tracks job start and termination"""
job_id = atf.submit_job_sbatch(
"--wrap 'while [ ! -f job_release ]; do sleep 1; done'", fatal=True
)
atf.wait_for_job_state(job_id, "RUNNING", fatal=True)
try:
consumer = kafka.KafkaConsumer(
topic_start,
bootstrap_servers=["localhost:9092"],
group_id=None,
auto_offset_reset="earliest",
consumer_timeout_ms=30000,
)
except Exception as e:
pytest.fail(f"Error connecting to Kafka: {e}")
message = next(consumer, None)
assert message is not None, f"No job start record received on topic {topic_start}"
try:
data = json.loads(message.value.decode("utf-8"))
except Exception as e:
pytest.fail(f"Failed to decode or parse JSON: {e}")
assert job_id == data.get(
"jobid"
), f"Expected jobid={job_id} in the job start record, got {data.get('jobid')}"
if atf.get_version() >= (26, 11):
assert data.get("state") in (
"RUNNING",
"CONFIGURING",
), f"Expected state RUNNING or CONFIGURING in the job start record, got {data.get('state')}"
else:
assert (
data.get("state") is None
), f"Expected no state in the job start record, got {data.get('state')}"
atf.run_command("touch job_release", fatal=True)
atf.wait_for_job_state(job_id, "DONE", fatal=True)
try:
consumer = kafka.KafkaConsumer(
topic,
bootstrap_servers=["localhost:9092"],
group_id=None,
auto_offset_reset="earliest",
consumer_timeout_ms=30000,
)
except Exception as e:
pytest.fail(f"Error connecting to Kafka: {e}")
message = next(consumer, None)
assert message is not None, f"No job end record received on topic {topic}"
try:
data = json.loads(message.value.decode("utf-8"))
except Exception as e:
pytest.fail(f"Failed to decode or parse JSON: {e}")
assert job_id == data.get(
"jobid"
), f"Expected jobid={job_id} in the job end record, got {data.get('jobid')}"
assert (
data.get("state") == "COMPLETED"
), f"Expected state COMPLETED in the job end record, got {data.get('state')}"