use serde_json::Value;
pub fn extract_image_groups(image: &Value) -> Vec<String> {
image
.get("configuration_group_names")
.and_then(Value::as_array)
.map(|arr| {
arr
.iter()
.filter_map(Value::as_str)
.map(str::to_string)
.collect()
})
.unwrap_or_default()
}
pub fn extract_session_template_groups(
session_template: &Value,
) -> Vec<String> {
let Some(boot_sets) = session_template
.get("bos_parameters")
.and_then(|p| p.get("boot_sets"))
.and_then(Value::as_object)
else {
return Vec::new();
};
let mut groups: Vec<String> = boot_sets
.values()
.filter_map(|set| set.get("node_groups"))
.filter_map(Value::as_array)
.flat_map(|arr| arr.iter().filter_map(Value::as_str).map(str::to_string))
.collect();
groups.sort();
groups.dedup();
groups
}
pub fn extract_all_target_groups(sat_file: &Value) -> Vec<String> {
let mut groups: Vec<String> = Vec::new();
if let Some(images) = sat_file.get("images").and_then(Value::as_array) {
for image in images {
groups.extend(extract_image_groups(image));
}
}
if let Some(templates) =
sat_file.get("session_templates").and_then(Value::as_array)
{
for tpl in templates {
groups.extend(extract_session_template_groups(tpl));
}
}
groups.sort();
groups.dedup();
groups
}
#[cfg(test)]
mod tests {
use super::{extract_image_groups, extract_session_template_groups};
use serde_json::json;
#[test]
fn extract_image_groups_reads_configuration_group_names() {
let image = json!({
"name": "img-v1",
"configuration": "cfg-v1",
"configuration_group_names": ["compute", "uan"],
});
assert_eq!(extract_image_groups(&image), vec!["compute", "uan"]);
}
#[test]
fn extract_image_groups_empty_when_field_absent() {
let image = json!({ "name": "img-v1", "configuration": "cfg-v1" });
assert!(extract_image_groups(&image).is_empty());
}
#[test]
fn extract_image_groups_empty_when_field_is_not_array() {
let image = json!({
"name": "img-v1",
"configuration_group_names": "compute",
});
assert!(extract_image_groups(&image).is_empty());
}
#[test]
fn extract_session_template_groups_reads_all_boot_sets() {
let template = json!({
"name": "st-1",
"bos_parameters": {
"boot_sets": {
"compute": { "node_groups": ["compute", "shared"] },
"uan": { "node_groups": ["uan", "shared"] },
}
}
});
let groups = extract_session_template_groups(&template);
assert_eq!(groups, vec!["compute", "shared", "uan"]);
}
#[test]
fn extract_session_template_groups_empty_when_bos_parameters_missing() {
let template = json!({ "name": "st-1" });
assert!(extract_session_template_groups(&template).is_empty());
}
#[test]
fn extract_session_template_groups_empty_when_boot_sets_missing() {
let template = json!({ "name": "st-1", "bos_parameters": {} });
assert!(extract_session_template_groups(&template).is_empty());
}
#[test]
fn extract_session_template_groups_skips_boot_sets_without_node_groups() {
let template = json!({
"name": "st-1",
"bos_parameters": {
"boot_sets": {
"compute": { "node_groups": ["compute"] },
"uan": { "kernel": "linux" }
}
}
});
assert_eq!(extract_session_template_groups(&template), vec!["compute"]);
}
#[test]
fn extract_all_target_groups_empty_sat_file_returns_empty() {
let sat = json!({});
assert!(super::extract_all_target_groups(&sat).is_empty());
}
#[test]
fn extract_all_target_groups_collects_from_images_and_templates() {
let sat = json!({
"images": [
{ "name": "img-1", "configuration_group_names": ["compute", "uan"] },
{ "name": "img-2", "configuration_group_names": ["compute"] },
],
"session_templates": [
{
"name": "st-1",
"bos_parameters": {
"boot_sets": {
"compute": { "node_groups": ["compute"] },
"uan": { "node_groups": ["uan", "admin"] },
}
}
}
]
});
let mut got = super::extract_all_target_groups(&sat);
got.sort();
assert_eq!(got, vec!["admin", "compute", "uan"]);
}
#[test]
fn extract_all_target_groups_handles_missing_sections() {
let sat = json!({ "images": [ { "name": "img", "configuration_group_names": ["g1"] } ] });
let got = super::extract_all_target_groups(&sat);
assert_eq!(got, vec!["g1"]);
}
}