[pve-devel] [PATCH installer v3 5/8] auto: add negative tests for root password option

Christoph Heiss c.heiss at proxmox.com
Mon Dec 16 10:41:03 CET 2024


Extends our test runner for the parse-answer tests to also run some
tests which are expected to fail, with a pre-determined error message
given in the accompanying json.

Signed-off-by: Christoph Heiss <c.heiss at proxmox.com>
---
Changes v2 -> v3:
  * rebased; use separate test function for tests instead of
    retro-fitting into existing one
  * implement `Debug` trait manually for `InstallRootPassword` to avoid
    leaking passwords accidentally

Changes v1 -> v2:
  * new patch

 proxmox-auto-installer/tests/parse-answer.rs  | 61 +++++++++++++++----
 .../both_password_and_hashed_set.json         |  3 +
 .../both_password_and_hashed_set.toml         | 15 +++++
 .../no_root_password_set.json                 |  3 +
 .../no_root_password_set.toml                 | 13 ++++
 .../parse_answer_fail/short_password.json     |  3 +
 .../parse_answer_fail/short_password.toml     | 14 +++++
 proxmox-installer-common/src/setup.rs         | 13 +++-
 8 files changed, 110 insertions(+), 15 deletions(-)
 create mode 100644 proxmox-auto-installer/tests/resources/parse_answer_fail/both_password_and_hashed_set.json
 create mode 100644 proxmox-auto-installer/tests/resources/parse_answer_fail/both_password_and_hashed_set.toml
 create mode 100644 proxmox-auto-installer/tests/resources/parse_answer_fail/no_root_password_set.json
 create mode 100644 proxmox-auto-installer/tests/resources/parse_answer_fail/no_root_password_set.toml
 create mode 100644 proxmox-auto-installer/tests/resources/parse_answer_fail/short_password.json
 create mode 100644 proxmox-auto-installer/tests/resources/parse_answer_fail/short_password.toml

diff --git a/proxmox-auto-installer/tests/parse-answer.rs b/proxmox-auto-installer/tests/parse-answer.rs
index 68b3834..32f5e28 100644
--- a/proxmox-auto-installer/tests/parse-answer.rs
+++ b/proxmox-auto-installer/tests/parse-answer.rs
@@ -58,27 +58,51 @@ fn run_named_test(name: &str) {
     let config: Value = serde_json::from_str(config_json.unwrap().as_str()).unwrap();
 
     let json_path = resource_path.join(format!("parse_answer/{name}.json"));
-    let compare_raw = fs::read_to_string(&json_path).unwrap();
-    let compare: Value = serde_json::from_str(&compare_raw).unwrap();
+    let compare: Value = read_json(json_path).unwrap();
 
     pretty_assertions::assert_eq!(config, compare);
 }
 
