Files
codex/codex-rs/app-server/src/turn_admission_tests.rs
T
dhruvgupta-oai d257beb16a Add experimental ChatGPT workspace switching to app-server (#57514)
## What changed

- Add `accountSession/list` and `accountSession/switch` for the active managed ChatGPT login, with optional workspace membership refresh.
- Validate membership and workspace policy, pause new turns, and unload running threads before switching credentials. Notify clients with `thread/closed` and `account/updated`; selecting the current workspace leaves threads running.
- Support browser sign-in for SSO through `allowBrowserLogin`, binding the callback to the requesting login and workspace. Require a separate sign-in for government workspaces.
- Preserve the selected workspace across token refresh and conditionally restore the previous workspace if routing validation fails. Guard credential writes against concurrent login or logout changes.

## Testing

Add app-server and auth tests covering workspace switching, credential preservation, policy and identity rejection, conditional rollback, stale sessions, and SSO callback validation.

GitOrigin-RevId: 1234abc33b71e69b66318da3e201fccc08867906
2026-10-27 17:04:16 +00:00

52 lines
1.7 KiB
Rust

use super::TurnAdmission;
use crate::error_code::INVALID_REQUEST_ERROR_CODE;
use codex_extension_api::TurnStartAdmission;
use pretty_assertions::assert_eq;
#[test]
fn drain_rejects_new_work_without_waiting_for_admitted_work() {
let admission = TurnAdmission::default();
let active = admission.subscribe_active();
let in_flight = admission.admit().expect("initial request admitted");
let automatic = admission
.admit_turn_start()
.expect("automatic start admitted");
admission.begin_drain();
assert_eq!(*active.borrow(), 2);
assert!(admission.admit_turn_start().is_none());
let error = admission.admit().err().expect("new request rejected");
assert_eq!(error.code, INVALID_REQUEST_ERROR_CODE);
assert_eq!(
error.data,
Some(serde_json::json!({ "reason": "serverShuttingDown" }))
);
drop(in_flight);
assert_eq!(*active.borrow(), 1);
drop(automatic);
assert_eq!(*active.borrow(), 0);
}
#[tokio::test]
async fn workspace_pause_waits_for_admitted_work_and_preserves_shutdown_drain() {
let admission = TurnAdmission::default();
let in_flight = admission.admit().unwrap();
let pending_pause = admission.pause();
tokio::pin!(pending_pause);
tokio::select! {
biased;
_ = &mut pending_pause => panic!("pause completed before the existing request"),
() = async {} => {}
}
assert!(admission.admit().is_err());
assert!(admission.admit_turn_start().is_none());
drop(in_flight);
let pause = pending_pause.await.unwrap();
drop(pause);
drop(admission.admit().unwrap());
let pause = admission.pause().await.unwrap();
admission.begin_drain();
drop(pause);
assert!(admission.admit().is_err());
}