rocketmq_common/utils/
env_utils.rs

1/*
2 * Licensed to the Apache Software Foundation (ASF) under one or more
3 * contributor license agreements.  See the NOTICE file distributed with
4 * this work for additional information regarding copyright ownership.
5 * The ASF licenses this file to You under the Apache License, Version 2.0
6 * (the "License"); you may not use this file except in compliance with
7 * the License.  You may obtain a copy of the License at
8 *
9 *     http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16 */
17use std::ffi::OsStr;
18
19use crate::common::mix_all::ROCKETMQ_HOME_ENV;
20
21/// Utility functions related to environment variables.
22pub struct EnvUtils;
23
24impl EnvUtils {
25    /// Gets the value of the specified environment variable.
26    ///
27    /// # Arguments
28    ///
29    /// * `key` - The name of the environment variable to retrieve.
30    ///
31    /// # Returns
32    ///
33    /// An `Option` containing the value of the environment variable, or `None` if the variable is
34    /// not set.
35    pub fn get_property<K: AsRef<OsStr>>(key: K) -> Option<String> {
36        std::env::var(key).ok()
37    }
38
39    /// Retrieves the value of the specified environment variable or returns a default value if the
40    /// variable is not set.
41    ///
42    /// # Arguments
43    /// * `key` - The name of the environment variable to retrieve.
44    /// * `default` - The default value to return if the environment variable is not set.
45    ///
46    /// # Returns
47    /// A `String` containing the value of the environment variable, or the default value.
48    pub fn get_property_or_default<K: AsRef<OsStr>>(key: K, default: impl Into<String>) -> String {
49        std::env::var(key).unwrap_or_else(|_| default.into())
50    }
51
52    /// Retrieves the value of the specified environment variable as an `i32`, or returns a default
53    /// value if the variable is not set or cannot be parsed.
54    ///
55    /// # Arguments
56    /// * `key` - The name of the environment variable to retrieve.
57    /// * `default` - The default value to return if the environment variable is not set or cannot
58    ///   be parsed.
59    ///
60    /// # Returns
61    /// An `i32` containing the value of the environment variable, or the default value.
62    pub fn get_property_as_i32<K: AsRef<OsStr>>(key: K, default: i32) -> i32 {
63        std::env::var(key)
64            .ok()
65            .and_then(|v| v.parse::<i32>().ok())
66            .unwrap_or(default)
67    }
68
69    /// Retrieves the value of the specified environment variable as a `bool`, or returns a default
70    /// value if the variable is not set or cannot be parsed.
71    ///
72    /// # Arguments
73    /// * `key` - The name of the environment variable to retrieve.
74    /// * `default` - The default value to return if the environment variable is not set or cannot
75    ///   be parsed.
76    ///
77    /// # Returns
78    /// A `bool` containing the value of the environment variable, or the default value.
79    ///
80    /// # Notes
81    /// The function considers the following values as `true`: `"true"`, `"1"`.
82    /// The function considers the following values as `false`: `"false"`, `"0"`.
83    pub fn get_property_as_bool<K: AsRef<OsStr>>(key: K, default: bool) -> bool {
84        std::env::var(key)
85            .ok()
86            .and_then(|v| {
87                let lower = v.to_lowercase();
88                match lower.as_str() {
89                    "true" | "1" => Some(true),
90                    "false" | "0" => Some(false),
91                    _ => None,
92                }
93            })
94            .unwrap_or(default)
95    }
96
97    /// Sets the value of the specified environment variable.
98    ///
99    /// # Arguments
100    ///
101    /// * `key` - The name of the environment variable to set.
102    /// * `value` - The value to set the environment variable to.
103    ///
104    /// # Safety
105    ///
106    /// This function uses `unsafe` because it modifies the environment variables,
107    /// which can have side effects on the entire process.
108    pub fn put_property<K: AsRef<OsStr>, V: AsRef<OsStr>>(key: K, value: V) {
109        unsafe {
110            std::env::set_var(key, value);
111        }
112    }
113
114    /// Gets the value of the ROCKETMQ_HOME environment variable.
115    ///
116    /// If ROCKETMQ_HOME is not set, it defaults to the current directory and sets ROCKETMQ_HOME
117    /// accordingly.
118    ///
119    /// # Returns
120    ///
121    /// The value of the ROCKETMQ_HOME environment variable as a `String`.
122    pub fn get_rocketmq_home() -> String {
123        std::env::var(ROCKETMQ_HOME_ENV).unwrap_or_else(|_| unsafe {
124            // If ROCKETMQ_HOME is not set, use the current directory as the default value
125            let rocketmq_home_dir = std::env::current_dir()
126                .ok()
127                .and_then(|p| p.into_os_string().into_string().ok())
128                .unwrap_or_else(|| ".".to_string());
129
130            // Set ROCKETMQ_HOME to the current directory
131            std::env::set_var(ROCKETMQ_HOME_ENV, &rocketmq_home_dir);
132            rocketmq_home_dir
133        })
134    }
135}
136
137#[cfg(test)]
138mod tests {
139    use std::path::PathBuf;
140
141    use super::*;
142
143    #[test]
144    fn test_get_property_existing_variable() {
145        // Set up
146        let key = "HOME";
147        let expected_value = "/home/user";
148
149        unsafe {
150            std::env::set_var(key, expected_value);
151        }
152
153        // Test
154        let result = EnvUtils::get_property(key);
155
156        // Assert
157        assert_eq!(result, Some(expected_value.to_string()));
158    }
159
160    #[test]
161    fn test_get_property_non_existing_variable() {
162        // Set up
163        let key = "NON_EXISTING_VARIABLE";
164
165        // Test
166        let result = EnvUtils::get_property(key);
167
168        // Assert
169        assert_eq!(result, None);
170    }
171
172    /*    #[test]
173    fn test_get_rocketmq_home_existing_variable() {
174        // Set up
175        let expected_value = PathBuf::from("/path/to/rocketmq_home");
176
177        std::env::set_var(ROCKETMQ_HOME_ENV, expected_value.clone());
178
179        // Test
180        let result = EnvUtils::get_rocketmq_home();
181
182        // Assert
183        assert_eq!(result, expected_value.to_string_lossy().to_string());
184    }*/
185
186    #[test]
187    fn test_get_rocketmq_home_non_existing_variable() {
188        // Set up
189        unsafe {
190            std::env::remove_var(ROCKETMQ_HOME_ENV);
191        }
192
193        // Test
194        let result = EnvUtils::get_rocketmq_home();
195
196        // Assert
197        assert_eq!(
198            result,
199            std::env::current_dir()
200                .unwrap()
201                .to_string_lossy()
202                .to_string()
203        );
204    }
205
206    #[test]
207    fn put_property_sets_value() {
208        let key = "TEST_ENV_VAR";
209        let value = "test_value";
210
211        EnvUtils::put_property(key, value);
212
213        let result = std::env::var(key).unwrap();
214        assert_eq!(result, value);
215    }
216
217    #[test]
218    fn put_property_overwrites_existing_value() {
219        let key = "TEST_ENV_VAR1";
220        let initial_value = "initial_value";
221        let new_value = "new_value";
222
223        unsafe {
224            std::env::set_var(key, initial_value);
225        }
226
227        EnvUtils::put_property(key, new_value);
228
229        let result = std::env::var(key).unwrap();
230        assert_eq!(result, new_value);
231    }
232
233    #[test]
234    fn put_property_handles_empty_value() {
235        let key = "TEST_ENV_VAR2";
236        let value = "";
237
238        EnvUtils::put_property(key, value);
239
240        let result = std::env::var(key).unwrap();
241        assert_eq!(result, value);
242    }
243
244    #[test]
245    fn retrieves_env_variable_value() {
246        std::env::set_var("TEST_KEY", "test_value");
247        assert_eq!(
248            EnvUtils::get_property_or_default("TEST_KEY", "default_value"),
249            "test_value"
250        );
251        std::env::remove_var("TEST_KEY");
252    }
253
254    #[test]
255    fn returns_default_when_env_variable_not_set() {
256        assert_eq!(
257            EnvUtils::get_property_or_default("NON_EXISTENT_KEY", "default_value"),
258            "default_value"
259        );
260    }
261
262    #[test]
263    fn retrieves_env_variable_as_i32() {
264        std::env::set_var("TEST_INT_KEY", "42");
265        assert_eq!(EnvUtils::get_property_as_i32("TEST_INT_KEY", 0), 42);
266        std::env::remove_var("TEST_INT_KEY");
267    }
268
269    #[test]
270    fn returns_default_when_env_variable_as_i32_not_set() {
271        assert_eq!(
272            EnvUtils::get_property_as_i32("NON_EXISTENT_INT_KEY", 10),
273            10
274        );
275    }
276
277    #[test]
278    fn returns_default_when_env_variable_as_i32_invalid() {
279        std::env::set_var("INVALID_INT_KEY", "not_a_number");
280        assert_eq!(EnvUtils::get_property_as_i32("INVALID_INT_KEY", 5), 5);
281        std::env::remove_var("INVALID_INT_KEY");
282    }
283
284    #[test]
285    fn returns_default_when_env_variable_as_bool_not_set() {
286        assert!(EnvUtils::get_property_as_bool(
287            "NON_EXISTENT_BOOL_KEY",
288            true
289        ));
290        assert!(!EnvUtils::get_property_as_bool(
291            "NON_EXISTENT_BOOL_KEY",
292            false
293        ));
294    }
295
296    #[test]
297    fn returns_default_when_env_variable_as_bool_invalid() {
298        std::env::set_var("INVALID_BOOL_KEY", "not_a_bool");
299        assert!(EnvUtils::get_property_as_bool("INVALID_BOOL_KEY", true));
300        assert!(!EnvUtils::get_property_as_bool("INVALID_BOOL_KEY", false));
301        std::env::remove_var("INVALID_BOOL_KEY");
302    }
303}