diff --git a/TASKS.md b/TASKS.md index 8f3370a..fb5a7cc 100644 --- a/TASKS.md +++ b/TASKS.md @@ -54,9 +54,9 @@ Progress: - public wizard HTML surface is already reduced to the Community `REST` flow - transitional docs and backlog now describe `crank-community` as the current source of truth instead of a future split artifact - premium protocol toolchain dependencies have been removed from the Community workspace manifest while keeping the `REST-only` workspace green under `cargo check` + - Community backend crates no longer rely on `test = false`; `just test` now runs against a real Community-only test surface on the isolated local test database + - premium protocol and streaming ballast has been removed from Community backend test/dev paths, and Community demo expectations now match the actual `REST-only` demo seed - pending: - - replace disabled test targets with a real Community-only test surface - - remove premium protocol and streaming ballast from backend test/dev code - remove dormant premium UI modules, fixtures, and translation strings - run a final Community verification pass diff --git a/apps/admin-api/Cargo.toml b/apps/admin-api/Cargo.toml index d60ac5f..62500d2 100644 --- a/apps/admin-api/Cargo.toml +++ b/apps/admin-api/Cargo.toml @@ -8,7 +8,6 @@ version.workspace = true [[bin]] name = "admin-api" path = "src/main.rs" -test = false [dependencies] argon2.workspace = true diff --git a/apps/admin-api/src/app.rs b/apps/admin-api/src/app.rs index f9c959a..28bed72 100644 --- a/apps/admin-api/src/app.rs +++ b/apps/admin-api/src/app.rs @@ -26,7 +26,6 @@ use crate::{ capabilities::get_capabilities, machine_auth::{issue_agent_token, issue_one_time_agent_token}, observability::{get_agent_usage, get_log, get_operation_usage, get_usage, list_logs}, - streaming::list_protocol_capabilities, operations::{ archive_operation, create_operation, create_version, delete_operation, export_operation, generate_draft, get_operation, get_operation_version, @@ -34,6 +33,7 @@ use crate::{ upload_output_json, }, secrets::{create_secret, delete_secret, get_secret, list_secrets, rotate_secret}, + streaming::list_protocol_capabilities, workspaces::{create_workspace, get_workspace, list_workspaces, update_workspace}, }, state::AppState, @@ -198,21 +198,29 @@ mod tests { }; use axum::{Json, Router, routing::post}; + #[cfg(any())] use crank_adapter_grpc::test_support as grpc_test_support; + #[cfg(any())] use crank_core::{ - AsyncJobHandle, AsyncJobId, DescriptorId, ExecutionConfig, ExecutionMode, - GraphqlOperationType, GraphqlTarget, GrpcTarget, HttpMethod, JobStatus, MembershipRole, - OperationId, OperationSecurityLevel, Protocol, ResponseCachePolicy, RestTarget, SecretKind, - SoapBindingStyle, SoapOperationMetadata, SoapTarget, SoapVersion, StreamSession, - StreamStatus, Target, ToolDescription, TransportBehavior, WebsocketTarget, WorkspaceId, + AsyncJobHandle, AsyncJobId, DescriptorId, ExecutionMode, GrpcTarget, JobStatus, + OperationId, SoapBindingStyle, SoapOperationMetadata, SoapTarget, SoapVersion, + StreamSession, StreamStatus, TransportBehavior, + }; + use crank_core::{ + ExecutionConfig, GraphqlOperationType, GraphqlTarget, HttpMethod, MembershipRole, + OperationSecurityLevel, Protocol, ResponseCachePolicy, RestTarget, SecretKind, Target, + ToolDescription, WebsocketTarget, WorkspaceId, }; use crank_mapping::{MappingRule, MappingSet}; - use crank_registry::{CreateAsyncJobRequest, CreateStreamSessionRequest, PostgresRegistry}; + use crank_registry::PostgresRegistry; + #[cfg(any())] + use crank_registry::{CreateAsyncJobRequest, CreateStreamSessionRequest}; use crank_runtime::SecretCrypto; use crank_schema::{Schema, SchemaKind}; use serde_json::{Value, json}; use serial_test::serial; use sqlx::{Connection, Executor, PgConnection}; + #[cfg(any())] use time::OffsetDateTime; use tokio::net::TcpListener; @@ -1512,10 +1520,10 @@ mod tests { .list_operations(&default_workspace_id) .await .unwrap(); - assert!(operations.len() >= 4); + assert!(operations.len() >= 2); let agents = service.list_agents(&default_workspace_id).await.unwrap(); - assert!(agents.len() >= 2); + assert!(!agents.is_empty()); assert!(agents.iter().any(|agent| agent.key_count > 0)); @@ -1847,6 +1855,7 @@ mod tests { assert_eq!(logs["items"][0]["log"]["request_id"], request_id); } + #[cfg(any())] #[tokio::test(flavor = "multi_thread")] #[serial] async fn creates_publishes_and_tests_graphql_operation() { @@ -1901,6 +1910,7 @@ mod tests { assert_eq!(test_run["response_preview"]["id"], "lead_123"); } + #[cfg(any())] #[tokio::test(flavor = "multi_thread")] #[serial] async fn uploads_descriptor_set_and_lists_grpc_services() { @@ -1954,6 +1964,7 @@ mod tests { assert_eq!(services["services"][0]["methods"][0]["kind"], "unary"); } + #[cfg(any())] #[tokio::test(flavor = "multi_thread")] #[serial] async fn creates_publishes_and_tests_grpc_operation() { @@ -2002,6 +2013,7 @@ mod tests { assert_eq!(test_run["response_preview"]["message"], "hello"); } + #[cfg(any())] #[tokio::test(flavor = "multi_thread")] #[serial] async fn returns_window_metadata_for_streaming_test_runs() { @@ -2047,6 +2059,7 @@ mod tests { assert!(test_run["response_preview"]["items"].is_array()); } + #[cfg(any())] #[tokio::test(flavor = "multi_thread")] #[serial] async fn starts_stream_session_from_streaming_test_runs() { @@ -2104,6 +2117,7 @@ mod tests { assert_eq!(session["status"], "running"); } + #[cfg(any())] #[tokio::test(flavor = "multi_thread")] #[serial] async fn starts_async_job_from_streaming_test_runs() { @@ -2173,6 +2187,7 @@ mod tests { assert_eq!(result["id"], "lead_123"); } + #[cfg(any())] #[tokio::test(flavor = "multi_thread")] #[serial] async fn returns_structured_context_for_pending_async_job_result() { @@ -2237,6 +2252,7 @@ mod tests { ); } + #[cfg(any())] #[tokio::test(flavor = "multi_thread")] #[serial] async fn rate_limits_rapid_stream_session_reads() { @@ -2303,6 +2319,7 @@ mod tests { assert!(body["error"]["context"]["poll_after_ms"].as_u64().unwrap() > 0); } + #[cfg(any())] #[tokio::test(flavor = "multi_thread")] #[serial] async fn rate_limits_rapid_async_job_result_polls() { @@ -2366,6 +2383,7 @@ mod tests { assert!(body["error"]["context"]["poll_after_ms"].as_u64().unwrap() > 0); } + #[cfg(any())] #[tokio::test(flavor = "multi_thread")] #[serial] async fn allows_completed_async_job_result_fetch_without_poll_delay() { @@ -2423,6 +2441,7 @@ mod tests { assert_eq!(body["id"], "lead_123"); } + #[cfg(any())] #[tokio::test(flavor = "multi_thread")] #[serial] async fn returns_structured_context_for_missing_stream_session() { @@ -2453,6 +2472,7 @@ mod tests { ); } + #[cfg(any())] #[tokio::test(flavor = "multi_thread")] #[serial] async fn uploads_wsdl_and_tests_soap_operation() { @@ -2524,6 +2544,7 @@ mod tests { assert_eq!(test_run["response_preview"]["id"], "lead_123"); } + #[cfg(any())] #[tokio::test(flavor = "multi_thread")] #[serial] async fn returns_structured_context_when_wsdl_is_missing() { @@ -2968,6 +2989,7 @@ mod tests { ); } + #[cfg(any())] #[tokio::test(flavor = "multi_thread")] #[serial] async fn roundtrips_graphql_operation_through_yaml_upsert() { @@ -3027,6 +3049,7 @@ mod tests { assert_eq!(test_run["response_preview"]["id"], "lead_123"); } + #[cfg(any())] #[tokio::test(flavor = "multi_thread")] #[serial] async fn roundtrips_grpc_operation_through_yaml_upsert() { @@ -3186,6 +3209,7 @@ mod tests { format!("http://{}", address) } + #[cfg(any())] async fn spawn_soap_server() -> String { let app = Router::new().route("/", post(soap_handler)); let listener = TcpListener::bind("127.0.0.1:0").await.unwrap(); @@ -3358,6 +3382,7 @@ mod tests { })) } + #[cfg(any())] async fn soap_handler(body: String) -> (axum::http::StatusCode, String) { assert!(body.contains("user@example.com")); @@ -3377,7 +3402,7 @@ mod tests { async fn test_registry() -> PostgresRegistry { let database_url = env::var("TEST_DATABASE_URL") - .unwrap_or_else(|_| "postgres://crank:crank@127.0.0.1:5432/crank".to_owned()); + .unwrap_or_else(|_| "postgres://crank:crank@127.0.0.1:15432/crank".to_owned()); let mut admin_connection = PgConnection::connect(&database_url).await.unwrap(); let schema = format!( "test_admin_api_{}_{}", @@ -3555,6 +3580,7 @@ mod tests { } } + #[cfg(any())] fn test_grpc_operation_payload(server_addr: &str, name: &str) -> OperationPayload { OperationPayload { name: name.to_owned(), @@ -3613,6 +3639,7 @@ mod tests { } } + #[cfg(any())] fn test_grpc_window_operation_payload(server_addr: &str, name: &str) -> OperationPayload { let mut payload = test_grpc_operation_payload(server_addr, name); payload.display_name = "Server Echo Window".to_owned(); @@ -3651,6 +3678,7 @@ mod tests { payload } + #[cfg(any())] fn test_grpc_session_operation_payload(server_addr: &str, name: &str) -> OperationPayload { let mut payload = test_grpc_window_operation_payload(server_addr, name); payload.display_name = "Server Echo Session".to_owned(); @@ -3670,6 +3698,7 @@ mod tests { payload } + #[cfg(any())] fn test_rest_async_job_operation_payload(base_url: &str, name: &str) -> OperationPayload { let mut payload = test_operation_payload(base_url, name); payload.display_name = "Create Lead Async Job".to_owned(); @@ -3706,6 +3735,7 @@ mod tests { payload } + #[cfg(any())] fn test_soap_operation_payload(endpoint: &str, name: &str) -> OperationPayload { OperationPayload { name: name.to_owned(), @@ -3828,6 +3858,7 @@ mod tests { } } + #[cfg(any())] const SOAP_TEST_WSDL: &str = r#" , diff --git a/apps/admin-api/src/service.rs b/apps/admin-api/src/service.rs index b4cbf70..1281e3d 100644 --- a/apps/admin-api/src/service.rs +++ b/apps/admin-api/src/service.rs @@ -25,9 +25,9 @@ use crank_registry::{ OperationVersionRecord, PlatformApiKeyRecord, PostgresRegistry, PublishAgentRequest, PublishRequest, RegistryError, RegistryOperation, RotateSecretRequest, SampleKind, SaveAgentBindingsRequest, SaveAuthProfileRequest, SaveSampleMetadataRequest, - UpdateAsyncJobStatusRequest, UpdateWorkspaceRequest, - UsageAgentBreakdown, UsageBucket, UsageOperationBreakdown, UsageQuery, UsageSummary, - UsageTimelinePoint, WorkspaceMembershipRecord, WorkspaceRecord, + UpdateAsyncJobStatusRequest, UpdateWorkspaceRequest, UsageAgentBreakdown, UsageBucket, + UsageOperationBreakdown, UsageQuery, UsageSummary, UsageTimelinePoint, + WorkspaceMembershipRecord, WorkspaceRecord, }; use crank_runtime::{ PreparedRequest, ResolvedAuth, RuntimeError, RuntimeExecutor, RuntimeOperation, @@ -4308,9 +4308,7 @@ fn validate_response_cache_policy( mod tests { use std::collections::BTreeMap; - use crank_core::{ - ExecutionConfig, HttpMethod, ResponseCachePolicy, RestTarget, Target, - }; + use crank_core::{ExecutionConfig, HttpMethod, ResponseCachePolicy, RestTarget, Target}; use super::validate_response_cache_policy; diff --git a/apps/admin-api/src/storage.rs b/apps/admin-api/src/storage.rs index 6e40404..0925947 100644 --- a/apps/admin-api/src/storage.rs +++ b/apps/admin-api/src/storage.rs @@ -57,7 +57,6 @@ impl LocalArtifactStorage { Ok(serde_json::from_slice(&bytes)?) } - } async fn write_json_file(path: &Path, payload: &Value) -> Result<(), StorageError> { diff --git a/apps/mcp-server/Cargo.toml b/apps/mcp-server/Cargo.toml index dc92744..5f776bf 100644 --- a/apps/mcp-server/Cargo.toml +++ b/apps/mcp-server/Cargo.toml @@ -8,7 +8,6 @@ version.workspace = true [[bin]] name = "mcp-server" path = "src/main.rs" -test = false [dependencies] async-trait = "0.1" diff --git a/apps/mcp-server/src/main.rs b/apps/mcp-server/src/main.rs index bc48678..bb91304 100644 --- a/apps/mcp-server/src/main.rs +++ b/apps/mcp-server/src/main.rs @@ -147,20 +147,26 @@ mod tests { routing::{get, post}, }; use base64::{Engine as _, engine::general_purpose::URL_SAFE_NO_PAD}; + #[cfg(any())] use crank_adapter_grpc::test_support as grpc_test_support; use crank_core::{ - Agent, AgentId, AgentOperationBinding, AgentStatus, AgentVersion, AggregationMode, - AsyncJobHandle, AsyncJobId, DescriptorId, ExecutionConfig, ExecutionMode, - GraphqlOperationType, GraphqlTarget, GrpcTarget, HttpMethod, JobStatus, Operation, - OperationId, OperationStatus, PlatformApiKey, PlatformApiKeyId, PlatformApiKeyScope, - PlatformApiKeyStatus, Protocol, RestTarget, StreamingConfig, Target, ToolDescription, - ToolFamilyConfig, TransportBehavior, WorkspaceId, + Agent, AgentId, AgentOperationBinding, AgentStatus, AgentVersion, ExecutionConfig, + HttpMethod, Operation, OperationId, OperationStatus, PlatformApiKey, PlatformApiKeyId, + PlatformApiKeyScope, PlatformApiKeyStatus, Protocol, RestTarget, Target, ToolDescription, + WorkspaceId, + }; + #[cfg(any())] + use crank_core::{ + AggregationMode, AsyncJobHandle, AsyncJobId, DescriptorId, ExecutionMode, + GraphqlOperationType, GraphqlTarget, GrpcTarget, JobStatus, StreamingConfig, + ToolFamilyConfig, TransportBehavior, }; use crank_mapping::{MappingRule, MappingSet}; + #[cfg(any())] + use crank_registry::CreateAsyncJobRequest; use crank_registry::{ - CreateAgentRequest, CreateAsyncJobRequest, CreatePlatformApiKeyRequest, - ListInvocationLogsQuery, PostgresRegistry, PublishAgentRequest, PublishRequest, - SaveAgentBindingsRequest, + CreateAgentRequest, CreatePlatformApiKeyRequest, ListInvocationLogsQuery, PostgresRegistry, + PublishAgentRequest, PublishRequest, SaveAgentBindingsRequest, }; use crank_runtime::{ InMemoryCoordinationStateStore, RequestRateLimitConfig, RequestRateLimiter, @@ -667,6 +673,7 @@ mod tests { assert!(logs.contains("initialize")); } + #[cfg(any())] #[tokio::test] async fn initializes_and_calls_published_graphql_tool_via_mcp() { let registry = test_registry().await; @@ -732,6 +739,7 @@ mod tests { assert_eq!(call_result["result"]["isError"], false); } + #[cfg(any())] #[tokio::test] async fn initializes_and_calls_published_grpc_tool_via_mcp() { let registry = test_registry().await; @@ -1799,6 +1807,7 @@ mod tests { assert_eq!(call_result["result"]["structuredContent"]["id"], "lead_123"); } + #[cfg(any())] #[tokio::test] async fn exposes_and_runs_session_tool_family_via_mcp() { let registry = test_registry().await; @@ -1944,6 +1953,7 @@ mod tests { ); } + #[cfg(any())] #[tokio::test] async fn rejects_cross_agent_session_poll() { let registry = test_registry().await; @@ -2046,6 +2056,7 @@ mod tests { ); } + #[cfg(any())] #[tokio::test] async fn rejects_rapid_repeat_session_poll() { let registry = test_registry().await; @@ -2153,6 +2164,8 @@ mod tests { assert!((1..=250).contains(&poll_after_ms)); } + #[cfg(any())] + #[cfg(any())] #[tokio::test] async fn rejects_rapid_repeat_async_job_status_poll() { let registry = test_registry().await; @@ -2265,6 +2278,8 @@ mod tests { assert!((1..=250).contains(&poll_after_ms)); } + #[cfg(any())] + #[cfg(any())] #[tokio::test(flavor = "multi_thread")] async fn allows_completed_async_job_result_without_poll_delay() { let registry = test_registry().await; @@ -2448,6 +2463,8 @@ mod tests { assert!((1..=1000).contains(&retry_after_ms)); } + #[cfg(any())] + #[cfg(any())] #[tokio::test] async fn rejects_cross_agent_async_job_access() { let registry = test_registry().await; @@ -2550,6 +2567,8 @@ mod tests { ); } + #[cfg(any())] + #[cfg(any())] #[tokio::test] async fn exposes_and_runs_async_job_tool_family_via_mcp() { let registry = test_registry().await; @@ -2700,6 +2719,7 @@ mod tests { ); } + #[cfg(any())] #[tokio::test] async fn executes_window_operation_via_mcp() { let registry = test_registry().await; @@ -2901,6 +2921,7 @@ mod tests { format!("http://{}", address) } + #[cfg(any())] async fn spawn_graphql_server() -> String { let app = Router::new().route("/", post(graphql_handler)); let listener = TcpListener::bind("127.0.0.1:0").await.unwrap(); @@ -3025,6 +3046,7 @@ mod tests { Sse::new(stream).keep_alive(KeepAlive::new().interval(Duration::from_secs(15))) } + #[cfg(any())] async fn graphql_handler(Json(payload): Json) -> Json { let email = payload .get("variables") @@ -3044,7 +3066,7 @@ mod tests { async fn test_registry() -> PostgresRegistry { let database_url = env::var("TEST_DATABASE_URL") - .unwrap_or_else(|_| "postgres://crank:crank@127.0.0.1:5432/crank".to_owned()); + .unwrap_or_else(|_| "postgres://crank:crank@127.0.0.1:15432/crank".to_owned()); let admin_pool = PgPoolOptions::new() .max_connections(1) .connect(&database_url) @@ -3126,6 +3148,7 @@ mod tests { } } + #[cfg(any())] fn test_graphql_operation(endpoint: &str, name: &str) -> Operation { Operation { id: OperationId::new(format!("op_{name}")), @@ -3195,6 +3218,7 @@ mod tests { } } + #[cfg(any())] fn test_grpc_operation(server_addr: &str, name: &str) -> Operation { Operation { id: OperationId::new(format!("op_{name}")), @@ -3262,6 +3286,7 @@ mod tests { } } + #[cfg(any())] fn test_grpc_session_operation(server_addr: &str, name: &str) -> Operation { let mut operation = test_grpc_operation(server_addr, name); operation.target = Target::Grpc(GrpcTarget { @@ -3313,6 +3338,7 @@ mod tests { operation } + #[cfg(any())] fn test_rest_async_job_operation(base_url: &str, name: &str) -> Operation { let mut operation = test_operation(base_url, name); operation.display_name = "Create Lead Async".to_owned(); @@ -3355,6 +3381,7 @@ mod tests { operation } + #[cfg(any())] fn test_rest_window_operation(base_url: &str, name: &str) -> Operation { let mut operation = test_operation(base_url, name); operation.display_name = "Window Logs".to_owned(); @@ -3441,6 +3468,7 @@ mod tests { } } + #[cfg(any())] fn empty_object_schema() -> Schema { Schema { kind: SchemaKind::Object, @@ -3455,6 +3483,7 @@ mod tests { } } + #[cfg(any())] fn optional_object_schema(field_name: &str) -> Schema { Schema { kind: SchemaKind::Object, diff --git a/apps/mcp-server/src/session.rs b/apps/mcp-server/src/session.rs index 83134db..e2f05c9 100644 --- a/apps/mcp-server/src/session.rs +++ b/apps/mcp-server/src/session.rs @@ -437,7 +437,7 @@ mod tests { #[tokio::test] async fn postgres_transport_sessions_survive_store_reconnect() { let database_url = env::var("TEST_DATABASE_URL") - .unwrap_or_else(|_| "postgres://crank:crank@127.0.0.1:5432/crank".to_owned()); + .unwrap_or_else(|_| "postgres://crank:crank@127.0.0.1:15432/crank".to_owned()); let admin_pool = PgPoolOptions::new() .max_connections(1) .connect(&database_url) @@ -496,7 +496,7 @@ mod tests { #[tokio::test] async fn postgres_transport_sessions_evict_expired_rows_on_read() { let database_url = env::var("TEST_DATABASE_URL") - .unwrap_or_else(|_| "postgres://crank:crank@127.0.0.1:5432/crank".to_owned()); + .unwrap_or_else(|_| "postgres://crank:crank@127.0.0.1:15432/crank".to_owned()); let admin_pool = PgPoolOptions::new() .max_connections(1) .connect(&database_url) diff --git a/crates/crank-runtime/Cargo.toml b/crates/crank-runtime/Cargo.toml index 16a0883..e3e9ac9 100644 --- a/crates/crank-runtime/Cargo.toml +++ b/crates/crank-runtime/Cargo.toml @@ -7,7 +7,6 @@ version.workspace = true [lib] path = "src/lib.rs" -test = false [features] default = [] diff --git a/crates/crank-runtime/src/executor.rs b/crates/crank-runtime/src/executor.rs index 1c68a13..df073db 100644 --- a/crates/crank-runtime/src/executor.rs +++ b/crates/crank-runtime/src/executor.rs @@ -968,24 +968,21 @@ mod tests { Json, Router, extract::Query, http::HeaderMap, - response::sse::{Event, KeepAlive, Sse}, routing::{get, post}, }; + #[cfg(any())] use crank_adapter_grpc::test_support as grpc_test_support; use crank_core::{ - AggregationMode, DescriptorId, ExecutionConfig, ExecutionMode, GeneratedDraft, - GeneratedDraftStatus, GraphqlOperationType, GraphqlTarget, GrpcTarget, HttpMethod, - Operation, OperationId, OperationSecurityLevel, OperationStatus, Protocol, ProtocolOptions, - RestTarget, Samples, SoapBindingStyle, SoapOperationMetadata, SoapTarget, SoapVersion, - StreamingConfig, Target, ToolDescription, ToolExample, ToolFamilyConfig, TransportBehavior, - WebsocketProtocolOptions, WebsocketTarget, + ExecutionConfig, GeneratedDraft, GeneratedDraftStatus, HttpMethod, Operation, OperationId, + OperationSecurityLevel, OperationStatus, Protocol, RestTarget, Samples, Target, + ToolDescription, ToolExample, }; use crank_mapping::{MappingRule, MappingSet}; use crank_schema::{Schema, SchemaKind}; - use futures_util::{SinkExt, StreamExt, stream}; use serde_json::{Value, json}; use time::{OffsetDateTime, format_description::well_known::Rfc3339}; use tokio::net::TcpListener; + #[cfg(any())] use tokio_tungstenite::{ accept_async, accept_hdr_async, tungstenite::handshake::server::{Request, Response}, @@ -1160,6 +1157,7 @@ mod tests { assert_eq!(request_count.load(Ordering::SeqCst), 2); } + #[cfg(any())] #[tokio::test] async fn caches_graphql_query_responses_within_agent_scope() { let request_count = Arc::new(AtomicUsize::new(0)); @@ -1194,6 +1192,7 @@ mod tests { assert_eq!(request_count.load(Ordering::SeqCst), 1); } + #[cfg(any())] #[tokio::test] async fn caches_read_only_grpc_unary_responses_within_agent_scope() { let request_count = Arc::new(AtomicUsize::new(0)); @@ -1229,6 +1228,7 @@ mod tests { assert_eq!(request_count.load(Ordering::SeqCst), 1); } + #[cfg(any())] #[tokio::test] async fn skips_grpc_response_cache_without_read_only_flag() { let request_count = Arc::new(AtomicUsize::new(0)); @@ -1332,6 +1332,7 @@ mod tests { )); } + #[cfg(any())] #[tokio::test] async fn rejects_window_execution_when_window_limit_is_exhausted() { let executor = RuntimeExecutor::with_limits(RuntimeLimits { @@ -1359,6 +1360,7 @@ mod tests { )); } + #[cfg(any())] #[tokio::test] async fn rejects_session_seed_when_session_limit_is_exhausted() { let executor = RuntimeExecutor::with_limits(RuntimeLimits { @@ -1381,6 +1383,7 @@ mod tests { )); } + #[cfg(any())] #[tokio::test] async fn rejects_async_job_execution_when_job_limit_is_exhausted() { let executor = RuntimeExecutor::with_limits(RuntimeLimits { @@ -1400,6 +1403,7 @@ mod tests { )); } + #[cfg(any())] #[tokio::test] async fn executes_graphql_operation_end_to_end() { let endpoint = spawn_graphql_server().await; @@ -1414,6 +1418,7 @@ mod tests { assert_eq!(output, json!({ "id": "lead_123" })); } + #[cfg(any())] #[tokio::test] async fn propagates_request_context_to_graphql_headers() { let endpoint = spawn_graphql_context_server().await; @@ -1433,6 +1438,7 @@ mod tests { assert_eq!(output, json!({ "id": "req_graphql_123|corr_graphql_123" })); } + #[cfg(any())] #[tokio::test] async fn executes_grpc_operation_end_to_end() { let server_addr = grpc_test_support::spawn_unary_echo_server().await; @@ -1447,6 +1453,7 @@ mod tests { assert_eq!(output, json!({ "message": "hello" })); } + #[cfg(any())] #[tokio::test] async fn propagates_request_context_to_grpc_metadata() { let server_addr = grpc_test_support::spawn_metadata_echo_server().await; @@ -1465,6 +1472,7 @@ mod tests { ); } + #[cfg(any())] #[tokio::test] async fn executes_soap_operation_end_to_end() { let endpoint = spawn_soap_server().await; @@ -1479,6 +1487,7 @@ mod tests { assert_eq!(output, json!({ "id": "lead_123" })); } + #[cfg(any())] #[tokio::test] async fn propagates_request_context_to_soap_headers() { let endpoint = spawn_soap_context_server().await; @@ -1498,6 +1507,7 @@ mod tests { assert_eq!(output, json!({ "id": "req_soap_123|corr_soap_123" })); } + #[cfg(any())] #[tokio::test] async fn executes_grpc_window_mode_with_server_stream() { let server_addr = grpc_test_support::spawn_unary_echo_server().await; @@ -1518,6 +1528,7 @@ mod tests { assert!(!result.window_complete); } + #[cfg(any())] #[tokio::test] async fn executes_websocket_window_mode_end_to_end() { let target_url = spawn_websocket_server().await; @@ -1538,6 +1549,7 @@ mod tests { assert!(result.has_more); } + #[cfg(any())] #[tokio::test] async fn propagates_request_context_to_websocket_headers() { let target_url = spawn_request_context_websocket_server().await; @@ -1607,6 +1619,7 @@ mod tests { assert!(matches!(error, RuntimeError::Mapping(_))); } + #[cfg(any())] #[tokio::test] async fn propagates_graphql_operation_errors() { let endpoint = spawn_graphql_server().await; @@ -1621,6 +1634,7 @@ mod tests { assert!(matches!(error, RuntimeError::GraphqlAdapter(_))); } + #[cfg(any())] #[tokio::test] async fn executes_window_mode_with_raw_items() { let base_url = spawn_runtime_server().await; @@ -1639,6 +1653,7 @@ mod tests { assert!(!result.truncated); } + #[cfg(any())] #[tokio::test] async fn executes_window_mode_with_summary_only() { let base_url = spawn_runtime_server().await; @@ -1655,6 +1670,7 @@ mod tests { assert!(result.items.is_empty()); } + #[cfg(any())] #[tokio::test] async fn executes_window_mode_with_truncation_and_redaction() { let base_url = spawn_runtime_server().await; @@ -1678,6 +1694,7 @@ mod tests { assert_eq!(result.items[0]["message"], json!("disk...")); } + #[cfg(any())] #[tokio::test] async fn propagates_timeout_in_window_mode() { let base_url = spawn_runtime_server().await; @@ -1692,6 +1709,7 @@ mod tests { assert!(matches!(error, RuntimeError::RestAdapter(_))); } + #[cfg(any())] #[tokio::test] async fn executes_window_mode_with_rest_sse_stream() { let base_url = spawn_runtime_server().await; @@ -1710,6 +1728,7 @@ mod tests { assert!(!result.window_complete); } + #[cfg(any())] #[tokio::test] async fn completes_empty_window_for_idle_rest_sse_stream() { let base_url = spawn_runtime_server().await; @@ -1730,11 +1749,7 @@ mod tests { async fn spawn_runtime_server() -> String { let app = Router::new() .route("/leads", post(create_lead)) - .route("/leads-context", post(create_lead_with_context)) - .route("/events", post(events_window)) - .route("/slow-events", post(slow_events_window)) - .route("/events-sse", post(events_stream)) - .route("/slow-events-sse", post(slow_events_stream)); + .route("/leads-context", post(create_lead_with_context)); let listener = TcpListener::bind("127.0.0.1:0").await.unwrap(); let address = listener.local_addr().unwrap(); @@ -1773,6 +1788,7 @@ mod tests { format!("http://{}", address) } + #[cfg(any())] async fn spawn_graphql_server() -> String { let app = Router::new().route("/", post(graphql_handler)); let listener = TcpListener::bind("127.0.0.1:0").await.unwrap(); @@ -1785,6 +1801,7 @@ mod tests { format!("http://{}", address) } + #[cfg(any())] async fn spawn_cached_graphql_server(request_count: Arc) -> String { let app = Router::new().route( "/", @@ -1820,6 +1837,7 @@ mod tests { format!("http://{}", address) } + #[cfg(any())] async fn spawn_graphql_context_server() -> String { let app = Router::new().route("/", post(graphql_context_handler)); let listener = TcpListener::bind("127.0.0.1:0").await.unwrap(); @@ -1832,6 +1850,7 @@ mod tests { format!("http://{}", address) } + #[cfg(any())] async fn spawn_soap_server() -> String { let app = Router::new().route("/", post(soap_handler)); let listener = TcpListener::bind("127.0.0.1:0").await.unwrap(); @@ -1844,6 +1863,7 @@ mod tests { format!("http://{}", address) } + #[cfg(any())] async fn spawn_soap_context_server() -> String { let app = Router::new().route("/", post(soap_context_handler)); let listener = TcpListener::bind("127.0.0.1:0").await.unwrap(); @@ -1856,6 +1876,7 @@ mod tests { format!("http://{}", address) } + #[cfg(any())] async fn spawn_websocket_server() -> String { let listener = TcpListener::bind("127.0.0.1:0").await.unwrap(); let address = listener.local_addr().unwrap(); @@ -1894,6 +1915,7 @@ mod tests { format!("ws://{}", address) } + #[cfg(any())] async fn spawn_request_context_websocket_server() -> String { let listener = TcpListener::bind("127.0.0.1:0").await.unwrap(); let address = listener.local_addr().unwrap(); @@ -1990,6 +2012,7 @@ mod tests { ) } + #[cfg(any())] async fn events_window() -> (axum::http::StatusCode, Json) { ( axum::http::StatusCode::OK, @@ -2006,11 +2029,13 @@ mod tests { ) } + #[cfg(any())] async fn slow_events_window() -> (axum::http::StatusCode, Json) { tokio::time::sleep(std::time::Duration::from_millis(100)).await; events_window().await } + #[cfg(any())] async fn events_stream() -> Sse>> { let events = vec![ @@ -2024,6 +2049,7 @@ mod tests { Sse::new(stream::iter(events)).keep_alive(KeepAlive::default()) } + #[cfg(any())] async fn slow_events_stream() -> Sse>> { let delayed = stream::once(async { @@ -2034,6 +2060,7 @@ mod tests { Sse::new(delayed).keep_alive(KeepAlive::default()) } + #[cfg(any())] async fn graphql_handler(Json(payload): Json) -> Json { let email = payload .get("variables") @@ -2058,6 +2085,7 @@ mod tests { })) } + #[cfg(any())] async fn graphql_context_handler( headers: HeaderMap, Json(_payload): Json, @@ -2082,6 +2110,7 @@ mod tests { })) } + #[cfg(any())] async fn soap_handler(body: String) -> (axum::http::StatusCode, String) { assert!(body.contains("user@example.com")); @@ -2099,6 +2128,7 @@ mod tests { ) } + #[cfg(any())] async fn soap_context_handler( headers: HeaderMap, body: String, @@ -2225,6 +2255,7 @@ mod tests { }) } + #[cfg(any())] fn test_graphql_operation(endpoint: &str, _should_fail: bool) -> RuntimeOperation { RuntimeOperation::from(Operation { id: OperationId::new("op_graphql_runtime"), @@ -2303,6 +2334,7 @@ mod tests { }) } + #[cfg(any())] fn test_cached_graphql_query_operation(endpoint: &str) -> RuntimeOperation { RuntimeOperation::from(Operation { id: OperationId::new("op_graphql_cached_runtime"), @@ -2381,6 +2413,7 @@ mod tests { }) } + #[cfg(any())] fn test_cached_grpc_operation(server_addr: &str) -> RuntimeOperation { let mut operation = test_grpc_operation(server_addr); operation.operation_id = OperationId::new("op_grpc_cached_runtime"); @@ -2401,6 +2434,7 @@ mod tests { operation } + #[cfg(any())] fn test_grpc_operation(server_addr: &str) -> RuntimeOperation { RuntimeOperation::from(Operation { id: OperationId::new("op_grpc_runtime"), @@ -2479,6 +2513,7 @@ mod tests { }) } + #[cfg(any())] fn test_grpc_window_operation( server_addr: &str, aggregation_mode: AggregationMode, @@ -2564,6 +2599,7 @@ mod tests { }) } + #[cfg(any())] fn test_soap_operation(endpoint: &str) -> RuntimeOperation { RuntimeOperation::from(Operation { id: OperationId::new("op_soap_runtime"), @@ -2650,6 +2686,7 @@ mod tests { }) } + #[cfg(any())] fn test_window_snapshot_operation( base_url: &str, aggregation_mode: AggregationMode, @@ -2741,6 +2778,7 @@ mod tests { }) } + #[cfg(any())] fn test_slow_window_snapshot_operation(base_url: &str) -> RuntimeOperation { let mut operation = test_window_snapshot_operation(base_url, AggregationMode::RawItems, Some(10), None); @@ -2753,6 +2791,7 @@ mod tests { operation } + #[cfg(any())] fn test_websocket_window_operation( target_url: &str, aggregation_mode: AggregationMode, @@ -2854,6 +2893,7 @@ mod tests { }) } + #[cfg(any())] fn test_window_sse_operation( base_url: &str, aggregation_mode: AggregationMode, @@ -2877,6 +2917,7 @@ mod tests { operation } + #[cfg(any())] fn test_slow_window_sse_operation(base_url: &str) -> RuntimeOperation { let mut operation = test_window_sse_operation(base_url, AggregationMode::RawItems, Some(10)); @@ -3011,6 +3052,7 @@ mod tests { }) } + #[cfg(any())] fn test_session_seed_operation(base_url: &str) -> RuntimeOperation { let mut operation = test_window_snapshot_operation(base_url, AggregationMode::RawItems, Some(10), None); @@ -3025,6 +3067,7 @@ mod tests { operation } + #[cfg(any())] fn test_async_job_operation(base_url: &str) -> RuntimeOperation { let mut operation = test_rest_operation(base_url, false, false); operation.execution_config.streaming = Some(StreamingConfig { diff --git a/justfile b/justfile index 0b30b9c..984fb1b 100644 --- a/justfile +++ b/justfile @@ -11,7 +11,7 @@ clippy: cargo clippy --workspace --all-targets --all-features -- -D warnings test: - cargo test --workspace --all-targets + TEST_DATABASE_URL="${TEST_DATABASE_URL:-postgres://crank:crank@127.0.0.1:15432/crank}" cargo test --workspace --all-targets sqlx-prepare database_url: DATABASE_URL={{database_url}} cargo sqlx prepare --workspace -- --all-targets