blob: 409752e7ecf486de5a8e5545a0746397da3e1a44 [file]
############################################################################
# Copyright (C) SchedMD LLC.
############################################################################
import json
import re
import pytest
import atf
topology_names = ["tree", "block", "flat1", "flat2", "ring", "torus"]
topology_yaml = """
---
- topology: tree
cluster_default: true
tree:
switches:
- switch: sw_root
children: s[1-2]
- switch: s1
nodes: node[1-2]
- switch: s2
nodes: node[3-4]
- topology: block
cluster_default: false
block:
block_sizes:
- 2
- 4
blocks:
- block: b1
nodes: node[1-2]
- block: b2
nodes: node[3-4]
- block: b3
nodes: node[5-6]
- block: b4
nodes: node[7-8]
- topology: flat1
cluster_default: false
flat:
alpha_step_rank: false
- topology: flat2
cluster_default: false
flat:
alpha_step_rank: true
- topology: ring
cluster_default: false
ring:
rings:
- ring: ring0
nodes: node[1-8]
- topology: torus
cluster_default: false
torus3d:
toruses:
- name: pod1
dims:
x: 2
y: 2
z: 2
nodes: node[1-8]
placements:
- dims:
x: 1
y: 1
z: 1
- dims:
x: 1
y: 1
z: 2
- dims:
x: 2
y: 2
z: 2
"""
# Setup
@pytest.fixture(scope="module", autouse=True)
def setup():
if atf.get_version("bin/scontrol") >= (26, 11):
atf.require_auto_config("Need to set specific topology.yaml and node count")
atf.require_config_file("topology.yaml", topology_yaml)
atf.require_nodes(8)
atf.require_slurm_running()
@pytest.mark.parametrize(
"action, min_version",
[
("show licenses", None),
("ping", None),
("show jobs", None),
("show job", None),
("show steps", None),
("show nodes", None),
("show partitions", None),
("show reservations", None),
("show topology", (26, 11)),
(f"show topology {topology_names[0]}", (26, 11)),
(f"show topology {topology_names[1]}", (26, 11)),
(f"show topology {topology_names[2]}", (26, 11)),
(f"show topology {topology_names[3]}", (26, 11)),
(f"show topology {topology_names[4]}", (26, 11)),
(f"show topology {topology_names[5]}", (26, 11)),
],
)
def test_json(action, min_version):
"""Verify scontrol --json has the correct format and meta data command"""
if (min_version is not None) and (atf.get_version("bin/scontrol") < min_version):
pytest.skip(
f"Skipping scontrol --json {action} because it requires version {min_version}"
)
expected_command = ["scontrol", "--json"]
expected_command.extend(action.split())
output = atf.run_command_output(f"scontrol --json {action}", fatal=True)
json_data = json.loads(output)
assert json_data is not None, f"scontrol --json {action} dumped a bare null"
assert (
json_data["errors"] == []
), f"scontrol --json {action} reported errors: {json_data['errors']}"
if atf.get_version("bin/scontrol") >= (26, 5):
assert (
json_data["meta"]["command"] == expected_command
), f"meta.command did not echo the invocation: {json_data['meta']['command']}"
@pytest.mark.skipif(
atf.get_version("bin/scontrol") < (26, 11),
reason="Issue 50235: scontrol --json show topology was added in 26.11",
)
def test_show_topology_unknown_name_json():
"""Verify scontrol --json show topology reports an unknown name as JSON"""
result = atf.run_command(
"scontrol --json show topology no_such_topology", xfail=True, fatal=True
)
assert result["stdout"].strip(), (
"scontrol --json produced no output at all; scontrol.1 documents --json "
"as dumping information as JSON, and the topology REST endpoint returns "
"a structured error envelope for this same condition"
)
errors = [error["error"] for error in json.loads(result["stdout"])["errors"]]
assert (
"Requested topology configuration is not available" in errors
), f"unknown topology name not reported in the --json errors: {errors}"
@pytest.mark.skipif(
atf.get_version("bin/scontrol") < (26, 11),
reason="Issue 50235: scontrol --json show topology and the interactive"
" stale-topology fix were added in 26.11",
)
def test_json_interactive_show_topology_by_name():
"""Verify interactive scontrol re-reads the topology for each name"""
output = atf.run_command_output(
"scontrol --json",
input="show topology tree\nshow topology block\n",
fatal=True,
)
# Filter out the interactive terminal log so a valid json can be processed
filtered_output = "[" + re.sub("scontrol:.*", ",", output)[1:-2] + "]"
tree_data = json.loads(filtered_output)[0]["topology"]["tree"]
block_data = json.loads(filtered_output)[1]["topology"]["block"]
assert (
len(tree_data) == 3
), f"interactive 'show topology tree' did not report the tree topology: {output}"
assert (
len(block_data) == 6
), f"interactive 'show topology block' reused the response cached for tree: {output}"