Skip to content

Commit

Permalink
refactor: remove mock tests and their interfaces
Browse files Browse the repository at this point in the history
  • Loading branch information
RolandSherwin committed Jan 11, 2024
1 parent 0411df3 commit e5a1a74
Show file tree
Hide file tree
Showing 25 changed files with 199 additions and 2,173 deletions.
246 changes: 12 additions & 234 deletions Cargo.lock

Large diffs are not rendered by default.

4 changes: 0 additions & 4 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@ name="testnet-deploy"

[dependencies]
async-recursion = "1.0.4"
async-trait = "0.1"
aws-config = "0.56.0"
aws-sdk-s3 = "0.29.0"
chrono = "0.4.31"
Expand Down Expand Up @@ -38,7 +37,4 @@ tokio = { version = "1.26", features = ["full"] }
tokio-stream = "0.1.14"

[dev-dependencies]
assert_fs = "~1.0"
httpmock = "0.6"
mockall = "0.11.3"
predicates = "2.0"
65 changes: 22 additions & 43 deletions src/ansible.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,16 +3,13 @@
//
// This SAFE Network Software is licensed under the BSD-3-Clause license.
// Please see the LICENSE file for more details.
use crate::error::{Error, Result};
use crate::CloudProvider;
use crate::{is_binary_on_path, run_external_command};
use crate::{
error::{Error, Result},
is_binary_on_path, run_external_command, CloudProvider,
};
use log::debug;
#[cfg(test)]
use mockall::automock;
use serde::Deserialize;
use std::collections::HashMap;
use std::net::IpAddr;
use std::path::PathBuf;
use std::{collections::HashMap, net::IpAddr, path::PathBuf};

/// Ansible has multiple 'binaries', e.g., `ansible-playbook`, `ansible-inventory` etc. that are
/// wrappers around the main `ansible` program. It would be a bit cumbersome to create a different
Expand Down Expand Up @@ -46,45 +43,13 @@ impl AnsibleBinary {
}
}

/// Provides an interface for running Ansible.
///
/// This trait exists for unit testing: it enables testing behaviour without actually calling the
/// Ansible process.
#[cfg_attr(test, automock)]
pub trait AnsibleRunnerInterface {
fn inventory_list(&self, inventory_path: PathBuf) -> Result<Vec<(String, IpAddr)>>;
fn run_playbook(
&self,
playbook_path: PathBuf,
inventory_path: PathBuf,
user: String,
extra_vars_document: Option<String>,
) -> Result<()>;
}

pub struct AnsibleRunner {
pub provider: CloudProvider,
pub working_directory_path: PathBuf,
pub ssh_sk_path: PathBuf,
pub vault_password_file_path: PathBuf,
}

impl AnsibleRunner {
pub fn new(
working_directory_path: PathBuf,
provider: CloudProvider,
ssh_sk_path: PathBuf,
vault_password_file_path: PathBuf,
) -> AnsibleRunner {
AnsibleRunner {
provider,
working_directory_path,
ssh_sk_path,
vault_password_file_path,
}
}
}

// The following three structs are utilities that are used to parse the output of the
// `ansible-inventory` command.
#[derive(Debug, Deserialize)]
Expand All @@ -100,11 +65,25 @@ struct Output {
_meta: Meta,
}

