sync15/
client_types.rs

1/* This Source Code Form is subject to the terms of the Mozilla Public
2 * License, v. 2.0. If a copy of the MPL was not distributed with this
3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
4
5//! This module has to be here because of some hard-to-avoid hacks done for the
6//! tabs engine... See issue #2590
7
8use crate::DeviceType;
9use serde::{Deserialize, Serialize};
10use std::collections::HashMap;
11
12/// Argument to `SyncEngine::set_clients` - a leaky abstraction of fxa/sync
13/// device ids. These are "short term" IDs in that they don't survive reauth
14/// etc, so used for "recent" things like open tabs.
15#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq)]
16pub struct ClientData {
17    pub local_client_id: String,
18    /// A hashmap of records in the `clients` collection. Key is the id of the record in
19    /// that collection, which may or may not be the device's fxa_device_id.
20    pub recent_clients: HashMap<String, RemoteClient>,
21}
22
23/// Information about a remote client in the clients collection.
24#[derive(Clone, Debug, Eq, Hash, PartialEq, Serialize, Deserialize)]
25pub struct RemoteClient {
26    pub fxa_device_id: Option<String>,
27    pub device_name: String,
28    #[serde(default)]
29    pub device_type: DeviceType,
30}
31
32#[cfg(test)]
33mod client_types_tests {
34    use super::*;
35
36    #[test]
37    fn test_remote_client() {
38        // Missing `device_type` gets DeviceType::Unknown.
39        let dt = serde_json::from_str::<RemoteClient>("{\"device_name\": \"foo\"}").unwrap();
40        assert_eq!(dt.device_type, DeviceType::Unknown);
41        // But reserializes as null.
42        assert_eq!(
43            serde_json::to_string(&dt).unwrap(),
44            "{\"fxa_device_id\":null,\"device_name\":\"foo\",\"device_type\":null}"
45        );
46
47        // explicit null is also unknown.
48        assert_eq!(
49            serde_json::from_str::<RemoteClient>(
50                "{\"device_name\": \"foo\", \"device_type\": null}",
51            )
52            .unwrap()
53            .device_type,
54            DeviceType::Unknown
55        );
56
57        // Unknown device_type string deserializes as DeviceType::Unknown.
58        let dt = serde_json::from_str::<RemoteClient>(
59            "{\"device_name\": \"foo\", \"device_type\": \"foo\"}",
60        )
61        .unwrap();
62        assert_eq!(dt.device_type, DeviceType::Unknown);
63        // The None gets re-serialized as null.
64        assert_eq!(
65            serde_json::to_string(&dt).unwrap(),
66            "{\"fxa_device_id\":null,\"device_name\":\"foo\",\"device_type\":null}"
67        );
68
69        // DeviceType::Unknown gets serialized as null.
70        let dt = RemoteClient {
71            device_name: "bar".to_string(),
72            fxa_device_id: None,
73            device_type: DeviceType::Unknown,
74        };
75        assert_eq!(
76            serde_json::to_string(&dt).unwrap(),
77            "{\"fxa_device_id\":null,\"device_name\":\"bar\",\"device_type\":null}"
78        );
79
80        // DeviceType::Desktop gets serialized as "desktop".
81        let dt = RemoteClient {
82            device_name: "bar".to_string(),
83            fxa_device_id: Some("fxa".to_string()),
84            device_type: DeviceType::Desktop,
85        };
86        assert_eq!(
87            serde_json::to_string(&dt).unwrap(),
88            "{\"fxa_device_id\":\"fxa\",\"device_name\":\"bar\",\"device_type\":\"desktop\"}"
89        );
90    }
91
92    #[test]
93    fn test_client_data() {
94        let client_data = ClientData {
95            local_client_id: "my-device".to_string(),
96            recent_clients: HashMap::from([
97                (
98                    "my-device".to_string(),
99                    RemoteClient {
100                        fxa_device_id: None,
101                        device_name: "my device".to_string(),
102                        device_type: DeviceType::Unknown,
103                    },
104                ),
105                (
106                    "device-no-tabs".to_string(),
107                    RemoteClient {
108                        fxa_device_id: None,
109                        device_name: "device with no tabs".to_string(),
110                        device_type: DeviceType::Unknown,
111                    },
112                ),
113                (
114                    "device-with-a-tab".to_string(),
115                    RemoteClient {
116                        fxa_device_id: None,
117                        device_name: "device with a tab".to_string(),
118                        device_type: DeviceType::Desktop,
119                    },
120                ),
121            ]),
122        };
123        //serialize
124        let client_data_ser = serde_json::to_string(&client_data).unwrap();
125        println!("SER: {}", client_data_ser);
126        // deserialize
127        let client_data_des: ClientData = serde_json::from_str(&client_data_ser).unwrap();
128        assert_eq!(client_data_des, client_data);
129    }
130}