1use serde::{Deserialize, Serialize};
6
7#[derive(Debug, Clone, Serialize, Deserialize)]
12pub struct DnsRecord {
13 pub id: Option<String>,
15
16 #[serde(rename = "type")]
18 pub record_type: String,
19
20 pub name: String,
22
23 pub content: String,
25
26 pub ttl: Option<i64>,
28
29 pub proxied: Option<bool>,
31
32 pub comment: Option<String>,
34}
35
36#[derive(Debug, Clone, Serialize, Deserialize)]
38pub struct ApiResponse<T> {
39 pub success: bool,
41
42 pub errors: Vec<ApiError>,
44
45 pub messages: Vec<String>,
47
48 pub result: Option<T>,
50}
51
52#[derive(Debug, Clone, Serialize, Deserialize)]
54pub struct ApiError {
55 pub code: i64,
57
58 pub message: String,
60}
61
62#[derive(Debug, Clone, Serialize, Deserialize)]
64pub struct DnsRecordResponse {
65 pub id: String,
66
67 #[serde(rename = "type")]
68 pub record_type: String,
69
70 pub name: String,
71
72 pub content: String,
73
74 pub ttl: i64,
75
76 pub proxied: bool,
77
78 pub comment: Option<String>,
79}
80
81#[derive(Debug, Clone, Serialize, Deserialize)]
83pub struct ZoneResponse {
84 pub id: String,
85
86 pub name: String,
87}
88
89#[cfg(test)]
90mod tests {
91 use super::*;
92
93 #[test]
94 fn test_dns_record_serialize_minimal() {
95 let record = DnsRecord {
96 id: None,
97 record_type: "A".to_string(),
98 name: "example.com".to_string(),
99 content: "192.168.1.1".to_string(),
100 ttl: None,
101 proxied: None,
102 comment: None,
103 };
104 let json = serde_json::to_string(&record).unwrap();
105 assert!(json.contains("\"type\":\"A\""));
106 assert!(json.contains("\"name\":\"example.com\""));
107 assert!(json.contains("\"content\":\"192.168.1.1\""));
108 }
109
110 #[test]
111 fn test_dns_record_serialize_full() {
112 let record = DnsRecord {
113 id: Some("abc123".to_string()),
114 record_type: "AAAA".to_string(),
115 name: "test.example.com".to_string(),
116 content: "2001:db8::1".to_string(),
117 ttl: Some(300),
118 proxied: Some(true),
119 comment: Some("Test record".to_string()),
120 };
121 let json = serde_json::to_string(&record).unwrap();
122 assert!(json.contains("\"id\":\"abc123\""));
123 assert!(json.contains("\"type\":\"AAAA\""));
124 assert!(json.contains("\"proxied\":true"));
125 assert!(json.contains("\"comment\":\"Test record\""));
126 }
127
128 #[test]
129 fn test_dns_record_deserialize() {
130 let json = r#"{
131 "id": "def456",
132 "type": "CNAME",
133 "name": "www.example.com",
134 "content": "example.com",
135 "ttl": 3600,
136 "proxied": false
137 }"#;
138 let record: DnsRecord = serde_json::from_str(json).unwrap();
139 assert_eq!(record.id, Some("def456".to_string()));
140 assert_eq!(record.record_type, "CNAME");
141 assert_eq!(record.name, "www.example.com");
142 assert_eq!(record.content, "example.com");
143 assert_eq!(record.ttl, Some(3600));
144 assert_eq!(record.proxied, Some(false));
145 }
146
147 #[test]
148 fn test_dns_record_deserialize_with_comment() {
149 let json = r#"{
150 "id": "ghi789",
151 "type": "A",
152 "name": "api.example.com",
153 "content": "10.0.0.1",
154 "ttl": 1,
155 "proxied": true,
156 "comment": "API server"
157 }"#;
158 let record: DnsRecord = serde_json::from_str(json).unwrap();
159 assert_eq!(record.comment, Some("API server".to_string()));
160 }
161
162 #[test]
163 fn test_dns_record_deserialize_without_comment() {
164 let json = r#"{
165 "id": "jkl012",
166 "type": "MX",
167 "name": "example.com",
168 "content": "mail.example.com",
169 "ttl": 3600,
170 "proxied": false
171 }"#;
172 let record: DnsRecord = serde_json::from_str(json).unwrap();
173 assert_eq!(record.comment, None);
174 }
175
176 #[test]
177 fn test_dns_record_type_renamed_correctly() {
178 let json = r#"{"type": "TXT", "name": "example.com", "content": "v=spf1"}"#;
179 let record: DnsRecord = serde_json::from_str(json).unwrap();
180 assert_eq!(record.record_type, "TXT");
181 }
182
183 #[test]
184 fn test_api_response_structure() {
185 let json = r#"{
186 "success": true,
187 "errors": [],
188 "messages": [],
189 "result": {
190 "id": "zone123",
191 "name": "example.com"
192 }
193 }"#;
194 let response: ApiResponse<ZoneResponse> = serde_json::from_str(json).unwrap();
195 assert!(response.success);
196 assert!(response.errors.is_empty());
197 assert!(response.messages.is_empty());
198 assert!(response.result.is_some());
199 let zone = response.result.unwrap();
200 assert_eq!(zone.id, "zone123");
201 assert_eq!(zone.name, "example.com");
202 }
203
204 #[test]
205 fn test_api_response_with_errors() {
206 let json = r#"{
207 "success": false,
208 "errors": [{"code": 1000, "message": "Invalid API token"}],
209 "messages": [],
210 "result": null
211 }"#;
212 let response: ApiResponse<serde_json::Value> = serde_json::from_str(json).unwrap();
213 assert!(!response.success);
214 assert_eq!(response.errors.len(), 1);
215 assert_eq!(response.errors[0].code, 1000);
216 assert_eq!(response.errors[0].message, "Invalid API token");
217 }
218
219 #[test]
220 fn test_dns_record_response_structure() {
221 let json = r#"{
222 "id": "rec123",
223 "type": "A",
224 "name": "example.com",
225 "content": "192.168.1.1",
226 "ttl": 300,
227 "proxied": false,
228 "comment": "Test"
229 }"#;
230 let record: DnsRecordResponse = serde_json::from_str(json).unwrap();
231 assert_eq!(record.id, "rec123");
232 assert_eq!(record.record_type, "A");
233 assert_eq!(record.content, "192.168.1.1");
234 assert_eq!(record.ttl, 300);
235 assert!(!record.proxied);
236 assert_eq!(record.comment, Some("Test".to_string()));
237 }
238
239 #[test]
240 fn test_zone_response_structure() {
241 let json = r#"{
242 "id": "zone456",
243 "name": "mydomain.org"
244 }"#;
245 let zone: ZoneResponse = serde_json::from_str(json).unwrap();
246 assert_eq!(zone.id, "zone456");
247 assert_eq!(zone.name, "mydomain.org");
248 }
249
250 #[test]
251 fn test_dns_record_roundtrip() {
252 let original = DnsRecord {
253 id: Some("rt001".to_string()),
254 record_type: "SRV".to_string(),
255 name: "_sip._tcp.example.com".to_string(),
256 content: "10 60 5060 sip.example.com".to_string(),
257 ttl: Some(3600),
258 proxied: Some(false),
259 comment: Some("SIP service".to_string()),
260 };
261 let json = serde_json::to_string(&original).unwrap();
262 let deserialized: DnsRecord = serde_json::from_str(&json).unwrap();
263 assert_eq!(deserialized.id, original.id);
264 assert_eq!(deserialized.record_type, original.record_type);
265 assert_eq!(deserialized.name, original.name);
266 assert_eq!(deserialized.content, original.content);
267 assert_eq!(deserialized.ttl, original.ttl);
268 assert_eq!(deserialized.proxied, original.proxied);
269 assert_eq!(deserialized.comment, original.comment);
270 }
271
272 #[test]
273 fn test_dns_record_clone() {
274 let record = DnsRecord {
275 id: Some("clone001".to_string()),
276 record_type: "A".to_string(),
277 name: "test.example.com".to_string(),
278 content: "10.0.0.1".to_string(),
279 ttl: Some(60),
280 proxied: Some(true),
281 comment: None,
282 };
283 let cloned = record.clone();
284 assert_eq!(cloned.id, record.id);
285 assert_eq!(cloned.record_type, record.record_type);
286 assert_eq!(cloned.content, record.content);
287 }
288
289 #[test]
290 fn test_dns_record_debug_format() {
291 let record = DnsRecord {
292 id: Some("debug001".to_string()),
293 record_type: "NS".to_string(),
294 name: "example.com".to_string(),
295 content: "ns1.example.com".to_string(),
296 ttl: Some(86400),
297 proxied: Some(false),
298 comment: None,
299 };
300 let debug_str = format!("{:?}", record);
301 assert!(debug_str.contains("debug001"));
302 assert!(debug_str.contains("NS"));
303 assert!(debug_str.contains("ns1.example.com"));
304 }
305}