use std::sync::Arc;
use reqwest::Client;
use serde_json::{Value, json};
use rustqueue::api::{self, AppState};
use rustqueue::config::AuthConfig;
use rustqueue::engine::queue::QueueManager;
use rustqueue::storage::MemoryStorage;
async fn start_test_server_with_auth(auth_config: AuthConfig) -> String {
let (event_tx, _) = tokio::sync::broadcast::channel(1024);
let storage = Arc::new(MemoryStorage::new());
let qm = Arc::new(QueueManager::new(storage));
let state = Arc::new(AppState {
queue_manager: qm,
start_time: std::time::Instant::now(),
metrics_handle: None,
event_tx,
auth_config,
auth_rate_limiter: rustqueue::api::auth::AuthRateLimiter::new(),
webhook_manager: None,
});
let app = api::router(state);
let listener = tokio::net::TcpListener::bind("127.0.0.1:0").await.unwrap();
let addr = listener.local_addr().unwrap();
tokio::spawn(async move {
axum::serve(listener, app).await.unwrap();
});
format!("http://{addr}")
}
#[tokio::test]
async fn test_auth_disabled_allows_all() {
let base = start_test_server_with_auth(AuthConfig {
enabled: false,
tokens: vec![],
})
.await;
let client = Client::new();
let resp = client
.get(format!("{base}/api/v1/health"))
.send()
.await
.unwrap();
assert_eq!(resp.status(), 200);
let resp = client
.post(format!("{base}/api/v1/queues/test/jobs"))
.json(&json!({"name": "task", "data": {}}))
.send()
.await
.unwrap();
assert_eq!(resp.status(), 201);
}
#[tokio::test]
async fn test_auth_enabled_rejects_no_token() {
let base = start_test_server_with_auth(AuthConfig {
enabled: true,
tokens: vec!["secret-token".to_string()],
})
.await;
let client = Client::new();
let resp = client
.post(format!("{base}/api/v1/queues/test/jobs"))
.json(&json!({"name": "task", "data": {}}))
.send()
.await
.unwrap();
assert_eq!(resp.status(), 401);
let body: Value = resp.json().await.unwrap();
assert_eq!(body["ok"], false);
assert_eq!(body["error"]["code"], "UNAUTHORIZED");
assert!(
body["error"]["message"]
.as_str()
.unwrap()
.contains("Missing")
);
}
#[tokio::test]
async fn test_auth_enabled_rejects_bad_token() {
let base = start_test_server_with_auth(AuthConfig {
enabled: true,
tokens: vec!["correct-token".to_string()],
})
.await;
let client = Client::new();
let resp = client
.post(format!("{base}/api/v1/queues/test/jobs"))
.header("Authorization", "Bearer wrong-token")
.json(&json!({"name": "task", "data": {}}))
.send()
.await
.unwrap();
assert_eq!(resp.status(), 401);
let body: Value = resp.json().await.unwrap();
assert_eq!(body["ok"], false);
assert_eq!(body["error"]["code"], "UNAUTHORIZED");
assert!(
body["error"]["message"]
.as_str()
.unwrap()
.contains("Invalid")
);
}
#[tokio::test]
async fn test_auth_enabled_accepts_valid_token() {
let base = start_test_server_with_auth(AuthConfig {
enabled: true,
tokens: vec!["my-secret-token".to_string()],
})
.await;
let client = Client::new();
let resp = client
.post(format!("{base}/api/v1/queues/test/jobs"))
.header("Authorization", "Bearer my-secret-token")
.json(&json!({"name": "task", "data": {}}))
.send()
.await
.unwrap();
assert_eq!(resp.status(), 201);
let body: Value = resp.json().await.unwrap();
assert_eq!(body["ok"], true);
assert!(body["id"].is_string());
}
#[tokio::test]
async fn test_health_always_public() {
let base = start_test_server_with_auth(AuthConfig {
enabled: true,
tokens: vec!["secret".to_string()],
})
.await;
let client = Client::new();
let resp = client
.get(format!("{base}/api/v1/health"))
.send()
.await
.unwrap();
assert_eq!(resp.status(), 200);
let body: Value = resp.json().await.unwrap();
assert_eq!(body["ok"], true);
assert_eq!(body["status"], "healthy");
}
#[tokio::test]
async fn test_dashboard_returns_401_when_auth_enabled() {
let base = start_test_server_with_auth(AuthConfig {
enabled: true,
tokens: vec!["dashboard-token".to_string()],
})
.await;
let client = Client::new();
let resp = client
.get(format!("{base}/dashboard"))
.send()
.await
.unwrap();
assert_eq!(resp.status(), 401);
let body: Value = resp.json().await.unwrap();
assert_eq!(body["ok"], false);
assert_eq!(body["error"]["code"], "UNAUTHORIZED");
}
#[tokio::test]
async fn test_dashboard_accessible_with_token_when_auth_enabled() {
let base = start_test_server_with_auth(AuthConfig {
enabled: true,
tokens: vec!["dashboard-token".to_string()],
})
.await;
let client = Client::new();
let resp = client
.get(format!("{base}/dashboard"))
.header("Authorization", "Bearer dashboard-token")
.send()
.await
.unwrap();
assert_eq!(resp.status(), 200);
}