|
|
@@ -334,3 +334,30 @@ async fn occupied_nodes_excluded() {
|
|
|
assert_eq!(cluster.nodes.len(), 1);
|
|
|
assert_eq!(cluster.nodes[0].name, "n2");
|
|
|
}
|
|
|
+
|
|
|
+#[test]
|
|
|
+fn dry_run_resolves_without_probing_when_all_nodes_unreachable() {
|
|
|
+ // Dry-run must resolve a cluster even when no node is reachable — the
|
|
|
+ // whole point is to preview the command without touching hardware.
|
|
|
+ let c = test_cluster("c", &["n1", "n2"]);
|
|
|
+ let config = test_config(vec![c.clone()]);
|
|
|
+ let recipe = test_recipe(Some(2));
|
|
|
+
|
|
|
+ let (cluster, _nccl) =
|
|
|
+ crate::orchestrate::prepare_cluster_dry_run(&config, &recipe, "auto", None).unwrap();
|
|
|
+ assert_eq!(cluster.name, "c");
|
|
|
+ // Dry-run keeps every configured node (no free-node filtering).
|
|
|
+ assert_eq!(cluster.nodes.len(), 2);
|
|
|
+}
|
|
|
+
|
|
|
+#[test]
|
|
|
+fn dry_run_solo_node_skips_probing() {
|
|
|
+ let c = test_cluster("c", &["n1", "n2"]);
|
|
|
+ let config = test_config(vec![c.clone()]);
|
|
|
+ let recipe = test_recipe(Some(1));
|
|
|
+
|
|
|
+ let (cluster, _nccl) =
|
|
|
+ crate::orchestrate::prepare_cluster_dry_run(&config, &recipe, "auto", Some("n2")).unwrap();
|
|
|
+ assert_eq!(cluster.nodes.len(), 1);
|
|
|
+ assert_eq!(cluster.nodes[0].name, "n2");
|
|
|
+}
|