diff testharness/src/bin/testharness.rs @ 163:a75a66cb4181

Add end-to-end tests; fix issues found by tests. - Create tests and installer/remover shell script - Fix Pointer/pointee problems - Add Debug formatting - Misc cleanup
author Paul Fisher <paul@pfish.zone>
date Mon, 14 Jul 2025 17:40:11 -0400
parents a2676475e86b
children 2f5913131295
line wrap: on
line diff
--- a/testharness/src/bin/testharness.rs	Mon Jul 14 15:07:16 2025 -0400
+++ b/testharness/src/bin/testharness.rs	Mon Jul 14 17:40:11 2025 -0400
@@ -1,3 +1,121 @@
 //! The actual program which runs the tests.
 
-fn main() {}
+use nonstick::conv::Exchange;
+use nonstick::items::Items;
+use nonstick::libpam::TransactionBuilder;
+use nonstick::{Conversation, ErrorCode, Flags, LibPamTransaction, PamShared, Transaction};
+use std::cell::Cell;
+use std::ffi::OsString;
+use std::os::unix::ffi::OsStrExt;
+
+fn main() {
+    test_wrong_user();
+    test_wrong_password();
+    test_correct();
+}
+
+#[derive(Debug, Default)]
+struct TestHarness {
+    username_requested: Cell<bool>,
+    wrong_username: bool,
+    wrong_password: bool,
+    changing_password: Cell<bool>,
+    change_prompt_count: Cell<u8>,
+}
+
+impl Conversation for &TestHarness {
+    fn communicate(&self, messages: &[Exchange]) {
+        if let [only_msg] = messages {
+            match only_msg {
+                Exchange::Prompt(p) => {
+                    if self.username_requested.get() {
+                        panic!("username already requested!")
+                    }
+                    if self.wrong_username {
+                        p.set_answer(Ok(OsString::from("not-right")))
+                    } else {
+                        p.set_answer(Ok(OsString::from("initial")))
+                    }
+                    self.username_requested.set(true)
+                }
+                Exchange::MaskedPrompt(p) => {
+                    let answer = if self.changing_password.get() {
+                        let prompts = self.change_prompt_count.get();
+                        self.change_prompt_count.set(prompts + 1);
+                        match prompts {
+                            0 => "mistake",
+                            1 => "mismatch",
+                            2 => "acceptable",
+                            3 => "acceptable",
+                            _ => panic!("unexpected number of prompts!"),
+                        }
+                    } else if self.wrong_password {
+                        "bogus"
+                    } else {
+                        "valid"
+                    };
+                    p.set_answer(Ok(OsString::from(answer)));
+                }
+                Exchange::Error(e) if self.changing_password.get() => e.set_answer(Ok(())),
+                other => panic!("Unknown message {other:?}!"),
+            }
+        } else {
+            for msg in messages {
+                match msg {
+                    Exchange::Info(i) => i.set_answer(Ok(())),
+                    Exchange::Error(e) => e.set_answer(Ok(())),
+                    Exchange::Prompt(p) => match p.question().as_bytes() {
+                        b"How many?" => p.set_answer(Ok(OsString::from("123"))),
+                        _ => p.set_answer(Err(ErrorCode::ConversationError)),
+                    },
+                    Exchange::MaskedPrompt(p) => match p.question().as_bytes() {
+                        b"Where?" => p.set_answer(Ok(OsString::from("abc"))),
+                        _ => p.set_answer(Err(ErrorCode::ConversationError)),
+                    },
+                    other => other.set_error(ErrorCode::Abort),
+                }
+            }
+        }
+    }
+}
+
+impl TestHarness {
+    fn start(&self) -> LibPamTransaction<&Self> {
+        TransactionBuilder::new_with_service("nonstick-testharness")
+            .build(self)
+            .expect("expected build success")
+    }
+}
+
+fn test_wrong_user() {
+    let harness = TestHarness {
+        wrong_username: true,
+        ..Default::default()
+    };
+    let mut tx = harness.start();
+    let auth = tx.authenticate(Flags::empty());
+    assert_eq!(auth, Err(ErrorCode::UserUnknown));
+}
+
+fn test_wrong_password() {
+    let harness = TestHarness {
+        wrong_password: true,
+        ..Default::default()
+    };
+    let mut tx = harness.start();
+    let auth = tx.authenticate(Flags::empty());
+    assert_eq!(auth, Err(ErrorCode::AuthenticationError));
+}
+
+fn test_correct() {
+    let harness = TestHarness::default();
+    let mut tx = harness.start();
+    tx.authenticate(Flags::empty()).unwrap();
+    assert_eq!(tx.items().user().unwrap().unwrap(), "updated-in-process");
+    let result = tx.account_management(Flags::empty());
+    assert_eq!(result, Err(ErrorCode::NewAuthTokRequired));
+    harness.changing_password.set(true);
+    let change = tx.change_authtok(Flags::CHANGE_EXPIRED_AUTHTOK);
+    assert_eq!(change, Err(ErrorCode::TryAgain));
+    tx.change_authtok(Flags::CHANGE_EXPIRED_AUTHTOK).unwrap();
+}