#![cfg(feature = "web")]
use actix_web::{test, web, App, HttpMessage, HttpRequest, HttpResponse};
use futures_util::future::{ready, FutureExt, LocalBoxFuture};
use road_runner_common::auth::{PrincipalKind, UserContext};
use road_runner_common::error::AppError;
use road_runner_common::middleware::UserContextMiddleware;
fn ctx() -> UserContext {
UserContext {
subject: "sub-1".to_string(),
principal: PrincipalKind::User,
email: None,
username: None,
roles: vec!["admin".to_string()],
scopes: vec![],
capabilities: vec![],
api_key_id: None,
acr: None,
}
}
async fn subject(req: HttpRequest) -> HttpResponse {
let subject = req.extensions().get::<UserContext>().map(|ctx| ctx.subject.clone());
match subject {
Some(subject) => HttpResponse::Ok().body(subject),
None => HttpResponse::NoContent().finish(),
}
}
#[actix_web::test]
async fn user_context_middleware_inserts_resolved_context() {
let resolver = |req| ready((req, Ok(Some(ctx())))).boxed_local();
let app = test::init_service(
App::new().wrap(UserContextMiddleware::new(resolver)).route("/", web::get().to(subject)),
)
.await;
let req = test::TestRequest::get().uri("/").to_request();
let response = test::call_service(&app, req).await;
let body = test::read_body(response).await;
assert_eq!(body, "sub-1");
}
#[actix_web::test]
async fn user_context_middleware_allows_anonymous_when_not_required() {
let resolver = |req| ready((req, Ok(None))).boxed_local();
let app = test::init_service(
App::new().wrap(UserContextMiddleware::new(resolver)).route("/", web::get().to(subject)),
)
.await;
let req = test::TestRequest::get().uri("/").to_request();
let response = test::call_service(&app, req).await;
assert_eq!(response.status(), actix_web::http::StatusCode::NO_CONTENT);
}
#[actix_web::test]
async fn user_context_middleware_rejects_missing_context_when_required() {
let resolver = |req| ready((req, Ok(None))).boxed_local();
let app = test::init_service(
App::new().wrap(UserContextMiddleware::new(resolver).required(true)).route("/", web::get().to(subject)),
)
.await;
let req = test::TestRequest::get().uri("/").to_request();
let result = test::try_call_service(&app, req).await;
assert!(result.is_err());
}
#[actix_web::test]
async fn user_context_middleware_returns_resolver_error() {
let resolver = |req| -> LocalBoxFuture<'static, _> {
ready((
req,
Err(AppError::Forbidden { message: "blocked".to_string() }),
))
.boxed_local()
};
let app = test::init_service(
App::new().wrap(UserContextMiddleware::new(resolver)).route("/", web::get().to(subject)),
)
.await;
let req = test::TestRequest::get().uri("/").to_request();
let result = test::try_call_service(&app, req).await;
assert!(result.is_err());
}