1 use serde::Deserialize; 2 3 use super::hypervisor::hyp_type::HypervisorType; 4 5 #[derive(Debug, Clone, Deserialize)] 6 pub struct BootMetadata { 7 /// The boot protocol used during startup 8 #[serde(rename = "boot-protocol")] 9 pub boot_protocol: BootProtocol, 10 /// The mode of booting 11 #[serde(rename = "boot-mode")] 12 pub boot_mode: BootMode, 13 /// The hypervisor used during startup 14 pub hypervisor: HypervisorType, 15 16 /// Kernel command-line arguments 17 #[serde(rename = "kcmd-args", default = "default_empty_vec")] 18 pub kcmd_args: Vec<String>, 19 /// Arguments passed to the init process 20 #[serde(rename = "init-args", default = "default_empty_vec")] 21 pub init_args: Vec<String>, 22 } 23 24 fn default_empty_vec() -> Vec<String> { 25 vec![] 26 } 27 28 #[derive(Debug, Clone, Deserialize, PartialEq, Eq)] 29 pub enum BootProtocol { 30 /// BIOS Bootloader 31 #[serde(rename = "grub-legacy")] 32 GrubLegacy, 33 /// UEFI Bootloader (Grub) 34 #[serde(rename = "grub-efi")] 35 GrubEFI, 36 /// Direct Linux Boot (with `-kernel` options) 37 #[serde(rename = "direct")] 38 Direct, 39 /// Dragon Stub Bootloader (riscv only) 40 #[serde(rename = "dragon-stub")] 41 DragonStub, 42 } 43 44 /// The mode of booting 45 #[derive(Debug, Clone, Deserialize, PartialEq, Eq)] 46 pub enum BootMode { 47 /// Graphic mode 48 #[serde(rename = "graphic")] 49 Graphic, 50 /// Graphic mode with VNC 51 #[serde(rename = "graphic-vnc")] 52 GraphicVnc, 53 /// No graphic mode 54 #[serde(rename = "no-graphic")] 55 NoGraphic, 56 } 57 58 #[cfg(test)] 59 mod tests { 60 use super::*; 61 62 // Helper function to parse TOML string into BootMetadata 63 fn parse_boot_metadata(toml_str: &str) -> Result<BootMetadata, toml::de::Error> { 64 toml::from_str(toml_str) 65 } 66 67 fn assert_missing_field(err_str: &str, field: &str) { 68 assert!(err_str.contains(&format!("missing field `{field}`"))); 69 } 70 71 fn assert_unknown_variant(err_str: &str, variant: &str) { 72 assert!(err_str.contains(&format!("unknown variant `{variant}`"))); 73 } 74 75 #[test] 76 fn test_parse_grub_legacy_graphic() { 77 let toml_str = r#" 78 boot-protocol = "grub-legacy" 79 boot-mode = "graphic" 80 hypervisor = "qemu" 81 "#; 82 83 let result = parse_boot_metadata(toml_str).unwrap(); 84 assert_eq!(result.boot_protocol, BootProtocol::GrubLegacy); 85 assert_eq!(result.boot_mode, BootMode::Graphic); 86 } 87 88 #[test] 89 fn test_parse_grub_efi_graphic_vnc() { 90 let toml_str = r#" 91 boot-protocol = "grub-efi" 92 boot-mode = "graphic-vnc" 93 hypervisor = "qemu" 94 "#; 95 96 let result = parse_boot_metadata(toml_str).unwrap(); 97 assert_eq!(result.boot_protocol, BootProtocol::GrubEFI); 98 assert_eq!(result.boot_mode, BootMode::GraphicVnc); 99 } 100 101 #[test] 102 fn test_parse_direct_no_graphic() { 103 let toml_str = r#" 104 boot-protocol = "direct" 105 boot-mode = "no-graphic" 106 hypervisor = "qemu" 107 "#; 108 109 let result = parse_boot_metadata(toml_str).unwrap(); 110 assert_eq!(result.boot_protocol, BootProtocol::Direct); 111 assert_eq!(result.boot_mode, BootMode::NoGraphic); 112 } 113 114 #[test] 115 fn test_parse_dragon_stub_graphic() { 116 let toml_str = r#" 117 boot-protocol = "dragon-stub" 118 boot-mode = "graphic" 119 hypervisor = "qemu" 120 "#; 121 122 let result = parse_boot_metadata(toml_str).unwrap(); 123 assert_eq!(result.boot_protocol, BootProtocol::DragonStub); 124 assert_eq!(result.boot_mode, BootMode::Graphic); 125 } 126 127 #[test] 128 fn test_parse_missing_boot_protocol() { 129 let toml_str = r#" 130 boot-mode = "graphic" 131 "#; 132 133 let r = parse_boot_metadata(toml_str); 134 assert!(r.is_err()); 135 let r = r.unwrap_err(); 136 assert_missing_field(&r.to_string(), "boot-protocol"); 137 } 138 139 #[test] 140 fn test_parse_missing_boot_mode() { 141 let toml_str = r#" 142 boot-protocol = "grub-legacy" 143 hypervisor = "qemu" 144 "#; 145 146 let r = parse_boot_metadata(toml_str); 147 assert!(r.is_err()); 148 let r = r.unwrap_err(); 149 assert_missing_field(&r.to_string(), "boot-mode"); 150 } 151 152 #[test] 153 fn test_parse_invalid_boot_protocol() { 154 let toml_str = r#" 155 boot-protocol = "invalid-protocol" 156 boot-mode = "graphic" 157 "#; 158 let r = parse_boot_metadata(toml_str); 159 assert!(r.is_err()); 160 let r = r.unwrap_err(); 161 assert_unknown_variant(&r.to_string(), "invalid-protocol"); 162 } 163 164 #[test] 165 fn test_parse_invalid_boot_mode() { 166 let toml_str = r#" 167 boot-protocol = "grub-legacy" 168 boot-mode = "invalid-mode" 169 "#; 170 171 let r = parse_boot_metadata(toml_str); 172 assert!(r.is_err()); 173 let r = r.unwrap_err(); 174 assert_unknown_variant(&r.to_string(), "invalid-mode"); 175 } 176 177 #[test] 178 fn test_parse_empty_fields() { 179 let toml_str = r#" 180 boot-protocol = "" 181 boot-mode = "" 182 "#; 183 184 assert!(parse_boot_metadata(toml_str).is_err()); 185 } 186 } 187