Upgrade testcontainers from 0.12 to 0.14 (#1552)

* Upgrade testcontainers from 0.12 to 0.14

* minor cleanup

---------

Co-authored-by: Byron Hambly <bhambly@blockstream.com>
This commit is contained in:
Ian McKenzie 2024-02-23 11:04:27 -08:00 committed by GitHub
parent 9c5914ff7a
commit b2ca1b5f8c
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
10 changed files with 136 additions and 257 deletions

View file

@ -1,6 +1,5 @@
use std::collections::HashMap;
use testcontainers::core::{Container, Docker, WaitForMessage};
use testcontainers::Image;
use std::collections::BTreeMap;
use testcontainers::{core::WaitFor, Image, ImageArgs};
pub const RPC_USER: &str = "admin";
pub const RPC_PASSWORD: &str = "123";
@ -10,57 +9,27 @@ pub const DATADIR: &str = "/home/bdk";
#[derive(Debug)]
pub struct Bitcoind {
args: BitcoindArgs,
entrypoint: Option<String>,
volume: Option<String>,
volumes: BTreeMap<String, String>,
}
impl Image for Bitcoind {
type Args = BitcoindArgs;
type EnvVars = HashMap<String, String>;
type Volumes = HashMap<String, String>;
type EntryPoint = str;
fn descriptor(&self) -> String {
"coblox/bitcoin-core:0.21.0".to_string()
fn name(&self) -> String {
"coblox/bitcoin-core".into()
}
fn wait_until_ready<D: Docker>(&self, container: &Container<'_, D, Self>) {
container
.logs()
.stdout
.wait_for_message("init message: Done loading")
.unwrap();
fn tag(&self) -> String {
"0.21.0".into()
}
fn args(&self) -> <Self as Image>::Args {
self.args.clone()
fn ready_conditions(&self) -> Vec<WaitFor> {
vec![WaitFor::message_on_stdout("init message: Done loading")]
}
fn volumes(&self) -> Self::Volumes {
let mut volumes = HashMap::new();
match self.volume.clone() {
None => {}
Some(volume) => {
volumes.insert(volume, DATADIR.to_string());
}
}
volumes
}
fn env_vars(&self) -> Self::EnvVars {
HashMap::new()
}
fn with_args(self, args: <Self as Image>::Args) -> Self {
Bitcoind { args, ..self }
}
fn with_entrypoint(self, entrypoint: &Self::EntryPoint) -> Self {
Self {
entrypoint: Some(entrypoint.to_string()),
..self
}
fn volumes(&self) -> Box<dyn Iterator<Item = (&String, &String)> + '_> {
Box::new(self.volumes.iter())
}
fn entrypoint(&self) -> Option<String> {
@ -71,16 +40,15 @@ impl Image for Bitcoind {
impl Default for Bitcoind {
fn default() -> Self {
Bitcoind {
args: BitcoindArgs::default(),
entrypoint: Some("/usr/bin/bitcoind".into()),
volume: None,
volumes: BTreeMap::default(),
}
}
}
impl Bitcoind {
pub fn with_volume(mut self, volume: String) -> Self {
self.volume = Some(volume);
self.volumes.insert(volume, DATADIR.to_string());
self
}
}
@ -109,7 +77,6 @@ impl IntoIterator for BitcoindArgs {
format!("-rpcuser={}", RPC_USER),
format!("-rpcpassword={}", RPC_PASSWORD),
"-printtoconsole".to_string(),
"-rest".to_string(),
"-fallbackfee=0.0002".to_string(),
format!("-datadir={}", DATADIR),
format!("-rpcport={}", RPC_PORT),
@ -120,3 +87,9 @@ impl IntoIterator for BitcoindArgs {
args.into_iter()
}
}
impl ImageArgs for BitcoindArgs {
fn into_iterator(self) -> Box<dyn Iterator<Item = String>> {
Box::new(self.into_iter())
}
}

View file

@ -1,8 +1,8 @@
use std::collections::BTreeMap;
use crate::harness::bitcoind;
use bitcoin::Network;
use std::collections::HashMap;
use testcontainers::core::{Container, Docker, WaitForMessage};
use testcontainers::Image;
use testcontainers::{core::WaitFor, Image, ImageArgs};
pub const HTTP_PORT: u16 = 60401;
pub const RPC_PORT: u16 = 3002;
@ -13,50 +13,25 @@ pub struct Electrs {
args: ElectrsArgs,
entrypoint: Option<String>,
wait_for_message: String,
volume: String,
volumes: BTreeMap<String, String>,
}
impl Image for Electrs {
type Args = ElectrsArgs;
type EnvVars = HashMap<String, String>;
type Volumes = HashMap<String, String>;
type EntryPoint = str;
fn descriptor(&self) -> String {
format!("vulpemventures/electrs:{}", self.tag)
fn name(&self) -> String {
"vulpemventures/electrs".into()
}
fn wait_until_ready<D: Docker>(&self, container: &Container<'_, D, Self>) {
container
.logs()
.stderr
.wait_for_message(&self.wait_for_message)
.unwrap();
fn tag(&self) -> String {
self.tag.clone()
}
fn args(&self) -> <Self as Image>::Args {
self.args.clone()
fn ready_conditions(&self) -> Vec<WaitFor> {
vec![WaitFor::message_on_stderr(self.wait_for_message.clone())]
}
fn volumes(&self) -> Self::Volumes {
let mut volumes = HashMap::new();
volumes.insert(self.volume.clone(), bitcoind::DATADIR.to_string());
volumes
}
fn env_vars(&self) -> Self::EnvVars {
HashMap::new()
}
fn with_args(self, args: <Self as Image>::Args) -> Self {
Electrs { args, ..self }
}
fn with_entrypoint(self, entrypoint: &Self::EntryPoint) -> Self {
Self {
entrypoint: Some(entrypoint.to_string()),
..self
}
fn volumes(&self) -> Box<dyn Iterator<Item = (&String, &String)> + '_> {
Box::new(self.volumes.iter())
}
fn entrypoint(&self) -> Option<String> {
@ -71,7 +46,7 @@ impl Default for Electrs {
args: ElectrsArgs::default(),
entrypoint: Some("/build/electrs".into()),
wait_for_message: "Running accept thread".to_string(),
volume: uuid::Uuid::new_v4().to_string(),
volumes: BTreeMap::default(),
}
}
}
@ -85,7 +60,7 @@ impl Electrs {
}
pub fn with_volume(mut self, volume: String) -> Self {
self.volume = volume;
self.volumes.insert(volume, bitcoind::DATADIR.to_string());
self
}
@ -93,6 +68,11 @@ impl Electrs {
self.args.daemon_rpc_addr = name;
self
}
pub fn self_and_args(self) -> (Self, ElectrsArgs) {
let args = self.args.clone();
(self, args)
}
}
#[derive(Debug, Clone)]
@ -137,7 +117,7 @@ impl IntoIterator for ElectrsArgs {
}
args.push("-vvvvv".to_string());
args.push(format!("--daemon-dir=={}", self.daemon_dir.as_str()));
args.push(format!("--daemon-dir={}", self.daemon_dir.as_str()));
args.push(format!("--daemon-rpc-addr={}", self.daemon_rpc_addr));
args.push(format!("--cookie={}", self.cookie));
args.push(format!("--http-addr={}", self.http_addr));
@ -147,3 +127,9 @@ impl IntoIterator for ElectrsArgs {
args.into_iter()
}
}
impl ImageArgs for ElectrsArgs {
fn into_iterator(self) -> Box<dyn Iterator<Item = String>> {
Box::new(self.into_iter())
}
}

View file

@ -28,7 +28,7 @@ use swap::seed::Seed;
use swap::{asb, bitcoin, cli, env, monero};
use tempfile::{tempdir, NamedTempFile};
use testcontainers::clients::Cli;
use testcontainers::{Container, Docker, RunArgs};
use testcontainers::{Container, RunnableImage};
use tokio::sync::mpsc;
use tokio::sync::mpsc::Receiver;
use tokio::task::JoinHandle;
@ -61,10 +61,7 @@ where
let alice_starting_balances =
StartingBalances::new(bitcoin::Amount::ZERO, xmr_amount, Some(10));
let electrs_rpc_port = containers
.electrs
.get_host_port(electrs::RPC_PORT)
.expect("Could not map electrs rpc port");
let electrs_rpc_port = containers.electrs.get_host_port_ipv4(electrs::RPC_PORT);
let alice_seed = Seed::random().unwrap();
let (alice_bitcoin_wallet, alice_monero_wallet) = init_test_wallets(
@ -146,14 +143,14 @@ where
async fn init_containers(cli: &Cli) -> (Monero, Containers<'_>) {
let prefix = random_prefix();
let bitcoind_name = format!("{}_{}", prefix, "bitcoind");
let (bitcoind, bitcoind_url) =
let (_bitcoind, bitcoind_url, mapped_port) =
init_bitcoind_container(cli, prefix.clone(), bitcoind_name.clone(), prefix.clone())
.await
.expect("could not init bitcoind");
let electrs = init_electrs_container(cli, prefix.clone(), bitcoind_name, prefix)
let electrs = init_electrs_container(cli, prefix.clone(), bitcoind_name, prefix, mapped_port)
.await
.expect("could not init electrs");
let (monero, monerod_container, monero_wallet_rpc_containers) =
let (monero, _monerod_container, _monero_wallet_rpc_containers) =
Monero::new(cli, vec![MONERO_WALLET_NAME_ALICE, MONERO_WALLET_NAME_BOB])
.await
.unwrap();
@ -162,9 +159,9 @@ async fn init_containers(cli: &Cli) -> (Monero, Containers<'_>) {
monero,
Containers {
bitcoind_url,
bitcoind,
monerod_container,
monero_wallet_rpc_containers,
_bitcoind,
_monerod_container,
_monero_wallet_rpc_containers,
electrs,
},
)
@ -175,29 +172,28 @@ async fn init_bitcoind_container(
volume: String,
name: String,
network: String,
) -> Result<(Container<'_, Cli, bitcoind::Bitcoind>, Url)> {
) -> Result<(Container<'_, bitcoind::Bitcoind>, Url, u16)> {
let image = bitcoind::Bitcoind::default().with_volume(volume);
let image = RunnableImage::from(image)
.with_container_name(name)
.with_network(network);
let run_args = RunArgs::default().with_name(name).with_network(network);
let docker = cli.run_with_args(image, run_args);
let a = docker
.get_host_port(bitcoind::RPC_PORT)
.context("Could not map bitcoind rpc port")?;
let docker = cli.run(image);
let port = docker.get_host_port_ipv4(bitcoind::RPC_PORT);
let bitcoind_url = {
let input = format!(
"http://{}:{}@localhost:{}",
bitcoind::RPC_USER,
bitcoind::RPC_PASSWORD,
a
port
);
Url::parse(&input).unwrap()
};
init_bitcoind(bitcoind_url.clone(), 5).await?;
Ok((docker, bitcoind_url.clone()))
Ok((docker, bitcoind_url.clone(), bitcoind::RPC_PORT))
}
pub async fn init_electrs_container(
@ -205,16 +201,18 @@ pub async fn init_electrs_container(
volume: String,
bitcoind_container_name: String,
network: String,
) -> Result<Container<'_, Cli, electrs::Electrs>> {
let bitcoind_rpc_addr = format!("{}:{}", bitcoind_container_name, bitcoind::RPC_PORT);
port: u16,
) -> Result<Container<'_, electrs::Electrs>> {
let bitcoind_rpc_addr = format!("{}:{}", bitcoind_container_name, port);
let image = electrs::Electrs::default()
.with_volume(volume)
.with_daemon_rpc_addr(bitcoind_rpc_addr)
.with_tag("latest");
let image = RunnableImage::from(image.self_and_args())
.with_network(network.clone())
.with_container_name(format!("{}_electrs", network));
let run_args = RunArgs::default().with_network(network);
let docker = cli.run_with_args(image, run_args);
let docker = cli.run(image);
Ok(docker)
}
@ -952,13 +950,12 @@ pub async fn mint(node_url: Url, address: bitcoin::Address, amount: bitcoin::Amo
}
// This is just to keep the containers alive
#[allow(dead_code)]
struct Containers<'a> {
bitcoind_url: Url,
bitcoind: Container<'a, Cli, bitcoind::Bitcoind>,
monerod_container: Container<'a, Cli, image::Monerod>,
monero_wallet_rpc_containers: Vec<Container<'a, Cli, image::MoneroWalletRpc>>,
electrs: Container<'a, Cli, electrs::Electrs>,
_bitcoind: Container<'a, bitcoind::Bitcoind>,
_monerod_container: Container<'a, image::Monerod>,
_monero_wallet_rpc_containers: Vec<Container<'a, image::MoneroWalletRpc>>,
electrs: Container<'a, electrs::Electrs>,
}
pub mod alice_run_until {