From 616d1203775f4813046517f992cdd452b1141b7b Mon Sep 17 00:00:00 2001 From: Daniel Karzel Date: Thu, 28 Jan 2021 18:07:33 +1100 Subject: [PATCH] Refactor to add roundtrip test for initial setup and reading config --- swap/src/config.rs | 76 ++++++++++++++++++++++++++++++++++------------ swap/src/fs.rs | 2 ++ swap/src/main.rs | 28 ++++++++++++++--- 3 files changed, 82 insertions(+), 24 deletions(-) diff --git a/swap/src/config.rs b/swap/src/config.rs index 291e717c..568da021 100644 --- a/swap/src/config.rs +++ b/swap/src/config.rs @@ -1,4 +1,4 @@ -use crate::fs::{default_config_path, ensure_directory_exists}; +use crate::fs::ensure_directory_exists; use anyhow::{Context, Result}; use config::{Config, ConfigError}; use dialoguer::{theme::ColorfulTheme, Input}; @@ -49,29 +49,39 @@ pub struct Monero { pub wallet_rpc_url: Url, } -pub fn read_config() -> anyhow::Result { - let default_path = default_config_path()?; - - if default_path.exists() { - info!( - "Using config file at default path: {}", - default_path.display() - ); - } else { - initial_setup(default_path.clone())?; - } - - File::read(&default_path) - .with_context(|| format!("failed to read config file {}", default_path.display())) +#[derive(thiserror::Error, Debug)] +pub enum Error { + #[error("config not initialized")] + ConfigNotInitialized, + #[error("other error")] + Other(#[from] anyhow::Error), } -fn initial_setup(config_path: PathBuf) -> Result<()> { +pub fn read_config(config_path: PathBuf) -> anyhow::Result { + if config_path.exists() { + info!( + "Using config file at default path: {}", + config_path.display() + ); + } else { + return Err(Error::ConfigNotInitialized); + } + + File::read(&config_path) + .with_context(|| format!("failed to read config file {}", config_path.display())) + .map_err(Error::Other) +} + +pub fn initial_setup(config_path: PathBuf, config_file: F) -> Result<()> +where + F: Fn() -> Result, +{ info!("Config file not found, running initial setup..."); ensure_directory_exists(config_path.as_path())?; - let initial_config = query_user_for_initial_testnet_config()?; + let initial_config = config_file()?; let toml = toml::to_string(&initial_config)?; - fs::write(config_path.clone(), toml)?; + fs::write(&config_path, toml)?; info!( "Initial setup complete, config file created at {} ", @@ -80,7 +90,7 @@ fn initial_setup(config_path: PathBuf) -> Result<()> { Ok(()) } -fn query_user_for_initial_testnet_config() -> Result { +pub fn query_user_for_initial_testnet_config() -> Result { println!(); let bitcoind_url: String = Input::with_theme(&ColorfulTheme::default()) .with_prompt("Enter Bitcoind URL (including username and password if applicable) or hit return to use default") @@ -109,3 +119,31 @@ fn query_user_for_initial_testnet_config() -> Result { }, }) } + +#[cfg(test)] +mod tests { + use super::*; + use std::str::FromStr; + use tempfile::tempdir; + + #[test] + fn config_roundtrip() { + let temp_dir = tempdir().unwrap().path().to_path_buf(); + let config_path = Path::join(&temp_dir, "config.toml"); + + let expected = File { + bitcoin: Bitcoin { + bitcoind_url: Url::from_str("http://127.0.0.1:18332").unwrap(), + wallet_name: "alice".to_string(), + }, + monero: Monero { + wallet_rpc_url: Url::from_str("http://127.0.0.1:38083/json_rpc").unwrap(), + }, + }; + + initial_setup(config_path.clone(), || Ok(expected.clone())).unwrap(); + let actual = read_config(config_path).unwrap(); + + assert_eq!(expected, actual); + } +} diff --git a/swap/src/fs.rs b/swap/src/fs.rs index ee12585b..be07733b 100644 --- a/swap/src/fs.rs +++ b/swap/src/fs.rs @@ -5,10 +5,12 @@ use std::path::{Path, PathBuf}; /// This is to store the configuration and seed files // Linux: /home//.config/xmr-btc-swap/ // OSX: /Users//Library/Preferences/xmr-btc-swap/ +#[allow(dead_code)] fn config_dir() -> Option { ProjectDirs::from("", "", "xmr-btc-swap").map(|proj_dirs| proj_dirs.config_dir().to_path_buf()) } +#[allow(dead_code)] pub fn default_config_path() -> anyhow::Result { config_dir() .map(|dir| Path::join(&dir, "config.toml")) diff --git a/swap/src/main.rs b/swap/src/main.rs index 69668bd7..ed0ce487 100644 --- a/swap/src/main.rs +++ b/swap/src/main.rs @@ -16,13 +16,15 @@ use crate::{ cli::{Command, Options, Resume}, config::read_config, }; -use anyhow::{Context, Result}; +use anyhow::{bail, Context, Result}; use database::Database; +use fs::default_config_path; use prettytable::{row, Table}; use protocol::{alice, bob, bob::Builder, SwapAmounts}; use settings::Settings; use std::sync::Arc; use structopt::StructOpt; +use swap::config::{initial_setup, query_user_for_initial_testnet_config}; use trace::init_tracing; use tracing::{info, log::LevelFilter}; use uuid::Uuid; @@ -67,7 +69,7 @@ async fn main() -> Result<()> { send_monero, receive_bitcoin, } => { - let settings = Settings::from_config_file_and_defaults(read_config()?); + let settings = init_settings()?; let swap_amounts = SwapAmounts { xmr: send_monero, @@ -105,7 +107,7 @@ async fn main() -> Result<()> { send_bitcoin, receive_monero, } => { - let settings = Settings::from_config_file_and_defaults(read_config()?); + let settings = init_settings()?; let swap_amounts = SwapAmounts { btc: send_bitcoin, @@ -154,7 +156,7 @@ async fn main() -> Result<()> { swap_id, listen_addr, }) => { - let settings = Settings::from_config_file_and_defaults(read_config()?); + let settings = init_settings()?; let (bitcoin_wallet, monero_wallet) = setup_wallets(settings.wallets).await?; @@ -178,7 +180,7 @@ async fn main() -> Result<()> { alice_peer_id, alice_addr, }) => { - let settings = Settings::from_config_file_and_defaults(read_config()?); + let settings = init_settings()?; let (bitcoin_wallet, monero_wallet) = setup_wallets(settings.wallets).await?; @@ -202,6 +204,22 @@ async fn main() -> Result<()> { Ok(()) } +fn init_settings() -> Result { + let config_path = default_config_path()?; + let config = match read_config(config_path.clone()) { + Ok(config) => config, + Err(config::Error::ConfigNotInitialized) => { + initial_setup(config_path.clone(), query_user_for_initial_testnet_config)?; + read_config(config_path)? + } + Err(e) => bail!(e), + }; + + let settings = Settings::from_config_file_and_defaults(config); + + Ok(settings) +} + async fn setup_wallets(settings: settings::Wallets) -> Result<(bitcoin::Wallet, monero::Wallet)> { let bitcoin_wallet = bitcoin::Wallet::new( settings.bitcoin.wallet_name.as_str(),