barter_data/exchange/gateio/
subscription.rs

1use super::message::GateioMessage;
2use barter_integration::{Validator, error::SocketError};
3use serde::{Deserialize, Serialize};
4
5/// Expected [`Gateio`](super::Gateio) [`Subscription`](crate::subscription::Subscription) response
6/// type wrapped in the generic [`GateioMessage<T>`](GateioMessage).
7pub type GateioSubResponse = GateioMessage<GateioSubResult>;
8
9/// Expected [`Gateio`](super::Gateio) [`Subscription`](crate::subscription::Subscription)
10/// response type.
11///
12/// See [`GateioMessage`] for full raw payload examples.
13///
14/// See docs: <https://www.gate.io/docs/developers/apiv4/ws/en/#server-response>
15#[derive(Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Debug, Deserialize, Serialize)]
16pub struct GateioSubResult {
17    pub status: String,
18}
19
20impl Validator for GateioSubResponse {
21    fn validate(self) -> Result<Self, SocketError>
22    where
23        Self: Sized,
24    {
25        match &self.error {
26            None => Ok(self),
27            Some(failure) => Err(SocketError::Subscribe(format!(
28                "received failure subscription response code: {} with message: {}",
29                failure.code, failure.message,
30            ))),
31        }
32    }
33}
34
35#[cfg(test)]
36mod tests {
37    use super::*;
38    use crate::exchange::gateio::message::GateioError;
39
40    mod de {
41        use super::*;
42
43        #[test]
44        fn test_gateio_sub_response() {
45            struct TestCase {
46                input: &'static str,
47                expected: Result<GateioSubResponse, SocketError>,
48            }
49
50            let tests = vec![TestCase {
51                // TC0: input response is Subscribed
52                input: r#"
53                    {
54                        "time": 1606292218,
55                        "time_ms": 1606292218231,
56                        "channel": "spot.trades",
57                        "event": "subscribe",
58                        "result": {
59                            "status": "success"
60                        }
61                    }
62                    "#,
63                expected: Ok(GateioSubResponse {
64                    channel: "spot.trades".to_string(),
65                    error: None,
66                    data: GateioSubResult {
67                        status: "success".to_string(),
68                    },
69                }),
70            }];
71
72            for (index, test) in tests.into_iter().enumerate() {
73                let actual = serde_json::from_str::<GateioSubResponse>(test.input);
74                match (actual, test.expected) {
75                    (Ok(actual), Ok(expected)) => {
76                        assert_eq!(actual, expected, "TC{} failed", index)
77                    }
78                    (Err(_), Err(_)) => {
79                        // Test passed
80                    }
81                    (actual, expected) => {
82                        // Test failed
83                        panic!(
84                            "TC{index} failed because actual != expected. \nActual: {actual:?}\nExpected: {expected:?}\n"
85                        );
86                    }
87                }
88            }
89        }
90    }
91
92    #[test]
93    fn test_validate_gateio_sub_response() {
94        struct TestCase {
95            input_response: GateioSubResponse,
96            is_valid: bool,
97        }
98
99        let cases = vec![
100            TestCase {
101                // TC0: input response is successful subscription
102                input_response: GateioSubResponse {
103                    channel: "spot.trades".to_string(),
104                    error: None,
105                    data: GateioSubResult {
106                        status: "success".to_string(),
107                    },
108                },
109                is_valid: true,
110            },
111            TestCase {
112                // TC1: input response is failed subscription
113                input_response: GateioSubResponse {
114                    channel: "spot.trades".to_string(),
115                    error: Some(GateioError {
116                        code: 0,
117                        message: "".to_string(),
118                    }),
119                    data: GateioSubResult {
120                        status: "not used".to_string(),
121                    },
122                },
123                is_valid: false,
124            },
125        ];
126
127        for (index, test) in cases.into_iter().enumerate() {
128            let actual = test.input_response.validate().is_ok();
129            assert_eq!(actual, test.is_valid, "TestCase {} failed", index);
130        }
131    }
132}