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
default_empty_vec() -> Vec<String>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
parse_boot_metadata(toml_str: &str) -> Result<BootMetadata, toml::de::Error>63 fn parse_boot_metadata(toml_str: &str) -> Result<BootMetadata, toml::de::Error> {
64 toml::from_str(toml_str)
65 }
66
assert_missing_field(err_str: &str, field: &str)67 fn assert_missing_field(err_str: &str, field: &str) {
68 assert!(err_str.contains(&format!("missing field `{field}`")));
69 }
70
assert_unknown_variant(err_str: &str, variant: &str)71 fn assert_unknown_variant(err_str: &str, variant: &str) {
72 assert!(err_str.contains(&format!("unknown variant `{variant}`")));
73 }
74
75 #[test]
test_parse_grub_legacy_graphic()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]
test_parse_grub_efi_graphic_vnc()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]
test_parse_direct_no_graphic()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]
test_parse_dragon_stub_graphic()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]
test_parse_missing_boot_protocol()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]
test_parse_missing_boot_mode()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]
test_parse_invalid_boot_protocol()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]
test_parse_invalid_boot_mode()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]
test_parse_empty_fields()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