diff options
Diffstat (limited to 'crates/core')
24 files changed, 213 insertions, 302 deletions
diff --git a/crates/core/agent_interface/Cargo.toml b/crates/core/agent_interface/Cargo.toml index 352f62b2..e7fb2d01 100644 --- a/crates/core/agent_interface/Cargo.toml +++ b/crates/core/agent_interface/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "agent_interface" -version = "0.6.1" +version = "0.6.2" authors = ["thin-edge.io team <info@thin-edge.io>"] edition = "2021" rust-version = "1.58.1" diff --git a/crates/core/c8y_api/Cargo.toml b/crates/core/c8y_api/Cargo.toml index 3d9e8036..aefbb6c5 100644 --- a/crates/core/c8y_api/Cargo.toml +++ b/crates/core/c8y_api/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "c8y_api" -version = "0.6.1" +version = "0.6.2" authors = ["thin-edge.io team <info@thin-edge.io>"] edition = "2021" rust-version = "1.58.1" diff --git a/crates/core/c8y_smartrest/Cargo.toml b/crates/core/c8y_smartrest/Cargo.toml index 5426da5e..3aed6de4 100644 --- a/crates/core/c8y_smartrest/Cargo.toml +++ b/crates/core/c8y_smartrest/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "c8y_smartrest" -version = "0.6.1" +version = "0.6.2" authors = ["thin-edge.io team <info@thin-edge.io>"] edition = "2021" rust-version = "1.58.1" diff --git a/crates/core/c8y_translator/Cargo.toml b/crates/core/c8y_translator/Cargo.toml index a8c427ec..b2aecfe3 100644 --- a/crates/core/c8y_translator/Cargo.toml +++ b/crates/core/c8y_translator/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "c8y_translator" -version = "0.6.1" +version = "0.6.2" authors = ["thin-edge.io team <info@thin-edge.io>"] edition = "2021" rust-version = "1.58.1" diff --git a/crates/core/c8y_translator/fuzz/Cargo.lock b/crates/core/c8y_translator/fuzz/Cargo.lock index e7a4927b..b9b5965d 100644 --- a/crates/core/c8y_translator/fuzz/Cargo.lock +++ b/crates/core/c8y_translator/fuzz/Cargo.lock @@ -25,7 +25,7 @@ checksum = "cdb031dd78e28731d87d56cc8ffef4a8f36ca26c38fe2de700543e627f8a464a" [[package]] name = "c8y_translator" -version = "0.6.1" +version = "0.6.2" dependencies = [ "clock", "json-writer", @@ -56,7 +56,7 @@ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" [[package]] name = "clock" -version = "0.6.1" +version = "0.6.2" dependencies = [ "mockall", "time", @@ -97,7 +97,7 @@ checksum = "1aab8fc367588b89dcee83ab0fd66b72b50b72fa1904d7095045ace2b0c81c35" [[package]] name = "json-writer" -version = "0.6.1" +version = "0.6.2" dependencies = [ "serde_json", "thiserror", @@ -309,7 +309,7 @@ checksum = "507e9898683b6c43a9aa55b64259b721b52ba226e0f3779137e50ad114a4c90b" [[package]] name = "thin_edge_json" -version = "0.6.1" +version = "0.6.2" dependencies = [ "clock", "json-writer", diff --git a/crates/core/plugin_sm/Cargo.toml b/crates/core/plugin_sm/Cargo.toml index b246444d..e54837a1 100644 --- a/crates/core/plugin_sm/Cargo.toml +++ b/crates/core/plugin_sm/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "plugin_sm" -version = "0.6.1" +version = "0.6.2" authors = ["thin-edge.io team <info@thin-edge.io>"] edition = "2021" rust-version = "1.58.1" @@ -10,6 +10,7 @@ agent_interface = { path = "../agent_interface" } async-trait = "0.1" csv = "1.1" download = { path = "../../common/download" } +logged_command = { path = "../../common/logged_command" } serde = { version = "1.0", features = ["derive"] } serde_json = "1.0" tedge_utils = { path = "../../common/tedge_utils" } diff --git a/crates/core/plugin_sm/src/lib.rs b/crates/core/plugin_sm/src/lib.rs index 79800999..c124bbbc 100644 --- a/crates/core/plugin_sm/src/lib.rs +++ b/crates/core/plugin_sm/src/lib.rs @@ -1,4 +1,3 @@ pub mod log_file; -pub mod logged_command; pub mod plugin; pub mod plugin_manager; diff --git a/crates/core/plugin_sm/src/logged_command.rs b/crates/core/plugin_sm/src/logged_command.rs deleted file mode 100644 index 11739ce0..00000000 --- a/crates/core/plugin_sm/src/logged_command.rs +++ /dev/null @@ -1,231 +0,0 @@ -use std::ffi::OsStr; -use std::process::{Output, Stdio}; -use tokio::fs::File; -use tokio::io::{AsyncWriteExt, BufWriter}; -use tokio::process::{Child, Command}; - -pub struct LoggingChild { - command_line: String, - pub inner_child: Child, -} - -impl LoggingChild { - pub async fn wait_with_output( - self, - logger: &mut BufWriter<File>, - ) -> Result<Output, std::io::Error> { - let outcome = self.inner_child.wait_with_output().await; - if let Err(err) = LoggedCommand::log_outcome(&self.command_line, &outcome, logger).await { - tracing::log::error!("Fail to log the command execution: {}", err); - } - - outcome - } -} - -/// A command which execution is logged. -/// -/// This struct wraps the main command with a nice representation of that command. -/// This `command_line` field is only required because the -/// [`Command::get_program()`](https://doc.rust-lang.org/std/process/struct.Command.html#method.get_program) -/// and -/// [`Command::get_args()`](https://doc.rust-lang.org/std/process/struct.Command.html#method.get_args) -/// are nightly-only experimental APIs. -pub struct LoggedCommand { - command_line: String, - command: Command, -} - -impl std::fmt::Display for LoggedCommand { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - self.command_line.fmt(f) - } -} - -impl LoggedCommand { - pub fn new(program: impl AsRef<OsStr>) -> LoggedCommand { - let command_line = match program.as_ref().to_str() { - None => format!("{:?}", program.as_ref()), - Some(cmd) => cmd.to_string(), - }; - - let mut command = Command::new(program); - command - .current_dir("/tmp") - .stdin(Stdio::piped()) - .stdout(Stdio::piped()) - .stderr(Stdio::piped()); - - LoggedCommand { - command_line, - command, - } - } - - pub fn arg(&mut self, arg: impl AsRef<OsStr>) -> &mut LoggedCommand { - // The arguments are displayed as debug, to be properly quoted and distinguished from each other. - self.command_line.push_str(&format!(" {:?}", arg.as_ref())); - self.command.arg(arg); - self - } - - /// Execute the command and log its exit status, stdout and stderr - /// - /// If the command has been executed the outcome is returned (successful or not). - /// If the command fails to execute (say not found or not executable) an `std::io::Error` is returned. - /// - /// If the function fails to log the execution of the command, - /// this is logged with `log::error!` without changing the return value. - pub async fn execute(mut self, logger: &mut BufWriter<File>) -> Result<Output, std::io::Error> { - let outcome = self.command.output().await; - - if let Err(err) = LoggedCommand::log_outcome(&self.command_line, &outcome, logger).await { - tracing::log::error!("Fail to log the command execution: {}", err); - } - - outcome - } - - pub fn spawn(&mut self) -> Result<LoggingChild, std::io::Error> { - let child = self.command.spawn()?; - Ok(LoggingChild { - command_line: self.command_line.clone(), - inner_child: child, - }) - } - - async fn log_outcome( - command_line: &str, - result: &Result<Output, std::io::Error>, - logger: &mut BufWriter<File>, - ) -> Result<(), std::io::Error> { - logger - .write_all(format!("----- $ {}\n", command_line).as_bytes()) - .await?; - - match result.as_ref() { - Ok(output) => { - match &output.status.code() { - None => logger.write_all(b"exit status: unknown\n\n").await?, - Some(code) => { - logger - .write_all(format!("exit status: {}\n\n", code).as_bytes()) - .await? - } - }; - logger.write_all(b"stdout <<EOF\n").await?; - logger.write_all(&output.stdout).await?; - logger.write_all(b"EOF\n\n").await?; - logger.write_all(b"stderr <<EOF\n").await?; - logger.write_all(&output.stderr).await?; - logger.write_all(b"EOF\n").await?; - } - Err(err) => { - logger - .write_all(format!("error: {}\n", &err).as_bytes()) - .await?; - } - } - - logger.flush().await?; - Ok(()) - } -} - -#[cfg(test)] -mod tests { - use super::*; - use tempfile::*; - use tokio::fs::File; - - #[tokio::test] - async fn on_execute_are_logged_command_line_exit_status_stdout_and_stderr( - ) -> Result<(), anyhow::Error> { - // Prepare a log file - let tmp_dir = TempDir::new()?; - let log_file_path = tmp_dir.path().join("operation.log"); - let log_file = File::create(log_file_path.clone()).await?; - let mut logger = BufWriter::new(log_file); - - // Prepare a command - let mut command = LoggedCommand::new("echo"); - command.arg("Hello").arg("World!"); - - // Execute the command with logging - let _ = command.execute(&mut logger).await; - - let log_content = String::from_utf8(std::fs::read(&log_file_path)?)?; - assert_eq!( - log_content, - r#"----- $ echo "Hello" "World!" -exit status: 0 - -stdout <<EOF -Hello World! -EOF - -stderr <<EOF -EOF -"# - ); - Ok(()) - } - - #[tokio::test] - async fn on_execute_with_error_stderr_is_logged() -> Result<(), anyhow::Error> { - // Prepare a log file - let tmp_dir = TempDir::new()?; - let log_file_path = tmp_dir.path().join("operation.log"); - let log_file = File::create(log_file_path.clone()).await?; - let mut logger = BufWriter::new(log_file); - - // Prepare a command that triggers some content on stderr - let mut command = LoggedCommand::new("ls"); - command.arg("dummy-file"); - - // Execute the command with logging - let _ = command.execute(&mut logger).await; - - // On expect the errors to be logged - let log_content = String::from_utf8(std::fs::read(&log_file_path)?)?; - assert_eq!( - log_content, - r#"----- $ ls "dummy-file" -exit status: 2 - -stdout <<EOF -EOF - -stderr <<EOF -ls: cannot access 'dummy-file': No such file or directory -EOF -"# - ); - Ok(()) - } - - #[tokio::test] - async fn on_execution_error_are_logged_command_line_and_error() -> Result<(), anyhow::Error> { - // Prepare a log file - let tmp_dir = TempDir::new()?; - let log_file_path = tmp_dir.path().join("operation.log"); - let log_file = File::create(log_file_path.clone()).await?; - let mut logger = BufWriter::new(log_file); - - // Prepare a command that cannot be executed - let command = LoggedCommand::new("dummy-command"); - - // Execute the command with logging - let _ = command.execute(&mut logger).await; - - // The fact that the command cannot be executed must be logged - let log_content = String::from_utf8(std::fs::read(&log_file_path)?)?; - assert_eq!( - log_content, - r#"----- $ dummy-command -error: No such file or directory (os error 2) -"# - ); - Ok(()) - } -} diff --git a/crates/core/plugin_sm/src/plugin.rs b/crates/core/plugin_sm/src/plugin.rs index f7df5449..95ab2988 100644 --- a/crates/core/plugin_sm/src/plugin.rs +++ b/crates/core/plugin_sm/src/plugin.rs @@ -1,8 +1,8 @@ -use crate::logged_command::LoggedCommand; use agent_interface::*; use async_trait::async_trait; use csv::ReaderBuilder; use download::Downloader; +use logged_command::LoggedCommand; use serde::Deserialize; use std::path::Path; use std::{path::PathBuf, process::Output}; diff --git a/crates/core/tedge/Cargo.toml b/crates/core/tedge/Cargo.toml index 14b13d89..f236f29b 100644 --- a/crates/core/tedge/Cargo.toml +++ b/crates/core/tedge/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "tedge" -version = "0.6.1" +version = "0.6.2" edition = "2021" rust-version = "1.58.1" authors = ["thin-edge.io team <info@thin-edge.io>"] @@ -9,7 +9,7 @@ readme = "README.md" description = "tedge is the cli tool for thin-edge.io" [package.metadata.deb] -depends = "mosquitto" +recommends = "mosquitto" maintainer-scripts = "../../../configuration/debian/tedge" [dependencies] diff --git a/crates/core/tedge/src/cli/config/config_key.rs b/crates/core/tedge/src/cli/config/config_key.rs index 064791a4..96227269 100644 --- a/crates/core/tedge/src/cli/config/config_key.rs +++ b/crates/core/tedge/src/cli/config/config_key.rs @@ -57,9 +57,9 @@ impl ConfigKey { config_key!(MqttExternalCertfileSetting), config_key!(MqttExternalKeyfileSetting), config_key!(SoftwarePluginDefaultSetting), - config_key!(TmpPathDefaultSetting), - config_key!(LogPathDefaultSetting), - config_key!(RunPathDefaultSetting), + config_key!(TmpPathSetting), + config_key!(LogPathSetting), + config_key!(RunPathSetting), ] } } diff --git a/crates/core/tedge/src/main.rs b/crates/core/tedge/src/main.rs index 5b384e35..eab007f6 100644 --- a/crates/core/tedge/src/main.rs +++ b/crates/core/tedge/src/main.rs @@ -1,6 +1,8 @@ #![forbid(unsafe_code)] #![deny(clippy::mem_forget)] +use std::path::PathBuf; + use anyhow::Context; use clap::Parser; use tedge_users::UserManager; @@ -18,7 +20,7 @@ fn main() -> anyhow::Result<()> { let opt = cli::Opt::parse(); if opt.init { - initialize_tedge()?; + initialize_tedge(&opt.config_dir)?; return Ok(()); } @@ -45,12 +47,23 @@ fn main() -> anyhow::Result<()> { } } -fn initialize_tedge() -> anyhow::Result<()> { - create_directory_with_user_group("/etc/tedge", "tedge", "tedge", 0o775)?; +fn initialize_tedge(cfg_dir: &PathBuf) -> anyhow::Result<()> { + let config_dir = cfg_dir.as_path().display().to_string(); + create_directory_with_user_group(&config_dir, "tedge", "tedge", 0o775)?; create_directory_with_user_group("/var/log/tedge", "tedge", "tedge", 0o775)?; - create_directory_with_user_group("/etc/tedge/mosquitto-conf", "tedge", "tedge", 0o775)?; - create_directory_with_user_group("/etc/tedge/operations", "tedge", "tedge", 0o775)?; - create_directory_with_user_group("/etc/tedge/plugins", "tedge", "tedge", 0o775)?; - create_directory_with_user_group("/etc/tedge/device-certs", "mosquitto", "mosquitto", 0o775)?; + create_directory_with_user_group( + &format!("{config_dir}/mosquitto-conf"), + "tedge", + "tedge", + 0o775, + )?; + create_directory_with_user_group(&format!("{config_dir}/operations"), "tedge", "tedge", 0o775)?; + create_directory_with_user_group(&format!("{config_dir}/plugins"), "tedge", "tedge", 0o775)?; + create_directory_with_user_group( + &format!("{config_dir}/device-certs"), + "mosquitto", + "mosquitto", + 0o775, + )?; Ok(()) } diff --git a/crates/core/tedge_agent/Cargo.toml b/crates/core/tedge_agent/Cargo.toml index 63a2ba5a..af1498bf 100644 --- a/crates/core/tedge_agent/Cargo.toml +++ b/crates/core/tedge_agent/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "tedge_agent" -version = "0.6.1" +version = "0.6.2" authors = ["thin-edge.io team <info@thin-edge.io>"] edition = "2021" rust-version = "1.58.1" diff --git a/crates/core/tedge_agent/src/agent.rs b/crates/core/tedge_agent/src/agent.rs index df41368f..b7c7ba27 100644 --- a/crates/core/tedge_agent/src/agent.rs +++ b/crates/core/tedge_agent/src/agent.rs @@ -20,9 +20,9 @@ use serde_json::json; use std::process; use std::{convert::TryInto, fmt::Debug, path::PathBuf, sync::Arc}; use tedge_config::{ - ConfigRepository, ConfigSettingAccessor, ConfigSettingAccessorStringExt, LogPathDefaultSetting, - MqttBindAddressSetting, MqttPortSetting, RunPathDefaultSetting, SoftwarePluginDefaultSetting, - TEdgeConfigLocation, TmpPathDefaultSetting, DEFAULT_LOG_PATH, DEFAULT_RUN_PATH, + ConfigRepository, ConfigSettingAccessor, ConfigSettingAccessorStringExt, LogPathSetting, + MqttBindAddressSetting, MqttPortSetting, RunPathSetting, SoftwarePluginDefaultSetting, + TEdgeConfigLocation, TmpPathSetting, DEFAULT_LOG_PATH, DEFAULT_RUN_PATH, }; use tedge_utils::file::create_directory_with_user_group; use tokio::sync::Mutex; @@ -139,11 +139,11 @@ impl SmAgentConfig { .tedge_config_root_path() .to_path_buf(); - let tedge_download_dir = tedge_config.query_string(TmpPathDefaultSetting)?.into(); + let tedge_download_dir = tedge_config.query_string(TmpPathSetting)?.into(); - let tedge_log_dir: String = tedge_config.query_string(LogPathDefaultSetting)?.into(); + let tedge_log_dir: String = tedge_config.query_string(LogPathSetting)?.into(); let tedge_log_dir = PathBuf::from(&format!("{tedge_log_dir}/{AGENT_LOG_PATH}")); - let tedge_run_dir = tedge_config.query_string(RunPathDefaultSetting)?.into(); + let tedge_run_dir = tedge_config.query_string(RunPathSetting)?.into(); Ok(SmAgentConfig::default() .with_sm_home(tedge_config_path) @@ -224,14 +224,10 @@ impl SmAgent { } #[instrument(skip(self), name = "sm-agent")] - pub async fn init(&mut self) -> Result<(), anyhow::Error> { - create_directory_with_user_group("/etc/tedge/.agent", "tedge-agent", "tedge-agent", 0o775)?; - create_directory_with_user_group( - "/var/log/tedge/agent", - "tedge-agent", - "tedge-agent", - 0o775, - )?; + pub async fn init(&mut self, config_dir: PathBuf) -> Result<(), anyhow::Error> { + let cfg_dir = config_dir.as_path().display().to_string(); + create_directory_with_user_group(&format!("{cfg_dir}/.agent"), "tedge", "tedge", 0o775)?; + create_directory_with_user_group("/var/log/tedge/agent", "tedge", "tedge", 0o775)?; info!("Initializing the tedge agent session"); mqtt_channel::init_session(&self.config.mqtt_config).await?; diff --git a/crates/core/tedge_agent/src/main.rs b/crates/core/tedge_agent/src/main.rs index 4e71de4b..96069769 100644 --- a/crates/core/tedge_agent/src/main.rs +++ b/crates/core/tedge_agent/src/main.rs @@ -47,13 +47,13 @@ async fn main() -> Result<(), anyhow::Error> { tedge_utils::logging::initialise_tracing_subscriber(agent_opt.debug); let tedge_config_location = - tedge_config::TEdgeConfigLocation::from_custom_root(agent_opt.config_dir); + tedge_config::TEdgeConfigLocation::from_custom_root(agent_opt.config_dir.clone()); let mut agent = agent::SmAgent::try_new( "tedge_agent", SmAgentConfig::try_new(tedge_config_location)?, )?; if agent_opt.init { - agent.init().await?; + agent.init(agent_opt.config_dir).await?; } else if agent_opt.clear { agent.clear_session().await?; } else { diff --git a/crates/core/tedge_agent/src/state.rs b/crates/core/tedge_agent/src/state.rs index e58052e5..b7819448 100644 --- a/crates/core/tedge_agent/src/state.rs +++ b/crates/core/tedge_agent/src/state.rs @@ -39,7 +39,7 @@ impl StateRepository for AgentStateRepository { async fn store(&self, state: &State) -> Result<(), StateError> { let toml = toml::to_string_pretty(&state)?; - // Create `$HOME/.tedge` or `/etc/tedge` directory in case it does not exist yet + // Create in path given through `config-dir` or `/etc/tedge` directory in case it does not exist yet if !self.state_repo_root.exists() { let () = fs::create_dir(&self.state_repo_root).await?; } diff --git a/crates/core/tedge_mapper/Cargo.toml b/crates/core/tedge_mapper/Cargo.toml index 64bdbd86..92bf879c 100644 --- a/crates/core/tedge_mapper/Cargo.toml +++ b/crates/core/tedge_mapper/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "tedge_mapper" -version = "0.6.1" +version = "0.6.2" authors = ["thin-edge.io team <info@thin-edge.io>"] edition = "2021" rust-version = "1.58.1" @@ -57,6 +57,7 @@ tracing = { version = "0.1", features = ["attributes", "log"] } assert_matches = "1.5" assert-json-diff = "2.0" serde = "1.0" +mockito = "0.31" mqtt_tests = { path = "../../tests/mqtt_tests" } serde_json = "1.0" serial_test = "0.5" diff --git a/crates/core/tedge_mapper/src/az/mapper.rs b/crates/core/tedge_mapper/src/az/mapper.rs index 0d998eff..7f608f08 100644 --- a/crates/core/tedge_mapper/src/az/mapper.rs +++ b/crates/core/tedge_mapper/src/az/mapper.rs @@ -1,3 +1,5 @@ +use std::path::Path; + use crate::{ az::converter::AzureConverter, core::{component::TEdgeComponent, mapper::create_mapper, size_threshold::SizeThreshold}, @@ -26,12 +28,13 @@ impl TEdgeComponent for AzureMapper { AZURE_MAPPER_NAME } - async fn init(&self) -> Result<(), anyhow::Error> { + async fn init(&self, cfg_dir: &Path) -> Result<(), anyhow::Error> { info!("Initialize tedge mapper az"); + let config_dir = cfg_dir.display().to_string(); create_directory_with_user_group( - "/etc/tedge/operations/az", - "tedge-mapper", - "tedge-mapper", + &format!("{config_dir}/operations/az"), + "tedge", + "tedge", 0o775, )?; @@ -39,7 +42,11 @@ impl TEdgeComponent for AzureMapper { Ok(()) } - async fn start(&self, tedge_config: TEdgeConfig) -> Result<(), anyhow::Error> { + async fn start( + &self, + tedge_config: TEdgeConfig, + _config_dir: &Path, + ) -> Result<(), anyhow::Error> { let add_timestamp = tedge_config.query(AzureMapperTimestamp)?.is_set(); let mqtt_port = tedge_config.query(MqttPortSetting)?.into(); let mqtt_host = tedge_config.query(MqttBindAddressSetting)?.to_string(); diff --git a/crates/core/tedge_mapper/src/c8y/mapper.rs b/crates/core/tedge_mapper/src/c8y/mapper.rs index cb9a4f93..3842b3a5 100644 --- a/crates/core/tedge_mapper/src/c8y/mapper.rs +++ b/crates/core/tedge_mapper/src/c8y/mapper.rs @@ -1,3 +1,5 @@ +use std::path::Path; + use crate::{ c8y::converter::CumulocityConverter, core::{component::TEdgeComponent, mapper::create_mapper, size_threshold::SizeThreshold}, @@ -47,19 +49,21 @@ impl TEdgeComponent for CumulocityMapper { CUMULOCITY_MAPPER_NAME } - async fn init(&self) -> Result<(), anyhow::Error> { + async fn init(&self, cfg_dir: &Path) -> Result<(), anyhow::Error> { info!("Initialize tedge mapper c8y"); - create_directories()?; - let operations = Operations::try_new("/etc/tedge/operations", "c8y")?; + let config_dir = cfg_dir.display().to_string(); + create_directories(&config_dir)?; + let operations = Operations::try_new(&format!("{config_dir}/operations"), "c8y")?; self.init_session(CumulocityMapper::subscriptions(&operations)?) .await?; Ok(()) } - async fn start(&self, tedge_config: TEdgeConfig) -> Result<(), anyhow::Error> { + async fn start(&self, tedge_config: TEdgeConfig, cfg_dir: &Path) -> Result<(), anyhow::Error> { let size_threshold = SizeThreshold(MQTT_MESSAGE_SIZE_THRESHOLD); + let config_dir = cfg_dir.display().to_string(); - let operations = Operations::try_new("/etc/tedge/operations", "c8y")?; + let operations = Operations::try_new(format!("{config_dir}/operations"), "c8y")?; let mut http_proxy = JwtAuthHttpProxy::try_new(&tedge_config).await?; http_proxy.init().await?; let device_name = tedge_config.query(DeviceIdSetting)?; @@ -87,24 +91,130 @@ impl TEdgeComponent for CumulocityMapper { } } -fn create_directories() -> Result<(), anyhow::Error> { +fn create_directories(config_dir: &str) -> Result<(), anyhow::Error> { create_directory_with_user_group( - "/etc/tedge/operations/c8y", - "tedge-mapper", - "tedge-mapper", + &format!("{config_dir}/operations/c8y"), + "tedge", + "tedge", 0o775, )?; create_file_with_user_group( - "/etc/tedge/operations/c8y/c8y_SoftwareUpdate", - "tedge-mapper", - "tedge-mapper", + &format!("{config_dir}/operations/c8y/c8y_SoftwareUpdate"), + "tedge", + "tedge", 0o644, )?; create_file_with_user_group( - "/etc/tedge/operations/c8y/c8y_Restart", - "tedge-mapper", - "tedge-mapper", + &format!("{config_dir}/operations/c8y/c8y_Restart"), + "tedge", + "tedge", 0o644, )?; Ok(()) } + +#[cfg(test)] +mod tests { + use super::*; + + use c8y_api::http_proxy::MockC8yJwtTokenRetriever; + use c8y_smartrest::smartrest_deserializer::SmartRestJwtResponse; + use mockito::mock; + use mqtt_tests::{assert_received_all_expected, test_mqtt_broker}; + use serde_json::json; + use std::time::Duration; |