Skip to content

Commit 7d2de51

Browse files
committed
Refactor OIDC test utilities
This commit introduces a macro for handling requests with cookies, simplifying the OIDC test flow. It also removes redundant session management functions, enhancing code clarity and maintainability. The setup function for OIDC tests is updated to improve readability and streamline the initialization process.
1 parent 0139171 commit 7d2de51

File tree

1 file changed

+70
-105
lines changed

1 file changed

+70
-105
lines changed

tests/oidc/mod.rs

Lines changed: 70 additions & 105 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,5 @@
1-
use actix_http::Request;
21
use actix_web::{
3-
body::MessageBody,
42
cookie::Cookie,
5-
dev::{Service, ServiceResponse},
63
http::{header, StatusCode},
74
test,
85
web::{self, Data},
@@ -12,7 +9,7 @@ use base64::Engine;
129
use openidconnect::url::Url;
1310
use serde::{Deserialize, Serialize};
1411
use serde_json::json;
15-
use sqlpage::{webserver::http::create_app, AppState};
12+
use sqlpage::webserver::http::create_app;
1613
use std::collections::HashMap;
1714
use std::sync::{Arc, Mutex};
1815
use tokio::sync::oneshot;
@@ -251,29 +248,6 @@ impl FakeOidcProvider {
251248
}
252249
}
253250

