Skip to content

Commit

Permalink
Extract common code in service tests into separate functions
Browse files Browse the repository at this point in the history
  • Loading branch information
0rzech committed Aug 26, 2024
1 parent f48c6a2 commit badf0be
Showing 1 changed file with 74 additions and 147 deletions.
221 changes: 74 additions & 147 deletions src/service.rs
Original file line number Diff line number Diff line change
Expand Up @@ -544,6 +544,7 @@ mod tests {

use anyhow::anyhow;
use axum::body::Body;
use session::Record;
use tower::{ServiceBuilder, ServiceExt};
use tower_sessions_memory_store::MemoryStore;

Expand Down Expand Up @@ -640,10 +641,7 @@ mod tests {
let req = Request::builder().body(Body::empty())?;
let res = svc.oneshot(req).await?;

assert!(res
.headers()
.get(http::header::SET_COOKIE)
.is_some_and(|set_cookie| set_cookie.to_str().is_ok_and(|s| s.starts_with("my.sid="))));
assert!(cookie_value_matches(&res, |s| s.starts_with("my.sid=")));

Ok(())
}
Expand All @@ -659,10 +657,7 @@ mod tests {
let req = Request::builder().body(Body::empty())?;
let res = svc.oneshot(req).await?;

assert!(res
.headers()
.get(http::header::SET_COOKIE)
.is_some_and(|set_cookie| set_cookie.to_str().is_ok_and(|s| s.contains("HttpOnly"))));
assert!(cookie_value_matches(&res, |s| s.contains("HttpOnly")));

let session_store = MemoryStore::default();
let session_layer = SessionManagerLayer::new(session_store).with_http_only(false);
Expand All @@ -673,10 +668,7 @@ mod tests {
let req = Request::builder().body(Body::empty())?;
let res = svc.oneshot(req).await?;

assert!(res
.headers()
.get(http::header::SET_COOKIE)
.is_some_and(|set_cookie| set_cookie.to_str().is_ok_and(|s| !s.contains("HttpOnly"))));
assert!(cookie_value_matches(&res, |s| !s.contains("HttpOnly")));

Ok(())
}
Expand All @@ -693,12 +685,7 @@ mod tests {
let req = Request::builder().body(Body::empty())?;
let res = svc.oneshot(req).await?;

assert!(res
.headers()
.get(http::header::SET_COOKIE)
.is_some_and(|set_cookie| set_cookie
.to_str()
.is_ok_and(|s| s.contains("SameSite=Strict"))));
assert!(cookie_value_matches(&res, |s| s.contains("SameSite=Strict")));

let session_store = MemoryStore::default();
let session_layer = SessionManagerLayer::new(session_store).with_same_site(SameSite::Lax);
Expand All @@ -709,12 +696,7 @@ mod tests {
let req = Request::builder().body(Body::empty())?;
let res = svc.oneshot(req).await?;

assert!(res
.headers()
.get(http::header::SET_COOKIE)
.is_some_and(|set_cookie| set_cookie
.to_str()
.is_ok_and(|s| s.contains("SameSite=Lax"))));
assert!(cookie_value_matches(&res, |s| s.contains("SameSite=Lax")));

let session_store = MemoryStore::default();
let session_layer = SessionManagerLayer::new(session_store).with_same_site(SameSite::None);
Expand All @@ -725,12 +707,7 @@ mod tests {
let req = Request::builder().body(Body::empty())?;
let res = svc.oneshot(req).await?;

assert!(res
.headers()
.get(http::header::SET_COOKIE)
.is_some_and(|set_cookie| set_cookie
.to_str()
.is_ok_and(|s| s.contains("SameSite=None"))));
assert!(cookie_value_matches(&res, |s| s.contains("SameSite=None")));

Ok(())
}
Expand All @@ -747,10 +724,7 @@ mod tests {
let req = Request::builder().body(Body::empty())?;
let res = svc.oneshot(req).await?;

assert!(res
.headers()
.get(http::header::SET_COOKIE)
.is_some_and(|set_cookie| set_cookie.to_str().is_ok_and(|s| !s.contains("Max-Age"))));
assert!(cookie_value_matches(&res, |s| !s.contains("Max-Age")));

let session_store = MemoryStore::default();
let inactivity_duration = time::Duration::hours(2);
Expand All @@ -764,21 +738,7 @@ mod tests {
let res = svc.oneshot(req).await?;

let expected_max_age = inactivity_duration.whole_seconds();
assert!(res
.headers()
.get(http::header::SET_COOKIE)
.is_some_and(|set_cookie| set_cookie.to_str().is_ok_and(|s| {
let max_age_value = s
.split("Max-Age=")
.nth(1)
.unwrap_or_default()
.split(';')
.next()
.unwrap_or_default()
.parse::<i64>()
.unwrap_or_default();
(max_age_value - expected_max_age).abs() <= 1
})));
assert!(cookie_has_expected_max_age(&res, expected_max_age));

let session_store = MemoryStore::default();
let expiry_time = time::OffsetDateTime::now_utc() + time::Duration::weeks(1);
Expand All @@ -792,60 +752,13 @@ mod tests {
let res = svc.oneshot(req).await?;

let expected_max_age = (expiry_time - time::OffsetDateTime::now_utc()).whole_seconds();
assert!(res
.headers()
.get(http::header::SET_COOKIE)
.is_some_and(|set_cookie| set_cookie.to_str().is_ok_and(|s| {
let max_age_value = s
.split("Max-Age=")
.nth(1)
.unwrap_or_default()
.split(';')
.next()
.unwrap_or_default()
.parse::<i64>()
.unwrap_or_default();
(max_age_value - expected_max_age).abs() <= 1
})));
assert!(cookie_has_expected_max_age(&res, expected_max_age));

Ok(())
}

#[tokio::test]
async fn always_save_test() -> anyhow::Result<()> {
let get_session_id = |res: &Response<Body>| {
res.headers()
.get(http::header::SET_COOKIE)
.unwrap()
.to_str()
.unwrap()
.split("id=")
.nth(1)
.unwrap()
.split(";")
.next()
.unwrap()
.to_string()
};
let has_expected_max_age_value = |res: &Response<Body>, expected_value: i64| {
res.headers()
.get(http::header::SET_COOKIE)
.is_some_and(|set_cookie| {
set_cookie.to_str().is_ok_and(|s| {
let max_age_value = s
.split("Max-Age=")
.nth(1)
.unwrap_or_default()
.split(';')
.next()
.unwrap_or_default()
.parse::<i64>()
.unwrap_or_default();
(max_age_value - expected_value).abs() <= 1
})
})
};

// on-session-end expiry

let session_store = MemoryStore::default();
Expand All @@ -859,24 +772,15 @@ mod tests {
let req1 = Request::builder().body(Body::empty())?;
let res1 = svc.call(req1).await?;
let sid1 = get_session_id(&res1);
let rec1 = session_store
.load(&Id::from_str(&sid1).unwrap())
.await?
.unwrap();
let rec1 = get_record(&session_store, &sid1).await;
let req2 = Request::builder()
.header(http::header::COOKIE, &format!("id={}", sid1))
.body(Body::empty())?;
let res2 = svc.call(req2).await?;
let sid2 = get_session_id(&res2);
let rec2 = session_store
.load(&Id::from_str(&sid2).unwrap())
.await?
.unwrap();
let rec2 = get_record(&session_store, &sid2).await;

assert!(res2
.headers()
.get(http::header::SET_COOKIE)
.is_some_and(|set_cookie| set_cookie.to_str().is_ok_and(|s| !s.contains("Max-Age"))));
assert!(cookie_value_matches(&res2, |s| !s.contains("Max-Age")));
assert!(sid1 == sid2);
assert!(rec1.expiry_date < rec2.expiry_date);

Expand All @@ -894,22 +798,16 @@ mod tests {
let req1 = Request::builder().body(Body::empty())?;
let res1 = svc.call(req1).await?;
let sid1 = get_session_id(&res1);
let rec1 = session_store
.load(&Id::from_str(&sid1).unwrap())
.await?
.unwrap();
let rec1 = get_record(&session_store, &sid1).await;
let req2 = Request::builder()
.header(http::header::COOKIE, &format!("id={}", sid1))
.body(Body::empty())?;
let res2 = svc.call(req2).await?;
let sid2 = get_session_id(&res2);
let rec2 = session_store
.load(&Id::from_str(&sid2).unwrap())
.await?
.unwrap();
let rec2 = get_record(&session_store, &sid2).await;

let expected_max_age = inactivity_duration.whole_seconds();
assert!(has_expected_max_age_value(&res2, expected_max_age));
assert!(cookie_has_expected_max_age(&res2, expected_max_age));
assert!(sid1 == sid2);
assert!(rec1.expiry_date < rec2.expiry_date);

Expand All @@ -927,22 +825,16 @@ mod tests {
let req1 = Request::builder().body(Body::empty())?;
let res1 = svc.call(req1).await?;
let sid1 = get_session_id(&res1);
let rec1 = session_store
.load(&Id::from_str(&sid1).unwrap())
.await?
.unwrap();
let rec1 = get_record(&session_store, &sid1).await;
let req2 = Request::builder()
.header(http::header::COOKIE, &format!("id={}", sid1))
.body(Body::empty())?;
let res2 = svc.call(req2).await?;
let sid2 = get_session_id(&res2);
let rec2 = session_store
.load(&Id::from_str(&sid2).unwrap())
.await?
.unwrap();
let rec2 = get_record(&session_store, &sid2).await;

let expected_max_age = (expiry_time - time::OffsetDateTime::now_utc()).whole_seconds();
assert!(has_expected_max_age_value(&res2, expected_max_age));
assert!(cookie_has_expected_max_age(&res2, expected_max_age));
assert!(sid1 == sid2);
assert!(rec1.expiry_date == rec2.expiry_date);

Expand All @@ -960,10 +852,7 @@ mod tests {
let req = Request::builder().body(Body::empty())?;
let res = svc.oneshot(req).await?;

assert!(res
.headers()
.get(http::header::SET_COOKIE)
.is_some_and(|set_cookie| set_cookie.to_str().is_ok_and(|s| s.contains("Secure"))));
assert!(cookie_value_matches(&res, |s| s.contains("Secure")));

let session_store = MemoryStore::default();
let session_layer = SessionManagerLayer::new(session_store).with_secure(false);
Expand All @@ -974,10 +863,7 @@ mod tests {
let req = Request::builder().body(Body::empty())?;
let res = svc.oneshot(req).await?;

assert!(res
.headers()
.get(http::header::SET_COOKIE)
.is_some_and(|set_cookie| set_cookie.to_str().is_ok_and(|s| !s.contains("Secure"))));
assert!(cookie_value_matches(&res, |s| !s.contains("Secure")));

Ok(())
}
Expand All @@ -993,12 +879,7 @@ mod tests {
let req = Request::builder().body(Body::empty())?;
let res = svc.oneshot(req).await?;

assert!(res
.headers()
.get(http::header::SET_COOKIE)
.is_some_and(|set_cookie| set_cookie
.to_str()
.is_ok_and(|s| s.contains("Path=/foo/bar"))));
assert!(cookie_value_matches(&res, |s| s.contains("Path=/foo/bar")));

Ok(())
}
Expand All @@ -1014,12 +895,7 @@ mod tests {
let req = Request::builder().body(Body::empty())?;
let res = svc.oneshot(req).await?;

assert!(res
.headers()
.get(http::header::SET_COOKIE)
.is_some_and(|set_cookie| set_cookie
.to_str()
.is_ok_and(|s| s.contains("Domain=example.com"))));
assert!(cookie_value_matches(&res, |s| s.contains("Domain=example.com")));

Ok(())
}
Expand Down Expand Up @@ -1059,4 +935,55 @@ mod tests {

Ok(())
}

fn cookie_value_matches<F>(res: &Response<Body>, matcher: F) -> bool
where
F: FnOnce(&str) -> bool,
{
res.headers()
.get(http::header::SET_COOKIE)
.is_some_and(|set_cookie| set_cookie.to_str().is_ok_and(matcher))
}

fn cookie_has_expected_max_age(res: &Response<Body>, expected_value: i64) -> bool {
res.headers()
.get(http::header::SET_COOKIE)
.is_some_and(|set_cookie| {
set_cookie.to_str().is_ok_and(|s| {
let max_age_value = s
.split("Max-Age=")
.nth(1)
.unwrap_or_default()
.split(';')
.next()
.unwrap_or_default()
.parse::<i64>()
.unwrap_or_default();
(max_age_value - expected_value).abs() <= 1
})
})
}

fn get_session_id(res: &Response<Body>) -> String {
res.headers()
.get(http::header::SET_COOKIE)
.unwrap()
.to_str()
.unwrap()
.split("id=")
.nth(1)
.unwrap()
.split(";")
.next()
.unwrap()
.to_string()
}

async fn get_record(store: &impl SessionStore, id: &str) -> Record {
store
.load(&Id::from_str(&id).unwrap())
.await
.unwrap()
.unwrap()
}
}

0 comments on commit badf0be

Please sign in to comment.