feat: expose streaming test run results
This commit is contained in:
+267
-3
@@ -221,9 +221,10 @@ mod tests {
|
||||
use axum::{Json, Router, routing::post};
|
||||
use crank_adapter_grpc::test_support as grpc_test_support;
|
||||
use crank_core::{
|
||||
DescriptorId, ExecutionConfig, GraphqlOperationType, GraphqlTarget, GrpcTarget, HttpMethod,
|
||||
MembershipRole, Protocol, RestTarget, SecretKind, SoapBindingStyle, SoapOperationMetadata,
|
||||
SoapTarget, SoapVersion, Target, ToolDescription, WorkspaceId,
|
||||
DescriptorId, ExecutionConfig, ExecutionMode, GraphqlOperationType, GraphqlTarget,
|
||||
GrpcTarget, HttpMethod, MembershipRole, Protocol, RestTarget, SecretKind, SoapBindingStyle,
|
||||
SoapOperationMetadata, SoapTarget, SoapVersion, Target, ToolDescription, TransportBehavior,
|
||||
WorkspaceId,
|
||||
};
|
||||
use crank_mapping::{MappingRule, MappingSet};
|
||||
use crank_registry::PostgresRegistry;
|
||||
@@ -1441,6 +1442,177 @@ mod tests {
|
||||
assert_eq!(test_run["response_preview"]["message"], "hello");
|
||||
}
|
||||
|
||||
#[tokio::test(flavor = "multi_thread")]
|
||||
#[serial]
|
||||
async fn returns_window_metadata_for_streaming_test_runs() {
|
||||
let registry = test_registry().await;
|
||||
let storage_root = test_storage_root("grpc_window_test_run");
|
||||
let server_addr = grpc_test_support::spawn_unary_echo_server().await;
|
||||
let base_url = spawn_admin_api(build_test_app(registry, storage_root)).await;
|
||||
let client = authorized_client(&base_url).await;
|
||||
|
||||
let created = client
|
||||
.post(format!("{base_url}/operations"))
|
||||
.json(&test_grpc_window_operation_payload(
|
||||
&server_addr,
|
||||
"echo_window_runtime",
|
||||
))
|
||||
.send()
|
||||
.await
|
||||
.unwrap()
|
||||
.json::<Value>()
|
||||
.await
|
||||
.unwrap();
|
||||
let operation_id = created["operation_id"].as_str().unwrap().to_owned();
|
||||
|
||||
let test_run = client
|
||||
.post(format!("{base_url}/operations/{operation_id}/test-runs"))
|
||||
.json(&json!({
|
||||
"version": 1,
|
||||
"input": { "message": "hello" }
|
||||
}))
|
||||
.send()
|
||||
.await
|
||||
.unwrap()
|
||||
.json::<Value>()
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
assert_eq!(test_run["ok"], true);
|
||||
assert_eq!(test_run["mode"], "window");
|
||||
assert!(test_run["window"].is_object());
|
||||
assert!(test_run["window"]["window_complete"].is_boolean());
|
||||
assert!(test_run["window"]["truncated"].is_boolean());
|
||||
assert!(test_run["window"]["has_more"].is_boolean());
|
||||
assert!(test_run["response_preview"]["items"].is_array());
|
||||
}
|
||||
|
||||
#[tokio::test(flavor = "multi_thread")]
|
||||
#[serial]
|
||||
async fn starts_stream_session_from_streaming_test_runs() {
|
||||
let registry = test_registry().await;
|
||||
let storage_root = test_storage_root("grpc_session_test_run");
|
||||
let server_addr = grpc_test_support::spawn_unary_echo_server().await;
|
||||
let base_url = spawn_admin_api(build_test_app(registry, storage_root)).await;
|
||||
let client = authorized_client(&base_url).await;
|
||||
|
||||
let created = client
|
||||
.post(format!("{base_url}/operations"))
|
||||
.json(&test_grpc_session_operation_payload(
|
||||
&server_addr,
|
||||
"echo_session_runtime",
|
||||
))
|
||||
.send()
|
||||
.await
|
||||
.unwrap()
|
||||
.json::<Value>()
|
||||
.await
|
||||
.unwrap();
|
||||
let operation_id = created["operation_id"].as_str().unwrap().to_owned();
|
||||
|
||||
let test_run = client
|
||||
.post(format!("{base_url}/operations/{operation_id}/test-runs"))
|
||||
.json(&json!({
|
||||
"version": 1,
|
||||
"input": { "message": "hello" }
|
||||
}))
|
||||
.send()
|
||||
.await
|
||||
.unwrap()
|
||||
.json::<Value>()
|
||||
.await
|
||||
.unwrap();
|
||||
let session_id = test_run["stream_session"]["session_id"]
|
||||
.as_str()
|
||||
.unwrap()
|
||||
.to_owned();
|
||||
|
||||
let session = client
|
||||
.get(format!("{base_url}/stream-sessions/{session_id}"))
|
||||
.send()
|
||||
.await
|
||||
.unwrap()
|
||||
.json::<Value>()
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
assert_eq!(test_run["ok"], true);
|
||||
assert_eq!(test_run["mode"], "session");
|
||||
assert_eq!(test_run["stream_session"]["status"], "running");
|
||||
assert!(test_run["response_preview"]["preview"]["items"].is_array());
|
||||
assert_eq!(session["id"], session_id);
|
||||
assert_eq!(session["status"], "running");
|
||||
}
|
||||
|
||||
#[tokio::test(flavor = "multi_thread")]
|
||||
#[serial]
|
||||
async fn starts_async_job_from_streaming_test_runs() {
|
||||
let registry = test_registry().await;
|
||||
let storage_root = test_storage_root("async_job_test_run");
|
||||
let upstream_base_url = spawn_upstream_server().await;
|
||||
let base_url = spawn_admin_api(build_test_app(registry, storage_root)).await;
|
||||
let client = authorized_client(&base_url).await;
|
||||
|
||||
let created = client
|
||||
.post(format!("{base_url}/operations"))
|
||||
.json(&test_rest_async_job_operation_payload(
|
||||
&upstream_base_url,
|
||||
"crm_async_job_runtime",
|
||||
))
|
||||
.send()
|
||||
.await
|
||||
.unwrap()
|
||||
.json::<Value>()
|
||||
.await
|
||||
.unwrap();
|
||||
let operation_id = created["operation_id"].as_str().unwrap().to_owned();
|
||||
|
||||
let test_run = client
|
||||
.post(format!("{base_url}/operations/{operation_id}/test-runs"))
|
||||
.json(&json!({
|
||||
"version": 1,
|
||||
"input": { "email": "user@example.com" }
|
||||
}))
|
||||
.send()
|
||||
.await
|
||||
.unwrap()
|
||||
.json::<Value>()
|
||||
.await
|
||||
.unwrap();
|
||||
let job_id = test_run["async_job"]["job_id"].as_str().unwrap().to_owned();
|
||||
|
||||
let mut job = Value::Null;
|
||||
for _ in 0..20 {
|
||||
job = client
|
||||
.get(format!("{base_url}/async-jobs/{job_id}"))
|
||||
.send()
|
||||
.await
|
||||
.unwrap()
|
||||
.json::<Value>()
|
||||
.await
|
||||
.unwrap();
|
||||
if job["status"] == "completed" {
|
||||
break;
|
||||
}
|
||||
tokio::time::sleep(std::time::Duration::from_millis(25)).await;
|
||||
}
|
||||
|
||||
let result = client
|
||||
.get(format!("{base_url}/async-jobs/{job_id}/result"))
|
||||
.send()
|
||||
.await
|
||||
.unwrap()
|
||||
.json::<Value>()
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
assert_eq!(test_run["ok"], true);
|
||||
assert_eq!(test_run["mode"], "async_job");
|
||||
assert_eq!(test_run["async_job"]["status"], "running");
|
||||
assert_eq!(job["status"], "completed");
|
||||
assert_eq!(result["id"], "lead_123");
|
||||
}
|
||||
|
||||
#[tokio::test(flavor = "multi_thread")]
|
||||
#[serial]
|
||||
async fn uploads_wsdl_and_tests_soap_operation() {
|
||||
@@ -2317,6 +2489,98 @@ mod tests {
|
||||
}
|
||||
}
|
||||
|
||||
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();
|
||||
payload.target = Target::Grpc(GrpcTarget {
|
||||
server_addr: server_addr.to_owned(),
|
||||
package: "echo".to_owned(),
|
||||
service: "EchoService".to_owned(),
|
||||
method: "ServerEcho".to_owned(),
|
||||
descriptor_ref: DescriptorId::new("desc_echo_stream"),
|
||||
descriptor_set_b64: grpc_test_support::descriptor_set_b64(),
|
||||
});
|
||||
payload.execution_config.streaming = Some(crank_core::StreamingConfig {
|
||||
mode: ExecutionMode::Window,
|
||||
transport_behavior: TransportBehavior::ServerStream,
|
||||
window_duration_ms: Some(100),
|
||||
poll_interval_ms: None,
|
||||
upstream_timeout_ms: Some(1_000),
|
||||
idle_timeout_ms: None,
|
||||
max_session_lifetime_ms: None,
|
||||
max_items: Some(2),
|
||||
max_bytes: None,
|
||||
aggregation_mode: crank_core::AggregationMode::RawItems,
|
||||
summary_path: None,
|
||||
items_path: Some("$.response.body.items".to_owned()),
|
||||
cursor_path: None,
|
||||
status_path: None,
|
||||
done_path: Some("$.response.body.done".to_owned()),
|
||||
redacted_paths: Vec::new(),
|
||||
truncate_item_fields: false,
|
||||
max_field_length: None,
|
||||
drop_duplicates: false,
|
||||
sampling_rate: None,
|
||||
tool_family: crank_core::ToolFamilyConfig::default(),
|
||||
});
|
||||
payload
|
||||
}
|
||||
|
||||
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();
|
||||
if let Some(streaming) = payload.execution_config.streaming.as_mut() {
|
||||
streaming.mode = ExecutionMode::Session;
|
||||
streaming.poll_interval_ms = Some(1_000);
|
||||
streaming.max_session_lifetime_ms = Some(60_000);
|
||||
streaming.tool_family = crank_core::ToolFamilyConfig {
|
||||
start_tool_name: Some("echo_session_start".to_owned()),
|
||||
poll_tool_name: Some("echo_session_poll".to_owned()),
|
||||
stop_tool_name: Some("echo_session_stop".to_owned()),
|
||||
status_tool_name: None,
|
||||
result_tool_name: None,
|
||||
cancel_tool_name: None,
|
||||
};
|
||||
}
|
||||
payload
|
||||
}
|
||||
|
||||
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();
|
||||
payload.execution_config.streaming = Some(crank_core::StreamingConfig {
|
||||
mode: ExecutionMode::AsyncJob,
|
||||
transport_behavior: TransportBehavior::DeferredResult,
|
||||
window_duration_ms: None,
|
||||
poll_interval_ms: Some(1_000),
|
||||
upstream_timeout_ms: Some(1_000),
|
||||
idle_timeout_ms: None,
|
||||
max_session_lifetime_ms: Some(300_000),
|
||||
max_items: None,
|
||||
max_bytes: None,
|
||||
aggregation_mode: crank_core::AggregationMode::SummaryPlusSamples,
|
||||
summary_path: None,
|
||||
items_path: None,
|
||||
cursor_path: None,
|
||||
status_path: None,
|
||||
done_path: None,
|
||||
redacted_paths: Vec::new(),
|
||||
truncate_item_fields: false,
|
||||
max_field_length: None,
|
||||
drop_duplicates: false,
|
||||
sampling_rate: None,
|
||||
tool_family: crank_core::ToolFamilyConfig {
|
||||
start_tool_name: Some("crm_async_start".to_owned()),
|
||||
poll_tool_name: None,
|
||||
stop_tool_name: None,
|
||||
status_tool_name: Some("crm_async_status".to_owned()),
|
||||
result_tool_name: Some("crm_async_result".to_owned()),
|
||||
cancel_tool_name: Some("crm_async_cancel".to_owned()),
|
||||
},
|
||||
});
|
||||
payload
|
||||
}
|
||||
|
||||
fn test_soap_operation_payload(endpoint: &str, name: &str) -> OperationPayload {
|
||||
OperationPayload {
|
||||
name: name.to_owned(),
|
||||
|
||||
Reference in New Issue
Block a user