254-
async fn make_request_with_session<S, B>(
255-
app: &S,
256-
mut req: test::TestRequest,
257-
cookies: &mut Vec<Cookie<'static>>,
258-
) -> ServiceResponse<B>
259-
where
260-
S: Service<Request, Response = ServiceResponse<B>, Error = actix_web::Error>,
261-
B: MessageBody,
262-
{
263-
for cookie in cookies.iter() {
264-
req = req.cookie(cookie.clone());
265-
}
266-
let resp = test::call_service(app, req.to_request()).await;
267-
268-
for new_cookie in extract_set_cookies(resp.headers()) {
269-
cookies.retain(|c| c.name() != new_cookie.name());
270-
if !new_cookie.value().is_empty() {
271-
cookies.push(new_cookie);
272-
}
273-
}
274-
resp
275-
}
276-
277251
fn get_query_param(url: &Url, name: &str) -> String {
278252
url.query_pairs()
279253
.find(|(k, _)| k == name)
@@ -282,10 +256,33 @@ fn get_query_param(url: &Url, name: &str) -> String {
282256
.to_string()
283257
}
284258

285-
async fn setup_oidc_test_state(
259+
macro_rules! request_with_cookies {
260+
($app:expr, $req:expr, $cookies:expr) => {{
261+
let mut req = $req;
262+
for cookie in $cookies.iter() {
263+
req = req.cookie(cookie.clone());
264+
}
265+
let resp = test::call_service(&$app, req.to_request()).await;
266+
for new_cookie in extract_set_cookies(resp.headers()) {
267+
$cookies.retain(|c: &Cookie| c.name() != new_cookie.name());
268+
if !new_cookie.value().is_empty() {
269+
$cookies.push(new_cookie);
270+
}
271+
}
272+
resp
273+
}};
274+
}
275+
276+
async fn setup_oidc_test(
286277
provider_mutator: impl FnOnce(&mut ProviderState),
287-
) -> (Data<AppState>, FakeOidcProvider) {
288-
use actix_web::web::Data;
278+
) -> (
279+
impl actix_web::dev::Service<
280+
actix_http::Request,
281+
Response = actix_web::dev::ServiceResponse<impl actix_web::body::MessageBody>,
282+
Error = actix_web::Error,
283+
>,
284+
FakeOidcProvider,
285+
) {
289286
use sqlpage::{
290287
app_config::{test_database_url, AppConfig},
291288
AppState,
@@ -316,74 +313,8 @@ async fn setup_oidc_test_state(
316313

317314
let config: AppConfig = serde_json::from_str(&config_json).unwrap();
318315
let app_state = AppState::init(&config).await.unwrap();
319-
let app_data = Data::new(app_state);
320-
(app_data, provider)
321-
}
322-
323-
async fn perform_oidc_callback<S, B>(
324-
app: &S,
325-
provider: &FakeOidcProvider,
326-
protected_path: &str,
327-
state_override: Option<String>,
328-
) -> (ServiceResponse<B>, Vec<Cookie<'static>>)
329-
where
330-
S: Service<Request, Response = ServiceResponse<B>, Error = actix_web::Error>,
331-
B: MessageBody,
332-
{
333-
let mut cookies: Vec<Cookie<'static>> = Vec::new();
334-
335-
let req = test::TestRequest::get().uri(protected_path);
336-
let resp = make_request_with_session(app, req, &mut cookies).await;
337-
assert_eq!(resp.status(), StatusCode::SEE_OTHER);
338-
339-
let location = resp.headers().get("location").unwrap().to_str().unwrap();
340-
let auth_url = Url::parse(location).unwrap();
341-
342-
let state = get_query_param(&auth_url, "state");
343-
let nonce = get_query_param(&auth_url, "nonce");
344-
let redirect_uri = get_query_param(&auth_url, "redirect_uri");
345-
346-
provider.store_auth_code("test_auth_code".to_string(), nonce);
347-
348-
let callback_state = state_override.unwrap_or(state);
349-
let callback_url = format!(
350-
"{}?code=test_auth_code&state={}",
351-
redirect_uri, callback_state
352-
);
353-
let parsed_callback_url = Url::parse(&callback_url).unwrap();
354-
let callback_req = test::TestRequest::get().uri(&format!(
355-
"{}?{}",
356-
parsed_callback_url.path(),
357-
parsed_callback_url.query().unwrap_or_default()
358-
));
359-
let callback_resp = make_request_with_session(app, callback_req, &mut cookies).await;
360-
(callback_resp, cookies)
361-
}
362-
363-
async fn simulate_oidc_login<S, B>(
364-
app: &S,
365-
provider: &FakeOidcProvider,
366-
protected_path: &str,
367-
) -> ServiceResponse<B>
368-
where
369-
S: Service<Request, Response = ServiceResponse<B>, Error = actix_web::Error>,
370-
B: MessageBody,
371-
{
372-
use actix_web::{http::StatusCode, test};
373-
374-
let (callback_resp, mut cookies) =
375-
perform_oidc_callback(app, provider, protected_path, None).await;
376-
assert_eq!(callback_resp.status(), StatusCode::SEE_OTHER);
377-
378-
let final_location = callback_resp
379-
.headers()
380-
.get("location")
381-
.unwrap()
382-
.to_str()
383-
.unwrap();
384-
assert_eq!(final_location, protected_path);
385-
let final_req = test::TestRequest::get().uri(final_location);
386-
make_request_with_session(app, final_req, &mut cookies).await
316+
let app = test::init_service(create_app(Data::new(app_state))).await;
317+
(app, provider)
387318
}
388319

389320
#[actix_web::test]
@@ -411,21 +342,55 @@ async fn test_fake_provider_discovery() {
411342

412343
#[actix_web::test]
413344
async fn test_oidc_happy_path() {
414-
let (app_data, provider) = setup_oidc_test_state(|_| {}).await;
415-
let app = actix_web::test::init_service(create_app(app_data.clone())).await;
416-
let final_resp = simulate_oidc_login(&app, &provider, "/").await;
345+
let (app, provider) = setup_oidc_test(|_| {}).await;
346+
let mut cookies: Vec<Cookie<'static>> = Vec::new();
347+
348+
let resp = request_with_cookies!(app, test::TestRequest::get().uri("/"), cookies);
349+
assert_eq!(resp.status(), StatusCode::SEE_OTHER);
350+
let auth_url = Url::parse(resp.headers().get("location").unwrap().to_str().unwrap()).unwrap();
351+
352+
let state = get_query_param(&auth_url, "state");
353+
let nonce = get_query_param(&auth_url, "nonce");
354+
let redirect_uri = get_query_param(&auth_url, "redirect_uri");
355+
provider.store_auth_code("test_auth_code".to_string(), nonce);
356+
357+
let callback_uri = format!(
358+
"{}?code=test_auth_code&state={}",
359+
Url::parse(&redirect_uri).unwrap().path(),
360+
state
361+
);
362+
let callback_resp =
363+
request_with_cookies!(app, test::TestRequest::get().uri(&callback_uri), cookies);
364+
assert_eq!(callback_resp.status(), StatusCode::SEE_OTHER);
365+
366+
let final_resp = request_with_cookies!(app, test::TestRequest::get().uri("/"), cookies);
417367
assert_eq!(final_resp.status(), StatusCode::OK);
418368
}
419369

420370
async fn assert_oidc_login_fails(
421371
provider_mutator: impl FnOnce(&mut ProviderState),
422372
state_override: Option<String>,
423373
) {
424-
let (app_data, provider) = setup_oidc_test_state(provider_mutator).await;
425-
let app = actix_web::test::init_service(create_app(app_data.clone())).await;
374+
let (app, provider) = setup_oidc_test(provider_mutator).await;
375+
let mut cookies: Vec<Cookie<'static>> = Vec::new();
376+
377+
let resp = request_with_cookies!(app, test::TestRequest::get().uri("/"), cookies);
378+
assert_eq!(resp.status(), StatusCode::SEE_OTHER);
379+
let auth_url = Url::parse(resp.headers().get("location").unwrap().to_str().unwrap()).unwrap();
426380

427-
let (callback_resp, cookies) =
428-
perform_oidc_callback(&app, &provider, "/", state_override).await;
381+
let state = get_query_param(&auth_url, "state");
382+
let nonce = get_query_param(&auth_url, "nonce");
383+
let redirect_uri = get_query_param(&auth_url, "redirect_uri");
384+
provider.store_auth_code("test_auth_code".to_string(), nonce);
385+
386+
let callback_state = state_override.unwrap_or(state);
387+
let callback_uri = format!(
388+
"{}?code=test_auth_code&state={}",
389+
Url::parse(&redirect_uri).unwrap().path(),
390+
callback_state
391+
);
392+
let callback_resp =
393+
request_with_cookies!(app, test::TestRequest::get().uri(&callback_uri), cookies);
429394

430395
assert_eq!(callback_resp.status(), StatusCode::SEE_OTHER);
431396
let location = callback_resp

0 commit comments

Comments
 (0)