Add tests

Signed-off-by: Nikolaos Karaolidis <nick@karaolidis.com>
This commit is contained in:
2024-03-20 10:19:36 +00:00
parent d072b849c0
commit 733e6373e9
8 changed files with 436 additions and 52 deletions

View File

@@ -24,13 +24,13 @@ build:
script:
- cargo +nightly build
# test:
# image: registry.karaolidis.com/karaolidis/qrust/rust
# stage: test
# cache:
# <<: *global_cache
# script:
# - cargo +nightly test
test:
image: registry.karaolidis.com/karaolidis/qrust/rust
stage: test
cache:
<<: *global_cache
script:
- cargo +nightly test
lint:
image: registry.karaolidis.com/karaolidis/qrust/rust

102
Cargo.lock generated
View File

@@ -19,9 +19,9 @@ checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe"
[[package]]
name = "aho-corasick"
version = "1.1.2"
version = "1.1.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b2969dcb958b36655471fc61f7e416fa76033bdd4bfed0678d8fee1e2d07a1f0"
checksum = "8e60d3430d3a69478ad0993f19238d2df97c507009a52b3c10addcd7f6bcb916"
dependencies = [
"memchr",
]
@@ -55,13 +55,13 @@ checksum = "7b3d0060af21e8d11a926981cc00c6c1541aa91dd64b9f881985c3da1094425f"
[[package]]
name = "async-trait"
version = "0.1.77"
version = "0.1.78"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c980ee35e870bd1a4d2c8294d4c04d0499e67bca1e4b5cefcc693c2fa00caea9"
checksum = "461abc97219de0eaaf81fe3ef974a540158f3d079c2ab200f891f1a2ef201e85"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.52",
"syn 2.0.53",
]
[[package]]
@@ -168,9 +168,9 @@ checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
[[package]]
name = "bitflags"
version = "2.4.2"
version = "2.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ed570934406eb16438a4e976b1b4500774099c13b8cb96eec99f620f05090ddf"
checksum = "cf4b9d6a944f767f8e5e0db018570623c85f3d925ac718db4e06d0187adb21c1"
[[package]]
name = "block-buffer"
@@ -233,6 +233,15 @@ dependencies = [
"windows-targets 0.52.4",
]
[[package]]
name = "claims"
version = "0.7.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b6995bbe186456c36307f8ea36be3eefe42f49d106896414e18efc4fb2f846b5"
dependencies = [
"autocfg",
]
[[package]]
name = "clickhouse"
version = "0.11.6"
@@ -342,7 +351,7 @@ dependencies = [
"proc-macro2",
"quote",
"strsim",
"syn 2.0.52",
"syn 2.0.53",
]
[[package]]
@@ -353,7 +362,7 @@ checksum = "a668eda54683121533a393014d8692171709ff57a7d61f187b6e782719f8933f"
dependencies = [
"darling_core",
"quote",
"syn 2.0.52",
"syn 2.0.53",
]
[[package]]
@@ -541,7 +550,7 @@ checksum = "87750cf4b7a4c0625b1529e4c543c2182106e4dedc60a2a6455e00d212c489ac"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.52",
"syn 2.0.53",
]
[[package]]
@@ -629,9 +638,9 @@ dependencies = [
[[package]]
name = "h2"
version = "0.3.24"
version = "0.3.25"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bb2c4422095b67ee78da96fbb51a4cc413b3b25883c7717ff7ca1ab31022c9c9"
checksum = "4fbd2820c5e49886948654ab546d0688ff24530286bdcf8fca3cefb16d4618eb"
dependencies = [
"bytes",
"fnv",
@@ -648,9 +657,9 @@ dependencies = [
[[package]]
name = "h2"
version = "0.4.2"
version = "0.4.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "31d030e59af851932b72ceebadf4a2b5986dba4c3b99dd2493f8273a0f151943"
checksum = "51ee2dd2e4f378392eeff5d51618cd9a63166a2513846bbc55f21cfacd9199d4"
dependencies = [
"bytes",
"fnv",
@@ -782,7 +791,7 @@ dependencies = [
"futures-channel",
"futures-core",
"futures-util",
"h2 0.3.24",
"h2 0.3.25",
"http 0.2.12",
"http-body 0.4.6",
"httparse",
@@ -805,7 +814,7 @@ dependencies = [
"bytes",
"futures-channel",
"futures-util",
"h2 0.4.2",
"h2 0.4.3",
"http 1.1.0",
"http-body 1.0.0",
"httparse",
@@ -1168,7 +1177,7 @@ version = "0.10.64"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "95a0481286a310808298130d22dd1fef0fa571e05a8f44ec801801e84b216b1f"
dependencies = [
"bitflags 2.4.2",
"bitflags 2.5.0",
"cfg-if",
"foreign-types",
"libc",
@@ -1185,7 +1194,7 @@ checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.52",
"syn 2.0.53",
]
[[package]]
@@ -1261,7 +1270,7 @@ checksum = "2f38a4412a78282e09a2cf38d195ea5420d15ba0602cb375210efbc877243965"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.52",
"syn 2.0.53",
]
[[package]]
@@ -1316,6 +1325,7 @@ dependencies = [
"async-trait",
"axum",
"backoff",
"claims",
"clickhouse",
"dotenv",
"futures-util",
@@ -1332,6 +1342,7 @@ dependencies = [
"serde-aux",
"serde_json",
"serde_repr",
"serde_test",
"serde_with",
"time",
"tokio",
@@ -1399,7 +1410,7 @@ version = "11.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9d86a7c4638d42c44551f4791a20e687dbb4c3de1f33c43dd71e355cd429def1"
dependencies = [
"bitflags 2.4.2",
"bitflags 2.5.0",
]
[[package]]
@@ -1442,16 +1453,16 @@ checksum = "c08c74e62047bb2de4ff487b251e4a92e24f48745648451635cec7d591162d9f"
[[package]]
name = "reqwest"
version = "0.11.26"
version = "0.11.27"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "78bf93c4af7a8bb7d879d51cebe797356ff10ae8516ace542b5182d9dcac10b2"
checksum = "dd67538700a17451e7cba03ac727fb961abb7607553461627b97de0b89cf4a62"
dependencies = [
"base64",
"bytes",
"encoding_rs",
"futures-core",
"futures-util",
"h2 0.3.24",
"h2 0.3.25",
"http 0.2.12",
"http-body 0.4.6",
"hyper 0.14.28",
@@ -1488,11 +1499,11 @@ checksum = "d626bb9dae77e28219937af045c257c28bfd3f69333c512553507f5f9798cb76"
[[package]]
name = "rustix"
version = "0.38.31"
version = "0.38.32"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6ea3e1a662af26cd7a3ba09c0297a31af215563ecf42817c98df621387f4e949"
checksum = "65e04861e65f21776e67888bfbea442b3642beaa0138fdb1dd7a84a52dffdb89"
dependencies = [
"bitflags 2.4.2",
"bitflags 2.5.0",
"errno",
"libc",
"linux-raw-sys",
@@ -1608,7 +1619,7 @@ checksum = "7eb0b34b42edc17f6b7cac84a52a1c5f0e1bb2227e997ca9011ea3dd34e8610b"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.52",
"syn 2.0.53",
]
[[package]]
@@ -1651,7 +1662,16 @@ checksum = "0b2e6b945e9d3df726b65d6ee24060aff8e3533d431f677a9695db04eff9dfdb"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.52",
"syn 2.0.53",
]
[[package]]
name = "serde_test"
version = "1.0.176"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5a2f49ace1498612d14f7e0b8245519584db8299541dfe31a06374a828d620ab"
dependencies = [
"serde",
]
[[package]]
@@ -1693,14 +1713,14 @@ dependencies = [
"darling",
"proc-macro2",
"quote",
"syn 2.0.52",
"syn 2.0.53",
]
[[package]]
name = "serde_yaml"
version = "0.9.32"
version = "0.9.33"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8fd075d994154d4a774f95b51fb96bdc2832b0ea48425c92546073816cda1f2f"
checksum = "a0623d197252096520c6f2a5e1171ee436e5af99a5d7caa2891e55e61950e6d9"
dependencies = [
"indexmap 2.2.5",
"itoa",
@@ -1790,9 +1810,9 @@ dependencies = [
[[package]]
name = "syn"
version = "2.0.52"
version = "2.0.53"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b699d15b36d1f02c3e7c69f8ffef53de37aefae075d8488d4ba1a7788d574a07"
checksum = "7383cd0e49fff4b6b90ca5670bfd3e9d6a733b3f90c686605aa7eec8c4996032"
dependencies = [
"proc-macro2",
"quote",
@@ -1855,7 +1875,7 @@ checksum = "c61f3ba182994efc43764a46c018c347bc492c79f024e705f46567b418f6d4f7"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.52",
"syn 2.0.53",
]
[[package]]
@@ -1941,7 +1961,7 @@ checksum = "5b8a1e28f2deaa14e508979454cb3a223b10b938b45af148bc0986de36f1923b"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.52",
"syn 2.0.53",
]
[[package]]
@@ -2109,9 +2129,9 @@ dependencies = [
[[package]]
name = "unsafe-libyaml"
version = "0.2.10"
version = "0.2.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ab4c90930b95a82d00dc9e9ac071b4991924390d46cbd0dfe566148667605e4b"
checksum = "673aac59facbab8a9007c7f6108d11f63b603f7cabff99fabf650fea5c32b861"
[[package]]
name = "url"
@@ -2132,9 +2152,9 @@ checksum = "09cc8ee72d2a9becf2f2febe0205bbed8fc6615b7cb429ad062dc7b7ddd036a9"
[[package]]
name = "uuid"
version = "1.7.0"
version = "1.8.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f00cc9702ca12d3c81455259621e676d0f7251cec66a21e98fe2e9a37db93b2a"
checksum = "a183cf7feeba97b4dd1c0d46788634f6221d87fa961b305bed08c851829efcc0"
dependencies = [
"getrandom",
"serde",
@@ -2188,7 +2208,7 @@ dependencies = [
"once_cell",
"proc-macro2",
"quote",
"syn 2.0.52",
"syn 2.0.53",
"wasm-bindgen-shared",
]
@@ -2222,7 +2242,7 @@ checksum = "e94f17b526d0a461a191c78ea52bbce64071ed5c04c9ffe424dcb38f74171bb7"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.52",
"syn 2.0.53",
"wasm-bindgen-backend",
"wasm-bindgen-shared",
]

View File

@@ -71,3 +71,7 @@ lazy_static = "1.4.0"
nonempty = { version = "0.10.0", features = [
"serialize",
] }
[dev-dependencies]
claims = "0.7.1"
serde_test = "1.0.176"

View File

@@ -13,3 +13,14 @@ pub fn strip(content: &str) -> String {
let content = content.trim();
content.to_string()
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_strip() {
let content = "<p> <b> Hello, </b> <i> World! </i> </p>";
assert_eq!(strip(content), "Hello, World!");
}
}

View File

@@ -223,3 +223,53 @@ impl Order {
orders
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_normalize() {
let order_template = Order {
id: Uuid::new_v4(),
client_order_id: Uuid::new_v4(),
created_at: OffsetDateTime::now_utc(),
updated_at: None,
submitted_at: OffsetDateTime::now_utc(),
filled_at: None,
expired_at: None,
cancel_requested_at: None,
canceled_at: None,
failed_at: None,
replaced_at: None,
replaced_by: None,
replaces: None,
asset_id: Uuid::new_v4(),
symbol: "AAPL".to_string(),
asset_class: super::super::asset::Class::UsEquity,
notional: None,
qty: None,
filled_qty: 0.0,
filled_avg_price: None,
order_class: Class::Simple,
order_type: Type::Market,
side: Side::Buy,
time_in_force: TimeInForce::Day,
limit_price: None,
stop_price: None,
status: Status::New,
extended_hours: false,
legs: None,
trail_percent: None,
trail_price: None,
hwm: None,
};
let mut order = order_template.clone();
order.legs = Some(vec![order_template.clone(), order_template.clone()]);
order.legs.as_mut().unwrap()[0].legs = Some(vec![order_template.clone()]);
let orders = order.normalize();
assert_eq!(orders.len(), 4);
}
}

View File

@@ -86,7 +86,7 @@ where
struct TimeVisitor;
impl<'de> Visitor<'de> for TimeVisitor {
type Value = time::Time;
type Value = Time;
fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
formatter.write_str("a string in the format HH:MM")
@@ -102,3 +102,92 @@ where
deserializer.deserialize_str(TimeVisitor)
}
#[cfg(test)]
mod tests {
use super::*;
use serde::Deserialize;
use serde_test::{assert_de_tokens, Token};
use time::Time;
#[test]
fn test_add_slash() {
assert_eq!(add_slash("BTCUSD"), "BTC/USD");
}
#[test]
fn test_add_slash_skip() {
assert_eq!(add_slash("ABTC"), "ABTC");
}
#[derive(PartialEq, Debug, Deserialize)]
#[serde(transparent)]
struct AddSlashToSymbol {
#[serde(deserialize_with = "add_slash_to_symbol")]
symbol: String,
}
#[test]
fn test_add_slash_to_symbol() {
assert_de_tokens::<AddSlashToSymbol>(
&AddSlashToSymbol {
symbol: String::from("BTC/USD"),
},
&[Token::Str("BTCUSD")],
);
}
#[test]
fn test_add_slash_to_symbol_skip() {
assert_de_tokens::<AddSlashToSymbol>(
&AddSlashToSymbol {
symbol: String::from("ABTC"),
},
&[Token::Str("ABTC")],
);
}
#[derive(PartialEq, Debug, Deserialize)]
#[serde(transparent)]
struct AddSlashToSymbols {
#[serde(deserialize_with = "add_slash_to_symbols")]
symbols: Vec<String>,
}
#[test]
fn test_add_slash_to_symbols() {
assert_de_tokens::<AddSlashToSymbols>(
&AddSlashToSymbols {
symbols: vec![
String::from("BTC/USD"),
String::from("ETH/USD"),
String::from("ABTC"),
],
},
&[
Token::Seq { len: Some(3) },
Token::Str("BTCUSD"),
Token::Str("ETHUSD"),
Token::Str("ABTC"),
Token::SeqEnd,
],
);
}
#[derive(PartialEq, Debug, Deserialize)]
#[serde(transparent)]
struct HumanTime {
#[serde(deserialize_with = "human_time_hh_mm")]
time: Time,
}
#[test]
fn test_human_time_hh_mm() {
assert_de_tokens::<HumanTime>(
&HumanTime {
time: Time::from_hms(12, 34, 0).unwrap(),
},
&[Token::Str("12:34")],
);
}
}

View File

@@ -5,27 +5,48 @@ pub fn timeframe<S>(timeframe: &Duration, serializer: S) -> Result<S::Ok, S::Err
where
S: serde::Serializer,
{
let mins = timeframe.as_secs() / 60;
let secs = timeframe.as_secs();
if secs < 60 || secs % 60 != 0 {
return Err(serde::ser::Error::custom("Invalid timeframe duration"));
}
let mins = secs / 60;
if mins < 60 {
return serializer.serialize_str(&format!("{mins}Min"));
}
if mins % 60 != 0 {
return Err(serde::ser::Error::custom("Invalid timeframe duration"));
}
let hours = mins / 60;
if hours < 24 {
return serializer.serialize_str(&format!("{hours}Hour"));
}
if hours % 24 != 0 {
return Err(serde::ser::Error::custom("Invalid timeframe duration"));
}
let days = hours / 24;
if days == 1 {
return serializer.serialize_str("1Day");
}
let weeks = days / 7;
if weeks == 1 {
if days == 7 {
return serializer.serialize_str("1Week");
}
if days < 30 || days % 30 != 0 {
return Err(serde::ser::Error::custom("Invalid timeframe duration"));
}
let months = days / 30;
if [1, 2, 3, 4, 6, 12].contains(&months) {
return serializer.serialize_str(&format!("{months}Month"));
};
@@ -87,3 +108,174 @@ where
join_symbols(&symbols, serializer)
}
#[cfg(test)]
mod tests {
use super::*;
use serde::Serialize;
use serde_test::{assert_ser_tokens, assert_ser_tokens_error, Token};
#[derive(Serialize)]
#[serde(transparent)]
struct Timeframe {
#[serde(serialize_with = "timeframe")]
duration: Duration,
}
#[test]
fn test_timeframe_30_mins() {
let timeframe = Timeframe {
duration: Duration::from_secs(60 * 30),
};
assert_ser_tokens(&timeframe, &[Token::Str("30Min")]);
}
#[test]
fn test_timeframe_2_hours() {
let timeframe = Timeframe {
duration: Duration::from_secs(60 * 60 * 2),
};
assert_ser_tokens(&timeframe, &[Token::Str("2Hour")]);
}
#[test]
fn test_timeframe_1_day() {
let timeframe = Timeframe {
duration: Duration::from_secs(60 * 60 * 24),
};
assert_ser_tokens(&timeframe, &[Token::Str("1Day")]);
}
#[test]
fn test_timeframe_1_week() {
let timeframe = Timeframe {
duration: Duration::from_secs(60 * 60 * 24 * 7),
};
assert_ser_tokens(&timeframe, &[Token::Str("1Week")]);
}
#[test]
fn test_timeframe_6_months() {
let timeframe = Timeframe {
duration: Duration::from_secs(60 * 60 * 24 * 30 * 6),
};
assert_ser_tokens(&timeframe, &[Token::Str("6Month")]);
}
#[test]
fn test_timeframe_invalid_1_second() {
let timeframe = Timeframe {
duration: Duration::from_secs(1),
};
assert_ser_tokens_error(&timeframe, &[], "Invalid timeframe duration");
}
#[test]
fn test_timeframe_invalid_61_seconds() {
let timeframe = Timeframe {
duration: Duration::from_secs(61),
};
assert_ser_tokens_error(&timeframe, &[], "Invalid timeframe duration");
}
#[test]
fn test_timeframe_invalid_6_days() {
let timeframe = Timeframe {
duration: Duration::from_secs(60 * 60 * 24 * 6),
};
assert_ser_tokens_error(&timeframe, &[], "Invalid timeframe duration");
}
#[test]
fn test_remove_slash() {
let pair = "BTC/USDT";
assert_eq!(remove_slash(pair), "BTCUSDT");
}
#[derive(Serialize)]
#[serde(transparent)]
struct JoinSymbols {
#[serde(serialize_with = "join_symbols")]
symbols: Vec<String>,
}
#[test]
fn test_join_symbols() {
let symbols = JoinSymbols {
symbols: vec![String::from("BTC/USD"), String::from("ETH/USD")],
};
assert_ser_tokens(&symbols, &[Token::Str("BTC/USD,ETH/USD")]);
}
#[derive(Serialize)]
#[serde(transparent)]
struct JoinSymbolsOption {
#[serde(serialize_with = "join_symbols_option")]
symbols: Option<Vec<String>>,
}
#[test]
fn test_join_symbols_option_some() {
let symbols = JoinSymbolsOption {
symbols: Some(vec![String::from("BTC/USD"), String::from("ETH/USD")]),
};
assert_ser_tokens(&symbols, &[Token::Str("BTC/USD,ETH/USD")]);
}
#[test]
fn test_join_symbols_option_none() {
let symbols = JoinSymbolsOption { symbols: None };
assert_ser_tokens(&symbols, &[Token::None]);
}
#[derive(Serialize)]
#[serde(transparent)]
struct RemoveSlashFromSymbols {
#[serde(serialize_with = "remove_slash_from_symbols")]
symbols: Vec<String>,
}
#[test]
fn test_remove_slash_from_symbols() {
let symbols = RemoveSlashFromSymbols {
symbols: vec![String::from("BTC/USD"), String::from("ETH/USD")],
};
assert_ser_tokens(
&symbols,
&[
Token::Seq { len: Some(2) },
Token::Str("BTCUSD"),
Token::Str("ETHUSD"),
Token::SeqEnd,
],
);
}
#[derive(Serialize)]
#[serde(transparent)]
struct RemoveSlashAndJoinSymbols {
#[serde(serialize_with = "remove_slash_and_join_symbols")]
symbols: Vec<String>,
}
#[test]
fn test_remove_slash_and_join_symbols() {
let symbols = RemoveSlashAndJoinSymbols {
symbols: vec![String::from("BTC/USD"), String::from("ETH/USD")],
};
assert_ser_tokens(&symbols, &[Token::Str("BTCUSD,ETHUSD")]);
}
}

View File

@@ -26,3 +26,21 @@ pub fn duration_until(time: OffsetDateTime) -> Duration {
Duration::default()
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_duration_until_future() {
let future = OffsetDateTime::now_utc() + Duration::from_secs(60);
let duration = duration_until(future).as_secs();
assert!((59..=61).contains(&duration));
}
#[test]
fn test_duration_until_past() {
let past = OffsetDateTime::now_utc() - Duration::from_secs(60);
assert_eq!(duration_until(past).as_secs(), 0);
}
}