From d63393ae57dd1d119dcf71fcacb54f46f130d136 Mon Sep 17 00:00:00 2001 From: Alexander Aglerimov Date: Fri, 17 Dec 2021 20:40:59 +0300 Subject: [PATCH 1/2] done: added tests for trait Market --- src/worker/market_helpers/market.rs | 100 +++++++++++++++++++++- src/worker/market_helpers/market_spine.rs | 6 +- src/worker/worker.rs | 50 ++++++----- 3 files changed, 129 insertions(+), 27 deletions(-) diff --git a/src/worker/market_helpers/market.rs b/src/worker/market_helpers/market.rs index 1fcff748..a40a855a 100644 --- a/src/worker/market_helpers/market.rs +++ b/src/worker/market_helpers/market.rs @@ -64,10 +64,7 @@ fn subscribe_channel( } fn update(market: Arc>) { - market.lock().unwrap().get_spine_mut().socket_enabled = true; - let channels = MarketChannels::get_all(); - let exchange_pairs: Vec = market .lock() .unwrap() @@ -174,7 +171,7 @@ pub trait Market { let market = Arc::clone(self.get_spine().arc.as_ref().unwrap()); - let thread_name = format!("fn: update, market: {}", self.get_spine().name,); + let thread_name = format!("fn: update, market: {}", self.get_spine().name); let thread = thread::Builder::new() .name(thread_name) .spawn(move || update(market)) @@ -185,3 +182,98 @@ pub trait Market { fn parse_last_trade_info(&mut self, pair: String, info: String); fn parse_depth_info(&mut self, pair: String, info: String); } + +#[cfg(test)] +mod test { + use crate::worker::market_helpers::market::{market_factory, update, Market}; + use crate::worker::market_helpers::market_channels::MarketChannels; + use crate::worker::market_helpers::market_spine::MarketSpine; + use crate::worker::worker::test::{check_threads, get_worker}; + use chrono::{Duration, Utc}; + use ntest::timeout; + use std::sync::mpsc::Receiver; + use std::sync::{Arc, Mutex}; + use std::thread::JoinHandle; + + fn get_market( + market_name: Option<&str>, + ) -> (Arc>, Receiver>) { + let market_name = market_name.unwrap_or("binance").to_string(); + + let (worker, tx, rx) = get_worker(); + let market_spine = MarketSpine::new(worker, tx, market_name); + let market = market_factory(market_spine); + + (market, rx) + } + + #[test] + #[should_panic] + fn test_market_factory() { + let (_, _) = get_market(Some("not_existing_market")); + } + + #[test] + fn test_market_factory_2() { + let (market, _) = get_market(None); + + assert!(market.lock().unwrap().get_spine().arc.is_some()); + } + + #[test] + #[timeout(3000)] + fn test_perform() { + let (market, rx) = get_market(None); + + let thread_names = vec![format!( + "fn: update, market: {}", + market.lock().unwrap().get_spine().name + )]; + + market.lock().unwrap().perform(); + + // TODO: Refactor (not always working) + check_threads(thread_names, rx); + + let now = Utc::now(); + let last_capitalization_refresh = market + .lock() + .unwrap() + .get_spine() + .get_last_capitalization_refresh(); + assert!(now - last_capitalization_refresh <= Duration::milliseconds(5000)); + } + + // #[test] + #[timeout(2000)] + /// TODO: Refactor (not always working) + fn test_update() { + let (market, rx) = get_market(None); + + let channels = MarketChannels::get_all(); + let exchange_pairs: Vec = market + .lock() + .unwrap() + .get_spine() + .get_exchange_pairs() + .keys() + .cloned() + .collect(); + + let mut thread_names = Vec::new(); + for pair in exchange_pairs { + for channel in channels { + let thread_name = format!( + "fn: subscribe_channel, market: {}, pair: {}, channel: {}", + market.lock().unwrap().get_spine().name, + pair, + channel + ); + thread_names.push(thread_name); + } + } + + update(market); + check_threads(thread_names, rx); + } +} diff --git a/src/worker/market_helpers/market_spine.rs b/src/worker/market_helpers/market_spine.rs index 734d481b..735fd795 100644 --- a/src/worker/market_helpers/market_spine.rs +++ b/src/worker/market_helpers/market_spine.rs @@ -25,7 +25,6 @@ pub struct MarketSpine { exchange_pairs: HashMap, conversions: HashMap, pairs: HashMap, - pub socket_enabled: bool, capitalization: HashMap, last_capitalization_refresh: DateTime, } @@ -41,7 +40,6 @@ impl MarketSpine { exchange_pairs: HashMap::new(), conversions: HashMap::new(), pairs: HashMap::new(), - socket_enabled: false, capitalization: HashMap::new(), last_capitalization_refresh: MIN_DATETIME, } @@ -281,4 +279,8 @@ impl MarketSpine { self.update_market_pair(pair, "totalValues", false); } } + + pub fn get_last_capitalization_refresh(&self) -> DateTime { + self.last_capitalization_refresh + } } diff --git a/src/worker/worker.rs b/src/worker/worker.rs index 2200d4f1..6798ba14 100644 --- a/src/worker/worker.rs +++ b/src/worker/worker.rs @@ -121,35 +121,54 @@ impl Worker { } #[cfg(test)] -mod test { +pub mod test { use crate::repository::pair_average_trade_price::PairAverageTradePrice; use crate::worker::defaults::{COINS, FIATS, MARKETS}; use crate::worker::worker::Worker; use ntest::timeout; - use std::sync::mpsc::Receiver; + use std::sync::mpsc::{Receiver, Sender}; use std::sync::{mpsc, Arc, Mutex}; use std::thread::JoinHandle; - fn get_worker() -> (Arc>, Receiver>) { + pub fn get_worker() -> ( + Arc>, + Sender>, + Receiver>, + ) { let (tx, rx) = mpsc::channel(); let pair_average_trade_price_repository = PairAverageTradePrice::new(); let worker = Worker::new( - tx, + tx.clone(), Arc::new(Mutex::new(pair_average_trade_price_repository)), ); - (worker, rx) + (worker, tx, rx) + } + + pub fn check_threads(mut thread_names: Vec, rx: Receiver>) { + let mut passed_thread_names = Vec::new(); + for received_thread in rx { + let thread_name = received_thread.thread().name().unwrap().to_string(); + assert!(!passed_thread_names.contains(&thread_name)); + + if let Some(index) = thread_names.iter().position(|r| r == &thread_name) { + passed_thread_names.push(thread_names.swap_remove(index)); + } + if thread_names.is_empty() { + break; + } + } } #[test] fn test_new() { - let (worker, _) = get_worker(); + let (worker, _, _) = get_worker(); assert!(worker.lock().unwrap().arc.is_some()); } fn test_configure(markets: Option>, coins: Option>) { - let (worker, _) = get_worker(); + let (worker, _, _) = get_worker(); worker .lock() .unwrap() @@ -199,8 +218,7 @@ mod test { #[test] #[timeout(1000)] fn test_start() { - let (worker, rx) = get_worker(); - worker.lock().unwrap().start(None, None); + let (worker, _, rx) = get_worker(); let markets = Vec::from(MARKETS); let mut thread_names = Vec::new(); @@ -209,17 +227,7 @@ mod test { thread_names.push(thread_name); } - let mut passed_thread_names = Vec::new(); - for received_thread in rx { - let thread_name = received_thread.thread().name().unwrap().to_string(); - assert!(!passed_thread_names.contains(&thread_name)); - - if let Some(index) = thread_names.iter().position(|r| r == &thread_name) { - passed_thread_names.push(thread_names.swap_remove(index)); - } - if thread_names.is_empty() { - break; - } - } + worker.lock().unwrap().start(None, None); + check_threads(thread_names, rx); } } From 12574f5f44093fc5ad7ecaa25dcbf31d89e47901 Mon Sep 17 00:00:00 2001 From: Alexander Aglerimov Date: Fri, 17 Dec 2021 21:16:54 +0300 Subject: [PATCH 2/2] done: refactoring - moved adding exchange pairs from "Worker::configure()" to "market::market_factory()" --- src/worker/market_helpers/market.rs | 38 ++++++++++++++++++++++++++--- src/worker/worker.rs | 32 +++--------------------- 2 files changed, 37 insertions(+), 33 deletions(-) diff --git a/src/worker/market_helpers/market.rs b/src/worker/market_helpers/market.rs index a40a855a..250d6332 100644 --- a/src/worker/market_helpers/market.rs +++ b/src/worker/market_helpers/market.rs @@ -9,7 +9,10 @@ use std::sync::{Arc, Mutex}; use std::thread; use std::time; -pub fn market_factory(mut spine: MarketSpine) -> Arc> { +pub fn market_factory( + mut spine: MarketSpine, + exchange_pairs: Vec, +) -> Arc> { let mask_pairs = match spine.name.as_ref() { "binance" => vec![("IOT", "IOTA"), ("USD", "USDT")], "bitfinex" => vec![("DASH", "dsh"), ("QTUM", "QTM")], @@ -32,6 +35,10 @@ pub fn market_factory(mut spine: MarketSpine) -> Arc> { .get_spine_mut() .set_arc(Arc::clone(&market)); + for exchange_pair in exchange_pairs { + market.lock().unwrap().add_exchange_pair(exchange_pair); + } + market } @@ -185,10 +192,12 @@ pub trait Market { #[cfg(test)] mod test { + use crate::worker::defaults::{COINS, FIATS}; use crate::worker::market_helpers::market::{market_factory, update, Market}; use crate::worker::market_helpers::market_channels::MarketChannels; use crate::worker::market_helpers::market_spine::MarketSpine; use crate::worker::worker::test::{check_threads, get_worker}; + use crate::worker::worker::Worker; use chrono::{Duration, Utc}; use ntest::timeout; use std::sync::mpsc::Receiver; @@ -199,10 +208,13 @@ mod test { market_name: Option<&str>, ) -> (Arc>, Receiver>) { let market_name = market_name.unwrap_or("binance").to_string(); + let fiats = Vec::from(FIATS); + let coins = Vec::from(COINS); + let exchange_pairs = Worker::make_exchange_pairs(coins, fiats); let (worker, tx, rx) = get_worker(); let market_spine = MarketSpine::new(worker, tx, market_name); - let market = market_factory(market_spine); + let market = market_factory(market_spine, exchange_pairs); (market, rx) } @@ -218,6 +230,24 @@ mod test { let (market, _) = get_market(None); assert!(market.lock().unwrap().get_spine().arc.is_some()); + + let fiats = Vec::from(FIATS); + let coins = Vec::from(COINS); + let exchange_pairs = Worker::make_exchange_pairs(coins, fiats); + let exchange_pair_keys: Vec = market + .lock() + .unwrap() + .get_spine() + .get_exchange_pairs() + .keys() + .cloned() + .collect(); + assert_eq!(exchange_pair_keys.len(), exchange_pairs.len()); + + for pair in &exchange_pairs { + let pair_string = market.lock().unwrap().make_pair(pair.get_pair_ref()); + assert!(exchange_pair_keys.contains(&pair_string)); + } } #[test] @@ -244,8 +274,8 @@ mod test { assert!(now - last_capitalization_refresh <= Duration::milliseconds(5000)); } - // #[test] - #[timeout(2000)] + #[test] + #[timeout(120000)] /// TODO: Refactor (not always working) fn test_update() { let (market, rx) = get_market(None); diff --git a/src/worker/worker.rs b/src/worker/worker.rs index 6798ba14..b2ec09b1 100644 --- a/src/worker/worker.rs +++ b/src/worker/worker.rs @@ -64,7 +64,7 @@ impl Worker { .insert(pair, new_avg); } - fn make_exchange_pairs(coins: Vec<&str>, fiats: Vec<&str>) -> Vec { + pub fn make_exchange_pairs(coins: Vec<&str>, fiats: Vec<&str>) -> Vec { let mut exchange_pairs = Vec::new(); for coin in coins { @@ -88,14 +88,7 @@ impl Worker { for market_name in market_names { let worker_2 = Arc::clone(self.arc.as_ref().unwrap()); let market_spine = MarketSpine::new(worker_2, self.tx.clone(), market_name.to_string()); - let market = market_factory(market_spine); - - for exchange_pair in &exchange_pairs { - market - .lock() - .unwrap() - .add_exchange_pair(exchange_pair.clone()); - } + let market = market_factory(market_spine, exchange_pairs.clone()); self.markets.push(market); } @@ -123,7 +116,7 @@ impl Worker { #[cfg(test)] pub mod test { use crate::repository::pair_average_trade_price::PairAverageTradePrice; - use crate::worker::defaults::{COINS, FIATS, MARKETS}; + use crate::worker::defaults::MARKETS; use crate::worker::worker::Worker; use ntest::timeout; use std::sync::mpsc::{Receiver, Sender}; @@ -175,30 +168,11 @@ pub mod test { .configure(markets.clone(), coins.clone()); let markets = markets.unwrap_or(Vec::from(MARKETS)); - let fiats = Vec::from(FIATS); - let coins = coins.unwrap_or(Vec::from(COINS)); - let exchange_pairs = Worker::make_exchange_pairs(coins, fiats); - assert_eq!(markets.len(), worker.lock().unwrap().markets.len()); for (i, market) in worker.lock().unwrap().markets.iter().enumerate() { let market_name = market.lock().unwrap().get_spine().name.clone(); assert_eq!(market_name, markets[i]); - - let exchange_pair_keys: Vec = market - .lock() - .unwrap() - .get_spine() - .get_exchange_pairs() - .keys() - .cloned() - .collect(); - assert_eq!(exchange_pair_keys.len(), exchange_pairs.len()); - - for pair in &exchange_pairs { - let pair_string = market.lock().unwrap().make_pair(pair.get_pair_ref()); - assert!(exchange_pair_keys.contains(&pair_string)); - } } }