Refactor to add roundtrip test for initial setup and reading config

This commit is contained in:
Daniel Karzel 2021-01-28 18:07:33 +11:00
parent b75e9b436c
commit 616d120377
3 changed files with 82 additions and 24 deletions

View File

@ -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<File> {
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<File, Error> {
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<F>(config_path: PathBuf, config_file: F) -> Result<()>
where
F: Fn() -> Result<File>,
{
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<File> {
pub fn query_user_for_initial_testnet_config() -> Result<File> {
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<File> {
},
})
}
#[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);
}
}

View File

@ -5,10 +5,12 @@ use std::path::{Path, PathBuf};
/// This is to store the configuration and seed files
// Linux: /home/<user>/.config/xmr-btc-swap/
// OSX: /Users/<user>/Library/Preferences/xmr-btc-swap/
#[allow(dead_code)]
fn config_dir() -> Option<PathBuf> {
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<PathBuf> {
config_dir()
.map(|dir| Path::join(&dir, "config.toml"))

View File

@ -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<Settings> {
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(),