use std::sync::Arc;
use sa_token_core::config::SaTokenConfig;
use sa_token_core::SaTokenContext;
use sa_token_core::SaTokenManager;
use sa_token_storage_memory::MemoryStorage;
fn build_manager() -> SaTokenManager {
let storage = Arc::new(MemoryStorage::new());
SaTokenConfig::builder().storage(storage).build()
}
#[test]
fn ctx_survives_yield_and_thread_hop() {
let rt = tokio::runtime::Builder::new_multi_thread()
.worker_threads(2)
.enable_all()
.build()
.unwrap();
rt.block_on(async {
let manager = build_manager();
let token = manager.login("u-1".to_string()).await.unwrap();
let info = manager.get_token_info(&token).await.unwrap();
let mut ctx = SaTokenContext::new();
ctx.token = Some(token.clone());
ctx.login_id = Some(info.login_id.clone());
ctx.token_info = Some(Arc::new(info));
let got: Option<String> = SaTokenContext::scope(ctx, async {
for _ in 0..32 {
tokio::task::yield_now().await; }
SaTokenContext::try_current().and_then(|c| c.login_id)
})
.await;
assert_eq!(got.as_deref(), Some("u-1"));
});
}
#[test]
fn ctx_is_none_outside_scope() {
let rt = tokio::runtime::Builder::new_multi_thread()
.worker_threads(2)
.enable_all()
.build()
.unwrap();
rt.block_on(async {
assert!(SaTokenContext::try_current().is_none());
});
}
#[test]
fn legacy_thread_local_still_works_same_thread() {
let mut ctx = SaTokenContext::new();
ctx.login_id = Some("legacy".into());
SaTokenContext::set_current(ctx);
assert_eq!(
SaTokenContext::try_current().unwrap().login_id.as_deref(),
Some("legacy")
);
SaTokenContext::clear();
assert!(SaTokenContext::try_current().is_none());
}