testcontainers_modules/oracle/free.rs
1use std::borrow::Cow;
2
3use testcontainers::{
4 core::{ContainerPort, WaitFor},
5 Image,
6};
7
8const DEFAULT_IMAGE_NAME: &str = "gvenzl/oracle-free";
9const DEFAULT_IMAGE_TAG: &str = "23-slim-faststart";
10/// Port that the [`Oracle Database Free`] container has internally
11/// Can be rebound externally via [`testcontainers::core::ImageExt::with_mapped_port`]
12///
13/// [`Oracle Database Free`]: https://www.oracle.com/database/free/
14pub const FREE_PORT: ContainerPort = ContainerPort::Tcp(1521);
15
16/// Module to work with [`Oracle Database Free`] inside of tests.
17/// The default image is [`gvenzl/oracle-free:23-slim-faststart`] (unofficial).
18/// Official dockerfiles can be found [here][Oracle official dockerfiles].
19///
20/// The default schema is `test`, with a password `test`.
21///
22/// NOTE: Currently, there is no Oracle Database Free port for ARM chips,
23/// hence Oracle Database Free images cannot run on the new Apple M chips via Docker Desktop.
24///
25/// # Example
26/// ```
27/// use std::time::Duration;
28/// use testcontainers_modules::{oracle::free::Oracle, testcontainers::{runners::SyncRunner, ImageExt}};
29///
30/// // On slower machines more time needed than 60 seconds may be required (see `with_startup_timeout`).
31/// let oracle = Oracle::default()
32/// .start()
33/// .unwrap();
34///
35/// let http_port = oracle.get_host_port_ipv4(1521).unwrap();
36///
37/// // do something with the started Oracle instance..
38/// ```
39///
40/// [`Oracle Database Free`]: https://www.oracle.com/database/free/
41/// [Oracle official dockerfiles]: https://github.com/oracle/docker-images/tree/main/OracleDatabase
42/// [`gvenzl/oracle-free:23-slim-faststart`]: https://hub.docker.com/r/gvenzl/oracle-free
43#[derive(Debug, Default, Clone)]
44pub struct Oracle {
45 /// (remove if there is another variable)
46 /// Field is included to prevent this struct to be a unit struct.
47 /// This allows extending functionality (and thus further variables) without breaking changes
48 _priv: (),
49}
50
51impl Image for Oracle {
52 fn name(&self) -> &str {
53 DEFAULT_IMAGE_NAME
54 }
55
56 fn tag(&self) -> &str {
57 DEFAULT_IMAGE_TAG
58 }
59
60 fn ready_conditions(&self) -> Vec<WaitFor> {
61 vec![WaitFor::message_on_stdout("DATABASE IS READY TO USE!")]
62 }
63
64 fn env_vars(
65 &self,
66 ) -> impl IntoIterator<Item = (impl Into<Cow<'_, str>>, impl Into<Cow<'_, str>>)> {
67 [
68 ("ORACLE_PASSWORD", "testsys"),
69 ("APP_USER", "test"),
70 ("APP_USER_PASSWORD", "test"),
71 ]
72 }
73
74 fn expose_ports(&self) -> &[ContainerPort] {
75 &[FREE_PORT]
76 }
77}
78
79#[cfg(test)]
80mod tests {
81 use std::time::Duration;
82
83 use super::*;
84 use crate::testcontainers::{runners::SyncRunner, ImageExt};
85
86 // remember to provide Oracle client 11.2 or later (see https://crates.io/crates/oracle)
87
88 #[test]
89 fn oracle_one_plus_one() -> Result<(), Box<dyn std::error::Error + 'static>> {
90 let oracle = Oracle::default()
91 .pull_image()?
92 .with_startup_timeout(Duration::from_secs(75));
93
94 let node = oracle.start()?;
95
96 let connection_string = format!(
97 "//{}:{}/FREEPDB1",
98 node.get_host()?,
99 node.get_host_port_ipv4(1521)?
100 );
101 let conn = oracle::Connection::connect("test", "test", connection_string)?;
102
103 let mut rows = conn.query("SELECT 1 + 1", &[])?;
104 let row = rows.next().unwrap()?;
105 let col: i32 = row.get(0)?;
106 assert_eq!(col, 2);
107 Ok(())
108 }
109}