use std::{collections::BTreeMap, sync::Arc}; use async_trait::async_trait; use crank_core::{ AdapterResponse, ExecutionConfig, ExecutionMode, HttpMethod, Operation, OperationId, OperationSecurityLevel, OperationStatus, PreparedRequest, Protocol, ProtocolAdapter, ProtocolAdapterError, RestTarget, RuntimeRequestContext as ProtocolRequestContext, Target, ToolDescription, }; use crank_mapping::MappingSet; use crank_runtime::RuntimeExecutorBuilder; use crank_schema::{Schema, SchemaKind}; use serde_json::json; use time::OffsetDateTime; use crate::support::RuntimeExecutorTestExt; #[tokio::test] async fn prepares_empty_request_for_no_input_get_with_empty_mapping() { let executor = RuntimeExecutorBuilder::new() .register_adapter(Arc::new(EmptyRequestAdapter)) .build(); let operation = no_input_get_operation().into(); let response = executor.execute(&operation, &json!({})).await.unwrap(); assert_eq!(response, json!({})); } struct EmptyRequestAdapter; #[async_trait] impl ProtocolAdapter for EmptyRequestAdapter { fn protocol(&self) -> Protocol { Protocol::Rest } fn supports_mode(&self, mode: ExecutionMode) -> bool { mode == ExecutionMode::Unary } async fn invoke_unary( &self, _target: &Target, request: &PreparedRequest, _context: &ProtocolRequestContext, ) -> Result { assert!(request.path_params.is_empty()); assert!(request.query_params.is_empty()); assert!(request.headers.is_empty()); assert!(request.body.is_none()); Ok(AdapterResponse { status_code: 200, headers: BTreeMap::new(), body: json!({}), data: json!({}), }) } } fn no_input_get_operation() -> Operation { Operation { id: OperationId::new("op_no_input_get"), name: "internal_health".to_owned(), display_name: "Internal Health".to_owned(), category: "smoke".to_owned(), protocol: Protocol::Rest, security_level: OperationSecurityLevel::Standard, status: OperationStatus::Draft, version: 1, target: Target::Rest(RestTarget { base_url: "http://admin-api:3001".to_owned(), method: HttpMethod::Get, path_template: "/health".to_owned(), static_headers: BTreeMap::new(), }), input_schema: Schema { kind: SchemaKind::Object, description: None, required: true, nullable: false, default_value: None, fields: BTreeMap::new(), items: None, enum_values: Vec::new(), variants: Vec::new(), }, output_schema: Schema { kind: SchemaKind::Object, description: None, required: true, nullable: false, default_value: None, fields: BTreeMap::new(), items: None, enum_values: Vec::new(), variants: Vec::new(), }, input_mapping: MappingSet { rules: Vec::new() }, output_mapping: MappingSet { rules: Vec::new() }, execution_config: ExecutionConfig { timeout_ms: 1_000, retry_policy: None, response_cache: None, idempotency: None, safety: None, approval_policy: None, auth_profile_ref: None, headers: BTreeMap::new(), }, tool_description: ToolDescription { title: "Internal Health".to_owned(), description: "Checks internal health.".to_owned(), tags: Vec::new(), examples: Vec::new(), }, samples: None, generated_draft: None, config_export: None, wizard_state: None, created_at: OffsetDateTime::UNIX_EPOCH, updated_at: OffsetDateTime::UNIX_EPOCH, published_at: None, } }