Files
codex/codex-rs/rmcp-client/src/oauth/refresh_lock_tests.rs
T
stevenlee-oai 6962a2ecae Serialize MCP OAuth credential refreshes (#32229)
## Why

Concurrent Codex processes can otherwise refresh the same rotating token, and a
cancelled or partially persisted refresh can leave durable and in-memory MCP
credentials out of sync.

## What changed

- Serialize each credential's read-refresh-write transaction across processes,
  reread the authoritative store after locking, and adopt credentials refreshed
  by another process.
- Keep refresh persistence running after caller cancellation, bound lock and
  provider waits independently, and preserve omitted refresh tokens and scopes.
- Fail MCP startup and operations when refresh or persistence fails instead of
  continuing with stale credentials, while requiring reauthorization for
  missing, unusable, or rejected refresh tokens.
- Exclude OAuth refresh time from the MCP initialization timeout.

## Testing

Add coverage for lock contention, concurrent refreshes, rejected and missing
credentials, storage failures, caller cancellation, and provider timeouts.

GitOrigin-RevId: 4d29b879bec646d2ceb922b526dc793b1a1f5423
2026-07-10 17:59:41 +00:00

41 lines
1.0 KiB
Rust

use super::RefreshCredentialLock;
use anyhow::Result;
use std::time::Duration;
use tempfile::tempdir;
#[tokio::test]
async fn acquisition_times_out_without_stealing() -> Result<()> {
let codex_home = tempdir()?;
let store_key = "test-store-key";
let held_lock = RefreshCredentialLock::acquire_in(
codex_home.path(),
store_key,
Duration::from_millis(/*millis*/ 100),
)
.await?;
let error = RefreshCredentialLock::acquire_in(
codex_home.path(),
store_key,
Duration::from_millis(/*millis*/ 50),
)
.await
.err()
.expect("contending lock acquisition should time out");
assert!(
error
.to_string()
.contains("timed out after 50ms waiting for OAuth refresh lock"),
"unexpected error: {error:#}"
);
drop(held_lock);
let _reacquired = RefreshCredentialLock::acquire_in(
codex_home.path(),
store_key,
Duration::from_millis(/*millis*/ 100),
)
.await?;
Ok(())
}