impl AnsibleRunnerInterface for AnsibleRunner {
impl AnsibleRunner {
pub fn new(
working_directory_path: PathBuf,
provider: CloudProvider,
ssh_sk_path: PathBuf,
vault_password_file_path: PathBuf,
) -> AnsibleRunner {
AnsibleRunner {
provider,
working_directory_path,
ssh_sk_path,
vault_password_file_path,
}
}

// This function is used to list the inventory of the ansible runner.
// It takes a PathBuf as an argument which represents the inventory path.
// It returns a Result containing a vector of tuples. Each tuple contains a string representing the name and the ansible host.
fn inventory_list(&self, inventory_path: PathBuf) -> Result<Vec<(String, IpAddr)>> {
pub fn inventory_list(&self, inventory_path: PathBuf) -> Result<Vec<(String, IpAddr)>> {
// Run the external command and store the output.
let output = run_external_command(
AnsibleBinary::AnsibleInventory.get_binary_path()?,
Expand Down Expand Up @@ -145,7 +124,7 @@ impl AnsibleRunnerInterface for AnsibleRunner {
Ok(inventory)
}

fn run_playbook(
pub fn run_playbook(
&self,
playbook_path: PathBuf,
inventory_path: PathBuf,
Expand Down
21 changes: 3 additions & 18 deletions src/digital_ocean.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,9 @@
// Please see the LICENSE file for more details.

use crate::error::{Error, Result};
use async_trait::async_trait;
use log::debug;
#[cfg(test)]
use mockall::automock;
use reqwest::Client;
use std::net::Ipv4Addr;
use std::str::FromStr;
use std::{net::Ipv4Addr, str::FromStr};

pub const DIGITAL_OCEAN_API_BASE_URL: &str = "https://api.digitalocean.com";
pub const DIGITAL_OCEAN_API_PAGE_SIZE: usize = 200;
Expand All @@ -22,25 +18,14 @@ pub struct Droplet {
pub ip_address: Ipv4Addr,
}

/// Provides an interface for using the SSH client.
///
/// This trait exists for unit testing: it enables testing behaviour without actually calling the
/// ssh process.
#[cfg_attr(test, automock)]
#[async_trait]
pub trait DigitalOceanClientInterface {
async fn list_droplets(&self) -> Result<Vec<Droplet>>;
}

pub struct DigitalOceanClient {
pub base_url: String,
pub access_token: String,
pub page_size: usize,
}

#[async_trait]
impl DigitalOceanClientInterface for DigitalOceanClient {
async fn list_droplets(&self) -> Result<Vec<Droplet>> {
impl DigitalOceanClient {
pub async fn list_droplets(&self) -> Result<Vec<Droplet>> {
let client = Client::new();
let mut has_next_page = true;
let mut page = 1;
Expand Down
54 changes: 25 additions & 29 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,16 +18,13 @@ pub mod setup;
pub mod ssh;
pub mod terraform;

#[cfg(test)]
mod tests;

use crate::{
ansible::{AnsibleRunner, AnsibleRunnerInterface},
ansible::AnsibleRunner,
error::{Error, Result},
rpc_client::{RpcClient, RpcClientInterface},
s3::{S3Repository, S3RepositoryInterface},
ssh::{SshClient, SshClientInterface},
terraform::{TerraformRunner, TerraformRunnerInterface},
rpc_client::RpcClient,
s3::S3Repository,
ssh::SshClient,
terraform::TerraformRunner,
};
use flate2::read::GzDecoder;
use indicatif::{ProgressBar, ProgressStyle};
Expand Down Expand Up @@ -310,39 +307,39 @@ impl TestnetDeployBuilder {
}

let testnet = TestnetDeploy::new(
Box::new(terraform_runner),
Box::new(ansible_runner),
Box::new(rpc_client),
Box::new(SshClient::new(ssh_secret_key_path)),
terraform_runner,
ansible_runner,
rpc_client,
SshClient::new(ssh_secret_key_path),
working_directory_path,
provider.clone(),
Box::new(S3Repository {}),
S3Repository {},
);

Ok(testnet)
}
}

pub struct TestnetDeploy {
pub terraform_runner: Box<dyn TerraformRunnerInterface>,
pub ansible_runner: Box<dyn AnsibleRunnerInterface>,
pub rpc_client: Box<dyn RpcClientInterface>,
pub ssh_client: Box<dyn SshClientInterface>,
pub terraform_runner: TerraformRunner,
pub ansible_runner: AnsibleRunner,
pub rpc_client: RpcClient,
pub ssh_client: SshClient,
pub working_directory_path: PathBuf,
pub cloud_provider: CloudProvider,
pub s3_repository: Box<dyn S3RepositoryInterface>,
pub s3_repository: S3Repository,
pub inventory_file_path: PathBuf,
}

impl TestnetDeploy {
pub fn new(
terraform_runner: Box<dyn TerraformRunnerInterface>,
ansible_runner: Box<dyn AnsibleRunnerInterface>,
rpc_client: Box<dyn RpcClientInterface>,
ssh_client: Box<dyn SshClientInterface>,
terraform_runner: TerraformRunner,
ansible_runner: AnsibleRunner,
rpc_client: RpcClient,
ssh_client: SshClient,
working_directory_path: PathBuf,
cloud_provider: CloudProvider,
s3_repository: Box<dyn S3RepositoryInterface>,
s3_repository: S3Repository,
) -> TestnetDeploy {
let inventory_file_path = working_directory_path
.join("ansible")
Expand Down Expand Up @@ -382,7 +379,7 @@ impl TestnetDeploy {
println!("Downloading the rpc client for safenode...");
let archive_name = "safenode_rpc_client-latest-x86_64-unknown-linux-musl.tar.gz";
get_and_extract_archive_from_s3(
&*self.s3_repository,
&self.s3_repository,
"sn-node-rpc-client",
archive_name,
&self.working_directory_path,
Expand Down Expand Up @@ -525,8 +522,7 @@ impl TestnetDeploy {
.par_iter()
.filter_map(|(vm_name, ip_address)| {
let ip_address = *ip_address;
let ssh_client_clone = self.ssh_client.clone_box();
match ssh_client_clone.run_script(
match self.ssh_client.run_script(
ip_address,
"safe",
PathBuf::from("scripts").join("get_peer_multiaddr.sh"),
Expand Down Expand Up @@ -569,7 +565,7 @@ impl TestnetDeploy {
do_clean(
name,
self.working_directory_path.clone(),
&*self.terraform_runner,
&self.terraform_runner,
vec![
"build".to_string(),
"genesis".to_string(),
Expand All @@ -583,7 +579,7 @@ impl TestnetDeploy {
/// Shared Helpers
///
pub async fn get_and_extract_archive_from_s3(
s3_repository: &dyn S3RepositoryInterface,
s3_repository: &S3Repository,
bucket_name: &str,
archive_bucket_path: &str,
dest_path: &Path,
Expand Down Expand Up @@ -686,7 +682,7 @@ pub fn is_binary_on_path(binary_name: &str) -> bool {
pub fn do_clean(
name: &str,
working_directory_path: PathBuf,
terraform_runner: &dyn TerraformRunnerInterface,
terraform_runner: &TerraformRunner,
inventory_types: Vec<String>,
) -> Result<()> {
terraform_runner.init()?;
Expand Down
15 changes: 10 additions & 5 deletions src/logs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,12 @@
// This SAFE Network Software is licensed under the BSD-3-Clause license.
// Please see the LICENSE file for more details.

use crate::error::{Error, Result};
use crate::s3::{S3Repository, S3RepositoryInterface};
use crate::{get_progress_bar, run_external_command, TestnetDeploy};
use crate::{
error::{Error, Result},
get_progress_bar, run_external_command,
s3::S3Repository,
TestnetDeploy,
};
use fs_extra::dir::{copy, remove, CopyOptions};
use log::debug;
use rayon::iter::{IntoParallelIterator, IntoParallelRefIterator, ParallelIterator};
Expand Down Expand Up @@ -136,11 +139,13 @@ impl TestnetDeploy {
println!("Running ripgrep with command: {rg_cmd}");

let progress_bar = get_progress_bar(all_node_inventory.len() as u64)?;
let ssh_client = self.ssh_client.clone_box();
let _failed_inventory = all_node_inventory
.par_iter()
.filter_map(|(vm_name, ip_address)| {
let op = match ssh_client.run_command(ip_address, "safe", &rg_cmd, true) {
let op = match self
.ssh_client
.run_command(ip_address, "safe", &rg_cmd, true)
{
Ok(output) => match Self::store_rg_output(&output, &log_abs_dest, vm_name) {
Ok(_) => None,
Err(err) => {
Expand Down
Loading

0 comments on commit e5a1a74

Please sign in to comment.