testcontainers_modules/redis/
stack.rs

1use testcontainers::{core::WaitFor, Image};
2
3const NAME: &str = "redis/redis-stack-server";
4const TAG: &str = "7.2.0-v8";
5
6/// Module to work with [`Redis Stack`] inside of tests.
7///
8/// Starts an instance of Redis Stack based on the official [`Redis Stack docker image`].
9///
10/// By default Redis is exposed on Port 6379 ([`REDIS_PORT`]) and has no access control. Please refer to the [`Redis reference guide`] for more informations on how to interact with the API.
11///
12/// # Example
13/// ```
14/// use redis::JsonCommands;
15/// use serde_json::json;
16/// use testcontainers_modules::{testcontainers::runners::SyncRunner, redis::{RedisStack, REDIS_PORT}};
17///
18/// let redis_instance = RedisStack::default().start().unwrap();
19/// let host_ip = redis_instance.get_host().unwrap();
20/// let host_port = redis_instance.get_host_port_ipv4(REDIS_PORT).unwrap();
21///
22/// let url = format!("redis://{host_ip}:{host_port}");
23/// let client = redis::Client::open(url.as_ref()).unwrap();
24/// let mut con = client.get_connection().unwrap();
25///
26/// con.json_set::<_,_,_,()>("my_key", "$", &json!({ "number": 42 })).unwrap();
27/// let result: String = con.json_get("my_key", "$..number").unwrap();
28/// ```
29///
30/// [`Redis Stack`]: https://redis.io/docs/about/about-stack/
31/// [`Redis Stack docker image`]: https://hub.docker.com/r/redis/redis-stack-server
32/// [`Redis reference guide`]: https://redis.io/docs/interact/
33/// [`REDIS_PORT`]: super::REDIS_PORT
34#[derive(Debug, Default, Clone)]
35pub struct RedisStack {
36    /// (remove if there is another variable)
37    /// Field is included to prevent this struct to be a unit struct.
38    /// This allows extending functionality (and thus further variables) without breaking changes
39    _priv: (),
40}
41
42impl Image for RedisStack {
43    fn name(&self) -> &str {
44        NAME
45    }
46
47    fn tag(&self) -> &str {
48        TAG
49    }
50
51    fn ready_conditions(&self) -> Vec<WaitFor> {
52        vec![WaitFor::message_on_stdout("Ready to accept connections")]
53    }
54}
55
56#[cfg(test)]
57mod tests {
58    use redis::JsonCommands;
59    use serde_json::json;
60
61    use crate::{
62        redis::{RedisStack, REDIS_PORT},
63        testcontainers::runners::SyncRunner,
64    };
65
66    #[test]
67    fn redis_fetch_an_integer_in_json() -> Result<(), Box<dyn std::error::Error + 'static>> {
68        let _ = pretty_env_logger::try_init();
69        let node = RedisStack::default().start()?;
70        let host_ip = node.get_host()?;
71        let host_port = node.get_host_port_ipv4(REDIS_PORT)?;
72        let url = format!("redis://{host_ip}:{host_port}");
73
74        let client = redis::Client::open(url.as_ref()).unwrap();
75        let mut con = client.get_connection().unwrap();
76
77        assert_eq!(
78            con.json_set("my_key", "$", &json!({ "number": 42 })),
79            Ok(true)
80        );
81        let result: String = con.json_get("my_key", "$..number").unwrap();
82        assert_eq!("[42]", result);
83        Ok(())
84    }
85}