//! HTTP integration tests for gold standard endpoints. //! //! Coverage: //! - Create gold standard //! - List gold standards //! - Remove gold standard //! - Verify agent against gold standard (correct and incorrect answers) #![allow(clippy::expect_used)] mod common; use axum::{ body::Body, http::{Request, StatusCode}, }; use serde_json::json; use tower::ServiceExt; use stemedb_api::create_router; #[tokio::test] async fn test_create_and_list_gold_standards() { let env = common::create_test_env().await; let app = create_router(env.state); // Create a gold standard let create_request = json!({ "assertion_hash": "a".repeat(64), "subject": "Earth", "predicate": "has_shape", "expected_object": "oblate_spheroid", "created_by": "admin_alice" }); let request = Request::builder() .uri("/v1/admin/gold-standards") .method("POST") .header("content-type", "application/json") .body(Body::from(serde_json::to_vec(&create_request).expect("JSON"))) .expect("Request"); let response = app.clone().oneshot(request).await.expect("Request"); assert_eq!(response.status(), StatusCode::CREATED); 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["subject"], "Earth"); assert_eq!(json["predicate"], "has_shape"); assert!(json["status"].as_str().expect("status").contains("created")); // List gold standards let request = Request::builder() .uri("/v1/admin/gold-standards") .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["count"], 1); let gs = &json["gold_standards"][0]; assert_eq!(gs["subject"], "Earth"); assert_eq!(gs["predicate"], "has_shape"); assert_eq!(gs["expected_object"], "oblate_spheroid"); assert_eq!(gs["created_by"], "admin_alice"); } #[tokio::test] async fn test_remove_gold_standard() { let env = common::create_test_env().await; let app = create_router(env.state); // Create a gold standard let create_request = json!({ "assertion_hash": "a".repeat(64), "subject": "Semaglutide", "predicate": "treats_condition", "expected_object": "type_2_diabetes", "created_by": "admin" }); let request = Request::builder() .uri("/v1/admin/gold-standards") .method("POST") .header("content-type", "application/json") .body(Body::from(serde_json::to_vec(&create_request).expect("JSON"))) .expect("Request"); let response = app.clone().oneshot(request).await.expect("Request"); assert_eq!(response.status(), StatusCode::CREATED); // Remove it let request = Request::builder() .uri("/v1/admin/gold-standards/Semaglutide/treats_condition") .method("DELETE") .body(Body::empty()) .expect("Request"); let response = app.clone().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["removed"], true); // List should be empty let request = Request::builder() .uri("/v1/admin/gold-standards") .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["count"], 0); } #[tokio::test] async fn test_verify_agent_correct_answer() { let env = common::create_test_env().await; let app = create_router(env.state); // Create a gold standard let create_request = json!({ "assertion_hash": "a".repeat(64), "subject": "Earth", "predicate": "has_shape", "expected_object": "oblate_spheroid", "created_by": "admin" }); let request = Request::builder() .uri("/v1/admin/gold-standards") .method("POST") .header("content-type", "application/json") .body(Body::from(serde_json::to_vec(&create_request).expect("JSON"))) .expect("Request"); let response = app.clone().oneshot(request).await.expect("Request"); assert_eq!(response.status(), StatusCode::CREATED); // Verify agent with correct answer let verify_request = json!({ "agent_id": "1".repeat(64), "subject": "Earth", "predicate": "has_shape", "agent_object": "oblate_spheroid" }); let request = Request::builder() .uri("/v1/admin/verify-agent") .method("POST") .header("content-type", "application/json") .body(Body::from(serde_json::to_vec(&verify_request).expect("JSON"))) .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["subject"], "Earth"); assert_eq!(json["predicate"], "has_shape"); assert_eq!(json["correct"], true); assert_eq!(json["agent_answer"], "oblate_spheroid"); assert_eq!(json["expected_answer"], "oblate_spheroid"); assert_eq!(json["trust_adjustment"], 0.05); // Reward assert_eq!(json["new_trust_score"], 0.55); // 0.5 + 0.05 } #[tokio::test] async fn test_verify_agent_incorrect_answer() { let env = common::create_test_env().await; let app = create_router(env.state); // Create a gold standard let create_request = json!({ "assertion_hash": "a".repeat(64), "subject": "Earth", "predicate": "has_shape", "expected_object": "oblate_spheroid", "created_by": "admin" }); let request = Request::builder() .uri("/v1/admin/gold-standards") .method("POST") .header("content-type", "application/json") .body(Body::from(serde_json::to_vec(&create_request).expect("JSON"))) .expect("Request"); let response = app.clone().oneshot(request).await.expect("Request"); assert_eq!(response.status(), StatusCode::CREATED); // Verify agent with incorrect answer let verify_request = json!({ "agent_id": "2".repeat(64), "subject": "Earth", "predicate": "has_shape", "agent_object": "flat" }); let request = Request::builder() .uri("/v1/admin/verify-agent") .method("POST") .header("content-type", "application/json") .body(Body::from(serde_json::to_vec(&verify_request).expect("JSON"))) .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["subject"], "Earth"); assert_eq!(json["predicate"], "has_shape"); assert_eq!(json["correct"], false); assert_eq!(json["agent_answer"], "flat"); assert_eq!(json["expected_answer"], "oblate_spheroid"); assert_eq!(json["trust_adjustment"], -0.1); // Penalty assert_eq!(json["new_trust_score"], 0.4); // 0.5 - 0.1 } #[tokio::test] async fn test_verify_agent_nonexistent_gold_standard() { let env = common::create_test_env().await; let app = create_router(env.state); // Verify agent against non-existent gold standard let verify_request = json!({ "agent_id": "3".repeat(64), "subject": "NonExistent", "predicate": "predicate", "agent_object": "answer" }); let request = Request::builder() .uri("/v1/admin/verify-agent") .method("POST") .header("content-type", "application/json") .body(Body::from(serde_json::to_vec(&verify_request).expect("JSON"))) .expect("Request"); let response = app.oneshot(request).await.expect("Request"); assert_eq!(response.status(), StatusCode::NOT_FOUND); 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["error"].as_str().expect("error").contains("not found")); }