+fn run_named_fail_parse_test(name: &str) {
+    let resource_path = get_test_resource_path().unwrap();
+    let (setup_info, locales, runtime_info, udev_info) = setup_test_basic(&resource_path);
+
+    let answer_path = resource_path.join(format!("parse_answer_fail/{name}.toml"));
+
+    let answer = get_answer(&answer_path).unwrap();
+    let config = parse_answer(&answer, &udev_info, &runtime_info, &locales, &setup_info);
+
+    let err_json: Value = {
+        let path = resource_path.join(format!("parse_answer_fail/{name}.json"));
+        read_json(path).unwrap()
+    };
+
+    assert!(config.is_err());
+    assert_eq!(
+        config.unwrap_err().to_string(),
+        err_json.get("error").unwrap().as_str().unwrap()
+    );
+}
+
 mod tests {
+    macro_rules! declare_tests {
+        ($fn:ident, $name:ident, $( $rest:ident ),* $(,)?) => {
+            declare_tests!($fn, $name);
+            declare_tests!($fn, $( $rest ),+);
+        };
+        ($fn:ident, $name:ident) => {
+            #[test]
+            fn $name() {
+                $fn(&stringify!($name));
+            }
+        };
+    }
+
     mod parse_answer {
         use super::super::run_named_test;
 
-        macro_rules! declare_named_tests {
-            ($name:ident, $( $rest:ident ),* $(,)?) => { declare_named_tests!($name); declare_named_tests!($( $rest ),+); };
-            ($name:ident) => {
-                #[test]
-                fn $name() {
-                    run_named_test(&stringify!($name));
-                }
-            };
-        }
-
-        declare_named_tests!(
+        declare_tests!(
+            run_named_test,
             btrfs,
             btrfs_raid_level_uppercase,
             disk_match,
@@ -93,4 +117,15 @@ mod tests {
             zfs_raid_level_uppercase,
         );
     }
+
+    mod parse_answer_fail {
+        use super::super::run_named_fail_parse_test;
+
+        declare_tests!(
+            run_named_fail_parse_test,
+            both_password_and_hashed_set,
+            no_root_password_set,
+            short_password
+        );
+    }
 }
diff --git a/proxmox-auto-installer/tests/resources/parse_answer_fail/both_password_and_hashed_set.json b/proxmox-auto-installer/tests/resources/parse_answer_fail/both_password_and_hashed_set.json
new file mode 100644
index 0000000..fd1213e
--- /dev/null
+++ b/proxmox-auto-installer/tests/resources/parse_answer_fail/both_password_and_hashed_set.json
@@ -0,0 +1,3 @@
+{
+  "error": "`global.root_password` and `global.root_password_hashed` cannot be set at the same time"
+}
diff --git a/proxmox-auto-installer/tests/resources/parse_answer_fail/both_password_and_hashed_set.toml b/proxmox-auto-installer/tests/resources/parse_answer_fail/both_password_and_hashed_set.toml
new file mode 100644
index 0000000..0a56fc9
--- /dev/null
+++ b/proxmox-auto-installer/tests/resources/parse_answer_fail/both_password_and_hashed_set.toml
@@ -0,0 +1,15 @@
+[global]
+keyboard = "de"
+country = "at"
+fqdn = "both-password-and-hashed-set.fail.testinstall"
+mailto = "mail at no.invalid"
+timezone = "Europe/Vienna"
+root_password = "12345678"
+root_password_hashed = "$y$j9T$343s9MNhV4xZhW1Be6J6H1$rIxofnXWmp0FQGGIPO3BRwb1jK4ZXWaxT7OjhHJmum0"
+
+[network]
+source = "from-dhcp"
+
+[disk-setup]
+filesystem = "ext4"
+disk_list = ["sda"]
diff --git a/proxmox-auto-installer/tests/resources/parse_answer_fail/no_root_password_set.json b/proxmox-auto-installer/tests/resources/parse_answer_fail/no_root_password_set.json
new file mode 100644
index 0000000..6d75755
--- /dev/null
+++ b/proxmox-auto-installer/tests/resources/parse_answer_fail/no_root_password_set.json
@@ -0,0 +1,3 @@
+{
+  "error": "One of `global.root_password` or `global.root_password_hashed` must be set"
+}
diff --git a/proxmox-auto-installer/tests/resources/parse_answer_fail/no_root_password_set.toml b/proxmox-auto-installer/tests/resources/parse_answer_fail/no_root_password_set.toml
new file mode 100644
index 0000000..454e0b6
--- /dev/null
+++ b/proxmox-auto-installer/tests/resources/parse_answer_fail/no_root_password_set.toml
@@ -0,0 +1,13 @@
+[global]
+keyboard = "de"
+country = "at"
+fqdn = "no-root-password-set.fail.testinstall"
+mailto = "mail at no.invalid"
+timezone = "Europe/Vienna"
+
+[network]
+source = "from-dhcp"
+
+[disk-setup]
+filesystem = "ext4"
+disk_list = ["sda"]
diff --git a/proxmox-auto-installer/tests/resources/parse_answer_fail/short_password.json b/proxmox-auto-installer/tests/resources/parse_answer_fail/short_password.json
new file mode 100644
index 0000000..c424b0b
--- /dev/null
+++ b/proxmox-auto-installer/tests/resources/parse_answer_fail/short_password.json
@@ -0,0 +1,3 @@
+{
+    "error": "`global.root_password` must be at least 8 characters long"
+}
diff --git a/proxmox-auto-installer/tests/resources/parse_answer_fail/short_password.toml b/proxmox-auto-installer/tests/resources/parse_answer_fail/short_password.toml
new file mode 100644
index 0000000..a0eb1ec
--- /dev/null
+++ b/proxmox-auto-installer/tests/resources/parse_answer_fail/short_password.toml
@@ -0,0 +1,14 @@
+[global]
+keyboard = "de"
+country = "at"
+fqdn = "short-password.fail.testinstall"
+mailto = "mail at no.invalid"
+timezone = "Europe/Vienna"
+root_password = "12345"
+
+[network]
+source = "from-dhcp"
+
+[disk-setup]
+filesystem = "ext4"
+disk_list = ["sda"]
diff --git a/proxmox-installer-common/src/setup.rs b/proxmox-installer-common/src/setup.rs
index 26a8755..492b240 100644
--- a/proxmox-installer-common/src/setup.rs
+++ b/proxmox-installer-common/src/setup.rs
@@ -489,7 +489,16 @@ pub enum InstallRootPassword {
     Hashed(String),
 }
 
-#[derive(Clone, Default, Deserialize, Serialize)]
+impl fmt::Debug for InstallRootPassword {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        match self {
+            InstallRootPassword::Plain(_) => write!(f, "********"),
+            InstallRootPassword::Hashed(s) => write!(f, "{}", s),
+        }
+    }
+}
+
+#[derive(Clone, Debug, Default, Deserialize, Serialize)]
 pub struct InstallFirstBootSetup {
     #[serde(
         serialize_with = "serialize_bool_as_u32",
@@ -520,7 +529,7 @@ pub fn spawn_low_level_installer(test_mode: bool) -> io::Result<process::Child>
 }
 
 /// See Proxmox::Install::Config
-#[derive(Deserialize, Serialize)]
+#[derive(Debug, Deserialize, Serialize)]
 pub struct InstallConfig {
     pub autoreboot: usize,
 
-- 
2.47.0





More information about the pve-devel mailing list