rustrade_data/exchange/kraken/
subscription.rs1use super::message::KrakenError;
2use rustrade_integration::{Validator, error::SocketError};
3use serde::{Deserialize, Serialize};
4
5#[derive(Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Debug, Deserialize, Serialize)]
36#[serde(tag = "status", rename_all = "camelCase")]
37pub enum KrakenSubResponse {
38 Subscribed {
39 #[serde(alias = "channelID")]
40 channel_id: u64,
41 #[serde(alias = "channelName")]
42 channel_name: String,
43 pair: String,
44 },
45 Error(KrakenError),
46}
47
48impl Validator for KrakenSubResponse {
49 type Error = SocketError;
50
51 fn validate(self) -> Result<Self, SocketError>
52 where
53 Self: Sized,
54 {
55 match &self {
56 KrakenSubResponse::Subscribed { .. } => Ok(self),
57 KrakenSubResponse::Error(error) => Err(SocketError::Subscribe(format!(
58 "received failure subscription response: {}",
59 error.message
60 ))),
61 }
62 }
63}
64
65#[cfg(test)]
66mod tests {
67 use super::*;
68
69 mod de {
70 use super::*;
71
72 #[test]
73 fn test_kraken_sub_response() {
74 struct TestCase {
75 input: &'static str,
76 expected: Result<KrakenSubResponse, SocketError>,
77 }
78
79 let cases = vec![
80 TestCase {
81 input: r#"
83 {
84 "channelID": 10001,
85 "channelName": "ticker",
86 "event": "subscriptionStatus",
87 "pair": "XBT/EUR",
88 "status": "subscribed",
89 "subscription": {
90 "name": "ticker"
91 }
92 }
93 "#,
94 expected: Ok(KrakenSubResponse::Subscribed {
95 channel_id: 10001,
96 channel_name: "ticker".to_string(),
97 pair: "XBT/EUR".to_string(),
98 }),
99 },
100 TestCase {
101 input: r#"
103 {
104 "errorMessage": "Subscription name invalid",
105 "event": "subscriptionStatus",
106 "pair": "XBT/USD",
107 "status": "error",
108 "subscription": {
109 "name": "trades"
110 }
111 }
112 "#,
113 expected: Ok(KrakenSubResponse::Error(KrakenError {
114 message: "Subscription name invalid".to_string(),
115 })),
116 },
117 ];
118
119 for (index, test) in cases.into_iter().enumerate() {
120 let actual = serde_json::from_str::<KrakenSubResponse>(test.input);
121 match (actual, test.expected) {
122 (Ok(actual), Ok(expected)) => {
123 assert_eq!(actual, expected, "TC{} failed", index)
124 }
125 (Err(_), Err(_)) => {
126 }
128 (actual, expected) => {
129 panic!(
131 "TC{index} failed because actual != expected. \nActual: {actual:?}\nExpected: {expected:?}\n"
132 );
133 }
134 }
135 }
136 }
137 }
138
139 #[test]
140 fn test_kraken_sub_response_validate() {
141 struct TestCase {
142 input_response: KrakenSubResponse,
143 is_valid: bool,
144 }
145
146 let cases = vec![
147 TestCase {
148 input_response: KrakenSubResponse::Subscribed {
150 channel_id: 10001,
151 channel_name: "ticker".to_string(),
152 pair: "XBT/EUR".to_string(),
153 },
154 is_valid: true,
155 },
156 TestCase {
157 input_response: KrakenSubResponse::Error(KrakenError {
159 message: "Subscription name invalid".to_string(),
160 }),
161 is_valid: false,
162 },
163 ];
164
165 for (index, test) in cases.into_iter().enumerate() {
166 let actual = test.input_response.validate().is_ok();
167 assert_eq!(actual, test.is_valid, "TestCase {} failed", index);
168 }
169 }
170}