Break monolith source files into focused modules: - stemedb-core/types.rs → types/ directory (assertion, source, gold_standard, etc.) - stemedb-storage: audit_store, quota_store, trust_rank_store, vector_index, vote_store → module directories - stemedb-ingest/worker.rs → worker/ with separate test modules - stemedb-query: engine, materializer, query → module directories - stemedb-lens: epoch_aware, skeptic → module directories - stemedb-sim/lib.rs → agent, arenas/, helpers, runner, strategy, types - stemedb-api/tests: integration_tests → http_basic, http_validation, http_epoch, http_pipeline - stemedb-api/tests: e2e_flow_test → e2e_full_pipeline, e2e_lens_resolution - stemedb-query/tests: e2e_pipeline → e2e_pipeline + e2e_decay Also adds new features: gold standard verification, escalation handlers, admin endpoints, concept hierarchy spec, arena roadmap, and Go SDK. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
261 lines
8.8 KiB
Rust
261 lines
8.8 KiB
Rust
//! 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"));
|
|
}
|