//! HTTP integration tests for query and filtering operations. //! //! Coverage: //! - GET /v1/query - Subject/predicate filtering //! - Lens parameter (Recency, Consensus, Confidence, Authority, VoteAwareConsensus) //! - Lifecycle filtering //! - Pagination (limit) //! - Response structure validation #![allow(clippy::expect_used)] mod common; use axum::{ body::Body, http::{Request, StatusCode}, }; use tower::ServiceExt; use stemedb_api::create_router; // ============================================================================ // GET /v1/query - Query Assertions Tests // ============================================================================ #[tokio::test] async fn test_query_basic_with_subject_predicate() { let env = common::create_test_env().await; let app = create_router(env.state); let request = Request::builder() .uri("/v1/query?subject=Test_Entity&predicate=test_property") .method("GET") .body(Body::empty()) .expect("Request"); let response = app.oneshot(request).await.expect("Request"); assert_eq!(response.status(), StatusCode::OK); let body = axum::body::to_bytes(response.into_body(), usize::MAX).await.expect("Body"); let json: serde_json::Value = serde_json::from_slice(&body).expect("JSON"); // Verify response structure (empty since DB is empty) assert!(json.get("assertions").is_some()); assert!(json.get("total_count").is_some()); assert!(json.get("has_more").is_some()); assert_eq!(json["assertions"], serde_json::json!([])); assert_eq!(json["total_count"], 0); } #[tokio::test] async fn test_query_with_lens_recency() { let env = common::create_test_env().await; let app = create_router(env.state); let request = Request::builder() .uri("/v1/query?subject=Test&predicate=prop&lens=Recency") .method("GET") .body(Body::empty()) .expect("Request"); let response = app.oneshot(request).await.expect("Request"); assert_eq!(response.status(), StatusCode::OK); let body = axum::body::to_bytes(response.into_body(), usize::MAX).await.expect("Body"); let json: serde_json::Value = serde_json::from_slice(&body).expect("JSON"); // When a lens is applied (even with empty results), conflict_score and // resolution_confidence should be None (empty result set) assert_eq!(json["assertions"], serde_json::json!([])); assert_eq!(json["total_count"], 0); assert!(json.get("conflict_score").is_none() || json["conflict_score"].is_null()); assert!(json.get("resolution_confidence").is_none() || json["resolution_confidence"].is_null()); } #[tokio::test] async fn test_query_lifecycle_filtering() { let env = common::create_test_env().await; let app = create_router(env.state); let request = Request::builder() .uri("/v1/query?subject=Test&lifecycle=Approved") .method("GET") .body(Body::empty()) .expect("Request"); let response = app.oneshot(request).await.expect("Request"); assert_eq!(response.status(), StatusCode::OK); let body = axum::body::to_bytes(response.into_body(), usize::MAX).await.expect("Body"); let json: serde_json::Value = serde_json::from_slice(&body).expect("JSON"); assert_eq!(json["assertions"], serde_json::json!([])); assert_eq!(json["total_count"], 0); } #[tokio::test] async fn test_query_with_limit() { let env = common::create_test_env().await; let app = create_router(env.state); let request = Request::builder() .uri("/v1/query?subject=Test&limit=10") .method("GET") .body(Body::empty()) .expect("Request"); let response = app.oneshot(request).await.expect("Request"); assert_eq!(response.status(), StatusCode::OK); let body = axum::body::to_bytes(response.into_body(), usize::MAX).await.expect("Body"); let json: serde_json::Value = serde_json::from_slice(&body).expect("JSON"); // Verify query executes successfully (limit parameter is accepted) assert!(json.get("assertions").is_some()); } #[tokio::test] async fn test_query_with_all_lenses() { let env = common::create_test_env().await; let app = create_router(env.state); // Test that all lens values are accepted let lenses = vec!["Recency", "Consensus", "Confidence", "Authority", "VoteAwareConsensus"]; for lens in lenses { let request = Request::builder() .uri(format!("/v1/query?subject=Test&predicate=prop&lens={}", lens)) .method("GET") .body(Body::empty()) .expect("Request"); let response = app.clone().oneshot(request).await.expect("Request"); assert_eq!(response.status(), StatusCode::OK, "Lens {} should be accepted", lens); } } #[tokio::test] async fn test_query_response_structure() { let env = common::create_test_env().await; let app = create_router(env.state); let request = Request::builder() .uri("/v1/query?subject=Test") .method("GET") .body(Body::empty()) .expect("Request"); let response = app.oneshot(request).await.expect("Request"); let body = axum::body::to_bytes(response.into_body(), usize::MAX).await.expect("Body"); let json: serde_json::Value = serde_json::from_slice(&body).expect("JSON"); // Verify expected fields are present assert!(json.get("assertions").is_some()); assert!(json.get("total_count").is_some()); assert!(json.get("has_more").is_some()); } #[tokio::test] async fn test_query_subject_only() { let env = common::create_test_env().await; let app = create_router(env.state); let request = Request::builder() .uri("/v1/query?subject=Entity123") .method("GET") .body(Body::empty()) .expect("Request"); let response = app.oneshot(request).await.expect("Request"); assert_eq!(response.status(), StatusCode::OK); let body = axum::body::to_bytes(response.into_body(), usize::MAX).await.expect("Body"); let json: serde_json::Value = serde_json::from_slice(&body).expect("JSON"); assert!(json.get("assertions").is_some()); } #[tokio::test] async fn test_query_predicate_only() { let env = common::create_test_env().await; let app = create_router(env.state); let request = Request::builder() .uri("/v1/query?predicate=has_property") .method("GET") .body(Body::empty()) .expect("Request"); let response = app.oneshot(request).await.expect("Request"); assert_eq!(response.status(), StatusCode::OK); let body = axum::body::to_bytes(response.into_body(), usize::MAX).await.expect("Body"); let json: serde_json::Value = serde_json::from_slice(&body).expect("JSON"); assert!(json.get("assertions").is_some()); } #[tokio::test] async fn test_query_empty_params() { let env = common::create_test_env().await; let app = create_router(env.state); let request = Request::builder().uri("/v1/query").method("GET").body(Body::empty()).expect("Request"); let response = app.oneshot(request).await.expect("Request"); assert_eq!(response.status(), StatusCode::OK); let body = axum::body::to_bytes(response.into_body(), usize::MAX).await.expect("Body"); let json: serde_json::Value = serde_json::from_slice(&body).expect("JSON"); assert!(json.get("assertions").is_some()); }