Download codex-rs/cli/tests/queue.rs from SaylorTwift/codex: direct link, hf CLI and curl.
- Browser
- Download file 8.54 kB
-
https://huggingface.co/SaylorTwift/codex/resolve/main/codex-rs/cli/tests/queue.rs
- Command line
-
hf download hf://SaylorTwift/codex/codex-rs/cli/tests/queue.rs
-
curl -L -o queue.rs https://huggingface.co/SaylorTwift/codex/resolve/main/codex-rs/cli/tests/queue.rs
8.54 kB
| use std::path::Path; | |
| use std::process::Output; | |
| use anyhow::Context; | |
| use anyhow::Result; | |
| use futures::SinkExt; | |
| use futures::StreamExt; | |
| use pretty_assertions::assert_eq; | |
| use serde_json::Value; | |
| use serde_json::json; | |
| use tempfile::TempDir; | |
| use tokio::net::TcpListener; | |
| use tokio_tungstenite::accept_async; | |
| use tokio_tungstenite::tungstenite::Message; | |
| const THREAD_ID: &str = "123e4567-e89b-12d3-a456-426614174000"; | |
| enum QueueResponse { | |
| Success, | |
| MethodNotFound, | |
| UnknownMethodVariant, | |
| } | |
| async fn respond_to_queue_request<S>( | |
| stream: S, | |
| codex_home: &Path, | |
| response: QueueResponse, | |
| ) -> Result<Value> | |
| where | |
| S: tokio::io::AsyncRead + tokio::io::AsyncWrite + Unpin, | |
| { | |
| let mut websocket = accept_async(stream).await?; | |
| let initialize = websocket | |
| .next() | |
| .await | |
| .context("missing initialize request")??; | |
| let initialize: Value = serde_json::from_str(initialize.to_text()?)?; | |
| assert_eq!(initialize["method"], "initialize"); | |
| assert_eq!( | |
| initialize["params"]["capabilities"]["experimentalApi"], | |
| true | |
| ); | |
| let initialized_response = json!({ | |
| "id": initialize["id"], | |
| "result": { | |
| "userAgent": "codex_cli_rs/0.0.0-test", | |
| "codexHome": codex_home, | |
| }, | |
| }); | |
| websocket | |
| .send(Message::Text(initialized_response.to_string().into())) | |
| .await?; | |
| let initialized = websocket | |
| .next() | |
| .await | |
| .context("missing initialized notification")??; | |
| let initialized: Value = serde_json::from_str(initialized.to_text()?)?; | |
| assert_eq!(initialized["method"], "initialized"); | |
| let request = websocket.next().await.context("missing queue request")??; | |
| let request: Value = serde_json::from_str(request.to_text()?)?; | |
| assert_eq!(request["method"], "thread/queue/add"); | |
| let result = match response { | |
| QueueResponse::Success => json!({ | |
| "id": request["id"], | |
| "result": { | |
| "queuedSubmission": { | |
| "id": "queued-submission-id", | |
| "input": request["params"]["input"], | |
| "clientUserMessageId": request["params"]["clientUserMessageId"], | |
| }, | |
| }, | |
| }), | |
| QueueResponse::MethodNotFound => json!({ | |
| "id": request["id"], | |
| "error": { "code": -32601, "message": "Method not found" }, | |
| }), | |
| QueueResponse::UnknownMethodVariant => json!({ | |
| "id": request["id"], | |
| "error": { | |
| "code": -32600, | |
| "message": "Invalid request: unknown variant `thread/queue/add`, expected `thread/list`", | |
| }, | |
| }), | |
| }; | |
| websocket | |
| .send(Message::Text(result.to_string().into())) | |
| .await?; | |
| Ok(request) | |
| } | |
| async fn queue_submits_message_to_remote_app_server() -> Result<()> { | |
| let (output, request) = run_remote_queue_command(QueueResponse::Success).await?; | |
| assert!( | |
| output.status.success(), | |
| "{}", | |
| String::from_utf8_lossy(&output.stderr) | |
| ); | |
| assert_eq!(request["params"]["threadId"], THREAD_ID); | |
| assert_eq!(request["params"]["input"][0]["text"], "do the thing"); | |
| assert_eq!( | |
| String::from_utf8(output.stdout)?, | |
| format!("Queued message queued-submission-id for thread {THREAD_ID}.\n") | |
| ); | |
| Ok(()) | |
| } | |
| async fn queue_does_not_fallback_from_unsupported_explicit_remote() -> Result<()> { | |
| let (output, _) = run_remote_queue_command(QueueResponse::MethodNotFound).await?; | |
| assert!(!output.status.success()); | |
| assert!( | |
| String::from_utf8(output.stderr)? | |
| .contains("remote app server does not support thread/queue/add") | |
| ); | |
| Ok(()) | |
| } | |
| fn queue_rejects_empty_message() -> Result<()> { | |
| let output = std::process::Command::new(codex_utils_cargo_bin::cargo_bin("codex")?) | |
| .args(["queue", "--thread", THREAD_ID, "--message", ""]) | |
| .output()?; | |
| assert!(!output.status.success()); | |
| Ok(()) | |
| } | |
| fn queue_rejects_image_attachments() -> Result<()> { | |
| let output = std::process::Command::new(codex_utils_cargo_bin::cargo_bin("codex")?) | |
| .args([ | |
| "queue", | |
| "--thread", | |
| THREAD_ID, | |
| "--message", | |
| "do the thing", | |
| "--image", | |
| "screenshot.png", | |
| ]) | |
| .output()?; | |
| assert!(!output.status.success()); | |
| assert!(String::from_utf8(output.stderr)?.contains("does not support image attachments")); | |
| Ok(()) | |
| } | |
| async fn run_remote_queue_command(response: QueueResponse) -> Result<(Output, Value)> { | |
| let codex_home = TempDir::new()?; | |
| let listener = TcpListener::bind("127.0.0.1:0").await?; | |
| let endpoint = format!("ws://{}", listener.local_addr()?); | |
| let remote_first = matches!(response, QueueResponse::MethodNotFound); | |
| let server_home = codex_home.path().to_path_buf(); | |
| let server = tokio::spawn(async move { | |
| let (stream, _) = listener.accept().await?; | |
| respond_to_queue_request(stream, server_home.as_path(), response).await | |
| }); | |
| let remote_args = if remote_first { | |
| [ | |
| "--remote", | |
| endpoint.as_str(), | |
| "--remote-auth-token-env", | |
| "CODEX_REMOTE_TOKEN", | |
| "queue", | |
| ] | |
| } else { | |
| [ | |
| "queue", | |
| "--remote", | |
| endpoint.as_str(), | |
| "--remote-auth-token-env", | |
| "CODEX_REMOTE_TOKEN", | |
| ] | |
| }; | |
| let output = tokio::process::Command::new(codex_utils_cargo_bin::cargo_bin("codex")?) | |
| .env("CODEX_HOME", codex_home.path()) | |
| .env("CODEX_REMOTE_TOKEN", "test-token") | |
| .args(remote_args) | |
| .args(["--thread", THREAD_ID, "--message", "do the thing"]) | |
| .output() | |
| .await?; | |
| Ok((output, server.await??)) | |
| } | |
| async fn queue_rejects_local_daemon_that_does_not_support_queueing() -> Result<()> { | |
| let codex_home = tempfile::tempdir_in("/tmp")?; | |
| let socket_path = codex_app_server::app_server_control_socket_path(codex_home.path())?; | |
| std::fs::create_dir_all( | |
| socket_path | |
| .as_path() | |
| .parent() | |
| .context("missing socket parent")?, | |
| )?; | |
| let listener = tokio::net::UnixListener::bind(socket_path.as_path())?; | |
| let server_home = codex_home.path().to_path_buf(); | |
| let server = tokio::spawn(async move { | |
| let (probe, _) = listener.accept().await?; | |
| drop(probe); | |
| let (stream, _) = listener.accept().await?; | |
| respond_to_queue_request( | |
| stream, | |
| server_home.as_path(), | |
| QueueResponse::UnknownMethodVariant, | |
| ) | |
| .await | |
| }); | |
| let output = tokio::process::Command::new(codex_utils_cargo_bin::cargo_bin("codex")?) | |
| .env("CODEX_HOME", codex_home.path()) | |
| .args(["queue", "--thread", THREAD_ID, "--message", "do the thing"]) | |
| .output() | |
| .await?; | |
| server.await??; | |
| assert!(!output.status.success()); | |
| assert!( | |
| String::from_utf8(output.stderr)? | |
| .contains("local app-server daemon does not support thread/queue/add") | |
| ); | |
| assert!(!codex_home.path().join("queue_1.sqlite").exists()); | |
| Ok(()) | |
| } | |
| async fn queue_rejects_overrides_that_bypass_local_daemon() -> Result<()> { | |
| let codex_home = tempfile::tempdir_in("/tmp")?; | |
| let socket_path = codex_app_server::app_server_control_socket_path(codex_home.path())?; | |
| std::fs::create_dir_all( | |
| socket_path | |
| .as_path() | |
| .parent() | |
| .context("missing socket parent")?, | |
| )?; | |
| let listener = tokio::net::UnixListener::bind(socket_path.as_path())?; | |
| let server = tokio::spawn(async move { | |
| let (probe, _) = listener.accept().await?; | |
| drop(probe); | |
| Ok::<_, std::io::Error>(()) | |
| }); | |
| let output = tokio::process::Command::new(codex_utils_cargo_bin::cargo_bin("codex")?) | |
| .env("CODEX_HOME", codex_home.path()) | |
| .args([ | |
| "queue", | |
| "-c", | |
| "model=\"test-model\"", | |
| "--thread", | |
| THREAD_ID, | |
| "--message", | |
| "do the thing", | |
| ]) | |
| .output() | |
| .await?; | |
| server.await??; | |
| assert!(!output.status.success()); | |
| assert!( | |
| String::from_utf8(output.stderr)? | |
| .contains("embedded app server while a local app-server daemon is running") | |
| ); | |
| Ok(()) | |
| } | |