Skip to content

Commit

Permalink
Add integration test for PoolSv2
Browse files Browse the repository at this point in the history
  • Loading branch information
jbesraa committed Sep 16, 2024
1 parent 0f48f9c commit 8c0a408
Show file tree
Hide file tree
Showing 5 changed files with 108 additions and 11 deletions.
4 changes: 4 additions & 0 deletions .github/workflows/test.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,10 @@ jobs:
cargo build --manifest-path=roles/Cargo.toml
cargo build --manifest-path=utils/Cargo.toml
- name: Roles Integration Tests
run: |
cargo test --manifest-path=roles/Cargo.toml --verbose --test '*' -- --nocapture
- name: Run sv1-client-and-server example
run: |
cargo run --manifest-path=examples/sv1-client-and-server/Cargo.toml --bin client_and_server -- 60
Expand Down
1 change: 1 addition & 0 deletions roles/Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions roles/tests-integration/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ once_cell = "1.20.0"
tar = "0.4.41"
pool_sv2 = { version = "0.1.0", path = "../pool" }
key-utils = { version = "1.0.0", path = "../../utils/key-utils" }
tokio = { version = "1.0.1", features = ["full"] }

[lib]
path = "tests/common/mod.rs"
77 changes: 66 additions & 11 deletions roles/tests-integration/tests/common/mod.rs
Original file line number Diff line number Diff line change
@@ -1,18 +1,20 @@
use bitcoind::{bitcoincore_rpc::RpcApi, BitcoinD, Conf};
use flate2::read::GzDecoder;
use key_utils::{Secp256k1PublicKey, Secp256k1SecretKey};
use once_cell::sync::Lazy;
use pool_sv2::PoolSv2;
use std::{
collections::HashSet,
env,
fs::{create_dir_all, File},
io::{BufReader, Read},
net::TcpListener,
net::{SocketAddr, TcpListener},
path::{Path, PathBuf},
str::FromStr,
sync::Mutex,
time::Duration,
};
use tar::Archive;
use once_cell::sync::Lazy;
use std::collections::HashSet;
use std::sync::Mutex;

// prevents get_available_port from ever returning the same port twice
static UNIQUE_PORTS: Lazy<Mutex<HashSet<u16>>> = Lazy::new(|| Mutex::new(HashSet::new()));
Expand Down Expand Up @@ -163,10 +165,7 @@ impl TemplateProvider {
}

pub fn is_port_open(address: std::net::SocketAddr) -> bool {
match TcpListener::bind(address) {
Ok(_) => false,
Err(_) => true,
}
TcpListener::bind(address).is_err()
}

pub fn get_available_port() -> u16 {
Expand All @@ -186,14 +185,17 @@ pub fn get_available_port() -> u16 {
}

#[derive(Debug)]
pub struct TestPoolSv2;
pub struct TestPoolSv2 {
pub pool: PoolSv2,
pub pool_port: u16,
}

impl TestPoolSv2 {
pub fn new(
listening_address: std::net::SocketAddr,
coinbase_outputs: Option<Vec<pool_sv2::mining_pool::CoinbaseOutput>>,
template_provider_address: Option<std::net::SocketAddr>,
) -> PoolSv2 {
) -> Self {
use pool_sv2::mining_pool::{CoinbaseOutput, Configuration};
let authority_public_key = Secp256k1PublicKey::try_from(
"9auqWEzQDVyd2oe1JVGFLMLHZtCo2FFqZwtKA5gd9xbuEu7PH72".to_string(),
Expand Down Expand Up @@ -234,6 +236,59 @@ impl TestPoolSv2 {
coinbase_outputs,
);
let pool = PoolSv2::new(config);
pool

Self {
pool,
pool_port: listening_address.port(),
}
}
}

pub async fn start_template_provider() -> (TemplateProvider, u16) {
let template_provider_port = get_available_port();
let template_provider = TemplateProvider::start(template_provider_port);
template_provider.generate_blocks(16);
(template_provider, template_provider_port)
}

pub async fn setup_poolsv2(
pool_listening_address: Option<std::net::SocketAddr>,
pool_coinbase_outputs: Option<Vec<pool_sv2::mining_pool::CoinbaseOutput>>,
template_provider_port: u16,
) -> (TestPoolSv2, u16) {
let pool_port = get_available_port();
let pool_listening_address = pool_listening_address
.unwrap_or(SocketAddr::from_str(&format!("127.0.0.1:{}", pool_port)).unwrap());
let is_pool_port_open = is_port_open(pool_listening_address);
assert_eq!(is_pool_port_open, false);
let pool = TestPoolSv2::new(
pool_listening_address,
pool_coinbase_outputs,
Some(SocketAddr::from_str(&format!("127.0.0.1:{}", template_provider_port)).unwrap()),
);
(pool, pool_port)
}

pub async fn start_template_provider_and_pool() -> Result<(), ()> {
let (template_provider, template_provider_port) = start_template_provider().await;
let (test_pool, pool_port) = setup_poolsv2(None, None, template_provider_port).await;
let pool = test_pool.pool;
let state = pool.state().await.safe_lock(|s| s.clone()).unwrap();
assert_eq!(state, pool_sv2::PoolState::Initial);
let _pool = pool.clone();
tokio::task::spawn(async move {
assert!(_pool.start().await.is_ok());
});
// Wait for the pool to start.
tokio::time::sleep(Duration::from_secs(1)).await;
let pool_listening_address = SocketAddr::from_str(&format!("127.0.0.1:{}", pool_port)).unwrap();
loop {
if is_port_open(pool_listening_address) {
break;
}
}
let state = pool.state().await.safe_lock(|s| s.clone()).unwrap();
assert_eq!(state, pool_sv2::PoolState::Running);
template_provider.stop();
Ok(())
}
36 changes: 36 additions & 0 deletions roles/tests-integration/tests/pool_integration.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
use std::{net::SocketAddr, str::FromStr};

use crate::common::{get_available_port, is_port_open};

mod common;

#[tokio::test]
async fn success_pool_template_provider_connection() {
assert!(common::start_template_provider_and_pool().await.is_ok());
}

#[tokio::test]
async fn pool_bad_coinbase_output() {
let (template_provider, template_provider_port) = common::start_template_provider().await;
let pool_port = get_available_port();
let pool_listening_address = SocketAddr::from_str(&format!("127.0.0.1:{}", pool_port)).unwrap();
let is_pool_port_open = is_port_open(pool_listening_address);
assert_eq!(is_pool_port_open, false);
let invalid_coinbase_output = vec![pool_sv2::mining_pool::CoinbaseOutput::new(
"P2PK".to_string(),
"04466d7fcae563e5cb09a0d1870bb580344804617879a14949cf22285f1bae3f276728176c3c6431f8eeda4538dc37c865e2784f3a9e77d044f33e407797e1278".to_string(),
)];
let (test_pool, _pool_port) = common::setup_poolsv2(
Some(pool_listening_address),
Some(invalid_coinbase_output),
template_provider_port,
)
.await;
let pool = test_pool.pool;
let state = pool.state().await.safe_lock(|s| s.clone()).unwrap();
assert_eq!(state, pool_sv2::PoolState::Initial);
assert!(pool.start().await.is_err());
let state = pool.state().await.safe_lock(|s| s.clone()).unwrap();
assert_eq!(state, pool_sv2::PoolState::Initial);
template_provider.stop();
}

0 comments on commit 8c0a408

Please sign in to comment.