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
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
use crate::{async_trait, Result, Session, SessionStore};
#[derive(Debug, Clone, Copy)]
pub struct CookieStore;
impl CookieStore {
pub fn new() -> Self {
Self
}
}
#[async_trait]
impl SessionStore for CookieStore {
async fn load_session(&self, cookie_value: String) -> Result<Option<Session>> {
let serialized = base64::decode(&cookie_value)?;
let session: Session = bincode::deserialize(&serialized)?;
Ok(session.validate())
}
async fn store_session(&self, session: Session) -> Result<Option<String>> {
let serialized = bincode::serialize(&session)?;
Ok(Some(base64::encode(serialized)))
}
async fn destroy_session(&self, _session: Session) -> Result {
Ok(())
}
async fn clear_store(&self) -> Result {
Ok(())
}
}
#[cfg(test)]
mod tests {
use super::*;
use async_std::task;
use std::time::Duration;
#[async_std::test]
async fn creating_a_new_session_with_no_expiry() -> Result {
let store = CookieStore::new();
let mut session = Session::new();
session.insert("key", "Hello")?;
let cloned = session.clone();
let cookie_value = store.store_session(session).await?.unwrap();
let loaded_session = store.load_session(cookie_value).await?.unwrap();
assert_eq!(cloned.id(), loaded_session.id());
assert_eq!("Hello", &loaded_session.get::<String>("key").unwrap());
assert!(!loaded_session.is_expired());
assert!(loaded_session.validate().is_some());
Ok(())
}
#[async_std::test]
async fn updating_a_session() -> Result {
let store = CookieStore::new();
let mut session = Session::new();
session.insert("key", "value")?;
let cookie_value = store.store_session(session).await?.unwrap();
let mut session = store.load_session(cookie_value.clone()).await?.unwrap();
session.insert("key", "other value")?;
let new_cookie_value = store.store_session(session).await?.unwrap();
let session = store.load_session(new_cookie_value).await?.unwrap();
assert_eq!(&session.get::<String>("key").unwrap(), "other value");
Ok(())
}
#[async_std::test]
async fn updating_a_session_extending_expiry() -> Result {
let store = CookieStore::new();
let mut session = Session::new();
session.expire_in(Duration::from_secs(1));
let original_expires = session.expiry().unwrap().clone();
let cookie_value = store.store_session(session).await?.unwrap();
let mut session = store.load_session(cookie_value.clone()).await?.unwrap();
assert_eq!(session.expiry().unwrap(), &original_expires);
session.expire_in(Duration::from_secs(3));
let new_expires = session.expiry().unwrap().clone();
let cookie_value = store.store_session(session).await?.unwrap();
let session = store.load_session(cookie_value.clone()).await?.unwrap();
assert_eq!(session.expiry().unwrap(), &new_expires);
task::sleep(Duration::from_secs(3)).await;
assert_eq!(None, store.load_session(cookie_value).await?);
Ok(())
}
#[async_std::test]
async fn creating_a_new_session_with_expiry() -> Result {
let store = CookieStore::new();
let mut session = Session::new();
session.expire_in(Duration::from_secs(3));
session.insert("key", "value")?;
let cloned = session.clone();
let cookie_value = store.store_session(session).await?.unwrap();
let loaded_session = store.load_session(cookie_value.clone()).await?.unwrap();
assert_eq!(cloned.id(), loaded_session.id());
assert_eq!("value", &*loaded_session.get::<String>("key").unwrap());
assert!(!loaded_session.is_expired());
task::sleep(Duration::from_secs(3)).await;
assert_eq!(None, store.load_session(cookie_value).await?);
Ok(())
}
}