sysmaster/backport-test-add-UT-testcase-for-command-dispatch.patch
huyubiao 8936fa02c5 sync patches from upstream,change the path of the unit,modify permissions for some directories and files
(cherry picked from commit ce9ff469b57f60130621bc293783bd3ac1fc92f2)
2023-08-05 18:15:53 +08:00

192 lines
6.0 KiB
Diff

From 2e5a2327f009432ac9bd247567f2b6d953ec63c6 Mon Sep 17 00:00:00 2001
From: licunlong <licunlong1@huawei.com>
Date: Thu, 13 Jul 2023 14:50:28 +0800
Subject: [PATCH] test: add UT testcase for command dispatch
---
core/sysmaster/manager/commands.rs | 171 +++++++++++++++++++++++++++++
1 file changed, 171 insertions(+)
diff --git a/core/sysmaster/manager/commands.rs b/core/sysmaster/manager/commands.rs
index ad3e97f..a05d949 100644
--- a/core/sysmaster/manager/commands.rs
+++ b/core/sysmaster/manager/commands.rs
@@ -132,3 +132,174 @@ where
0i8
}
}
+
+#[cfg(test)]
+mod tests {
+ use std::sync::{Arc, Mutex};
+ use std::{os::unix::net::UnixStream, rc::Rc};
+
+ use cmdproto::error::Result;
+ use cmdproto::proto::{execute::ExecuterAction, unit_comm};
+ use cmdproto::proto::{CommandRequest, ProstClientStream};
+ use constants::SCTL_SOCKET;
+ use event::{EventState, Events};
+ use sysmaster::rel::{ReliConf, Reliability};
+
+ use crate::manager::RELI_HISTORY_MAX_DBS;
+
+ use super::Commands;
+
+ struct TestExecAction {}
+
+ impl ExecuterAction for TestExecAction {
+ type Error = nix::Error;
+ type Status = nix::Error;
+
+ fn start(&self, _unit_name: &str) -> Result<(), Self::Error> {
+ Err(nix::Error::ENOENT)
+ }
+
+ fn stop(&self, _unit_name: &str) -> Result<(), Self::Error> {
+ Ok(())
+ }
+
+ fn restart(&self, _unit_name: &str) -> Result<(), Self::Error> {
+ Ok(())
+ }
+
+ fn reload(&self, _unit_name: &str) -> Result<(), Self::Error> {
+ Ok(())
+ }
+
+ fn isolate(&self, _unit_name: &str) -> Result<(), Self::Error> {
+ Ok(())
+ }
+
+ fn reset_failed(&self, _unit_name: &str) -> Result<(), Self::Error> {
+ Ok(())
+ }
+
+ fn status(&self, _unit_name: &str) -> Result<Self::Status, Self::Error> {
+ Ok(nix::Error::EINVAL)
+ }
+
+ fn list_units(&self) -> Result<String, Self::Error> {
+ Ok(String::new())
+ }
+
+ fn suspend(&self) -> Result<i32, Self::Error> {
+ Ok(0)
+ }
+
+ fn poweroff(&self) -> Result<i32, Self::Error> {
+ Ok(0)
+ }
+
+ fn reboot(&self) -> Result<i32, Self::Error> {
+ Ok(0)
+ }
+
+ fn halt(&self) -> Result<i32, Self::Error> {
+ Ok(0)
+ }
+
+ fn disable(&self, _unit_name: &str) -> Result<(), Self::Error> {
+ Ok(())
+ }
+
+ fn enable(&self, _unit_name: &str) -> Result<(), Self::Error> {
+ Ok(())
+ }
+
+ fn mask(&self, _unit_name: &str) -> Result<(), Self::Error> {
+ Ok(())
+ }
+
+ fn unmask(&self, _unit_name: &str) -> Result<(), Self::Error> {
+ Ok(())
+ }
+
+ fn daemon_reload(&self) {}
+
+ fn daemon_reexec(&self) {}
+
+ fn switch_root(&self, _init: &[String]) -> Result<(), Self::Error> {
+ Ok(())
+ }
+ }
+
+ #[test]
+ fn test_sctl_socket() {
+ if !nix::unistd::getuid().is_root() {
+ println!(
+ "We will create a socket under '/run', so we must be root to run this testcase."
+ );
+ return;
+ }
+
+ let mutex_main = Arc::new(Mutex::new(0));
+ let mutex_child = Arc::clone(&mutex_main);
+ let temp = mutex_main.lock().unwrap();
+
+ std::thread::spawn(move || {
+ /* Wait until the main thread are ready to process our request. */
+ let mut test_ok = mutex_child.lock().unwrap();
+ /* 1. Start a service as root. */
+ let stream = UnixStream::connect(SCTL_SOCKET).unwrap();
+ let mut client = ProstClientStream::new(stream);
+
+ let req = CommandRequest::new_unitcomm(
+ unit_comm::Action::Start,
+ vec!["foo.service".to_string()],
+ );
+ let data = client.execute(req).unwrap();
+ if !data
+ .message
+ .eq("Failed to start foo.service: ENOENT: No such file or directory")
+ {
+ return;
+ }
+ /* 2. Start a service as an unprivileged user. */
+ if nix::unistd::setuid(nix::unistd::Uid::from_raw(1000)).is_err() {
+ println!("Failed to set ourself to unprivileged user");
+ return;
+ }
+ let stream = UnixStream::connect(SCTL_SOCKET).unwrap();
+ let mut client = ProstClientStream::new(stream);
+
+ let req = CommandRequest::new_unitcomm(
+ unit_comm::Action::Start,
+ vec!["foo.service".to_string()],
+ );
+ let data = client.execute(req).unwrap();
+ if !data
+ .message
+ .eq("Failed to execute your command: Operation not permitted.")
+ {
+ return;
+ }
+ *test_ok = 1;
+ });
+
+ let exec_action = TestExecAction {};
+ let reli = Rc::new(Reliability::new(
+ ReliConf::new().set_max_dbs(RELI_HISTORY_MAX_DBS),
+ ));
+ /* This will remove the /run/sysmaster/sctl on the compiling environment. */
+ let command = Rc::new(Commands::new(&reli, exec_action));
+ let e = Events::new().unwrap();
+ e.add_source(command.clone()).unwrap();
+ e.set_enabled(command.clone(), EventState::On).unwrap();
+ /* Drop temp, let the child thread go. */
+ drop(temp);
+ /* We have 2 events to dispatch, but are not sure if we can get these events after waiting
+ * 300ms, 400ms. So we wait one more time to make sure all events are dispatched. */
+ e.run(300).unwrap();
+ e.run(400).unwrap();
+ e.run(300).unwrap();
+ let test_ok = mutex_main.lock().unwrap();
+ /* The value should be set to 1 in the child process, if everything works well. */
+ assert_eq!(*test_ok, 1);
+ e.del_source(command).unwrap();
+ }
+}
--
2.33.0