testcontainers_modules/solr/
mod.rs

1use testcontainers::{core::WaitFor, Image};
2
3/// Port that the [`Apache Solr`] container has internally
4/// Can be rebound externally via [`testcontainers::core::ImageExt::with_mapped_port`]
5///
6/// [`Apache Solr`]: https://solr.apache.org/
7pub const SOLR_PORT: u16 = 8983;
8
9const NAME: &str = "solr";
10const TAG: &str = "9.5.0-slim";
11
12/// Module to work with [`Solr`] inside of tests.
13///
14/// Starts an instance of Solr based on the official [`Solr docker image`].
15///
16/// By default Solr is exposed via HTTP on Port 8983 ([`SOLR_PORT`]) and has no access control. Please refer to the [`Solr reference guide`] for more informations on how to interact with the API.
17///
18/// # Example
19/// ```
20/// use testcontainers_modules::{solr, testcontainers::runners::SyncRunner};
21///
22/// let solr_instance = solr::Solr::default().start().unwrap();
23/// let host_port = solr_instance.get_host_port_ipv4(solr::SOLR_PORT).unwrap();
24///
25/// let solr_url = format!("http://127.0.0.1:{}", host_port);
26///
27/// // use HTTP client to interact with the solr API
28/// ```
29///
30/// [`Solr`]: https://solr.apache.org/
31/// [`Solr docker image`]: https://hub.docker.com/_/solr
32/// [`Solr reference guide`]: https://solr.apache.org/guide/solr/latest/
33#[derive(Debug, Default, Clone)]
34pub struct Solr {
35    /// (remove if there is another variable)
36    /// Field is included to prevent this struct to be a unit struct.
37    /// This allows extending functionality (and thus further variables) without breaking changes
38    _priv: (),
39}
40
41impl Image for Solr {
42    fn name(&self) -> &str {
43        NAME
44    }
45
46    fn tag(&self) -> &str {
47        TAG
48    }
49
50    fn ready_conditions(&self) -> Vec<WaitFor> {
51        vec![WaitFor::message_on_stdout("o.e.j.s.Server Started Server")]
52    }
53}
54
55#[cfg(test)]
56mod tests {
57    use reqwest::{self, StatusCode};
58    use testcontainers::runners::SyncRunner;
59
60    use super::*;
61
62    #[test]
63    fn solr_ping() -> Result<(), Box<dyn std::error::Error + 'static>> {
64        let solr_image = Solr::default();
65        let container = solr_image.start()?;
66        let host_ip = container.get_host()?;
67        let host_port = container.get_host_port_ipv4(SOLR_PORT)?;
68
69        let url = format!("http://{host_ip}:{host_port}/solr/admin/cores?action=STATUS");
70        let res = reqwest::blocking::get(url).expect("valid HTTP response");
71
72        assert_eq!(res.status(), StatusCode::OK);
73
74        let json: serde_json::Value = res.json().expect("valid JSON body");
75
76        assert_eq!(json["responseHeader"]["status"], 0);
77        Ok(())
78    }
79}