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