opensearch_testcontainer/
lib.rs1use std::{borrow::Cow, collections::HashMap};
2
3use testcontainers::{core::*, Image};
4
5const NAME: &str = "opensearchproject/opensearch";
6const TAG: &str = "3.1.0";
7
8#[derive(Debug, Clone)]
9pub struct OpenSearch {
10 image_name: String,
11 env_vars: HashMap<String, String>,
12 tag: String,
13 username: String,
14 password: String,
15}
16
17impl OpenSearch {
18 pub fn with_name(mut self, name: &str) -> Self {
19 self.image_name = name.to_owned();
20 self
21 }
22
23 pub fn with_tag(mut self, tag: &str) -> Self {
24 self.tag = tag.to_owned();
25 self
26 }
27
28 pub fn with_cluster_name(mut self, name: &str) -> Self {
29 self.env_vars
30 .insert("cluster.name".to_owned(), name.to_owned());
31 self
32 }
33
34 pub fn with_env_var(mut self, key: &str, value: &str) -> Self {
35 self.env_vars.insert(key.to_owned(), value.to_owned());
36 self
37 }
38
39 pub fn username(&self) -> String {
40 self.username.to_owned()
41 }
42
43 pub fn password(&self) -> String {
44 self.password.to_owned()
45 }
46}
47
48impl Default for OpenSearch {
49 fn default() -> Self {
50 let mut env_vars = HashMap::new();
51 env_vars.insert("discovery.type".to_owned(), "single-node".to_owned());
52 env_vars.insert(
53 "OPENSEARCH_INITIAL_ADMIN_PASSWORD".to_owned(),
54 "?qbr9:6Y7nk6".to_owned(),
55 );
56 OpenSearch {
57 image_name: NAME.to_owned(),
58 env_vars,
59 tag: TAG.to_owned(),
60 username: "admin".to_owned(),
61 password: "?qbr9:6Y7nk6".to_owned(),
62 }
63 }
64}
65
66impl Image for OpenSearch {
67 fn name(&self) -> &str {
68 &self.image_name.as_str()
69 }
70
71 fn tag(&self) -> &str {
72 self.tag.as_str()
73 }
74
75 fn ready_conditions(&self) -> Vec<WaitFor> {
76 vec![
77 WaitFor::message_on_stdout("[YELLOW] to [GREEN]"),
78 WaitFor::message_on_stdout("ML configuration initialized successfully"),
79 ]
80 }
81
82 fn env_vars(
83 &self,
84 ) -> impl IntoIterator<Item = (impl Into<Cow<'_, str>>, impl Into<Cow<'_, str>>)> {
85 Box::new(self.env_vars.iter())
86 }
87
88 fn expose_ports(&self) -> &[ContainerPort] {
89 &[
90 ContainerPort::Tcp(9200),
91 ContainerPort::Tcp(9300),
92 ContainerPort::Tcp(9600),
93 ]
94 }
95}
96
97#[cfg(test)]
98mod tests {
99 use testcontainers::runners::AsyncRunner;
100
101 use crate::OpenSearch as OpenSearchImage;
102
103 #[tokio::test(flavor = "multi_thread", worker_threads = 2)]
104 async fn opensearch_default() {
105 let os_image = OpenSearchImage::default();
106 let opensearch = os_image.clone().start().await.unwrap();
107 let host_port = opensearch.get_host_port_ipv4(9200).await.unwrap();
108
109 let client = reqwest::Client::builder()
110 .danger_accept_invalid_certs(true)
111 .build()
112 .unwrap();
113
114 let response = client
115 .get(format!("https://127.0.0.1:{host_port}"))
116 .header("content-type", "application/json")
117 .basic_auth(os_image.username(), Some(os_image.password()))
118 .send()
119 .await
120 .unwrap();
121
122 let response = response.text().await.unwrap();
123 println!("response: {}", response);
124 let response: serde_json::Value = serde_json::from_str(&response).unwrap();
125
126 assert_eq!(response["version"]["number"], "3.1.0");
127 }
128}