diff --git a/crates/admin-cli/src/expected_machines/common.rs b/crates/admin-cli/src/expected_machines/common.rs index 2b5055820a..75988b1d13 100644 --- a/crates/admin-cli/src/expected_machines/common.rs +++ b/crates/admin-cli/src/expected_machines/common.rs @@ -21,10 +21,31 @@ use carbide_uuid::rack::RackId; use mac_address::MacAddress; use serde::{Deserialize, Serialize}; +#[derive(Debug, Deserialize)] +#[serde(untagged)] +enum ExpectedMachineIdJson { + String(String), + RpcUuid { value: String }, +} + +fn deserialize_optional_expected_machine_id<'de, D>( + deserializer: D, +) -> Result, D::Error> +where + D: serde::Deserializer<'de>, +{ + Ok( + Option::::deserialize(deserializer)?.map(|id| match id { + ExpectedMachineIdJson::String(value) => value, + ExpectedMachineIdJson::RpcUuid { value } => value, + }), + ) +} + /// JSON shape for `replace-all` and file-based `update` (field names match gRPC / API `ExpectedMachine`). #[derive(Debug, Serialize, Deserialize)] pub struct ExpectedMachineJson { - #[serde(default)] + #[serde(default, deserialize_with = "deserialize_optional_expected_machine_id")] pub id: Option, pub bmc_mac_address: MacAddress, pub bmc_username: String, diff --git a/crates/admin-cli/src/expected_machines/tests.rs b/crates/admin-cli/src/expected_machines/tests.rs index 741b187455..61a5c61c6a 100644 --- a/crates/admin-cli/src/expected_machines/tests.rs +++ b/crates/admin-cli/src/expected_machines/tests.rs @@ -28,6 +28,7 @@ use carbide_test_support::Outcome::*; use carbide_test_support::scenarios; use clap::{CommandFactory, Parser}; +use super::common::ExpectedMachineJson; use super::*; // verify_cmd_structure runs a baseline clap debug_assert() @@ -222,6 +223,61 @@ fn parse_replace_all() { } } +#[test] +fn expected_machine_json_accepts_missing_id() { + let machine: ExpectedMachineJson = serde_json::from_str( + r#"{ + "bmc_mac_address": "00:11:22:33:44:55", + "bmc_username": "admin", + "bmc_password": "secret", + "chassis_serial_number": "SN123" + }"#, + ) + .expect("expected machine without id should parse"); + + assert_eq!(machine.id, None); +} + +#[test] +fn expected_machine_json_accepts_string_id() { + let machine: ExpectedMachineJson = serde_json::from_str( + r#"{ + "id": "123e4567-e89b-12d3-a456-426614174000", + "bmc_mac_address": "00:11:22:33:44:55", + "bmc_username": "admin", + "bmc_password": "secret", + "chassis_serial_number": "SN123" + }"#, + ) + .expect("expected machine with string id should parse"); + + assert_eq!( + machine.id.as_deref(), + Some("123e4567-e89b-12d3-a456-426614174000") + ); +} + +#[test] +fn expected_machine_json_accepts_rpc_uuid_id() { + let machine: ExpectedMachineJson = serde_json::from_str( + r#"{ + "id": { + "value": "123e4567-e89b-12d3-a456-426614174000" + }, + "bmc_mac_address": "00:11:22:33:44:55", + "bmc_username": "admin", + "bmc_password": "secret", + "chassis_serial_number": "SN123" + }"#, + ) + .expect("expected machine with RPC UUID id should parse"); + + assert_eq!( + machine.id.as_deref(), + Some("123e4567-e89b-12d3-a456-426614174000") + ); +} + // parse_erase ensures erase parses with no arguments. #[test] fn parse_erase() {