use super::test_helpers::*;
use crate::claims::Claims;
use serde_json::json;
use std::sync::Arc;
use tokio::task::JoinSet;
#[cfg(test)]
mod tests {
use super::*;
#[tokio::test]
async fn test_claims_concurrent_access() {
let claims = Arc::new(create_test_claims());
let mut join_set = JoinSet::new();
for i in 0..20 {
let claims_clone = claims.clone();
join_set.spawn(async move {
let user_id = claims_clone.user_id();
let email = claims_clone.email();
let role = claims_clone.role();
let is_anonymous = claims_clone.is_anonymous();
(
user_id == TEST_USER_ID,
email == Some(TEST_EMAIL),
role == "authenticated",
!is_anonymous,
i,
)
});
}
let mut results = Vec::new();
while let Some(result) = join_set.join_next().await {
results.push(result.unwrap());
}
assert_eq!(results.len(), 20);
for (user_id_ok, email_ok, role_ok, not_anonymous, _) in results {
assert!(user_id_ok, "User ID should be consistent across threads");
assert!(email_ok, "Email should be consistent across threads");
assert!(role_ok, "Role should be consistent across threads");
assert!(
not_anonymous,
"Anonymous status should be consistent across threads"
);
}
}
#[tokio::test]
async fn test_claims_metadata_concurrent_access() {
let mut claims = create_test_claims();
claims.user_metadata = Some(json!({
"counter": 42,
"data": {
"nested": "value",
"array": [1, 2, 3]
}
}));
let claims = Arc::new(claims);
let mut join_set = JoinSet::new();
for _ in 0..10 {
let claims_clone = claims.clone();
join_set.spawn(async move {
let counter: Option<i32> = claims_clone.get_user_metadata("counter");
let data: Option<serde_json::Value> = claims_clone.get_user_metadata("data");
(counter == Some(42), data.is_some())
});
}
let mut success_count = 0;
while let Some(result) = join_set.join_next().await {
let (counter_ok, data_ok) = result.unwrap();
if counter_ok && data_ok {
success_count += 1;
}
}
assert_eq!(
success_count, 10,
"All concurrent metadata accesses should succeed"
);
}
#[test]
fn test_claims_serialization_performance() {
let mut claims = create_test_claims();
let mut metadata = serde_json::Map::new();
for i in 0..100 {
metadata.insert(
format!("key_{i}"),
json!({
"id": i,
"name": format!("item_{}", i),
"data": vec![i; 5]
}),
);
}
claims.user_metadata = Some(serde_json::Value::Object(metadata));
let start = std::time::Instant::now();
let serialized = serde_json::to_string(&claims).expect("Should serialize claims");
let serialize_duration = start.elapsed();
let start = std::time::Instant::now();
let deserialized: Claims =
serde_json::from_str(&serialized).expect("Should deserialize claims");
let deserialize_duration = start.elapsed();
assert!(
serialize_duration.as_millis() < 100,
"Serialization should be fast"
);
assert!(
deserialize_duration.as_millis() < 100,
"Deserialization should be fast"
);
assert_eq!(deserialized.sub, claims.sub);
assert_eq!(deserialized.exp, claims.exp);
assert_eq!(deserialized.user_metadata, claims.user_metadata);
}
#[test]
fn test_claims_clone_consistency() {
let original = create_test_claims();
let start = std::time::Instant::now();
let mut clones = Vec::new();
for _ in 0..100 {
clones.push(original.clone());
}
let clone_duration = start.elapsed();
assert_eq!(clones.len(), 100);
assert!(
clone_duration.as_millis() < 10,
"100 clones should be very fast"
);
for clone in &clones {
assert_eq!(clone.sub, original.sub);
assert_eq!(clone.exp, original.exp);
assert_eq!(clone.email, original.email);
assert_eq!(clone.role, original.role);
assert_eq!(clone.user_metadata, original.user_metadata);
}
}
#[test]
fn test_claims_metadata_deserialization_error() {
let mut claims = create_test_claims();
claims.user_metadata = Some(json!({
"profile": {
"age": "not_a_number" }
}));
let age: Option<i32> = claims.get_user_metadata("profile.age");
assert!(
age.is_none(),
"Should return None for deserialization failure"
);
#[derive(serde::Deserialize, Debug)]
#[allow(dead_code)]
struct Profile {
age: i32,
}
let profile: Option<Profile> = claims.get_user_metadata("profile");
assert!(
profile.is_none(),
"Should return None for struct deserialization failure"
);
}
#[tokio::test]
async fn test_claims_memory_stability() {
use std::time::{Duration, Instant};
use tokio::time::sleep;
let start_time = Instant::now();
let test_duration = Duration::from_secs(5); let mut iteration_count = 0;
while start_time.elapsed() < test_duration {
let mut claims_batch = Vec::new();
for i in 0..1000 {
let mut claims = create_test_claims();
claims.user_metadata = Some(json!({
"batch_id": iteration_count,
"item_id": i,
"timestamp": start_time.elapsed().as_millis(),
"data": vec![i; 10] }));
claims_batch.push(claims);
}
assert_eq!(claims_batch.len(), 1000);
for (i, claims) in claims_batch.iter().enumerate() {
assert_eq!(claims.user_id(), TEST_USER_ID);
let batch_id: Option<u64> = claims.get_user_metadata("batch_id");
assert_eq!(batch_id, Some(iteration_count));
let item_id: Option<usize> = claims.get_user_metadata("item_id");
assert_eq!(item_id, Some(i));
}
drop(claims_batch);
iteration_count += 1;
sleep(Duration::from_millis(10)).await;
}
assert!(
iteration_count > 10,
"Should have completed multiple iterations: {iteration_count}"
);
}
#[tokio::test]
async fn test_claims_concurrent_memory_usage() {
use std::sync::atomic::{AtomicUsize, Ordering};
use std::sync::Arc;
use tokio::task::JoinSet;
let counter = Arc::new(AtomicUsize::new(0));
let mut join_set = JoinSet::new();
for task_id in 0..10 {
let counter_clone = counter.clone();
join_set.spawn(async move {
let mut local_claims = Vec::new();
for i in 0..500 {
let mut claims = create_test_claims();
claims.user_metadata = Some(json!({
"task_id": task_id,
"local_id": i,
"payload": format!("data_{}_{}", task_id, i)
}));
local_claims.push(claims);
}
for (i, claims) in local_claims.iter().enumerate() {
let task_id_meta: Option<usize> = claims.get_user_metadata("task_id");
assert_eq!(task_id_meta, Some(task_id));
let local_id_meta: Option<usize> = claims.get_user_metadata("local_id");
assert_eq!(local_id_meta, Some(i));
}
counter_clone.fetch_add(local_claims.len(), Ordering::Relaxed);
local_claims.len()
});
}
let mut total_processed = 0;
while let Some(result) = join_set.join_next().await {
total_processed += result.unwrap();
}
assert_eq!(total_processed, 5000); assert_eq!(counter.load(Ordering::Relaxed), 5000);
}
#[test]
fn test_claims_clone_memory_efficiency() {
let original = create_test_claims();
let start_time = std::time::Instant::now();
let mut clones = Vec::with_capacity(10000);
for _ in 0..10000 {
clones.push(original.clone());
}
let clone_duration = start_time.elapsed();
assert!(
clone_duration.as_millis() < 200,
"10000 clones should complete in reasonable time: {}ms (limit: 200ms)",
clone_duration.as_millis()
);
for (i, clone) in clones.iter().enumerate().step_by(1000) {
assert_eq!(clone.user_id(), original.user_id());
assert_eq!(clone.email(), original.email());
assert_eq!(clone.role(), original.role());
if i % 1000 == 0 {
assert_eq!(clone.sub, original.sub);
assert_eq!(clone.exp, original.exp);
}
}
assert_eq!(clones.len(), 10000);
}
#[test]
fn test_claims_serialization_under_memory_pressure() {
let mut large_claims = create_test_claims();
let mut metadata = serde_json::Map::new();
for i in 0..1000 {
metadata.insert(
format!("large_key_{i}"),
json!({
"id": i,
"data": vec![i; 100], "nested": {
"level1": {
"level2": {
"value": format!("deep_value_{}", i)
}
}
}
}),
);
}
large_claims.user_metadata = Some(serde_json::Value::Object(metadata));
for iteration in 0..50 {
let start = std::time::Instant::now();
let serialized =
serde_json::to_string(&large_claims).expect("Should serialize large claims");
let deserialized: Claims =
serde_json::from_str(&serialized).expect("Should deserialize large claims");
let duration = start.elapsed();
assert!(
duration.as_millis() < 500,
"Iteration {} took too long: {}ms",
iteration,
duration.as_millis()
);
assert_eq!(deserialized.sub, large_claims.sub);
assert_eq!(deserialized.user_metadata, large_claims.user_metadata);
if iteration % 10 == 0 {
let test_object: Option<serde_json::Value> =
deserialized.get_user_metadata("large_key_500");
assert!(test_object.is_some());
if let Some(obj) = test_object {
let nested_value = obj["nested"]["level1"]["level2"]["value"].as_str();
assert_eq!(nested_value, Some("deep_value_500"));
}
}
}
}
}