1use super::Application;
2use serde::de::{self, Deserialize, Deserializer, Visitor, MapAccess, SeqAccess};
3use serde::ser::{Serialize, Serializer, SerializeStruct};
4use std::convert::From;
5use std::fmt;
6
7
8#[derive(Debug, PartialEq, Deserialize)]
9pub struct Applications {
10 #[serde(rename = "versions__delta")]
11 pub versions_delta: i16,
12 #[serde(rename = "apps__hashcode")]
13 pub apps_hashcode: String,
14 #[serde(rename = "application", deserialize_with = "deserialize_applications_field")]
15 pub applications: Vec<Application>
16}
17
18
19impl Serialize for Applications {
20 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> where
21 S: Serializer {
22 let mut s = serializer.serialize_struct("Applications", 3)?;
23 s.serialize_field("versions__delta", &self.versions_delta)?;
24 s.serialize_field("apps__hashcode", &self.apps_hashcode)?;
25
26 if self.applications.len() == 1 {
27 s.serialize_field("application", &self.applications.get(0))?;
28 } else if !self.applications.is_empty() {
29 s.serialize_field("application", &self.applications)?;
30 }
31 s.end()
32 }
33}
34
35impl From<Application> for Vec<Application> {
36 fn from(v: Application) -> Self {
37 vec![v]
38 }
39}
40
41fn deserialize_applications_field<'de, D>(de: D) -> Result<Vec<Application>, D::Error>
42 where D: Deserializer<'de> {
43 struct ApplicationOrVec;
44
45 impl<'de> Visitor<'de> for ApplicationOrVec {
46 type Value = Vec<Application>;
47
48 fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
49 formatter.write_str("application or vec")
50 }
51
52 fn visit_map<A>(self, visitor: A) -> Result<Self::Value, A::Error> where
53 A: MapAccess<'de>, {
54 let result: Result<Application, A::Error> = Deserialize::deserialize(de::value::MapAccessDeserializer::new(visitor));
55 result.map(|a| From::from(a))
56 }
57
58 fn visit_seq<A>(self, visitor: A) -> Result<Self::Value, A::Error> where
59 A: SeqAccess<'de>, {
60 Deserialize::deserialize(de::value::SeqAccessDeserializer::new(visitor))
61 }
62 }
63
64 de.deserialize_any(ApplicationOrVec)
65}
66
67#[cfg(test)]
68pub mod tests {
69 use serde_json::{self, Map};
70 use super::*;
71 use super::super::Application;
72 use super::super::Instance;
73 use super::super::Status;
74 use super::super::DataCenterInfo;
75 use super::super::DcName;
76 use super::super::LeaseInfo;
77 use super::super::ActionType;
78
79 #[test]
80 fn test_applications_serialize() {
81 let applications = build_test_applications();
82 let result = serde_json::to_string(&applications).unwrap();
83 assert!(result.contains("\"apps__hashcode\":\"UP_1_\""));
84 assert!(result.contains("\"name\":\"INTEGRATION_TEST\""));
85 }
86
87 #[test]
88 fn test_applications_deserialize() {
89 let json = build_test_applications_json();
90 let applications = build_test_applications();
91 let result = serde_json::from_str(json.as_ref()).unwrap();
92
93 assert_eq!(applications, result)
94 }
95
96 #[test]
97 fn test_applications_multi_deserialize() {
98 let json = build_test_multi_applications_json();
99 let result: Applications = serde_json::from_str(json.as_ref()).unwrap();
100 assert_eq!(2, result.applications.len())
101 }
102
103 pub fn build_test_applications() -> Applications {
104 Applications {
105 versions_delta: 1,
106 apps_hashcode: "UP_1_".to_string(),
107 applications: vec![
108 Application {
109 name: "INTEGRATION_TEST".to_string(),
110 instance: Instance {
111 host_name: "localhost".to_string(),
112 app: "INTEGRATION_TEST".to_string(),
113 ip_addr: "127.0.0.1".to_string(),
114 status: Status::Up,
115 overriddenstatus: Some(Status::Unknown),
116 port: Some(7001),
117 secure_port: Some(7002),
118 country_id: 1,
119 data_center_info: DataCenterInfo {
120 name: DcName::MyOwn,
121 metadata: None
122 },
123 lease_info: Some(LeaseInfo {
124 renewal_interval_in_secs: 30,
125 duration_in_secs: 90,
126 registration_timestamp: 1503701416749,
127 last_renewal_timestamp: 1503701416749,
128 eviction_timestamp: 0,
129 service_up_timestamp: 1503701416464
130 }),
131 metadata: Map::new(),
132 homepage_url: "http://google.com".to_string(),
133 status_page_url: "http://google.com".to_string(),
134 health_check_url: "http://google.com".to_string(),
135 vip_address: "127.0.0.1".to_string(),
136 secure_vip_address: "127.0.0.1".to_string(),
137 is_coordinating_discovery_server: false,
138 last_updated_timestamp: 1503701416750,
139 last_dirty_timestamp: 1503701416457,
140 action_type: ActionType::Added
141 }
142 }
143 ]
144 }
145 }
146
147 pub fn build_test_applications_json() -> String {
148 r#"
149 {
150 "versions__delta": 1,
151 "apps__hashcode": "UP_1_",
152 "application": {
153 "name": "INTEGRATION_TEST",
154 "instance": {
155 "hostName": "localhost",
156 "app": "INTEGRATION_TEST",
157 "ipAddr": "127.0.0.1",
158 "status": "UP",
159 "overriddenstatus": "UNKNOWN",
160 "port": {
161 "@enabled": "true",
162 "$": "7001"
163 },
164 "securePort": {
165 "@enabled": "false",
166 "$": "7002"
167 },
168 "countryId": 1,
169 "dataCenterInfo": {
170 "name": "MyOwn"
171 },
172 "leaseInfo": {
173 "renewalIntervalInSecs": 30,
174 "durationInSecs": 90,
175 "registrationTimestamp": 1503701416749,
176 "lastRenewalTimestamp": 1503701416749,
177 "evictionTimestamp": 0,
178 "serviceUpTimestamp": 1503701416464
179 },
180 "metadata": {
181 "@class": "java.util.Collections$EmptyMap"
182 },
183 "homePageUrl": "http://google.com",
184 "statusPageUrl": "http://google.com",
185 "healthCheckUrl": "http://google.com",
186 "vipAddress": "127.0.0.1",
187 "secureVipAddress": "127.0.0.1",
188 "isCoordinatingDiscoveryServer": false,
189 "lastUpdatedTimestamp": 1503701416750,
190 "lastDirtyTimestamp": 1503701416457,
191 "actionType": "ADDED"
192 }
193 }
194 }
195 "#.to_string()
196 .replace(" ", "")
197 .replace("\n", "")
198 }
199
200 pub fn build_test_multi_applications_json() -> String {
201 r#"
202 {
203 "versions__delta": 1,
204 "apps__hashcode": "UP_1_",
205 "application": [{
206 "name": "INTEGRATION_TEST",
207 "instance": {
208 "hostName": "localhost",
209 "app": "INTEGRATION_TEST",
210 "ipAddr": "127.0.0.1",
211 "status": "UP",
212 "overriddenstatus": "UNKNOWN",
213 "port": {
214 "@enabled": "true",
215 "$": "7001"
216 },
217 "securePort": {
218 "@enabled": "false",
219 "$": "7002"
220 },
221 "countryId": 1,
222 "dataCenterInfo": {
223 "name": "MyOwn"
224 },
225 "leaseInfo": {
226 "renewalIntervalInSecs": 30,
227 "durationInSecs": 90,
228 "registrationTimestamp": 1503701416749,
229 "lastRenewalTimestamp": 1503701416749,
230 "evictionTimestamp": 0,
231 "serviceUpTimestamp": 1503701416464
232 },
233 "metadata": {
234 "@class": "java.util.Collections$EmptyMap"
235 },
236 "homePageUrl": "http://google.com",
237 "statusPageUrl": "http://google.com",
238 "healthCheckUrl": "http://google.com",
239 "vipAddress": "127.0.0.1",
240 "secureVipAddress": "127.0.0.1",
241 "isCoordinatingDiscoveryServer": false,
242 "lastUpdatedTimestamp": 1503701416750,
243 "lastDirtyTimestamp": 1503701416457,
244 "actionType": "ADDED"
245 }
246 }, {
247 "name": "INTEGRATION_TEST2",
248 "instance": {
249 "hostName": "localhost",
250 "app": "INTEGRATION_TEST",
251 "ipAddr": "127.0.0.1",
252 "status": "UP",
253 "overriddenstatus": "UNKNOWN",
254 "port": {
255 "@enabled": "true",
256 "$": "7001"
257 },
258 "securePort": {
259 "@enabled": "false",
260 "$": "7002"
261 },
262 "countryId": 1,
263 "dataCenterInfo": {
264 "name": "MyOwn"
265 },
266 "leaseInfo": {
267 "renewalIntervalInSecs": 30,
268 "durationInSecs": 90,
269 "registrationTimestamp": 1503701416749,
270 "lastRenewalTimestamp": 1503701416749,
271 "evictionTimestamp": 0,
272 "serviceUpTimestamp": 1503701416464
273 },
274 "metadata": {
275 "@class": "java.util.Collections$EmptyMap"
276 },
277 "homePageUrl": "http://google.com",
278 "statusPageUrl": "http://google.com",
279 "healthCheckUrl": "http://google.com",
280 "vipAddress": "127.0.0.1",
281 "secureVipAddress": "127.0.0.1",
282 "isCoordinatingDiscoveryServer": false,
283 "lastUpdatedTimestamp": 1503701416750,
284 "lastDirtyTimestamp": 1503701416457,
285 "actionType": "ADDED"
286 }
287 }]
288 }
289 "#.to_string()
290 .replace(" ", "")
291 .replace("\n", "")
292 }
293}