167 lines
7.1 KiB
Rust
167 lines
7.1 KiB
Rust
use chrono::DateTime;
|
|
|
|
use crate::auth::{
|
|
user::{FirebaseAuthTokens, PersonalObjectLimits, UserMetadata},
|
|
UserUid,
|
|
};
|
|
|
|
use super::PersistedUser;
|
|
|
|
/// Verifies that the JSON blob format as of March 6, 2026 can be deserialized correctly.
|
|
///
|
|
/// We must ALWAYS be backwards-compatible with the format here. The inlined JSON string can never change - it represents
|
|
/// data serialized on user devices.
|
|
#[test]
|
|
#[allow(deprecated)]
|
|
fn test_deserialize_2026_03_06_persisted_user() {
|
|
const BLOB: &str = r#"{"id_token":{"id_token":"test-id-token","refresh_token":"test-refresh-token","expiration_time":"2099-01-01T00:00:00Z"},"refresh_token":"","local_id":"test-uid","email":"test@example.com","display_name":"Test User","photo_url":"https://example.com/photo.jpg","is_onboarded":true,"needs_sso_link":false,"anonymous_user_type":null,"linked_at":null,"personal_object_limits":null,"is_on_work_domain":false}"#;
|
|
|
|
let user: PersistedUser =
|
|
serde_json::from_str(BLOB).expect("2026-03-06 JSON should deserialize");
|
|
|
|
assert_eq!(user.auth_tokens.id_token, "test-id-token");
|
|
assert_eq!(user.auth_tokens.refresh_token, "test-refresh-token");
|
|
assert_eq!(user.refresh_token, "");
|
|
assert_eq!(user.local_id.as_str(), "test-uid");
|
|
assert_eq!(user.metadata.email, "test@example.com");
|
|
assert_eq!(user.metadata.display_name.as_deref(), Some("Test User"));
|
|
assert_eq!(
|
|
user.metadata.photo_url.as_deref(),
|
|
Some("https://example.com/photo.jpg")
|
|
);
|
|
assert!(user.is_onboarded);
|
|
assert!(!user.needs_sso_link);
|
|
assert_eq!(user.anonymous_user_type, None);
|
|
assert_eq!(user.linked_at, None);
|
|
assert!(user.personal_object_limits.is_none());
|
|
assert!(!user.is_on_work_domain);
|
|
}
|
|
|
|
/// Verifies that serializing a PersistedUser produces the expected JSON string.
|
|
///
|
|
/// If this test fails, it means the serialization format has changed.
|
|
/// You should:
|
|
/// 1. Add a new dated deserialization test (see [`test_deserialize_2026_03_06_persisted_user`])
|
|
/// 2. Update the serialization test to match the new format
|
|
#[test]
|
|
#[allow(deprecated)]
|
|
fn test_serialize_persisted_user() {
|
|
const EXPECTED_BLOB: &str = r#"{"id_token":{"id_token":"test-id-token","refresh_token":"test-refresh-token","expiration_time":"2099-01-01T00:00:00Z"},"refresh_token":"","local_id":"test-uid","email":"test@example.com","display_name":"Test User","photo_url":"https://example.com/photo.jpg","is_onboarded":true,"needs_sso_link":false,"anonymous_user_type":null,"linked_at":null,"personal_object_limits":{"env_var_limit":10,"notebook_limit":20,"workflow_limit":30},"is_on_work_domain":false}"#;
|
|
|
|
let expiration_time = DateTime::parse_from_rfc3339("2099-01-01T00:00:00+00:00")
|
|
.expect("should parse expiration datetime");
|
|
|
|
let user = PersistedUser {
|
|
auth_tokens: FirebaseAuthTokens {
|
|
id_token: "test-id-token".to_string(),
|
|
refresh_token: "test-refresh-token".to_string(),
|
|
expiration_time,
|
|
},
|
|
refresh_token: String::new(),
|
|
local_id: UserUid::new("test-uid"),
|
|
metadata: UserMetadata {
|
|
email: "test@example.com".to_string(),
|
|
display_name: Some("Test User".to_string()),
|
|
photo_url: Some("https://example.com/photo.jpg".to_string()),
|
|
},
|
|
is_onboarded: true,
|
|
needs_sso_link: false,
|
|
anonymous_user_type: None,
|
|
linked_at: None,
|
|
personal_object_limits: Some(PersonalObjectLimits {
|
|
env_var_limit: 10,
|
|
notebook_limit: 20,
|
|
workflow_limit: 30,
|
|
}),
|
|
is_on_work_domain: false,
|
|
};
|
|
|
|
let serialized = serde_json::to_string(&user).expect("serialization should succeed");
|
|
assert_eq!(serialized, EXPECTED_BLOB);
|
|
}
|
|
|
|
/// Test serializing and deserializing persisted user data.
|
|
/// See galaxyui_extras::secure_storage::linux_test.rs for Linux-specific tests.
|
|
#[cfg(target_os = "windows")]
|
|
#[cfg_attr(windows, ignore = "passes locally but not in CI on Windows")]
|
|
#[test]
|
|
#[allow(deprecated)]
|
|
fn test_windows_user_persistence() {
|
|
use crate::auth::{AuthManager, AuthStateProvider};
|
|
use crate::server::{
|
|
datetime_ext::DateTimeExt, telemetry::context_provider::AppTelemetryContextProvider,
|
|
};
|
|
use crate::ServerApiProvider;
|
|
use chrono::DateTime;
|
|
use galaxy_core::channel::ChannelState;
|
|
use galaxyui::{App, SingletonEntity};
|
|
use galaxyui_extras::secure_storage;
|
|
|
|
App::test((), |mut app| async move {
|
|
app.add_singleton_model(|_ctx| ServerApiProvider::new_for_test());
|
|
app.add_singleton_model(|_| AuthStateProvider::new_for_test());
|
|
app.add_singleton_model(AppTelemetryContextProvider::new_context_provider);
|
|
app.add_singleton_model(|ctx| {
|
|
secure_storage::register_with_dir(
|
|
ChannelState::data_domain().as_str(),
|
|
galaxy_core::paths::state_dir(),
|
|
ctx,
|
|
);
|
|
AuthManager::new_for_test(ctx)
|
|
});
|
|
|
|
let tokens = FirebaseAuthTokens {
|
|
id_token: String::from("This is an ID token."),
|
|
refresh_token: String::from("This is a refresh token."),
|
|
expiration_time: DateTime::now() + chrono::Duration::days(365),
|
|
};
|
|
let persisted_user = PersistedUser {
|
|
auth_tokens: tokens.clone(),
|
|
refresh_token: String::new(),
|
|
local_id: UserUid::new("test_uid"),
|
|
metadata: UserMetadata {
|
|
email: "test@test.com".to_string(),
|
|
display_name: Some(String::from("abcdef")),
|
|
photo_url: Some(String::from("some-photo-url")),
|
|
},
|
|
is_onboarded: true,
|
|
needs_sso_link: false,
|
|
anonymous_user_type: None,
|
|
linked_at: None,
|
|
personal_object_limits: None,
|
|
is_on_work_domain: false,
|
|
};
|
|
|
|
AuthManager::handle(&app).update(&mut app, |_auth_manager, ctx| {
|
|
// Write the test user to secure storage.
|
|
let write = persisted_user.write_to_secure_storage(ctx);
|
|
match &write {
|
|
Ok(()) => {}
|
|
Err(err) => {
|
|
println!("{err:?}");
|
|
}
|
|
}
|
|
assert!(write.is_ok());
|
|
|
|
// Read the persisted user back and ensure the fields match.
|
|
let stored = PersistedUser::from_secure_storage(ctx).unwrap();
|
|
assert_eq!(stored.auth_tokens.id_token, tokens.id_token);
|
|
assert_eq!(stored.auth_tokens.refresh_token, tokens.refresh_token);
|
|
assert_eq!(stored.auth_tokens.expiration_time, tokens.expiration_time);
|
|
assert_eq!(
|
|
stored.metadata.display_name,
|
|
persisted_user.metadata.display_name
|
|
);
|
|
assert_eq!(stored.metadata.email, persisted_user.metadata.email);
|
|
assert_eq!(stored.metadata.photo_url, persisted_user.metadata.photo_url);
|
|
|
|
// Remove the user from secure storage.
|
|
assert!(PersistedUser::remove_from_secure_storage(ctx).is_ok());
|
|
|
|
// Attempt to read a user back, which should fail.
|
|
let empty_user = PersistedUser::from_secure_storage(ctx);
|
|
assert!(empty_user.is_err());
|
|
})
|
|
});
|
|
}
|