1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
pub use crate::http_client::GetAttachedClientResponse as AttachedClient;
use crate::{error::*, util, CachedResponse, FirefoxAccount};
const ATTACHED_CLIENTS_FRESHNESS_THRESHOLD: u64 = 60_000;
impl FirefoxAccount {
pub fn get_attached_clients(&mut self) -> Result<Vec<AttachedClient>> {
if let Some(a) = &self.attached_clients_cache {
if util::now() < a.cached_at + ATTACHED_CLIENTS_FRESHNESS_THRESHOLD {
return Ok(a.response.clone());
}
}
let session_token = self.get_session_token()?;
let response = self
.client
.attached_clients(&self.state.config, &session_token)?;
self.attached_clients_cache = Some(CachedResponse {
response: response.clone(),
cached_at: util::now(),
etag: "".into(),
});
Ok(response)
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::{
config::Config,
http_client::{DeviceType, FxAClientMock},
};
use std::sync::Arc;
#[test]
fn test_get_attached_clients() {
let config = Config::stable_dev("12345678", "https://foo.bar");
let mut fxa = FirefoxAccount::with_config(config);
fxa.set_session_token("session");
let mut client = FxAClientMock::new();
client
.expect_attached_clients(mockiato::Argument::any, |arg| arg.partial_eq("session"))
.times(1)
.returns_once(Ok(vec![AttachedClient {
client_id: Some("12345678".into()),
session_token_id: None,
refresh_token_id: None,
device_id: None,
device_type: Some(DeviceType::Desktop),
is_current_session: true,
name: None,
created_time: None,
last_access_time: None,
scope: None,
user_agent: "attachedClientsUserAgent".into(),
os: None,
}]));
fxa.set_client(Arc::new(client));
assert!(fxa.attached_clients_cache.is_none());
let res = fxa.get_attached_clients();
assert!(res.is_ok());
assert!(fxa.attached_clients_cache.is_some());
let cached_attached_clients_res = fxa.attached_clients_cache.unwrap();
assert!(!cached_attached_clients_res.response.is_empty());
assert!(cached_attached_clients_res.cached_at > 0);
let cached_attached_clients = &cached_attached_clients_res.response[0];
assert_eq!(
cached_attached_clients.clone().client_id.unwrap(),
"12345678".to_string()
);
}
#[test]
fn test_get_attached_clients_network_errors() {
let config = Config::stable_dev("12345678", "https://foo.bar");
let mut fxa = FirefoxAccount::with_config(config);
fxa.set_session_token("session");
let mut client = FxAClientMock::new();
client
.expect_attached_clients(mockiato::Argument::any, |arg| arg.partial_eq("session"))
.times(1)
.returns_once(Err(ErrorKind::RemoteError {
code: 500,
errno: 101,
error: "Did not work!".to_owned(),
message: "Did not work!".to_owned(),
info: "Did not work!".to_owned(),
}
.into()));
fxa.set_client(Arc::new(client));
assert!(fxa.attached_clients_cache.is_none());
let res = fxa.get_attached_clients();
assert!(res.is_err());
assert!(fxa.attached_clients_cache.is_none());
}
}