diff --git a/codex-rs/exec-server/src/environment.rs b/codex-rs/exec-server/src/environment.rs index 076dd08a83..70072731fa 100644 --- a/codex-rs/exec-server/src/environment.rs +++ b/codex-rs/exec-server/src/environment.rs @@ -89,13 +89,6 @@ pub struct EnvironmentReadyInfo { pub selected_capability_roots: Vec, } -/// The one-shot capability to complete a deferred environment registration. -#[must_use = "the deferred environment cannot connect until registration is completed"] -pub struct DeferredEnvironmentRegistration { - environment_id: String, - environment: Option>, -} - /// Maximum capability roots accepted from environment ready information. pub const MAX_SELECTED_CAPABILITY_ROOTS: usize = 256; @@ -232,7 +225,16 @@ impl EnvironmentManager { local_runtime_paths, http_client_factory, }; - manager.upsert_noise_environment(REMOTE_ENVIRONMENT_ID.to_string(), connect_provider)?; + let identity = noise_channel_identity()?; + let environment = Arc::new(Environment::remote_with_transport( + ExecServerTransportParams::NoiseRendezvous { + provider: connect_provider, + identity, + }, + manager.local_runtime_paths.clone(), + manager.http_client_factory.clone(), + )); + manager.insert_environment(REMOTE_ENVIRONMENT_ID.to_string(), environment)?; Ok(manager) } @@ -380,26 +382,6 @@ impl EnvironmentManager { .cloned() } - /// Publishes capability roots without changing an environment's provisioning state. - pub fn publish_ready_info( - &self, - environment_id: &str, - ready_info: EnvironmentReadyInfo, - ) -> Result<(), ExecServerError> { - validate_environment_id(environment_id)?; - validate_environment_ready_info(environment_id, &ready_info)?; - - let environments = self - .environments - .read() - .unwrap_or_else(std::sync::PoisonError::into_inner); - let environment = environments.get(environment_id).ok_or_else(|| { - ExecServerError::Protocol(format!("environment `{environment_id}` is not registered")) - })?; - environment.ready_info.store(Some(Arc::new(ready_info))); - Ok(()) - } - /// Records a Ready or Failed provisioning result for an environment. /// /// Ordinary environments are ignored. A provisioned environment keeps the same `Arc` from @@ -489,22 +471,6 @@ impl EnvironmentManager { self.insert_environment(environment_id, environment) } - /// Adds or replaces a Noise environment completed through its registration handle. - pub fn register_deferred_noise_environment( - &self, - environment_id: String, - provider: Arc, - ) -> Result { - validate_environment_id(&environment_id)?; - let environment = - Arc::new(self.provisioning_noise_environment(provider, /*initial_result*/ None)?); - self.insert_environment(environment_id.clone(), Arc::clone(&environment))?; - Ok(DeferredEnvironmentRegistration { - environment_id, - environment: Some(environment), - }) - } - /// Returns the stable environment for an ID, creating it as pending when absent. pub fn materialize_pending_noise_environment( &self, @@ -548,22 +514,6 @@ impl EnvironmentManager { Ok(environment) } - /// Adds or replaces a named remote environment using authenticated Noise rendezvous. - pub fn upsert_noise_environment( - &self, - environment_id: String, - provider: Arc, - ) -> Result<(), ExecServerError> { - validate_environment_id(&environment_id)?; - let identity = noise_channel_identity()?; - let environment = Arc::new(Environment::remote_with_transport( - ExecServerTransportParams::NoiseRendezvous { provider, identity }, - self.local_runtime_paths.clone(), - self.http_client_factory.clone(), - )); - self.insert_environment(environment_id, environment) - } - fn insert_environment( &self, environment_id: String, @@ -582,36 +532,6 @@ impl EnvironmentManager { } } -impl DeferredEnvironmentRegistration { - /// Completes provisioning with ready information or a terminal error message. - pub fn complete( - mut self, - result: Result, - ) -> Result<(), ExecServerError> { - let Some(environment) = self.environment.take() else { - return Err(ExecServerError::Disconnected( - "deferred environment registration is inactive".into(), - )); - }; - - match result { - Ok(ready_info) => environment.apply_ready_report(&self.environment_id, ready_info), - Err(error) => environment.apply_error_report(&self.environment_id, error), - } - } -} - -impl Drop for DeferredEnvironmentRegistration { - fn drop(&mut self) { - if let Some(environment) = self.environment.take() { - let _ = environment.apply_error_report( - &self.environment_id, - "environment registration ended before completion".to_string(), - ); - } - } -} - fn validate_environment_ready_info( environment_id: &str, ready_info: &EnvironmentReadyInfo, diff --git a/codex-rs/exec-server/src/lib.rs b/codex-rs/exec-server/src/lib.rs index 17fdb78ef8..9d846a305f 100644 --- a/codex-rs/exec-server/src/lib.rs +++ b/codex-rs/exec-server/src/lib.rs @@ -81,7 +81,6 @@ pub use environment::CODEX_EXEC_SERVER_NOISE_CHATGPT_ACCOUNT_ID_ENV_VAR; pub use environment::CODEX_EXEC_SERVER_NOISE_ENVIRONMENT_ID_ENV_VAR; pub use environment::CODEX_EXEC_SERVER_NOISE_REGISTRY_URL_ENV_VAR; pub use environment::CODEX_EXEC_SERVER_URL_ENV_VAR; -pub use environment::DeferredEnvironmentRegistration; pub use environment::Environment; pub use environment::EnvironmentConnectionState; pub use environment::EnvironmentManager; diff --git a/codex-rs/exec-server/tests/deferred_environment.rs b/codex-rs/exec-server/tests/deferred_environment.rs index 442b6afad0..d08b9ab5e6 100644 --- a/codex-rs/exec-server/tests/deferred_environment.rs +++ b/codex-rs/exec-server/tests/deferred_environment.rs @@ -54,367 +54,6 @@ fn ready_info(root_id: &str, environment_id: &str) -> anyhow::Result anyhow::Result<()> { - let manager = environment_manager_without_environments(); - let provider = Arc::new(FailingNoiseConnectProvider::default()); - let registration = - manager.register_deferred_noise_environment("tools".to_string(), provider.clone())?; - let environment = manager.get_environment("tools").expect("environment"); - let connection_state = environment - .subscribe_connection_state() - .expect("remote environment connection state"); - let mut readiness = Box::pin(environment.wait_until_ready()); - - assert!(poll!(&mut readiness).is_pending()); - assert_eq!(provider.calls(), 0); - assert!(environment.selected_capability_roots().is_empty()); - - let ready_info = ready_info("selected-root", "tools")?; - registration.complete(Ok(ready_info.clone()))?; - assert_eq!( - environment.selected_capability_roots(), - ready_info.selected_capability_roots - ); - let error = readiness.await.unwrap_err(); - assert!(error.to_string().contains("test Noise provider called")); - assert_eq!(provider.calls(), 1); - assert!(!connection_state.has_changed()?); - Ok(()) -} - -#[tokio::test] -async fn deferred_registration_replaces_an_ordinary_noise_environment() -> anyhow::Result<()> { - let manager = environment_manager_without_environments(); - manager.upsert_noise_environment( - "tools".to_string(), - Arc::new(FailingNoiseConnectProvider::default()), - )?; - let ordinary = manager - .get_environment("tools") - .expect("ordinary environment"); - let deferred_provider = Arc::new(FailingNoiseConnectProvider::default()); - - let registration = manager - .register_deferred_noise_environment("tools".to_string(), deferred_provider.clone())?; - let deferred = manager - .get_environment("tools") - .expect("deferred environment"); - assert!(!Arc::ptr_eq(&ordinary, &deferred)); - let mut readiness = Box::pin(deferred.wait_until_ready()); - assert!(poll!(&mut readiness).is_pending()); - - registration.complete(Ok(ready_info("selected-root", "tools")?))?; - let error = readiness.await.unwrap_err(); - assert!(error.to_string().contains("test Noise provider called")); - assert_eq!(deferred_provider.calls(), 1); - Ok(()) -} - -#[tokio::test] -async fn ordinary_noise_environment_replaces_a_deferred_registration() -> anyhow::Result<()> { - let manager = environment_manager_without_environments(); - let deferred_provider = Arc::new(FailingNoiseConnectProvider::default()); - let registration = manager - .register_deferred_noise_environment("tools".to_string(), deferred_provider.clone())?; - let deferred = manager - .get_environment("tools") - .expect("deferred environment"); - let ordinary_provider = Arc::new(FailingNoiseConnectProvider::default()); - - manager.upsert_noise_environment("tools".to_string(), ordinary_provider.clone())?; - let ordinary = manager - .get_environment("tools") - .expect("ordinary environment"); - assert!(!Arc::ptr_eq(&deferred, &ordinary)); - - drop(registration); - let error = deferred.wait_until_ready().await.unwrap_err(); - assert!( - error - .to_string() - .contains("registration ended before completion") - ); - assert_eq!(deferred_provider.calls(), 0); - let error = ordinary.wait_until_ready().await.unwrap_err(); - assert!(error.to_string().contains("test Noise provider called")); - assert_eq!(ordinary_provider.calls(), 1); - Ok(()) -} - -#[tokio::test] -async fn existing_environment_publishes_readiness_without_replacement() -> anyhow::Result<()> { - let manager = environment_manager_without_environments(); - let existing_provider = Arc::new(FailingNoiseConnectProvider::default()); - manager.upsert_noise_environment("tools".to_string(), existing_provider)?; - let existing_environment = manager - .get_environment("tools") - .expect("existing environment"); - - let ready_info = ready_info("selected-root", "tools")?; - manager.publish_ready_info("tools", ready_info.clone())?; - - let current_environment = manager - .get_environment("tools") - .expect("current environment"); - assert!(Arc::ptr_eq(&existing_environment, ¤t_environment)); - assert_eq!( - existing_environment.selected_capability_roots(), - ready_info.selected_capability_roots - ); - Ok(()) -} - -#[tokio::test] -async fn readiness_updates_the_current_environment_after_replacement() -> anyhow::Result<()> { - let manager = environment_manager_without_environments(); - manager.upsert_noise_environment( - "tools".to_string(), - Arc::new(FailingNoiseConnectProvider::default()), - )?; - let captured_environment = manager - .get_environment("tools") - .expect("captured environment"); - manager.upsert_noise_environment( - "tools".to_string(), - Arc::new(FailingNoiseConnectProvider::default()), - )?; - let current_environment = manager - .get_environment("tools") - .expect("replacement environment"); - let ready_info = ready_info("selected-root", "tools")?; - - manager.publish_ready_info("tools", ready_info.clone())?; - - assert!(!Arc::ptr_eq(&captured_environment, ¤t_environment)); - assert!(captured_environment.selected_capability_roots().is_empty()); - assert_eq!( - current_environment.selected_capability_roots(), - ready_info.selected_capability_roots - ); - Ok(()) -} - -#[tokio::test] -async fn publishing_readiness_requires_existing_environment() -> anyhow::Result<()> { - let manager = environment_manager_without_environments(); - - let error = manager - .publish_ready_info("tools", ready_info("selected-root", "tools")?) - .unwrap_err(); - - assert!(matches!(error, ExecServerError::Protocol(_))); - assert!(manager.get_environment("tools").is_none()); - Ok(()) -} - -#[tokio::test] -async fn existing_environment_accepts_matching_readiness() -> anyhow::Result<()> { - let manager = environment_manager_without_environments(); - manager.upsert_noise_environment( - "tools".to_string(), - Arc::new(FailingNoiseConnectProvider::default()), - )?; - let environment = manager.get_environment("tools").expect("environment"); - let ready_info = ready_info("selected-root", "tools")?; - - for _ in 0..2 { - manager.publish_ready_info("tools", ready_info.clone())?; - } - assert_eq!( - environment.selected_capability_roots(), - ready_info.selected_capability_roots - ); - Ok(()) -} - -#[tokio::test] -async fn existing_environment_overwrites_published_readiness() -> anyhow::Result<()> { - let manager = environment_manager_without_environments(); - manager.upsert_noise_environment( - "tools".to_string(), - Arc::new(FailingNoiseConnectProvider::default()), - )?; - let environment = manager.get_environment("tools").expect("environment"); - let selected_ready_info = ready_info("selected-root", "tools")?; - manager.publish_ready_info("tools", selected_ready_info)?; - - let updated_ready_info = ready_info("different-root", "tools")?; - manager.publish_ready_info("tools", updated_ready_info.clone())?; - assert_eq!( - environment.selected_capability_roots(), - updated_ready_info.selected_capability_roots - ); - assert!(Arc::ptr_eq( - &environment, - &manager.get_environment("tools").expect("environment") - )); - - manager.publish_ready_info("tools", EnvironmentReadyInfo::default())?; - assert!(environment.selected_capability_roots().is_empty()); - Ok(()) -} - -#[tokio::test] -async fn publishing_readiness_before_deferred_completion_preserves_the_gate() -> anyhow::Result<()> -{ - let manager = environment_manager_without_environments(); - let provider = Arc::new(FailingNoiseConnectProvider::default()); - let registration = - manager.register_deferred_noise_environment("tools".to_string(), provider.clone())?; - let environment = manager.get_environment("tools").expect("environment"); - let mut readiness = Box::pin(environment.wait_until_ready()); - - manager.publish_ready_info("tools", ready_info("published-root", "tools")?)?; - assert!(poll!(&mut readiness).is_pending()); - assert_eq!(provider.calls(), 0); - - let completed_ready_info = ready_info("completed-root", "tools")?; - registration.complete(Ok(completed_ready_info.clone()))?; - assert_eq!( - environment.selected_capability_roots(), - completed_ready_info.selected_capability_roots - ); - let error = readiness.await.unwrap_err(); - assert!(error.to_string().contains("test Noise provider called")); - assert_eq!(provider.calls(), 1); - Ok(()) -} - -#[tokio::test] -async fn existing_environment_rejects_invalid_readiness() -> anyhow::Result<()> { - let manager = environment_manager_without_environments(); - manager.upsert_noise_environment( - "tools".to_string(), - Arc::new(FailingNoiseConnectProvider::default()), - )?; - let existing_environment = manager - .get_environment("tools") - .expect("existing environment"); - let error = manager - .publish_ready_info("tools", ready_info("selected-root", "other")?) - .unwrap_err(); - - assert!(matches!(error, ExecServerError::Protocol(_))); - assert!(existing_environment.selected_capability_roots().is_empty()); - let current_environment = manager - .get_environment("tools") - .expect("current environment"); - assert!(Arc::ptr_eq(&existing_environment, ¤t_environment)); - Ok(()) -} - -#[tokio::test] -async fn failure_and_dropped_registration_are_terminal() -> anyhow::Result<()> { - let manager = environment_manager_without_environments(); - let failed_provider = Arc::new(FailingNoiseConnectProvider::default()); - let failed = manager - .register_deferred_noise_environment("failed".to_string(), failed_provider.clone())?; - let failed_environment = manager.get_environment("failed").expect("environment"); - failed.complete(Err("provisioning failed".to_string()))?; - let error = failed_environment.wait_until_ready().await.unwrap_err(); - assert!( - error - .to_string() - .ends_with("environment unavailable: provisioning failed") - ); - assert_eq!(failed_provider.calls(), 0); - - let dropped_provider = Arc::new(FailingNoiseConnectProvider::default()); - let dropped = manager - .register_deferred_noise_environment("dropped".to_string(), dropped_provider.clone())?; - let dropped_environment = manager.get_environment("dropped").expect("environment"); - drop(dropped); - let error = dropped_environment.wait_until_ready().await.unwrap_err(); - assert!( - error - .to_string() - .contains("registration ended before completion") - ); - assert_eq!(dropped_provider.calls(), 0); - assert!(manager.get_environment("failed").is_some()); - assert!(manager.get_environment("dropped").is_some()); - Ok(()) -} - -#[tokio::test] -async fn invalid_ready_info_is_terminal() -> anyhow::Result<()> { - let manager = environment_manager_without_environments(); - let provider = Arc::new(FailingNoiseConnectProvider::default()); - let registration = - manager.register_deferred_noise_environment("tools".to_string(), provider.clone())?; - let environment = manager.get_environment("tools").expect("environment"); - - let error = registration - .complete(Ok(ready_info("selected-root", "other")?)) - .unwrap_err(); - assert!(matches!(error, ExecServerError::Protocol(_))); - let readiness_error = environment.wait_until_ready().await.unwrap_err(); - assert!( - readiness_error - .to_string() - .contains("belong to environment") - ); - assert!(environment.selected_capability_roots().is_empty()); - assert_eq!(provider.calls(), 0); - Ok(()) -} - -#[tokio::test] -async fn late_completion_is_isolated_from_replacement() -> anyhow::Result<()> { - let manager = environment_manager_without_environments(); - let old_provider = Arc::new(FailingNoiseConnectProvider::default()); - let old_registration = - manager.register_deferred_noise_environment("tools".to_string(), old_provider.clone())?; - let old_environment = manager.get_environment("tools").expect("old environment"); - let current_provider = Arc::new(FailingNoiseConnectProvider::default()); - let current_registration = manager - .register_deferred_noise_environment("tools".to_string(), current_provider.clone())?; - let current = manager.get_environment("tools").expect("current"); - - let old_ready_info = ready_info("old-root", "tools")?; - old_registration.complete(Ok(old_ready_info.clone()))?; - assert_eq!( - old_environment.selected_capability_roots(), - old_ready_info.selected_capability_roots - ); - assert!(current.selected_capability_roots().is_empty()); - let old_error = old_environment.wait_until_ready().await.unwrap_err(); - assert!(old_error.to_string().contains("test Noise provider called")); - assert_eq!(old_provider.calls(), 1); - let mut current_readiness = Box::pin(current.wait_until_ready()); - assert!(poll!(&mut current_readiness).is_pending()); - assert_eq!(current_provider.calls(), 0); - - let current_ready_info = ready_info("current-root", "tools")?; - current_registration.complete(Ok(current_ready_info.clone()))?; - assert_eq!( - current.selected_capability_roots(), - current_ready_info.selected_capability_roots - ); - let current_error = current_readiness.await.unwrap_err(); - assert!( - current_error - .to_string() - .contains("test Noise provider called") - ); - assert_eq!(current_provider.calls(), 1); - Ok(()) -} - -#[tokio::test] -async fn eager_noise_environment_connects_without_registration() -> anyhow::Result<()> { - let manager = environment_manager_without_environments(); - let provider = Arc::new(FailingNoiseConnectProvider::default()); - manager.upsert_noise_environment("tools".to_string(), provider.clone())?; - let environment = manager.get_environment("tools").expect("environment"); - - let error = environment.wait_until_ready().await.unwrap_err(); - assert!(error.to_string().contains("test Noise provider called")); - assert_eq!(provider.calls(), 1); - Ok(()) -} - #[tokio::test] async fn readiness_before_materialization_creates_the_stable_environment() -> anyhow::Result<()> { let manager = environment_manager_without_environments(); @@ -469,6 +108,33 @@ async fn materialize_then_report_ready_reuses_the_pending_environment() -> anyho Ok(()) } +#[tokio::test] +async fn ordinary_environment_ignores_provisioning_reports() -> anyhow::Result<()> { + let manager = environment_manager_without_environments(); + manager.upsert_environment( + "tools".to_string(), + "ws://127.0.0.1:1".to_string(), + Some(std::time::Duration::from_millis(1)), + )?; + let existing_environment = manager + .get_environment("tools") + .expect("existing environment"); + + let reported = manager.report_environment_provisioning_status( + "tools".to_string(), + Ok(ready_info("selected-root", "tools")?), + Arc::new(FailingNoiseConnectProvider::default()), + )?; + + let current_environment = manager + .get_environment("tools") + .expect("current environment"); + assert!(Arc::ptr_eq(&existing_environment, ¤t_environment)); + assert!(reported.is_none()); + assert!(existing_environment.selected_capability_roots().is_empty()); + Ok(()) +} + #[tokio::test] async fn failure_before_materialization_is_terminal_without_connecting() -> anyhow::Result<()> { let manager = environment_manager_without_environments(); @@ -537,15 +203,6 @@ async fn repeated_failure_preserves_the_first_error_and_rejects_ready() -> anyho .expect("repeated failure should be idempotent"); assert!(Arc::ptr_eq(&failed, &repeated)); - let error = manager - .report_environment_provisioning_status( - "tools".to_string(), - Ok(ready_info("selected-root", "other")?), - provider.clone(), - ) - .unwrap_err(); - assert!(error.to_string().contains("first failure")); - let error = manager .report_environment_provisioning_status( "tools".to_string(), @@ -585,3 +242,141 @@ async fn ready_environment_rejects_a_later_failure() -> anyhow::Result<()> { assert_eq!(ready.selected_capability_roots().len(), 1); Ok(()) } + +#[tokio::test] +async fn existing_environment_accepts_matching_readiness() -> anyhow::Result<()> { + let manager = environment_manager_without_environments(); + let provider = Arc::new(FailingNoiseConnectProvider::default()); + let ready_info = ready_info("selected-root", "tools")?; + + let environment = manager + .report_environment_provisioning_status( + "tools".to_string(), + Ok(ready_info.clone()), + provider.clone(), + )? + .expect("readiness report should create the environment"); + manager.report_environment_provisioning_status( + "tools".to_string(), + Ok(ready_info.clone()), + provider, + )?; + assert_eq!( + environment.selected_capability_roots(), + ready_info.selected_capability_roots + ); + Ok(()) +} + +#[tokio::test] +async fn existing_environment_overwrites_reported_readiness() -> anyhow::Result<()> { + let manager = environment_manager_without_environments(); + let provider = Arc::new(FailingNoiseConnectProvider::default()); + let environment = manager + .report_environment_provisioning_status( + "tools".to_string(), + Ok(ready_info("selected-root", "tools")?), + provider.clone(), + )? + .expect("readiness report should create the environment"); + + let updated_ready_info = ready_info("different-root", "tools")?; + manager.report_environment_provisioning_status( + "tools".to_string(), + Ok(updated_ready_info.clone()), + provider, + )?; + assert_eq!( + environment.selected_capability_roots(), + updated_ready_info.selected_capability_roots + ); + assert!(Arc::ptr_eq( + &environment, + &manager.get_environment("tools").expect("environment") + )); + Ok(()) +} + +#[tokio::test] +async fn invalid_ready_report_fails_the_provisioning_gate() -> anyhow::Result<()> { + let manager = environment_manager_without_environments(); + let provider = Arc::new(FailingNoiseConnectProvider::default()); + let environment = + manager.materialize_pending_noise_environment("tools".to_string(), provider.clone())?; + let readiness = Box::pin(environment.wait_until_ready()); + + let error = manager + .report_environment_provisioning_status( + "tools".to_string(), + Ok(ready_info("selected-root", "other")?), + provider.clone(), + ) + .unwrap_err(); + + assert!(matches!(error, ExecServerError::Protocol(_))); + let readiness_error = readiness.await.unwrap_err(); + assert!(readiness_error.to_string().contains(&error.to_string())); + assert!(environment.selected_capability_roots().is_empty()); + assert_eq!(provider.calls(), 0); + + let later_ready_error = manager + .report_environment_provisioning_status( + "tools".to_string(), + Ok(ready_info("selected-root", "tools")?), + provider.clone(), + ) + .unwrap_err(); + assert!( + later_ready_error + .to_string() + .contains("provisioning already failed") + ); + assert!(environment.selected_capability_roots().is_empty()); + assert_eq!(provider.calls(), 0); + Ok(()) +} + +#[tokio::test] +async fn duplicate_materialization_reuses_the_pending_environment() -> anyhow::Result<()> { + let manager = environment_manager_without_environments(); + let provider = Arc::new(FailingNoiseConnectProvider::default()); + let environment = + manager.materialize_pending_noise_environment("tools".to_string(), provider.clone())?; + let replacement_provider = Arc::new(FailingNoiseConnectProvider::default()); + + let current = manager + .materialize_pending_noise_environment("tools".to_string(), replacement_provider.clone())?; + assert!(Arc::ptr_eq(&environment, ¤t)); + assert_eq!(provider.calls(), 0); + assert_eq!(replacement_provider.calls(), 0); + Ok(()) +} + +#[tokio::test] +async fn deferred_materialization_conflicts_with_an_existing_ordinary_environment() +-> anyhow::Result<()> { + let manager = environment_manager_without_environments(); + manager.upsert_environment( + "tools".to_string(), + "ws://127.0.0.1:1".to_string(), + Some(std::time::Duration::from_millis(1)), + )?; + let existing_environment = manager.get_environment("tools").expect("environment"); + let deferred_provider = Arc::new(FailingNoiseConnectProvider::default()); + + let error = manager + .materialize_pending_noise_environment("tools".to_string(), deferred_provider.clone()) + .unwrap_err(); + + assert!(matches!( + error, + ExecServerError::ProvisioningModeConflict { environment_id } + if environment_id == "tools" + )); + let current_environment = manager + .get_environment("tools") + .expect("ordinary environment should remain registered"); + assert!(Arc::ptr_eq(&existing_environment, ¤t_environment)); + assert_eq!(deferred_provider.calls(), 0); + Ok(()) +}