Signed-off-by: Yuhang Wei <weiyuhang3@huawei.com> (cherry picked from commit 9186039f774168dfbacef04dac8ee56356149736)
818 lines
33 KiB
Diff
818 lines
33 KiB
Diff
From e30fcb3c11ba4290b892e7307976b2c2a64c8fee Mon Sep 17 00:00:00 2001
|
|
From: Yuhang Wei <weiyuhang3@huawei.com>
|
|
Date: Tue, 16 Jan 2024 20:05:26 +0800
|
|
Subject: [PATCH 08/13] test(rust os-agent): add os-agent unit tests
|
|
|
|
Signed-off-by: Yuhang Wei <weiyuhang3@huawei.com>
|
|
---
|
|
KubeOS-Rust/agent/src/rpc/agent_impl.rs | 28 +++++----
|
|
KubeOS-Rust/cli/src/client.rs | 23 ++-----
|
|
KubeOS-Rust/cli/src/method/callable_method.rs | 28 +++++++++
|
|
KubeOS-Rust/cli/src/method/configure.rs | 31 ++++++++++
|
|
KubeOS-Rust/cli/src/method/prepare_upgrade.rs | 37 +++++++++++
|
|
KubeOS-Rust/cli/src/method/request.rs | 37 +++++++++++
|
|
KubeOS-Rust/cli/src/method/rollback.rs | 13 ++++
|
|
KubeOS-Rust/cli/src/method/upgrade.rs | 13 ++++
|
|
KubeOS-Rust/manager/src/api/types.rs | 58 +++++++++++++++++
|
|
KubeOS-Rust/manager/src/sys_mgmt/config.rs | 62 +++++++++----------
|
|
.../manager/src/sys_mgmt/containerd_image.rs | 22 +------
|
|
.../manager/src/sys_mgmt/disk_image.rs | 7 ++-
|
|
.../manager/src/sys_mgmt/docker_image.rs | 4 +-
|
|
KubeOS-Rust/manager/src/utils/common.rs | 43 ++++++++++---
|
|
.../manager/src/utils/container_image.rs | 46 ++++++++++++--
|
|
KubeOS-Rust/manager/src/utils/partition.rs | 15 +++++
|
|
16 files changed, 366 insertions(+), 101 deletions(-)
|
|
|
|
diff --git a/KubeOS-Rust/agent/src/rpc/agent_impl.rs b/KubeOS-Rust/agent/src/rpc/agent_impl.rs
|
|
index bc1eabd..8aef414 100644
|
|
--- a/KubeOS-Rust/agent/src/rpc/agent_impl.rs
|
|
+++ b/KubeOS-Rust/agent/src/rpc/agent_impl.rs
|
|
@@ -13,7 +13,7 @@
|
|
use std::{sync::Mutex, thread, time::Duration};
|
|
|
|
use anyhow::{bail, Result};
|
|
-use log::{debug, error, info};
|
|
+use log::{debug, info};
|
|
use manager::{
|
|
api::{AgentStatus, ConfigureRequest, ImageType, Response, UpgradeRequest},
|
|
sys_mgmt::{CtrImageHandler, DiskImageHandler, DockerImageHandler, CONFIG_TEMPLATE, DEFAULT_GRUBENV_PATH},
|
|
@@ -101,7 +101,6 @@ impl AgentImpl {
|
|
debug!("Found configuration type: \"{}\"", config_type);
|
|
configuration.set_config(config)?;
|
|
} else {
|
|
- error!("Unknown configuration type: \"{}\"", config_type);
|
|
bail!("Unknown configuration type: \"{}\"", config_type);
|
|
}
|
|
}
|
|
@@ -123,7 +122,7 @@ impl AgentImpl {
|
|
Ok(Response { status: AgentStatus::Rollbacked })
|
|
}
|
|
|
|
- pub fn reboot(&self) -> Result<()> {
|
|
+ fn reboot(&self) -> Result<()> {
|
|
info!("Wait to reboot");
|
|
thread::sleep(Duration::from_secs(1));
|
|
sync();
|
|
@@ -144,7 +143,15 @@ mod test {
|
|
use super::*;
|
|
|
|
#[test]
|
|
- fn configure_impl_tests() {
|
|
+ fn test_reboot() {
|
|
+ let mut agent = AgentImpl::default();
|
|
+ agent.disable_reboot = true;
|
|
+ let res = agent.reboot();
|
|
+ assert!(res.is_ok());
|
|
+ }
|
|
+
|
|
+ #[test]
|
|
+ fn test_configure() {
|
|
let agent = AgentImpl::default();
|
|
let req = ConfigureRequest {
|
|
configs: vec![Sysconfig {
|
|
@@ -153,7 +160,7 @@ mod test {
|
|
contents: HashMap::new(),
|
|
}],
|
|
};
|
|
- let res = agent.configure_impl(req).unwrap();
|
|
+ let res = agent.configure(req).unwrap();
|
|
assert_eq!(res, Response { status: AgentStatus::Configured });
|
|
|
|
let req = ConfigureRequest {
|
|
@@ -163,17 +170,12 @@ mod test {
|
|
contents: HashMap::new(),
|
|
}],
|
|
};
|
|
- let res = agent.configure_impl(req);
|
|
+ let res = agent.configure(req);
|
|
assert!(res.is_err());
|
|
}
|
|
|
|
#[test]
|
|
- fn upgrade_impl_tests() {
|
|
- let _ = env_logger::builder()
|
|
- .target(env_logger::Target::Stdout)
|
|
- .filter_level(log::LevelFilter::Trace)
|
|
- .is_test(true)
|
|
- .try_init();
|
|
+ fn test_prepare_upgrade() {
|
|
let agent = AgentImpl::default();
|
|
let req = UpgradeRequest {
|
|
version: "v2".into(),
|
|
@@ -185,7 +187,7 @@ mod test {
|
|
mtls: false,
|
|
certs: CertsInfo { ca_cert: "".to_string(), client_cert: "".to_string(), client_key: "".to_string() },
|
|
};
|
|
- let res = agent.prepare_upgrade_impl(req);
|
|
+ let res = agent.prepare_upgrade(req);
|
|
assert!(res.is_err());
|
|
}
|
|
}
|
|
diff --git a/KubeOS-Rust/cli/src/client.rs b/KubeOS-Rust/cli/src/client.rs
|
|
index ce45cdd..9765a42 100644
|
|
--- a/KubeOS-Rust/cli/src/client.rs
|
|
+++ b/KubeOS-Rust/cli/src/client.rs
|
|
@@ -43,27 +43,14 @@ impl Client {
|
|
|
|
#[cfg(test)]
|
|
mod test {
|
|
- use kubeos_manager::api;
|
|
-
|
|
use super::*;
|
|
- use crate::method::{callable_method::RpcMethod, configure::ConfigureMethod};
|
|
-
|
|
#[test]
|
|
- #[ignore]
|
|
fn test_client() {
|
|
- let socket_path = "/home/yuhang/os-agent-rust.sock";
|
|
+ let socket_path = "/tmp/KubeOS-test.sock";
|
|
let cli = Client::new(socket_path);
|
|
-
|
|
- let configured = api::AgentStatus::Configured;
|
|
- let resp = api::Response { status: configured };
|
|
- let config_request = api::ConfigureRequest {
|
|
- configs: vec![api::Sysconfig {
|
|
- model: "kernel.sysctl".into(),
|
|
- config_path: "".into(),
|
|
- contents: std::collections::hash_map::HashMap::new(),
|
|
- }],
|
|
- };
|
|
- let config_resp = ConfigureMethod::new(config_request).call(&cli).unwrap();
|
|
- assert_eq!(resp, config_resp);
|
|
+ let command = "example_command";
|
|
+ let params = vec![];
|
|
+ let request = cli.send_request(cli.build_request(command, ¶ms));
|
|
+ assert!(request.is_err());
|
|
}
|
|
}
|
|
diff --git a/KubeOS-Rust/cli/src/method/callable_method.rs b/KubeOS-Rust/cli/src/method/callable_method.rs
|
|
index c46614b..a174b5b 100644
|
|
--- a/KubeOS-Rust/cli/src/method/callable_method.rs
|
|
+++ b/KubeOS-Rust/cli/src/method/callable_method.rs
|
|
@@ -24,3 +24,31 @@ pub trait RpcMethod {
|
|
response.result().map_err(parse_error)
|
|
}
|
|
}
|
|
+
|
|
+#[cfg(test)]
|
|
+mod tests {
|
|
+ use super::*;
|
|
+ use crate::client;
|
|
+
|
|
+ #[derive(Default)]
|
|
+ struct DummyMethod;
|
|
+
|
|
+ impl RpcMethod for DummyMethod {
|
|
+ type Response = String;
|
|
+
|
|
+ fn command_name(&self) -> &'static str {
|
|
+ "dummy_command"
|
|
+ }
|
|
+
|
|
+ fn command_params(&self) -> Vec<Box<RawValue>> {
|
|
+ vec![]
|
|
+ }
|
|
+ }
|
|
+
|
|
+ #[test]
|
|
+ fn test_call() {
|
|
+ let client = client::Client::new("/tmp/KubeOS-test.sock");
|
|
+ let result = DummyMethod::default().call(&client);
|
|
+ assert!(result.is_err());
|
|
+ }
|
|
+}
|
|
diff --git a/KubeOS-Rust/cli/src/method/configure.rs b/KubeOS-Rust/cli/src/method/configure.rs
|
|
index d137106..cca752d 100644
|
|
--- a/KubeOS-Rust/cli/src/method/configure.rs
|
|
+++ b/KubeOS-Rust/cli/src/method/configure.rs
|
|
@@ -39,3 +39,34 @@ impl RpcMethod for ConfigureMethod {
|
|
vec![to_raw_value(&self.req).unwrap()]
|
|
}
|
|
}
|
|
+#[cfg(test)]
|
|
+mod tests {
|
|
+ use kubeos_manager::api::{ConfigureRequest, Sysconfig};
|
|
+
|
|
+ use super::*;
|
|
+
|
|
+ #[test]
|
|
+ fn test_configure_method() {
|
|
+ let req = ConfigureRequest { configs: vec![] };
|
|
+ let mut method = ConfigureMethod::new(req);
|
|
+
|
|
+ // Test set_configure_request method
|
|
+ let new_req = ConfigureRequest {
|
|
+ configs: vec![Sysconfig {
|
|
+ model: "model".to_string(),
|
|
+ config_path: "config_path".to_string(),
|
|
+ contents: Default::default(),
|
|
+ }],
|
|
+ };
|
|
+ method.set_configure_request(new_req);
|
|
+
|
|
+ // Test command_name method
|
|
+ assert_eq!(method.command_name(), "configure");
|
|
+
|
|
+ // Test command_params method
|
|
+ let expected_params =
|
|
+ "RawValue({\"configs\":[{\"model\":\"model\",\"config_path\":\"config_path\",\"contents\":{}}]})";
|
|
+ let actual_params = format!("{:?}", method.command_params()[0]);
|
|
+ assert_eq!(actual_params, expected_params);
|
|
+ }
|
|
+}
|
|
diff --git a/KubeOS-Rust/cli/src/method/prepare_upgrade.rs b/KubeOS-Rust/cli/src/method/prepare_upgrade.rs
|
|
index 91dae79..f2034f6 100644
|
|
--- a/KubeOS-Rust/cli/src/method/prepare_upgrade.rs
|
|
+++ b/KubeOS-Rust/cli/src/method/prepare_upgrade.rs
|
|
@@ -39,3 +39,40 @@ impl RpcMethod for PrepareUpgradeMethod {
|
|
vec![to_raw_value(&self.req).unwrap()]
|
|
}
|
|
}
|
|
+#[cfg(test)]
|
|
+mod tests {
|
|
+ use kubeos_manager::api::{CertsInfo, UpgradeRequest};
|
|
+
|
|
+ use super::*;
|
|
+
|
|
+ #[test]
|
|
+ fn test_prepare_upgrade_method() {
|
|
+ let req = UpgradeRequest {
|
|
+ version: "v1".into(),
|
|
+ check_sum: "".into(),
|
|
+ image_type: "".into(),
|
|
+ container_image: "".into(),
|
|
+ image_url: "".to_string(),
|
|
+ flag_safe: false,
|
|
+ mtls: false,
|
|
+ certs: CertsInfo { ca_cert: "".to_string(), client_cert: "".to_string(), client_key: "".to_string() },
|
|
+ };
|
|
+ let mut method = PrepareUpgradeMethod::new(req);
|
|
+ let new_req = UpgradeRequest {
|
|
+ version: "v2".into(),
|
|
+ check_sum: "xxx".into(),
|
|
+ image_type: "xxx".into(),
|
|
+ container_image: "xxx".into(),
|
|
+ image_url: "".to_string(),
|
|
+ flag_safe: false,
|
|
+ mtls: false,
|
|
+ certs: CertsInfo { ca_cert: "".to_string(), client_cert: "".to_string(), client_key: "".to_string() },
|
|
+ };
|
|
+ method.set_prepare_upgrade_request(new_req);
|
|
+ assert_eq!(method.command_name(), "prepare_upgrade");
|
|
+
|
|
+ let expected_params = "RawValue({\"version\":\"v2\",\"check_sum\":\"xxx\",\"image_type\":\"xxx\",\"container_image\":\"xxx\",\"image_url\":\"\",\"flag_safe\":false,\"mtls\":false,\"certs\":{\"ca_cert\":\"\",\"client_cert\":\"\",\"client_key\":\"\"}})";
|
|
+ let actual_params = format!("{:?}", method.command_params()[0]);
|
|
+ assert_eq!(actual_params, expected_params);
|
|
+ }
|
|
+}
|
|
diff --git a/KubeOS-Rust/cli/src/method/request.rs b/KubeOS-Rust/cli/src/method/request.rs
|
|
index 2dc1ffb..ff75afd 100644
|
|
--- a/KubeOS-Rust/cli/src/method/request.rs
|
|
+++ b/KubeOS-Rust/cli/src/method/request.rs
|
|
@@ -50,3 +50,40 @@ pub fn parse_error(error: Error) -> anyhow::Error {
|
|
},
|
|
}
|
|
}
|
|
+
|
|
+#[cfg(test)]
|
|
+mod tests {
|
|
+ use jsonrpc::error::RpcError;
|
|
+ use serde::de::Error as DeError;
|
|
+
|
|
+ use super::*;
|
|
+
|
|
+ #[test]
|
|
+ fn test_parse_error() {
|
|
+ // Test Error::Transport
|
|
+ let transport_error =
|
|
+ Error::Transport(Box::new(std::io::Error::new(std::io::ErrorKind::Other, "Connection timeout")));
|
|
+ let result = parse_error(transport_error);
|
|
+ assert_eq!(result.to_string(), "Cannot connect to KubeOS os-agent unix socket, Connection timeout");
|
|
+
|
|
+ // Test Error::Json
|
|
+ let json_error = Error::Json(serde_json::Error::custom("Failed to parse response"));
|
|
+ let result = parse_error(json_error);
|
|
+ assert_eq!(result.to_string(), "Failed to parse response");
|
|
+
|
|
+ // Test Error::Rpc with "Method not found" message
|
|
+ let rpc_error = Error::Rpc(RpcError { code: -32601, message: "Method not found".to_string(), data: None });
|
|
+ let result = parse_error(rpc_error);
|
|
+ assert_eq!(result.to_string(), "Method is unimplemented");
|
|
+
|
|
+ // Test Error::Rpc with other message
|
|
+ let rpc_error = Error::Rpc(RpcError { code: -32603, message: "Internal server error".to_string(), data: None });
|
|
+ let result = parse_error(rpc_error);
|
|
+ assert_eq!(result.to_string(), "Internal server error");
|
|
+
|
|
+ // Test other Error variant
|
|
+ let other_error = Error::VersionMismatch;
|
|
+ let result = parse_error(other_error);
|
|
+ assert_eq!(result.to_string(), "Response is invalid");
|
|
+ }
|
|
+}
|
|
diff --git a/KubeOS-Rust/cli/src/method/rollback.rs b/KubeOS-Rust/cli/src/method/rollback.rs
|
|
index 55aa751..7945f4b 100644
|
|
--- a/KubeOS-Rust/cli/src/method/rollback.rs
|
|
+++ b/KubeOS-Rust/cli/src/method/rollback.rs
|
|
@@ -27,3 +27,16 @@ impl RpcMethod for RollbackMethod {
|
|
vec![]
|
|
}
|
|
}
|
|
+
|
|
+#[cfg(test)]
|
|
+mod tests {
|
|
+ use super::*;
|
|
+ #[test]
|
|
+ fn test_rollback_method() {
|
|
+ let method = RollbackMethod::default();
|
|
+ assert_eq!(method.command_name(), "rollback");
|
|
+ let expected_params = "[]";
|
|
+ let actual_params = format!("{:?}", method.command_params());
|
|
+ assert_eq!(actual_params, expected_params);
|
|
+ }
|
|
+}
|
|
diff --git a/KubeOS-Rust/cli/src/method/upgrade.rs b/KubeOS-Rust/cli/src/method/upgrade.rs
|
|
index a9692ca..f2f94cd 100644
|
|
--- a/KubeOS-Rust/cli/src/method/upgrade.rs
|
|
+++ b/KubeOS-Rust/cli/src/method/upgrade.rs
|
|
@@ -27,3 +27,16 @@ impl RpcMethod for UpgradeMethod {
|
|
vec![]
|
|
}
|
|
}
|
|
+
|
|
+#[cfg(test)]
|
|
+mod tests {
|
|
+ use super::*;
|
|
+ #[test]
|
|
+ fn test_upgrade_method() {
|
|
+ let method = UpgradeMethod::default();
|
|
+ assert_eq!(method.command_name(), "upgrade");
|
|
+ let expected_params = "[]";
|
|
+ let actual_params = format!("{:?}", method.command_params());
|
|
+ assert_eq!(actual_params, expected_params);
|
|
+ }
|
|
+}
|
|
diff --git a/KubeOS-Rust/manager/src/api/types.rs b/KubeOS-Rust/manager/src/api/types.rs
|
|
index 28ee97d..98aeaa3 100644
|
|
--- a/KubeOS-Rust/manager/src/api/types.rs
|
|
+++ b/KubeOS-Rust/manager/src/api/types.rs
|
|
@@ -80,3 +80,61 @@ impl<T: CommandExecutor> ImageType<T> {
|
|
pub trait ImageHandler<T: CommandExecutor> {
|
|
fn download_image(&self, req: &UpgradeRequest) -> anyhow::Result<UpgradeImageManager<T>>;
|
|
}
|
|
+
|
|
+#[cfg(test)]
|
|
+mod tests {
|
|
+ use anyhow::Result;
|
|
+ use mockall::mock;
|
|
+
|
|
+ use super::*;
|
|
+ use crate::utils::PreparePath;
|
|
+
|
|
+ mock! {
|
|
+ pub CommandExec{}
|
|
+ impl CommandExecutor for CommandExec {
|
|
+ fn run_command<'a>(&self, name: &'a str, args: &[&'a str]) -> Result<()>;
|
|
+ fn run_command_with_output<'a>(&self, name: &'a str, args: &[&'a str]) -> Result<String>;
|
|
+ }
|
|
+ impl Clone for CommandExec {
|
|
+ fn clone(&self) -> Self;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ #[test]
|
|
+ fn test_download_image() {
|
|
+ let req = UpgradeRequest {
|
|
+ version: "KubeOS v2".to_string(),
|
|
+ image_type: "containerd".to_string(),
|
|
+ container_image: "kubeos-temp".to_string(),
|
|
+ check_sum: "22222".to_string(),
|
|
+ image_url: "".to_string(),
|
|
+ flag_safe: false,
|
|
+ mtls: false,
|
|
+ certs: CertsInfo { ca_cert: "".to_string(), client_cert: "".to_string(), client_key: "".to_string() },
|
|
+ };
|
|
+
|
|
+ let mut mock_executor1 = MockCommandExec::new();
|
|
+ mock_executor1.expect_run_command().returning(|_, _| Ok(()));
|
|
+ mock_executor1.expect_run_command_with_output().returning(|_, _| Ok(String::new()));
|
|
+ let c_handler = CtrImageHandler::new(PreparePath::default(), mock_executor1);
|
|
+ let image_type = ImageType::Containerd(c_handler);
|
|
+ let result = image_type.download_image(&req);
|
|
+ assert!(result.is_err());
|
|
+
|
|
+ let mut mock_executor2 = MockCommandExec::new();
|
|
+ mock_executor2.expect_run_command().returning(|_, _| Ok(()));
|
|
+ mock_executor2.expect_run_command_with_output().returning(|_, _| Ok(String::new()));
|
|
+ let docker_handler = DockerImageHandler::new(PreparePath::default(), "test".into(), mock_executor2);
|
|
+ let image_type = ImageType::Docker(docker_handler);
|
|
+ let result = image_type.download_image(&req);
|
|
+ assert!(result.is_err());
|
|
+
|
|
+ let mut mock_executor3 = MockCommandExec::new();
|
|
+ mock_executor3.expect_run_command().returning(|_, _| Ok(()));
|
|
+ mock_executor3.expect_run_command_with_output().returning(|_, _| Ok(String::new()));
|
|
+ let disk_handler = DiskImageHandler::new(PreparePath::default(), mock_executor3, "test".into());
|
|
+ let image_type = ImageType::Disk(disk_handler);
|
|
+ let result = image_type.download_image(&req);
|
|
+ assert!(result.is_err());
|
|
+ }
|
|
+}
|
|
diff --git a/KubeOS-Rust/manager/src/sys_mgmt/config.rs b/KubeOS-Rust/manager/src/sys_mgmt/config.rs
|
|
index cb5fad1..48517b4 100644
|
|
--- a/KubeOS-Rust/manager/src/sys_mgmt/config.rs
|
|
+++ b/KubeOS-Rust/manager/src/sys_mgmt/config.rs
|
|
@@ -186,7 +186,7 @@ fn handle_delete_key(config_kv: &Vec<&str>, new_config_info: &KeyInfo) -> String
|
|
return config_kv.join("=");
|
|
}
|
|
info!("Delete configuration {}={}", key, old_value);
|
|
- String::from("")
|
|
+ String::new()
|
|
}
|
|
|
|
fn handle_update_key(config_kv: &Vec<&str>, new_config_info: &KeyInfo) -> String {
|
|
@@ -413,11 +413,20 @@ mod tests {
|
|
let mut tmp_file = tempfile::NamedTempFile::new().unwrap();
|
|
writeln!(tmp_file, "{}", comment).unwrap();
|
|
writeln!(tmp_file, "a=0").unwrap();
|
|
+ writeln!(tmp_file, "d=4").unwrap();
|
|
+ writeln!(tmp_file, "e=5").unwrap();
|
|
+ writeln!(tmp_file, "g=7").unwrap();
|
|
let kernel_sysctl_persist = KernelSysctlPersist {};
|
|
let config_detail = HashMap::from([
|
|
("a".to_string(), KeyInfo { value: "1".to_string(), operation: "".to_string() }),
|
|
("b".to_string(), KeyInfo { value: "2".to_string(), operation: "delete".to_string() }),
|
|
("c".to_string(), KeyInfo { value: "3".to_string(), operation: "add".to_string() }),
|
|
+ ("d".to_string(), KeyInfo { value: "".to_string(), operation: "".to_string() }),
|
|
+ ("e".to_string(), KeyInfo { value: "".to_string(), operation: "delete".to_string() }),
|
|
+ ("f".to_string(), KeyInfo { value: "".to_string(), operation: "add".to_string() }),
|
|
+ ("g".to_string(), KeyInfo { value: "7".to_string(), operation: "delete".to_string() }),
|
|
+ ("".to_string(), KeyInfo { value: "8".to_string(), operation: "".to_string() }),
|
|
+ ("s=x".to_string(), KeyInfo { value: "8".to_string(), operation: "".to_string() }),
|
|
]);
|
|
let mut config = Sysconfig {
|
|
model: KERNEL_SYSCTL_PERSIST.to_string(),
|
|
@@ -426,33 +435,16 @@ mod tests {
|
|
};
|
|
kernel_sysctl_persist.set_config(&mut config).unwrap();
|
|
let result = fs::read_to_string(tmp_file.path().to_str().unwrap()).unwrap();
|
|
- let expected_res = format!("{}\n{}\n{}\n", comment, "a=1", "c=3");
|
|
+ let expected_res = format!("{}\n{}\n{}\n{}\n{}\n", comment, "a=1", "d=4", "e=5", "c=3");
|
|
assert_eq!(result, expected_res);
|
|
-
|
|
- // test config_path is empty
|
|
- // remember modify DEFAULT_KERNEL_CONFIG_PATH first
|
|
- // let config_detail = HashMap::from([
|
|
- // (
|
|
- // "aaa".to_string(),
|
|
- // KeyInfo {
|
|
- // value: "3".to_string(),
|
|
- // operation: "add".to_string(),
|
|
- // },
|
|
- // ),
|
|
- // (
|
|
- // "bbb".to_string(),
|
|
- // KeyInfo {
|
|
- // value: "1".to_string(),
|
|
- // operation: "delete".to_string(),
|
|
- // },
|
|
- // ),
|
|
- // ]);
|
|
- // config.config_path = "".to_string();
|
|
- // config.contents = config_detail;
|
|
- // kernel_sysctl_persist.set_config(&mut config).unwrap();
|
|
- // let result = fs::read_to_string(crate::sys_mgmt::DEFAULT_KERNEL_CONFIG_PATH).unwrap();
|
|
- // let expected_res = format!("{}\n", "aaa=3",);
|
|
- // assert_eq!(result, expected_res);
|
|
+ let mut config = Sysconfig {
|
|
+ model: KERNEL_SYSCTL_PERSIST.to_string(),
|
|
+ config_path: String::from("/tmp/kubeos-test-kernel-sysctl-persist.txt"),
|
|
+ contents: HashMap::new(),
|
|
+ };
|
|
+ kernel_sysctl_persist.set_config(&mut config).unwrap();
|
|
+ assert!(is_file_exist(&config.config_path));
|
|
+ delete_file_or_dir(&config.config_path).unwrap();
|
|
}
|
|
|
|
#[test]
|
|
@@ -492,7 +484,7 @@ menuentry 'B' --class KubeOS --class gnu-linux --class gnu --class os --unrestri
|
|
initrd /boot/initramfs.img
|
|
}";
|
|
writeln!(tmp_file, "{}", grub_cfg).unwrap();
|
|
- let config_first_part = HashMap::from([
|
|
+ let config_second_part = HashMap::from([
|
|
("debug".to_string(), KeyInfo { value: "".to_string(), operation: "".to_string() }),
|
|
("quiet".to_string(), KeyInfo { value: "".to_string(), operation: "delete".to_string() }),
|
|
("panic".to_string(), KeyInfo { value: "5".to_string(), operation: "".to_string() }),
|
|
@@ -506,15 +498,16 @@ menuentry 'B' --class KubeOS --class gnu-linux --class gnu --class os --unrestri
|
|
let mut config = Sysconfig {
|
|
model: GRUB_CMDLINE_CURRENT.to_string(),
|
|
config_path: String::new(),
|
|
- contents: config_first_part,
|
|
+ contents: config_second_part,
|
|
};
|
|
grub_cmdline.set_config(&mut config).unwrap();
|
|
grub_cmdline.is_cur_partition = false;
|
|
- let config_second = HashMap::from([
|
|
+ let config_first_part = HashMap::from([
|
|
("pci".to_string(), KeyInfo { value: "nomis".to_string(), operation: "".to_string() }),
|
|
- ("panic".to_string(), KeyInfo { value: "5".to_string(), operation: "".to_string() }),
|
|
+ ("quiet".to_string(), KeyInfo { value: "11".to_string(), operation: "delete".to_string() }),
|
|
+ ("panic".to_string(), KeyInfo { value: "5".to_string(), operation: "update".to_string() }),
|
|
]);
|
|
- config.contents = config_second;
|
|
+ config.contents = config_first_part;
|
|
config.model = GRUB_CMDLINE_NEXT.to_string();
|
|
grub_cmdline.set_config(&mut config).unwrap();
|
|
let result = fs::read_to_string(tmp_file.path().to_str().unwrap()).unwrap();
|
|
@@ -540,6 +533,11 @@ menuentry 'B' --class KubeOS --class gnu-linux --class gnu --class os --unrestri
|
|
}
|
|
";
|
|
assert_eq!(result, expected_res);
|
|
+
|
|
+ // test grub.cfg not exist
|
|
+ grub_cmdline.grub_path = "/tmp/grub-KubeOS-test.cfg".to_string();
|
|
+ let res = grub_cmdline.set_config(&mut config);
|
|
+ assert!(res.is_err());
|
|
}
|
|
|
|
#[test]
|
|
diff --git a/KubeOS-Rust/manager/src/sys_mgmt/containerd_image.rs b/KubeOS-Rust/manager/src/sys_mgmt/containerd_image.rs
|
|
index 0b50ad6..dd7036f 100644
|
|
--- a/KubeOS-Rust/manager/src/sys_mgmt/containerd_image.rs
|
|
+++ b/KubeOS-Rust/manager/src/sys_mgmt/containerd_image.rs
|
|
@@ -48,7 +48,7 @@ impl Default for CtrImageHandler<RealCommandExecutor> {
|
|
|
|
impl<T: CommandExecutor> CtrImageHandler<T> {
|
|
#[cfg(test)]
|
|
- fn new(paths: PreparePath, executor: T) -> Self {
|
|
+ pub fn new(paths: PreparePath, executor: T) -> Self {
|
|
Self { paths, executor }
|
|
}
|
|
|
|
@@ -301,24 +301,4 @@ mod tests {
|
|
|
|
assert!(result.is_ok());
|
|
}
|
|
-
|
|
- #[test]
|
|
- #[ignore]
|
|
- fn test_download_image() {
|
|
- init();
|
|
- let ctr = CtrImageHandler { paths: PreparePath::default(), executor: RealCommandExecutor {} };
|
|
- let update_req = UpgradeRequest {
|
|
- version: "KubeOS v2".to_string(),
|
|
- image_type: "containerd".to_string(),
|
|
- container_image: "docker.io/library/busybox:latest".to_string(),
|
|
- check_sum: "".to_string(),
|
|
- image_url: "".to_string(),
|
|
- flag_safe: false,
|
|
- mtls: false,
|
|
- certs: CertsInfo { ca_cert: "".to_string(), client_cert: "".to_string(), client_key: "".to_string() },
|
|
- };
|
|
- ctr.download_image(&update_req).unwrap();
|
|
- let tar_path = "/persist/KubeOS-Update/os.tar";
|
|
- assert_eq!(true, Path::new(tar_path).exists());
|
|
- }
|
|
}
|
|
diff --git a/KubeOS-Rust/manager/src/sys_mgmt/disk_image.rs b/KubeOS-Rust/manager/src/sys_mgmt/disk_image.rs
|
|
index 4ccb603..a120db8 100644
|
|
--- a/KubeOS-Rust/manager/src/sys_mgmt/disk_image.rs
|
|
+++ b/KubeOS-Rust/manager/src/sys_mgmt/disk_image.rs
|
|
@@ -41,7 +41,7 @@ impl Default for DiskImageHandler<RealCommandExecutor> {
|
|
|
|
impl<T: CommandExecutor> DiskImageHandler<T> {
|
|
#[cfg(test)]
|
|
- fn new(paths: PreparePath, executor: T, certs_path: String) -> Self {
|
|
+ pub fn new(paths: PreparePath, executor: T, certs_path: String) -> Self {
|
|
Self { paths, executor, certs_path }
|
|
}
|
|
|
|
@@ -392,11 +392,14 @@ mod tests {
|
|
.with_body("This is a test txt file for KubeOS test.\n")
|
|
.create();
|
|
handler.download_image(&upgrade_request).unwrap();
|
|
-
|
|
assert_eq!(true, handler.paths.image_path.exists());
|
|
assert_eq!(
|
|
fs::read(handler.paths.image_path.to_str().unwrap()).unwrap(),
|
|
"This is a test txt file for KubeOS test.\n".as_bytes()
|
|
);
|
|
+
|
|
+ let _m = mockito::mock("GET", "/test.txt").with_status(404).with_body("Not found").create();
|
|
+ let res = handler.download_image(&upgrade_request);
|
|
+ assert!(res.is_err())
|
|
}
|
|
}
|
|
diff --git a/KubeOS-Rust/manager/src/sys_mgmt/docker_image.rs b/KubeOS-Rust/manager/src/sys_mgmt/docker_image.rs
|
|
index 121e257..177dfeb 100644
|
|
--- a/KubeOS-Rust/manager/src/sys_mgmt/docker_image.rs
|
|
+++ b/KubeOS-Rust/manager/src/sys_mgmt/docker_image.rs
|
|
@@ -33,7 +33,7 @@ impl Default for DockerImageHandler<RealCommandExecutor> {
|
|
|
|
impl<T: CommandExecutor> DockerImageHandler<T> {
|
|
#[cfg(test)]
|
|
- fn new(paths: PreparePath, container_name: String, executor: T) -> Self {
|
|
+ pub fn new(paths: PreparePath, container_name: String, executor: T) -> Self {
|
|
Self { paths, container_name, executor }
|
|
}
|
|
|
|
@@ -129,6 +129,8 @@ mod tests {
|
|
let result =
|
|
DockerImageHandler::new(PreparePath::default(), "test".into(), mock_executor).check_and_rm_container();
|
|
assert!(result.is_ok());
|
|
+
|
|
+ assert_eq!(DockerImageHandler::default().container_name, "kubeos-temp");
|
|
}
|
|
|
|
#[test]
|
|
diff --git a/KubeOS-Rust/manager/src/utils/common.rs b/KubeOS-Rust/manager/src/utils/common.rs
|
|
index 301a8c8..da8c8c3 100644
|
|
--- a/KubeOS-Rust/manager/src/utils/common.rs
|
|
+++ b/KubeOS-Rust/manager/src/utils/common.rs
|
|
@@ -23,14 +23,25 @@ use nix::{mount, mount::MntFlags};
|
|
use super::executor::CommandExecutor;
|
|
use crate::sys_mgmt::{MOUNT_DIR, OS_IMAGE_NAME, PERSIST_DIR, ROOTFS_ARCHIVE, UPDATE_DIR};
|
|
|
|
+/// * persist_path: /persist
|
|
+///
|
|
+/// * update_path: /persist/KubeOS-Update
|
|
+///
|
|
+/// * mount_path: /persist/KubeOS-Update/kubeos-update
|
|
+///
|
|
+/// * tar_path: /persist/KubeOS-Update/os.tar
|
|
+///
|
|
+/// * image_path: /persist/update.img
|
|
+///
|
|
+/// * rootfs_file: os.tar
|
|
#[derive(Clone)]
|
|
pub struct PreparePath {
|
|
- pub persist_path: PathBuf, // persist_path: /persist
|
|
- pub update_path: PathBuf, // update_path: /persist/KubeOS-Update
|
|
- pub mount_path: PathBuf, // mount_path: /persist/KubeOS-Update/kubeos-update
|
|
- pub tar_path: PathBuf, // tar_path: /persist/KubeOS-Update/os.tar
|
|
- pub image_path: PathBuf, // image_path: /persist/update.img
|
|
- pub rootfs_file: String, // rootfs_file: os.tar
|
|
+ pub persist_path: PathBuf,
|
|
+ pub update_path: PathBuf,
|
|
+ pub mount_path: PathBuf,
|
|
+ pub tar_path: PathBuf,
|
|
+ pub image_path: PathBuf,
|
|
+ pub rootfs_file: String,
|
|
}
|
|
|
|
impl Default for PreparePath {
|
|
@@ -72,7 +83,7 @@ pub fn check_disk_size<P: AsRef<Path>>(need_bytes: i64, path: P) -> Result<()> {
|
|
Ok(())
|
|
}
|
|
|
|
-// clean_env will umount the mount path and delete directory /persist/KubeOS-Update and /persist/update.img
|
|
+/// clean_env will umount the mount path and delete directory /persist/KubeOS-Update and /persist/update.img
|
|
pub fn clean_env<P>(update_path: P, mount_path: P, image_path: P) -> Result<()>
|
|
where
|
|
P: AsRef<Path>,
|
|
@@ -160,6 +171,7 @@ mod tests {
|
|
use tempfile::{NamedTempFile, TempDir};
|
|
|
|
use super::*;
|
|
+ use crate::utils::RealCommandExecutor;
|
|
|
|
// Mock the CommandExecutor trait
|
|
mock! {
|
|
@@ -278,10 +290,23 @@ mod tests {
|
|
}
|
|
|
|
#[test]
|
|
- #[ignore]
|
|
fn test_get_boot_mode() {
|
|
init();
|
|
let boot_mode = get_boot_mode();
|
|
- assert!(boot_mode == "uefi");
|
|
+ let executor = RealCommandExecutor {};
|
|
+ let res = executor.run_command("ls", &["/sys/firmware/efi"]);
|
|
+ if res.is_ok() {
|
|
+ assert!(boot_mode == "uefi");
|
|
+ } else {
|
|
+ assert!(boot_mode == "bios");
|
|
+ }
|
|
+ }
|
|
+
|
|
+ #[test]
|
|
+ fn test_is_command_available() {
|
|
+ init();
|
|
+ let executor = RealCommandExecutor {};
|
|
+ assert_eq!(is_command_available("ls", &executor), true);
|
|
+ assert_eq!(is_command_available("aaaabb", &executor), false);
|
|
}
|
|
}
|
|
diff --git a/KubeOS-Rust/manager/src/utils/container_image.rs b/KubeOS-Rust/manager/src/utils/container_image.rs
|
|
index a54fc19..7c3aa02 100644
|
|
--- a/KubeOS-Rust/manager/src/utils/container_image.rs
|
|
+++ b/KubeOS-Rust/manager/src/utils/container_image.rs
|
|
@@ -197,12 +197,24 @@ mod tests {
|
|
let out1 = get_oci_image_digest(container_runtime, image_name, &mock).unwrap();
|
|
let expect_output = "1111";
|
|
assert_eq!(out1, expect_output);
|
|
+ mock.expect_run_command_with_output().times(1).returning(|_, _| Ok("invalid output".to_string()));
|
|
+ let out2 = get_oci_image_digest(container_runtime, image_name, &mock);
|
|
+ assert!(out2.is_err());
|
|
|
|
let container_runtime = "crictl";
|
|
let command_output2 = "[docker.io/nginx@sha256:1111]";
|
|
mock.expect_run_command_with_output().times(1).returning(|_, _| Ok(command_output2.to_string()));
|
|
- let out2 = get_oci_image_digest(container_runtime, image_name, &mock).unwrap();
|
|
- assert_eq!(out2, expect_output);
|
|
+ let out3 = get_oci_image_digest(container_runtime, image_name, &mock).unwrap();
|
|
+ assert_eq!(out3, expect_output);
|
|
+
|
|
+ let out4 = get_oci_image_digest("invalid", image_name, &mock);
|
|
+ assert!(out4.is_err());
|
|
+
|
|
+ let container_runtime = "crictl";
|
|
+ let command_output3 = "[docker.io/nginx:sha256:1111]";
|
|
+ mock.expect_run_command_with_output().times(1).returning(|_, _| Ok(command_output3.to_string()));
|
|
+ let out5 = get_oci_image_digest(container_runtime, image_name, &mock);
|
|
+ assert!(out5.is_err());
|
|
}
|
|
|
|
#[test]
|
|
@@ -211,11 +223,13 @@ mod tests {
|
|
let mut mock = MockCommandExec::new();
|
|
let image_name = "docker.io/nginx:latest";
|
|
let container_runtime = "crictl";
|
|
- let command_output = "[docker.io/nginx@sha256:1111]";
|
|
- let check_sum = "1111";
|
|
- mock.expect_run_command_with_output().times(1).returning(|_, _| Ok(command_output.to_string()));
|
|
+ let command_output = "[docker.io/nginx@sha256:1a2b]";
|
|
+ let check_sum = "1A2B";
|
|
+ mock.expect_run_command_with_output().times(2).returning(|_, _| Ok(command_output.to_string()));
|
|
let result = check_oci_image_digest(container_runtime, image_name, check_sum, &mock);
|
|
assert!(result.is_ok());
|
|
+ let result = check_oci_image_digest(container_runtime, image_name, "1111", &mock);
|
|
+ assert!(result.is_err());
|
|
}
|
|
|
|
#[test]
|
|
@@ -251,4 +265,26 @@ mod tests {
|
|
let result = pull_image("aaa", image_name, &mock_executor);
|
|
assert!(result.is_err());
|
|
}
|
|
+
|
|
+ #[test]
|
|
+ fn test_remove_image_if_exist() {
|
|
+ init();
|
|
+ let mut mock_executor = MockCommandExec::new();
|
|
+ mock_executor
|
|
+ .expect_run_command_with_output()
|
|
+ .withf(|cmd, args| cmd == "ctr" && args.contains(&"check")) // simplified with a closure
|
|
+ .times(1)
|
|
+ .returning(|_, _| Ok(String::from("something")));
|
|
+ mock_executor
|
|
+ .expect_run_command()
|
|
+ .withf(|cmd, args| cmd == "ctr" && args.contains(&"rm")) // simplified with a closure
|
|
+ .times(1)
|
|
+ .returning(|_, _| Ok(()));
|
|
+ let image_name = "docker.io/nginx:latest";
|
|
+ let res = remove_image_if_exist("ctr", image_name, &mock_executor);
|
|
+ assert!(res.is_ok());
|
|
+
|
|
+ let res = remove_image_if_exist("invalid", image_name, &mock_executor);
|
|
+ assert!(res.is_err());
|
|
+ }
|
|
}
|
|
diff --git a/KubeOS-Rust/manager/src/utils/partition.rs b/KubeOS-Rust/manager/src/utils/partition.rs
|
|
index 0419159..fcfa2d8 100644
|
|
--- a/KubeOS-Rust/manager/src/utils/partition.rs
|
|
+++ b/KubeOS-Rust/manager/src/utils/partition.rs
|
|
@@ -22,6 +22,7 @@ pub struct PartitionInfo {
|
|
pub fs_type: String,
|
|
}
|
|
|
|
+/// get_partition_info returns the current partition info and the next partition info.
|
|
pub fn get_partition_info<T: CommandExecutor>(executor: &T) -> Result<(PartitionInfo, PartitionInfo), anyhow::Error> {
|
|
let lsblk = executor.run_command_with_output("lsblk", &["-lno", "NAME,MOUNTPOINTS,FSTYPE"])?;
|
|
// After split whitespace, the root directory line should have 3 elements, which are "sda2 / ext4".
|
|
@@ -93,5 +94,19 @@ mod tests {
|
|
PartitionInfo { device: "/dev/sda3".to_string(), menuentry: "B".to_string(), fs_type: "ext4".to_string() },
|
|
);
|
|
assert_eq!(res, expect_res);
|
|
+
|
|
+ let command_output2 = "sda\nsda1 /boot/efi vfat\nsda2 ext4\nsda3 / ext4\nsda4 /persist ext4\nsr0 iso9660\n";
|
|
+ mock.expect_run_command_with_output().times(1).returning(|_, _| Ok(command_output2.to_string()));
|
|
+ let res = get_partition_info(&mock).unwrap();
|
|
+ let expect_res = (
|
|
+ PartitionInfo { device: "/dev/sda3".to_string(), menuentry: "B".to_string(), fs_type: "ext4".to_string() },
|
|
+ PartitionInfo { device: "/dev/sda2".to_string(), menuentry: "A".to_string(), fs_type: "ext4".to_string() },
|
|
+ );
|
|
+ assert_eq!(res, expect_res);
|
|
+
|
|
+ let command_output3 = "";
|
|
+ mock.expect_run_command_with_output().times(1).returning(|_, _| Ok(command_output3.to_string()));
|
|
+ let res = get_partition_info(&mock);
|
|
+ assert!(res.is_err());
|
|
}
|
|
}
|
|
--
|
|
2.34.1
|
|
|