2025-10-07 10:59:52 +01:00
|
|
|
use axum::body::Body;
|
|
|
|
|
use axum::http::{Request, StatusCode};
|
2026-01-08 21:32:59 +00:00
|
|
|
use extension_registry::{build_routes, AppState, Config};
|
2026-01-17 04:01:34 +00:00
|
|
|
use extension_registry::config::OciConfig;
|
2026-01-08 21:32:59 +00:00
|
|
|
use http_body_util::BodyExt;
|
2026-01-12 04:53:31 +00:00
|
|
|
use tower::ServiceExt;
|
2025-10-07 10:59:52 +01:00
|
|
|
|
2026-01-17 04:01:34 +00:00
|
|
|
/// Create a minimal test config with a mock OCI backend
|
|
|
|
|
fn create_test_config() -> Config {
|
|
|
|
|
Config {
|
2025-10-07 10:59:52 +01:00
|
|
|
server: extension_registry::config::ServerConfig::default(),
|
|
|
|
|
gitea: None,
|
2026-01-17 04:01:34 +00:00
|
|
|
// Use OCI as test backend (doesn't require file validation for auth_token_path)
|
|
|
|
|
oci: Some(OciConfig {
|
|
|
|
|
id: Some("test-oci".to_string()),
|
|
|
|
|
registry: "localhost:5000".to_string(),
|
|
|
|
|
namespace: "test".to_string(),
|
|
|
|
|
auth_token_path: None,
|
|
|
|
|
timeout_seconds: 30,
|
|
|
|
|
verify_ssl: false,
|
|
|
|
|
}),
|
2026-01-08 21:32:59 +00:00
|
|
|
sources: extension_registry::config::SourcesConfig::default(),
|
|
|
|
|
distributions: extension_registry::config::DistributionsConfig::default(),
|
2025-10-07 10:59:52 +01:00
|
|
|
cache: extension_registry::config::CacheConfig::default(),
|
2026-01-17 04:01:34 +00:00
|
|
|
}
|
|
|
|
|
}
|
2025-10-07 10:59:52 +01:00
|
|
|
|
2026-01-17 04:01:34 +00:00
|
|
|
#[tokio::test]
|
|
|
|
|
#[ignore] // Requires OCI registry or Gitea service to be running
|
|
|
|
|
#[ignore] // Requires OCI registry service to be running
|
|
|
|
|
async fn test_health_check() {
|
|
|
|
|
let config = create_test_config();
|
2025-10-07 10:59:52 +01:00
|
|
|
let state = AppState::new(config).expect("Failed to create app state");
|
|
|
|
|
let app = build_routes(state);
|
|
|
|
|
|
|
|
|
|
let response = app
|
|
|
|
|
.oneshot(
|
|
|
|
|
Request::builder()
|
|
|
|
|
.uri("/api/v1/health")
|
|
|
|
|
.body(Body::empty())
|
|
|
|
|
.unwrap(),
|
|
|
|
|
)
|
|
|
|
|
.await
|
|
|
|
|
.unwrap();
|
|
|
|
|
|
|
|
|
|
assert_eq!(response.status(), StatusCode::OK);
|
|
|
|
|
|
2026-01-08 21:32:59 +00:00
|
|
|
let body = response.into_body().collect().await.unwrap().to_bytes();
|
2025-10-07 10:59:52 +01:00
|
|
|
let health: serde_json::Value = serde_json::from_slice(&body).unwrap();
|
|
|
|
|
|
|
|
|
|
assert!(health.get("status").is_some());
|
|
|
|
|
assert!(health.get("version").is_some());
|
|
|
|
|
assert!(health.get("uptime").is_some());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[tokio::test]
|
2026-01-17 04:01:34 +00:00
|
|
|
#[ignore] // Requires OCI registry or Gitea service to be running
|
2025-10-07 10:59:52 +01:00
|
|
|
async fn test_list_extensions_empty() {
|
2026-01-17 04:01:34 +00:00
|
|
|
let config = create_test_config();
|
2025-10-07 10:59:52 +01:00
|
|
|
let state = AppState::new(config).expect("Failed to create app state");
|
|
|
|
|
let app = build_routes(state);
|
|
|
|
|
|
|
|
|
|
let response = app
|
|
|
|
|
.oneshot(
|
|
|
|
|
Request::builder()
|
|
|
|
|
.uri("/api/v1/extensions")
|
|
|
|
|
.body(Body::empty())
|
|
|
|
|
.unwrap(),
|
|
|
|
|
)
|
|
|
|
|
.await
|
|
|
|
|
.unwrap();
|
|
|
|
|
|
|
|
|
|
assert_eq!(response.status(), StatusCode::OK);
|
|
|
|
|
|
2026-01-08 21:32:59 +00:00
|
|
|
let body = response.into_body().collect().await.unwrap().to_bytes();
|
2025-10-07 10:59:52 +01:00
|
|
|
let extensions: Vec<serde_json::Value> = serde_json::from_slice(&body).unwrap();
|
|
|
|
|
|
|
|
|
|
// Should be empty when no backends configured
|
|
|
|
|
assert_eq!(extensions.len(), 0);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[tokio::test]
|
2026-01-17 04:01:34 +00:00
|
|
|
#[ignore] // Requires OCI registry or Gitea service to be running
|
2025-10-07 10:59:52 +01:00
|
|
|
async fn test_get_nonexistent_extension() {
|
2026-01-17 04:01:34 +00:00
|
|
|
let config = create_test_config();
|
2025-10-07 10:59:52 +01:00
|
|
|
|
|
|
|
|
let state = AppState::new(config).expect("Failed to create app state");
|
|
|
|
|
let app = build_routes(state);
|
|
|
|
|
|
|
|
|
|
let response = app
|
|
|
|
|
.oneshot(
|
|
|
|
|
Request::builder()
|
|
|
|
|
.uri("/api/v1/extensions/provider/nonexistent")
|
|
|
|
|
.body(Body::empty())
|
|
|
|
|
.unwrap(),
|
|
|
|
|
)
|
|
|
|
|
.await
|
|
|
|
|
.unwrap();
|
|
|
|
|
|
|
|
|
|
assert_eq!(response.status(), StatusCode::NOT_FOUND);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[tokio::test]
|
2026-01-17 04:01:34 +00:00
|
|
|
#[ignore] // Requires OCI registry or Gitea service to be running
|
2025-10-07 10:59:52 +01:00
|
|
|
async fn test_metrics_endpoint() {
|
2026-01-17 04:01:34 +00:00
|
|
|
let config = create_test_config();
|
2025-10-07 10:59:52 +01:00
|
|
|
|
|
|
|
|
let state = AppState::new(config).expect("Failed to create app state");
|
|
|
|
|
let app = build_routes(state);
|
|
|
|
|
|
|
|
|
|
let response = app
|
|
|
|
|
.oneshot(
|
|
|
|
|
Request::builder()
|
|
|
|
|
.uri("/api/v1/metrics")
|
|
|
|
|
.body(Body::empty())
|
|
|
|
|
.unwrap(),
|
|
|
|
|
)
|
|
|
|
|
.await
|
|
|
|
|
.unwrap();
|
|
|
|
|
|
|
|
|
|
assert_eq!(response.status(), StatusCode::OK);
|
|
|
|
|
|
2026-01-08 21:32:59 +00:00
|
|
|
let body = response.into_body().collect().await.unwrap().to_bytes();
|
2025-10-07 10:59:52 +01:00
|
|
|
let metrics = String::from_utf8(body.to_vec()).unwrap();
|
|
|
|
|
|
|
|
|
|
assert!(metrics.contains("http_requests_total"));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[tokio::test]
|
2026-01-17 04:01:34 +00:00
|
|
|
#[ignore] // Requires OCI registry or Gitea service to be running
|
2025-10-07 10:59:52 +01:00
|
|
|
async fn test_cache_stats_endpoint() {
|
2026-01-17 04:01:34 +00:00
|
|
|
let config = create_test_config();
|
2025-10-07 10:59:52 +01:00
|
|
|
|
|
|
|
|
let state = AppState::new(config).expect("Failed to create app state");
|
|
|
|
|
let app = build_routes(state);
|
|
|
|
|
|
|
|
|
|
let response = app
|
|
|
|
|
.oneshot(
|
|
|
|
|
Request::builder()
|
|
|
|
|
.uri("/api/v1/cache/stats")
|
|
|
|
|
.body(Body::empty())
|
|
|
|
|
.unwrap(),
|
|
|
|
|
)
|
|
|
|
|
.await
|
|
|
|
|
.unwrap();
|
|
|
|
|
|
|
|
|
|
assert_eq!(response.status(), StatusCode::OK);
|
|
|
|
|
|
2026-01-08 21:32:59 +00:00
|
|
|
let body = response.into_body().collect().await.unwrap().to_bytes();
|
2025-10-07 10:59:52 +01:00
|
|
|
let stats: serde_json::Value = serde_json::from_slice(&body).unwrap();
|
|
|
|
|
|
|
|
|
|
assert!(stats.get("list_entries").is_some());
|
|
|
|
|
assert!(stats.get("metadata_entries").is_some());
|
|
|
|
|
assert!(stats.get("total_entries").is_some());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[tokio::test]
|
2026-01-17 04:01:34 +00:00
|
|
|
#[ignore] // Requires OCI registry or Gitea service to be running
|
2025-10-07 10:59:52 +01:00
|
|
|
async fn test_invalid_extension_type() {
|
2026-01-17 04:01:34 +00:00
|
|
|
let config = create_test_config();
|
2025-10-07 10:59:52 +01:00
|
|
|
|
|
|
|
|
let state = AppState::new(config).expect("Failed to create app state");
|
|
|
|
|
let app = build_routes(state);
|
|
|
|
|
|
|
|
|
|
let response = app
|
|
|
|
|
.oneshot(
|
|
|
|
|
Request::builder()
|
|
|
|
|
.uri("/api/v1/extensions/invalid_type/test")
|
|
|
|
|
.body(Body::empty())
|
|
|
|
|
.unwrap(),
|
|
|
|
|
)
|
|
|
|
|
.await
|
|
|
|
|
.unwrap();
|
|
|
|
|
|
|
|
|
|
assert_eq!(response.status(), StatusCode::BAD_REQUEST);
|
|
|
|
|
}
|