Skip to main content

zombienet_provider/shared/
helpers.rs

1use std::{env, path::PathBuf};
2
3use anyhow::anyhow;
4
5use crate::{types::RunCommandOptions, DynNode, ProviderError};
6
7/// Check if we are running in `CI` by checking the 'RUN_IN_CI' env var
8pub fn running_in_ci() -> bool {
9    env::var("RUN_IN_CI").unwrap_or_default() == "1"
10}
11
12/// serde default for the fields that older records did not carry.
13pub(crate) fn default_true() -> bool {
14    true
15}
16
17/// The pause/resume/restart controls are messages on the wrapper's pipe. A
18/// process started without the wrapper has no pipe, and `echo` into a path
19/// that is not a pipe would create a file and report success, so refuse.
20pub(crate) fn ensure_wrapper(
21    name: &str,
22    wrapper: bool,
23    action: &str,
24    failed: fn(String, anyhow::Error) -> ProviderError,
25) -> Result<(), ProviderError> {
26    if wrapper {
27        Ok(())
28    } else {
29        Err(failed(
30            name.to_string(),
31            anyhow!("runs without the zombie wrapper, {action} is not available"),
32        ))
33    }
34}
35
36/// Executes a command on a temporary node and extracts the execution result either from the
37/// standard output or a file.
38pub async fn extract_execution_result(
39    temp_node: &DynNode,
40    options: RunCommandOptions,
41    expected_path: Option<&PathBuf>,
42) -> Result<String, ProviderError> {
43    let output_contents = temp_node
44        .run_command(options)
45        .await?
46        .map_err(|(_, msg)| ProviderError::FileGenerationFailed(anyhow!("{msg}")))?;
47
48    // If an expected_path is provided, read the file contents from inside the container
49    if let Some(expected_path) = expected_path.as_ref() {
50        Ok(temp_node
51            .run_command(
52                RunCommandOptions::new("cat")
53                    .args(vec![expected_path.to_string_lossy().to_string()]),
54            )
55            .await?
56            .map_err(|(_, msg)| {
57                ProviderError::FileGenerationFailed(anyhow!(format!(
58                    "failed reading expected_path {}: {}",
59                    expected_path.display(),
60                    msg
61                )))
62            })?)
63    } else {
64        Ok(output_contents)
65    }
66}
67
68pub fn extract_namespace_info(
69    json_value: &serde_json::Value,
70) -> Result<(PathBuf, String), ProviderError> {
71    let base_dir = json_value
72        .get("local_base_dir")
73        .and_then(|v| v.as_str())
74        .map(PathBuf::from)
75        .ok_or(ProviderError::InvalidConfig(
76            "`field local_base_dir` is missing from zombie.json".to_string(),
77        ))?;
78
79    let name =
80        json_value
81            .get("ns")
82            .and_then(|v| v.as_str())
83            .ok_or(ProviderError::InvalidConfig(
84                "field `ns` is missing from zombie.json".to_string(),
85            ))?;
86
87    Ok((base_dir, name.to_string()))
88}
89
90#[cfg(test)]
91mod tests {
92    use super::*;
93
94    #[test]
95    fn check_runing_in_ci_env_var() {
96        assert!(!running_in_ci());
97        // now set the env var
98        env::set_var("RUN_IN_CI", "1");
99        assert!(running_in_ci());
100        // reset
101        env::set_var("RUN_IN_CI", "");
102    }
103}