Skip to main content

rustrade_data/exchange/gateio/
subscription.rs

1use super::message::GateioMessage;
2use rustrade_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    type Error = SocketError;
22
23    fn validate(self) -> Result<Self, Self::Error>
24    where
25        Self: Sized,
26    {
27        match &self.error {
28            None => Ok(self),
29            Some(failure) => Err(SocketError::Subscribe(format!(
30                "received failure subscription response code: {} with message: {}",
31                failure.code, failure.message,
32            ))),
33        }
34    }
35}
36
37#[cfg(test)]
38mod tests {
39    use super::*;
40    use crate::exchange::gateio::message::GateioError;
41
42    mod de {
43        use super::*;
44
45        #[test]
46        fn test_gateio_sub_response() {
47            struct TestCase {
48                input: &'static str,
49                expected: Result<GateioSubResponse, SocketError>,
50            }
51
52            let tests = vec![TestCase {
53                // TC0: input response is Subscribed
54                input: r#"
55                    {
56                        "time": 1606292218,
57                        "time_ms": 1606292218231,
58                        "channel": "spot.trades",
59                        "event": "subscribe",
60                        "result": {
61                            "status": "success"
62                        }
63                    }
64                    "#,
65                expected: Ok(GateioSubResponse {
66                    channel: "spot.trades".to_string(),
67                    error: None,
68                    data: GateioSubResult {
69                        status: "success".to_string(),
70                    },
71                }),
72            }];
73
74            for (index, test) in tests.into_iter().enumerate() {
75                let actual = serde_json::from_str::<GateioSubResponse>(test.input);
76                match (actual, test.expected) {
77                    (Ok(actual), Ok(expected)) => {
78                        assert_eq!(actual, expected, "TC{} failed", index)
79                    }
80                    (Err(_), Err(_)) => {
81                        // Test passed
82                    }
83                    (actual, expected) => {
84                        // Test failed
85                        panic!(
86                            "TC{index} failed because actual != expected. \nActual: {actual:?}\nExpected: {expected:?}\n"
87                        );
88                    }
89                }
90            }
91        }
92    }
93
94    #[test]
95    fn test_validate_gateio_sub_response() {
96        struct TestCase {
97            input_response: GateioSubResponse,
98            is_valid: bool,
99        }
100
101        let cases = vec![
102            TestCase {
103                // TC0: input response is successful subscription
104                input_response: GateioSubResponse {
105                    channel: "spot.trades".to_string(),
106                    error: None,
107                    data: GateioSubResult {
108                        status: "success".to_string(),
109                    },
110                },
111                is_valid: true,
112            },
113            TestCase {
114                // TC1: input response is failed subscription
115                input_response: GateioSubResponse {
116                    channel: "spot.trades".to_string(),
117                    error: Some(GateioError {
118                        code: 0,
119                        message: "".to_string(),
120                    }),
121                    data: GateioSubResult {
122                        status: "not used".to_string(),
123                    },
124                },
125                is_valid: false,
126            },
127        ];
128
129        for (index, test) in cases.into_iter().enumerate() {
130            let actual = test.input_response.validate().is_ok();
131            assert_eq!(actual, test.is_valid, "TestCase {} failed", index);
132        }
133    }
134}