Skip to content

Commit 48a30ef

Browse files
stephentoubCopilot
andcommitted
Fix Rust E2E suite runtime
Replace the global Rust E2E lock with bounded replay-test concurrency so the suite no longer serializes every replay-backed case. Wait for disconnected-client tool removal before sending the follow-up multi-client prompt to keep the concurrent run deterministic. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
1 parent 49d873e commit 48a30ef

3 files changed

Lines changed: 22 additions & 4 deletions

File tree

.github/workflows/rust-sdk-tests.yml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -96,9 +96,10 @@ jobs:
9696
- name: cargo test
9797
timeout-minutes: 90
9898
env:
99+
RUST_E2E_CONCURRENCY: 4
99100
COPILOT_HMAC_KEY: ${{ secrets.COPILOT_DEVELOPER_CLI_INTEGRATION_HMAC_KEY }}
100101
COPILOT_CLI_PATH: ${{ steps.setup-copilot.outputs.cli-path }}
101-
run: cargo test --features test-support -- --test-threads=1 --nocapture
102+
run: cargo test --features test-support -- --nocapture
102103

103104
# Validates the `embedded-cli` build path on all three supported
104105
# platforms. This is the only place `build.rs` actually runs (the

rust/tests/e2e/multi_client.rs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -237,7 +237,13 @@ async fn disconnecting_client_removes_its_tools() {
237237
.expect("ephemeral answer");
238238
assert!(assistant_message_content(&ephemeral).contains("EPHEMERAL_test2"));
239239

240+
let tools_removed = wait_for_event(
241+
session1.subscribe(),
242+
"ephemeral tool removal",
243+
|event| event.parsed_type() == SessionEventType::SessionToolsUpdated,
244+
);
240245
client2.force_stop();
246+
tools_removed.await;
241247
let after = session1
242248
.send_and_wait(
243249
"Use the stable_tool with input 'still_here'. Also try using ephemeral_tool if it is available.",

rust/tests/e2e/support.rs

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -16,9 +16,9 @@ use github_copilot_sdk::{
1616
SessionLifecycleEvent, Transport,
1717
};
1818
use serde_json::json;
19-
use tokio::sync::Mutex;
19+
use tokio::sync::Semaphore;
2020

21-
static E2E_LOCK: LazyLock<Mutex<()>> = LazyLock::new(|| Mutex::new(()));
21+
static E2E_CONCURRENCY: LazyLock<Semaphore> = LazyLock::new(|| Semaphore::new(e2e_concurrency()));
2222

2323
pub const DEFAULT_TEST_TOKEN: &str = "rust-e2e-token";
2424

@@ -28,7 +28,10 @@ pub async fn with_e2e_context<F>(category: &str, snapshot_name: &str, test: F)
2828
where
2929
F: for<'a> FnOnce(&'a mut E2eContext) -> TestFuture<'a>,
3030
{
31-
let _guard = E2E_LOCK.lock().await;
31+
let _permit = E2E_CONCURRENCY
32+
.acquire()
33+
.await
34+
.expect("E2E concurrency semaphore should stay open");
3235
let mut ctx = E2eContext::new(category, snapshot_name)
3336
.await
3437
.unwrap_or_else(|err| panic!("create E2E context: {err}"));
@@ -452,6 +455,14 @@ fn default_test_timeout() -> Duration {
452455
}
453456
}
454457

458+
fn e2e_concurrency() -> usize {
459+
std::env::var("RUST_E2E_CONCURRENCY")
460+
.ok()
461+
.and_then(|value| value.parse::<usize>().ok())
462+
.filter(|&value| value > 0)
463+
.unwrap_or(4)
464+
}
465+
455466
pub fn get_system_message(exchange: &serde_json::Value) -> String {
456467
exchange
457468
.get("request")

0 commit comments

Comments
 (0)