testcontainers_modules/trufflesuite_ganachecli/
mod.rs1use std::borrow::Cow;
2
3use testcontainers::{
4 core::{ContainerPort, WaitFor},
5 Image,
6};
7
8const NAME: &str = "trufflesuite/ganache-cli";
9const TAG: &str = "v6.1.3";
10
11pub const GANACHE_CLI_PORT: ContainerPort = ContainerPort::Tcp(8545);
16
17#[derive(Debug, Default, Clone)]
44pub struct GanacheCli {
45 cmd: GanacheCliCmd,
46}
47
48#[derive(Debug, Clone)]
50pub struct GanacheCliCmd {
51 pub network_id: u32,
53 pub number_of_accounts: u32,
55 pub mnemonic: String,
57}
58
59impl Default for GanacheCliCmd {
60 fn default() -> Self {
61 GanacheCliCmd {
62 network_id: 42,
63 number_of_accounts: 7,
64 mnemonic: "supersecure".to_string(),
65 }
66 }
67}
68
69impl IntoIterator for &GanacheCliCmd {
70 type Item = String;
71 type IntoIter = <Vec<String> as IntoIterator>::IntoIter;
72
73 fn into_iter(self) -> Self::IntoIter {
74 let mut args = Vec::new();
75
76 if !self.mnemonic.is_empty() {
77 args.push("-m".to_string());
78 args.push(self.mnemonic.to_string());
79 }
80
81 args.push("-a".to_string());
82 args.push(self.number_of_accounts.to_string());
83 args.push("-i".to_string());
84 args.push(self.network_id.to_string());
85
86 args.into_iter()
87 }
88}
89
90impl Image for GanacheCli {
91 fn name(&self) -> &str {
92 NAME
93 }
94
95 fn tag(&self) -> &str {
96 TAG
97 }
98
99 fn expose_ports(&self) -> &[ContainerPort] {
100 &[GANACHE_CLI_PORT]
101 }
102
103 fn ready_conditions(&self) -> Vec<WaitFor> {
104 vec![WaitFor::message_on_stdout("Listening on localhost:")]
105 }
106
107 fn cmd(&self) -> impl IntoIterator<Item = impl Into<Cow<'_, str>>> {
108 &self.cmd
109 }
110}
111
112#[cfg(test)]
113mod tests {
114 use testcontainers::runners::SyncRunner;
115
116 use super::*;
117
118 #[test]
119 fn trufflesuite_ganachecli_listaccounts() -> Result<(), Box<dyn std::error::Error + 'static>> {
120 let _ = pretty_env_logger::try_init();
121 let node = GanacheCli::default().start()?;
122 let host_ip = node.get_host()?;
123 let host_port = node.get_host_port_ipv4(GANACHE_CLI_PORT)?;
124
125 let response = reqwest::blocking::Client::new()
126 .post(format!("http://{host_ip}:{host_port}"))
127 .body(
128 serde_json::json!({
129 "jsonrpc": "2.0",
130 "method": "net_version",
131 "params": [],
132 "id": 1
133 })
134 .to_string(),
135 )
136 .header("content-type", "application/json")
137 .send()
138 .unwrap();
139
140 let response = response.text().unwrap();
141 let response: serde_json::Value = serde_json::from_str(&response).unwrap();
142
143 assert_eq!(response["result"], "42");
144 Ok(())
145 }
146}