diff --git a/crates/matrix-sdk/src/test_utils/mocks/mod.rs b/crates/matrix-sdk/src/test_utils/mocks/mod.rs index 46a5f0beb..2dd4e58b5 100644 --- a/crates/matrix-sdk/src/test_utils/mocks/mod.rs +++ b/crates/matrix-sdk/src/test_utils/mocks/mod.rs @@ -35,7 +35,7 @@ use ruma::{ DeviceId, EventId, MilliSecondsSinceUnixEpoch, MxcUri, OwnedDeviceId, OwnedEventId, OwnedOneTimeKeyId, OwnedRoomId, OwnedUserId, RoomId, ServerName, UserId, api::client::{ - profile::ProfileFieldName, + profile::{ProfileFieldName, ProfileFieldValue}, receipt::create_receipt::v3::ReceiptType, room::Visibility, sync::sync_events::v5, @@ -1656,6 +1656,13 @@ impl MatrixMockServer { .and(path(format!("/_matrix/client/v3/profile/{user_id}/{field}"))); self.mock_endpoint(mock, DeleteProfileFieldEndpoint).expect_default_access_token() } + + /// Create a prebuilt mock for the endpoint used to get a profile. + pub fn mock_get_profile(&self, user_id: &UserId) -> MockEndpoint<'_, GetProfileEndpoint> { + let mock = + Mock::given(method("GET")).and(path(format!("/_matrix/client/v3/profile/{user_id}"))); + self.mock_endpoint(mock, GetProfileEndpoint) + } } /// A specification for a push rule ID. @@ -4731,3 +4738,17 @@ impl<'a> MockEndpoint<'a, DeleteProfileFieldEndpoint> { self.ok_empty_json() } } + +/// A prebuilt mock for `GET /_matrix/client/*/profile/{user_id}`. +pub struct GetProfileEndpoint; + +impl<'a> MockEndpoint<'a, GetProfileEndpoint> { + /// Returns a successful empty response. + pub fn ok_with_fields(self, fields: Vec) -> MatrixMock<'a> { + let profile = fields + .iter() + .map(|field| (field.field_name(), field.value())) + .collect::>(); + self.respond_with(ResponseTemplate::new(200).set_body_json(profile)) + } +} diff --git a/crates/matrix-sdk/tests/integration/account.rs b/crates/matrix-sdk/tests/integration/account.rs index c0a1ee049..11635b111 100644 --- a/crates/matrix-sdk/tests/integration/account.rs +++ b/crates/matrix-sdk/tests/integration/account.rs @@ -4,7 +4,7 @@ use matrix_sdk_test::async_test; use ruma::{ api::{ MatrixVersion, - client::profile::{ProfileFieldName, ProfileFieldValue, TimeZone}, + client::profile::{AvatarUrl, DisplayName, ProfileFieldName, ProfileFieldValue, TimeZone}, }, mxc_uri, }; @@ -220,3 +220,81 @@ async fn test_delete_profile_field() { account.delete_profile_field(ProfileFieldName::TimeZone).await.unwrap(); } } + +#[async_test] +async fn test_fetch_user_profile() { + let tz = "Africa/Bujumbura"; + let display_name = "Alice"; + + let server = MatrixMockServer::new().await; + let client = server.client_builder().build().await; + let user_id = client.user_id().unwrap(); + + server + .mock_get_profile(user_id) + .ok_with_fields(vec![ + ProfileFieldValue::TimeZone(tz.to_owned()), + ProfileFieldValue::DisplayName(display_name.to_owned()), + ]) + .mock_once() + .named("get profile") + .mount() + .await; + + let profile = client.account().fetch_user_profile().await.unwrap(); + + assert_eq!(profile.get_static::().unwrap().as_deref(), Some(tz)); + assert_eq!(profile.get_static::().unwrap().as_deref(), Some(display_name)); + assert_eq!(profile.get_static::().unwrap(), None); +} + +#[async_test] +async fn test_get_cached_avatar_url() { + let avatar_url = mxc_uri!("mxc://localhost/1mA63"); + + let server = MatrixMockServer::new().await; + let client = server.client_builder().build().await; + let user_id = client.user_id().unwrap(); + + let account = client.account(); + + // The cache is empty. + let res_avatar_url = account.get_cached_avatar_url().await.unwrap(); + assert_eq!(res_avatar_url, None); + + // Fetch it from the homeserver, it should fill the cache. + { + let _guard = server + .mock_get_profile_field(user_id, ProfileFieldName::AvatarUrl) + .ok_with_value(Some(avatar_url.as_str().into())) + .mock_once() + .named("get avatar_url profile field with value") + .mount_as_scoped() + .await; + + let res_avatar_url = account.get_avatar_url().await.unwrap(); + assert_eq!(res_avatar_url.as_deref(), Some(avatar_url)); + } + + // The cache was filled. + let res_avatar_url = account.get_cached_avatar_url().await.unwrap(); + assert_eq!(res_avatar_url.as_deref(), Some(avatar_url)); + + // Fetch it again from the homeserver, a missing value should empty the cache. + { + let _guard = server + .mock_get_profile_field(user_id, ProfileFieldName::AvatarUrl) + .ok_with_value(None) + .mock_once() + .named("get avatar_url profile field without value") + .mount_as_scoped() + .await; + + let res_avatar_url = account.get_avatar_url().await.unwrap(); + assert_eq!(res_avatar_url, None); + } + + // The cache was emptied. + let res_avatar_url = account.get_cached_avatar_url().await.unwrap(); + assert_eq!(res_avatar_url, None); +}