1use crate::common::NoExtension;
2use crate::domain::transfer::DomainTransferResponseData;
3use crate::extensions::low_balance::LowBalance;
4use crate::host::info::HostInfoResponseData;
5use crate::request::{Command, Transaction};
6use serde::{Deserialize, Serialize};
7
8impl<'a> Transaction<NoExtension> for MessagePoll<'a> {}
9
10impl<'a> Command for MessagePoll<'a> {
11 type Response = MessagePollResponse;
12 const COMMAND: &'static str = "poll";
13}
14
15#[derive(Serialize, Debug)]
18pub struct MessagePoll<'a> {
20 op: &'a str,
23}
24
25impl Default for MessagePoll<'static> {
26 fn default() -> Self {
27 Self { op: "req" }
28 }
29}
30
31#[non_exhaustive]
35#[derive(Deserialize, Debug)]
36pub enum MessageData {
37 #[serde(rename = "trnData")]
39 DomainTransfer(DomainTransferResponseData),
40 #[serde(rename = "infData")]
42 HostInfo(HostInfoResponseData),
43 #[serde(rename = "pollData")]
45 LowBalance(LowBalance),
46}
47
48#[derive(Deserialize, Debug)]
50pub struct MessagePollResponse {
51 #[serde(rename = "trnData", alias = "infData", alias = "pollData")]
53 pub message_data: MessageData,
54}
55
56#[cfg(test)]
57mod tests {
58 use super::MessagePoll;
59 use crate::message::poll::MessageData;
60 use crate::response::ResultCode;
61 use crate::tests::{assert_serialized, response_from_file, CLTRID, SVTRID};
62
63 use chrono::{TimeZone, Utc};
64 use std::net::IpAddr;
65
66 #[test]
67 fn command() {
68 let object = MessagePoll::default();
69 assert_serialized("request/message/poll.xml", &object);
70 }
71
72 #[test]
73 fn domain_transfer_response() {
74 let object = response_from_file::<MessagePoll>("response/message/poll_domain_transfer.xml");
75 let result = object.res_data().unwrap();
76 let msg = object.message_queue().unwrap();
77
78 assert_eq!(
79 object.result.code,
80 ResultCode::CommandCompletedSuccessfullyAckToDequeue
81 );
82 assert_eq!(
83 object.result.message,
84 "Command completed successfully; ack to dequeue".into()
85 );
86 assert_eq!(msg.count, 5);
87 assert_eq!(msg.id, "12345".to_string());
88 assert_eq!(
89 msg.date,
90 Utc.with_ymd_and_hms(2021, 7, 23, 19, 12, 43).single()
91 );
92 assert_eq!(
93 *(msg.message.as_ref().unwrap()),
94 "Transfer requested.".into()
95 );
96
97 if let MessageData::DomainTransfer(tr) = &result.message_data {
98 assert_eq!(tr.name, "eppdev-transfer.com".into());
99 assert_eq!(tr.transfer_status, "pending".into());
100 assert_eq!(tr.requester_id, "eppdev".into());
101 assert_eq!(
102 tr.requested_at,
103 Utc.with_ymd_and_hms(2021, 7, 23, 15, 31, 21).unwrap()
104 );
105 assert_eq!(tr.ack_id, "ClientY".into());
106 assert_eq!(
107 tr.ack_by,
108 Utc.with_ymd_and_hms(2021, 7, 28, 15, 31, 21).unwrap()
109 );
110 assert_eq!(
111 tr.expiring_at,
112 Utc.with_ymd_and_hms(2022, 7, 2, 14, 53, 19).single()
113 );
114 } else {
115 panic!("Wrong type");
116 }
117
118 assert_eq!(object.tr_ids.client_tr_id.unwrap(), CLTRID.into());
119 assert_eq!(object.tr_ids.server_tr_id, SVTRID.into());
120 }
121
122 #[test]
123 fn host_info_response() {
124 let object = response_from_file::<MessagePoll>("response/message/poll_host_info.xml");
125 let result = object.res_data().unwrap();
126 let msg = object.message_queue().unwrap();
127
128 assert_eq!(
129 object.result.code,
130 ResultCode::CommandCompletedSuccessfullyAckToDequeue
131 );
132 assert_eq!(
133 object.result.message,
134 "Command completed successfully; ack to dequeue".into()
135 );
136 assert_eq!(msg.count, 4);
137 assert_eq!(msg.id, "12345".to_string());
138 assert_eq!(
139 msg.date,
140 Utc.with_ymd_and_hms(2022, 1, 2, 11, 30, 45).single()
141 );
142 assert_eq!(
143 *(msg.message.as_ref().unwrap()),
144 "Unused objects policy".into()
145 );
146
147 if let MessageData::HostInfo(host) = &result.message_data {
148 assert_eq!(host.name, "ns.test.com".into());
149
150 assert_eq!(host.roid, "1234".into());
151 assert!(host.statuses.iter().any(|s| s.status == "ok"));
152 assert!(host
153 .addresses
154 .iter()
155 .any(|a| a == &IpAddr::from([1, 1, 1, 1])));
156 assert_eq!(host.client_id, "1234".into());
157 assert_eq!(host.creator_id, "user".into());
158 assert_eq!(
159 host.created_at,
160 Utc.with_ymd_and_hms(2021, 12, 1, 22, 40, 48).unwrap()
161 );
162 assert_eq!(host.updater_id, Some("user".into()));
163 assert_eq!(
164 host.updated_at,
165 Utc.with_ymd_and_hms(2021, 12, 1, 22, 40, 48).single()
166 );
167 } else {
168 panic!("Wrong type");
169 }
170
171 assert_eq!(object.tr_ids.client_tr_id.unwrap(), CLTRID.into());
172 assert_eq!(object.tr_ids.server_tr_id, SVTRID.into());
173 }
174
175 #[test]
176 fn message_only_response() {
177 let object = response_from_file::<MessagePoll>("response/message/poll_message_only.xml");
178 let msg = object.message_queue().unwrap();
179
180 assert_eq!(
181 object.result.code,
182 ResultCode::CommandCompletedSuccessfullyAckToDequeue
183 );
184 assert_eq!(
185 object.result.message,
186 "Command completed successfully; ack to dequeue".into()
187 );
188
189 assert_eq!(msg.count, 4);
190 assert_eq!(msg.id, "12346".to_string());
191 assert_eq!(
192 msg.date,
193 Utc.with_ymd_and_hms(2000, 6, 8, 22, 10, 0).single()
194 );
195 assert_eq!(
196 *(msg.message.as_ref().unwrap()),
197 "Credit balance low.".into()
198 );
199
200 assert_eq!(object.tr_ids.client_tr_id.unwrap(), CLTRID.into());
201 assert_eq!(object.tr_ids.server_tr_id, SVTRID.into());
202 }
203
204 #[test]
205 fn empty_queue_response() {
206 let object = response_from_file::<MessagePoll>("response/message/poll_empty_queue.xml");
207
208 assert_eq!(
209 object.result.code,
210 ResultCode::CommandCompletedSuccessfullyNoMessages
211 );
212 assert_eq!(
213 object.result.message,
214 "Command completed successfully; no messages".into()
215 );
216
217 assert_eq!(object.tr_ids.client_tr_id.unwrap(), CLTRID.into());
218 assert_eq!(object.tr_ids.server_tr_id, SVTRID.into());
219 }
220}