Lines
93.65 %
Functions
100 %
Branches
use axum::{
body::Body,
http::{Request, StatusCode},
};
use tower::ServiceExt;
use crate::common::{create_test_app_state, test_limiter};
use web::route::create_api_router;
// PUBLIC API ROUTES TESTS
#[supp_macro::shared_runtime_test]
async fn test_public_routes_accessible() {
let app_state = create_test_app_state().await;
let app = create_api_router(app_state.clone(), test_limiter()).with_state(app_state);
// Test version endpoint
let response = app
.clone()
.oneshot(
Request::builder()
.uri("/version")
.body(Body::empty())
.unwrap(),
)
.await
.unwrap();
assert_eq!(response.status(), StatusCode::OK);
// Test logout endpoint (requires auth, so expect 401/403)
.uri("/auth/logout")
// Logout requires authentication, so should return 401 or 403
assert!(
response.status() == StatusCode::UNAUTHORIZED || response.status() == StatusCode::FORBIDDEN
);
}
async fn test_protected_routes_require_auth() {
let protected_routes = vec!["/auth/refresh"];
for route in protected_routes {
.method("GET")
.uri(route)
response.status() == StatusCode::UNAUTHORIZED
|| response.status() == StatusCode::FORBIDDEN
|| response.status().is_server_error(),
"Route {} should require authentication, got status: {}",
route,
response.status()
/// The password endpoint must sit behind `auth`. It is the second endpoint in
/// the app that verifies a password, so an unauthenticated caller reaching it
/// would be an unthrottled credential oracle on someone else's account.
async fn test_password_change_requires_auth() {
.method("POST")
.uri("/auth/password")
.header("content-type", "application/json")
.body(Body::from(r#"{"current_password":"a","new_password":"b"}"#))
response.status() == StatusCode::UNAUTHORIZED || response.status() == StatusCode::FORBIDDEN,
"unauthenticated password change must be refused, got: {}",